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  }