File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sqlite3 / tool / showwal.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:04:17 2012 UTC (12 years, 10 months ago) by misho
Branches: sqlite3, MAIN
CVS tags: v3_7_10, HEAD
sqlite3

    1: /*
    2: ** A utility for printing content from a write-ahead log file.
    3: */
    4: #include <stdio.h>
    5: #include <ctype.h>
    6: #include <sys/types.h>
    7: #include <sys/stat.h>
    8: #include <fcntl.h>
    9: #include <unistd.h>
   10: #include <stdlib.h>
   11: #include <string.h>
   12: 
   13: 
   14: static int pagesize = 1024;     /* Size of a database page */
   15: static int fd = -1;             /* File descriptor for reading the WAL file */
   16: static int mxFrame = 0;         /* Last frame */
   17: static int perLine = 16;        /* HEX elements to print per line */
   18: 
   19: typedef long long int i64;      /* Datatype for 64-bit integers */
   20: 
   21: 
   22: /*
   23: ** Convert the var-int format into i64.  Return the number of bytes
   24: ** in the var-int.  Write the var-int value into *pVal.
   25: */
   26: static int decodeVarint(const unsigned char *z, i64 *pVal){
   27:   i64 v = 0;
   28:   int i;
   29:   for(i=0; i<8; i++){
   30:     v = (v<<7) + (z[i]&0x7f);
   31:     if( (z[i]&0x80)==0 ){ *pVal = v; return i+1; }
   32:   }
   33:   v = (v<<8) + (z[i]&0xff);
   34:   *pVal = v;
   35:   return 9;
   36: }
   37: 
   38: /* Report an out-of-memory error and die.
   39: */
   40: static void out_of_memory(void){
   41:   fprintf(stderr,"Out of memory...\n");
   42:   exit(1);
   43: }
   44: 
   45: /*
   46: ** Read content from the file.
   47: **
   48: ** Space to hold the content is obtained from malloc() and needs to be
   49: ** freed by the caller.
   50: */
   51: static unsigned char *getContent(int ofst, int nByte){
   52:   unsigned char *aData;
   53:   aData = malloc(nByte);
   54:   if( aData==0 ) out_of_memory();
   55:   lseek(fd, ofst, SEEK_SET);
   56:   read(fd, aData, nByte);
   57:   return aData;
   58: }
   59: 
   60: /*
   61: ** Print a range of bytes as hex and as ascii.
   62: */
   63: static void print_byte_range(
   64:   int ofst,              /* First byte in the range of bytes to print */
   65:   int nByte,             /* Number of bytes to print */
   66:   unsigned char *aData,  /* Content to print */
   67:   int printOfst          /* Add this amount to the index on the left column */
   68: ){
   69:   int i, j;
   70:   const char *zOfstFmt;
   71: 
   72:   if( ((printOfst+nByte)&~0xfff)==0 ){
   73:     zOfstFmt = " %03x: ";
   74:   }else if( ((printOfst+nByte)&~0xffff)==0 ){
   75:     zOfstFmt = " %04x: ";
   76:   }else if( ((printOfst+nByte)&~0xfffff)==0 ){
   77:     zOfstFmt = " %05x: ";
   78:   }else if( ((printOfst+nByte)&~0xffffff)==0 ){
   79:     zOfstFmt = " %06x: ";
   80:   }else{
   81:     zOfstFmt = " %08x: ";
   82:   }
   83: 
   84:   for(i=0; i<nByte; i += perLine){
   85:     fprintf(stdout, zOfstFmt, i+printOfst);
   86:     for(j=0; j<perLine; j++){
   87:       if( i+j>nByte ){
   88:         fprintf(stdout, "   ");
   89:       }else{
   90:         fprintf(stdout,"%02x ", aData[i+j]);
   91:       }
   92:     }
   93:     for(j=0; j<perLine; j++){
   94:       if( i+j>nByte ){
   95:         fprintf(stdout, " ");
   96:       }else{
   97:         fprintf(stdout,"%c", isprint(aData[i+j]) ? aData[i+j] : '.');
   98:       }
   99:     }
  100:     fprintf(stdout,"\n");
  101:   }
  102: }
  103: 
  104: /* Print a line of decode output showing a 4-byte integer.
  105: */
  106: static void print_decode_line(
  107:   unsigned char *aData,      /* Content being decoded */
  108:   int ofst, int nByte,       /* Start and size of decode */
  109:   int asHex,                 /* If true, output value as hex */
  110:   const char *zMsg           /* Message to append */
  111: ){
  112:   int i, j;
  113:   int val = aData[ofst];
  114:   char zBuf[100];
  115:   sprintf(zBuf, " %03x: %02x", ofst, aData[ofst]);
  116:   i = strlen(zBuf);
  117:   for(j=1; j<4; j++){
  118:     if( j>=nByte ){
  119:       sprintf(&zBuf[i], "   ");
  120:     }else{
  121:       sprintf(&zBuf[i], " %02x", aData[ofst+j]);
  122:       val = val*256 + aData[ofst+j];
  123:     }
  124:     i += strlen(&zBuf[i]);
  125:   }
  126:   if( asHex ){
  127:     sprintf(&zBuf[i], "  0x%08x", val);
  128:   }else{
  129:     sprintf(&zBuf[i], "   %9d", val);
  130:   }
  131:   printf("%s  %s\n", zBuf, zMsg);
  132: }
  133: 
  134: /*
  135: ** Print an entire page of content as hex
  136: */
  137: static void print_frame(int iFrame){
  138:   int iStart;
  139:   unsigned char *aData;
  140:   iStart = 32 + (iFrame-1)*(pagesize+24);
  141:   fprintf(stdout, "Frame %d:   (offsets 0x%x..0x%x)\n",
  142:           iFrame, iStart, iStart+pagesize+24);
  143:   aData = getContent(iStart, pagesize+24);
  144:   print_decode_line(aData, 0, 4, 0, "Page number");
  145:   print_decode_line(aData, 4, 4, 0, "DB size, or 0 for non-commit");
  146:   print_decode_line(aData, 8, 4, 1, "Salt-1");
  147:   print_decode_line(aData,12, 4, 1, "Salt-2");
  148:   print_decode_line(aData,16, 4, 1, "Checksum-1");
  149:   print_decode_line(aData,20, 4, 1, "Checksum-2");
  150:   print_byte_range(iStart+24, pagesize, aData+24, 0);
  151:   free(aData);
  152: }
  153: 
  154: /*
  155: ** extract a 32-bit big-endian integer
  156: */
  157: static unsigned int getInt32(const unsigned char *a){
  158:   unsigned int x = (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3];
  159:   return x;
  160: }
  161: 
  162: /*
  163: ** Print an entire page of content as hex
  164: */
  165: static void print_oneline_frame(int iFrame){
  166:   int iStart;
  167:   unsigned char *aData;
  168:   iStart = 32 + (iFrame-1)*(pagesize+24);
  169:   aData = getContent(iStart, 24);
  170:   fprintf(stdout, "Frame %4d: %6d %6d 0x%08x 0x%08x 0x%08x 0x%08x\n",
  171:           iFrame, 
  172:           getInt32(aData),
  173:           getInt32(aData+4),
  174:           getInt32(aData+8),
  175:           getInt32(aData+12),
  176:           getInt32(aData+16),
  177:           getInt32(aData+20)
  178:   );
  179:   free(aData);
  180: }
  181: 
  182: /*
  183: ** Decode the WAL header.
  184: */
  185: static void print_wal_header(void){
  186:   unsigned char *aData;
  187:   aData = getContent(0, 32);
  188:   printf("WAL Header:\n");
  189:   print_decode_line(aData, 0, 4,1,"Magic.  0x377f0682 (le) or 0x377f0683 (be)");
  190:   print_decode_line(aData, 4, 4, 0, "File format");
  191:   print_decode_line(aData, 8, 4, 0, "Database page size");
  192:   print_decode_line(aData, 12,4, 0, "Checkpoint sequence number");
  193:   print_decode_line(aData, 16,4, 1, "Salt-1");
  194:   print_decode_line(aData, 20,4, 1, "Salt-2");
  195:   print_decode_line(aData, 24,4, 1, "Checksum-1");
  196:   print_decode_line(aData, 28,4, 1, "Checksum-2");
  197:   free(aData);
  198: }
  199: 
  200: /*
  201: ** Create a description for a single cell.
  202: */
  203: static int describeCell(unsigned char cType, unsigned char *a, char **pzDesc){
  204:   int i;
  205:   int nDesc = 0;
  206:   int n = 0;
  207:   int leftChild;
  208:   i64 nPayload;
  209:   i64 rowid;
  210:   static char zDesc[100];
  211:   i = 0;
  212:   if( cType<=5 ){
  213:     leftChild = ((a[0]*256 + a[1])*256 + a[2])*256 + a[3];
  214:     a += 4;
  215:     n += 4;
  216:     sprintf(zDesc, "left-child: %d ", leftChild);
  217:     nDesc = strlen(zDesc);
  218:   }
  219:   if( cType!=5 ){
  220:     i = decodeVarint(a, &nPayload);
  221:     a += i;
  222:     n += i;
  223:     sprintf(&zDesc[nDesc], "sz: %lld ", nPayload);
  224:     nDesc += strlen(&zDesc[nDesc]);
  225:   }
  226:   if( cType==5 || cType==13 ){
  227:     i = decodeVarint(a, &rowid);
  228:     a += i;
  229:     n += i;
  230:     sprintf(&zDesc[nDesc], "rowid: %lld ", rowid);
  231:     nDesc += strlen(&zDesc[nDesc]);
  232:   }
  233:   *pzDesc = zDesc;
  234:   return n;
  235: }
  236: 
  237: /*
  238: ** Decode a btree page
  239: */
  240: static void decode_btree_page(unsigned char *a, int pgno, int hdrSize){
  241:   const char *zType = "unknown";
  242:   int nCell;
  243:   int i;
  244:   int iCellPtr;
  245:   switch( a[0] ){
  246:     case 2:  zType = "index interior node";  break;
  247:     case 5:  zType = "table interior node";  break;
  248:     case 10: zType = "index leaf";           break;
  249:     case 13: zType = "table leaf";           break;
  250:   }
  251:   printf("Decode of btree page %d:\n", pgno);
  252:   print_decode_line(a, 0, 1, 0, zType);
  253:   print_decode_line(a, 1, 2, 0, "Offset to first freeblock");
  254:   print_decode_line(a, 3, 2, 0, "Number of cells on this page");
  255:   nCell = a[3]*256 + a[4];
  256:   print_decode_line(a, 5, 2, 0, "Offset to cell content area");
  257:   print_decode_line(a, 7, 1, 0, "Fragmented byte count");
  258:   if( a[0]==2 || a[0]==5 ){
  259:     print_decode_line(a, 8, 4, 0, "Right child");
  260:     iCellPtr = 12;
  261:   }else{
  262:     iCellPtr = 8;
  263:   }
  264:   for(i=0; i<nCell; i++){
  265:     int cofst = iCellPtr + i*2;
  266:     char *zDesc;
  267:     cofst = a[cofst]*256 + a[cofst+1];
  268:     describeCell(a[0], &a[cofst-hdrSize], &zDesc);
  269:     printf(" %03x: cell[%d] %s\n", cofst, i, zDesc);
  270:   }
  271: }
  272: 
  273: int main(int argc, char **argv){
  274:   struct stat sbuf;
  275:   unsigned char zPgSz[2];
  276:   if( argc<2 ){
  277:     fprintf(stderr,"Usage: %s FILENAME ?PAGE? ...\n", argv[0]);
  278:     exit(1);
  279:   }
  280:   fd = open(argv[1], O_RDONLY);
  281:   if( fd<0 ){
  282:     fprintf(stderr,"%s: can't open %s\n", argv[0], argv[1]);
  283:     exit(1);
  284:   }
  285:   zPgSz[0] = 0;
  286:   zPgSz[1] = 0;
  287:   lseek(fd, 10, SEEK_SET);
  288:   read(fd, zPgSz, 2);
  289:   pagesize = zPgSz[0]*256 + zPgSz[1];
  290:   if( pagesize==0 ) pagesize = 1024;
  291:   printf("Pagesize: %d\n", pagesize);
  292:   fstat(fd, &sbuf);
  293:   if( sbuf.st_size<32 ){
  294:     printf("file too small to be a WAL\n");
  295:     return 0;
  296:   }
  297:   mxFrame = (sbuf.st_size - 32)/(pagesize + 24);
  298:   printf("Available pages: 1..%d\n", mxFrame);
  299:   if( argc==2 ){
  300:     int i;
  301:     print_wal_header();
  302:     for(i=1; i<=mxFrame; i++) print_oneline_frame(i);
  303:   }else{
  304:     int i;
  305:     for(i=2; i<argc; i++){
  306:       int iStart, iEnd;
  307:       char *zLeft;
  308:       if( strcmp(argv[i], "header")==0 ){
  309:         print_wal_header();
  310:         continue;
  311:       }
  312:       if( !isdigit(argv[i][0]) ){
  313:         fprintf(stderr, "%s: unknown option: [%s]\n", argv[0], argv[i]);
  314:         continue;
  315:       }
  316:       iStart = strtol(argv[i], &zLeft, 0);
  317:       if( zLeft && strcmp(zLeft,"..end")==0 ){
  318:         iEnd = mxFrame;
  319:       }else if( zLeft && zLeft[0]=='.' && zLeft[1]=='.' ){
  320:         iEnd = strtol(&zLeft[2], 0, 0);
  321: #if 0
  322:       }else if( zLeft && zLeft[0]=='b' ){
  323:         int ofst, nByte, hdrSize;
  324:         unsigned char *a;
  325:         if( iStart==1 ){
  326:           ofst = hdrSize = 100;
  327:           nByte = pagesize-100;
  328:         }else{
  329:           hdrSize = 0;
  330:           ofst = (iStart-1)*pagesize;
  331:           nByte = pagesize;
  332:         }
  333:         a = getContent(ofst, nByte);
  334:         decode_btree_page(a, iStart, hdrSize);
  335:         free(a);
  336:         continue;
  337: #endif
  338:       }else{
  339:         iEnd = iStart;
  340:       }
  341:       if( iStart<1 || iEnd<iStart || iEnd>mxFrame ){
  342:         fprintf(stderr,
  343:           "Page argument should be LOWER?..UPPER?.  Range 1 to %d\n",
  344:           mxFrame);
  345:         exit(1);
  346:       }
  347:       while( iStart<=iEnd ){
  348:         print_frame(iStart);
  349:         iStart++;
  350:       }
  351:     }
  352:   }
  353:   close(fd);
  354:   return 0;
  355: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>