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 the testing only */ 18 #include "sqliteInt.h" 19 #include "os.h" 20 #include "tcl.h" 21 22 #ifndef SQLITE_OMIT_DISKIO /* This file is a no-op if disk I/O is disabled */ 23 24 /* 25 ** crashFile is a subclass of OsFile that is taylored for the 26 ** crash test module. 27 */ 28 typedef struct crashFile crashFile; 29 struct crashFile { 30 IoMethod const *pMethod; /* Must be first */ 31 u8 **apBlk; /* Array of blocks that have been written to. */ 32 int nBlk; /* Size of apBlock. */ 33 i64 offset; /* Next character to be read from the file */ 34 int nMaxWrite; /* Largest offset written to. */ 35 char *zName; /* File name */ 36 OsFile *pBase; /* The real file */ 37 crashFile *pNext; /* Next in a list of them all */ 38 }; 39 40 /* 41 ** Size of a simulated disk block 42 */ 43 #define BLOCKSIZE 512 44 #define BLOCK_OFFSET(x) ((x) * BLOCKSIZE) 45 46 47 /* 48 ** The following variables control when a simulated crash occurs. 49 ** 50 ** If iCrashDelay is non-zero, then zCrashFile contains (full path) name of 51 ** a file that SQLite will call sqlite3OsSync() on. Each time this happens 52 ** iCrashDelay is decremented. If iCrashDelay is zero after being 53 ** decremented, a "crash" occurs during the sync() operation. 54 ** 55 ** In other words, a crash occurs the iCrashDelay'th time zCrashFile is 56 ** synced. 57 */ 58 static int iCrashDelay = 0; 59 static char zCrashFile[500]; 60 61 /* 62 ** Set the value of the two crash parameters. 63 */ 64 static void setCrashParams(int iDelay, char const *zFile){ 65 sqlite3OsEnterMutex(); 66 assert( strlen(zFile)<sizeof(zCrashFile) ); 67 strcpy(zCrashFile, zFile); 68 iCrashDelay = iDelay; 69 sqlite3OsLeaveMutex(); 70 } 71 72 /* 73 ** File zPath is being sync()ed. Return non-zero if this should 74 ** cause a crash. 75 */ 76 static int crashRequired(char const *zPath){ 77 int r; 78 int n; 79 sqlite3OsEnterMutex(); 80 n = strlen(zCrashFile); 81 if( zCrashFile[n-1]=='*' ){ 82 n--; 83 }else if( strlen(zPath)>n ){ 84 n = strlen(zPath); 85 } 86 r = 0; 87 if( iCrashDelay>0 && strncmp(zPath, zCrashFile, n)==0 ){ 88 iCrashDelay--; 89 if( iCrashDelay<=0 ){ 90 r = 1; 91 } 92 } 93 sqlite3OsLeaveMutex(); 94 return r; 95 } 96 97 /* 98 ** A list of all open files. 99 */ 100 static crashFile *pAllFiles = 0; 101 102 /* Forward reference */ 103 static void initFile(OsFile **pId, char const *zName, OsFile *pBase); 104 105 /* 106 ** Undo the work done by initFile. Delete the OsFile structure 107 ** and unlink the structure from the pAllFiles list. 108 */ 109 static void closeFile(crashFile **pId){ 110 crashFile *pFile = *pId; 111 if( pFile==pAllFiles ){ 112 pAllFiles = pFile->pNext; 113 }else{ 114 crashFile *p; 115 for(p=pAllFiles; p->pNext!=pFile; p=p->pNext ){ 116 assert( p ); 117 } 118 p->pNext = pFile->pNext; 119 } 120 sqliteFree(*pId); 121 *pId = 0; 122 } 123 124 /* 125 ** Read block 'blk' off of the real disk file and into the cache of pFile. 126 */ 127 static int readBlockIntoCache(crashFile *pFile, int blk){ 128 if( blk>=pFile->nBlk ){ 129 int n = ((pFile->nBlk * 2) + 100 + blk); 130 /* if( pFile->nBlk==0 ){ printf("DIRTY %s\n", pFile->zName); } */ 131 pFile->apBlk = (u8 **)sqliteRealloc(pFile->apBlk, n * sizeof(u8*)); 132 if( !pFile->apBlk ) return SQLITE_NOMEM; 133 memset(&pFile->apBlk[pFile->nBlk], 0, (n - pFile->nBlk)*sizeof(u8*)); 134 pFile->nBlk = n; 135 } 136 137 if( !pFile->apBlk[blk] ){ 138 i64 filesize; 139 int rc; 140 141 u8 *p = sqliteMalloc(BLOCKSIZE); 142 if( !p ) return SQLITE_NOMEM; 143 pFile->apBlk[blk] = p; 144 145 rc = sqlite3OsFileSize(pFile->pBase, &filesize); 146 if( rc!=SQLITE_OK ) return rc; 147 148 if( BLOCK_OFFSET(blk)<filesize ){ 149 int len = BLOCKSIZE; 150 rc = sqlite3OsSeek(pFile->pBase, blk*BLOCKSIZE); 151 if( BLOCK_OFFSET(blk+1)>filesize ){ 152 len = filesize - BLOCK_OFFSET(blk); 153 } 154 if( rc!=SQLITE_OK ) return rc; 155 rc = sqlite3OsRead(pFile->pBase, p, len); 156 if( rc!=SQLITE_OK ) return rc; 157 } 158 } 159 160 return SQLITE_OK; 161 } 162 163 /* 164 ** Write the cache of pFile to disk. If crash is non-zero, randomly 165 ** skip blocks when writing. The cache is deleted before returning. 166 */ 167 static int writeCache2(crashFile *pFile, int crash){ 168 int i; 169 int nMax = pFile->nMaxWrite; 170 int rc = SQLITE_OK; 171 172 for(i=0; i<pFile->nBlk; i++){ 173 u8 *p = pFile->apBlk[i]; 174 if( p ){ 175 int skip = 0; 176 int trash = 0; 177 if( crash ){ 178 char random; 179 sqlite3Randomness(1, &random); 180 if( random & 0x01 ){ 181 if( random & 0x02 ){ 182 trash = 1; 183 #ifdef TRACE_WRITECACHE 184 printf("Trashing block %d of %s\n", i, pFile->zName); 185 #endif 186 }else{ 187 skip = 1; 188 #ifdef TRACE_WRITECACHE 189 printf("Skiping block %d of %s\n", i, pFile->zName); 190 #endif 191 } 192 }else{ 193 #ifdef TRACE_WRITECACHE 194 printf("Writing block %d of %s\n", i, pFile->zName); 195 #endif 196 } 197 } 198 if( rc==SQLITE_OK ){ 199 rc = sqlite3OsSeek(pFile->pBase, BLOCK_OFFSET(i)); 200 } 201 if( rc==SQLITE_OK && !skip ){ 202 int len = BLOCKSIZE; 203 if( BLOCK_OFFSET(i+1)>nMax ){ 204 len = nMax-BLOCK_OFFSET(i); 205 } 206 if( len>0 ){ 207 if( trash ){ 208 sqlite3Randomness(len, p); 209 } 210 rc = sqlite3OsWrite(pFile->pBase, p, len); 211 } 212 } 213 sqliteFree(p); 214 } 215 } 216 sqliteFree(pFile->apBlk); 217 pFile->nBlk = 0; 218 pFile->apBlk = 0; 219 pFile->nMaxWrite = 0; 220 return rc; 221 } 222 223 /* 224 ** Write the cache to disk. 225 */ 226 static int writeCache(crashFile *pFile){ 227 if( pFile->apBlk ){ 228 int c = crashRequired(pFile->zName); 229 if( c ){ 230 crashFile *p; 231 #ifdef TRACE_WRITECACHE 232 printf("\nCrash during sync of %s\n", pFile->zName); 233 #endif 234 for(p=pAllFiles; p; p=p->pNext){ 235 writeCache2(p, 1); 236 } 237 exit(-1); 238 }else{ 239 return writeCache2(pFile, 0); 240 } 241 } 242 return SQLITE_OK; 243 } 244 245 /* 246 ** Close the file. 247 */ 248 static int crashClose(OsFile **pId){ 249 crashFile *pFile = (crashFile*)*pId; 250 if( pFile ){ 251 /* printf("CLOSE %s (%d blocks)\n", pFile->zName, pFile->nBlk); */ 252 writeCache(pFile); 253 sqlite3OsClose(&pFile->pBase); 254 } 255 closeFile(&pFile); 256 *pId = 0; 257 return SQLITE_OK; 258 } 259 260 static int crashSeek(OsFile *id, i64 offset){ 261 ((crashFile*)id)->offset = offset; 262 return SQLITE_OK; 263 } 264 265 static int crashRead(OsFile *id, void *pBuf, int amt){ 266 i64 offset; /* The current offset from the start of the file */ 267 i64 end; /* The byte just past the last byte read */ 268 int blk; /* Block number the read starts on */ 269 int i; 270 u8 *zCsr; 271 int rc = SQLITE_OK; 272 crashFile *pFile = (crashFile*)id; 273 274 offset = pFile->offset; 275 end = offset+amt; 276 blk = (offset/BLOCKSIZE); 277 278 zCsr = (u8 *)pBuf; 279 for(i=blk; i*BLOCKSIZE<end; i++){ 280 int off = 0; 281 int len = 0; 282 283 284 if( BLOCK_OFFSET(i) < offset ){ 285 off = offset-BLOCK_OFFSET(i); 286 } 287 len = BLOCKSIZE - off; 288 if( BLOCK_OFFSET(i+1) > end ){ 289 len = len - (BLOCK_OFFSET(i+1)-end); 290 } 291 292 if( i<pFile->nBlk && pFile->apBlk[i]){ 293 u8 *pBlk = pFile->apBlk[i]; 294 memcpy(zCsr, &pBlk[off], len); 295 }else{ 296 rc = sqlite3OsSeek(pFile->pBase, BLOCK_OFFSET(i) + off); 297 if( rc!=SQLITE_OK ) return rc; 298 rc = sqlite3OsRead(pFile->pBase, zCsr, len); 299 if( rc!=SQLITE_OK ) return rc; 300 } 301 302 zCsr += len; 303 } 304 assert( zCsr==&((u8 *)pBuf)[amt] ); 305 306 pFile->offset = end; 307 return rc; 308 } 309 310 static int crashWrite(OsFile *id, const void *pBuf, int amt){ 311 i64 offset; /* The current offset from the start of the file */ 312 i64 end; /* The byte just past the last byte written */ 313 int blk; /* Block number the write starts on */ 314 int i; 315 const u8 *zCsr; 316 int rc = SQLITE_OK; 317 crashFile *pFile = (crashFile*)id; 318 319 offset = pFile->offset; 320 end = offset+amt; 321 blk = (offset/BLOCKSIZE); 322 323 zCsr = (u8 *)pBuf; 324 for(i=blk; i*BLOCKSIZE<end; i++){ 325 u8 *pBlk; 326 int off = 0; 327 int len = 0; 328 329 /* Make sure the block is in the cache */ 330 rc = readBlockIntoCache(pFile, i); 331 if( rc!=SQLITE_OK ) return rc; 332 333 /* Write into the cache */ 334 pBlk = pFile->apBlk[i]; 335 assert( pBlk ); 336 337 if( BLOCK_OFFSET(i) < offset ){ 338 off = offset-BLOCK_OFFSET(i); 339 } 340 len = BLOCKSIZE - off; 341 if( BLOCK_OFFSET(i+1) > end ){ 342 len = len - (BLOCK_OFFSET(i+1)-end); 343 } 344 memcpy(&pBlk[off], zCsr, len); 345 zCsr += len; 346 } 347 if( pFile->nMaxWrite<end ){ 348 pFile->nMaxWrite = end; 349 } 350 assert( zCsr==&((u8 *)pBuf)[amt] ); 351 pFile->offset = end; 352 return rc; 353 } 354 355 /* 356 ** Sync the file. First flush the write-cache to disk, then call the 357 ** real sync() function. 358 */ 359 static int crashSync(OsFile *id, int dataOnly){ 360 return writeCache((crashFile*)id); 361 } 362 363 /* 364 ** Truncate the file. Set the internal OsFile.nMaxWrite variable to the new 365 ** file size to ensure that nothing in the write-cache past this point 366 ** is written to disk. 367 */ 368 static int crashTruncate(OsFile *id, i64 nByte){ 369 crashFile *pFile = (crashFile*)id; 370 pFile->nMaxWrite = nByte; 371 return sqlite3OsTruncate(pFile->pBase, nByte); 372 } 373 374 /* 375 ** Return the size of the file. If the cache contains a write that extended 376 ** the file, then return this size instead of the on-disk size. 377 */ 378 static int crashFileSize(OsFile *id, i64 *pSize){ 379 crashFile *pFile = (crashFile*)id; 380 int rc = sqlite3OsFileSize(pFile->pBase, pSize); 381 if( rc==SQLITE_OK && pSize && *pSize<pFile->nMaxWrite ){ 382 *pSize = pFile->nMaxWrite; 383 } 384 return rc; 385 } 386 387 /* 388 ** Set this global variable to 1 to enable crash testing. 389 */ 390 int sqlite3CrashTestEnable = 0; 391 392 /* 393 ** The three functions used to open files. All that is required is to 394 ** initialise the os_test.c specific fields and then call the corresponding 395 ** os_unix.c function to really open the file. 396 */ 397 int sqlite3CrashOpenReadWrite(const char *zFilename, OsFile **pId,int *pRdonly){ 398 OsFile *pBase = 0; 399 int rc; 400 401 sqlite3CrashTestEnable = 0; 402 rc = sqlite3OsOpenReadWrite(zFilename, &pBase, pRdonly); 403 sqlite3CrashTestEnable = 1; 404 if( !rc ){ 405 initFile(pId, zFilename, pBase); 406 } 407 return rc; 408 } 409 int sqlite3CrashOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){ 410 OsFile *pBase = 0; 411 int rc; 412 413 sqlite3CrashTestEnable = 0; 414 rc = sqlite3OsOpenExclusive(zFilename, &pBase, delFlag); 415 sqlite3CrashTestEnable = 1; 416 if( !rc ){ 417 initFile(pId, zFilename, pBase); 418 } 419 return rc; 420 } 421 int sqlite3CrashOpenReadOnly(const char *zFilename, OsFile **pId, int NotUsed){ 422 OsFile *pBase = 0; 423 int rc; 424 425 sqlite3CrashTestEnable = 0; 426 rc = sqlite3OsOpenReadOnly(zFilename, &pBase); 427 sqlite3CrashTestEnable = 1; 428 if( !rc ){ 429 initFile(pId, zFilename, pBase); 430 } 431 return rc; 432 } 433 434 /* 435 ** OpenDirectory is a no-op 436 */ 437 static int crashOpenDir(OsFile *id, const char *zName){ 438 return SQLITE_OK; 439 } 440 441 /* 442 ** Locking primitives are passed through into the underlying 443 ** file descriptor. 444 */ 445 int crashLock(OsFile *id, int lockType){ 446 return sqlite3OsLock(((crashFile*)id)->pBase, lockType); 447 } 448 int crashUnlock(OsFile *id, int lockType){ 449 return sqlite3OsUnlock(((crashFile*)id)->pBase, lockType); 450 } 451 int crashCheckReservedLock(OsFile *id){ 452 return sqlite3OsCheckReservedLock(((crashFile*)id)->pBase); 453 } 454 void crashSetFullSync(OsFile *id, int setting){ 455 return; /* This is a no-op */ 456 } 457 int crashLockState(OsFile *id){ 458 return sqlite3OsLockState(((crashFile*)id)->pBase); 459 } 460 461 /* 462 ** Return the underlying file handle. 463 */ 464 int crashFileHandle(OsFile *id){ 465 #if defined(SQLITE_TEST) || defined(SQLITE_DEBUG) 466 return sqlite3OsFileHandle(((crashFile*)id)->pBase); 467 #endif 468 return 0; 469 } 470 471 /* 472 ** This vector defines all the methods that can operate on an OsFile 473 ** for the crash tester. 474 */ 475 static const IoMethod crashIoMethod = { 476 crashClose, 477 crashOpenDir, 478 crashRead, 479 crashWrite, 480 crashSeek, 481 crashTruncate, 482 crashSync, 483 crashSetFullSync, 484 crashFileHandle, 485 crashFileSize, 486 crashLock, 487 crashUnlock, 488 crashLockState, 489 crashCheckReservedLock, 490 }; 491 492 493 /* 494 ** Initialise the os_test.c specific fields of pFile. 495 */ 496 static void initFile(OsFile **pId, char const *zName, OsFile *pBase){ 497 crashFile *pFile = sqliteMalloc(sizeof(crashFile) + strlen(zName)+1); 498 pFile->pMethod = &crashIoMethod; 499 pFile->nMaxWrite = 0; 500 pFile->offset = 0; 501 pFile->nBlk = 0; 502 pFile->apBlk = 0; 503 pFile->zName = (char *)(&pFile[1]); 504 strcpy(pFile->zName, zName); 505 pFile->pBase = pBase; 506 pFile->pNext = pAllFiles; 507 pAllFiles = pFile; 508 *pId = (OsFile*)pFile; 509 } 510 511 512 /* 513 ** tclcmd: sqlite_crashparams DELAY CRASHFILE 514 ** 515 ** This procedure implements a TCL command that enables crash testing 516 ** in testfixture. Once enabled, crash testing cannot be disabled. 517 */ 518 static int crashParamsObjCmd( 519 void * clientData, 520 Tcl_Interp *interp, 521 int objc, 522 Tcl_Obj *CONST objv[] 523 ){ 524 int delay; 525 const char *zFile; 526 int nFile; 527 if( objc!=3 ){ 528 Tcl_WrongNumArgs(interp, 1, objv, "DELAY CRASHFILE"); 529 return TCL_ERROR; 530 } 531 if( Tcl_GetIntFromObj(interp, objv[1], &delay) ) return TCL_ERROR; 532 zFile = Tcl_GetStringFromObj(objv[2], &nFile); 533 if( nFile>=sizeof(zCrashFile)-1 ){ 534 Tcl_AppendResult(interp, "crash file name too big", 0); 535 return TCL_ERROR; 536 } 537 setCrashParams(delay, zFile); 538 sqlite3CrashTestEnable = 1; 539 return TCL_OK; 540 } 541 542 #endif /* SQLITE_OMIT_DISKIO */ 543 544 /* 545 ** This procedure registers the TCL procedures defined in this file. 546 */ 547 int Sqlitetest6_Init(Tcl_Interp *interp){ 548 #ifndef SQLITE_OMIT_DISKIO 549 Tcl_CreateObjCommand(interp, "sqlite3_crashparams", crashParamsObjCmd, 0, 0); 550 #endif 551 return TCL_OK; 552 } 553 554 #endif /* SQLITE_TEST */ 555