mirror of
https://github.com/fluencelabs/redis
synced 2025-05-08 00:42:15 +00:00
Merge branch 'lfu-fixes' into unstable
This commit is contained in:
commit
2785d6caa0
@ -330,13 +330,13 @@ void loadServerConfigFromString(char *config) {
|
|||||||
}
|
}
|
||||||
} else if (!strcasecmp(argv[0],"lfu-log-factor") && argc == 2) {
|
} else if (!strcasecmp(argv[0],"lfu-log-factor") && argc == 2) {
|
||||||
server.lfu_log_factor = atoi(argv[1]);
|
server.lfu_log_factor = atoi(argv[1]);
|
||||||
if (server.maxmemory_samples < 0) {
|
if (server.lfu_log_factor < 0) {
|
||||||
err = "lfu-log-factor must be 0 or greater";
|
err = "lfu-log-factor must be 0 or greater";
|
||||||
goto loaderr;
|
goto loaderr;
|
||||||
}
|
}
|
||||||
} else if (!strcasecmp(argv[0],"lfu-decay-time") && argc == 2) {
|
} else if (!strcasecmp(argv[0],"lfu-decay-time") && argc == 2) {
|
||||||
server.lfu_decay_time = atoi(argv[1]);
|
server.lfu_decay_time = atoi(argv[1]);
|
||||||
if (server.maxmemory_samples < 1) {
|
if (server.lfu_decay_time < 0) {
|
||||||
err = "lfu-decay-time must be 0 or greater";
|
err = "lfu-decay-time must be 0 or greater";
|
||||||
goto loaderr;
|
goto loaderr;
|
||||||
}
|
}
|
||||||
@ -1221,6 +1221,8 @@ void configGetCommand(client *c) {
|
|||||||
/* Numerical values */
|
/* Numerical values */
|
||||||
config_get_numerical_field("maxmemory",server.maxmemory);
|
config_get_numerical_field("maxmemory",server.maxmemory);
|
||||||
config_get_numerical_field("maxmemory-samples",server.maxmemory_samples);
|
config_get_numerical_field("maxmemory-samples",server.maxmemory_samples);
|
||||||
|
config_get_numerical_field("lfu-log-factor",server.lfu_log_factor);
|
||||||
|
config_get_numerical_field("lfu-decay-time",server.lfu_decay_time);
|
||||||
config_get_numerical_field("timeout",server.maxidletime);
|
config_get_numerical_field("timeout",server.maxidletime);
|
||||||
config_get_numerical_field("active-defrag-threshold-lower",server.active_defrag_threshold_lower);
|
config_get_numerical_field("active-defrag-threshold-lower",server.active_defrag_threshold_lower);
|
||||||
config_get_numerical_field("active-defrag-threshold-upper",server.active_defrag_threshold_upper);
|
config_get_numerical_field("active-defrag-threshold-upper",server.active_defrag_threshold_upper);
|
||||||
@ -1992,6 +1994,8 @@ int rewriteConfig(char *path) {
|
|||||||
rewriteConfigBytesOption(state,"maxmemory",server.maxmemory,CONFIG_DEFAULT_MAXMEMORY);
|
rewriteConfigBytesOption(state,"maxmemory",server.maxmemory,CONFIG_DEFAULT_MAXMEMORY);
|
||||||
rewriteConfigEnumOption(state,"maxmemory-policy",server.maxmemory_policy,maxmemory_policy_enum,CONFIG_DEFAULT_MAXMEMORY_POLICY);
|
rewriteConfigEnumOption(state,"maxmemory-policy",server.maxmemory_policy,maxmemory_policy_enum,CONFIG_DEFAULT_MAXMEMORY_POLICY);
|
||||||
rewriteConfigNumericalOption(state,"maxmemory-samples",server.maxmemory_samples,CONFIG_DEFAULT_MAXMEMORY_SAMPLES);
|
rewriteConfigNumericalOption(state,"maxmemory-samples",server.maxmemory_samples,CONFIG_DEFAULT_MAXMEMORY_SAMPLES);
|
||||||
|
rewriteConfigNumericalOption(state,"lfu-log-factor",server.lfu_log_factor,CONFIG_DEFAULT_LFU_LOG_FACTOR);
|
||||||
|
rewriteConfigNumericalOption(state,"lfu-decay-time",server.lfu_decay_time,CONFIG_DEFAULT_LFU_DECAY_TIME);
|
||||||
rewriteConfigNumericalOption(state,"active-defrag-threshold-lower",server.active_defrag_threshold_lower,CONFIG_DEFAULT_DEFRAG_THRESHOLD_LOWER);
|
rewriteConfigNumericalOption(state,"active-defrag-threshold-lower",server.active_defrag_threshold_lower,CONFIG_DEFAULT_DEFRAG_THRESHOLD_LOWER);
|
||||||
rewriteConfigNumericalOption(state,"active-defrag-threshold-upper",server.active_defrag_threshold_upper,CONFIG_DEFAULT_DEFRAG_THRESHOLD_UPPER);
|
rewriteConfigNumericalOption(state,"active-defrag-threshold-upper",server.active_defrag_threshold_upper,CONFIG_DEFAULT_DEFRAG_THRESHOLD_UPPER);
|
||||||
rewriteConfigBytesOption(state,"active-defrag-ignore-bytes",server.active_defrag_ignore_bytes,CONFIG_DEFAULT_DEFRAG_IGNORE_BYTES);
|
rewriteConfigBytesOption(state,"active-defrag-ignore-bytes",server.active_defrag_ignore_bytes,CONFIG_DEFAULT_DEFRAG_IGNORE_BYTES);
|
||||||
|
16
src/db.c
16
src/db.c
@ -38,6 +38,15 @@
|
|||||||
* C-level DB API
|
* C-level DB API
|
||||||
*----------------------------------------------------------------------------*/
|
*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Update LFU when an object is accessed.
|
||||||
|
* Firstly, decrement the counter if the decrement time is reached.
|
||||||
|
* Then logarithmically increment the counter, and update the access time. */
|
||||||
|
void updateLFU(robj *val) {
|
||||||
|
unsigned long counter = LFUDecrAndReturn(val);
|
||||||
|
counter = LFULogIncr(counter);
|
||||||
|
val->lru = (LFUGetTimeInMinutes()<<8) | counter;
|
||||||
|
}
|
||||||
|
|
||||||
/* Low level key lookup API, not actually called directly from commands
|
/* Low level key lookup API, not actually called directly from commands
|
||||||
* implementations that should instead rely on lookupKeyRead(),
|
* implementations that should instead rely on lookupKeyRead(),
|
||||||
* lookupKeyWrite() and lookupKeyReadWithFlags(). */
|
* lookupKeyWrite() and lookupKeyReadWithFlags(). */
|
||||||
@ -54,9 +63,7 @@ robj *lookupKey(redisDb *db, robj *key, int flags) {
|
|||||||
!(flags & LOOKUP_NOTOUCH))
|
!(flags & LOOKUP_NOTOUCH))
|
||||||
{
|
{
|
||||||
if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {
|
if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {
|
||||||
unsigned long ldt = val->lru >> 8;
|
updateLFU(val);
|
||||||
unsigned long counter = LFULogIncr(val->lru & 255);
|
|
||||||
val->lru = (ldt << 8) | counter;
|
|
||||||
} else {
|
} else {
|
||||||
val->lru = LRU_CLOCK();
|
val->lru = LRU_CLOCK();
|
||||||
}
|
}
|
||||||
@ -180,6 +187,9 @@ void dbOverwrite(redisDb *db, robj *key, robj *val) {
|
|||||||
int saved_lru = old->lru;
|
int saved_lru = old->lru;
|
||||||
dictReplace(db->dict, key->ptr, val);
|
dictReplace(db->dict, key->ptr, val);
|
||||||
val->lru = saved_lru;
|
val->lru = saved_lru;
|
||||||
|
/* LFU should be not only copied but also updated
|
||||||
|
* when a key is overwritten. */
|
||||||
|
updateLFU(val);
|
||||||
} else {
|
} else {
|
||||||
dictReplace(db->dict, key->ptr, val);
|
dictReplace(db->dict, key->ptr, val);
|
||||||
}
|
}
|
||||||
|
27
src/evict.c
27
src/evict.c
@ -60,8 +60,6 @@ struct evictionPoolEntry {
|
|||||||
|
|
||||||
static struct evictionPoolEntry *EvictionPoolLRU;
|
static struct evictionPoolEntry *EvictionPoolLRU;
|
||||||
|
|
||||||
unsigned long LFUDecrAndReturn(robj *o);
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
* Implementation of eviction, aging and LRU
|
* Implementation of eviction, aging and LRU
|
||||||
* --------------------------------------------------------------------------*/
|
* --------------------------------------------------------------------------*/
|
||||||
@ -302,8 +300,8 @@ unsigned long LFUGetTimeInMinutes(void) {
|
|||||||
return (server.unixtime/60) & 65535;
|
return (server.unixtime/60) & 65535;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Given an object last decrement time, compute the minimum number of minutes
|
/* Given an object last access time, compute the minimum number of minutes
|
||||||
* that elapsed since the last decrement. Handle overflow (ldt greater than
|
* that elapsed since the last access. Handle overflow (ldt greater than
|
||||||
* the current 16 bits minutes time) considering the time as wrapping
|
* the current 16 bits minutes time) considering the time as wrapping
|
||||||
* exactly once. */
|
* exactly once. */
|
||||||
unsigned long LFUTimeElapsed(unsigned long ldt) {
|
unsigned long LFUTimeElapsed(unsigned long ldt) {
|
||||||
@ -324,25 +322,22 @@ uint8_t LFULogIncr(uint8_t counter) {
|
|||||||
return counter;
|
return counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the object decrement time is reached, decrement the LFU counter and
|
/* If the object decrement time is reached decrement the LFU counter but
|
||||||
* update the decrement time field. Return the object frequency counter.
|
* do not update LFU fields of the object, we update the access time
|
||||||
|
* and counter in an explicit way when the object is really accessed.
|
||||||
|
* And we will times halve the counter according to the times of
|
||||||
|
* elapsed time than server.lfu_decay_time.
|
||||||
|
* Return the object frequency counter.
|
||||||
*
|
*
|
||||||
* This function is used in order to scan the dataset for the best object
|
* This function is used in order to scan the dataset for the best object
|
||||||
* to fit: as we check for the candidate, we incrementally decrement the
|
* to fit: as we check for the candidate, we incrementally decrement the
|
||||||
* counter of the scanned objects if needed. */
|
* counter of the scanned objects if needed. */
|
||||||
#define LFU_DECR_INTERVAL 1
|
|
||||||
unsigned long LFUDecrAndReturn(robj *o) {
|
unsigned long LFUDecrAndReturn(robj *o) {
|
||||||
unsigned long ldt = o->lru >> 8;
|
unsigned long ldt = o->lru >> 8;
|
||||||
unsigned long counter = o->lru & 255;
|
unsigned long counter = o->lru & 255;
|
||||||
if (LFUTimeElapsed(ldt) >= server.lfu_decay_time && counter) {
|
unsigned long num_periods = server.lfu_decay_time ? LFUTimeElapsed(ldt) / server.lfu_decay_time : 0;
|
||||||
if (counter > LFU_INIT_VAL*2) {
|
if (num_periods)
|
||||||
counter /= 2;
|
counter = (num_periods > counter) ? 0 : counter - num_periods;
|
||||||
if (counter < LFU_INIT_VAL*2) counter = LFU_INIT_VAL*2;
|
|
||||||
} else {
|
|
||||||
counter--;
|
|
||||||
}
|
|
||||||
o->lru = (LFUGetTimeInMinutes()<<8) | counter;
|
|
||||||
}
|
|
||||||
return counter;
|
return counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1050,10 +1050,14 @@ void objectCommand(client *c) {
|
|||||||
if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nullbulk))
|
if ((o = objectCommandLookupOrReply(c,c->argv[2],shared.nullbulk))
|
||||||
== NULL) return;
|
== NULL) return;
|
||||||
if (!(server.maxmemory_policy & MAXMEMORY_FLAG_LFU)) {
|
if (!(server.maxmemory_policy & MAXMEMORY_FLAG_LFU)) {
|
||||||
addReplyError(c,"A non-LFU 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.");
|
addReplyError(c,"An LFU maxmemory policy is not 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;
|
return;
|
||||||
}
|
}
|
||||||
addReplyLongLong(c,o->lru&255);
|
/* LFUDecrAndReturn should be called
|
||||||
|
* in case of the key has not been accessed for a long time,
|
||||||
|
* because we update the access time only
|
||||||
|
* when the key is read or overwritten. */
|
||||||
|
addReplyLongLong(c,LFUDecrAndReturn(o));
|
||||||
} else {
|
} else {
|
||||||
addReplyErrorFormat(c, "Unknown subcommand or wrong number of arguments for '%s'. Try OBJECT help",
|
addReplyErrorFormat(c, "Unknown subcommand or wrong number of arguments for '%s'. Try OBJECT help",
|
||||||
(char *)c->argv[1]->ptr);
|
(char *)c->argv[1]->ptr);
|
||||||
|
135
src/redis-cli.c
135
src/redis-cli.c
@ -107,6 +107,7 @@ static struct config {
|
|||||||
char *pattern;
|
char *pattern;
|
||||||
char *rdb_filename;
|
char *rdb_filename;
|
||||||
int bigkeys;
|
int bigkeys;
|
||||||
|
int hotkeys;
|
||||||
int stdinarg; /* get last arg from stdin. (-x option) */
|
int stdinarg; /* get last arg from stdin. (-x option) */
|
||||||
char *auth;
|
char *auth;
|
||||||
int output; /* output mode, see OUTPUT_* defines */
|
int output; /* output mode, see OUTPUT_* defines */
|
||||||
@ -1129,6 +1130,8 @@ static int parseOptions(int argc, char **argv) {
|
|||||||
config.pipe_timeout = atoi(argv[++i]);
|
config.pipe_timeout = atoi(argv[++i]);
|
||||||
} else if (!strcmp(argv[i],"--bigkeys")) {
|
} else if (!strcmp(argv[i],"--bigkeys")) {
|
||||||
config.bigkeys = 1;
|
config.bigkeys = 1;
|
||||||
|
} else if (!strcmp(argv[i],"--hotkeys")) {
|
||||||
|
config.hotkeys = 1;
|
||||||
} else if (!strcmp(argv[i],"--eval") && !lastarg) {
|
} else if (!strcmp(argv[i],"--eval") && !lastarg) {
|
||||||
config.eval = argv[++i];
|
config.eval = argv[++i];
|
||||||
} else if (!strcmp(argv[i],"--ldb")) {
|
} else if (!strcmp(argv[i],"--ldb")) {
|
||||||
@ -1229,6 +1232,8 @@ static void usage(void) {
|
|||||||
" no reply is received within <n> seconds.\n"
|
" no reply is received within <n> seconds.\n"
|
||||||
" Default timeout: %d. Use 0 to wait forever.\n"
|
" Default timeout: %d. Use 0 to wait forever.\n"
|
||||||
" --bigkeys Sample Redis keys looking for big keys.\n"
|
" --bigkeys Sample Redis keys looking for big keys.\n"
|
||||||
|
" --hotkeys Sample Redis keys looking for hot keys.\n"
|
||||||
|
" only works when maxmemory-policy is *lfu.\n"
|
||||||
" --scan List all keys using the SCAN command.\n"
|
" --scan List all keys using the SCAN command.\n"
|
||||||
" --pattern <pat> Useful with --scan to specify a SCAN pattern.\n"
|
" --pattern <pat> Useful with --scan to specify a SCAN pattern.\n"
|
||||||
" --intrinsic-latency <sec> Run a test to measure intrinsic system latency.\n"
|
" --intrinsic-latency <sec> Run a test to measure intrinsic system latency.\n"
|
||||||
@ -2343,6 +2348,129 @@ static void findBigKeys(void) {
|
|||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void getKeyFreqs(redisReply *keys, unsigned long long *freqs) {
|
||||||
|
redisReply *reply;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
/* Pipeline OBJECT freq commands */
|
||||||
|
for(i=0;i<keys->elements;i++) {
|
||||||
|
redisAppendCommand(context, "OBJECT freq %s", keys->element[i]->str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Retrieve freqs */
|
||||||
|
for(i=0;i<keys->elements;i++) {
|
||||||
|
if(redisGetReply(context, (void**)&reply)!=REDIS_OK) {
|
||||||
|
fprintf(stderr, "Error getting freq for key '%s' (%d: %s)\n",
|
||||||
|
keys->element[i]->str, context->err, context->errstr);
|
||||||
|
exit(1);
|
||||||
|
} else if(reply->type != REDIS_REPLY_INTEGER) {
|
||||||
|
if(reply->type == REDIS_REPLY_ERROR) {
|
||||||
|
fprintf(stderr, "Error: %s\n", reply->str);
|
||||||
|
exit(1);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Warning: OBJECT freq on '%s' failed (may have been deleted)\n", keys->element[i]->str);
|
||||||
|
freqs[i] = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
freqs[i] = reply->integer;
|
||||||
|
}
|
||||||
|
freeReplyObject(reply);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define HOTKEYS_SAMPLE 16
|
||||||
|
static void findHotKeys(void) {
|
||||||
|
redisReply *keys, *reply;
|
||||||
|
unsigned long long counters[HOTKEYS_SAMPLE] = {0};
|
||||||
|
sds hotkeys[HOTKEYS_SAMPLE] = {NULL};
|
||||||
|
unsigned long long sampled = 0, total_keys, *freqs = NULL, it = 0;
|
||||||
|
unsigned int arrsize = 0, i, k;
|
||||||
|
double pct;
|
||||||
|
|
||||||
|
/* Total keys pre scanning */
|
||||||
|
total_keys = getDbSize();
|
||||||
|
|
||||||
|
/* Status message */
|
||||||
|
printf("\n# Scanning the entire keyspace to find hot keys as well as\n");
|
||||||
|
printf("# average sizes per key type. You can use -i 0.1 to sleep 0.1 sec\n");
|
||||||
|
printf("# per 100 SCAN commands (not usually needed).\n\n");
|
||||||
|
|
||||||
|
/* SCAN loop */
|
||||||
|
do {
|
||||||
|
/* Calculate approximate percentage completion */
|
||||||
|
pct = 100 * (double)sampled/total_keys;
|
||||||
|
|
||||||
|
/* Grab some keys and point to the keys array */
|
||||||
|
reply = sendScan(&it);
|
||||||
|
keys = reply->element[1];
|
||||||
|
|
||||||
|
/* Reallocate our freqs array if we need to */
|
||||||
|
if(keys->elements > arrsize) {
|
||||||
|
freqs = zrealloc(freqs, sizeof(unsigned long long)*keys->elements);
|
||||||
|
|
||||||
|
if(!freqs) {
|
||||||
|
fprintf(stderr, "Failed to allocate storage for keys!\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
arrsize = keys->elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
getKeyFreqs(keys, freqs);
|
||||||
|
|
||||||
|
/* Now update our stats */
|
||||||
|
for(i=0;i<keys->elements;i++) {
|
||||||
|
sampled++;
|
||||||
|
/* Update overall progress */
|
||||||
|
if(sampled % 1000000 == 0) {
|
||||||
|
printf("[%05.2f%%] Sampled %llu keys so far\n", pct, sampled);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use eviction pool here */
|
||||||
|
k = 0;
|
||||||
|
while (k < HOTKEYS_SAMPLE && freqs[i] > counters[k]) k++;
|
||||||
|
if (k == 0) continue;
|
||||||
|
k--;
|
||||||
|
if (k == 0 || counters[k] == 0) {
|
||||||
|
sdsfree(hotkeys[k]);
|
||||||
|
} else {
|
||||||
|
sdsfree(hotkeys[0]);
|
||||||
|
memmove(counters,counters+1,sizeof(counters[0])*k);
|
||||||
|
memmove(hotkeys,hotkeys+1,sizeof(hotkeys[0])*k);
|
||||||
|
}
|
||||||
|
counters[k] = freqs[i];
|
||||||
|
hotkeys[k] = sdsnew(keys->element[i]->str);
|
||||||
|
printf(
|
||||||
|
"[%05.2f%%] Hot key '%s' found so far with counter %llu\n",
|
||||||
|
pct, keys->element[i]->str, freqs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sleep if we've been directed to do so */
|
||||||
|
if(sampled && (sampled %100) == 0 && config.interval) {
|
||||||
|
usleep(config.interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
freeReplyObject(reply);
|
||||||
|
} while(it != 0);
|
||||||
|
|
||||||
|
if (freqs) zfree(freqs);
|
||||||
|
|
||||||
|
/* We're done */
|
||||||
|
printf("\n-------- summary -------\n\n");
|
||||||
|
|
||||||
|
printf("Sampled %llu keys in the keyspace!\n", sampled);
|
||||||
|
|
||||||
|
for (i=1; i<= HOTKEYS_SAMPLE; i++) {
|
||||||
|
k = HOTKEYS_SAMPLE - i;
|
||||||
|
if(counters[k]>0) {
|
||||||
|
printf("hot key found with counter: %llu\tkeyname: %s\n", counters[k], hotkeys[k]);
|
||||||
|
sdsfree(hotkeys[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
/*------------------------------------------------------------------------------
|
/*------------------------------------------------------------------------------
|
||||||
* Stats mode
|
* Stats mode
|
||||||
*--------------------------------------------------------------------------- */
|
*--------------------------------------------------------------------------- */
|
||||||
@ -2720,6 +2848,7 @@ int main(int argc, char **argv) {
|
|||||||
config.pipe_mode = 0;
|
config.pipe_mode = 0;
|
||||||
config.pipe_timeout = REDIS_CLI_DEFAULT_PIPE_TIMEOUT;
|
config.pipe_timeout = REDIS_CLI_DEFAULT_PIPE_TIMEOUT;
|
||||||
config.bigkeys = 0;
|
config.bigkeys = 0;
|
||||||
|
config.hotkeys = 0;
|
||||||
config.stdinarg = 0;
|
config.stdinarg = 0;
|
||||||
config.auth = NULL;
|
config.auth = NULL;
|
||||||
config.eval = NULL;
|
config.eval = NULL;
|
||||||
@ -2780,6 +2909,12 @@ int main(int argc, char **argv) {
|
|||||||
findBigKeys();
|
findBigKeys();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Find hot keys */
|
||||||
|
if (config.hotkeys) {
|
||||||
|
if (cliConnect(0) == REDIS_ERR) exit(1);
|
||||||
|
findHotKeys();
|
||||||
|
}
|
||||||
|
|
||||||
/* Stat mode */
|
/* Stat mode */
|
||||||
if (config.stat_mode) {
|
if (config.stat_mode) {
|
||||||
if (cliConnect(0) == REDIS_ERR) exit(1);
|
if (cliConnect(0) == REDIS_ERR) exit(1);
|
||||||
|
@ -586,7 +586,7 @@ typedef struct redisObject {
|
|||||||
unsigned encoding:4;
|
unsigned encoding:4;
|
||||||
unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or
|
unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or
|
||||||
* LFU data (least significant 8 bits frequency
|
* LFU data (least significant 8 bits frequency
|
||||||
* and most significant 16 bits decreas time). */
|
* and most significant 16 bits access time). */
|
||||||
int refcount;
|
int refcount;
|
||||||
void *ptr;
|
void *ptr;
|
||||||
} robj;
|
} robj;
|
||||||
@ -1118,8 +1118,8 @@ struct redisServer {
|
|||||||
unsigned long long maxmemory; /* Max number of memory bytes to use */
|
unsigned long long maxmemory; /* Max number of memory bytes to use */
|
||||||
int maxmemory_policy; /* Policy for key eviction */
|
int maxmemory_policy; /* Policy for key eviction */
|
||||||
int maxmemory_samples; /* Pricision of random sampling */
|
int maxmemory_samples; /* Pricision of random sampling */
|
||||||
unsigned int lfu_log_factor; /* LFU logarithmic counter factor. */
|
int lfu_log_factor; /* LFU logarithmic counter factor. */
|
||||||
unsigned int lfu_decay_time; /* LFU counter decay factor. */
|
int lfu_decay_time; /* LFU counter decay factor. */
|
||||||
/* Blocked clients */
|
/* Blocked clients */
|
||||||
unsigned int bpop_blocked_clients; /* Number of clients blocked by lists */
|
unsigned int bpop_blocked_clients; /* Number of clients blocked by lists */
|
||||||
list *unblocked_clients; /* list of clients to unblock before next loop */
|
list *unblocked_clients; /* list of clients to unblock before next loop */
|
||||||
@ -1802,6 +1802,7 @@ void evictionPoolAlloc(void);
|
|||||||
#define LFU_INIT_VAL 5
|
#define LFU_INIT_VAL 5
|
||||||
unsigned long LFUGetTimeInMinutes(void);
|
unsigned long LFUGetTimeInMinutes(void);
|
||||||
uint8_t LFULogIncr(uint8_t value);
|
uint8_t LFULogIncr(uint8_t value);
|
||||||
|
unsigned long LFUDecrAndReturn(robj *o);
|
||||||
|
|
||||||
/* Keys hashing / comparison functions for dict.c hash tables. */
|
/* Keys hashing / comparison functions for dict.c hash tables. */
|
||||||
uint64_t dictSdsHash(const void *key);
|
uint64_t dictSdsHash(const void *key);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user