mirror of
https://github.com/fluencelabs/redis
synced 2025-03-19 00:50:50 +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];
|
||||
key = dictGetKey(de);
|
||||
|
||||
/* If the dictionary we are sampling from is not the main
|
||||
* dictionary (but the expires one) we need to lookup the key
|
||||
* again in the key dictionary to obtain the value object. */
|
||||
if (sampledict != keydict) de = dictFind(keydict, key);
|
||||
o = dictGetVal(de);
|
||||
if (server.maxmemory_policy != MAXMEMORY_VOLATILE_TTL) {
|
||||
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) {
|
||||
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
|
||||
* so that we expire keys starting from greater idle time.
|
||||
* 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 of 255. */
|
||||
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.
|
||||
@ -377,7 +389,9 @@ int freeMemoryIfNeeded(void) {
|
||||
dict *dict;
|
||||
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;
|
||||
|
||||
while(bestkey == NULL) {
|
||||
@ -388,8 +402,7 @@ int freeMemoryIfNeeded(void) {
|
||||
* every DB. */
|
||||
for (i = 0; i < server.dbnum; i++) {
|
||||
db = server.db+i;
|
||||
dict = (server.maxmemory_policy == MAXMEMORY_ALLKEYS_LRU ||
|
||||
server.maxmemory_policy == MAXMEMORY_ALLKEYS_LFU) ?
|
||||
dict = (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) ?
|
||||
db->dict : db->expires;
|
||||
if ((keys = dictSize(dict)) != 0) {
|
||||
evictionPoolPopulate(i, dict, db->dict, pool);
|
||||
@ -403,9 +416,7 @@ int freeMemoryIfNeeded(void) {
|
||||
if (pool[k].key == NULL) continue;
|
||||
bestdbid = pool[k].dbid;
|
||||
|
||||
if (server.maxmemory_policy == MAXMEMORY_ALLKEYS_LRU ||
|
||||
server.maxmemory_policy == MAXMEMORY_ALLKEYS_LFU)
|
||||
{
|
||||
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
|
||||
de = dictFind(server.db[pool[k].dbid].dict,
|
||||
pool[k].key);
|
||||
} 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. */
|
||||
if (bestkey) {
|
||||
db = server.db+bestdbid;
|
||||
|
@ -348,15 +348,17 @@ typedef long long mstime_t; /* millisecond time type. */
|
||||
* properties common to multiple policies is faster. */
|
||||
#define MAXMEMORY_FLAG_LRU (1<<0)
|
||||
#define MAXMEMORY_FLAG_LFU (1<<1)
|
||||
#define MAXMEMORY_FLAG_ALLKEYS (1<<2)
|
||||
#define MAXMEMORY_FLAG_NO_SHARED_INTEGERS \
|
||||
(MAXMEMORY_FLAG_LRU|MAXMEMORY_FLAG_LFU)
|
||||
|
||||
#define MAXMEMORY_VOLATILE_LRU ((0<<8)|MAXMEMORY_FLAG_LRU)
|
||||
#define MAXMEMORY_VOLATILE_LFU ((1<<8)|MAXMEMORY_FLAG_LFU)
|
||||
#define MAXMEMORY_VOLATILE_TTL (2<<8)
|
||||
#define MAXMEMORY_VOLATILE_RANDOM (3<<8)
|
||||
#define MAXMEMORY_ALLKEYS_LRU ((4<<8)|MAXMEMORY_FLAG_LRU)
|
||||
#define MAXMEMORY_ALLKEYS_LFU ((5<<8)|MAXMEMORY_FLAG_LFU)
|
||||
#define MAXMEMORY_ALLKEYS_RANDOM (6<<8)
|
||||
#define MAXMEMORY_ALLKEYS_LRU ((4<<8)|MAXMEMORY_FLAG_LRU|MAXMEMORY_FLAG_ALLKEYS)
|
||||
#define MAXMEMORY_ALLKEYS_LFU ((5<<8)|MAXMEMORY_FLAG_LFU|MAXMEMORY_FLAG_ALLKEYS)
|
||||
#define MAXMEMORY_ALLKEYS_RANDOM ((6<<8)|MAXMEMORY_FLAG_ALLKEYS)
|
||||
#define MAXMEMORY_NO_EVICTION (7<<8)
|
||||
|
||||
#define CONFIG_DEFAULT_MAXMEMORY_POLICY MAXMEMORY_NO_EVICTION
|
||||
|
Loading…
x
Reference in New Issue
Block a user