Reputation: 222
Redigo is a golang client for the redis database. It uses struct Pool
to maintain a pool of connections. This struct holds a mutex lock for application putting and getting connection parallelly.
type Pool struct {
// ...
IdleTimeout time.Duration
mu sync.Mutex
// Stack of idleConn with most recently used at the front.
idle list.List
}
In its get
method, connection pool removes stale (idle timeout) connections firstly. When finding a stale connection, the pool pops it, releases lock, then closes connection, tries to acquire lock again.
func (p *Pool) get() (Conn, error) {
p.mu.Lock()
// Prune stale connections.
if timeout := p.IdleTimeout; timeout > 0 {
for i, n := 0, p.idle.Len(); i < n; i++ {
e := p.idle.Back()
if e == nil {
break
}
ic := e.Value.(idleConn)
if ic.t.Add(timeout).After(nowFunc()) {
break
}
p.idle.Remove(e)
p.release()
// Why does pool unlock and try to acquire lock again?
p.mu.Unlock()
// Close this stale connection.
ic.c.Close()
p.mu.Lock()
}
}
Why does pool unlock and try to acquire lock again, instead of just unlocking before function returns? I guess closing a connection may cost quite a lot time, which will slow down other goroutine waiting on this mutex.
Here is the whole Pool get method
Upvotes: 1
Views: 1715
Reputation: 222
Close a connection may cost quite a lot time, which will slow down other goroutine waiting on this mutex. As what @Cerise Limón said - It seems unwise to lock all use of the pool for this time.
After unlocking the mutex, one of the waiting goroutines gets the mutex. Although goroutine for get
method still needs to remove stale connections, the one for put
method can put connection to pool and continue to do other work as soon as possible.
Upvotes: 0