LCOV - code coverage report
Current view: directory - redis/src - redis-check-aof.c (source / functions) Found Hit Coverage
Test: redis.info Lines: 102 74 72.5 %
Date: 2012-04-04 Functions: 7 7 100.0 %
Colors: not hit hit

       1                 : #include "fmacros.h"
       2                 : #include <stdlib.h>
       3                 : #include <stdio.h>
       4                 : #include <string.h>
       5                 : #include <unistd.h>
       6                 : #include <sys/stat.h>
       7                 : #include "config.h"
       8                 : 
       9                 : #define ERROR(...) { \
      10                 :     char __buf[1024]; \
      11                 :     sprintf(__buf, __VA_ARGS__); \
      12                 :     sprintf(error, "0x%16llx: %s", (long long)epos, __buf); \
      13                 : }
      14                 : 
      15                 : static char error[1024];
      16                 : static off_t epos;
      17                 : 
      18              26 : int consumeNewline(char *buf) {
      19              26 :     if (strncmp(buf,"\r\n",2) != 0) {
      20               0 :         ERROR("Expected \\r\\n, got: %02x%02x",buf[0],buf[1]);
      21               0 :         return 0;
      22                 :     }
      23              26 :     return 1;
      24                 : }
      25                 : 
      26              16 : int readLong(FILE *fp, char prefix, long *target) {
      27                 :     char buf[128], *eptr;
      28              16 :     epos = ftello(fp);
      29              16 :     if (fgets(buf,sizeof(buf),fp) == NULL) {
      30               0 :         return 0;
      31                 :     }
      32              16 :     if (buf[0] != prefix) {
      33               0 :         ERROR("Expected prefix '%c', got: '%c'",buf[0],prefix);
      34                 :         return 0;
      35                 :     }
      36              16 :     *target = strtol(buf+1,&eptr,10);
      37              16 :     return consumeNewline(eptr);
      38                 : }
      39                 : 
      40              12 : int readBytes(FILE *fp, char *target, long length) {
      41                 :     long real;
      42              12 :     epos = ftello(fp);
      43              24 :     real = fread(target,1,length,fp);
      44              12 :     if (real != length) {
      45               4 :         ERROR("Expected to read %ld bytes, got %ld bytes",length,real);
      46               2 :         return 0;
      47                 :     }
      48              10 :     return 1;
      49                 : }
      50                 : 
      51              12 : int readString(FILE *fp, char** target) {
      52                 :     long len;
      53              12 :     *target = NULL;
      54              12 :     if (!readLong(fp,'$',&len)) {
      55               0 :         return 0;
      56                 :     }
      57                 : 
      58                 :     /* Increase length to also consume \r\n */
      59              12 :     len += 2;
      60              12 :     *target = (char*)malloc(len);
      61              12 :     if (!readBytes(fp,*target,len)) {
      62               2 :         return 0;
      63                 :     }
      64              10 :     if (!consumeNewline(*target+len-2)) {
      65               0 :         return 0;
      66                 :     }
      67              10 :     (*target)[len-2] = '\0';
      68              10 :     return 1;
      69                 : }
      70                 : 
      71               4 : int readArgc(FILE *fp, long *target) {
      72               4 :     return readLong(fp,'*',target);
      73                 : }
      74                 : 
      75               2 : off_t process(FILE *fp) {
      76                 :     long argc;
      77               2 :     off_t pos = 0;
      78               2 :     int i, multi = 0;
      79                 :     char *str;
      80                 : 
      81                 :     while(1) {
      82               4 :         if (!multi) pos = ftello(fp);
      83               4 :         if (!readArgc(fp, &argc)) break;
      84                 : 
      85              14 :         for (i = 0; i < argc; i++) {
      86              12 :             if (!readString(fp,&str)) break;
      87              10 :             if (i == 0) {
      88               4 :                 if (strcasecmp(str, "multi") == 0) {
      89               0 :                     if (multi++) {
      90               0 :                         ERROR("Unexpected MULTI");
      91                 :                         break;
      92                 :                     }
      93               4 :                 } else if (strcasecmp(str, "exec") == 0) {
      94               0 :                     if (--multi) {
      95               0 :                         ERROR("Unexpected EXEC");
      96                 :                         break;
      97                 :                     }
      98                 :                 }
      99                 :             }
     100              10 :             free(str);
     101                 :         }
     102                 : 
     103                 :         /* Stop if the loop did not finish */
     104               4 :         if (i < argc) {
     105               2 :             if (str) free(str);
     106                 :             break;
     107                 :         }
     108                 :     }
     109                 : 
     110               2 :     if (feof(fp) && multi && strlen(error) == 0) {
     111               0 :         ERROR("Reached EOF before reading EXEC for MULTI");
     112                 :     }
     113               2 :     if (strlen(error) > 0) {
     114               2 :         printf("%s\n", error);
     115                 :     }
     116               2 :     return pos;
     117                 : }
     118                 : 
     119               2 : int main(int argc, char **argv) {
     120                 :     char *filename;
     121               2 :     int fix = 0;
     122                 : 
     123               2 :     if (argc < 2) {
     124               0 :         printf("Usage: %s [--fix] <file.aof>\n", argv[0]);
     125               0 :         exit(1);
     126               2 :     } else if (argc == 2) {
     127               1 :         filename = argv[1];
     128               1 :     } else if (argc == 3) {
     129               1 :         if (strcmp(argv[1],"--fix") != 0) {
     130               0 :             printf("Invalid argument: %s\n", argv[1]);
     131               0 :             exit(1);
     132                 :         }
     133               1 :         filename = argv[2];
     134               1 :         fix = 1;
     135                 :     } else {
     136               0 :         printf("Invalid arguments\n");
     137               0 :         exit(1);
     138                 :     }
     139                 : 
     140               2 :     FILE *fp = fopen(filename,"r+");
     141               2 :     if (fp == NULL) {
     142               0 :         printf("Cannot open file: %s\n", filename);
     143               0 :         exit(1);
     144                 :     }
     145                 : 
     146                 :     struct redis_stat sb;
     147               4 :     if (redis_fstat(fileno(fp),&sb) == -1) {
     148               0 :         printf("Cannot stat file: %s\n", filename);
     149               0 :         exit(1);
     150                 :     }
     151                 : 
     152               2 :     off_t size = sb.st_size;
     153               2 :     if (size == 0) {
     154               0 :         printf("Empty file: %s\n", filename);
     155               0 :         exit(1);
     156                 :     }
     157                 : 
     158               2 :     off_t pos = process(fp);
     159               2 :     off_t diff = size-pos;
     160               2 :     printf("AOF analyzed: size=%lld, ok_up_to=%lld, diff=%lld\n",
     161                 :         (long long) size, (long long) pos, (long long) diff);
     162               2 :     if (diff > 0) {
     163               2 :         if (fix) {
     164                 :             char buf[2];
     165               1 :             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);
     166               1 :             printf("Continue? [y/N]: ");
     167               3 :             if (fgets(buf,sizeof(buf),stdin) == NULL ||
     168               1 :                 strncasecmp(buf,"y",1) != 0) {
     169               0 :                     printf("Aborting...\n");
     170               0 :                     exit(1);
     171                 :             }
     172               1 :             if (ftruncate(fileno(fp), pos) == -1) {
     173               0 :                 printf("Failed to truncate AOF\n");
     174               0 :                 exit(1);
     175                 :             } else {
     176               1 :                 printf("Successfully truncated AOF\n");
     177                 :             }
     178                 :         } else {
     179               1 :             printf("AOF is not valid\n");
     180               1 :             exit(1);
     181                 :         }
     182                 :     } else {
     183               0 :         printf("AOF is valid\n");
     184                 :     }
     185                 : 
     186               1 :     fclose(fp);
     187               1 :     return 0;
     188                 : }

Generated by: LCOV version 1.7