1

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

lorneli
  • 252
  • 3
  • 11
  • I think your guess is correct. Closing a connection can take an unknown amount of time. It seems unwise to lock all use of the pool for this time. – Charlie Tumahai Mar 13 '17 at 01:26

1 Answers1

0

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.

lorneli
  • 252
  • 3
  • 11
  • "Close a connection may cost quite a lot time" --- this needs some elaboration. Under the hood it's implemented as `err := c.fd.Close()`. Under what circumstances can this be slow? – zerkms Mar 13 '17 at 03:19
  • @zerkms To be honest, I can't understand the underlying `netFD.Close` in net/fd_unix.go. In theory, when tcp terminating normally, each side (client and server) would send FIN and receive ACK from the other. During this time, network latency and packet loss could exist. – lorneli Mar 13 '17 at 09:49