summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2016-07-18 13:49:31 +0200
committerantirez <antirez@gmail.com>2016-07-18 13:50:19 +0200
commita8e2d0849e2a40f8bec14cd1b7ff170c17f772c3 (patch)
treeef6ea43c6ed64418c3759892417783de078a3fb1
parent24dd4a8f0444377af55cb1842ff0cfd5a8f74788 (diff)
downloadredis-a8e2d0849e2a40f8bec14cd1b7ff170c17f772c3.tar.gz
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.
-rw-r--r--src/db.c9
-rw-r--r--src/evict.c36
-rw-r--r--src/object.c8
3 files changed, 49 insertions, 4 deletions
diff --git a/src/db.c b/src/db.c
index b00227d81..d33c810b3 100644
--- a/src/db.c
+++ b/src/db.c
@@ -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
diff --git a/src/evict.c b/src/evict.c
index 753a2ac81..b48892b41 100644
--- a/src/evict.c
+++ b/src/evict.c
@@ -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;
diff --git a/src/object.c b/src/object.c
index 8f19f60f2..c64d810b0 100644
--- a/src/object.c
+++ b/src/object.c
@@ -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)");