Skip to content

Commit

Permalink
Convert check-dump to Redis check-rdb mode
Browse files Browse the repository at this point in the history
redis-check-dump is now named redis-check-rdb and it runs
as a mode of redis-server instead of an independent binary.

You can now use 'redis-server redis.conf --check-rdb' to check
the RDB defined in redis.conf.  Using argument --check-rdb
checks the RDB and exits.  We could potentially also allow
the server to continue starting if the RDB check succeeds.

This change also enables us to use RDB checking programatically
from inside Redis for certain failure conditions.
  • Loading branch information
mattsta committed Jan 28, 2015
1 parent 9802ec3 commit 145473a
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 45 deletions.
19 changes: 9 additions & 10 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 ""
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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

Expand Down Expand Up @@ -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)
59 changes: 24 additions & 35 deletions src/redis-check-dump.c → src/redis-check-rdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,18 +133,13 @@ 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 checkType(unsigned char t) {
/* In case a new object type is added, update the following
* condition as necessary. */
return
Expand All @@ -154,7 +149,7 @@ int checkType(unsigned char t) {
}

/* 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;

Expand Down Expand Up @@ -188,7 +183,7 @@ int processHeader(void) {
return dump_version;
}

int loadType(entry *e) {
static int loadType(entry *e) {
uint32_t offset = CURR_OFFSET;

/* this byte needs to qualify as type */
Expand All @@ -208,15 +203,15 @@ int loadType(entry *e) {
return 0;
}

int peekType() {
static int peekType() {
unsigned char t;
if (readBytes(&t, -1) && (checkType(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;
Expand All @@ -231,7 +226,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;
Expand All @@ -257,7 +252,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;
Expand Down Expand Up @@ -289,7 +284,7 @@ char *loadIntegerObject(int enctype) {
return buf;
}

char* loadLzfStringObject() {
static char* loadLzfStringObject() {
unsigned int slen, clen;
char *c, *s;

Expand All @@ -313,7 +308,7 @@ char* loadLzfStringObject() {
}

/* returns NULL when not processable, char* when valid */
char* loadStringObject() {
static char* loadStringObject() {
uint32_t offset = CURR_OFFSET;
int isencoded;
uint32_t len;
Expand All @@ -336,7 +331,7 @@ 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)) {
Expand All @@ -346,7 +341,7 @@ char* loadStringObject() {
return buf;
}

int processStringObject(char** store) {
static int processStringObject(char** store) {
unsigned long offset = CURR_OFFSET;
char *key = loadStringObject();
if (key == NULL) {
Expand All @@ -363,7 +358,7 @@ int processStringObject(char** store) {
return 1;
}

double* loadDoubleValue() {
static double* loadDoubleValue() {
char buf[256];
unsigned char len;
double* val;
Expand All @@ -386,7 +381,7 @@ double* loadDoubleValue() {
}
}

int processDoubleValue(double** store) {
static int processDoubleValue(double** store) {
unsigned long offset = CURR_OFFSET;
double *val = loadDoubleValue();
if (val == NULL) {
Expand All @@ -403,7 +398,7 @@ int processDoubleValue(double** store) {
return 1;
}

int loadPair(entry *e) {
static int loadPair(entry *e) {
uint32_t offset = CURR_OFFSET;
uint32_t i;

Expand Down Expand Up @@ -486,7 +481,7 @@ int loadPair(entry *e) {
return 1;
}

entry loadEntry() {
static entry loadEntry() {
entry e = { NULL, -1, 0 };
uint32_t length, offset[4];

Expand Down Expand Up @@ -544,7 +539,7 @@ 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);
Expand All @@ -554,21 +549,21 @@ void printCentered(int indent, int width, char* body) {
printf("%s %s %s\n", 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];

Expand Down Expand Up @@ -708,24 +703,18 @@ void process(void) {
}
}

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\n", rdbfilename);
}
if (fstat(fd, &stat) == -1) {
ERROR("Cannot stat: %s\n", argv[1]);
ERROR("Cannot stat: %s\n", rdbfilename);
} else {
size = stat.st_size;
}
Expand All @@ -736,7 +725,7 @@ int main(int argc, char **argv) {

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\n", rdbfilename);
}

/* Initialize static vars */
Expand Down
24 changes: 24 additions & 0 deletions src/redis.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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," ");
Expand All @@ -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]);
Expand Down
3 changes: 3 additions & 0 deletions src/redis.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down

0 comments on commit 145473a

Please sign in to comment.