// The table's name. name string // All cached items. items map[interface{}]*CacheItem
// Timer responsible for triggering cleanup. cleanupTimer *time.Timer // 当前计时器持续时间 // Current timer duration. cleanupInterval time.Duration
// The logger used for this table. logger *log.Logger
// Callback method triggered when trying to load a non-existing key. loadData func(key interface{}, args ...interface{}) *CacheItem // Callback method triggered when adding a new item to the cache. // 触发回调函数,回调函数可以不止一个 addedItem []func(item *CacheItem) // Callback method triggered before deleting an item from the cache. aboutToDeleteItem []func(item *CacheItem) }
func(table *CacheTable)addInternal(item *CacheItem) { // Careful: do not run this method unless the table-mutex is locked! // It will unlock it for the caller before running the callbacks and checks table.log("Adding item with key", item.key, "and lifespan of", item.lifeSpan, "to table", table.name) // 将数据加入缓存中 table.items[item.key] = item
// Trigger callback after adding an item to cache. if addedItem != nil { for _, callback := range addedItem { callback(item) } }
// If we haven't set up any expiration check timer or found a more imminent item. // 如果item的过期时间小于下次检查的时间间隔,则触发过期检查,重置过期时间间隔 if item.lifeSpan > 0 && (expDur == 0 || item.lifeSpan < expDur) { table.expirationCheck() } }
// To be more accurate with timers, we would need to update 'now' on every // loop iteration. Not sure it's really efficient though. now := time.Now() smallestDuration := 0 * time.Second // 遍历缓存中的数据,找出最先过期的时间差 for key, item := range table.items { // Cache values so we don't keep blocking the mutex. item.RLock() lifeSpan := item.lifeSpan accessedOn := item.accessedOn item.RUnlock() // lifeSpan为0,代表用不过期 if lifeSpan == 0 { continue } if now.Sub(accessedOn) >= lifeSpan { // 过期的则删掉 table.deleteInternal(key) } else { // Find the item chronologically closest to its end-of-lifespan. // 这个分支中 lifeSpan-now.Sub(accessedOn) 一定大于 0,如果小于0的话,会被if拦截 if smallestDuration == 0 || lifeSpan-now.Sub(accessedOn) < smallestDuration { smallestDuration = lifeSpan - now.Sub(accessedOn) } } }
// Setup the interval for the next cleanup run. table.cleanupInterval = smallestDuration // smallestDuration <= 0时,不再执行定时检查任务 // smallestDuration 只能等于或者大于0 if smallestDuration > 0 { // smallestDuration大于0,则设置定时执行任务 table.cleanupTimer = time.AfterFunc(smallestDuration, func() { // 协程 go table.expirationCheck() }) } table.Unlock() }
// The item's key. key interface{} // The item's data. data interface{} // How long will the item live in the cache when not being accessed/kept alive. lifeSpan time.Duration
// Creation timestamp. createdOn time.Time // Last access timestamp. accessedOn time.Time // How often the item was accessed. accessCount int64
// Callback method triggered right before removing the item from the cache aboutToExpire []func(key interface{}) }