From bafd03f53c0302c0f87be4140b8a9ebc98c1dbea Mon Sep 17 00:00:00 2001 From: Malavan Date: Fri, 7 May 2021 09:40:23 +0000 Subject: [PATCH] Speedup keyIsExpired by removing subkey search Former-commit-id: a01564158e40300ab4a0338c0a6e924972385407 --- src/db.cpp | 12 ++---------- src/expire.cpp | 2 +- src/expire.h | 32 +++++++++++++++++++++++++++----- src/server.h | 1 + 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/db.cpp b/src/db.cpp index de2ed2754..3935686c5 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -1626,17 +1626,9 @@ int keyIsExpired(redisDb *db, robj *key) { /* Don't expire anything while loading. It will be done later. */ if (g_pserver->loading) return 0; - long long when = -1; - for (auto &exp : *pexpire) - { - if (exp.subkey() == nullptr) - { - when = exp.when(); - break; - } - } + long long when = pexpire->whenFull(); - if (when == -1) + if (when == INVALID_EXPIRE) return 0; /* If we are in the context of a Lua script, we pretend that time is diff --git a/src/expire.cpp b/src/expire.cpp index 4d7b4ce0a..b6022c712 100644 --- a/src/expire.cpp +++ b/src/expire.cpp @@ -153,7 +153,7 @@ int activeExpireCycleExpire(redisDb *db, expireEntry &e, long long now, size_t & pfat->popfrontExpireEntry(); fTtlChanged = true; - if ((tried % ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP) == 0) { + if ((tried % ACTIVE_EXPIRE_CYCLE_SUBKEY_LOOKUPS_PER_LOOP) == 0) { break; } } diff --git a/src/expire.h b/src/expire.h index d002d6383..3600fcd97 100644 --- a/src/expire.h +++ b/src/expire.h @@ -1,5 +1,7 @@ #pragma once +#define INVALID_EXPIRE LLONG_MIN + class expireEntryFat { friend class expireEntry; @@ -31,6 +33,14 @@ public: ~expireEntryFat(); long long when() const noexcept { return m_vecexpireEntries.front().when; } + long long whenFull() const noexcept { + for (size_t i = 0; i < size(); ++i) { + if (m_vecexpireEntries[i].spsubkey == nullptr) { + return m_vecexpireEntries[i].when; + } + } + return INVALID_EXPIRE; + } const char *key() const noexcept { return m_keyPrimary; } bool operator<(long long when) const noexcept { return this->when() < when; } @@ -51,7 +61,7 @@ class expireEntry { expireEntryFat *m_pfatentry; } u; long long m_when; // LLONG_MIN means this is a fat entry and we should use the pointer - + long long m_whenFull; public: class iter { @@ -91,7 +101,8 @@ public: { if (subkey != nullptr) { - m_when = LLONG_MIN; + m_when = INVALID_EXPIRE; + m_whenFull = INVALID_EXPIRE; u.m_pfatentry = new (MALLOC_LOCAL) expireEntryFat(key); u.m_pfatentry->expireSubKey(subkey, when); } @@ -99,19 +110,22 @@ public: { u.m_key = key; m_when = when; + m_whenFull = when; } } expireEntry(expireEntryFat *pfatentry) { u.m_pfatentry = pfatentry; - m_when = LLONG_MIN; + m_when = INVALID_EXPIRE; + m_whenFull = pfatentry->whenFull(); } expireEntry(expireEntry &&e) { u.m_key = e.u.m_key; m_when = e.m_when; + m_whenFull = e.m_whenFull; e.u.m_key = (char*)key(); // we do this so it can still be found in the set e.m_when = 0; } @@ -130,7 +144,7 @@ public: u.m_key = key; } - inline bool FFat() const noexcept { return m_when == LLONG_MIN; } + inline bool FFat() const noexcept { return m_when == INVALID_EXPIRE; } expireEntryFat *pfatentry() { assert(FFat()); return u.m_pfatentry; } @@ -160,9 +174,17 @@ public: return u.m_pfatentry->when(); return m_when; } + long long whenFull() const noexcept + { + return m_whenFull; + } void update(const char *subkey, long long when) { + if (subkey == nullptr) + { + m_whenFull = when; + } if (!FFat()) { if (subkey == nullptr) @@ -175,7 +197,7 @@ public: // we have to upgrade to a fat entry long long whenT = m_when; sds keyPrimary = u.m_key; - m_when = LLONG_MIN; + m_when = INVALID_EXPIRE; u.m_pfatentry = new (MALLOC_LOCAL) expireEntryFat(keyPrimary); u.m_pfatentry->expireSubKey(nullptr, whenT); // at this point we're fat so fall through diff --git a/src/server.h b/src/server.h index 1eae8b0f2..c1bb7dd9f 100644 --- a/src/server.h +++ b/src/server.h @@ -303,6 +303,7 @@ inline bool operator!=(const void *p, const robj_sharedptr &rhs) #define CONFIG_DEFAULT_ENABLE_MULTIMASTER 0 #define ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP 64 /* Loopkups per loop. */ +#define ACTIVE_EXPIRE_CYCLE_SUBKEY_LOOKUPS_PER_LOOP 16384 /* Subkey loopkups per loop. */ #define ACTIVE_EXPIRE_CYCLE_FAST_DURATION 1000 /* Microseconds */ #define ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC 25 /* CPU max % for keys collection */ #define ACTIVE_EXPIRE_CYCLE_SLOW 0