This is a creation in Article, where the information may have evolved or changed.
Structural Body Analysis
type Pool struct { // 用来创建redis连接的方法 Dial func() (Conn, error) // 如果设置了给func,那么每次p.Get()的时候都会调用改方法来验证连接的可用性 TestOnBorrow func(c Conn, t time.Time) error // 定义连接池中最大连接数(超过这个数会关闭老的链接,总会保持这个数) MaxIdle int // 当前连接池中可用的链接数. MaxActive int // 定义链接的超时时间,每次p.Get()的时候会检测这个连接是否超时(超时会关闭,并释放可用连接数). IdleTimeout time.Duration // 当可用连接数为0是,那么当wait=true,那么当调用p.Get()时,会阻塞等待,否则,返回nil. Wait bool // 读写锁控制. mu sync.Mutex // 用来条件控制,这里主要是当链接被关闭时,提醒在等待的进程可以使用了,或者可以自行创建了 cond *sync.Cond // 当前连接池是否已经关闭 closed bool // 当前可用的链接数 active int // 链接存储在一个栈中. idle list.List}
Connection pooling Shutdown method
func (p *Pool) Close() error { p.mu.Lock() // 获取连接池所有链接栈 idle := p.idle // 重新初始化 p.idle.Init() // 标示已经关闭 p.closed = true // 控制可用连接数 p.active -= idle.Len() // 如果当前有进程正在等待获取的话,则通知可以获取或者自行创建 if p.cond != nil { p.cond.Broadcast() } p.mu.Unlock() // 遍历栈,逐个关闭链接 for e := idle.Front(); e != nil; e = e.Next() { e.Value.(idleConn).c.Close() } return nil}
Release a link
func (p *Pool) release() { // 当链接超时,或者ping不通,或者创建失败,则立即使用链接表示 p.active -= 1 // 如果已经有进程在之前等待了,则通知其使用或者自行创建 if p.cond != nil { p.cond.Signal() }}
Close connection
func (p *Pool) put(c Conn, forceClose bool) error { err := c.Err() p.mu.Lock() // 如果连接池没有关闭,并且不是强制关闭的 if !p.closed && err == nil && !forceClose { // 把指定的链接放在空闲栈首位 p.idle.PushFront(idleConn{t: nowFunc(), c: c}) // 如果栈的长度大于指定长度,则吧最后一个(可能超时)剔除 if p.idle.Len() > p.MaxIdle { c = p.idle.Remove(p.idle.Back()).(idleConn).c } else { c = nil } } if c == nil { //成功放回空闲连接通知其他阻塞的进程 if p.cond != nil { p.cond.Signal() } p.mu.Unlock() return nil } // 减少active计数(感觉这里可以不用处理,上面如果是替换的话) p.release() p.mu.Unlock() // 关闭连接 return c.Close()}
Get links
Func (P *pool) get (Conn, error) {P.mu.lock ()//Handle old link (detect if timeout) if timeout: = p.idletimeout; Timeout > 0 { For I, N: = 0, P.idle.len (); I < n; i++ {e: = P.idle.back () if E = = nil {break} IC: = E.value. ( Idleconn)//The time that the link was created plus whether the time-out is less than the current time if Ic.t.add (timeout). After (Nowfunc ()) {break}//Timeout link, remove P.idle.remove (e)//available from stack The number of connections is reduced and other waiting processes are notified to process P.release () P.mu.unlock ()//Close the current connection ic.c.close () P.mu.lock ()}} for {//Gets an available link from the list of connection stacks for I, N: = 0, P.idle.len (); i < n; i++ { Connect from the front of the idle list, then it must be the connection you just used e: = P.idle.front () if E = = nil {break} Type assertion IC: = E.value. (idleconn)//Remove P.idle.remove from the stack (e) Test: = P.testonborrow P.mu.unlock ()//Check link if test = Nil by using Check link function | | Test (IC.C, ic.t) = = Nil {return ic.c, nil}//Check for problems, close connection ic.c.close () P.mu.lock ()//reduces the number of available connections and notifies other processes that processing p.release ()}//detects if the connection pool has been closed. If p.closed {p.mu.unlock () return nil, errors. New ("Redigo:get on Closed Pool")}//If the number of available connections is 0 or less than the maximum available number of available connections, create if p.maxactive = = 0 | | P.active < p.maxactive {dial: = p.dial p.active + 1 P.mu.unlock ()//Connect RE Dis Server c, err: = dial ()//connection failure closed if err! = Nil {P.mu.lock () P.release () P.mu.unlock () c = nil} return c, err} If no wait is configured, then return nil if!p.wait {p.mu.unlock () return nil, errpoolexhausted} If you configure the wait, thatInitialize, and start waiting until there is a process to notify the link number enough or you can create if P.cond = = Nil {P.cond = sync. Newcond (&P.MU)} p.cond.wait ()}}