database package

清除無效鏈接

在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

相關文章
相關標籤/搜索