diff --git a/src/db.cpp b/src/db.cpp index 067f4b74b..fa6e678a2 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -242,7 +242,7 @@ robj *lookupKeyWriteOrReply(client *c, robj *key, robj *reply) { return o; } -bool dbAddCore(redisDb *db, sds key, robj *val, bool fUpdateMvcc, bool fAssumeNew = false) { +bool dbAddCore(redisDb *db, sds key, robj *val, bool fUpdateMvcc, bool fAssumeNew = false, dict_iter *piterExisting = nullptr) { serverAssert(!val->FExpires()); sds copy = sdsdupshared(key); @@ -251,7 +251,7 @@ bool dbAddCore(redisDb *db, sds key, robj *val, bool fUpdateMvcc, bool fAssumeNe setMvccTstamp(val, mvcc); } - bool fInserted = db->insert(copy, val, fAssumeNew); + bool fInserted = db->insert(copy, val, fAssumeNew, piterExisting); if (fInserted) { @@ -321,8 +321,12 @@ void redisDb::dbOverwriteCore(redisDb::iter itr, sds keySds, robj *val, bool fUp * This function does not modify the expire time of the existing key. * * The program is aborted if the key was not already present. */ -void dbOverwrite(redisDb *db, robj *key, robj *val, bool fRemoveExpire) { - auto itr = db->find(key); +void dbOverwrite(redisDb *db, robj *key, robj *val, bool fRemoveExpire, dict_iter *pitrExisting) { + redisDb::iter itr; + if (pitrExisting != nullptr) + itr = *pitrExisting; + else + itr = db->find(key); serverAssertWithInfo(NULL,key,itr != nullptr); lookupKeyUpdateObj(itr.val(), LOOKUP_NONE); @@ -366,8 +370,9 @@ int dbMerge(redisDb *db, sds key, robj *val, int fReplace) * in a context where there is no clear client performing the operation. */ void genericSetKey(client *c, redisDb *db, robj *key, robj *val, int keepttl, int signal) { db->prepOverwriteForSnapshot(szFromObj(key)); - if (!dbAddCore(db, szFromObj(key), val, true /* fUpdateMvcc */)) { - dbOverwrite(db, key, val, !keepttl); + dict_iter iter; + if (!dbAddCore(db, szFromObj(key), val, true /* fUpdateMvcc */, false /*fAssumeNew*/, &iter)) { + dbOverwrite(db, key, val, !keepttl, &iter); } incrRefCount(val); if (signal) signalModifiedKey(c,db,key); @@ -2594,11 +2599,12 @@ void redisDb::storageProviderInitialize() } } -bool redisDbPersistentData::insert(char *key, robj *o, bool fAssumeNew) +bool redisDbPersistentData::insert(char *key, robj *o, bool fAssumeNew, dict_iter *piterExisting) { if (!fAssumeNew && (g_pserver->m_pstorageFactory != nullptr || m_pdbSnapshot != nullptr)) ensure(key); - int res = dictAdd(m_pdict, key, o); + dictEntry *de; + int res = dictAdd(m_pdict, key, o, &de); serverAssert(FImplies(fAssumeNew, res == DICT_OK)); if (res == DICT_OK) { @@ -2610,6 +2616,11 @@ bool redisDbPersistentData::insert(char *key, robj *o, bool fAssumeNew) #endif trackkey(key, false /* fUpdate */); } + else + { + if (piterExisting) + *piterExisting = dict_iter(m_pdict, de); + } return (res == DICT_OK); } diff --git a/src/dict.cpp b/src/dict.cpp index 1ed414b69..ac17fc7ab 100644 --- a/src/dict.cpp +++ b/src/dict.cpp @@ -573,9 +573,9 @@ static void _dictRehashStep(dict *d) { } /* Add an element to the target hash table */ -int dictAdd(dict *d, void *key, void *val) +int dictAdd(dict *d, void *key, void *val, dictEntry **existing) { - dictEntry *entry = dictAddRaw(d,key,NULL); + dictEntry *entry = dictAddRaw(d,key,existing); if (!entry) return DICT_ERR; dictSetVal(d, entry, val); diff --git a/src/dict.h b/src/dict.h index 64fdc98c9..ed33c9175 100644 --- a/src/dict.h +++ b/src/dict.h @@ -205,7 +205,7 @@ typedef void (dictScanBucketFunction)(void *privdata, dictEntry **bucketref); dict *dictCreate(dictType *type, void *privDataPtr); int dictExpand(dict *d, unsigned long size, bool fShrink = false); int dictTryExpand(dict *d, unsigned long size, bool fShrink); -int dictAdd(dict *d, void *key, void *val); +int dictAdd(dict *d, void *key, void *val, dictEntry **existing = nullptr); dictEntry *dictAddRaw(dict *d, void *key, dictEntry **existing); dictEntry *dictAddOrFind(dict *d, void *key); int dictReplace(dict *d, void *key, void *val); diff --git a/src/server.cpp b/src/server.cpp index ef1039cea..7cc1a9ac3 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2086,7 +2086,7 @@ void databasesCron(bool fMainThread) { /* Perform hash tables rehashing if needed, but only if there are no * other processes saving the DB on disk. Otherwise rehashing is bad * as will cause a lot of copy-on-write of memory pages. */ - if (!hasActiveChildProcess() || g_pserver->FRdbSaveInProgress()) { + if (!(hasActiveChildProcess() || g_pserver->FRdbSaveInProgress())) { /* We use global counters so if we stop the computation at a given * DB we'll be able to start from the successive in the next * cron loop iteration. */ diff --git a/src/server.h b/src/server.h index fa2183149..40923d80e 100644 --- a/src/server.h +++ b/src/server.h @@ -1067,6 +1067,9 @@ class dict_iter : public dict_const_iter { dict *m_dict = nullptr; public: + dict_iter() + : dict_const_iter(nullptr) + {} explicit dict_iter(nullptr_t) : dict_const_iter(nullptr) {} @@ -1131,7 +1134,7 @@ public: void getStats(char *buf, size_t bufsize) { dictGetStats(buf, bufsize, m_pdict); } void getExpireStats(char *buf, size_t bufsize) { m_setexpire->getstats(buf, bufsize); } - bool insert(char *k, robj *o, bool fAssumeNew = false); + bool insert(char *k, robj *o, bool fAssumeNew = false, dict_iter *existing = nullptr); void tryResize(); int incrementallyRehash(); void updateValue(dict_iter itr, robj *val); @@ -3325,7 +3328,7 @@ int objectSetLRUOrLFU(robj *val, long long lfu_freq, long long lru_idle, #define LOOKUP_NONOTIFY (1<<1) #define LOOKUP_UPDATEMVCC (1<<2) void dbAdd(redisDb *db, robj *key, robj *val); -void dbOverwrite(redisDb *db, robj *key, robj *val, bool fRemoveExpire = false); +void dbOverwrite(redisDb *db, robj *key, robj *val, bool fRemoveExpire = false, dict_iter *pitrExisting = nullptr); int dbMerge(redisDb *db, sds key, robj *val, int fReplace); void genericSetKey(client *c, redisDb *db, robj *key, robj *val, int keepttl, int signal); void setKey(client *c, redisDb *db, robj *key, robj *val);