You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

pool.go 8.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. package pool
  2. import (
  3. "errors"
  4. "net"
  5. "sync"
  6. "sync/atomic"
  7. "time"
  8. "github.com/go-redis/redis/internal"
  9. )
  10. var ErrClosed = errors.New("redis: client is closed")
  11. var ErrPoolTimeout = errors.New("redis: connection pool timeout")
  12. var timers = sync.Pool{
  13. New: func() interface{} {
  14. t := time.NewTimer(time.Hour)
  15. t.Stop()
  16. return t
  17. },
  18. }
  19. // Stats contains pool state information and accumulated stats.
  20. type Stats struct {
  21. Hits uint32 // number of times free connection was found in the pool
  22. Misses uint32 // number of times free connection was NOT found in the pool
  23. Timeouts uint32 // number of times a wait timeout occurred
  24. TotalConns uint32 // number of total connections in the pool
  25. IdleConns uint32 // number of idle connections in the pool
  26. StaleConns uint32 // number of stale connections removed from the pool
  27. }
  28. type Pooler interface {
  29. NewConn() (*Conn, error)
  30. CloseConn(*Conn) error
  31. Get() (*Conn, error)
  32. Put(*Conn)
  33. Remove(*Conn)
  34. Len() int
  35. IdleLen() int
  36. Stats() *Stats
  37. Close() error
  38. }
  39. type Options struct {
  40. Dialer func() (net.Conn, error)
  41. OnClose func(*Conn) error
  42. PoolSize int
  43. MinIdleConns int
  44. MaxConnAge time.Duration
  45. PoolTimeout time.Duration
  46. IdleTimeout time.Duration
  47. IdleCheckFrequency time.Duration
  48. }
  49. type ConnPool struct {
  50. opt *Options
  51. dialErrorsNum uint32 // atomic
  52. lastDialErrorMu sync.RWMutex
  53. lastDialError error
  54. queue chan struct{}
  55. connsMu sync.Mutex
  56. conns []*Conn
  57. idleConns []*Conn
  58. poolSize int
  59. idleConnsLen int
  60. stats Stats
  61. _closed uint32 // atomic
  62. }
  63. var _ Pooler = (*ConnPool)(nil)
  64. func NewConnPool(opt *Options) *ConnPool {
  65. p := &ConnPool{
  66. opt: opt,
  67. queue: make(chan struct{}, opt.PoolSize),
  68. conns: make([]*Conn, 0, opt.PoolSize),
  69. idleConns: make([]*Conn, 0, opt.PoolSize),
  70. }
  71. for i := 0; i < opt.MinIdleConns; i++ {
  72. p.checkMinIdleConns()
  73. }
  74. if opt.IdleTimeout > 0 && opt.IdleCheckFrequency > 0 {
  75. go p.reaper(opt.IdleCheckFrequency)
  76. }
  77. return p
  78. }
  79. func (p *ConnPool) checkMinIdleConns() {
  80. if p.opt.MinIdleConns == 0 {
  81. return
  82. }
  83. if p.poolSize < p.opt.PoolSize && p.idleConnsLen < p.opt.MinIdleConns {
  84. p.poolSize++
  85. p.idleConnsLen++
  86. go p.addIdleConn()
  87. }
  88. }
  89. func (p *ConnPool) addIdleConn() {
  90. cn, err := p.newConn(true)
  91. if err != nil {
  92. return
  93. }
  94. p.connsMu.Lock()
  95. p.conns = append(p.conns, cn)
  96. p.idleConns = append(p.idleConns, cn)
  97. p.connsMu.Unlock()
  98. }
  99. func (p *ConnPool) NewConn() (*Conn, error) {
  100. return p._NewConn(false)
  101. }
  102. func (p *ConnPool) _NewConn(pooled bool) (*Conn, error) {
  103. cn, err := p.newConn(pooled)
  104. if err != nil {
  105. return nil, err
  106. }
  107. p.connsMu.Lock()
  108. p.conns = append(p.conns, cn)
  109. if pooled {
  110. if p.poolSize < p.opt.PoolSize {
  111. p.poolSize++
  112. } else {
  113. cn.pooled = false
  114. }
  115. }
  116. p.connsMu.Unlock()
  117. return cn, nil
  118. }
  119. func (p *ConnPool) newConn(pooled bool) (*Conn, error) {
  120. if p.closed() {
  121. return nil, ErrClosed
  122. }
  123. if atomic.LoadUint32(&p.dialErrorsNum) >= uint32(p.opt.PoolSize) {
  124. return nil, p.getLastDialError()
  125. }
  126. netConn, err := p.opt.Dialer()
  127. if err != nil {
  128. p.setLastDialError(err)
  129. if atomic.AddUint32(&p.dialErrorsNum, 1) == uint32(p.opt.PoolSize) {
  130. go p.tryDial()
  131. }
  132. return nil, err
  133. }
  134. cn := NewConn(netConn)
  135. cn.pooled = pooled
  136. return cn, nil
  137. }
  138. func (p *ConnPool) tryDial() {
  139. for {
  140. if p.closed() {
  141. return
  142. }
  143. conn, err := p.opt.Dialer()
  144. if err != nil {
  145. p.setLastDialError(err)
  146. time.Sleep(time.Second)
  147. continue
  148. }
  149. atomic.StoreUint32(&p.dialErrorsNum, 0)
  150. _ = conn.Close()
  151. return
  152. }
  153. }
  154. func (p *ConnPool) setLastDialError(err error) {
  155. p.lastDialErrorMu.Lock()
  156. p.lastDialError = err
  157. p.lastDialErrorMu.Unlock()
  158. }
  159. func (p *ConnPool) getLastDialError() error {
  160. p.lastDialErrorMu.RLock()
  161. err := p.lastDialError
  162. p.lastDialErrorMu.RUnlock()
  163. return err
  164. }
  165. // Get returns existed connection from the pool or creates a new one.
  166. func (p *ConnPool) Get() (*Conn, error) {
  167. if p.closed() {
  168. return nil, ErrClosed
  169. }
  170. err := p.waitTurn()
  171. if err != nil {
  172. return nil, err
  173. }
  174. for {
  175. p.connsMu.Lock()
  176. cn := p.popIdle()
  177. p.connsMu.Unlock()
  178. if cn == nil {
  179. break
  180. }
  181. if p.isStaleConn(cn) {
  182. _ = p.CloseConn(cn)
  183. continue
  184. }
  185. atomic.AddUint32(&p.stats.Hits, 1)
  186. return cn, nil
  187. }
  188. atomic.AddUint32(&p.stats.Misses, 1)
  189. newcn, err := p._NewConn(true)
  190. if err != nil {
  191. p.freeTurn()
  192. return nil, err
  193. }
  194. return newcn, nil
  195. }
  196. func (p *ConnPool) getTurn() {
  197. p.queue <- struct{}{}
  198. }
  199. func (p *ConnPool) waitTurn() error {
  200. select {
  201. case p.queue <- struct{}{}:
  202. return nil
  203. default:
  204. timer := timers.Get().(*time.Timer)
  205. timer.Reset(p.opt.PoolTimeout)
  206. select {
  207. case p.queue <- struct{}{}:
  208. if !timer.Stop() {
  209. <-timer.C
  210. }
  211. timers.Put(timer)
  212. return nil
  213. case <-timer.C:
  214. timers.Put(timer)
  215. atomic.AddUint32(&p.stats.Timeouts, 1)
  216. return ErrPoolTimeout
  217. }
  218. }
  219. }
  220. func (p *ConnPool) freeTurn() {
  221. <-p.queue
  222. }
  223. func (p *ConnPool) popIdle() *Conn {
  224. if len(p.idleConns) == 0 {
  225. return nil
  226. }
  227. idx := len(p.idleConns) - 1
  228. cn := p.idleConns[idx]
  229. p.idleConns = p.idleConns[:idx]
  230. p.idleConnsLen--
  231. p.checkMinIdleConns()
  232. return cn
  233. }
  234. func (p *ConnPool) Put(cn *Conn) {
  235. if !cn.pooled {
  236. p.Remove(cn)
  237. return
  238. }
  239. p.connsMu.Lock()
  240. p.idleConns = append(p.idleConns, cn)
  241. p.idleConnsLen++
  242. p.connsMu.Unlock()
  243. p.freeTurn()
  244. }
  245. func (p *ConnPool) Remove(cn *Conn) {
  246. p.removeConn(cn)
  247. p.freeTurn()
  248. _ = p.closeConn(cn)
  249. }
  250. func (p *ConnPool) CloseConn(cn *Conn) error {
  251. p.removeConn(cn)
  252. return p.closeConn(cn)
  253. }
  254. func (p *ConnPool) removeConn(cn *Conn) {
  255. p.connsMu.Lock()
  256. for i, c := range p.conns {
  257. if c == cn {
  258. p.conns = append(p.conns[:i], p.conns[i+1:]...)
  259. if cn.pooled {
  260. p.poolSize--
  261. p.checkMinIdleConns()
  262. }
  263. break
  264. }
  265. }
  266. p.connsMu.Unlock()
  267. }
  268. func (p *ConnPool) closeConn(cn *Conn) error {
  269. if p.opt.OnClose != nil {
  270. _ = p.opt.OnClose(cn)
  271. }
  272. return cn.Close()
  273. }
  274. // Len returns total number of connections.
  275. func (p *ConnPool) Len() int {
  276. p.connsMu.Lock()
  277. n := len(p.conns)
  278. p.connsMu.Unlock()
  279. return n
  280. }
  281. // IdleLen returns number of idle connections.
  282. func (p *ConnPool) IdleLen() int {
  283. p.connsMu.Lock()
  284. n := p.idleConnsLen
  285. p.connsMu.Unlock()
  286. return n
  287. }
  288. func (p *ConnPool) Stats() *Stats {
  289. idleLen := p.IdleLen()
  290. return &Stats{
  291. Hits: atomic.LoadUint32(&p.stats.Hits),
  292. Misses: atomic.LoadUint32(&p.stats.Misses),
  293. Timeouts: atomic.LoadUint32(&p.stats.Timeouts),
  294. TotalConns: uint32(p.Len()),
  295. IdleConns: uint32(idleLen),
  296. StaleConns: atomic.LoadUint32(&p.stats.StaleConns),
  297. }
  298. }
  299. func (p *ConnPool) closed() bool {
  300. return atomic.LoadUint32(&p._closed) == 1
  301. }
  302. func (p *ConnPool) Filter(fn func(*Conn) bool) error {
  303. var firstErr error
  304. p.connsMu.Lock()
  305. for _, cn := range p.conns {
  306. if fn(cn) {
  307. if err := p.closeConn(cn); err != nil && firstErr == nil {
  308. firstErr = err
  309. }
  310. }
  311. }
  312. p.connsMu.Unlock()
  313. return firstErr
  314. }
  315. func (p *ConnPool) Close() error {
  316. if !atomic.CompareAndSwapUint32(&p._closed, 0, 1) {
  317. return ErrClosed
  318. }
  319. var firstErr error
  320. p.connsMu.Lock()
  321. for _, cn := range p.conns {
  322. if err := p.closeConn(cn); err != nil && firstErr == nil {
  323. firstErr = err
  324. }
  325. }
  326. p.conns = nil
  327. p.poolSize = 0
  328. p.idleConns = nil
  329. p.idleConnsLen = 0
  330. p.connsMu.Unlock()
  331. return firstErr
  332. }
  333. func (p *ConnPool) reapStaleConn() *Conn {
  334. if len(p.idleConns) == 0 {
  335. return nil
  336. }
  337. cn := p.idleConns[0]
  338. if !p.isStaleConn(cn) {
  339. return nil
  340. }
  341. p.idleConns = append(p.idleConns[:0], p.idleConns[1:]...)
  342. p.idleConnsLen--
  343. return cn
  344. }
  345. func (p *ConnPool) ReapStaleConns() (int, error) {
  346. var n int
  347. for {
  348. p.getTurn()
  349. p.connsMu.Lock()
  350. cn := p.reapStaleConn()
  351. p.connsMu.Unlock()
  352. if cn != nil {
  353. p.removeConn(cn)
  354. }
  355. p.freeTurn()
  356. if cn != nil {
  357. p.closeConn(cn)
  358. n++
  359. } else {
  360. break
  361. }
  362. }
  363. return n, nil
  364. }
  365. func (p *ConnPool) reaper(frequency time.Duration) {
  366. ticker := time.NewTicker(frequency)
  367. defer ticker.Stop()
  368. for range ticker.C {
  369. if p.closed() {
  370. break
  371. }
  372. n, err := p.ReapStaleConns()
  373. if err != nil {
  374. internal.Logf("ReapStaleConns failed: %s", err)
  375. continue
  376. }
  377. atomic.AddUint32(&p.stats.StaleConns, uint32(n))
  378. }
  379. }
  380. func (p *ConnPool) isStaleConn(cn *Conn) bool {
  381. if p.opt.IdleTimeout == 0 && p.opt.MaxConnAge == 0 {
  382. return false
  383. }
  384. now := time.Now()
  385. if p.opt.IdleTimeout > 0 && now.Sub(cn.UsedAt()) >= p.opt.IdleTimeout {
  386. return true
  387. }
  388. if p.opt.MaxConnAge > 0 && now.Sub(cn.InitedAt) >= p.opt.MaxConnAge {
  389. return true
  390. }
  391. return false
  392. }