summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSalvatore Sanfilippo <antirez@gmail.com>2015-01-28 17:30:27 +0100
committerSalvatore Sanfilippo <antirez@gmail.com>2015-01-28 17:30:27 +0100
commitd3ef6c94bfa2d063f0fdbf128fba20119f5c1986 (patch)
tree1bcf4755f5d8c49df470961f5fb926c23bbc2e48
parent9802ec3c83cf6b61edad50bc41ddb3f6fdb13c6f (diff)
parentd8c7db1bdba3938f31856a067b2966285acbf97f (diff)
downloadredis-d3ef6c94bfa2d063f0fdbf128fba20119f5c1986.tar.gz
Merge pull request #1744 from mattsta/better-RDB-failure-error
Improve Loading RDB Failure Action
-rw-r--r--src/Makefile19
-rw-r--r--src/rdb.c24
-rw-r--r--src/redis-check-rdb.c (renamed from src/redis-check-dump.c)239
-rw-r--r--src/redis.c24
-rw-r--r--src/redis.h3
5 files changed, 137 insertions, 172 deletions
diff --git a/src/Makefile b/src/Makefile
index 295600c4e..271ab34d8 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -117,17 +117,16 @@ endif
REDIS_SERVER_NAME=redis-server
REDIS_SENTINEL_NAME=redis-sentinel
-REDIS_SERVER_OBJ=adlist.o quicklist.o ae.o anet.o dict.o redis.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o
+REDIS_SERVER_OBJ=adlist.o quicklist.o ae.o anet.o dict.o redis.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o
REDIS_CLI_NAME=redis-cli
REDIS_CLI_OBJ=anet.o sds.o adlist.o redis-cli.o zmalloc.o release.o anet.o ae.o crc64.o
REDIS_BENCHMARK_NAME=redis-benchmark
REDIS_BENCHMARK_OBJ=ae.o anet.o redis-benchmark.o sds.o adlist.o zmalloc.o redis-benchmark.o
-REDIS_CHECK_DUMP_NAME=redis-check-dump
-REDIS_CHECK_DUMP_OBJ=redis-check-dump.o lzf_c.o lzf_d.o crc64.o
+REDIS_CHECK_RDB_NAME=redis-check-rdb
REDIS_CHECK_AOF_NAME=redis-check-aof
REDIS_CHECK_AOF_OBJ=redis-check-aof.o
-all: $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_DUMP_NAME) $(REDIS_CHECK_AOF_NAME)
+all: $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_RDB_NAME) $(REDIS_CHECK_AOF_NAME)
@echo ""
@echo "Hint: It's a good idea to run 'make test' ;)"
@echo ""
@@ -178,6 +177,10 @@ $(REDIS_SERVER_NAME): $(REDIS_SERVER_OBJ)
$(REDIS_SENTINEL_NAME): $(REDIS_SERVER_NAME)
$(REDIS_INSTALL) $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME)
+# redis-check-rdb
+$(REDIS_CHECK_RDB_NAME): $(REDIS_SERVER_NAME)
+ $(REDIS_INSTALL) $(REDIS_SERVER_NAME) $(REDIS_CHECK_RDB_NAME)
+
# redis-cli
$(REDIS_CLI_NAME): $(REDIS_CLI_OBJ)
$(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/linenoise/linenoise.o $(FINAL_LIBS)
@@ -186,10 +189,6 @@ $(REDIS_CLI_NAME): $(REDIS_CLI_OBJ)
$(REDIS_BENCHMARK_NAME): $(REDIS_BENCHMARK_OBJ)
$(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a $(FINAL_LIBS)
-# redis-check-dump
-$(REDIS_CHECK_DUMP_NAME): $(REDIS_CHECK_DUMP_OBJ)
- $(REDIS_LD) -o $@ $^ $(FINAL_LIBS)
-
# redis-check-aof
$(REDIS_CHECK_AOF_NAME): $(REDIS_CHECK_AOF_OBJ)
$(REDIS_LD) -o $@ $^ $(FINAL_LIBS)
@@ -201,7 +200,7 @@ $(REDIS_CHECK_AOF_NAME): $(REDIS_CHECK_AOF_OBJ)
$(REDIS_CC) -c $<
clean:
- rm -rf $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_DUMP_NAME) $(REDIS_CHECK_AOF_NAME) *.o *.gcda *.gcno *.gcov redis.info lcov-html
+ rm -rf $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_RDB_NAME) $(REDIS_CHECK_AOF_NAME) *.o *.gcda *.gcno *.gcov redis.info lcov-html
.PHONY: clean
@@ -257,6 +256,6 @@ install: all
$(REDIS_INSTALL) $(REDIS_SERVER_NAME) $(INSTALL_BIN)
$(REDIS_INSTALL) $(REDIS_BENCHMARK_NAME) $(INSTALL_BIN)
$(REDIS_INSTALL) $(REDIS_CLI_NAME) $(INSTALL_BIN)
- $(REDIS_INSTALL) $(REDIS_CHECK_DUMP_NAME) $(INSTALL_BIN)
+ $(REDIS_INSTALL) $(REDIS_CHECK_RDB_NAME) $(INSTALL_BIN)
$(REDIS_INSTALL) $(REDIS_CHECK_AOF_NAME) $(INSTALL_BIN)
@ln -sf $(REDIS_SERVER_NAME) $(INSTALL_BIN)/$(REDIS_SENTINEL_NAME)
diff --git a/src/rdb.c b/src/rdb.c
index d5e3a7f47..3cf8344aa 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;
}
diff --git a/src/redis-check-dump.c b/src/redis-check-rdb.c
index 546462001..c34204204 100644
--- a/src/redis-check-dump.c
+++ b/src/redis-check-rdb.c
@@ -29,74 +29,19 @@
*/
+#include "redis.h"
+#include "rdb.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
-#include <string.h>
-#include <arpa/inet.h>
-#include <stdint.h>
-#include <limits.h>
#include "lzf.h"
#include "crc64.h"
-/* Object types */
-#define REDIS_STRING 0
-#define REDIS_LIST 1
-#define REDIS_SET 2
-#define REDIS_ZSET 3
-#define REDIS_HASH 4
-#define REDIS_HASH_ZIPMAP 9
-#define REDIS_LIST_ZIPLIST 10
-#define REDIS_SET_INTSET 11
-#define REDIS_ZSET_ZIPLIST 12
-#define REDIS_HASH_ZIPLIST 13
-
-/* Objects encoding. Some kind of objects like Strings and Hashes can be
- * internally represented in multiple ways. The 'encoding' field of the object
- * is set to one of this fields for this object. */
-#define REDIS_ENCODING_RAW 0 /* Raw representation */
-#define REDIS_ENCODING_INT 1 /* Encoded as integer */
-#define REDIS_ENCODING_ZIPMAP 2 /* Encoded as zipmap */
-#define REDIS_ENCODING_HT 3 /* Encoded as a hash table */
-
-/* Object types only used for dumping to disk */
-#define REDIS_EXPIRETIME_MS 252
-#define REDIS_EXPIRETIME 253
-#define REDIS_SELECTDB 254
-#define REDIS_EOF 255
-
-/* Defines related to the dump file format. To store 32 bits lengths for short
- * keys requires a lot of space, so we check the most significant 2 bits of
- * the first byte to interpreter the length:
- *
- * 00|000000 => if the two MSB are 00 the len is the 6 bits of this byte
- * 01|000000 00000000 => 01, the len is 14 byes, 6 bits + 8 bits of next byte
- * 10|000000 [32 bit integer] => if it's 01, a full 32 bit len will follow
- * 11|000000 this means: specially encoded object will follow. The six bits
- * number specify the kind of object that follows.
- * See the REDIS_RDB_ENC_* defines.
- *
- * Lengths up to 63 are stored using a single byte, most DB keys, and may
- * values, will fit inside. */
-#define REDIS_RDB_6BITLEN 0
-#define REDIS_RDB_14BITLEN 1
-#define REDIS_RDB_32BITLEN 2
-#define REDIS_RDB_ENCVAL 3
-#define REDIS_RDB_LENERR UINT_MAX
-
-/* When a length of a string object stored on disk has the first two bits
- * set, the remaining two bits specify a special encoding for the object
- * accordingly to the following defines: */
-#define REDIS_RDB_ENC_INT8 0 /* 8 bit signed integer */
-#define REDIS_RDB_ENC_INT16 1 /* 16 bit signed integer */
-#define REDIS_RDB_ENC_INT32 2 /* 32 bit signed integer */
-#define REDIS_RDB_ENC_LZF 3 /* string compressed with FASTLZ */
-
#define ERROR(...) { \
- printf(__VA_ARGS__); \
+ redisLog(REDIS_WARNING, __VA_ARGS__); \
exit(1); \
}
@@ -133,28 +78,23 @@ typedef struct {
char success;
} entry;
-/* Global vars that are actually used as constants. The following double
- * values are used for double on-disk serialization, and are initialized
- * at runtime to avoid strange compiler optimizations. */
-static double R_Zero, R_PosInf, R_NegInf, R_Nan;
-
#define MAX_TYPES_NUM 256
#define MAX_TYPE_NAME_LEN 16
/* store string types for output */
static char types[MAX_TYPES_NUM][MAX_TYPE_NAME_LEN];
/* Return true if 't' is a valid object type. */
-int checkType(unsigned char t) {
+static int rdbCheckType(unsigned char t) {
/* In case a new object type is added, update the following
* condition as necessary. */
return
- (t >= REDIS_HASH_ZIPMAP && t <= REDIS_HASH_ZIPLIST) ||
- t <= REDIS_HASH ||
- t >= REDIS_EXPIRETIME_MS;
+ (t >= REDIS_RDB_TYPE_HASH_ZIPMAP && t <= REDIS_RDB_TYPE_HASH_ZIPLIST) ||
+ t <= REDIS_RDB_TYPE_HASH ||
+ t >= REDIS_RDB_OPCODE_EXPIRETIME_MS;
}
/* when number of bytes to read is negative, do a peek */
-int readBytes(void *target, long num) {
+static int readBytes(void *target, long num) {
char peek = (num < 0) ? 1 : 0;
num = (num < 0) ? -num : num;
@@ -173,28 +113,28 @@ int processHeader(void) {
int dump_version;
if (!readBytes(buf, 9)) {
- ERROR("Cannot read header\n");
+ ERROR("Cannot read header");
}
/* expect the first 5 bytes to equal REDIS */
if (memcmp(buf,"REDIS",5) != 0) {
- ERROR("Wrong signature in header\n");
+ ERROR("Wrong signature in header");
}
dump_version = (int)strtol(buf + 5, NULL, 10);
if (dump_version < 1 || dump_version > 6) {
- ERROR("Unknown RDB format version: %d\n", dump_version);
+ ERROR("Unknown RDB format version: %d", dump_version);
}
return dump_version;
}
-int loadType(entry *e) {
+static int loadType(entry *e) {
uint32_t offset = CURR_OFFSET;
/* this byte needs to qualify as type */
unsigned char t;
if (readBytes(&t, 1)) {
- if (checkType(t)) {
+ if (rdbCheckType(t)) {
e->type = t;
return 1;
} else {
@@ -208,18 +148,18 @@ int loadType(entry *e) {
return 0;
}
-int peekType() {
+static int peekType() {
unsigned char t;
- if (readBytes(&t, -1) && (checkType(t)))
+ if (readBytes(&t, -1) && (rdbCheckType(t)))
return t;
return -1;
}
/* discard time, just consume the bytes */
-int processTime(int type) {
+static int processTime(int type) {
uint32_t offset = CURR_OFFSET;
unsigned char t[8];
- int timelen = (type == REDIS_EXPIRETIME_MS) ? 8 : 4;
+ int timelen = (type == REDIS_RDB_OPCODE_EXPIRETIME_MS) ? 8 : 4;
if (readBytes(t,timelen)) {
return 1;
@@ -231,7 +171,7 @@ int processTime(int type) {
return 0;
}
-uint32_t loadLength(int *isencoded) {
+static uint32_t loadLength(int *isencoded) {
unsigned char buf[2];
uint32_t len;
int type;
@@ -257,7 +197,7 @@ uint32_t loadLength(int *isencoded) {
}
}
-char *loadIntegerObject(int enctype) {
+static char *loadIntegerObject(int enctype) {
uint32_t offset = CURR_OFFSET;
unsigned char enc[4];
long long val;
@@ -284,36 +224,36 @@ char *loadIntegerObject(int enctype) {
/* convert val into string */
char *buf;
- buf = malloc(sizeof(char) * 128);
+ buf = zmalloc(sizeof(char) * 128);
sprintf(buf, "%lld", val);
return buf;
}
-char* loadLzfStringObject() {
+static char* loadLzfStringObject() {
unsigned int slen, clen;
char *c, *s;
if ((clen = loadLength(NULL)) == REDIS_RDB_LENERR) return NULL;
if ((slen = loadLength(NULL)) == REDIS_RDB_LENERR) return NULL;
- c = malloc(clen);
+ c = zmalloc(clen);
if (!readBytes(c, clen)) {
- free(c);
+ zfree(c);
return NULL;
}
- s = malloc(slen+1);
+ s = zmalloc(slen+1);
if (lzf_decompress(c,clen,s,slen) == 0) {
- free(c); free(s);
+ zfree(c); zfree(s);
return NULL;
}
- free(c);
+ zfree(c);
return s;
}
/* returns NULL when not processable, char* when valid */
-char* loadStringObject() {
+static char* loadStringObject() {
uint32_t offset = CURR_OFFSET;
int isencoded;
uint32_t len;
@@ -336,48 +276,48 @@ char* loadStringObject() {
if (len == REDIS_RDB_LENERR) return NULL;
- char *buf = malloc(sizeof(char) * (len+1));
+ char *buf = zmalloc(sizeof(char) * (len+1));
if (buf == NULL) return NULL;
buf[len] = '\0';
if (!readBytes(buf, len)) {
- free(buf);
+ zfree(buf);
return NULL;
}
return buf;
}
-int processStringObject(char** store) {
+static int processStringObject(char** store) {
unsigned long offset = CURR_OFFSET;
char *key = loadStringObject();
if (key == NULL) {
SHIFT_ERROR(offset, "Error reading string object");
- free(key);
+ zfree(key);
return 0;
}
if (store != NULL) {
*store = key;
} else {
- free(key);
+ zfree(key);
}
return 1;
}
-double* loadDoubleValue() {
+static double* loadDoubleValue() {
char buf[256];
unsigned char len;
double* val;
if (!readBytes(&len,1)) return NULL;
- val = malloc(sizeof(double));
+ val = zmalloc(sizeof(double));
switch(len) {
case 255: *val = R_NegInf; return val;
case 254: *val = R_PosInf; return val;
case 253: *val = R_Nan; return val;
default:
if (!readBytes(buf, len)) {
- free(val);
+ zfree(val);
return NULL;
}
buf[len] = '\0';
@@ -386,24 +326,24 @@ double* loadDoubleValue() {
}
}
-int processDoubleValue(double** store) {
+static int processDoubleValue(double** store) {
unsigned long offset = CURR_OFFSET;
double *val = loadDoubleValue();
if (val == NULL) {
SHIFT_ERROR(offset, "Error reading double value");
- free(val);
+ zfree(val);
return 0;
}
if (store != NULL) {
*store = val;
} else {
- free(val);
+ zfree(val);
}
return 1;
}
-int loadPair(entry *e) {
+static int loadPair(entry *e) {
uint32_t offset = CURR_OFFSET;
uint32_t i;
@@ -417,10 +357,10 @@ int loadPair(entry *e) {
}
uint32_t length = 0;
- if (e->type == REDIS_LIST ||
- e->type == REDIS_SET ||
- e->type == REDIS_ZSET ||
- e->type == REDIS_HASH) {
+ if (e->type == REDIS_RDB_TYPE_LIST ||
+ e->type == REDIS_RDB_TYPE_SET ||
+ e->type == REDIS_RDB_TYPE_ZSET ||
+ e->type == REDIS_RDB_TYPE_HASH) {
if ((length = loadLength(NULL)) == REDIS_RDB_LENERR) {
SHIFT_ERROR(offset, "Error reading %s length", types[e->type]);
return 0;
@@ -428,19 +368,19 @@ int loadPair(entry *e) {
}
switch(e->type) {
- case REDIS_STRING:
- case REDIS_HASH_ZIPMAP:
- case REDIS_LIST_ZIPLIST:
- case REDIS_SET_INTSET:
- case REDIS_ZSET_ZIPLIST:
- case REDIS_HASH_ZIPLIST:
+ case REDIS_RDB_TYPE_STRING:
+ case REDIS_RDB_TYPE_HASH_ZIPMAP:
+ case REDIS_RDB_TYPE_LIST_ZIPLIST:
+ case REDIS_RDB_TYPE_SET_INTSET:
+ case REDIS_RDB_TYPE_ZSET_ZIPLIST:
+ case REDIS_RDB_TYPE_HASH_ZIPLIST:
if (!processStringObject(NULL)) {
SHIFT_ERROR(offset, "Error reading entry value");
return 0;
}
break;
- case REDIS_LIST:
- case REDIS_SET:
+ case REDIS_RDB_TYPE_LIST:
+ case REDIS_RDB_TYPE_SET:
for (i = 0; i < length; i++) {
offset = CURR_OFFSET;
if (!processStringObject(NULL)) {
@@ -449,7 +389,7 @@ int loadPair(entry *e) {
}
}
break;
- case REDIS_ZSET:
+ case REDIS_RDB_TYPE_ZSET:
for (i = 0; i < length; i++) {
offset = CURR_OFFSET;
if (!processStringObject(NULL)) {
@@ -463,7 +403,7 @@ int loadPair(entry *e) {
}
}
break;
- case REDIS_HASH:
+ case REDIS_RDB_TYPE_HASH:
for (i = 0; i < length; i++) {
offset = CURR_OFFSET;
if (!processStringObject(NULL)) {
@@ -486,7 +426,7 @@ int loadPair(entry *e) {
return 1;
}
-entry loadEntry() {
+static entry loadEntry() {
entry e = { NULL, -1, 0 };
uint32_t length, offset[4];
@@ -499,7 +439,7 @@ entry loadEntry() {
}
offset[1] = CURR_OFFSET;
- if (e.type == REDIS_SELECTDB) {
+ if (e.type == REDIS_RDB_OPCODE_SELECTDB) {
if ((length = loadLength(NULL)) == REDIS_RDB_LENERR) {
SHIFT_ERROR(offset[1], "Error reading database number");
return e;
@@ -508,7 +448,7 @@ entry loadEntry() {
SHIFT_ERROR(offset[1], "Database number out of range (%d)", length);
return e;
}
- } else if (e.type == REDIS_EOF) {
+ } else if (e.type == REDIS_RDB_OPCODE_EOF) {
if (positions[level].offset < positions[level].size) {
SHIFT_ERROR(offset[0], "Unexpected EOF");
} else {
@@ -517,8 +457,8 @@ entry loadEntry() {
return e;
} else {
/* optionally consume expire */
- if (e.type == REDIS_EXPIRETIME ||
- e.type == REDIS_EXPIRETIME_MS) {
+ if (e.type == REDIS_RDB_OPCODE_EXPIRETIME ||
+ e.type == REDIS_RDB_OPCODE_EXPIRETIME_MS) {
if (!processTime(e.type)) return e;
if (!loadType(&e)) return e;
}
@@ -544,31 +484,31 @@ entry loadEntry() {
return e;
}
-void printCentered(int indent, int width, char* body) {
+static void printCentered(int indent, int width, char* body) {
char head[256], tail[256];
memset(head, '\0', 256);
memset(tail, '\0', 256);
memset(head, '=', indent);
memset(tail, '=', width - 2 - indent - strlen(body));
- printf("%s %s %s\n", head, body, tail);
+ redisLog(REDIS_WARNING, "%s %s %s", head, body, tail);
}
-void printValid(uint64_t ops, uint64_t bytes) {
+static void printValid(uint64_t ops, uint64_t bytes) {
char body[80];
sprintf(body, "Processed %llu valid opcodes (in %llu bytes)",
(unsigned long long) ops, (unsigned long long) bytes);
printCentered(4, 80, body);
}
-void printSkipped(uint64_t bytes, uint64_t offset) {
+static void printSkipped(uint64_t bytes, uint64_t offset) {
char body[80];
sprintf(body, "Skipped %llu bytes (resuming at 0x%08llx)",
(unsigned long long) bytes, (unsigned long long) offset);
printCentered(4, 80, body);
}
-void printErrorStack(entry *e) {
+static void printErrorStack(entry *e) {
unsigned int i;
char body[64];
@@ -598,7 +538,7 @@ void printErrorStack(entry *e) {
/* display error stack */
for (i = 0; i < errors.level; i++) {
- printf("0x%08lx - %s\n",
+ redisLog(REDIS_WARNING, "0x%08lx - %s",
(unsigned long) errors.offset[i], errors.error[i]);
}
}
@@ -611,7 +551,7 @@ void process(void) {
/* Exclude the final checksum for RDB >= 5. Will be checked at the end. */
if (dump_version >= 5) {
if (positions[0].size < 8) {
- printf("RDB version >= 5 but no room for checksum.\n");
+ redisLog(REDIS_WARNING, "RDB version >= 5 but no room for checksum.");
exit(1);
}
positions[0].size -= 8;
@@ -660,7 +600,7 @@ void process(void) {
/* advance position */
positions[0] = positions[1];
}
- free(entry.key);
+ zfree(entry.key);
}
/* because there is another potential error,
@@ -668,7 +608,7 @@ void process(void) {
printValid(num_valid_ops, num_valid_bytes);
/* expect an eof */
- if (entry.type != REDIS_EOF) {
+ if (entry.type != REDIS_RDB_OPCODE_EOF) {
/* last byte should be EOF, add error */
errors.level = 0;
SHIFT_ERROR(positions[0].offset, "Expected EOF, got %s", types[entry.type]);
@@ -696,47 +636,40 @@ void process(void) {
if (crc != crc2) {
SHIFT_ERROR(positions[0].offset, "RDB CRC64 does not match.");
} else {
- printf("CRC64 checksum is OK\n");
+ redisLog(REDIS_WARNING, "CRC64 checksum is OK");
}
}
/* print summary on errors */
if (num_errors) {
- printf("\n");
- printf("Total unprocessable opcodes: %llu\n",
+ redisLog(REDIS_WARNING, "Total unprocessable opcodes: %llu",
(unsigned long long) num_errors);
}
}
-int main(int argc, char **argv) {
- /* expect the first argument to be the dump file */
- if (argc <= 1) {
- printf("Usage: %s <dump.rdb>\n", argv[0]);
- exit(0);
- }
-
+int redis_check_rdb(char *rdbfilename) {
int fd;
off_t size;
struct stat stat;
void *data;
- fd = open(argv[1], O_RDONLY);
+ fd = open(rdbfilename, O_RDONLY);
if (fd < 1) {
- ERROR("Cannot open file: %s\n", argv[1]);
+ ERROR("Cannot open file: %s", rdbfilename);
}
if (fstat(fd, &stat) == -1) {
- ERROR("Cannot stat: %s\n", argv[1]);
+ ERROR("Cannot stat: %s", rdbfilename);
} else {
size = stat.st_size;
}
if (sizeof(size_t) == sizeof(int32_t) && size >= INT_MAX) {
- ERROR("Cannot check dump files >2GB on a 32-bit platform\n");
+ ERROR("Cannot check dump files >2GB on a 32-bit platform");
}
data = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
if (data == MAP_FAILED) {
- ERROR("Cannot mmap: %s\n", argv[1]);
+ ERROR("Cannot mmap: %s", rdbfilename);
}
/* Initialize static vars */
@@ -746,22 +679,16 @@ int main(int argc, char **argv) {
errors.level = 0;
/* Object types */
- sprintf(types[REDIS_STRING], "STRING");
- sprintf(types[REDIS_LIST], "LIST");
- sprintf(types[REDIS_SET], "SET");
- sprintf(types[REDIS_ZSET], "ZSET");
- sprintf(types[REDIS_HASH], "HASH");
+ sprintf(types[REDIS_RDB_TYPE_STRING], "STRING");
+ sprintf(types[REDIS_RDB_TYPE_LIST], "LIST");
+ sprintf(types[REDIS_RDB_TYPE_SET], "SET");
+ sprintf(types[REDIS_RDB_TYPE_ZSET], "ZSET");
+ sprintf(types[REDIS_RDB_TYPE_HASH], "HASH");
/* Object types only used for dumping to disk */
- sprintf(types[REDIS_EXPIRETIME], "EXPIRETIME");
- sprintf(types[REDIS_SELECTDB], "SELECTDB");
- sprintf(types[REDIS_EOF], "EOF");
-
- /* Double constants initialization */
- R_Zero = 0.0;
- R_PosInf = 1.0/R_Zero;
- R_NegInf = -1.0/R_Zero;
- R_Nan = R_Zero/R_Zero;
+ sprintf(types[REDIS_RDB_OPCODE_EXPIRETIME], "EXPIRETIME");
+ sprintf(types[REDIS_RDB_OPCODE_SELECTDB], "SELECTDB");
+ sprintf(types[REDIS_RDB_OPCODE_EOF], "EOF");
process();
diff --git a/src/redis.c b/src/redis.c
index 13df8d28e..24739cc3c 100644
--- a/src/redis.c
+++ b/src/redis.c
@@ -3550,6 +3550,17 @@ int checkForSentinelMode(int argc, char **argv) {
return 0;
}
+/* Returns 1 if there is --check-rdb among the arguments or if
+ * argv[0] is exactly "redis-check-rdb". */
+int checkForCheckRDBMode(int argc, char **argv) {
+ int j;
+
+ if (strstr(argv[0],"redis-check-rdb") != NULL) return 1;
+ for (j = 1; j < argc; j++)
+ if (!strcmp(argv[j],"--check-rdb")) return 1;
+ return 0;
+}
+
/* Function called at startup to load RDB or AOF file in memory. */
void loadDataFromDisk(void) {
long long start = ustime();
@@ -3766,6 +3777,11 @@ int main(int argc, char **argv) {
while(j != argc) {
if (argv[j][0] == '-' && argv[j][1] == '-') {
/* Option name */
+ if (!strcmp(argv[j], "--check-rdb")) {
+ /* Argument has no options, need to skip for parsing. */
+ j++;
+ continue;
+ }
if (sdslen(options)) options = sdscat(options,"\n");
options = sdscat(options,argv[j]+2);
options = sdscat(options," ");
@@ -3791,9 +3807,17 @@ int main(int argc, char **argv) {
redisLog(REDIS_WARNING, "Warning: no config file specified, using the default config. In order to specify a config file use %s /path/to/%s.conf", argv[0], server.sentinel_mode ? "sentinel" : "redis");
}
+ if (checkForCheckRDBMode(argc, argv)) {
+ redisLog(REDIS_WARNING, "Checking RDB file %s", server.rdb_filename);
+ redisLog(REDIS_WARNING, "To check different RDB file: "
+ "redis-check-rdb --dbfilename <dump.rdb>");
+ exit(redis_check_rdb(server.rdb_filename));
+ }
+
server.supervised = redisIsSupervised(server.supervised_mode);
int background = server.daemonize && !server.supervised;
if (background) daemonize();
+
initServer();
if (background || server.pidfile) createPidFile();
redisSetProcTitle(argv[0]);
diff --git a/src/redis.h b/src/redis.h
index 0c191d06f..87bb811b2 100644
--- a/src/redis.h
+++ b/src/redis.h
@@ -1380,6 +1380,9 @@ void sentinelTimer(void);
char *sentinelHandleConfiguration(char **argv, int argc);
void sentinelIsRunning(void);
+/* redis-check-rdb */
+int redis_check_rdb(char *rdbfilename);
+
/* Scripting */
void scriptingInit(void);