From d8c7db1bdba3938f31856a067b2966285acbf97f Mon Sep 17 00:00:00 2001 From: Matt Stancliff Date: Mon, 12 May 2014 11:44:37 -0400 Subject: [PATCH] Improve RDB error-on-load handling Previouly if we loaded a corrupt RDB, Redis printed an error report with a big "REPORT ON GITHUB" message at the bottom. But, we know RDB load failures are corrupt data, not corrupt code. Now when RDB failure is detected (duplicate keys or unknown data types in the file), we run check-rdb against the RDB then exit. The automatic check-rdb hopefully gives the user instant feedback about what is wrong instead of providing a mysterious stack trace. --- src/rdb.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/rdb.c b/src/rdb.c index d5e3a7f4..3cf8344a 100644 --- a/src/rdb.c +++ b/src/rdb.c @@ -44,6 +44,16 @@ #define RDB_LOAD_ENC (1<<0) #define RDB_LOAD_PLAIN (1<<1) +#define rdbExitReportCorruptRDB(reason) rdbCheckThenExit(reason, __LINE__); + +void rdbCheckThenExit(char *reason, int where) { + redisLog(REDIS_WARNING, "Corrupt RDB detected at rdb.c:%d (%s). " + "Running 'redis-check-rdb --dbfilename %s'", + where, reason, server.rdb_filename); + redis_check_rdb(server.rdb_filename); + exit(1); +} + static int rdbWriteRaw(rio *rdb, void *p, size_t len) { if (rdb && rioWrite(rdb,p,len) == 0) return -1; @@ -188,7 +198,7 @@ void *rdbLoadIntegerObject(rio *rdb, int enctype, int flags) { val = (int32_t)v; } else { val = 0; /* anti-warning */ - redisPanic("Unknown RDB integer encoding type"); + rdbExitReportCorruptRDB("Unknown RDB integer encoding type"); } if (plain) { char buf[REDIS_LONGSTR_SIZE], *p; @@ -394,7 +404,7 @@ void *rdbGenericLoadStringObject(rio *rdb, int flags) { case REDIS_RDB_ENC_LZF: return rdbLoadLzfStringObject(rdb,flags); default: - redisPanic("Unknown RDB encoding type"); + rdbExitReportCorruptRDB("Unknown RDB encoding type"); } } @@ -923,7 +933,7 @@ void rdbRemoveTempFile(pid_t childpid) { /* Load a Redis object of the specified type from the specified file. * On success a newly allocated object is returned, otherwise NULL. */ robj *rdbLoadObject(int rdbtype, rio *rdb) { - robj *o, *ele, *dec; + robj *o = NULL, *ele, *dec; size_t len; unsigned int i; @@ -1078,7 +1088,9 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) { /* Add pair to hash table */ ret = dictAdd((dict*)o->ptr, field, value); - redisAssert(ret == DICT_OK); + if (ret == DICT_ERR) { + rdbExitReportCorruptRDB("Duplicate keys detected"); + } } /* All pairs should be read by now */ @@ -1164,11 +1176,11 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) { hashTypeConvert(o, REDIS_ENCODING_HT); break; default: - redisPanic("Unknown encoding"); + rdbExitReportCorruptRDB("Unknown encoding"); break; } } else { - redisPanic("Unknown object type"); + rdbExitReportCorruptRDB("Unknown object type"); } return o; }