gitee.com/quant1x/gox@v1.21.2/pool/channel.go (about) 1 package pool 2 3 import ( 4 "errors" 5 "fmt" 6 "gitee.com/quant1x/gox/logger" 7 "sync" 8 "time" 9 ) 10 11 // Config 连接池相关配置 12 type Config struct { 13 //连接池中拥有的最小连接数 14 InitialCap int 15 //最大并发存活连接数 16 MaxCap int 17 //最大空闲连接 18 MaxIdle int 19 //生成连接的方法 20 Factory func() (any, error) 21 //关闭连接的方法 22 Close func(any) error 23 //检查连接是否有效的方法 24 Ping func(any) error 25 //连接最大空闲时间,超过该事件则将失效 26 IdleTimeout time.Duration 27 } 28 29 type connReq struct { 30 idleConn *idleConn 31 } 32 33 // channelPool 存放连接信息 34 type channelPool struct { 35 mu sync.RWMutex // 读写锁 36 conns chan *idleConn // 空闲连接 37 idleTimeout time.Duration // 空闲时间 38 waitTimeOut time.Duration // 等待时间 39 maxActive int // 最大活跃数 40 openingConns int // 打开连接数 41 connReqs []chan connReq // 池满后请求新连接的队列 42 factory func() (any, error) // 新连接工厂 43 close func(any) error // 关闭 44 ping func(any) error // ping 45 } 46 47 type idleConn struct { 48 conn any 49 t time.Time 50 } 51 52 // NewChannelPool 初始化连接 53 func NewChannelPool(poolConfig *Config) (Pool, error) { 54 if !(poolConfig.InitialCap <= poolConfig.MaxIdle && poolConfig.MaxCap >= poolConfig.MaxIdle && poolConfig.InitialCap >= 0) { 55 return nil, errors.New("invalid capacity settings") 56 } 57 logger.Warnf("init connect pool: MaxCap=%d, InitialCap=%d, MaxIdle=%d", poolConfig.MaxCap, poolConfig.InitialCap, poolConfig.MaxIdle) 58 if poolConfig.Factory == nil { 59 return nil, errors.New("invalid factory func settings") 60 } 61 if poolConfig.Close == nil { 62 return nil, errors.New("invalid close func settings") 63 } 64 65 c := &channelPool{ 66 conns: make(chan *idleConn, poolConfig.MaxIdle), 67 factory: poolConfig.Factory, 68 close: poolConfig.Close, 69 idleTimeout: poolConfig.IdleTimeout, 70 maxActive: poolConfig.MaxCap, 71 openingConns: poolConfig.InitialCap, 72 } 73 74 if poolConfig.Ping != nil { 75 c.ping = poolConfig.Ping 76 } 77 78 for i := 0; i < poolConfig.InitialCap; i++ { 79 conn, err := c.factory() 80 if err != nil { 81 c.Release() 82 return nil, fmt.Errorf("factory is not able to fill the pool: %s", err) 83 } 84 c.conns <- &idleConn{conn: conn, t: time.Now()} 85 } 86 87 return c, nil 88 } 89 90 // getConns 获取所有连接 91 func (c *channelPool) getConns() chan *idleConn { 92 c.mu.Lock() 93 conns := c.conns 94 c.mu.Unlock() 95 return conns 96 } 97 98 // Get 从pool中取一个连接 99 func (c *channelPool) Get() (any, error) { 100 conns := c.getConns() 101 if conns == nil { 102 return nil, ErrClosed 103 } 104 for { 105 select { 106 case wrapConn := <-conns: 107 if wrapConn == nil { 108 return nil, ErrClosed 109 } 110 //判断是否超时,超时则丢弃 111 if timeout := c.idleTimeout; timeout > 0 { 112 if wrapConn.t.Add(timeout).Before(time.Now()) { 113 logger.Warnf("空闲超时, 关闭连接.") 114 //丢弃并关闭该连接 115 _ = c.Close(wrapConn.conn) 116 continue 117 } 118 } 119 //判断是否失效,失效则丢弃,如果用户没有设定 ping 方法,就不检查 120 if c.ping != nil { 121 if err := c.Ping(wrapConn.conn); err != nil { 122 logger.Warnf("ping失败, 关闭连接.") 123 _ = c.Close(wrapConn.conn) 124 continue 125 } 126 } 127 return wrapConn.conn, nil 128 default: 129 c.mu.Lock() 130 //logger.Warnf("default-1") 131 if c.openingConns >= c.maxActive { 132 //logger.Warnf("default-1: 1") 133 req := make(chan connReq, 1) 134 c.connReqs = append(c.connReqs, req) 135 c.mu.Unlock() 136 ret, ok := <-req 137 if !ok { 138 //logger.Warnf("default-1: 1-1") 139 return nil, ErrMaxActiveConnReached 140 } 141 //logger.Warnf("default-1: 2") 142 if timeout := c.idleTimeout; timeout > 0 { 143 //logger.Warnf("default-1: 2-1") 144 if ret.idleConn.t.Add(timeout).Before(time.Now()) { 145 //丢弃并关闭该连接 146 //logger.Warnf("default-1: 2-1-1") 147 logger.Warnf("超时, 关闭连接.") 148 _ = c.Close(ret.idleConn.conn) 149 continue 150 } 151 //logger.Warnf("default-1: 2-2") 152 } 153 //logger.Warnf("default-1: 3") 154 return ret.idleConn.conn, nil 155 } 156 //logger.Warnf("default-2") 157 if c.factory == nil { 158 //logger.Warnf("default-2: 1") 159 c.mu.Unlock() 160 return nil, ErrClosed 161 } 162 //logger.Warnf("default-3") 163 conn, err := c.factory() 164 if err != nil { 165 //logger.Warnf("default-3: 1") 166 c.mu.Unlock() 167 return nil, err 168 } 169 //logger.Warnf("default-4") 170 c.openingConns++ 171 c.mu.Unlock() 172 return conn, nil 173 } 174 } 175 } 176 177 // Put 将连接放回pool中 178 func (c *channelPool) Put(conn any) error { 179 if conn == nil { 180 return ErrIsNil 181 } 182 183 c.mu.Lock() 184 185 if c.conns == nil { 186 c.mu.Unlock() 187 logger.Warnf("队列无效, 关闭连接.") 188 return c.Close(conn) 189 } 190 191 if l := len(c.connReqs); l > 0 { 192 req := c.connReqs[0] 193 copy(c.connReqs, c.connReqs[1:]) 194 c.connReqs = c.connReqs[:l-1] 195 req <- connReq{ 196 idleConn: &idleConn{conn: conn, t: time.Now()}, 197 } 198 c.mu.Unlock() 199 return nil 200 } else { 201 select { 202 case c.conns <- &idleConn{conn: conn, t: time.Now()}: 203 c.mu.Unlock() 204 return nil 205 default: 206 c.mu.Unlock() 207 //连接池已满,直接关闭该连接 208 logger.Warnf("返还连接, 连接池已满, 关闭连接.") 209 return c.Close(conn) 210 } 211 } 212 } 213 214 // Close 关闭单条连接 215 func (c *channelPool) Close(conn any) error { 216 if conn == nil { 217 return ErrIsNil 218 } 219 c.mu.Lock() 220 defer c.mu.Unlock() 221 if c.close == nil { 222 return nil 223 } 224 c.openingConns-- 225 return c.close(conn) 226 } 227 228 // Ping 检查单条连接是否有效 229 func (c *channelPool) Ping(conn any) error { 230 if conn == nil { 231 return ErrIsNil 232 } 233 return c.ping(conn) 234 } 235 236 // Release 释放连接池中所有连接 237 func (c *channelPool) Release() { 238 c.mu.Lock() 239 conns := c.conns 240 c.conns = nil 241 c.factory = nil 242 c.ping = nil 243 closeFun := c.close 244 c.close = nil 245 c.mu.Unlock() 246 247 if conns == nil { 248 return 249 } 250 251 close(conns) 252 for wrapConn := range conns { 253 _ = closeFun(wrapConn.conn) 254 } 255 } 256 257 // CloseAll 仅关闭连接池中所有连接 258 func (c *channelPool) CloseAll() { 259 c.mu.Lock() 260 defer c.mu.Unlock() 261 if c.conns == nil || c.close == nil { 262 return 263 } 264 select { 265 case wrapConn := <-c.conns: 266 _ = c.close(wrapConn.conn) 267 c.openingConns-- 268 default: 269 break 270 } 271 } 272 273 // Len 连接池中已有的连接 274 func (c *channelPool) Len() int { 275 return len(c.getConns()) 276 }