github.com/qxnw/lib4go@v0.0.0-20180426074627-c80c7e84b925/pool/pool.go (about) 1 package pool 2 3 import ( 4 "errors" 5 "fmt" 6 "sync" 7 "time" 8 ) 9 10 //pool 存放链接信息 11 type pool struct { 12 mu sync.Mutex 13 conns chan *idleConn 14 factory func() (interface{}, error) 15 close func(interface{}) error 16 done bool 17 idleTimeout time.Duration 18 } 19 20 type idleConn struct { 21 conn interface{} 22 t time.Time 23 } 24 25 //Len 连接池中已有的连接 26 func (c *pool) Len() int { 27 return len(c.getConns()) 28 } 29 30 var ( 31 //ErrClosed 连接池已经关闭Error 32 ErrClosed = errors.New("pool is closed") 33 34 // AutoReleaseTime 定时自动清除 35 TimeOut time.Duration 36 ) 37 38 //IPool 基本方法 39 type IPool interface { 40 Get() (interface{}, error) 41 42 Put(interface{}) error 43 44 Close(interface{}) error 45 46 Release() 47 48 Len() int 49 50 AutoReleaseStart() 51 } 52 53 //PoolConfigOptions 连接池相关配置 54 type PoolConfigOptions struct { 55 //连接池中拥有的最小连接数 56 InitialCap int 57 //连接池中拥有的最大的连接数 58 MaxCap int 59 //生成连接的方法 60 Factory func() (interface{}, error) 61 //关闭链接的方法 62 Close func(interface{}) error 63 //链接最大空闲时间,超过该时间则将失效 64 IdleTimeout time.Duration 65 } 66 67 //New 初始化链接 68 func New(config *PoolConfigOptions) (IPool, error) { 69 if config.InitialCap < 0 || config.MaxCap <= 0 || config.InitialCap > config.MaxCap { 70 return nil, errors.New("invalid capacity settings") 71 } 72 73 /*add by champly 2016年12月12日14:06:14*/ 74 if config.Factory == nil || config.Close == nil { 75 return nil, errors.New("invalid function settings") 76 } 77 78 // 添加设置自动清理超时连接 79 TimeOut = config.IdleTimeout 80 if TimeOut == 0 { 81 TimeOut = time.Hour * 30 82 } 83 /*end*/ 84 85 c := &pool{ 86 conns: make(chan *idleConn, config.MaxCap), 87 factory: config.Factory, 88 close: config.Close, 89 idleTimeout: config.IdleTimeout, 90 } 91 for i := 0; i < config.InitialCap; i++ { 92 conn, err := c.factory() 93 if err != nil { 94 c.Release() 95 return nil, fmt.Errorf("factory is not able to fill the pool: %s", err) 96 } 97 c.conns <- &idleConn{conn: conn, t: time.Now()} 98 } 99 100 return c, nil 101 } 102 103 //getConns 获取所有连接 104 func (c *pool) getConns() chan *idleConn { 105 c.mu.Lock() 106 conns := c.conns 107 c.mu.Unlock() 108 return conns 109 } 110 111 //Get 从pool中取一个连接 112 func (c *pool) Get() (interface{}, error) { 113 conns := c.getConns() 114 if conns == nil || c.done { 115 return nil, ErrClosed 116 } 117 for { 118 select { 119 case wrapConn := <-conns: 120 if wrapConn == nil { 121 return nil, ErrClosed 122 } 123 // 判断是否超时,超时则丢弃 124 if timeout := c.idleTimeout; timeout > 0 { 125 if wrapConn.t.Add(timeout).Before(time.Now()) { 126 //丢弃并关闭该链接 127 c.Close(wrapConn.conn) 128 continue 129 } 130 } 131 132 return wrapConn.conn, nil 133 default: 134 conn, err := c.factory() 135 if err != nil { 136 return nil, err 137 } 138 139 return conn, nil 140 } 141 } 142 } 143 144 //Put 将连接放回pool中 145 func (c *pool) Put(conn interface{}) error { 146 if conn == nil { 147 return errors.New("connection is nil. rejecting") 148 } 149 150 c.mu.Lock() 151 defer c.mu.Unlock() 152 153 if c.conns == nil || c.done { 154 return c.Close(conn) 155 } 156 157 select { 158 case c.conns <- &idleConn{conn: conn, t: time.Now()}: 159 return nil 160 default: 161 return c.Close(conn) 162 } 163 } 164 165 //Close 关闭单条连接 166 func (c *pool) Close(conn interface{}) error { 167 if conn == nil { 168 return errors.New("connection is nil. rejecting") 169 } 170 return c.close(conn) 171 } 172 173 //Release 释放连接池中所有链接 174 func (c *pool) Release() { 175 c.mu.Lock() 176 conns := c.conns 177 c.conns = nil 178 c.factory = nil 179 closeFun := c.close 180 c.close = nil 181 c.mu.Unlock() 182 183 if conns == nil { 184 return 185 } 186 187 close(conns) 188 for wrapConn := range conns { 189 closeFun(wrapConn.conn) 190 } 191 } 192 193 /*add by champly 2016年12月12日16:24:35*/ 194 // AutoReleaseTimeout 自动清除超时的连接 195 func (c *pool) AutoReleaseStart() { 196 go func() { 197 for { 198 select { 199 case <-time.After(TimeOut): 200 c.clear() 201 if c.done { 202 return 203 } 204 } 205 } 206 }() 207 } 208 209 func (c *pool) clear() { 210 start := time.Now() 211 if c.Len() > 0 { 212 c.mu.Lock() 213 conns := c.conns 214 defer c.mu.Unlock() 215 if conns == nil { 216 return 217 } 218 219 fmt.Println("pool中总连接数:", len(c.conns)) 220 length := len(c.conns) 221 for i := 0; i < length; i++ { 222 wrapConn, ok := <-conns 223 if ok { 224 if wrapConn == nil { 225 return 226 } 227 // 如果超时 228 if timeout := c.idleTimeout; timeout > 0 { 229 if wrapConn.t.Add(timeout).Before(time.Now()) { 230 c.Close(wrapConn.conn) 231 continue 232 } 233 } 234 // 如果没有超时, 写回idleConn 235 c.conns <- &idleConn{conn: wrapConn.conn, t: time.Now()} 236 } 237 } 238 } 239 240 fmt.Println("总共耗时:", time.Now().Sub(start), " 现在连接数:", len(c.conns)) 241 } 242 243 /*end*/