summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2020-04-09 12:02:27 +0200
committerantirez <antirez@gmail.com>2020-04-09 12:10:10 +0200
commit451872527cec0b369211284b48e48867f5d168a9 (patch)
treee8d6d699f1c1042ca135043f3c13b716ed0f5596
parent3d5b2d41b52906269778c42fec40d3c85535b9bf (diff)
downloadredis-451872527cec0b369211284b48e48867f5d168a9.tar.gz
More powerful DEBUG RELOAD.
Related to #3243.
-rw-r--r--src/debug.c45
-rw-r--r--src/rdb.c18
-rw-r--r--src/rdb.h8
3 files changed, 55 insertions, 16 deletions
diff --git a/src/debug.c b/src/debug.c
index baaaa2424..1351b2536 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -366,7 +366,7 @@ void debugCommand(client *c) {
"OOM -- Crash the server simulating an out-of-memory error.",
"PANIC -- Crash the server simulating a panic.",
"POPULATE <count> [prefix] [size] -- Create <count> string keys named key:<num>. If a prefix is specified is used instead of the 'key' prefix.",
-"RELOAD -- Save the RDB on disk and reload it back in memory.",
+"RELOAD [MERGE] [NOFLUSH] [NOSAVE] -- Save the RDB on disk and reload it back in memory. By default it will save the RDB file and load it back. With the NOFLUSH option the current database is not removed before loading the new one, but conficts in keys will kill the server with an exception. When MERGE is used, conflicting keys will be loaded (the key in the loaded RDB file will win). When NOSAVE is used, the server will not save the current dataset in the RDB file before loading. Use DEBUG RELOAD NOSAVE when you want just to load the RDB file you placed in the Redis working directory in order to replace the current dataset in memory. Use DEBUG RELOAD NOSAVE NOFLUSH MERGE when you want to add what is in the current RDB file placed in the Redis current directory, with the current memory content. Use DEBUG RELOAD when you want to verify Redis is able to persist the current dataset in the RDB file, flush the memory content, and load it back.",
"RESTART -- Graceful restart: save config, db, restart.",
"SDSLEN <key> -- Show low level SDS string info representing key and value.",
"SEGFAULT -- Crash the server with sigsegv.",
@@ -411,15 +411,44 @@ NULL
serverLog(LL_WARNING, "DEBUG LOG: %s", (char*)c->argv[2]->ptr);
addReply(c,shared.ok);
} else if (!strcasecmp(c->argv[1]->ptr,"reload")) {
- rdbSaveInfo rsi, *rsiptr;
- rsiptr = rdbPopulateSaveInfo(&rsi);
- if (rdbSave(server.rdb_filename,rsiptr) != C_OK) {
- addReply(c,shared.err);
- return;
+ int flush = 1, save = 1;
+ int flags = RDBFLAGS_NONE;
+
+ /* Parse the additional options that modify the RELOAD
+ * behavior. */
+ for (int j = 2; j < c->argc; j++) {
+ char *opt = c->argv[j]->ptr;
+ if (!strcasecmp(opt,"MERGE")) {
+ flags |= RDBFLAGS_ALLOW_DUP;
+ } else if (!strcasecmp(opt,"NOFLUSH")) {
+ flush = 0;
+ } else if (!strcasecmp(opt,"NOSAVE")) {
+ save = 0;
+ } else {
+ addReplyError(c,"DEBUG RELOAD only supports the "
+ "MERGE, NOFLUSH and NOSAVE options.");
+ return;
+ }
}
- emptyDb(-1,EMPTYDB_NO_FLAGS,NULL);
+
+ /* The default beahvior is to save the RDB file before loading
+ * it back. */
+ if (save) {
+ rdbSaveInfo rsi, *rsiptr;
+ rsiptr = rdbPopulateSaveInfo(&rsi);
+ if (rdbSave(server.rdb_filename,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 = rdbLoad(server.rdb_filename,NULL,RDBFLAGS_NONE);
+ int ret = rdbLoad(server.rdb_filename,NULL,flags);
unprotectClient(c);
if (ret != C_OK) {
addReplyError(c,"Error trying to load the RDB dump");
diff --git a/src/rdb.c b/src/rdb.c
index 313830c25..3f25535ab 100644
--- a/src/rdb.c
+++ b/src/rdb.c
@@ -2242,18 +2242,28 @@ int rdbLoadRio(rio *rdb, int rdbflags, rdbSaveInfo *rsi) {
sdsfree(key);
decrRefCount(val);
} else {
+ robj keyobj;
+
/* Add the new object in the hash table */
int retval = dictAdd(db->dict, key, val);
if (retval != DICT_OK) {
- serverLog(LL_WARNING,
- "RDB has duplicated key '%s' in DB %d",key,db->id);
- serverPanic("Duplicated key found in RDB file");
+ if (rdbflags & RDBFLAGS_ALLOW_DUP) {
+ /* This flag is useful for DEBUG RELOAD special modes.
+ * When it's set we allow new keys to replace the current
+ * keys with the same name. */
+ initStaticStringObject(keyobj,key);
+ dbSyncDelete(db,&keyobj);
+ dictAdd(db->dict, key, val);
+ } else {
+ serverLog(LL_WARNING,
+ "RDB has duplicated key '%s' in DB %d",key,db->id);
+ serverPanic("Duplicated key found in RDB file");
+ }
}
if (server.cluster_enabled) slotToKeyAdd(key);
/* Set the expire time if needed */
if (expiretime != -1) {
- robj keyobj;
initStaticStringObject(keyobj,key);
setExpire(NULL,db,&keyobj,expiretime);
}
diff --git a/src/rdb.h b/src/rdb.h
index 9dfcae7a5..aae682dbc 100644
--- a/src/rdb.h
+++ b/src/rdb.h
@@ -122,10 +122,10 @@
#define RDB_LOAD_SDS (1<<2)
/* flags on the purpose of rdb save or load */
-#define RDBFLAGS_NONE 0
-#define RDBFLAGS_AOF_PREAMBLE (1<<0)
-#define RDBFLAGS_REPLICATION (1<<1)
-#define RDBFLAGS_ALLOW_DUP (1<<2)
+#define RDBFLAGS_NONE 0 /* No special RDB loading. */
+#define RDBFLAGS_AOF_PREAMBLE (1<<0) /* Load/save the RDB as AOF preamble. */
+#define RDBFLAGS_REPLICATION (1<<1) /* Load/save for SYNC. */
+#define RDBFLAGS_ALLOW_DUP (1<<2) /* Allow duplicated keys when loading.*/
int rdbSaveType(rio *rdb, unsigned char type);
int rdbLoadType(rio *rdb);