在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