在database库下清除过时链接时,使用了以下的代码逻辑。其中freeConn是空闲链接池,d是链接可被重复使用的最长时间,nowFunc返回的是当前时间。最新生成的链接在freeConn的末尾,而清除的过程则是使用最新的、次新的链接依次替换最先过时的、次早过时的链接。缓存
在for循环中直接使用len来获取总计数,在循环体内部将freeConn末尾的值替换首部的值,并将freeConn的len长度减去1。最后还作了i—
操做,重复校验了一次。app
expiredSince := nowFunc().Add(-d) var closing []*driverConn for i := 0; i < len(db.freeConn); i++ { c := db.freeConn[i] if c.createdAt.Before(expiredSince) { closing = append(closing, c) last := len(db.freeConn) - 1 db.freeConn[i] = db.freeConn[last] db.freeConn[last] = nil db.freeConn = db.freeConn[:last] i-- } }
slice中首部和尾部数据的交换过程,以及每次经过i--
达到的重复校验的思路。函数
清除无效链接的工做是由一个goroutine在后台完成的,下面是截取的部分代码。for循环内部是处理链接的具体实现。每次清除操做完成后,经过Reset来重置Timer。学习
func (db *DB) connectionCleaner(d time.Duration) { const minInterval = time.Second if d < minInterval { d = minInterval } t := time.NewTimer(d) for { select { case <-t.C: case <-db.cleanerCh: // maxLifetime was changed or db was closed. } if d < minInterval { d = minInterval } t.Reset(d) } }
学习NewTimer函数的使用,它在声明后仅仅执行一次。经过Reset来从新使他生效。这样能够忽略操做执行的具体时间,每次都在上次操做完成后,间隔固定时间,再执行下一次操做。code
还能够对比NewTicker作比较。io
从freeConn中获取一个缓存的链接,拿到链接以后并将它从freeConn中移除。同时,校验链接是否已经超过最大链接使用时间。for循环
if strategy == cachedOrNewConn && numFree > 0 { conn := db.freeConn[0] copy(db.freeConn, db.freeConn[1:]) db.freeConn = db.freeConn[:numFree-1] conn.inUse = true db.mu.Unlock() if conn.expired(lifetime) { conn.Close() return nil, driver.ErrBadConn } return conn, nil }
使用copy对slice的第一个元素进行移除。同时,经过从新赋值来修改slice的len属性。ast