2012-11-08 12:25:23 -05:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2009-2012, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
|
|
|
* Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions are met:
|
|
|
|
*
|
|
|
|
* * Redistributions of source code must retain the above copyright notice,
|
|
|
|
* this list of conditions and the following disclaimer.
|
|
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* * Neither the name of Redis nor the names of its contributors may be used
|
|
|
|
* to endorse or promote products derived from this software without
|
|
|
|
* specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
2010-05-12 05:56:12 -04:00
|
|
|
#include "fmacros.h"
|
2010-05-05 07:36:29 -04:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2010-05-05 07:46:37 -04:00
|
|
|
#include <unistd.h>
|
2010-05-05 07:36:29 -04:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#define ERROR(...) { \
|
|
|
|
char __buf[1024]; \
|
|
|
|
sprintf(__buf, __VA_ARGS__); \
|
2012-02-14 13:57:31 -05:00
|
|
|
sprintf(error, "0x%16llx: %s", (long long)epos, __buf); \
|
2010-05-05 07:36:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static char error[1024];
|
2012-02-14 13:57:31 -05:00
|
|
|
static off_t epos;
|
2010-05-05 07:36:29 -04:00
|
|
|
|
|
|
|
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;
|
2012-02-14 13:57:31 -05:00
|
|
|
epos = ftello(fp);
|
2010-05-05 07:36:29 -04:00
|
|
|
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;
|
2012-02-14 13:57:31 -05:00
|
|
|
epos = ftello(fp);
|
2010-05-05 07:36:29 -04:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2012-02-14 13:57:31 -05:00
|
|
|
off_t process(FILE *fp) {
|
|
|
|
long argc;
|
|
|
|
off_t pos = 0;
|
2010-05-05 07:36:29 -04:00
|
|
|
int i, multi = 0;
|
|
|
|
char *str;
|
|
|
|
|
|
|
|
while(1) {
|
2012-02-14 13:57:31 -05:00
|
|
|
if (!multi) pos = ftello(fp);
|
2010-05-05 08:06:55 -04:00
|
|
|
if (!readArgc(fp, &argc)) break;
|
2010-05-05 07:36:29 -04:00
|
|
|
|
|
|
|
for (i = 0; i < argc; i++) {
|
2010-05-05 08:06:55 -04:00
|
|
|
if (!readString(fp,&str)) break;
|
2010-05-05 07:36:29 -04:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2010-05-05 08:06:55 -04:00
|
|
|
/* Stop if the loop did not finish */
|
2010-05-05 07:36:29 -04:00
|
|
|
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) {
|
2010-05-05 07:46:37 -04:00
|
|
|
char *filename;
|
|
|
|
int fix = 0;
|
2010-05-05 08:02:04 -04:00
|
|
|
|
|
|
|
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) {
|
2010-05-05 07:46:37 -04:00
|
|
|
if (strcmp(argv[1],"--fix") != 0) {
|
|
|
|
printf("Invalid argument: %s\n", argv[1]);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
filename = argv[2];
|
2010-05-05 08:02:04 -04:00
|
|
|
fix = 1;
|
2010-05-05 07:46:37 -04:00
|
|
|
} else {
|
2010-05-05 08:02:04 -04:00
|
|
|
printf("Invalid arguments\n");
|
2010-05-05 07:46:37 -04:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
FILE *fp = fopen(filename,"r+");
|
2010-05-05 07:36:29 -04:00
|
|
|
if (fp == NULL) {
|
2010-05-05 07:46:37 -04:00
|
|
|
printf("Cannot open file: %s\n", filename);
|
2010-05-05 07:36:29 -04:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct redis_stat sb;
|
|
|
|
if (redis_fstat(fileno(fp),&sb) == -1) {
|
2010-05-05 07:46:37 -04:00
|
|
|
printf("Cannot stat file: %s\n", filename);
|
2010-05-05 07:36:29 -04:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2012-02-14 13:57:31 -05:00
|
|
|
off_t size = sb.st_size;
|
2010-05-05 07:36:29 -04:00
|
|
|
if (size == 0) {
|
2010-05-05 07:46:37 -04:00
|
|
|
printf("Empty file: %s\n", filename);
|
2010-05-05 07:36:29 -04:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2012-02-14 13:57:31 -05:00
|
|
|
off_t pos = process(fp);
|
|
|
|
off_t diff = size-pos;
|
|
|
|
printf("AOF analyzed: size=%lld, ok_up_to=%lld, diff=%lld\n",
|
|
|
|
(long long) size, (long long) pos, (long long) diff);
|
2010-05-05 10:38:50 -04:00
|
|
|
if (diff > 0) {
|
2010-05-05 07:46:37 -04:00
|
|
|
if (fix) {
|
2010-05-05 10:38:50 -04:00
|
|
|
char buf[2];
|
2012-02-14 13:57:31 -05:00
|
|
|
printf("This will shrink the AOF from %lld bytes, with %lld bytes, to %lld bytes\n",(long long)size,(long long)diff,(long long)pos);
|
2010-05-05 10:38:50 -04:00
|
|
|
printf("Continue? [y/N]: ");
|
|
|
|
if (fgets(buf,sizeof(buf),stdin) == NULL ||
|
|
|
|
strncasecmp(buf,"y",1) != 0) {
|
|
|
|
printf("Aborting...\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2010-05-05 07:46:37 -04:00
|
|
|
if (ftruncate(fileno(fp), pos) == -1) {
|
2010-05-05 10:38:50 -04:00
|
|
|
printf("Failed to truncate AOF\n");
|
2010-05-05 07:46:37 -04:00
|
|
|
exit(1);
|
|
|
|
} else {
|
2010-05-05 10:38:50 -04:00
|
|
|
printf("Successfully truncated AOF\n");
|
2010-05-05 07:46:37 -04:00
|
|
|
}
|
|
|
|
} else {
|
2010-05-05 10:38:50 -04:00
|
|
|
printf("AOF is not valid\n");
|
|
|
|
exit(1);
|
2010-05-05 07:46:37 -04:00
|
|
|
}
|
2010-05-05 07:36:29 -04:00
|
|
|
} else {
|
2010-05-05 07:46:37 -04:00
|
|
|
printf("AOF is valid\n");
|
2010-05-05 07:36:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
fclose(fp);
|
|
|
|
return 0;
|
|
|
|
}
|