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