gitee.com/quant1x/gox@v1.7.6/pool/channel.go (about)

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