mirror of
https://github.com/fluencelabs/redis
synced 2025-06-20 20:46:31 +00:00
implemented different algorithms for maxmemory
This commit is contained in:
104
src/redis.c
104
src/redis.c
@ -478,6 +478,10 @@ void activeExpireCycle(void) {
|
||||
}
|
||||
}
|
||||
|
||||
void updateLRUClock(void) {
|
||||
server.lruclock = (time(NULL)/REDIS_LRU_CLOCK_RESOLUTION) &
|
||||
REDIS_LRU_CLOCK_MAX;
|
||||
}
|
||||
|
||||
int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
|
||||
int j, loops = server.cronloops++;
|
||||
@ -491,14 +495,18 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
|
||||
* To access a global var is faster than calling time(NULL) */
|
||||
server.unixtime = time(NULL);
|
||||
/* We have just 22 bits per object for LRU information.
|
||||
* So we use an (eventually wrapping) LRU clock with minutes resolution.
|
||||
* 2^22 minutes are more than 7 years.
|
||||
* So we use an (eventually wrapping) LRU clock with 10 seconds resolution.
|
||||
* 2^22 bits with 10 seconds resoluton is more or less 1.5 years.
|
||||
*
|
||||
* Note that even if this will wrap after 7 years it's not a problem,
|
||||
* Note that even if this will wrap after 1.5 years it's not a problem,
|
||||
* everything will still work but just some object will appear younger
|
||||
* to Redis :)
|
||||
* to Redis. But for this to happen a given object should never be touched
|
||||
* for 1.5 years.
|
||||
*
|
||||
* Note that you can change the resolution altering the
|
||||
* REDIS_LRU_CLOCK_RESOLUTION define.
|
||||
*/
|
||||
server.lruclock = (time(NULL)/60) & REDIS_LRU_CLOCK_MAX;
|
||||
updateLRUClock();
|
||||
|
||||
/* We received a SIGTERM, shutting down here in a safe way, as it is
|
||||
* not ok doing so inside the signal handler. */
|
||||
@ -729,6 +737,8 @@ void initServerConfig() {
|
||||
server.maxclients = 0;
|
||||
server.blpop_blocked_clients = 0;
|
||||
server.maxmemory = 0;
|
||||
server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_LRU;
|
||||
server.maxmemory_samples = 3;
|
||||
server.vm_enabled = 0;
|
||||
server.vm_swap_file = zstrdup("/tmp/redis-%p.vm");
|
||||
server.vm_page_size = 256; /* 256 bytes per page */
|
||||
@ -742,6 +752,7 @@ void initServerConfig() {
|
||||
server.list_max_ziplist_value = REDIS_LIST_MAX_ZIPLIST_VALUE;
|
||||
server.set_max_intset_entries = REDIS_SET_MAX_INTSET_ENTRIES;
|
||||
server.shutdown_asap = 0;
|
||||
updateLRUClock();
|
||||
|
||||
resetServerSaveParams();
|
||||
|
||||
@ -1327,10 +1338,93 @@ int tryFreeOneObjectFromFreelist(void) {
|
||||
* memory usage.
|
||||
*/
|
||||
void freeMemoryIfNeeded(void) {
|
||||
/* Remove keys accordingly to the active policy as long as we are
|
||||
* over the memory limit. */
|
||||
while (server.maxmemory && zmalloc_used_memory() > server.maxmemory) {
|
||||
int j, k, freed = 0;
|
||||
|
||||
/* Basic strategy -- remove objects from the free list. */
|
||||
if (tryFreeOneObjectFromFreelist() == REDIS_OK) continue;
|
||||
|
||||
for (j = 0; j < server.dbnum; j++) {
|
||||
long bestval;
|
||||
sds bestkey = NULL;
|
||||
struct dictEntry *de;
|
||||
redisDb *db = server.db+j;
|
||||
dict *dict;
|
||||
|
||||
if (server.maxmemory_policy == REDIS_MAXMEMORY_ALLKEYS_LRU ||
|
||||
server.maxmemory_policy == REDIS_MAXMEMORY_ALLKEYS_RANDOM)
|
||||
{
|
||||
dict = server.db[j].dict;
|
||||
} else {
|
||||
dict = server.db[j].expires;
|
||||
}
|
||||
if (dictSize(dict) == 0) continue;
|
||||
|
||||
/* volatile-random and allkeys-random policy */
|
||||
if (server.maxmemory_policy == REDIS_MAXMEMORY_ALLKEYS_RANDOM ||
|
||||
server.maxmemory_policy == REDIS_MAXMEMORY_VOLATILE_RANDOM)
|
||||
{
|
||||
de = dictGetRandomKey(dict);
|
||||
bestkey = dictGetEntryKey(de);
|
||||
}
|
||||
|
||||
/* volatile-lru and allkeys-lru policy */
|
||||
else if (server.maxmemory_policy == REDIS_MAXMEMORY_ALLKEYS_LRU ||
|
||||
server.maxmemory_policy == REDIS_MAXMEMORY_VOLATILE_LRU)
|
||||
{
|
||||
for (k = 0; k < server.maxmemory_samples; k++) {
|
||||
sds thiskey;
|
||||
long thisval;
|
||||
robj *o;
|
||||
|
||||
de = dictGetRandomKey(dict);
|
||||
thiskey = dictGetEntryKey(de);
|
||||
o = dictGetEntryVal(de);
|
||||
thisval = estimateObjectIdleTime(o);
|
||||
|
||||
/* Higher idle time is better candidate for deletion */
|
||||
if (bestkey == NULL || thisval > bestval) {
|
||||
bestkey = thiskey;
|
||||
bestval = thisval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* volatile-ttl */
|
||||
else if (server.maxmemory_policy == REDIS_MAXMEMORY_VOLATILE_TTL) {
|
||||
for (k = 0; k < server.maxmemory_samples; k++) {
|
||||
sds thiskey;
|
||||
long thisval;
|
||||
|
||||
de = dictGetRandomKey(dict);
|
||||
thiskey = dictGetEntryKey(de);
|
||||
thisval = (long) dictGetEntryVal(de);
|
||||
|
||||
/* Expire sooner (minor expire unix timestamp) is better
|
||||
* candidate for deletion */
|
||||
if (bestkey == NULL || thisval < bestval) {
|
||||
bestkey = thiskey;
|
||||
bestval = thisval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Finally remove the selected key. */
|
||||
if (bestkey) {
|
||||
robj *keyobj = createStringObject(bestkey,sdslen(bestkey));
|
||||
dbDelete(db,keyobj);
|
||||
server.stat_expiredkeys++;
|
||||
decrRefCount(keyobj);
|
||||
freed++;
|
||||
}
|
||||
}
|
||||
if (!freed) return; /* nothing to free... */
|
||||
}
|
||||
|
||||
while(0) {
|
||||
int j, k, freed = 0;
|
||||
for (j = 0; j < server.dbnum; j++) {
|
||||
int minttl = -1;
|
||||
sds minkey = NULL;
|
||||
|
Reference in New Issue
Block a user