diff --git a/src/StorageCache.cpp b/src/StorageCache.cpp index ad56a253a..af2ac12b7 100644 --- a/src/StorageCache.cpp +++ b/src/StorageCache.cpp @@ -148,4 +148,14 @@ size_t StorageCache::count() const void StorageCache::beginWriteBatch() { serverAssert(GlobalLocksAcquired()); // Otherwise we deadlock m_spstorage->beginWriteBatch(); +} + +void StorageCache::emergencyFreeCache() { + dict *d = m_pdict; + m_pdict = nullptr; + if (d != nullptr) { + g_pserver->asyncworkqueue->AddWorkFunction([d]{ + dictRelease(d); + }); + } } \ No newline at end of file diff --git a/src/StorageCache.h b/src/StorageCache.h index 9f92f75c0..184eb60bd 100644 --- a/src/StorageCache.h +++ b/src/StorageCache.h @@ -43,6 +43,8 @@ public: void bulkInsert(sds *rgkeys, sds *rgvals, size_t celem); void retrieve(sds key, IStorage::callbackSingle fn) const; bool erase(sds key); + void emergencyFreeCache(); + bool keycacheIsEnabled() const { return m_pdict != nullptr; } bool enumerate(IStorage::callback fn) const { return m_spstorage->enumerate(fn); } diff --git a/src/db.cpp b/src/db.cpp index c883bddba..446657040 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -3065,6 +3065,20 @@ void redisDbPersistentData::removeAllCachedValues() } } +void redisDbPersistentData::disableKeyCache() +{ + if (m_spstorage == nullptr) + return; + m_spstorage->emergencyFreeCache(); +} + +bool redisDbPersistentData::keycacheIsEnabled() +{ + if (m_spstorage == nullptr) + return false; + return m_spstorage->keycacheIsEnabled(); +} + void redisDbPersistentData::trackkey(const char *key, bool fUpdate) { if (m_fTrackingChanges && !m_fAllChanged && m_spstorage) { diff --git a/src/evict.cpp b/src/evict.cpp index 84bf21c36..20ebc9058 100644 --- a/src/evict.cpp +++ b/src/evict.cpp @@ -868,10 +868,15 @@ cant_free: redisDb *db = g_pserver->db[idb]; if (db->FStorageProvider()) { - serverLog(LL_WARNING, "Failed to evict keys, falling back to flushing entire cache. Consider increasing maxmemory-samples."); - db->removeAllCachedValues(); - if (((mem_reported - zmalloc_used_memory()) + mem_freed) >= mem_tofree) - result = EVICT_OK; + if (db->size() != 0 && db->size(true /*fcachedOnly*/) == 0 && db->keycacheIsEnabled()) { + serverLog(LL_WARNING, "Key cache exceeds maxmemory, freeing - performance may be affected increase maxmemory if possible"); + db->disableKeyCache(); + } else if (db->size(true /*fCachedOnly*/)) { + serverLog(LL_WARNING, "Failed to evict keys, falling back to flushing entire cache. Consider increasing maxmemory-samples."); + db->removeAllCachedValues(); + if (((mem_reported - zmalloc_used_memory()) + mem_freed) >= mem_tofree) + result = EVICT_OK; + } } } } diff --git a/src/server.h b/src/server.h index 1153fde23..f76d73beb 100644 --- a/src/server.h +++ b/src/server.h @@ -1182,6 +1182,8 @@ public: bool FStorageProvider() { return m_spstorage != nullptr; } bool removeCachedValue(const char *key, dictEntry **ppde = nullptr); void removeAllCachedValues(); + void disableKeyCache(); + bool keycacheIsEnabled(); bool prefetchKeysAsync(client *c, struct parsed_command &command, bool fExecOK); @@ -1337,6 +1339,8 @@ struct redisDb : public redisDbPersistentDataSnapshot using redisDbPersistentData::endSnapshot; using redisDbPersistentData::restoreSnapshot; using redisDbPersistentData::removeAllCachedValues; + using redisDbPersistentData::disableKeyCache; + using redisDbPersistentData::keycacheIsEnabled; using redisDbPersistentData::dictUnsafeKeyOnly; using redisDbPersistentData::resortExpire; using redisDbPersistentData::prefetchKeysAsync;