Skip to content

Commit

Permalink
postpone the initialization of oject's lru&lfu until it is added to t…
Browse files Browse the repository at this point in the history
…he db as a value object (redis#11626)

This pr can get two performance benefits:
1. Stop redundant initialization when most robj objects are created
2. LRU_CLOCK will no longer be called in io threads, so we can avoid the `atomicGet`

Another code optimization:
deleted the redundant judgment in dbSetValue, no matter in LFU or LRU, the lru field inold
robj is always the freshest (it is always updated in lookupkey), so we don't need to judge if in LFU
  • Loading branch information
judeng authored May 24, 2023
1 parent d664889 commit d71478a
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 19 deletions.
8 changes: 5 additions & 3 deletions src/db.c
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ void dbAdd(redisDb *db, robj *key, robj *val) {
sds copy = sdsdup(key->ptr);
dictEntry *de = dictAddRaw(db->dict, copy, NULL);
serverAssertWithInfo(NULL, key, de != NULL);
initObjectLRUOrLFU(val);
dictSetVal(db->dict, de, val);
signalKeyAsReady(db, key, val->type);
if (server.cluster_enabled) slotToKeyAddEntry(de, db);
Expand All @@ -212,6 +213,7 @@ void dbAdd(redisDb *db, robj *key, robj *val) {
int dbAddRDBLoad(redisDb *db, sds key, robj *val) {
dictEntry *de = dictAddRaw(db->dict, key, NULL);
if (de == NULL) return 0;
initObjectLRUOrLFU(val);
dictSetVal(db->dict, de, val);
if (server.cluster_enabled) slotToKeyAddEntry(de, db);
return 1;
Expand All @@ -232,9 +234,9 @@ static void dbSetValue(redisDb *db, robj *key, robj *val, int overwrite) {

serverAssertWithInfo(NULL,key,de != NULL);
robj *old = dictGetVal(de);
if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {
val->lru = old->lru;
}

val->lru = old->lru;

if (overwrite) {
/* RM_StringDMA may call dbUnshareStringValue which may free val, so we
* need to incr to retain old */
Expand Down
2 changes: 1 addition & 1 deletion src/evict.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ unsigned int getLRUClock(void) {
unsigned int LRU_CLOCK(void) {
unsigned int lruclock;
if (1000/server.hz <= LRU_CLOCK_RESOLUTION) {
atomicGet(server.lruclock,lruclock);
lruclock = server.lruclock;
} else {
lruclock = getLRUClock();
}
Expand Down
16 changes: 9 additions & 7 deletions src/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,21 @@ robj *createObject(int type, void *ptr) {
o->encoding = OBJ_ENCODING_RAW;
o->ptr = ptr;
o->refcount = 1;
o->lru = 0;
return o;
}

void initObjectLRUOrLFU(robj *o) {
if (o->refcount == OBJ_SHARED_REFCOUNT)
return;
/* Set the LRU to the current lruclock (minutes resolution), or
* alternatively the LFU counter. */
if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {
o->lru = (LFUGetTimeInMinutes()<<8) | LFU_INIT_VAL;
o->lru = (LFUGetTimeInMinutes() << 8) | LFU_INIT_VAL;
} else {
o->lru = LRU_CLOCK();
}
return o;
return;
}

/* Set a special refcount in the object to make it "shared":
Expand Down Expand Up @@ -91,11 +97,7 @@ robj *createEmbeddedStringObject(const char *ptr, size_t len) {
o->encoding = OBJ_ENCODING_EMBSTR;
o->ptr = sh+1;
o->refcount = 1;
if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {
o->lru = (LFUGetTimeInMinutes()<<8) | LFU_INIT_VAL;
} else {
o->lru = LRU_CLOCK();
}
o->lru = 0;

sh->len = len;
sh->alloc = len;
Expand Down
11 changes: 4 additions & 7 deletions src/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -1324,8 +1324,7 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
*
* Note that you can change the resolution altering the
* LRU_CLOCK_RESOLUTION define. */
unsigned int lruclock = getLRUClock();
atomicSet(server.lruclock,lruclock);
server.lruclock = getLRUClock();

cronUpdateMemoryStats();

Expand Down Expand Up @@ -1985,6 +1984,7 @@ void createSharedObjects(void) {
for (j = 0; j < OBJ_SHARED_INTEGERS; j++) {
shared.integers[j] =
makeObjectShared(createObject(OBJ_STRING,(void*)(long)j));
initObjectLRUOrLFU(shared.integers[j]);
shared.integers[j]->encoding = OBJ_ENCODING_INT;
}
for (j = 0; j < OBJ_SHARED_BULKHDR_LEN; j++) {
Expand Down Expand Up @@ -2089,8 +2089,7 @@ void initServerConfig(void) {
server.latency_tracking_info_percentiles[1] = 99.0; /* p99 */
server.latency_tracking_info_percentiles[2] = 99.9; /* p999 */

unsigned int lruclock = getLRUClock();
atomicSet(server.lruclock,lruclock);
server.lruclock = getLRUClock();
resetServerSaveParams();

appendServerSaveParams(60*60,1); /* save after 1 hour and 1 change */
Expand Down Expand Up @@ -5496,8 +5495,6 @@ sds genRedisInfoString(dict *section_dict, int all_sections, int everything) {
call_uname = 0;
}

unsigned int lruclock;
atomicGet(server.lruclock,lruclock);
info = sdscatfmt(info,
"# Server\r\n"
"redis_version:%s\r\n"
Expand Down Expand Up @@ -5548,7 +5545,7 @@ sds genRedisInfoString(dict *section_dict, int all_sections, int everything) {
(int64_t)(uptime/(3600*24)),
server.hz,
server.config_hz,
lruclock,
server.lruclock,
server.executable ? server.executable : "",
server.configfile ? server.configfile : "",
server.io_threads_active);
Expand Down
3 changes: 2 additions & 1 deletion src/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -1549,7 +1549,7 @@ struct redisServer {
dict *orig_commands; /* Command table before command renaming. */
aeEventLoop *el;
rax *errors; /* Errors table */
redisAtomic unsigned int lruclock; /* Clock for LRU eviction */
unsigned int lruclock; /* Clock for LRU eviction */
volatile sig_atomic_t shutdown_asap; /* Shutdown ordered by signal handler. */
mstime_t shutdown_mstime; /* Timestamp to limit graceful shutdown. */
int last_sig_received; /* Indicates the last SIGNAL received, if any (e.g., SIGINT or SIGTERM). */
Expand Down Expand Up @@ -2728,6 +2728,7 @@ void freeZsetObject(robj *o);
void freeHashObject(robj *o);
void dismissObject(robj *o, size_t dump_size);
robj *createObject(int type, void *ptr);
void initObjectLRUOrLFU(robj *o);
robj *createStringObject(const char *ptr, size_t len);
robj *createRawStringObject(const char *ptr, size_t len);
robj *createEmbeddedStringObject(const char *ptr, size_t len);
Expand Down
17 changes: 17 additions & 0 deletions tests/unit/maxmemory.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -571,3 +571,20 @@ start_server {tags {"maxmemory" "external:skip"}} {
r config set maxmemory-policy noeviction
}
}

start_server {tags {"maxmemory" "external:skip"}} {
test {lru/lfu value of the key just added} {
r config set maxmemory-policy allkeys-lru
r set foo a
assert {[r object idletime foo] <= 2}
r del foo
r set foo 1
r get foo
assert {[r object idletime foo] <= 2}

r config set maxmemory-policy allkeys-lfu
r del foo
r set foo a
assert {[r object freq foo] == 5}
}
}

0 comments on commit d71478a

Please sign in to comment.