共计 1335 个字符,预计需要花费 4 分钟才能阅读完成。
清除无效连接
在 database 库下清除过期连接时,使用了如下的代码逻辑。其中 freeConn 是空闲连接池,d 是连接可被重复使用的最长时间,nowFunc 返回的是当前时间。最新生成的连接在 freeConn 的末尾,而清除的过程则是使用最新的、次新的连接依次替换最早过期的、次早过期的连接。
在 for 循环中直接使用 len 来获取总计数,在循环体内部将 freeConn 末尾的值替换首部的值,并将 freeConn 的 len 长度减去 1。最后还做了 i—
操作,重复校验了一次。
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 来重新使他生效。这样可以忽略操作执行的具体时间,每次都在上次操作完成后,间隔固定时间,再执行下一次操作。
还可以对比 NewTicker 做比较。
获取连接
从 freeConn 中获取一个缓存的连接,拿到连接之后并将它从 freeConn 中移除。同时,校验连接是否已经超过最大连接使用时间。
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 属性。
正文完