diff --git a/src/db.c b/src/db.c index a78c8bad2..2e6d85cf4 100644 --- a/src/db.c +++ b/src/db.c @@ -122,6 +122,10 @@ robj *lookupKey(serverDb *db, robj *key, int flags) { server.current_client->cmd->proc != touchCommand) flags |= LOOKUP_NOTOUCH; if (!hasActiveChildProcess() && !(flags & LOOKUP_NOTOUCH)) { + if (!canUseSharedObject() && val->refcount == OBJ_SHARED_REFCOUNT) { + val = dupStringObject(val); + kvstoreDictSetVal(db->keys, getKeySlot(key->ptr), de, val); + } if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) { updateLFU(val); } else { diff --git a/src/object.c b/src/object.c index 1a335edd6..ea3538b9e 100644 --- a/src/object.c +++ b/src/object.c @@ -647,8 +647,10 @@ robj *tryObjectEncodingEx(robj *o, int try_trim) { * Note that we avoid using shared integers when maxmemory is used * because every object needs to have a private LRU field for the LRU * algorithm to work well. */ - if ((server.maxmemory == 0 || !(server.maxmemory_policy & MAXMEMORY_FLAG_NO_SHARED_INTEGERS)) && value >= 0 && - value < OBJ_SHARED_INTEGERS) { + if (canUseSharedObject() && + value >= 0 && + value < OBJ_SHARED_INTEGERS) + { decrRefCount(o); return shared.integers[value]; } else { diff --git a/src/server.h b/src/server.h index bac4c33c9..8f273db1e 100644 --- a/src/server.h +++ b/src/server.h @@ -2855,6 +2855,9 @@ int collateStringObjects(const robj *a, const robj *b); int equalStringObjects(robj *a, robj *b); unsigned long long estimateObjectIdleTime(robj *o); void trimStringObjectIfNeeded(robj *o, int trim_small_values); +static inline int canUseSharedObject(void) { + return server.maxmemory == 0 || !(server.maxmemory_policy & MAXMEMORY_FLAG_NO_SHARED_INTEGERS); +} #define sdsEncodedObject(objptr) (objptr->encoding == OBJ_ENCODING_RAW || objptr->encoding == OBJ_ENCODING_EMBSTR) /* Synchronous I/O with timeout */ diff --git a/tests/unit/maxmemory.tcl b/tests/unit/maxmemory.tcl index 92e68ac1e..ee1232796 100644 --- a/tests/unit/maxmemory.tcl +++ b/tests/unit/maxmemory.tcl @@ -168,6 +168,21 @@ start_server {tags {"maxmemory external:skip"}} { r config set maxmemory 0 } + test "Shared integers are unshared with maxmemory and LRU policy" { + r set a 1 + r set b 1 + assert_refcount_morethan a 1 + assert_refcount_morethan b 1 + r config set maxmemory 1073741824 + r config set maxmemory-policy allkeys-lru + r get a + assert_refcount 1 a + r config set maxmemory-policy volatile-lru + r get b + assert_refcount 1 b + r config set maxmemory 0 + } + foreach policy { allkeys-random allkeys-lru allkeys-lfu volatile-lru volatile-lfu volatile-random volatile-ttl } {