mirror of
https://github.com/fluencelabs/redis
synced 2025-03-19 09:00:51 +00:00
Volatile-ttl eviction policy implemented in terms of the pool.
Precision of the eviction improved sensibly. Also this allows us to have a single code path for most eviction types.
This commit is contained in:
parent
9f1b7ab2ed
commit
2d5eb1f1a0
65
src/evict.c
65
src/evict.c
@ -159,14 +159,21 @@ void evictionPoolPopulate(int dbid, dict *sampledict, dict *keydict, struct evic
|
|||||||
|
|
||||||
de = samples[j];
|
de = samples[j];
|
||||||
key = dictGetKey(de);
|
key = dictGetKey(de);
|
||||||
|
|
||||||
/* If the dictionary we are sampling from is not the main
|
/* If the dictionary we are sampling from is not the main
|
||||||
* dictionary (but the expires one) we need to lookup the key
|
* dictionary (but the expires one) we need to lookup the key
|
||||||
* again in the key dictionary to obtain the value object. */
|
* again in the key dictionary to obtain the value object. */
|
||||||
if (sampledict != keydict) de = dictFind(keydict, key);
|
if (server.maxmemory_policy != MAXMEMORY_VOLATILE_TTL) {
|
||||||
o = dictGetVal(de);
|
if (sampledict != keydict) de = dictFind(keydict, key);
|
||||||
|
o = dictGetVal(de);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate the idle time according to the policy. This is called
|
||||||
|
* idle just because the code initially handled LRU, but is in fact
|
||||||
|
* just a score where an higher score means better candidate. */
|
||||||
if (server.maxmemory_policy & MAXMEMORY_FLAG_LRU) {
|
if (server.maxmemory_policy & MAXMEMORY_FLAG_LRU) {
|
||||||
idle = estimateObjectIdleTime(o);
|
idle = estimateObjectIdleTime(o);
|
||||||
} else {
|
} else if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {
|
||||||
/* When we use an LRU policy, we sort the keys by idle time
|
/* When we use an LRU policy, we sort the keys by idle time
|
||||||
* so that we expire keys starting from greater idle time.
|
* so that we expire keys starting from greater idle time.
|
||||||
* However when the policy is an LFU one, we have a frequency
|
* However when the policy is an LFU one, we have a frequency
|
||||||
@ -175,6 +182,11 @@ void evictionPoolPopulate(int dbid, dict *sampledict, dict *keydict, struct evic
|
|||||||
* frequency subtracting the actual frequency to the maximum
|
* frequency subtracting the actual frequency to the maximum
|
||||||
* frequency of 255. */
|
* frequency of 255. */
|
||||||
idle = 255-LFUDecrAndReturn(o);
|
idle = 255-LFUDecrAndReturn(o);
|
||||||
|
} else if (server.maxmemory_policy == MAXMEMORY_VOLATILE_TTL) {
|
||||||
|
/* In this case the sooner the expire the better. */
|
||||||
|
idle = ULLONG_MAX - (long)dictGetVal(de);
|
||||||
|
} else {
|
||||||
|
serverPanic("Unknown eviction policy in evictionPoolPopulate()");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Insert the element inside the pool.
|
/* Insert the element inside the pool.
|
||||||
@ -377,7 +389,9 @@ int freeMemoryIfNeeded(void) {
|
|||||||
dict *dict;
|
dict *dict;
|
||||||
dictEntry *de;
|
dictEntry *de;
|
||||||
|
|
||||||
if (server.maxmemory_policy & (MAXMEMORY_FLAG_LRU|MAXMEMORY_FLAG_LFU)) {
|
if (server.maxmemory_policy & (MAXMEMORY_FLAG_LRU|MAXMEMORY_FLAG_LFU) ||
|
||||||
|
server.maxmemory_policy == MAXMEMORY_VOLATILE_TTL)
|
||||||
|
{
|
||||||
struct evictionPoolEntry *pool = EvictionPoolLRU;
|
struct evictionPoolEntry *pool = EvictionPoolLRU;
|
||||||
|
|
||||||
while(bestkey == NULL) {
|
while(bestkey == NULL) {
|
||||||
@ -388,8 +402,7 @@ int freeMemoryIfNeeded(void) {
|
|||||||
* every DB. */
|
* every DB. */
|
||||||
for (i = 0; i < server.dbnum; i++) {
|
for (i = 0; i < server.dbnum; i++) {
|
||||||
db = server.db+i;
|
db = server.db+i;
|
||||||
dict = (server.maxmemory_policy == MAXMEMORY_ALLKEYS_LRU ||
|
dict = (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) ?
|
||||||
server.maxmemory_policy == MAXMEMORY_ALLKEYS_LFU) ?
|
|
||||||
db->dict : db->expires;
|
db->dict : db->expires;
|
||||||
if ((keys = dictSize(dict)) != 0) {
|
if ((keys = dictSize(dict)) != 0) {
|
||||||
evictionPoolPopulate(i, dict, db->dict, pool);
|
evictionPoolPopulate(i, dict, db->dict, pool);
|
||||||
@ -403,9 +416,7 @@ int freeMemoryIfNeeded(void) {
|
|||||||
if (pool[k].key == NULL) continue;
|
if (pool[k].key == NULL) continue;
|
||||||
bestdbid = pool[k].dbid;
|
bestdbid = pool[k].dbid;
|
||||||
|
|
||||||
if (server.maxmemory_policy == MAXMEMORY_ALLKEYS_LRU ||
|
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
|
||||||
server.maxmemory_policy == MAXMEMORY_ALLKEYS_LFU)
|
|
||||||
{
|
|
||||||
de = dictFind(server.db[pool[k].dbid].dict,
|
de = dictFind(server.db[pool[k].dbid].dict,
|
||||||
pool[k].key);
|
pool[k].key);
|
||||||
} else {
|
} else {
|
||||||
@ -452,42 +463,6 @@ int freeMemoryIfNeeded(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* volatile-ttl */
|
|
||||||
else if (server.maxmemory_policy == MAXMEMORY_VOLATILE_TTL) {
|
|
||||||
long bestttl = 0; /* Initialized to avoid warning. */
|
|
||||||
|
|
||||||
/* In this policy we scan a single DB per iteration (visiting
|
|
||||||
* a different DB per call), expiring the key with the smallest
|
|
||||||
* TTL among the few sampled.
|
|
||||||
*
|
|
||||||
* Note that this algorithm makes local-DB choices, and should
|
|
||||||
* use a pool and code more similr to the one used in the
|
|
||||||
* LRU eviction policies in the future. */
|
|
||||||
for (i = 0; i < server.dbnum; i++) {
|
|
||||||
j = (++next_db) % server.dbnum;
|
|
||||||
db = server.db+j;
|
|
||||||
dict = db->expires;
|
|
||||||
if (dictSize(dict) != 0) {
|
|
||||||
for (k = 0; k < server.maxmemory_samples; k++) {
|
|
||||||
sds thiskey;
|
|
||||||
long thisttl;
|
|
||||||
|
|
||||||
de = dictGetRandomKey(dict);
|
|
||||||
thiskey = dictGetKey(de);
|
|
||||||
thisttl = (long) dictGetVal(de);
|
|
||||||
|
|
||||||
/* Keys expiring sooner (smaller unix timestamp) are
|
|
||||||
* better candidates for deletion */
|
|
||||||
if (bestkey == NULL || thisttl < bestttl) {
|
|
||||||
bestkey = thiskey;
|
|
||||||
bestttl = thisttl;
|
|
||||||
bestdbid = j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Finally remove the selected key. */
|
/* Finally remove the selected key. */
|
||||||
if (bestkey) {
|
if (bestkey) {
|
||||||
db = server.db+bestdbid;
|
db = server.db+bestdbid;
|
||||||
|
@ -348,15 +348,17 @@ typedef long long mstime_t; /* millisecond time type. */
|
|||||||
* properties common to multiple policies is faster. */
|
* properties common to multiple policies is faster. */
|
||||||
#define MAXMEMORY_FLAG_LRU (1<<0)
|
#define MAXMEMORY_FLAG_LRU (1<<0)
|
||||||
#define MAXMEMORY_FLAG_LFU (1<<1)
|
#define MAXMEMORY_FLAG_LFU (1<<1)
|
||||||
|
#define MAXMEMORY_FLAG_ALLKEYS (1<<2)
|
||||||
#define MAXMEMORY_FLAG_NO_SHARED_INTEGERS \
|
#define MAXMEMORY_FLAG_NO_SHARED_INTEGERS \
|
||||||
(MAXMEMORY_FLAG_LRU|MAXMEMORY_FLAG_LFU)
|
(MAXMEMORY_FLAG_LRU|MAXMEMORY_FLAG_LFU)
|
||||||
|
|
||||||
#define MAXMEMORY_VOLATILE_LRU ((0<<8)|MAXMEMORY_FLAG_LRU)
|
#define MAXMEMORY_VOLATILE_LRU ((0<<8)|MAXMEMORY_FLAG_LRU)
|
||||||
#define MAXMEMORY_VOLATILE_LFU ((1<<8)|MAXMEMORY_FLAG_LFU)
|
#define MAXMEMORY_VOLATILE_LFU ((1<<8)|MAXMEMORY_FLAG_LFU)
|
||||||
#define MAXMEMORY_VOLATILE_TTL (2<<8)
|
#define MAXMEMORY_VOLATILE_TTL (2<<8)
|
||||||
#define MAXMEMORY_VOLATILE_RANDOM (3<<8)
|
#define MAXMEMORY_VOLATILE_RANDOM (3<<8)
|
||||||
#define MAXMEMORY_ALLKEYS_LRU ((4<<8)|MAXMEMORY_FLAG_LRU)
|
#define MAXMEMORY_ALLKEYS_LRU ((4<<8)|MAXMEMORY_FLAG_LRU|MAXMEMORY_FLAG_ALLKEYS)
|
||||||
#define MAXMEMORY_ALLKEYS_LFU ((5<<8)|MAXMEMORY_FLAG_LFU)
|
#define MAXMEMORY_ALLKEYS_LFU ((5<<8)|MAXMEMORY_FLAG_LFU|MAXMEMORY_FLAG_ALLKEYS)
|
||||||
#define MAXMEMORY_ALLKEYS_RANDOM (6<<8)
|
#define MAXMEMORY_ALLKEYS_RANDOM ((6<<8)|MAXMEMORY_FLAG_ALLKEYS)
|
||||||
#define MAXMEMORY_NO_EVICTION (7<<8)
|
#define MAXMEMORY_NO_EVICTION (7<<8)
|
||||||
|
|
||||||
#define CONFIG_DEFAULT_MAXMEMORY_POLICY MAXMEMORY_NO_EVICTION
|
#define CONFIG_DEFAULT_MAXMEMORY_POLICY MAXMEMORY_NO_EVICTION
|
||||||
|
Loading…
x
Reference in New Issue
Block a user