Annotation of embedaddon/sqlite3/src/test6.c, revision 1.1.1.1

1.1       misho       1: /*
                      2: ** 2004 May 22
                      3: **
                      4: ** The author disclaims copyright to this source code.  In place of
                      5: ** a legal notice, here is a blessing:
                      6: **
                      7: **    May you do good and not evil.
                      8: **    May you find forgiveness for yourself and forgive others.
                      9: **    May you share freely, never taking more than you give.
                     10: **
                     11: ******************************************************************************
                     12: **
                     13: ** This file contains code that modified the OS layer in order to simulate
                     14: ** the effect on the database file of an OS crash or power failure.  This
                     15: ** is used to test the ability of SQLite to recover from those situations.
                     16: */
                     17: #if SQLITE_TEST          /* This file is used for testing only */
                     18: #include "sqliteInt.h"
                     19: #include "tcl.h"
                     20: 
                     21: #ifndef SQLITE_OMIT_DISKIO  /* This file is a no-op if disk I/O is disabled */
                     22: 
                     23: /* #define TRACE_CRASHTEST */
                     24: 
                     25: typedef struct CrashFile CrashFile;
                     26: typedef struct CrashGlobal CrashGlobal;
                     27: typedef struct WriteBuffer WriteBuffer;
                     28: 
                     29: /*
                     30: ** Method:
                     31: **
                     32: **   This layer is implemented as a wrapper around the "real" 
                     33: **   sqlite3_file object for the host system. Each time data is 
                     34: **   written to the file object, instead of being written to the
                     35: **   underlying file, the write operation is stored in an in-memory 
                     36: **   structure (type WriteBuffer). This structure is placed at the
                     37: **   end of a global ordered list (the write-list).
                     38: **
                     39: **   When data is read from a file object, the requested region is
                     40: **   first retrieved from the real file. The write-list is then 
                     41: **   traversed and data copied from any overlapping WriteBuffer 
                     42: **   structures to the output buffer. i.e. a read() operation following
                     43: **   one or more write() operations works as expected, even if no
                     44: **   data has actually been written out to the real file.
                     45: **
                     46: **   When a fsync() operation is performed, an operating system crash 
                     47: **   may be simulated, in which case exit(-1) is called (the call to 
                     48: **   xSync() never returns). Whether or not a crash is simulated,
                     49: **   the data associated with a subset of the WriteBuffer structures 
                     50: **   stored in the write-list is written to the real underlying files 
                     51: **   and the entries removed from the write-list. If a crash is simulated,
                     52: **   a subset of the buffers may be corrupted before the data is written.
                     53: **
                     54: **   The exact subset of the write-list written and/or corrupted is
                     55: **   determined by the simulated device characteristics and sector-size.
                     56: **
                     57: ** "Normal" mode:
                     58: **
                     59: **   Normal mode is used when the simulated device has none of the
                     60: **   SQLITE_IOCAP_XXX flags set.
                     61: **
                     62: **   In normal mode, if the fsync() is not a simulated crash, the 
                     63: **   write-list is traversed from beginning to end. Each WriteBuffer
                     64: **   structure associated with the file handle used to call xSync()
                     65: **   is written to the real file and removed from the write-list.
                     66: **
                     67: **   If a crash is simulated, one of the following takes place for 
                     68: **   each WriteBuffer in the write-list, regardless of which 
                     69: **   file-handle it is associated with:
                     70: **
                     71: **     1. The buffer is correctly written to the file, just as if
                     72: **        a crash were not being simulated.
                     73: **
                     74: **     2. Nothing is done.
                     75: **
                     76: **     3. Garbage data is written to all sectors of the file that 
                     77: **        overlap the region specified by the WriteBuffer. Or garbage
                     78: **        data is written to some contiguous section within the 
                     79: **        overlapped sectors.
                     80: **
                     81: ** Device Characteristic flag handling:
                     82: **
                     83: **   If the IOCAP_ATOMIC flag is set, then option (3) above is 
                     84: **   never selected.
                     85: **
                     86: **   If the IOCAP_ATOMIC512 flag is set, and the WriteBuffer represents
                     87: **   an aligned write() of an integer number of 512 byte regions, then
                     88: **   option (3) above is never selected. Instead, each 512 byte region
                     89: **   is either correctly written or left completely untouched. Similar
                     90: **   logic governs the behaviour if any of the other ATOMICXXX flags
                     91: **   is set.
                     92: **
                     93: **   If either the IOCAP_SAFEAPPEND or IOCAP_SEQUENTIAL flags are set
                     94: **   and a crash is being simulated, then an entry of the write-list is
                     95: **   selected at random. Everything in the list after the selected entry 
                     96: **   is discarded before processing begins.
                     97: **
                     98: **   If IOCAP_SEQUENTIAL is set and a crash is being simulated, option 
                     99: **   (1) is selected for all write-list entries except the last. If a 
                    100: **   crash is not being simulated, then all entries in the write-list
                    101: **   that occur before at least one write() on the file-handle specified
                    102: **   as part of the xSync() are written to their associated real files.
                    103: **
                    104: **   If IOCAP_SAFEAPPEND is set and the first byte written by the write()
                    105: **   operation is one byte past the current end of the file, then option
                    106: **   (1) is always selected.
                    107: */
                    108: 
                    109: /*
                    110: ** Each write operation in the write-list is represented by an instance
                    111: ** of the following structure.
                    112: **
                    113: ** If zBuf is 0, then this structure represents a call to xTruncate(), 
                    114: ** not xWrite(). In that case, iOffset is the size that the file is
                    115: ** truncated to.
                    116: */
                    117: struct WriteBuffer {
                    118:   i64 iOffset;                 /* Byte offset of the start of this write() */
                    119:   int nBuf;                    /* Number of bytes written */
                    120:   u8 *zBuf;                    /* Pointer to copy of written data */
                    121:   CrashFile *pFile;            /* File this write() applies to */
                    122: 
                    123:   WriteBuffer *pNext;          /* Next in CrashGlobal.pWriteList */
                    124: };
                    125: 
                    126: struct CrashFile {
                    127:   const sqlite3_io_methods *pMethod;   /* Must be first */
                    128:   sqlite3_file *pRealFile;             /* Underlying "real" file handle */
                    129:   char *zName;
                    130:   int flags;                           /* Flags the file was opened with */
                    131: 
                    132:   /* Cache of the entire file. This is used to speed up OsRead() and 
                    133:   ** OsFileSize() calls. Although both could be done by traversing the
                    134:   ** write-list, in practice this is impractically slow.
                    135:   */
                    136:   int iSize;                           /* Size of file in bytes */
                    137:   int nData;                           /* Size of buffer allocated at zData */
                    138:   u8 *zData;                           /* Buffer containing file contents */
                    139: };
                    140: 
                    141: struct CrashGlobal {
                    142:   WriteBuffer *pWriteList;     /* Head of write-list */
                    143:   WriteBuffer *pWriteListEnd;  /* End of write-list */
                    144: 
                    145:   int iSectorSize;             /* Value of simulated sector size */
                    146:   int iDeviceCharacteristics;  /* Value of simulated device characteristics */
                    147: 
                    148:   int iCrash;                  /* Crash on the iCrash'th call to xSync() */
                    149:   char zCrashFile[500];        /* Crash during an xSync() on this file */ 
                    150: };
                    151: 
                    152: static CrashGlobal g = {0, 0, SQLITE_DEFAULT_SECTOR_SIZE, 0, 0};
                    153: 
                    154: /*
                    155: ** Set this global variable to 1 to enable crash testing.
                    156: */
                    157: static int sqlite3CrashTestEnable = 0;
                    158: 
                    159: static void *crash_malloc(int nByte){
                    160:   return (void *)Tcl_Alloc((size_t)nByte);
                    161: }
                    162: static void crash_free(void *p){
                    163:   Tcl_Free(p);
                    164: }
                    165: static void *crash_realloc(void *p, int n){
                    166:   return (void *)Tcl_Realloc(p, (size_t)n);
                    167: }
                    168: 
                    169: /*
                    170: ** Wrapper around the sqlite3OsWrite() function that avoids writing to the
                    171: ** 512 byte block begining at offset PENDING_BYTE.
                    172: */
                    173: static int writeDbFile(CrashFile *p, u8 *z, i64 iAmt, i64 iOff){
                    174:   int rc = SQLITE_OK;
                    175:   int iSkip = 0;
                    176:   if( iOff==PENDING_BYTE && (p->flags&SQLITE_OPEN_MAIN_DB) ){
                    177:     iSkip = 512;
                    178:   }
                    179:   if( (iAmt-iSkip)>0 ){
                    180:     rc = sqlite3OsWrite(p->pRealFile, &z[iSkip], iAmt-iSkip, iOff+iSkip);
                    181:   }
                    182:   return rc;
                    183: }
                    184: 
                    185: /*
                    186: ** Flush the write-list as if xSync() had been called on file handle
                    187: ** pFile. If isCrash is true, simulate a crash.
                    188: */
                    189: static int writeListSync(CrashFile *pFile, int isCrash){
                    190:   int rc = SQLITE_OK;
                    191:   int iDc = g.iDeviceCharacteristics;
                    192: 
                    193:   WriteBuffer *pWrite;
                    194:   WriteBuffer **ppPtr;
                    195: 
                    196:   /* If this is not a crash simulation, set pFinal to point to the 
                    197:   ** last element of the write-list that is associated with file handle
                    198:   ** pFile.
                    199:   **
                    200:   ** If this is a crash simulation, set pFinal to an arbitrarily selected
                    201:   ** element of the write-list.
                    202:   */
                    203:   WriteBuffer *pFinal = 0;
                    204:   if( !isCrash ){
                    205:     for(pWrite=g.pWriteList; pWrite; pWrite=pWrite->pNext){
                    206:       if( pWrite->pFile==pFile ){
                    207:         pFinal = pWrite;
                    208:       }
                    209:     }
                    210:   }else if( iDc&(SQLITE_IOCAP_SEQUENTIAL|SQLITE_IOCAP_SAFE_APPEND) ){
                    211:     int nWrite = 0;
                    212:     int iFinal;
                    213:     for(pWrite=g.pWriteList; pWrite; pWrite=pWrite->pNext) nWrite++;
                    214:     sqlite3_randomness(sizeof(int), &iFinal);
                    215:     iFinal = ((iFinal<0)?-1*iFinal:iFinal)%nWrite;
                    216:     for(pWrite=g.pWriteList; iFinal>0; pWrite=pWrite->pNext) iFinal--;
                    217:     pFinal = pWrite;
                    218:   }
                    219: 
                    220: #ifdef TRACE_CRASHTEST
                    221:   printf("Sync %s (is %s crash)\n", pFile->zName, (isCrash?"a":"not a"));
                    222: #endif
                    223: 
                    224:   ppPtr = &g.pWriteList;
                    225:   for(pWrite=*ppPtr; rc==SQLITE_OK && pWrite; pWrite=*ppPtr){
                    226:     sqlite3_file *pRealFile = pWrite->pFile->pRealFile;
                    227: 
                    228:     /* (eAction==1)      -> write block out normally,
                    229:     ** (eAction==2)      -> do nothing,
                    230:     ** (eAction==3)      -> trash sectors.
                    231:     */
                    232:     int eAction = 0;
                    233:     if( !isCrash ){
                    234:       eAction = 2;
                    235:       if( (pWrite->pFile==pFile || iDc&SQLITE_IOCAP_SEQUENTIAL) ){
                    236:         eAction = 1;
                    237:       }
                    238:     }else{
                    239:       char random;
                    240:       sqlite3_randomness(1, &random);
                    241: 
                    242:       /* Do not select option 3 (sector trashing) if the IOCAP_ATOMIC flag 
                    243:       ** is set or this is an OsTruncate(), not an Oswrite().
                    244:       */
                    245:       if( (iDc&SQLITE_IOCAP_ATOMIC) || (pWrite->zBuf==0) ){
                    246:         random &= 0x01;
                    247:       }
                    248: 
                    249:       /* If IOCAP_SEQUENTIAL is set and this is not the final entry
                    250:       ** in the truncated write-list, always select option 1 (write
                    251:       ** out correctly).
                    252:       */
                    253:       if( (iDc&SQLITE_IOCAP_SEQUENTIAL && pWrite!=pFinal) ){
                    254:         random = 0;
                    255:       }
                    256: 
                    257:       /* If IOCAP_SAFE_APPEND is set and this OsWrite() operation is
                    258:       ** an append (first byte of the written region is 1 byte past the
                    259:       ** current EOF), always select option 1 (write out correctly).
                    260:       */
                    261:       if( iDc&SQLITE_IOCAP_SAFE_APPEND && pWrite->zBuf ){
                    262:         i64 iSize;
                    263:         sqlite3OsFileSize(pRealFile, &iSize);
                    264:         if( iSize==pWrite->iOffset ){
                    265:           random = 0;
                    266:         }
                    267:       }
                    268: 
                    269:       if( (random&0x06)==0x06 ){
                    270:         eAction = 3;
                    271:       }else{
                    272:         eAction = ((random&0x01)?2:1);
                    273:       }
                    274:     }
                    275: 
                    276:     switch( eAction ){
                    277:       case 1: {               /* Write out correctly */
                    278:         if( pWrite->zBuf ){
                    279:           rc = writeDbFile(
                    280:               pWrite->pFile, pWrite->zBuf, pWrite->nBuf, pWrite->iOffset
                    281:           );
                    282:         }else{
                    283:           rc = sqlite3OsTruncate(pRealFile, pWrite->iOffset);
                    284:         }
                    285:         *ppPtr = pWrite->pNext;
                    286: #ifdef TRACE_CRASHTEST
                    287:         if( isCrash ){
                    288:           printf("Writing %d bytes @ %d (%s)\n", 
                    289:             pWrite->nBuf, (int)pWrite->iOffset, pWrite->pFile->zName
                    290:           );
                    291:         }
                    292: #endif
                    293:         crash_free(pWrite);
                    294:         break;
                    295:       }
                    296:       case 2: {               /* Do nothing */
                    297:         ppPtr = &pWrite->pNext;
                    298: #ifdef TRACE_CRASHTEST
                    299:         if( isCrash ){
                    300:           printf("Omiting %d bytes @ %d (%s)\n", 
                    301:             pWrite->nBuf, (int)pWrite->iOffset, pWrite->pFile->zName
                    302:           );
                    303:         }
                    304: #endif
                    305:         break;
                    306:       }
                    307:       case 3: {               /* Trash sectors */
                    308:         u8 *zGarbage;
                    309:         int iFirst = (pWrite->iOffset/g.iSectorSize);
                    310:         int iLast = (pWrite->iOffset+pWrite->nBuf-1)/g.iSectorSize;
                    311: 
                    312:         assert(pWrite->zBuf);
                    313: 
                    314: #ifdef TRACE_CRASHTEST
                    315:         printf("Trashing %d sectors @ sector %d (%s)\n", 
                    316:             1+iLast-iFirst, iFirst, pWrite->pFile->zName
                    317:         );
                    318: #endif
                    319: 
                    320:         zGarbage = crash_malloc(g.iSectorSize);
                    321:         if( zGarbage ){
                    322:           sqlite3_int64 i;
                    323:           for(i=iFirst; rc==SQLITE_OK && i<=iLast; i++){
                    324:             sqlite3_randomness(g.iSectorSize, zGarbage); 
                    325:             rc = writeDbFile(
                    326:               pWrite->pFile, zGarbage, g.iSectorSize, i*g.iSectorSize
                    327:             );
                    328:           }
                    329:           crash_free(zGarbage);
                    330:         }else{
                    331:           rc = SQLITE_NOMEM;
                    332:         }
                    333: 
                    334:         ppPtr = &pWrite->pNext;
                    335:         break;
                    336:       }
                    337: 
                    338:       default:
                    339:         assert(!"Cannot happen");
                    340:     }
                    341: 
                    342:     if( pWrite==pFinal ) break;
                    343:   }
                    344: 
                    345:   if( rc==SQLITE_OK && isCrash ){
                    346:     exit(-1);
                    347:   }
                    348: 
                    349:   for(pWrite=g.pWriteList; pWrite && pWrite->pNext; pWrite=pWrite->pNext);
                    350:   g.pWriteListEnd = pWrite;
                    351: 
                    352:   return rc;
                    353: }
                    354: 
                    355: /*
                    356: ** Add an entry to the end of the write-list.
                    357: */
                    358: static int writeListAppend(
                    359:   sqlite3_file *pFile,
                    360:   sqlite3_int64 iOffset,
                    361:   const u8 *zBuf,
                    362:   int nBuf
                    363: ){
                    364:   WriteBuffer *pNew;
                    365: 
                    366:   assert((zBuf && nBuf) || (!nBuf && !zBuf));
                    367: 
                    368:   pNew = (WriteBuffer *)crash_malloc(sizeof(WriteBuffer) + nBuf);
                    369:   if( pNew==0 ){
                    370:     fprintf(stderr, "out of memory in the crash simulator\n");
                    371:   }
                    372:   memset(pNew, 0, sizeof(WriteBuffer)+nBuf);
                    373:   pNew->iOffset = iOffset;
                    374:   pNew->nBuf = nBuf;
                    375:   pNew->pFile = (CrashFile *)pFile;
                    376:   if( zBuf ){
                    377:     pNew->zBuf = (u8 *)&pNew[1];
                    378:     memcpy(pNew->zBuf, zBuf, nBuf);
                    379:   }
                    380: 
                    381:   if( g.pWriteList ){
                    382:     assert(g.pWriteListEnd);
                    383:     g.pWriteListEnd->pNext = pNew;
                    384:   }else{
                    385:     g.pWriteList = pNew;
                    386:   }
                    387:   g.pWriteListEnd = pNew;
                    388:   
                    389:   return SQLITE_OK;
                    390: }
                    391: 
                    392: /*
                    393: ** Close a crash-file.
                    394: */
                    395: static int cfClose(sqlite3_file *pFile){
                    396:   CrashFile *pCrash = (CrashFile *)pFile;
                    397:   writeListSync(pCrash, 0);
                    398:   sqlite3OsClose(pCrash->pRealFile);
                    399:   return SQLITE_OK;
                    400: }
                    401: 
                    402: /*
                    403: ** Read data from a crash-file.
                    404: */
                    405: static int cfRead(
                    406:   sqlite3_file *pFile, 
                    407:   void *zBuf, 
                    408:   int iAmt, 
                    409:   sqlite_int64 iOfst
                    410: ){
                    411:   CrashFile *pCrash = (CrashFile *)pFile;
                    412: 
                    413:   /* Check the file-size to see if this is a short-read */
                    414:   if( pCrash->iSize<(iOfst+iAmt) ){
                    415:     return SQLITE_IOERR_SHORT_READ;
                    416:   }
                    417: 
                    418:   memcpy(zBuf, &pCrash->zData[iOfst], iAmt);
                    419:   return SQLITE_OK;
                    420: }
                    421: 
                    422: /*
                    423: ** Write data to a crash-file.
                    424: */
                    425: static int cfWrite(
                    426:   sqlite3_file *pFile, 
                    427:   const void *zBuf, 
                    428:   int iAmt, 
                    429:   sqlite_int64 iOfst
                    430: ){
                    431:   CrashFile *pCrash = (CrashFile *)pFile;
                    432:   if( iAmt+iOfst>pCrash->iSize ){
                    433:     pCrash->iSize = iAmt+iOfst;
                    434:   }
                    435:   while( pCrash->iSize>pCrash->nData ){
                    436:     u8 *zNew;
                    437:     int nNew = (pCrash->nData*2) + 4096;
                    438:     zNew = crash_realloc(pCrash->zData, nNew);
                    439:     if( !zNew ){
                    440:       return SQLITE_NOMEM;
                    441:     }
                    442:     memset(&zNew[pCrash->nData], 0, nNew-pCrash->nData);
                    443:     pCrash->nData = nNew;
                    444:     pCrash->zData = zNew;
                    445:   }
                    446:   memcpy(&pCrash->zData[iOfst], zBuf, iAmt);
                    447:   return writeListAppend(pFile, iOfst, zBuf, iAmt);
                    448: }
                    449: 
                    450: /*
                    451: ** Truncate a crash-file.
                    452: */
                    453: static int cfTruncate(sqlite3_file *pFile, sqlite_int64 size){
                    454:   CrashFile *pCrash = (CrashFile *)pFile;
                    455:   assert(size>=0);
                    456:   if( pCrash->iSize>size ){
                    457:     pCrash->iSize = size;
                    458:   }
                    459:   return writeListAppend(pFile, size, 0, 0);
                    460: }
                    461: 
                    462: /*
                    463: ** Sync a crash-file.
                    464: */
                    465: static int cfSync(sqlite3_file *pFile, int flags){
                    466:   CrashFile *pCrash = (CrashFile *)pFile;
                    467:   int isCrash = 0;
                    468: 
                    469:   const char *zName = pCrash->zName;
                    470:   const char *zCrashFile = g.zCrashFile;
                    471:   int nName = strlen(zName);
                    472:   int nCrashFile = strlen(zCrashFile);
                    473: 
                    474:   if( nCrashFile>0 && zCrashFile[nCrashFile-1]=='*' ){
                    475:     nCrashFile--;
                    476:     if( nName>nCrashFile ) nName = nCrashFile;
                    477:   }
                    478: 
                    479:   if( nName==nCrashFile && 0==memcmp(zName, zCrashFile, nName) ){
                    480:     if( (--g.iCrash)==0 ) isCrash = 1;
                    481:   }
                    482: 
                    483:   return writeListSync(pCrash, isCrash);
                    484: }
                    485: 
                    486: /*
                    487: ** Return the current file-size of the crash-file.
                    488: */
                    489: static int cfFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
                    490:   CrashFile *pCrash = (CrashFile *)pFile;
                    491:   *pSize = (i64)pCrash->iSize;
                    492:   return SQLITE_OK;
                    493: }
                    494: 
                    495: /*
                    496: ** Calls related to file-locks are passed on to the real file handle.
                    497: */
                    498: static int cfLock(sqlite3_file *pFile, int eLock){
                    499:   return sqlite3OsLock(((CrashFile *)pFile)->pRealFile, eLock);
                    500: }
                    501: static int cfUnlock(sqlite3_file *pFile, int eLock){
                    502:   return sqlite3OsUnlock(((CrashFile *)pFile)->pRealFile, eLock);
                    503: }
                    504: static int cfCheckReservedLock(sqlite3_file *pFile, int *pResOut){
                    505:   return sqlite3OsCheckReservedLock(((CrashFile *)pFile)->pRealFile, pResOut);
                    506: }
                    507: static int cfFileControl(sqlite3_file *pFile, int op, void *pArg){
                    508:   if( op==SQLITE_FCNTL_SIZE_HINT ){
                    509:     CrashFile *pCrash = (CrashFile *)pFile;
                    510:     i64 nByte = *(i64 *)pArg;
                    511:     if( nByte>pCrash->iSize ){
                    512:       if( SQLITE_OK==writeListAppend(pFile, nByte, 0, 0) ){
                    513:         pCrash->iSize = nByte;
                    514:       }
                    515:     }
                    516:     return SQLITE_OK;
                    517:   }
                    518:   return sqlite3OsFileControl(((CrashFile *)pFile)->pRealFile, op, pArg);
                    519: }
                    520: 
                    521: /*
                    522: ** The xSectorSize() and xDeviceCharacteristics() functions return
                    523: ** the global values configured by the [sqlite_crashparams] tcl
                    524: *  interface.
                    525: */
                    526: static int cfSectorSize(sqlite3_file *pFile){
                    527:   return g.iSectorSize;
                    528: }
                    529: static int cfDeviceCharacteristics(sqlite3_file *pFile){
                    530:   return g.iDeviceCharacteristics;
                    531: }
                    532: 
                    533: /*
                    534: ** Pass-throughs for WAL support.
                    535: */
                    536: static int cfShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
                    537:   return sqlite3OsShmLock(((CrashFile*)pFile)->pRealFile, ofst, n, flags);
                    538: }
                    539: static void cfShmBarrier(sqlite3_file *pFile){
                    540:   sqlite3OsShmBarrier(((CrashFile*)pFile)->pRealFile);
                    541: }
                    542: static int cfShmUnmap(sqlite3_file *pFile, int delFlag){
                    543:   return sqlite3OsShmUnmap(((CrashFile*)pFile)->pRealFile, delFlag);
                    544: }
                    545: static int cfShmMap(
                    546:   sqlite3_file *pFile,            /* Handle open on database file */
                    547:   int iRegion,                    /* Region to retrieve */
                    548:   int sz,                         /* Size of regions */
                    549:   int w,                          /* True to extend file if necessary */
                    550:   void volatile **pp              /* OUT: Mapped memory */
                    551: ){
                    552:   return sqlite3OsShmMap(((CrashFile*)pFile)->pRealFile, iRegion, sz, w, pp);
                    553: }
                    554: 
                    555: static const sqlite3_io_methods CrashFileVtab = {
                    556:   2,                            /* iVersion */
                    557:   cfClose,                      /* xClose */
                    558:   cfRead,                       /* xRead */
                    559:   cfWrite,                      /* xWrite */
                    560:   cfTruncate,                   /* xTruncate */
                    561:   cfSync,                       /* xSync */
                    562:   cfFileSize,                   /* xFileSize */
                    563:   cfLock,                       /* xLock */
                    564:   cfUnlock,                     /* xUnlock */
                    565:   cfCheckReservedLock,          /* xCheckReservedLock */
                    566:   cfFileControl,                /* xFileControl */
                    567:   cfSectorSize,                 /* xSectorSize */
                    568:   cfDeviceCharacteristics,      /* xDeviceCharacteristics */
                    569:   cfShmMap,                     /* xShmMap */
                    570:   cfShmLock,                    /* xShmLock */
                    571:   cfShmBarrier,                 /* xShmBarrier */
                    572:   cfShmUnmap                    /* xShmUnmap */
                    573: };
                    574: 
                    575: /*
                    576: ** Application data for the crash VFS
                    577: */
                    578: struct crashAppData {
                    579:   sqlite3_vfs *pOrig;                   /* Wrapped vfs structure */
                    580: };
                    581: 
                    582: /*
                    583: ** Open a crash-file file handle.
                    584: **
                    585: ** The caller will have allocated pVfs->szOsFile bytes of space
                    586: ** at pFile. This file uses this space for the CrashFile structure
                    587: ** and allocates space for the "real" file structure using 
                    588: ** sqlite3_malloc(). The assumption here is (pVfs->szOsFile) is
                    589: ** equal or greater than sizeof(CrashFile).
                    590: */
                    591: static int cfOpen(
                    592:   sqlite3_vfs *pCfVfs,
                    593:   const char *zName,
                    594:   sqlite3_file *pFile,
                    595:   int flags,
                    596:   int *pOutFlags
                    597: ){
                    598:   sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
                    599:   int rc;
                    600:   CrashFile *pWrapper = (CrashFile *)pFile;
                    601:   sqlite3_file *pReal = (sqlite3_file*)&pWrapper[1];
                    602: 
                    603:   memset(pWrapper, 0, sizeof(CrashFile));
                    604:   rc = sqlite3OsOpen(pVfs, zName, pReal, flags, pOutFlags);
                    605: 
                    606:   if( rc==SQLITE_OK ){
                    607:     i64 iSize;
                    608:     pWrapper->pMethod = &CrashFileVtab;
                    609:     pWrapper->zName = (char *)zName;
                    610:     pWrapper->pRealFile = pReal;
                    611:     rc = sqlite3OsFileSize(pReal, &iSize);
                    612:     pWrapper->iSize = (int)iSize;
                    613:     pWrapper->flags = flags;
                    614:   }
                    615:   if( rc==SQLITE_OK ){
                    616:     pWrapper->nData = (4096 + pWrapper->iSize);
                    617:     pWrapper->zData = crash_malloc(pWrapper->nData);
                    618:     if( pWrapper->zData ){
                    619:       /* os_unix.c contains an assert() that fails if the caller attempts
                    620:       ** to read data from the 512-byte locking region of a file opened
                    621:       ** with the SQLITE_OPEN_MAIN_DB flag. This region of a database file
                    622:       ** never contains valid data anyhow. So avoid doing such a read here.
                    623:       */
                    624:       const int isDb = (flags&SQLITE_OPEN_MAIN_DB);
                    625:       i64 iChunk = pWrapper->iSize;
                    626:       if( iChunk>PENDING_BYTE && isDb ){
                    627:         iChunk = PENDING_BYTE;
                    628:       }
                    629:       memset(pWrapper->zData, 0, pWrapper->nData);
                    630:       rc = sqlite3OsRead(pReal, pWrapper->zData, iChunk, 0); 
                    631:       if( SQLITE_OK==rc && pWrapper->iSize>(PENDING_BYTE+512) && isDb ){
                    632:         i64 iOff = PENDING_BYTE+512;
                    633:         iChunk = pWrapper->iSize - iOff;
                    634:         rc = sqlite3OsRead(pReal, &pWrapper->zData[iOff], iChunk, iOff);
                    635:       }
                    636:     }else{
                    637:       rc = SQLITE_NOMEM;
                    638:     }
                    639:   }
                    640:   if( rc!=SQLITE_OK && pWrapper->pMethod ){
                    641:     sqlite3OsClose(pFile);
                    642:   }
                    643:   return rc;
                    644: }
                    645: 
                    646: static int cfDelete(sqlite3_vfs *pCfVfs, const char *zPath, int dirSync){
                    647:   sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
                    648:   return pVfs->xDelete(pVfs, zPath, dirSync);
                    649: }
                    650: static int cfAccess(
                    651:   sqlite3_vfs *pCfVfs, 
                    652:   const char *zPath, 
                    653:   int flags, 
                    654:   int *pResOut
                    655: ){
                    656:   sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
                    657:   return pVfs->xAccess(pVfs, zPath, flags, pResOut);
                    658: }
                    659: static int cfFullPathname(
                    660:   sqlite3_vfs *pCfVfs, 
                    661:   const char *zPath, 
                    662:   int nPathOut,
                    663:   char *zPathOut
                    664: ){
                    665:   sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
                    666:   return pVfs->xFullPathname(pVfs, zPath, nPathOut, zPathOut);
                    667: }
                    668: static void *cfDlOpen(sqlite3_vfs *pCfVfs, const char *zPath){
                    669:   sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
                    670:   return pVfs->xDlOpen(pVfs, zPath);
                    671: }
                    672: static void cfDlError(sqlite3_vfs *pCfVfs, int nByte, char *zErrMsg){
                    673:   sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
                    674:   pVfs->xDlError(pVfs, nByte, zErrMsg);
                    675: }
                    676: static void (*cfDlSym(sqlite3_vfs *pCfVfs, void *pH, const char *zSym))(void){
                    677:   sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
                    678:   return pVfs->xDlSym(pVfs, pH, zSym);
                    679: }
                    680: static void cfDlClose(sqlite3_vfs *pCfVfs, void *pHandle){
                    681:   sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
                    682:   pVfs->xDlClose(pVfs, pHandle);
                    683: }
                    684: static int cfRandomness(sqlite3_vfs *pCfVfs, int nByte, char *zBufOut){
                    685:   sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
                    686:   return pVfs->xRandomness(pVfs, nByte, zBufOut);
                    687: }
                    688: static int cfSleep(sqlite3_vfs *pCfVfs, int nMicro){
                    689:   sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
                    690:   return pVfs->xSleep(pVfs, nMicro);
                    691: }
                    692: static int cfCurrentTime(sqlite3_vfs *pCfVfs, double *pTimeOut){
                    693:   sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
                    694:   return pVfs->xCurrentTime(pVfs, pTimeOut);
                    695: }
                    696: 
                    697: static int processDevSymArgs(
                    698:   Tcl_Interp *interp,
                    699:   int objc,
                    700:   Tcl_Obj *CONST objv[],
                    701:   int *piDeviceChar,
                    702:   int *piSectorSize
                    703: ){
                    704:   struct DeviceFlag {
                    705:     char *zName;
                    706:     int iValue;
                    707:   } aFlag[] = {
                    708:     { "atomic",              SQLITE_IOCAP_ATOMIC                },
                    709:     { "atomic512",           SQLITE_IOCAP_ATOMIC512             },
                    710:     { "atomic1k",            SQLITE_IOCAP_ATOMIC1K              },
                    711:     { "atomic2k",            SQLITE_IOCAP_ATOMIC2K              },
                    712:     { "atomic4k",            SQLITE_IOCAP_ATOMIC4K              },
                    713:     { "atomic8k",            SQLITE_IOCAP_ATOMIC8K              },
                    714:     { "atomic16k",           SQLITE_IOCAP_ATOMIC16K             },
                    715:     { "atomic32k",           SQLITE_IOCAP_ATOMIC32K             },
                    716:     { "atomic64k",           SQLITE_IOCAP_ATOMIC64K             },
                    717:     { "sequential",          SQLITE_IOCAP_SEQUENTIAL            },
                    718:     { "safe_append",         SQLITE_IOCAP_SAFE_APPEND           },
                    719:     { "powersafe_overwrite", SQLITE_IOCAP_POWERSAFE_OVERWRITE   },
                    720:     { 0, 0 }
                    721:   };
                    722: 
                    723:   int i;
                    724:   int iDc = 0;
                    725:   int iSectorSize = 0;
                    726:   int setSectorsize = 0;
                    727:   int setDeviceChar = 0;
                    728: 
                    729:   for(i=0; i<objc; i+=2){
                    730:     int nOpt;
                    731:     char *zOpt = Tcl_GetStringFromObj(objv[i], &nOpt);
                    732: 
                    733:     if( (nOpt>11 || nOpt<2 || strncmp("-sectorsize", zOpt, nOpt)) 
                    734:      && (nOpt>16 || nOpt<2 || strncmp("-characteristics", zOpt, nOpt))
                    735:     ){
                    736:       Tcl_AppendResult(interp, 
                    737:         "Bad option: \"", zOpt, 
                    738:         "\" - must be \"-characteristics\" or \"-sectorsize\"", 0
                    739:       );
                    740:       return TCL_ERROR;
                    741:     }
                    742:     if( i==objc-1 ){
                    743:       Tcl_AppendResult(interp, "Option requires an argument: \"", zOpt, "\"",0);
                    744:       return TCL_ERROR;
                    745:     }
                    746: 
                    747:     if( zOpt[1]=='s' ){
                    748:       if( Tcl_GetIntFromObj(interp, objv[i+1], &iSectorSize) ){
                    749:         return TCL_ERROR;
                    750:       }
                    751:       setSectorsize = 1;
                    752:     }else{
                    753:       int j;
                    754:       Tcl_Obj **apObj;
                    755:       int nObj;
                    756:       if( Tcl_ListObjGetElements(interp, objv[i+1], &nObj, &apObj) ){
                    757:         return TCL_ERROR;
                    758:       }
                    759:       for(j=0; j<nObj; j++){
                    760:         int rc;
                    761:         int iChoice;
                    762:         Tcl_Obj *pFlag = Tcl_DuplicateObj(apObj[j]);
                    763:         Tcl_IncrRefCount(pFlag);
                    764:         Tcl_UtfToLower(Tcl_GetString(pFlag));
                    765:  
                    766:         rc = Tcl_GetIndexFromObjStruct(
                    767:             interp, pFlag, aFlag, sizeof(aFlag[0]), "no such flag", 0, &iChoice
                    768:         );
                    769:         Tcl_DecrRefCount(pFlag);
                    770:         if( rc ){
                    771:           return TCL_ERROR;
                    772:         }
                    773: 
                    774:         iDc |= aFlag[iChoice].iValue;
                    775:       }
                    776:       setDeviceChar = 1;
                    777:     }
                    778:   }
                    779: 
                    780:   if( setDeviceChar ){
                    781:     *piDeviceChar = iDc;
                    782:   }
                    783:   if( setSectorsize ){
                    784:     *piSectorSize = iSectorSize;
                    785:   }
                    786: 
                    787:   return TCL_OK;
                    788: }
                    789: 
                    790: /*
                    791: ** tclcmd:   sqlite_crash_enable ENABLE
                    792: **
                    793: ** Parameter ENABLE must be a boolean value. If true, then the "crash"
                    794: ** vfs is added to the system. If false, it is removed.
                    795: */
                    796: static int crashEnableCmd(
                    797:   void * clientData,
                    798:   Tcl_Interp *interp,
                    799:   int objc,
                    800:   Tcl_Obj *CONST objv[]
                    801: ){
                    802:   int isEnable;
                    803:   static sqlite3_vfs crashVfs = {
                    804:     2,                  /* iVersion */
                    805:     0,                  /* szOsFile */
                    806:     0,                  /* mxPathname */
                    807:     0,                  /* pNext */
                    808:     "crash",            /* zName */
                    809:     0,                  /* pAppData */
                    810:   
                    811:     cfOpen,               /* xOpen */
                    812:     cfDelete,             /* xDelete */
                    813:     cfAccess,             /* xAccess */
                    814:     cfFullPathname,       /* xFullPathname */
                    815:     cfDlOpen,             /* xDlOpen */
                    816:     cfDlError,            /* xDlError */
                    817:     cfDlSym,              /* xDlSym */
                    818:     cfDlClose,            /* xDlClose */
                    819:     cfRandomness,         /* xRandomness */
                    820:     cfSleep,              /* xSleep */
                    821:     cfCurrentTime,        /* xCurrentTime */
                    822:     0,                    /* xGetlastError */
                    823:     0,                    /* xCurrentTimeInt64 */
                    824:   };
                    825: 
                    826:   if( objc!=2 ){
                    827:     Tcl_WrongNumArgs(interp, 1, objv, "ENABLE");
                    828:     return TCL_ERROR;
                    829:   }
                    830: 
                    831:   if( Tcl_GetBooleanFromObj(interp, objv[1], &isEnable) ){
                    832:     return TCL_ERROR;
                    833:   }
                    834: 
                    835:   if( (isEnable && crashVfs.pAppData) || (!isEnable && !crashVfs.pAppData) ){
                    836:     return TCL_OK;
                    837:   }
                    838: 
                    839:   if( crashVfs.pAppData==0 ){
                    840:     sqlite3_vfs *pOriginalVfs = sqlite3_vfs_find(0);
                    841:     crashVfs.mxPathname = pOriginalVfs->mxPathname;
                    842:     crashVfs.pAppData = (void *)pOriginalVfs;
                    843:     crashVfs.szOsFile = sizeof(CrashFile) + pOriginalVfs->szOsFile;
                    844:     sqlite3_vfs_register(&crashVfs, 0);
                    845:   }else{
                    846:     crashVfs.pAppData = 0;
                    847:     sqlite3_vfs_unregister(&crashVfs);
                    848:   }
                    849: 
                    850:   return TCL_OK;
                    851: }
                    852: 
                    853: /*
                    854: ** tclcmd:   sqlite_crashparams ?OPTIONS? DELAY CRASHFILE
                    855: **
                    856: ** This procedure implements a TCL command that enables crash testing
                    857: ** in testfixture.  Once enabled, crash testing cannot be disabled.
                    858: **
                    859: ** Available options are "-characteristics" and "-sectorsize". Both require
                    860: ** an argument. For -sectorsize, this is the simulated sector size in
                    861: ** bytes. For -characteristics, the argument must be a list of io-capability
                    862: ** flags to simulate. Valid flags are "atomic", "atomic512", "atomic1K",
                    863: ** "atomic2K", "atomic4K", "atomic8K", "atomic16K", "atomic32K", 
                    864: ** "atomic64K", "sequential" and "safe_append".
                    865: **
                    866: ** Example:
                    867: **
                    868: **   sqlite_crashparams -sect 1024 -char {atomic sequential} ./test.db 1
                    869: **
                    870: */
                    871: static int crashParamsObjCmd(
                    872:   void * clientData,
                    873:   Tcl_Interp *interp,
                    874:   int objc,
                    875:   Tcl_Obj *CONST objv[]
                    876: ){
                    877:   int iDelay;
                    878:   const char *zCrashFile;
                    879:   int nCrashFile, iDc, iSectorSize;
                    880: 
                    881:   iDc = -1;
                    882:   iSectorSize = -1;
                    883: 
                    884:   if( objc<3 ){
                    885:     Tcl_WrongNumArgs(interp, 1, objv, "?OPTIONS? DELAY CRASHFILE");
                    886:     goto error;
                    887:   }
                    888: 
                    889:   zCrashFile = Tcl_GetStringFromObj(objv[objc-1], &nCrashFile);
                    890:   if( nCrashFile>=sizeof(g.zCrashFile) ){
                    891:     Tcl_AppendResult(interp, "Filename is too long: \"", zCrashFile, "\"", 0);
                    892:     goto error;
                    893:   }
                    894:   if( Tcl_GetIntFromObj(interp, objv[objc-2], &iDelay) ){
                    895:     goto error;
                    896:   }
                    897: 
                    898:   if( processDevSymArgs(interp, objc-3, &objv[1], &iDc, &iSectorSize) ){
                    899:     return TCL_ERROR;
                    900:   }
                    901: 
                    902:   if( iDc>=0 ){
                    903:     g.iDeviceCharacteristics = iDc;
                    904:   }
                    905:   if( iSectorSize>=0 ){
                    906:     g.iSectorSize = iSectorSize;
                    907:   }
                    908: 
                    909:   g.iCrash = iDelay;
                    910:   memcpy(g.zCrashFile, zCrashFile, nCrashFile+1);
                    911:   sqlite3CrashTestEnable = 1;
                    912:   return TCL_OK;
                    913: 
                    914: error:
                    915:   return TCL_ERROR;
                    916: }
                    917: 
                    918: static int devSymObjCmd(
                    919:   void * clientData,
                    920:   Tcl_Interp *interp,
                    921:   int objc,
                    922:   Tcl_Obj *CONST objv[]
                    923: ){
                    924:   void devsym_register(int iDeviceChar, int iSectorSize);
                    925: 
                    926:   int iDc = -1;
                    927:   int iSectorSize = -1;
                    928: 
                    929:   if( processDevSymArgs(interp, objc-1, &objv[1], &iDc, &iSectorSize) ){
                    930:     return TCL_ERROR;
                    931:   }
                    932:   devsym_register(iDc, iSectorSize);
                    933: 
                    934:   return TCL_OK;
                    935: }
                    936: 
                    937: /*
                    938: ** tclcmd: register_jt_vfs ?-default? PARENT-VFS
                    939: */
                    940: static int jtObjCmd(
                    941:   void * clientData,
                    942:   Tcl_Interp *interp,
                    943:   int objc,
                    944:   Tcl_Obj *CONST objv[]
                    945: ){
                    946:   int jt_register(char *, int);
                    947:   char *zParent = 0;
                    948: 
                    949:   if( objc!=2 && objc!=3 ){
                    950:     Tcl_WrongNumArgs(interp, 1, objv, "?-default? PARENT-VFS");
                    951:     return TCL_ERROR;
                    952:   }
                    953:   zParent = Tcl_GetString(objv[1]);
                    954:   if( objc==3 ){
                    955:     if( strcmp(zParent, "-default") ){
                    956:       Tcl_AppendResult(interp, 
                    957:           "bad option \"", zParent, "\": must be -default", 0
                    958:       );
                    959:       return TCL_ERROR;
                    960:     }
                    961:     zParent = Tcl_GetString(objv[2]);
                    962:   }
                    963: 
                    964:   if( !(*zParent) ){
                    965:     zParent = 0;
                    966:   }
                    967:   if( jt_register(zParent, objc==3) ){
                    968:     Tcl_AppendResult(interp, "Error in jt_register", 0);
                    969:     return TCL_ERROR;
                    970:   }
                    971: 
                    972:   return TCL_OK;
                    973: }
                    974: 
                    975: /*
                    976: ** tclcmd: unregister_jt_vfs
                    977: */
                    978: static int jtUnregisterObjCmd(
                    979:   void * clientData,
                    980:   Tcl_Interp *interp,
                    981:   int objc,
                    982:   Tcl_Obj *CONST objv[]
                    983: ){
                    984:   void jt_unregister(void);
                    985: 
                    986:   if( objc!=1 ){
                    987:     Tcl_WrongNumArgs(interp, 1, objv, "");
                    988:     return TCL_ERROR;
                    989:   }
                    990: 
                    991:   jt_unregister();
                    992:   return TCL_OK;
                    993: }
                    994: 
                    995: #endif /* SQLITE_OMIT_DISKIO */
                    996: 
                    997: /*
                    998: ** This procedure registers the TCL procedures defined in this file.
                    999: */
                   1000: int Sqlitetest6_Init(Tcl_Interp *interp){
                   1001: #ifndef SQLITE_OMIT_DISKIO
                   1002:   Tcl_CreateObjCommand(interp, "sqlite3_crash_enable", crashEnableCmd, 0, 0);
                   1003:   Tcl_CreateObjCommand(interp, "sqlite3_crashparams", crashParamsObjCmd, 0, 0);
                   1004:   Tcl_CreateObjCommand(interp, "sqlite3_simulate_device", devSymObjCmd, 0, 0);
                   1005:   Tcl_CreateObjCommand(interp, "register_jt_vfs", jtObjCmd, 0, 0);
                   1006:   Tcl_CreateObjCommand(interp, "unregister_jt_vfs", jtUnregisterObjCmd, 0, 0);
                   1007: #endif
                   1008:   return TCL_OK;
                   1009: }
                   1010: 
                   1011: #endif /* SQLITE_TEST */

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