diff options
author | antirez <antirez@gmail.com> | 2010-06-22 00:07:48 +0200 |
---|---|---|
committer | antirez <antirez@gmail.com> | 2010-07-01 14:38:51 +0200 |
commit | e2641e09cc0daf44f63f654230f72d22acf3a9af (patch) | |
tree | f0443876d28414f7c80787593e5f35a9f9c87747 /src/redis-check-aof.c | |
parent | c2ff0e90b8ce84d7b966622ffe0178303bb0a625 (diff) | |
download | redis-e2641e09cc0daf44f63f654230f72d22acf3a9af.tar.gz |
redis.c split into many different C files.
networking related stuff moved into networking.c
moved more code
more work on layout of source code
SDS instantaneuos memory saving. By Pieter and Salvatore at VMware ;)
cleanly compiling again after the first split, now splitting it in more C files
moving more things around... work in progress
split replication code
splitting more
Sets split
Hash split
replication split
even more splitting
more splitting
minor change
Diffstat (limited to 'src/redis-check-aof.c')
-rw-r--r-- | src/redis-check-aof.c | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/src/redis-check-aof.c b/src/redis-check-aof.c new file mode 100644 index 000000000..ff0d1f82c --- /dev/null +++ b/src/redis-check-aof.c @@ -0,0 +1,185 @@ +#include "fmacros.h" +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> +#include "config.h" + +#define ERROR(...) { \ + char __buf[1024]; \ + sprintf(__buf, __VA_ARGS__); \ + sprintf(error, "0x%08lx: %s", epos, __buf); \ +} + +static char error[1024]; +static long epos; + +int consumeNewline(char *buf) { + if (strncmp(buf,"\r\n",2) != 0) { + ERROR("Expected \\r\\n, got: %02x%02x",buf[0],buf[1]); + return 0; + } + return 1; +} + +int readLong(FILE *fp, char prefix, long *target) { + char buf[128], *eptr; + epos = ftell(fp); + if (fgets(buf,sizeof(buf),fp) == NULL) { + return 0; + } + if (buf[0] != prefix) { + ERROR("Expected prefix '%c', got: '%c'",buf[0],prefix); + return 0; + } + *target = strtol(buf+1,&eptr,10); + return consumeNewline(eptr); +} + +int readBytes(FILE *fp, char *target, long length) { + long real; + epos = ftell(fp); + real = fread(target,1,length,fp); + if (real != length) { + ERROR("Expected to read %ld bytes, got %ld bytes",length,real); + return 0; + } + return 1; +} + +int readString(FILE *fp, char** target) { + long len; + *target = NULL; + if (!readLong(fp,'$',&len)) { + return 0; + } + + /* Increase length to also consume \r\n */ + len += 2; + *target = (char*)malloc(len); + if (!readBytes(fp,*target,len)) { + return 0; + } + if (!consumeNewline(*target+len-2)) { + return 0; + } + (*target)[len-2] = '\0'; + return 1; +} + +int readArgc(FILE *fp, long *target) { + return readLong(fp,'*',target); +} + +long process(FILE *fp) { + long argc, pos = 0; + int i, multi = 0; + char *str; + + while(1) { + if (!multi) pos = ftell(fp); + if (!readArgc(fp, &argc)) break; + + for (i = 0; i < argc; i++) { + if (!readString(fp,&str)) break; + if (i == 0) { + if (strcasecmp(str, "multi") == 0) { + if (multi++) { + ERROR("Unexpected MULTI"); + break; + } + } else if (strcasecmp(str, "exec") == 0) { + if (--multi) { + ERROR("Unexpected EXEC"); + break; + } + } + } + free(str); + } + + /* Stop if the loop did not finish */ + if (i < argc) { + if (str) free(str); + break; + } + } + + if (feof(fp) && multi && strlen(error) == 0) { + ERROR("Reached EOF before reading EXEC for MULTI"); + } + if (strlen(error) > 0) { + printf("%s\n", error); + } + return pos; +} + +int main(int argc, char **argv) { + char *filename; + int fix = 0; + + if (argc < 2) { + printf("Usage: %s [--fix] <file.aof>\n", argv[0]); + exit(1); + } else if (argc == 2) { + filename = argv[1]; + } else if (argc == 3) { + if (strcmp(argv[1],"--fix") != 0) { + printf("Invalid argument: %s\n", argv[1]); + exit(1); + } + filename = argv[2]; + fix = 1; + } else { + printf("Invalid arguments\n"); + exit(1); + } + + FILE *fp = fopen(filename,"r+"); + if (fp == NULL) { + printf("Cannot open file: %s\n", filename); + exit(1); + } + + struct redis_stat sb; + if (redis_fstat(fileno(fp),&sb) == -1) { + printf("Cannot stat file: %s\n", filename); + exit(1); + } + + long size = sb.st_size; + if (size == 0) { + printf("Empty file: %s\n", filename); + exit(1); + } + + long pos = process(fp); + long diff = size-pos; + if (diff > 0) { + if (fix) { + char buf[2]; + printf("This will shrink the AOF from %ld bytes, with %ld bytes, to %ld bytes\n",size,diff,pos); + printf("Continue? [y/N]: "); + if (fgets(buf,sizeof(buf),stdin) == NULL || + strncasecmp(buf,"y",1) != 0) { + printf("Aborting...\n"); + exit(1); + } + if (ftruncate(fileno(fp), pos) == -1) { + printf("Failed to truncate AOF\n"); + exit(1); + } else { + printf("Successfully truncated AOF\n"); + } + } else { + printf("AOF is not valid\n"); + exit(1); + } + } else { + printf("AOF is valid\n"); + } + + fclose(fp); + return 0; +} |