Closed
Description
Late binding does the following (putIdleConn):
waitingDialer := t.idleConnCh[key]
select {
case waitingDialer <- pconn:
t.idleMu.Unlock()
return true
default:
if waitingDialer != nil {
delete(t.idleConnCh, key)
}
}
However, receive in getConn is not atomic with creation of the idleConnCh channel, so it is possible that:
- getConn inserts a chan into idleConnCh
- putIdleConn gets the chan, but the non-blocking send fails
- getConn blocks on receive from idleConnCh
So when we need a conn the most, we actually miss the opportunity to match getConn and putIdleConn.
Another bad consequence is that putIdleConn will delete the chan from t.idleConnCh in this situation. This can disable late binding for a set of concurrent getConn's -- subsequent putIdleConn's won't hand off connections to them.