首先看下serverCron中,服務器每次循環執行的時候,都會刷新server.lrulock。redis
int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) { ... server.lruclock = getLRUClock(); ...
使用的方法是getLRUClock,LRU_CLOCK_RESOLUTION表明LRU算法的精度,即一個LRU的單位是多長時間。LRU_CLOCK_MAX表明邏輯時鐘的最大位數,相似現實中的錶盤,劃分了最大的刻度,一個刻度是一個LRU大小。因此整個方法表示的含義爲:當前時間是LRU的單位的多少倍,即已通過了多少個LRU,而後對最大刻度LRU_CLOCK_MAX取模。算法
unsigned int getLRUClock(void) { return (mstime()/LRU_CLOCK_RESOLUTION) & LRU_CLOCK_MAX; }
瞭解以上概念後,再看到建立object對象的時候,會給其lru屬性賦值,下次被訪問時也會更新。服務器
robj *createObject(int type, void *ptr) { robj *o = zmalloc(sizeof(*o)); o->type = type; o->encoding = OBJ_ENCODING_RAW; o->ptr = ptr; o->refcount = 1; /* Set the LRU to the current lruclock (minutes resolution). */ o->lru = LRU_CLOCK(); return o; }
/* Low level key lookup API, not actually called directly from commands * implementations that should instead rely on lookupKeyRead(), * lookupKeyWrite() and lookupKeyReadWithFlags(). */ robj *lookupKey(redisDb *db, robj *key, int flags) { dictEntry *de = dictFind(db->dict,key->ptr); if (de) { robj *val = dictGetVal(de); /* Update the access time for the ageing algorithm. * Don't do it if we have a saving child, as this will trigger * a copy on write madness. */ if (server.rdb_child_pid == -1 && server.aof_child_pid == -1 && !(flags & LOOKUP_NOTOUCH)) { val->lru = LRU_CLOCK(); } return val; } else { return NULL; } }
使用的方法是LRU_CLOCK,server.hz表明服務器刷新的頻率,意思是若是服務器的時間更新精度值比LRU的精度值要小(精度值表示一次刷新的間隔時間,越小精度越高),說明服務器的精度更高,直接用服務器的時間。舉例若是服務器精度是10ms, LRU精度是100ms,則在100ms內服務器進行10次刷新,獲得的server.lrulock都是同樣,既然如此,沒必要調用getLRUCLOCK()函數增長額外的開銷。app
/* Macro used to obtain the current LRU clock. * If the current resolution is lower than the frequency we refresh the * LRU clock (as it should be in production servers) we return the * precomputed value, otherwise we need to resort to a system call. */ #define LRU_CLOCK() ((1000/server.hz <= LRU_CLOCK_RESOLUTION) ? server.lruclock : getLRUClock())
那麼obj的lru值是如何使用的呢,判斷一個key是否須要過時淘汰時,先計算其最近沒有使用的時間,方法以下:獲取當前時鐘,若是obj的lru小於當前時鐘,則獲取obj到當前時鐘間隔了多少個LRU單位時間,再乘以LRU_CLOCK_RESOLUTION即獲得真實毫秒數。函數
/* Given an object returns the min number of milliseconds the object was never * requested, using an approximated LRU algorithm. */ unsigned long long estimateObjectIdleTime(robj *o) { unsigned long long lruclock = LRU_CLOCK(); if (lruclock >= o->lru) { return (lruclock - o->lru) * LRU_CLOCK_RESOLUTION; } else { return (lruclock + (LRU_CLOCK_MAX - o->lru)) * LRU_CLOCK_RESOLUTION; } }