Compare commits

..
Author SHA1 Message Date
Malavan Sotheeswaran 08b0716f0b Merge remote-tracking branch 'internal/main' into merge_internal 2023-09-28 14:17:09 -07:00
Malavan SotheeswaranandJohn Sully dfcc848e1c enable level_compaction_dynamic_level_bytes after flush, and flush expires for FLASH (#229)
* enable level_compaction_dynamic_level_bytes after flush, and flush expires

* update debug reload for flash

* update debug reload for flash complete

* missing forward declare

* commit existing changes then track changes for debug reload

* missing args

* commitChanges is conditional

Co-authored-by: John Sully <jsully@snapchat.com>
2023-09-28 16:59:23 -04:00
Malavan Sotheeswaran 8f61819773 fix mac compile 2023-09-28 00:03:29 -07:00
Malavan Sotheeswaran e60133ffe4 Merge remote-tracking branch 'internal/main' into merge_internal 2023-09-27 16:41:51 -07:00
John Sully e7f90f0096 Fix bug where we erroneously answer queries belonging to another shard 2023-09-27 07:38:09 +00:00
John Sully 025b7077f7 Fix crossslot error migrating batches of keys 2023-09-26 00:11:21 -04:00
Malavan Sotheeswaran 596c513d3e only use internal locks when multithreaded (#205) 2023-09-25 15:53:47 -04:00
John Sully 570bcb55c7 make async rehash configurable 2023-09-23 16:32:28 -04:00
John Sully 68d751046e async rehash is preventing rehashing during RDB load after a db flush. Ensure it can't interefere after a flush 2023-09-23 16:32:28 -04:00
John Sully cfe257a9c7 Fix logic bug 2023-09-20 12:57:10 -07:00
John Sully c6e20ea396 Fix over pessimistic checks that prevent replicas from serving mget 2023-09-20 12:57:10 -07:00
a00817524 5f5753ae53 build failure 2023-09-17 19:06:00 -04:00
a00817524 e42d83d208 build failure 2023-09-17 19:06:00 -04:00
a00817524 9c32d4c1c8 removed proc call 2023-09-17 19:06:00 -04:00
a00817524 337eb297a1 review rework 2023-09-17 19:06:00 -04:00
a00817524 cf13e7b594 Async FLASH Design: AE event loop changes to understand StorageToken 2023-09-17 19:06:00 -04:00
John Sully 9251f1c244 Permit keys of differing slots as long as they are served by this cluster and we are not migrating 2023-09-14 21:55:04 -04:00
Zhaozhen Liang 7b7c0ba192 Merge pull request #224 from Snapchat/remove-dot-in-nodename-metrics
fix nodename metricsname
2023-09-11 15:37:16 -06:00
zliang 98e306c59b Merge branch 'main' into remove-dot-in-nodename-metrics 2023-09-11 12:18:39 -06:00
Alex Cope a55c687cd0 Emit more aggregate metrics in modstatsd (#223) 2023-09-11 10:43:25 -07:00
Malavan Sotheeswaran ace783a00e Flash expiration (#197)
Design Doc: https://docs.google.com/document/d/1NmnYGnHLdZp-KOUCUatX5iXpF-L3YK4VUc9Lm3Tqxpo/edit?usp=sharing
2023-09-08 16:25:53 -04:00
Malavan Sotheeswaran 7d4f461562 Make propagating before freeing module context optional (#225)
* don't propogate on module context free for rdb load

* default in wrong place
2023-09-08 15:51:48 -04:00
zliang e31533bd7a fix unnecessary replace 2023-08-31 12:45:42 -06:00
zliang c20af57cf1 fix nodename metricsname 2023-08-31 12:29:59 -06:00
John Sully 820482bffe Fix slow to free when low lock contention 2023-08-25 20:40:16 -04:00
John Sully f435218ed9 Fix memory leaks 2023-08-25 16:44:10 +00:00
Alex Cope 8b755aee1b Multiply CPU percent metric by 100 2023-08-22 17:33:57 -04:00
Malavan Sotheeswaran 441b74a936 Merge remote-tracking branch 'origin/main' 2023-07-25 21:44:27 -07:00
Alex Cope ce70e8cd0c revert 2023-07-25 21:35:17 -07:00
Alex Cope e3a1ea3928 with config 2023-07-25 21:34:50 -07:00
Rolf Ahrenberg a464a7173d Use tini in Alpine-based Docker image (#682) 2023-07-25 21:33:30 -07:00
Karthick Ariyaratnam (A) 806175df99 Fix a fug where repl-backlog-size config was modifed in keydb.conf with the runtime value during config rewrite. 2023-07-25 21:33:30 -07:00
Karthick AriyaratnamandKarthick Ariyaratnam bcb542128a Fix a bug where a temp rdb file with zero bytes is generated in flash mode. (#696)
Co-authored-by: Karthick Ariyaratnam (A) <k00809413@china.huawei.com>
2023-07-25 21:33:30 -07:00
Ikko Eltociear Ashimine 870b0db23d Fix typo in module.cpp (#686)
comparision -> comparison
2023-07-25 21:33:30 -07:00
Philipp Trulson a4c19e3430 Enable KeyDB FLASH in Docker images (#687) 2023-07-25 21:33:30 -07:00
Pim van den Broek 9a8a36e8ee Fix redis-cli symlink (#689) 2023-07-25 21:33:30 -07:00
John Sully aef01878a5 Build break fix 2023-07-25 21:32:52 -07:00
John Sully bd6eb379d5 Prevent crash on free when using repl-disk-buffer-reserve (#207) 2023-07-25 21:32:52 -07:00
John Sully 06a49a6179 Fix OOM issues during full sync when fork bgsave is used (#209) 2023-07-25 21:32:52 -07:00
John Sully 9ab1278cf1 Prevent a deadlock when running CLIENT KILL with large numbers of clients (#206) 2023-07-25 21:32:52 -07:00
Alex Cope cc8ed88577 nullptr 2023-07-25 21:32:52 -07:00
Alex Cope 0d2f98d6e1 fix compile error 2023-07-25 21:32:52 -07:00
Alex Cope 872c60566f use enum class 2023-07-25 21:32:52 -07:00
Alex Cope b5a20a4f91 modify 2023-07-25 21:32:52 -07:00
Alex Cope cf4735b61e ok 2023-07-25 21:32:52 -07:00
Alex Cope b2ecf2c856 fix 2023-07-25 21:32:52 -07:00
Alex Cope e80aba694c fix 2023-07-25 21:32:52 -07:00
Alex Cope f774a17d8a fix 2023-07-25 21:32:52 -07:00
Alex Cope 329bf17e97 fix 2023-07-25 21:32:52 -07:00
Alex Cope 4da21dd328 clean 2023-07-25 21:32:52 -07:00
Alex Cope 3792ffb580 fix 2023-07-25 21:32:52 -07:00
Alex Cope 271c2cb92c meminfo 2023-07-25 21:32:52 -07:00
Alex Cope 4c0cf9e5cd fix 2023-07-25 21:32:52 -07:00
Alex Cope e3cdc765a1 fix 2023-07-25 21:32:52 -07:00
Alex Cope 60d74262dc fixes 2023-07-25 21:32:52 -07:00
Alex Cope 65b7fafd29 llu 2023-07-25 21:32:52 -07:00
Alex Cope ac7e6c0691 fix compiler errors 2023-07-25 21:32:52 -07:00
Alex Cope 87012bf98e update sys free 2023-07-25 21:32:52 -07:00
Alex Cope 1dc5ea40f3 update 2023-07-25 21:32:51 -07:00
Alex Cope 22d5ce41f3 update 2023-07-25 21:32:51 -07:00
Alex Cope c9d63c50c0 update 2023-07-25 21:32:51 -07:00
Alex Cope 39e3141a0a revert 2023-07-25 21:32:51 -07:00
Alex Cope 1f2c179124 with config 2023-07-25 21:32:24 -07:00
Alex Cope 4c3d9341fd port changes to 6.3 2023-07-25 21:31:42 -07:00
Rolf Ahrenberg 821b39acac Use tini in Alpine-based Docker image (#682) 2023-07-26 00:20:41 -04:00
Karthick Ariyaratnam (A) 0d01b810c3 Fix a fug where repl-backlog-size config was modifed in keydb.conf with the runtime value during config rewrite. 2023-07-14 13:12:16 -04:00
Karthick AriyaratnamandKarthick Ariyaratnam 501ae473e1 Fix a bug where a temp rdb file with zero bytes is generated in flash mode. (#696)
Co-authored-by: Karthick Ariyaratnam (A) <k00809413@china.huawei.com>
2023-07-13 13:26:00 -04:00
Ikko Eltociear Ashimine 6f77a82480 Fix typo in module.cpp (#686)
comparision -> comparison
2023-07-05 18:38:39 -04:00
Philipp Trulson 8e052f728c Enable KeyDB FLASH in Docker images (#687) 2023-07-05 18:38:14 -04:00
Pim van den Broek 26285d3dd5 Fix redis-cli symlink (#689) 2023-07-05 18:37:35 -04:00
27 changed files with 235 additions and 123 deletions

No files matched your search

+2 -1
View File
@@ -53,7 +53,7 @@ RUN set -eux; \
grep -E '^ *createBoolConfig[(]"protected-mode",.*, *1 *,.*[)],$' ./src/config.cpp; \
sed -ri 's!^( *createBoolConfig[(]"protected-mode",.*, *)1( *,.*[)],)$!\10\2!' ./src/config.cpp; \
grep -E '^ *createBoolConfig[(]"protected-mode",.*, *0 *,.*[)],$' ./src/config.cpp; \
make -j$(nproc) BUILD_TLS=yes; \
make -j$(nproc) BUILD_TLS=yes ENABLE_FLASH=yes; \
cd src; \
strip keydb-cli keydb-benchmark keydb-check-rdb keydb-check-aof keydb-diagnostic-tool keydb-sentinel keydb-server; \
mv keydb-server keydb-cli keydb-benchmark keydb-check-rdb keydb-check-aof keydb-diagnostic-tool keydb-sentinel /usr/local/bin/; \
@@ -83,6 +83,7 @@ RUN \
sed -i 's/^\(logfile .*\)$/# \1/' /etc/keydb/keydb.conf; \
sed -i 's/protected-mode yes/protected-mode no/g' /etc/keydb/keydb.conf; \
sed -i 's/^\(bind .*\)$/# \1/' /etc/keydb/keydb.conf; \
cd /usr/local/bin; \
ln -s keydb-cli redis-cli; \
cd /etc/keydb; \
ln -s keydb.conf redis.conf; \
+4 -3
View File
@@ -5,7 +5,7 @@ RUN mkdir -p /etc/keydb
ARG BRANCH
RUN set -eux; \
\
apk add --no-cache su-exec; \
apk add --no-cache su-exec tini; \
apk add --no-cache --virtual .build-deps \
coreutils \
gcc \
@@ -32,7 +32,7 @@ RUN set -eux; \
grep -E '^ *createBoolConfig[(]"protected-mode",.*, *1 *,.*[)],$' ./src/config.cpp; \
sed -ri 's!^( *createBoolConfig[(]"protected-mode",.*, *)1( *,.*[)],)$!\10\2!' ./src/config.cpp; \
grep -E '^ *createBoolConfig[(]"protected-mode",.*, *0 *,.*[)],$' ./src/config.cpp; \
make -j$(nproc) BUILD_TLS=yes; \
make -j$(nproc) BUILD_TLS=yes ENABLE_FLASH=yes; \
cd src; \
strip keydb-cli keydb-benchmark keydb-check-rdb keydb-check-aof keydb-diagnostic-tool keydb-sentinel keydb-server; \
mv keydb-server keydb-cli keydb-benchmark keydb-check-rdb keydb-check-aof keydb-diagnostic-tool keydb-sentinel /usr/local/bin/; \
@@ -54,6 +54,7 @@ RUN set -eux; \
sed -i 's/^\(logfile .*\)$/# \1/' /etc/keydb/keydb.conf; \
sed -i 's/protected-mode yes/protected-mode no/g' /etc/keydb/keydb.conf; \
sed -i 's/^\(bind .*\)$/# \1/' /etc/keydb/keydb.conf; \
cd /usr/local/bin; \
ln -s keydb-cli redis-cli; \
cd /etc/keydb; \
ln -s keydb.conf redis.conf; \
@@ -76,6 +77,6 @@ RUN set -eux; \
chmod +x /usr/local/bin/docker-entrypoint.sh
VOLUME /data
WORKDIR /data
ENTRYPOINT ["docker-entrypoint.sh"]
ENTRYPOINT ["tini", "--", "docker-entrypoint.sh"]
EXPOSE 6379
CMD ["keydb-server", "/etc/keydb/keydb.conf"]
+1 -1
View File
@@ -44,7 +44,7 @@ public:
endWriteBatch();
}
virtual std::vector<std::string> getExpirationCandidates(unsigned int count, long long time) = 0;
virtual std::vector<std::string> getExpirationCandidates(unsigned int count) = 0;
virtual std::vector<std::string> getEvictionCandidates(unsigned int count) = 0;
virtual void setExpire(const char *key, size_t cchKey, long long expire) = 0;
virtual void removeExpire(const char *key, size_t cchKey, long long expire) = 0;
+1 -1
View File
@@ -51,7 +51,7 @@ public:
bool enumerate(IStorage::callback fn) const { return m_spstorage->enumerate(fn); }
bool enumerate_hashslot(IStorage::callback fn, unsigned int hashslot) const { return m_spstorage->enumerate_hashslot(fn, hashslot); }
std::vector<std::string> getExpirationCandidates(unsigned int count, long long time) { return m_spstorage->getExpirationCandidates(count, time); }
std::vector<std::string> getExpirationCandidates(unsigned int count) { return m_spstorage->getExpirationCandidates(count); }
std::vector<std::string> getEvictionCandidates(unsigned int count) { return m_spstorage->getEvictionCandidates(count); }
void setExpire(const char *key, size_t cchKey, long long expire) { m_spstorage->setExpire(key, cchKey, expire); }
void removeExpire(const char *key, size_t cchKey, long long expire) { m_spstorage->removeExpire(key, cchKey, expire); }
+30 -1
View File
@@ -113,6 +113,8 @@ enum class AE_ASYNC_OP
PostCppFunction,
DeleteFileEvent,
CreateFileEvent,
PostAsynDBFunction,
};
struct aeCommand
@@ -125,6 +127,8 @@ struct aeCommand
aePostFunctionProc *proc;
aeFileProc *fproc;
std::function<void()> *pfn;
aePostFunctionTokenProc* tproc;
};
void *clientData;
};
@@ -175,6 +179,17 @@ void aeProcessCmd(aeEventLoop *eventLoop, int fd, void *, int )
(*cmd.pfn)();
delete cmd.pfn;
break;
}
case AE_ASYNC_OP::PostAsynDBFunction:
{ //added to support async api IStorage
if (cmd.fLock && !ulock.owns_lock()) {
g_forkLock.releaseRead();
ulock.lock();
g_forkLock.acquireRead();
}
((aePostFunctionTokenProc*)cmd.tproc)(eventLoop,(StorageToken*)cmd.clientData);
break;
}
break;
}
@@ -256,6 +271,20 @@ int aePostFunction(aeEventLoop *eventLoop, aePostFunctionProc *proc, void *arg)
return AE_OK;
}
int aePostFunction(aeEventLoop *eventLoop, aePostFunctionTokenProc *proc, StorageToken *token)
{
//added to support async api IStorage
aeCommand cmd = {};
cmd.op = AE_ASYNC_OP::PostAsynDBFunction;
cmd.tproc = proc;
cmd.clientData = (void*)token;
cmd.fLock = true;
auto size = write(eventLoop->fdCmdWrite, &cmd, sizeof(cmd));
if (size != sizeof(cmd))
return AE_ERR;
return AE_OK;
}
int aePostFunction(aeEventLoop *eventLoop, std::function<void()> fn, bool fLock, bool fForceQueue)
{
if (eventLoop == g_eventLoopThisThread && !fForceQueue)
@@ -861,7 +890,7 @@ void aeReleaseForkLock()
void aeForkLockInChild()
{
g_forkLock.setNotify(false);
g_forkLock.setMulti(false);
}
int aeThreadOwnsLock()
+5 -1
View File
@@ -72,13 +72,15 @@ extern "C" {
#define AE_NOTUSED(V) ((void) V)
struct aeEventLoop;
/* Types and data structures */
typedef void aeFileProc(struct aeEventLoop *eventLoop, int fd, void *clientData, int mask);
typedef int aeTimeProc(struct aeEventLoop *eventLoop, long long id, void *clientData);
typedef void aeEventFinalizerProc(struct aeEventLoop *eventLoop, void *clientData);
typedef void aeBeforeSleepProc(struct aeEventLoop *eventLoop);
typedef void aePostFunctionProc(void *pvArgs);
//added to support async api IStorage
struct StorageToken;
typedef void aePostFunctionTokenProc(struct aeEventLoop *el, struct StorageToken *token);
/* File event structure */
typedef struct aeFileEvent {
@@ -134,6 +136,8 @@ int aePostFunction(aeEventLoop *eventLoop, aePostFunctionProc *proc, void *arg);
#ifdef __cplusplus
} // EXTERN C
int aePostFunction(aeEventLoop *eventLoop, std::function<void()> fn, bool fLock = true, bool fForceQueue = false);
//added to support async api IStorage
int aePostFunction(aeEventLoop *eventLoop, aePostFunctionTokenProc *proc, StorageToken *token);
extern "C" {
#endif
void aeDeleteEventLoop(aeEventLoop *eventLoop);
+3 -1
View File
@@ -5991,7 +5991,9 @@ clusterNode *getNodeByQuery(client *c, struct redisCommand *cmd, robj **argv, in
/* If it is not the first key, make sure it is exactly
* the same key as the first we saw. */
if (!equalStringObjects(firstkey,thiskey)) {
if (slot != thisslot) {
clusterNode* nThisKey = g_pserver->cluster->slots[thisslot];
if ((slot != thisslot) && (nThisKey != n || migrating_slot || importing_slot || g_pserver->cluster->migrating_slots_to[slot] != nullptr || g_pserver->cluster->importing_slots_from[slot] != nullptr)) {
/* Error: multiple keys from different slots. */
getKeysFreeResult(&result);
if (error_code)
+2 -1
View File
@@ -2946,7 +2946,7 @@ standardConfig configs[] = {
createLongLongConfig("latency-monitor-threshold", NULL, MODIFIABLE_CONFIG, 0, LLONG_MAX, g_pserver->latency_monitor_threshold, 0, INTEGER_CONFIG, NULL, NULL),
createLongLongConfig("proto-max-bulk-len", NULL, MODIFIABLE_CONFIG, 1024*1024, LLONG_MAX, g_pserver->proto_max_bulk_len, 512ll*1024*1024, MEMORY_CONFIG, NULL, NULL), /* Bulk request max size */
createLongLongConfig("stream-node-max-entries", NULL, MODIFIABLE_CONFIG, 0, LLONG_MAX, g_pserver->stream_node_max_entries, 100, INTEGER_CONFIG, NULL, NULL),
createLongLongConfig("repl-backlog-size", NULL, MODIFIABLE_CONFIG, 1, LLONG_MAX, g_pserver->repl_backlog_size, 1024*1024, MEMORY_CONFIG, NULL, updateReplBacklogSize), /* Default: 1mb */
createLongLongConfig("repl-backlog-size", NULL, MODIFIABLE_CONFIG, 1, LLONG_MAX, g_pserver->repl_backlog_config_size, 1024*1024, MEMORY_CONFIG, NULL, updateReplBacklogSize), /* Default: 1mb */
createLongLongConfig("repl-backlog-disk-reserve", NULL, IMMUTABLE_CONFIG, 0, LLONG_MAX, cserver.repl_backlog_disk_size, 0, MEMORY_CONFIG, NULL, NULL),
createLongLongConfig("max-snapshot-slip", NULL, MODIFIABLE_CONFIG, 0, 5000, g_pserver->snapshot_slip, 400, 0, NULL, NULL),
createLongLongConfig("max-rand-count", NULL, MODIFIABLE_CONFIG, 0, LONG_MAX/2, g_pserver->rand_total_threshold, LONG_MAX/2, 0, NULL, NULL),
@@ -2982,6 +2982,7 @@ standardConfig configs[] = {
createSDSConfig("availability-zone", NULL, MODIFIABLE_CONFIG, 0, g_pserver->sdsAvailabilityZone, "", NULL, NULL),
createIntConfig("overload-protect-percent", NULL, MODIFIABLE_CONFIG, 0, 200, g_pserver->overload_protect_threshold, 0, INTEGER_CONFIG, NULL, NULL),
createIntConfig("force-eviction-percent", NULL, MODIFIABLE_CONFIG, 0, 100, g_pserver->force_eviction_percent, 0, INTEGER_CONFIG, NULL, NULL),
createBoolConfig("enable-async-rehash", NULL, MODIFIABLE_CONFIG, g_pserver->enable_async_rehash, 1, NULL, NULL),
#ifdef USE_OPENSSL
createIntConfig("tls-port", NULL, MODIFIABLE_CONFIG, 0, 65535, g_pserver->tls_port, 0, INTEGER_CONFIG, NULL, updateTLSPort), /* TCP port. */
+8 -6
View File
@@ -2703,11 +2703,6 @@ void redisDbPersistentData::prepOverwriteForSnapshot(char *key)
auto itr = m_pdbSnapshot->find_cached_threadsafe(key);
if (itr.key() != nullptr)
{
if (itr.val()->FExpires()) {
// Note: I'm sure we could handle this, but its too risky at the moment.
// There are known bugs doing this with expires
return;
}
sds keyNew = sdsdupshared(itr.key());
if (dictAdd(m_pdictTombstone, keyNew, (void*)dictHashKey(m_pdict, key)) != DICT_OK)
sdsfree(keyNew);
@@ -2745,6 +2740,13 @@ void redisDbPersistentData::clear(void(callback)(void*))
if (m_spstorage != nullptr)
m_spstorage->clear(callback);
dictEmpty(m_pdictTombstone,callback);
// To avoid issues with async rehash we completly free the old dict and create a fresh one
dictRelease(m_pdict);
dictRelease(m_pdictTombstone);
m_pdict = dictCreate(&dbDictType, this);
m_pdictTombstone = dictCreate(&dbTombstoneDictType, this);
m_pdbSnapshot = nullptr;
m_numexpires = 0;
}
@@ -2880,10 +2882,10 @@ LNotFound:
{
dictAdd(m_pdict, sdsNewKey, o);
o->SetFExpires(spexpire != nullptr);
if (spexpire != nullptr) {
o->expire = std::move(*spexpire);
}
o->SetFExpires(spexpire != nullptr);
g_pserver->stat_storage_provider_read_hits++;
} else {
sdsfree(sdsNewKey);
+67 -21
View File
@@ -79,6 +79,7 @@ void printCrashReport(void);
void bugReportEnd(int killViaSignal, int sig);
void logStackTrace(void *eip, int uplevel);
void getTempFileName(char tmpfile[], int tmpfileNum);
bool initializeStorageProvider(const char **err);
/* ================================= Debugging ============================== */
@@ -308,7 +309,7 @@ void computeDatasetDigest(unsigned char *final) {
mixDigest(final,&aux,sizeof(aux));
/* Iterate this DB writing every entry */
db->iterate_threadsafe([final, db](const char *key, robj_roptr o)->bool {
db->iterate_threadsafe([final](const char *key, robj_roptr o)->bool {
unsigned char digest[20];
robj *keyobj;
@@ -535,30 +536,75 @@ NULL
return;
}
}
if (g_pserver->m_pstorageFactory) {
protectClient(c);
/* The default behavior is to save the RDB file before loading
* it back. */
if (save) {
rdbSaveInfo rsi, *rsiptr;
rsiptr = rdbPopulateSaveInfo(&rsi);
if (rdbSave(nullptr, rsiptr) != C_OK) {
addReply(c,shared.err);
for (int idb = 0; idb < cserver.dbnum; ++idb) {
if (g_pserver->db[idb]->processChanges(false))
g_pserver->db[idb]->commitChanges();
g_pserver->db[idb]->storageProviderDelete();
}
delete g_pserver->metadataDb;
if (flush) emptyDb(-1,EMPTYDB_NO_FLAGS,NULL);
delete g_pserver->m_pstorageFactory;
const char *err;
if (!initializeStorageProvider(&err))
{
serverLog(LL_WARNING, "Failed to initialize storage provider: %s",err);
exit(EXIT_FAILURE);
}
g_pserver->metadataDb = g_pserver->m_pstorageFactory->createMetadataDb();
for (int idb = 0; idb < cserver.dbnum; ++idb)
{
int dbid = idb;
std::string dbid_key = "db-" + std::to_string(idb);
g_pserver->metadataDb->retrieve(dbid_key.c_str(), dbid_key.length(), [&](const char *, size_t, const void *data, size_t){
dbid = *(int*)data;
});
delete g_pserver->db[idb];
g_pserver->db[idb] = new (MALLOC_LOCAL) redisDb();
g_pserver->db[idb]->initialize(dbid);
}
moduleFireServerEvent(REDISMODULE_EVENT_LOADING, REDISMODULE_SUBEVENT_LOADING_FLASH_START, NULL);
for (int idb = 0; idb < cserver.dbnum; ++idb)
{
g_pserver->db[idb]->storageProviderInitialize();
g_pserver->db[idb]->trackChanges(false);
}
moduleFireServerEvent(REDISMODULE_EVENT_LOADING, REDISMODULE_SUBEVENT_LOADING_ENDED, NULL);
unprotectClient(c);
} else {
/* The default behavior is to save the RDB file before loading
* it back. */
if (save) {
rdbSaveInfo rsi, *rsiptr;
rsiptr = rdbPopulateSaveInfo(&rsi);
if (rdbSave(nullptr, rsiptr) != C_OK) {
addReply(c,shared.err);
return;
}
}
/* The default behavior is to remove the current dataset from
* memory before loading the RDB file, however when MERGE is
* used together with NOFLUSH, we are able to merge two datasets. */
if (flush) emptyDb(-1,EMPTYDB_NO_FLAGS,NULL);
protectClient(c);
int ret = rdbLoadFile(g_pserver->rdb_filename,NULL,flags);
unprotectClient(c);
if (ret != C_OK) {
addReplyError(c,"Error trying to load the RDB dump");
return;
}
}
/* The default behavior is to remove the current dataset from
* memory before loading the RDB file, however when MERGE is
* used together with NOFLUSH, we are able to merge two datasets. */
if (flush) emptyDb(-1,EMPTYDB_NO_FLAGS,NULL);
protectClient(c);
int ret = rdbLoadFile(g_pserver->rdb_filename,NULL,flags);
unprotectClient(c);
if (ret != C_OK) {
addReplyError(c,"Error trying to load the RDB dump");
return;
}
serverLog(LL_WARNING,"DB reloaded by DEBUG RELOAD");
addReply(c,shared.ok);
} else if (!strcasecmp(szFromObj(c->argv[1]),"loadaof")) {
+5 -3
View File
@@ -518,11 +518,13 @@ void pexpireMemberAtCommand(client *c)
} while (sampled == 0 ||
(expired*100/sampled) > config_cycle_acceptable_stale);
} else {
long long now;
long prev_expired;
long long now = mstime();
size_t tried = 0;
std::vector<std::string> keys;
do {
keys = db->getStorageCache()->getExpirationCandidates(ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP, now);
prev_expired = total_expired;
keys = db->getStorageCache()->getExpirationCandidates(ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP);
for (std::string key : keys) {
robj* keyobj = createStringObject(key.c_str(), key.size());
db->find(szFromObj(keyobj));
@@ -533,7 +535,7 @@ void pexpireMemberAtCommand(client *c)
}
total_sampled += keys.size();
elapsed = ustime()-start;
} while (keys.size() > 0 && (elapsed < timelimit));
} while (keys.size() > 0 && (elapsed < timelimit) && (total_expired - prev_expired) > 0);
if (ustime()-start > timelimit) {
timelimit_exit = 1;
+4
View File
@@ -160,6 +160,8 @@ public:
expireEntry &operator=(expireEntry &&e)
{
if (FFat())
delete pfatentry();
s = e.s;
e.s.m_whenAndPtrUnion = 0;
e.s.fFat = false;
@@ -167,6 +169,8 @@ public:
}
expireEntry &operator=(expireEntry &e) {
if (FFat())
delete pfatentry();
if (e.FFat()) {
s.m_whenAndPtrUnion = reinterpret_cast<long long>(new expireEntryFat(*e.pfatentry()));
s.fFat = true;
+1
View File
@@ -19,6 +19,7 @@ static size_t getMemKey(std::string key) {
}
return 0;
# else
(void)key;
return 0;
# endif
}
+4 -3
View File
@@ -690,8 +690,9 @@ void moduleHandlePropagationAfterCommandCallback(RedisModuleCtx *ctx) {
}
/* Free the context after the user function was called. */
void moduleFreeContext(RedisModuleCtx *ctx) {
moduleHandlePropagationAfterCommandCallback(ctx);
void moduleFreeContext(RedisModuleCtx *ctx, bool propogate) {
if (propogate)
moduleHandlePropagationAfterCommandCallback(ctx);
autoMemoryCollect(ctx);
poolAllocRelease(ctx);
if (ctx->postponed_arrays) {
@@ -7057,7 +7058,7 @@ RedisModuleString *RM_DictPrev(RedisModuleCtx *ctx, RedisModuleDictIter *di, voi
/* Compare the element currently pointed by the iterator to the specified
* element given by key/keylen, according to the operator 'op' (the set of
* valid operators are the same valid for RedisModule_DictIteratorStart).
* If the comparision is successful the command returns REDISMODULE_OK
* If the comparison is successful the command returns REDISMODULE_OK
* otherwise REDISMODULE_ERR is returned.
*
* This is useful when we want to just emit a lexicographical range, so
+1 -1
View File
@@ -4,7 +4,7 @@ OBJECT_FILES := modmain.o
MODSNAP_CXX_FLAGS := -std=gnu++14
%.o: %.cpp
$(CXX) -o $@ -c $< $(MODULE_FLAGS) -I../../../deps/cpp-statsd-client/include $(MODSNAP_CXX_FLAGS)
$(CXX) -o $@ -c $< $(MODULE_FLAGS) -I../../../deps/cpp-statsd-client/include $(MODSNAP_CXX_FLAGS) -g
modstatsd.so: $(OBJECT_FILES)
$(CXX) -shared $(OBJECT_FILES) -o modstatsd.so
+14 -11
View File
@@ -76,7 +76,7 @@ std::string m_strPrefix { "keydb" };
const std::regex g_replica_or_db_info_regex { "^(slave|db)(\\d+)" };
const char *g_string_counter_separator = "__";
const uint64_t g_stats_buffer_size_bytes = 1600;
utsname sysName;
std::string nodeName;
int unameResult;
enum class StatsD_Type {
@@ -582,7 +582,7 @@ void event_cron_handler(struct RedisModuleCtx *ctx, RedisModuleEvent eid, uint64
size_t startTime = ustime();
#ifdef __linux__
/* Log CPU Usage */
/* Log CPU Usage */
static long long s_mscpuLast = 0;
struct rusage self_ru;
getrusage(RUSAGE_SELF, &self_ru);
@@ -591,7 +591,7 @@ void event_cron_handler(struct RedisModuleCtx *ctx, RedisModuleEvent eid, uint64
+ (self_ru.ru_stime.tv_sec * 1000) + (self_ru.ru_stime.tv_usec / 1000);
g_stats->gauge("cpu_load_perc", (double)(mscpuCur - s_mscpuLast) / ((curTime - lastTime)*1000), true /* prefixOnly */);
g_stats->gauge("cpu_load_perc", ((double)(mscpuCur - s_mscpuLast) / ((curTime - lastTime)*1000))*100, false /* prefixOnly */);
s_mscpuLast = mscpuCur;
#endif
@@ -600,7 +600,7 @@ void event_cron_handler(struct RedisModuleCtx *ctx, RedisModuleEvent eid, uint64
/* node name */
if (unameResult == 0) {
g_stats->increment("node_name" + std::string(g_string_counter_separator) + sysName.nodename);
g_stats->increment("node_name" + std::string(g_string_counter_separator) + nodeName);
}
/* Log INFO Fields */
@@ -653,7 +653,7 @@ void event_cron_handler(struct RedisModuleCtx *ctx, RedisModuleEvent eid, uint64
reply = RedisModule_Call(ctx, "dbsize", "");
long long keys = RedisModule_CallReplyInteger(reply);
RedisModule_FreeCallReply(reply);
g_stats->gauge("keys", keys);
g_stats->gauge("keys", keys, false /* prefixOnly */);
RedisModule_Log(ctx, REDISMODULE_LOGLEVEL_DEBUG, "Emitting metric \"keys\": %llu", keys);
g_stats->timing("emit_keys_metric_time_taken_us", ustime() - commandStartTime);
@@ -672,17 +672,20 @@ extern "C" int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv,
RedisModule_AutoMemory(ctx);
/* Use pod name if available*/
const char *podName = getenv("POD_NAME");
utsname sysName;
unameResult = uname(&sysName);
if (unameResult == 0) {
nodeName = std::string(sysName.nodename);
std::replace(nodeName.begin(), nodeName.end(), '.', '-');
}
if (podName != nullptr) {
m_strPrefix = podName;
std::replace(m_strPrefix.begin(), m_strPrefix.end(), '.', '-');
}
else {
if (unameResult == 0) {
m_strPrefix = std::string(sysName.nodename);
unameResult = 1;
}
else if (unameResult == 0) {
m_strPrefix = nodeName;
unameResult = 1;
}
std::replace(m_strPrefix.begin(), m_strPrefix.end(), '.', '-');
for (int iarg = 0; iarg < argc; ++iarg) {
size_t len = 0;
+2
View File
@@ -46,6 +46,7 @@ robj *createObject(int type, void *ptr) {
char *oB = (char*)zcalloc(sizeof(robj)+mvccExtraBytes, MALLOC_SHARED);
robj *o = reinterpret_cast<robj*>(oB + mvccExtraBytes);
new (o) redisObject;
o->type = type;
o->encoding = OBJ_ENCODING_RAW;
o->m_ptr = ptr;
@@ -418,6 +419,7 @@ void decrRefCount(robj_roptr o) {
case OBJ_NESTEDHASH: freeNestedHashObject(o); break;
default: serverPanic("Unknown object type"); break;
}
o->~redisObject();
if (g_pserver->fActiveReplica) {
zfree(reinterpret_cast<redisObjectExtended*>(o.unsafe_robjcast())-1);
} else {
+1 -1
View File
@@ -2542,7 +2542,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb, sds key, int *error, uint64_t mvcc_ts
* encoding version in the lower 10 bits of the module ID. */
void *ptr = mt->rdb_load(&io,moduleid&1023);
if (io.ctx) {
moduleFreeContext(io.ctx);
moduleFreeContext(io.ctx, false /* propogate */);
zfree(io.ctx);
}
+47 -33
View File
@@ -8,38 +8,46 @@ class readWriteLock {
int m_readCount = 0;
int m_writeCount = 0;
bool m_writeWaiting = false;
bool m_notify = true;
bool m_multi = true;
public:
readWriteLock(const char *name) : m_readLock(name), m_writeLock(name) {}
void acquireRead() {
std::unique_lock<fastlock> rm(m_readLock);
while (m_writeCount > 0 || m_writeWaiting)
m_cv.wait(rm);
std::unique_lock<fastlock> rm(m_readLock, std::defer_lock);
if (m_multi) {
rm.lock();
while (m_writeCount > 0 || m_writeWaiting)
m_cv.wait(rm);
}
m_readCount++;
}
bool tryAcquireRead() {
std::unique_lock<fastlock> rm(m_readLock, std::defer_lock);
if (!rm.try_lock())
return false;
if (m_writeCount > 0 || m_writeWaiting)
return false;
if (m_multi) {
if (!rm.try_lock())
return false;
if (m_writeCount > 0 || m_writeWaiting)
return false;
}
m_readCount++;
return true;
}
void acquireWrite(bool exclusive = true) {
std::unique_lock<fastlock> rm(m_readLock);
m_writeWaiting = true;
while (m_readCount > 0)
m_cv.wait(rm);
if (exclusive) {
/* Another thread might have the write lock while we have the read lock
but won't be able to release it until they can acquire the read lock
so release the read lock and try again instead of waiting to avoid deadlock */
while(!m_writeLock.try_lock())
std::unique_lock<fastlock> rm(m_readLock, std::defer_lock);
if (m_multi) {
rm.lock();
m_writeWaiting = true;
while (m_readCount > 0)
m_cv.wait(rm);
if (exclusive) {
/* Another thread might have the write lock while we have the read lock
but won't be able to release it until they can acquire the read lock
so release the read lock and try again instead of waiting to avoid deadlock */
while(!m_writeLock.try_lock())
m_cv.wait(rm);
}
}
m_writeCount++;
m_writeWaiting = false;
@@ -52,32 +60,38 @@ public:
bool tryAcquireWrite(bool exclusive = true) {
std::unique_lock<fastlock> rm(m_readLock, std::defer_lock);
if (!rm.try_lock())
return false;
if (m_readCount > 0)
return false;
if (exclusive)
if (!m_writeLock.try_lock())
if (m_multi) {
if (!rm.try_lock())
return false;
if (m_readCount > 0)
return false;
if (exclusive)
if (!m_writeLock.try_lock())
return false;
}
m_writeCount++;
return true;
}
void releaseRead() {
std::unique_lock<fastlock> rm(m_readLock);
m_readCount--;
if (m_notify)
std::unique_lock<fastlock> rm(m_readLock, std::defer_lock);
if (m_multi) {
rm.lock();
m_cv.notify_all();
}
m_readCount--;
}
void releaseWrite(bool exclusive = true) {
std::unique_lock<fastlock> rm(m_readLock);
std::unique_lock<fastlock> rm(m_readLock, std::defer_lock);
serverAssert(m_writeCount > 0);
if (exclusive)
m_writeLock.unlock();
m_writeCount--;
if (m_notify)
if (m_multi) {
rm.lock();
if (exclusive)
m_writeLock.unlock();
m_cv.notify_all();
}
m_writeCount--;
}
void downgradeWrite(bool exclusive = true) {
@@ -85,8 +99,8 @@ public:
acquireRead();
}
void setNotify(bool notify) {
m_notify = notify;
void setMulti(bool multi) {
m_multi = multi;
}
bool hasReader() {
+3 -1
View File
@@ -188,6 +188,8 @@ int bg_unlink(const char *filename) {
/* ---------------------------------- MASTER -------------------------------- */
bool createDiskBacklog() {
if (g_pserver->repl_backlog_disk != nullptr)
return true; // already exists
// Lets create some disk backed pages and add them here
std::string path = "./repl-backlog-temp" + std::to_string(gettid());
#if (defined __APPLE__ || defined __FreeBSD__)
@@ -3733,7 +3735,7 @@ retry_connect:
}
/* Prepare a suitable temp file for bulk transfer */
if (!useDisklessLoad()) {
if (!useDisklessLoad() && !mi->isRocksdbSnapshotRepl) {
while(maxtries--) {
auto dt = std::chrono::system_clock::now().time_since_epoch();
auto dtMillisecond = std::chrono::duration_cast<std::chrono::milliseconds>(dt);
+6 -4
View File
@@ -2137,7 +2137,7 @@ void databasesCron(bool fMainThread) {
::dict *dict = g_pserver->db[rehash_db]->dictUnsafeKeyOnly();
/* Are we async rehashing? And if so is it time to re-calibrate? */
/* The recalibration limit is a prime number to ensure balancing across threads */
if (rehashes_per_ms > 0 && async_rehashes < 131 && !cserver.active_defrag_enabled && cserver.cthreads > 1 && dictSize(dict) > 2048 && dictIsRehashing(dict) && !g_pserver->loading) {
if (g_pserver->enable_async_rehash && rehashes_per_ms > 0 && async_rehashes < 131 && !cserver.active_defrag_enabled && cserver.cthreads > 1 && dictSize(dict) > 2048 && dictIsRehashing(dict) && !g_pserver->loading && aeLockContention() > 1) {
serverTL->rehashCtl = dictRehashAsyncStart(dict, rehashes_per_ms * ((1000 / g_pserver->hz) / 10)); // Estimate 10% CPU time spent in lock contention
if (serverTL->rehashCtl)
++async_rehashes;
@@ -5663,7 +5663,8 @@ sds genRedisInfoString(const char *section) {
"lru_clock:%u\r\n"
"executable:%s\r\n"
"config_file:%s\r\n"
"availability_zone:%s\r\n",
"availability_zone:%s\r\n"
"features:%s\r\n",
KEYDB_SET_VERSION,
redisGitSHA1(),
strtol(redisGitDirty(),NULL,10) > 0,
@@ -5690,7 +5691,8 @@ sds genRedisInfoString(const char *section) {
lruclock,
cserver.executable ? cserver.executable : "",
cserver.configfile ? cserver.configfile : "",
g_pserver->sdsAvailabilityZone);
g_pserver->sdsAvailabilityZone,
"cluster_mget");
}
/* Clients */
@@ -7411,7 +7413,7 @@ static void validateConfiguration()
exit(EXIT_FAILURE);
}
g_pserver->repl_backlog_config_size = g_pserver->repl_backlog_size; // this is normally set in the update logic, but not on initial config
g_pserver->repl_backlog_size = g_pserver->repl_backlog_config_size; // this is normally set in the update logic, but not on initial config
}
int iAmMaster(void) {
+3 -1
View File
@@ -966,6 +966,7 @@ struct redisObjectExtended {
typedef struct redisObject {
friend redisObject *createEmbeddedStringObject(const char *ptr, size_t len);
friend redisObject *createObject(int type, void *ptr);
protected:
redisObject() {}
@@ -2305,6 +2306,7 @@ struct redisServer {
rax *errors; /* Errors table */
int activerehashing; /* Incremental rehash in serverCron() */
int active_defrag_running; /* Active defragmentation running (holds current scan aggressiveness) */
int enable_async_rehash = 1; /* Should we use the async rehash feature? */
int cronloops; /* Number of times the cron function run */
char runid[CONFIG_RUN_ID_SIZE+1]; /* ID always different at every exec. */
int sentinel_mode; /* True if this instance is a Sentinel. */
@@ -2917,7 +2919,7 @@ int moduleGetCommandKeysViaAPI(struct redisCommand *cmd, robj **argv, int argc,
moduleType *moduleTypeLookupModuleByID(uint64_t id);
void moduleTypeNameByID(char *name, uint64_t moduleid);
const char *moduleTypeModuleName(moduleType *mt);
void moduleFreeContext(struct RedisModuleCtx *ctx);
void moduleFreeContext(struct RedisModuleCtx *ctx, bool propogate = true);
void unblockClientFromModule(client *c);
void moduleHandleBlockedClients(int iel);
void moduleBlockedClientTimedOut(client *c);
+5 -1
View File
@@ -587,8 +587,12 @@ bool redisDbPersistentDataSnapshot::iterate_threadsafe_core(std::function<bool(c
if (!fKeyOnly)
{
size_t offset = 0;
deserializeExpire((const char*)data, cbData, &offset);
std::unique_ptr<expireEntry> spexpire = deserializeExpire((const char*)data, cbData, &offset);
o = deserializeStoredObject(reinterpret_cast<const char*>(data)+offset, cbData-offset);
o->SetFExpires(spexpire != nullptr);
if (spexpire != nullptr) {
o->expire = std::move(*spexpire);
}
}
fContinue = fn(sdsKey, o);
if (o != nullptr)
+14 -10
View File
@@ -149,11 +149,22 @@ size_t RocksDBStorageProvider::clear()
rocksdb::ColumnFamilyHandle *handle = nullptr;
rocksdb::ColumnFamilyOptions cf_options(m_pfactory->RocksDbOptions());
cf_options.level_compaction_dynamic_level_bytes = true;
m_spdb->CreateColumnFamily(cf_options, strName, &handle);
m_spcolfamily = std::shared_ptr<rocksdb::ColumnFamilyHandle>(handle);
if (!status.ok())
throw status.ToString();
status = m_spdb->DropColumnFamily(m_spexpirecolfamily.get());
strName = m_spexpirecolfamily->GetName();
m_spdb->CreateColumnFamily(cf_options, strName, &handle);
m_spexpirecolfamily = std::shared_ptr<rocksdb::ColumnFamilyHandle>(handle);
if (!status.ok())
throw status.ToString();
m_count = 0;
return celem;
}
@@ -242,21 +253,14 @@ void RocksDBStorageProvider::removeExpire(const char *key, size_t cchKey, long l
throw status.ToString();
}
std::vector<std::string> RocksDBStorageProvider::getExpirationCandidates(unsigned int count, long long time)
std::vector<std::string> RocksDBStorageProvider::getExpirationCandidates(unsigned int count)
{
std::vector<std::string> result;
std::unique_ptr<rocksdb::Iterator> it = std::unique_ptr<rocksdb::Iterator>(m_spdb->NewIterator(ReadOptions(), m_spexpirecolfamily.get()));
for (it->SeekToFirst(); it->Valid() && (*((long long *)it->key().data()) < time) && (result.size() < count); it->Next()) {
for (it->SeekToFirst(); it->Valid() && result.size() < count; it->Next()) {
if (FInternalKey(it->key().data(), it->key().size()))
continue;
result.emplace_back(it->value().data(), it->value().size());
rocksdb::Status status;
if (m_spbatch)
status = m_spbatch->Delete(m_spexpirecolfamily.get(), it->key());
else
status = m_spdb->Delete(WriteOptions(), m_spexpirecolfamily.get(), it->key());
if (!status.ok())
throw status.ToString();
}
return result;
}
@@ -277,7 +281,7 @@ std::vector<std::string> RocksDBStorageProvider::getEvictionCandidates(unsigned
}
} else {
std::unique_ptr<rocksdb::Iterator> it = std::unique_ptr<rocksdb::Iterator>(m_spdb->NewIterator(ReadOptions(), m_spexpirecolfamily.get()));
for (it->SeekToFirst(); it->Valid() && result.size() < 16; it->Next()) {
for (it->SeekToFirst(); it->Valid() && result.size() < count; it->Next()) {
if (FInternalKey(it->key().data(), it->key().size()))
continue;
result.emplace_back(it->value().data(), it->value().size());
+1 -1
View File
@@ -36,7 +36,7 @@ public:
virtual bool enumerate(callback fn) const override;
virtual bool enumerate_hashslot(callback fn, unsigned int hashslot) const override;
virtual std::vector<std::string> getExpirationCandidates(unsigned int count, long long time) override;
virtual std::vector<std::string> getExpirationCandidates(unsigned int count) override;
virtual std::vector<std::string> getEvictionCandidates(unsigned int count) override;
virtual void setExpire(const char *key, size_t cchKey, long long expire) override;
virtual void removeExpire(const char *key, size_t cchKey, long long expire) override;
+1 -1
View File
@@ -29,7 +29,7 @@ public:
virtual bool enumerate_hashslot(callback fn, unsigned int hashslot) const override;
virtual size_t count() const override;
virtual std::vector<std::string> getExpirationCandidates(unsigned int, long long) override { return std::vector<std::string>(); }
virtual std::vector<std::string> getExpirationCandidates(unsigned int) override { return std::vector<std::string>(); }
virtual std::vector<std::string> getEvictionCandidates(unsigned int) override { return std::vector<std::string>(); }
virtual void setExpire(const char *, size_t, long long) override {}
virtual void removeExpire(const char *, size_t, long long) override {}
-15
View File
@@ -81,21 +81,6 @@ if {$::flash_enabled} {
}
}
test { EXPIRE reduces used disk space } {
r flushall
r set testkey foo ex 10
r debug flush-storage
set used [r debug get-storage-usage]
assert_equal {1} [r dbsize]
wait_for_condition 50 1000 {
[r dbsize] == 0
} else {
fail "key is not expired"
}
set after [r debug get-storage-usage]
assert {$after < $used}
}
test { SUBKEY EXPIRE persists after cache flush } {
r flushall
r sadd testkey foo bar baz