Use atomic.Value instead of lock for ConnPool.lastDialError

This makes the reading and writing of lastDialError from the pool
faster, as atomic.Value is much more lightweight than the mutex.

Note that using error in atomic.Value directly could cause panics,
because errors could have inconsistent types. Thus wrap them with a
simple struct.
This commit is contained in:
Yuxuan 'fishy' Wang 2020-07-13 15:38:11 -07:00
parent f3d06886e6
commit 4f70db6849
1 changed files with 11 additions and 9 deletions

View File

@ -60,13 +60,16 @@ type Options struct {
IdleCheckFrequency time.Duration IdleCheckFrequency time.Duration
} }
type lastDialErrorWrap struct {
err error
}
type ConnPool struct { type ConnPool struct {
opt *Options opt *Options
dialErrorsNum uint32 // atomic dialErrorsNum uint32 // atomic
lastDialErrorMu sync.RWMutex lastDialError atomic.Value
lastDialError error
queue chan struct{} queue chan struct{}
@ -204,16 +207,15 @@ func (p *ConnPool) tryDial() {
} }
func (p *ConnPool) setLastDialError(err error) { func (p *ConnPool) setLastDialError(err error) {
p.lastDialErrorMu.Lock() p.lastDialError.Store(&lastDialErrorWrap{err: err})
p.lastDialError = err
p.lastDialErrorMu.Unlock()
} }
func (p *ConnPool) getLastDialError() error { func (p *ConnPool) getLastDialError() error {
p.lastDialErrorMu.RLock() err, _ := p.lastDialError.Load().(*lastDialErrorWrap)
err := p.lastDialError if err != nil {
p.lastDialErrorMu.RUnlock() return err.err
return err }
return nil
} }
// Get returns existed connection from the pool or creates a new one. // Get returns existed connection from the pool or creates a new one.