github.com/hdt3213/godis@v1.2.9/lib/pool/pool.go (about) 1 package pool 2 3 import ( 4 "errors" 5 "sync" 6 ) 7 8 var ( 9 ErrClosed = errors.New("pool closed") 10 ErrMax = errors.New("reach max connection limit") 11 ) 12 13 type request chan interface{} 14 15 type Config struct { 16 MaxIdle uint 17 MaxActive uint 18 } 19 20 // Pool stores object for reusing, such as redis connection 21 type Pool struct { 22 Config 23 factory func() (interface{}, error) 24 finalizer func(x interface{}) 25 idles chan interface{} 26 waitingReqs []request 27 activeCount uint // increases during creating connection, decrease during destroying connection 28 mu sync.Mutex 29 closed bool 30 } 31 32 func New(factory func() (interface{}, error), finalizer func(x interface{}), cfg Config) *Pool { 33 return &Pool{ 34 factory: factory, 35 finalizer: finalizer, 36 idles: make(chan interface{}, cfg.MaxIdle), 37 waitingReqs: make([]request, 0), 38 Config: cfg, 39 } 40 } 41 42 // getOnNoIdle try to create a new connection or waiting for connection being returned 43 // invoker should have pool.mu 44 func (pool *Pool) getOnNoIdle() (interface{}, error) { 45 if pool.activeCount >= pool.MaxActive { 46 // waiting for connection being returned 47 req := make(chan interface{}, 1) 48 pool.waitingReqs = append(pool.waitingReqs, req) 49 pool.mu.Unlock() 50 x, ok := <-req 51 if !ok { 52 return nil, ErrMax 53 } 54 return x, nil 55 } 56 57 // create a new connection 58 pool.activeCount++ // hold a place for new connection 59 pool.mu.Unlock() 60 x, err := pool.factory() 61 if err != nil { 62 // create failed return token 63 pool.mu.Lock() 64 pool.activeCount-- // release the holding place 65 pool.mu.Unlock() 66 return nil, err 67 } 68 return x, nil 69 } 70 71 func (pool *Pool) Get() (interface{}, error) { 72 pool.mu.Lock() 73 if pool.closed { 74 pool.mu.Unlock() 75 return nil, ErrClosed 76 } 77 78 select { 79 case item := <-pool.idles: 80 pool.mu.Unlock() 81 return item, nil 82 default: 83 // no pooled item, create one 84 return pool.getOnNoIdle() 85 } 86 } 87 88 func (pool *Pool) Put(x interface{}) { 89 pool.mu.Lock() 90 91 if pool.closed { 92 pool.mu.Unlock() 93 pool.finalizer(x) 94 return 95 } 96 97 if len(pool.waitingReqs) > 0 { 98 req := pool.waitingReqs[0] 99 copy(pool.waitingReqs, pool.waitingReqs[1:]) 100 pool.waitingReqs = pool.waitingReqs[:len(pool.waitingReqs)-1] 101 req <- x 102 pool.mu.Unlock() 103 return 104 } 105 106 select { 107 case pool.idles <- x: 108 pool.mu.Unlock() 109 return 110 default: 111 // reach max idle, destroy redundant item 112 pool.mu.Unlock() 113 pool.activeCount-- 114 pool.finalizer(x) 115 } 116 } 117 118 func (pool *Pool) Close() { 119 pool.mu.Lock() 120 if pool.closed { 121 pool.mu.Unlock() 122 return 123 } 124 pool.closed = true 125 close(pool.idles) 126 pool.mu.Unlock() 127 128 for x := range pool.idles { 129 pool.finalizer(x) 130 } 131 }