LFU: Initial naive eviction cycle.

It is possible to get better results by using the pool like in the LRU
case. Also from tests during the morning I believe the current
implementation has issues in the frequency decay function that should
decrease the counter at periodic intervals.
This commit is contained in:
antirez 2016-07-18 13:49:31 +02:00
parent 24dd4a8f04
commit a8e2d0849e
3 changed files with 49 additions and 4 deletions

View File

@ -175,7 +175,14 @@ void dbOverwrite(redisDb *db, robj *key, robj *val) {
dictEntry *de = dictFind(db->dict,key->ptr);
serverAssertWithInfo(NULL,key,de != NULL);
dictReplace(db->dict, key->ptr, val);
if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {
robj *old = dictGetVal(de);
int saved_lru = old->lru;
dictReplace(db->dict, key->ptr, val);
val->lru = saved_lru;
} else {
dictReplace(db->dict, key->ptr, val);
}
}
/* High level Set operation. This function can be used in order to set

View File

@ -294,6 +294,7 @@ unsigned long LFUDecrAndReturn(robj *o) {
if (LFUTimeElapsed(ldt) > LFU_DECR_INTERVAL && counter) {
if (counter > LFU_INIT_VAL*2) {
counter /= 2;
if (counter < LFU_INIT_VAL*2) counter = LFU_INIT_VAL*2;
} else {
counter--;
}
@ -360,9 +361,7 @@ int freeMemoryIfNeeded(void) {
dict *dict;
dictEntry *de;
if (server.maxmemory_policy == MAXMEMORY_ALLKEYS_LRU ||
server.maxmemory_policy == MAXMEMORY_VOLATILE_LRU)
{
if (server.maxmemory_policy & MAXMEMORY_FLAG_LRU) {
struct evictionPoolEntry *pool = EvictionPoolLRU;
while(bestkey == NULL) {
@ -470,6 +469,37 @@ int freeMemoryIfNeeded(void) {
}
}
/* allkeys-lfu and volatile-lfu */
else if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {
long bestfreq = 0; /* Initialized to avoid warning. */
for (i = 0; i < server.dbnum; i++) {
j = (++next_db) % server.dbnum;
db = server.db+j;
dict = (server.maxmemory_policy == MAXMEMORY_ALLKEYS_LFU) ?
db->dict : db->expires;
if (dictSize(dict) != 0) {
for (k = 0; k < server.maxmemory_samples; k++) {
sds thiskey;
long thisfreq;
de = dictGetRandomKey(dict);
thiskey = dictGetKey(de);
robj *o = dictFetchValue(db->dict,thiskey);
thisfreq = LFUDecrAndReturn(o);
/* Keys with a smaller access frequency are
* better candidates for deletion */
if (bestkey == NULL || thisfreq < bestfreq) {
bestkey = thiskey;
bestfreq = thisfreq;
bestdbid = j;
}
}
}
}
}
/* Finally remove the selected key. */
if (bestkey) {
db = server.db+bestdbid;

View File

@ -722,10 +722,18 @@ void objectCommand(client *c) {
} else if (!strcasecmp(c->argv[1]->ptr,"idletime") && c->argc == 3) {
if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nullbulk))
== NULL) return;
if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {
addReplyError(c,"An LFU maxmemory policy is selected, idle time not tracked. Please note that when switching between policies at runtime LRU and LFU data will take some time to adjust.");
return;
}
addReplyLongLong(c,estimateObjectIdleTime(o)/1000);
} else if (!strcasecmp(c->argv[1]->ptr,"freq") && c->argc == 3) {
if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nullbulk))
== NULL) return;
if (server.maxmemory_policy & MAXMEMORY_FLAG_LRU) {
addReplyError(c,"An LRU maxmemory policy is selected, access frequency not tracked. Please note that when switching between policies at runtime LRU and LFU data will take some time to adjust.");
return;
}
addReplyLongLong(c,o->lru&255);
} else {
addReplyError(c,"Syntax error. Try OBJECT (refcount|encoding|idletime|freq)");