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.
This commit is contained in:
Matt Stancliff 2014-05-12 11:44:37 -04:00
parent 764b000c3e
commit d8c7db1bdb

View File

@ -44,6 +44,16 @@
#define RDB_LOAD_ENC (1<<0) #define RDB_LOAD_ENC (1<<0)
#define RDB_LOAD_PLAIN (1<<1) #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) { static int rdbWriteRaw(rio *rdb, void *p, size_t len) {
if (rdb && rioWrite(rdb,p,len) == 0) if (rdb && rioWrite(rdb,p,len) == 0)
return -1; return -1;
@ -188,7 +198,7 @@ void *rdbLoadIntegerObject(rio *rdb, int enctype, int flags) {
val = (int32_t)v; val = (int32_t)v;
} else { } else {
val = 0; /* anti-warning */ val = 0; /* anti-warning */
redisPanic("Unknown RDB integer encoding type"); rdbExitReportCorruptRDB("Unknown RDB integer encoding type");
} }
if (plain) { if (plain) {
char buf[REDIS_LONGSTR_SIZE], *p; char buf[REDIS_LONGSTR_SIZE], *p;
@ -394,7 +404,7 @@ void *rdbGenericLoadStringObject(rio *rdb, int flags) {
case REDIS_RDB_ENC_LZF: case REDIS_RDB_ENC_LZF:
return rdbLoadLzfStringObject(rdb,flags); return rdbLoadLzfStringObject(rdb,flags);
default: 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. /* Load a Redis object of the specified type from the specified file.
* On success a newly allocated object is returned, otherwise NULL. */ * On success a newly allocated object is returned, otherwise NULL. */
robj *rdbLoadObject(int rdbtype, rio *rdb) { robj *rdbLoadObject(int rdbtype, rio *rdb) {
robj *o, *ele, *dec; robj *o = NULL, *ele, *dec;
size_t len; size_t len;
unsigned int i; unsigned int i;
@ -1078,7 +1088,9 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
/* Add pair to hash table */ /* Add pair to hash table */
ret = dictAdd((dict*)o->ptr, field, value); 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 */ /* All pairs should be read by now */
@ -1164,11 +1176,11 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
hashTypeConvert(o, REDIS_ENCODING_HT); hashTypeConvert(o, REDIS_ENCODING_HT);
break; break;
default: default:
redisPanic("Unknown encoding"); rdbExitReportCorruptRDB("Unknown encoding");
break; break;
} }
} else { } else {
redisPanic("Unknown object type"); rdbExitReportCorruptRDB("Unknown object type");
} }
return o; return o;
} }