blob: 8805cb80fd34c1e19ba95b121383bf6fceb30c93 [file] [log] [blame]
drh9c06c952005-11-26 00:25:00 +00001/*
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.
danielk1977822a5162008-05-16 04:51:54 +000016**
danielk197717b90b52008-06-06 11:11:25 +000017** $Id: test6.c,v 1.39 2008/06/06 11:11:26 danielk1977 Exp $
drh9c06c952005-11-26 00:25:00 +000018*/
danielk1977f55b8992007-08-24 08:15:53 +000019#if SQLITE_TEST /* This file is used for testing only */
drh9c06c952005-11-26 00:25:00 +000020#include "sqliteInt.h"
drh9c06c952005-11-26 00:25:00 +000021#include "tcl.h"
22
drh198bf392006-01-06 21:52:49 +000023#ifndef SQLITE_OMIT_DISKIO /* This file is a no-op if disk I/O is disabled */
24
danielk1977f8940ae2007-08-23 11:07:10 +000025/* #define TRACE_CRASHTEST */
26
danielk197762079062007-08-15 17:08:46 +000027typedef struct CrashFile CrashFile;
28typedef struct CrashGlobal CrashGlobal;
danielk19770d24e6b2007-08-14 17:42:05 +000029typedef struct WriteBuffer WriteBuffer;
30
31/*
32** Method:
33**
34** This layer is implemented as a wrapper around the "real"
35** sqlite3_file object for the host system. Each time data is
36** written to the file object, instead of being written to the
37** underlying file, the write operation is stored in an in-memory
38** structure (type WriteBuffer). This structure is placed at the
39** end of a global ordered list (the write-list).
40**
41** When data is read from a file object, the requested region is
42** first retrieved from the real file. The write-list is then
43** traversed and data copied from any overlapping WriteBuffer
44** structures to the output buffer. i.e. a read() operation following
45** one or more write() operations works as expected, even if no
46** data has actually been written out to the real file.
47**
48** When a fsync() operation is performed, an operating system crash
49** may be simulated, in which case exit(-1) is called (the call to
50** xSync() never returns). Whether or not a crash is simulated,
51** the data associated with a subset of the WriteBuffer structures
52** stored in the write-list is written to the real underlying files
53** and the entries removed from the write-list. If a crash is simulated,
54** a subset of the buffers may be corrupted before the data is written.
55**
56** The exact subset of the write-list written and/or corrupted is
57** determined by the simulated device characteristics and sector-size.
58**
59** "Normal" mode:
60**
61** Normal mode is used when the simulated device has none of the
62** SQLITE_IOCAP_XXX flags set.
63**
64** In normal mode, if the fsync() is not a simulated crash, the
65** write-list is traversed from beginning to end. Each WriteBuffer
66** structure associated with the file handle used to call xSync()
67** is written to the real file and removed from the write-list.
68**
69** If a crash is simulated, one of the following takes place for
70** each WriteBuffer in the write-list, regardless of which
71** file-handle it is associated with:
72**
73** 1. The buffer is correctly written to the file, just as if
74** a crash were not being simulated.
75**
76** 2. Nothing is done.
77**
78** 3. Garbage data is written to all sectors of the file that
79** overlap the region specified by the WriteBuffer. Or garbage
80** data is written to some contiguous section within the
81** overlapped sectors.
82**
83** Device Characteristic flag handling:
84**
85** If the IOCAP_ATOMIC flag is set, then option (3) above is
86** never selected.
87**
88** If the IOCAP_ATOMIC512 flag is set, and the WriteBuffer represents
89** an aligned write() of an integer number of 512 byte regions, then
90** option (3) above is never selected. Instead, each 512 byte region
91** is either correctly written or left completely untouched. Similar
92** logic governs the behaviour if any of the other ATOMICXXX flags
93** is set.
94**
95** If either the IOCAP_SAFEAPPEND or IOCAP_SEQUENTIAL flags are set
96** and a crash is being simulated, then an entry of the write-list is
97** selected at random. Everything in the list after the selected entry
98** is discarded before processing begins.
99**
100** If IOCAP_SEQUENTIAL is set and a crash is being simulated, option
101** (1) is selected for all write-list entries except the last. If a
102** crash is not being simulated, then all entries in the write-list
103** that occur before at least one write() on the file-handle specified
104** as part of the xSync() are written to their associated real files.
105**
106** If IOCAP_SAFEAPPEND is set and the first byte written by the write()
107** operation is one byte past the current end of the file, then option
108** (1) is always selected.
109*/
danielk197762079062007-08-15 17:08:46 +0000110
111/*
112** Each write operation in the write-list is represented by an instance
113** of the following structure.
114**
115** If zBuf is 0, then this structure represents a call to xTruncate(),
116** not xWrite(). In that case, iOffset is the size that the file is
117** truncated to.
118*/
danielk19770d24e6b2007-08-14 17:42:05 +0000119struct WriteBuffer {
danielk197762079062007-08-15 17:08:46 +0000120 i64 iOffset; /* Byte offset of the start of this write() */
121 int nBuf; /* Number of bytes written */
122 u8 *zBuf; /* Pointer to copy of written data */
123 CrashFile *pFile; /* File this write() applies to */
124
125 WriteBuffer *pNext; /* Next in CrashGlobal.pWriteList */
danielk19770d24e6b2007-08-14 17:42:05 +0000126};
127
danielk197762079062007-08-15 17:08:46 +0000128struct CrashFile {
129 const sqlite3_io_methods *pMethod; /* Must be first */
130 sqlite3_file *pRealFile; /* Underlying "real" file handle */
danielk19771e536952007-08-16 10:09:01 +0000131 char *zName;
danielk1977967a4a12007-08-20 14:23:44 +0000132
danielk1977f1da17a2007-08-21 13:07:46 +0000133 /* Cache of the entire file. This is used to speed up OsRead() and
134 ** OsFileSize() calls. Although both could be done by traversing the
135 ** write-list, in practice this is impractically slow.
136 */
danielk1977967a4a12007-08-20 14:23:44 +0000137 int iSize; /* Size of file in bytes */
138 int nData; /* Size of buffer allocated at zData */
139 u8 *zData; /* Buffer containing file contents */
drh9c06c952005-11-26 00:25:00 +0000140};
141
danielk197762079062007-08-15 17:08:46 +0000142struct CrashGlobal {
143 WriteBuffer *pWriteList; /* Head of write-list */
danielk1977967a4a12007-08-20 14:23:44 +0000144 WriteBuffer *pWriteListEnd; /* End of write-list */
drh9c06c952005-11-26 00:25:00 +0000145
danielk197762079062007-08-15 17:08:46 +0000146 int iSectorSize; /* Value of simulated sector size */
147 int iDeviceCharacteristics; /* Value of simulated device characteristics */
drh9c06c952005-11-26 00:25:00 +0000148
danielk197762079062007-08-15 17:08:46 +0000149 int iCrash; /* Crash on the iCrash'th call to xSync() */
150 char zCrashFile[500]; /* Crash during an xSync() on this file */
151};
drh9c06c952005-11-26 00:25:00 +0000152
danielk1977967a4a12007-08-20 14:23:44 +0000153static CrashGlobal g = {0, 0, SQLITE_DEFAULT_SECTOR_SIZE, 0, 0};
drh9c06c952005-11-26 00:25:00 +0000154
155/*
drh66560ad2006-01-06 14:32:19 +0000156** Set this global variable to 1 to enable crash testing.
157*/
danielk1977967a4a12007-08-20 14:23:44 +0000158static int sqlite3CrashTestEnable = 0;
drh66560ad2006-01-06 14:32:19 +0000159
danielk1977a98d7b42008-01-18 13:42:54 +0000160static void *crash_malloc(int nByte){
161 return (void *)Tcl_Alloc((size_t)nByte);
162}
163static void crash_free(void *p){
164 Tcl_Free(p);
165}
166static void *crash_realloc(void *p, int n){
167 return (void *)Tcl_Realloc(p, (size_t)n);
168}
169
drh66560ad2006-01-06 14:32:19 +0000170/*
danielk197762079062007-08-15 17:08:46 +0000171** Flush the write-list as if xSync() had been called on file handle
172** pFile. If isCrash is true, simulate a crash.
drh9c06c952005-11-26 00:25:00 +0000173*/
danielk197762079062007-08-15 17:08:46 +0000174static int writeListSync(CrashFile *pFile, int isCrash){
175 int rc = SQLITE_OK;
176 int iDc = g.iDeviceCharacteristics;
drh66560ad2006-01-06 14:32:19 +0000177
danielk197762079062007-08-15 17:08:46 +0000178 WriteBuffer *pWrite;
179 WriteBuffer **ppPtr;
drh66560ad2006-01-06 14:32:19 +0000180
danielk1977f55b8992007-08-24 08:15:53 +0000181 /* If this is not a crash simulation, set pFinal to point to the
182 ** last element of the write-list that is associated with file handle
183 ** pFile.
184 **
185 ** If this is a crash simulation, set pFinal to an arbitrarily selected
186 ** element of the write-list.
danielk197762079062007-08-15 17:08:46 +0000187 */
188 WriteBuffer *pFinal = 0;
189 if( !isCrash ){
190 for(pWrite=g.pWriteList; pWrite; pWrite=pWrite->pNext){
191 if( pWrite->pFile==pFile ){
192 pFinal = pWrite;
193 }
194 }
danielk1977f55b8992007-08-24 08:15:53 +0000195 }else if( iDc&(SQLITE_IOCAP_SEQUENTIAL|SQLITE_IOCAP_SAFE_APPEND) ){
196 int nWrite = 0;
197 int iFinal;
198 for(pWrite=g.pWriteList; pWrite; pWrite=pWrite->pNext) nWrite++;
drh2fa18682008-03-19 14:15:34 +0000199 sqlite3_randomness(sizeof(int), &iFinal);
danielk1977f55b8992007-08-24 08:15:53 +0000200 iFinal = ((iFinal<0)?-1*iFinal:iFinal)%nWrite;
201 for(pWrite=g.pWriteList; iFinal>0; pWrite=pWrite->pNext) iFinal--;
202 pFinal = pWrite;
drh1a235932005-11-29 18:37:15 +0000203 }
drh66560ad2006-01-06 14:32:19 +0000204
danielk1977f8940ae2007-08-23 11:07:10 +0000205#ifdef TRACE_CRASHTEST
206 printf("Sync %s (is %s crash)\n", pFile->zName, (isCrash?"a":"not a"));
207#endif
208
danielk197762079062007-08-15 17:08:46 +0000209 ppPtr = &g.pWriteList;
210 for(pWrite=*ppPtr; rc==SQLITE_OK && pWrite; pWrite=*ppPtr){
danielk1977967a4a12007-08-20 14:23:44 +0000211 sqlite3_file *pRealFile = pWrite->pFile->pRealFile;
danielk197762079062007-08-15 17:08:46 +0000212
213 /* (eAction==1) -> write block out normally,
214 ** (eAction==2) -> do nothing,
215 ** (eAction==3) -> trash sectors.
216 */
217 int eAction = 0;
218 if( !isCrash ){
219 eAction = 2;
220 if( (pWrite->pFile==pFile || iDc&SQLITE_IOCAP_SEQUENTIAL) ){
221 eAction = 1;
222 }
223 }else{
224 char random;
drh2fa18682008-03-19 14:15:34 +0000225 sqlite3_randomness(1, &random);
danielk197762079062007-08-15 17:08:46 +0000226
danielk1977f55b8992007-08-24 08:15:53 +0000227 /* Do not select option 3 (sector trashing) if the IOCAP_ATOMIC flag
228 ** is set or this is an OsTruncate(), not an Oswrite().
229 */
230 if( (iDc&SQLITE_IOCAP_ATOMIC) || (pWrite->zBuf==0) ){
danielk197762079062007-08-15 17:08:46 +0000231 random &= 0x01;
232 }
233
danielk1977f55b8992007-08-24 08:15:53 +0000234 /* If IOCAP_SEQUENTIAL is set and this is not the final entry
235 ** in the truncated write-list, always select option 1 (write
236 ** out correctly).
237 */
238 if( (iDc&SQLITE_IOCAP_SEQUENTIAL && pWrite!=pFinal) ){
239 random = 0;
240 }
241
242 /* If IOCAP_SAFE_APPEND is set and this OsWrite() operation is
243 ** an append (first byte of the written region is 1 byte past the
244 ** current EOF), always select option 1 (write out correctly).
245 */
246 if( iDc&SQLITE_IOCAP_SAFE_APPEND && pWrite->zBuf ){
247 i64 iSize;
248 sqlite3OsFileSize(pRealFile, &iSize);
249 if( iSize==pWrite->iOffset ){
250 random = 0;
251 }
252 }
253
danielk197762079062007-08-15 17:08:46 +0000254 if( (random&0x06)==0x06 ){
255 eAction = 3;
256 }else{
257 eAction = ((random&0x01)?2:1);
258 }
259 }
260
261 switch( eAction ){
262 case 1: { /* Write out correctly */
263 if( pWrite->zBuf ){
264 rc = sqlite3OsWrite(
danielk1977967a4a12007-08-20 14:23:44 +0000265 pRealFile, pWrite->zBuf, pWrite->nBuf, pWrite->iOffset
danielk197762079062007-08-15 17:08:46 +0000266 );
267 }else{
danielk1977967a4a12007-08-20 14:23:44 +0000268 rc = sqlite3OsTruncate(pRealFile, pWrite->iOffset);
danielk197762079062007-08-15 17:08:46 +0000269 }
270 *ppPtr = pWrite->pNext;
danielk1977f8940ae2007-08-23 11:07:10 +0000271#ifdef TRACE_CRASHTEST
272 if( isCrash ){
danielk1977f55b8992007-08-24 08:15:53 +0000273 printf("Writing %d bytes @ %d (%s)\n",
274 pWrite->nBuf, (int)pWrite->iOffset, pWrite->pFile->zName
275 );
danielk1977f8940ae2007-08-23 11:07:10 +0000276 }
277#endif
danielk1977a98d7b42008-01-18 13:42:54 +0000278 crash_free(pWrite);
danielk197762079062007-08-15 17:08:46 +0000279 break;
280 }
281 case 2: { /* Do nothing */
282 ppPtr = &pWrite->pNext;
danielk1977f8940ae2007-08-23 11:07:10 +0000283#ifdef TRACE_CRASHTEST
284 if( isCrash ){
danielk1977f55b8992007-08-24 08:15:53 +0000285 printf("Omiting %d bytes @ %d (%s)\n",
286 pWrite->nBuf, (int)pWrite->iOffset, pWrite->pFile->zName
287 );
danielk1977f8940ae2007-08-23 11:07:10 +0000288 }
289#endif
danielk197762079062007-08-15 17:08:46 +0000290 break;
291 }
292 case 3: { /* Trash sectors */
293 u8 *zGarbage;
danielk1977967a4a12007-08-20 14:23:44 +0000294 int iFirst = (pWrite->iOffset/g.iSectorSize);
295 int iLast = (pWrite->iOffset+pWrite->nBuf-1)/g.iSectorSize;
296
297 assert(pWrite->zBuf);
danielk197762079062007-08-15 17:08:46 +0000298
danielk1977f8940ae2007-08-23 11:07:10 +0000299#ifdef TRACE_CRASHTEST
danielk1977f55b8992007-08-24 08:15:53 +0000300 printf("Trashing %d sectors @ sector %d (%s)\n",
301 1+iLast-iFirst, iFirst, pWrite->pFile->zName
302 );
danielk1977f8940ae2007-08-23 11:07:10 +0000303#endif
304
danielk1977a98d7b42008-01-18 13:42:54 +0000305 zGarbage = crash_malloc(g.iSectorSize);
danielk197762079062007-08-15 17:08:46 +0000306 if( zGarbage ){
307 sqlite3_int64 i;
308 for(i=iFirst; rc==SQLITE_OK && i<=iLast; i++){
drh2fa18682008-03-19 14:15:34 +0000309 sqlite3_randomness(g.iSectorSize, zGarbage);
danielk197762079062007-08-15 17:08:46 +0000310 rc = sqlite3OsWrite(
danielk1977967a4a12007-08-20 14:23:44 +0000311 pRealFile, zGarbage, g.iSectorSize, i*g.iSectorSize
danielk197762079062007-08-15 17:08:46 +0000312 );
313 }
danielk1977a98d7b42008-01-18 13:42:54 +0000314 crash_free(zGarbage);
danielk197762079062007-08-15 17:08:46 +0000315 }else{
316 rc = SQLITE_NOMEM;
317 }
318
319 ppPtr = &pWrite->pNext;
320 break;
321 }
322
323 default:
324 assert(!"Cannot happen");
325 }
326
327 if( pWrite==pFinal ) break;
drh1a235932005-11-29 18:37:15 +0000328 }
danielk197762079062007-08-15 17:08:46 +0000329
330 if( rc==SQLITE_OK && isCrash ){
331 exit(-1);
332 }
333
danielk1977967a4a12007-08-20 14:23:44 +0000334 for(pWrite=g.pWriteList; pWrite && pWrite->pNext; pWrite=pWrite->pNext);
335 g.pWriteListEnd = pWrite;
336
drh1a235932005-11-29 18:37:15 +0000337 return rc;
drh9c06c952005-11-26 00:25:00 +0000338}
339
340/*
danielk197762079062007-08-15 17:08:46 +0000341** Add an entry to the end of the write-list.
drh18839212005-11-26 03:43:23 +0000342*/
danielk197762079062007-08-15 17:08:46 +0000343static int writeListAppend(
344 sqlite3_file *pFile,
345 sqlite3_int64 iOffset,
346 const u8 *zBuf,
347 int nBuf
348){
349 WriteBuffer *pNew;
350
351 assert((zBuf && nBuf) || (!nBuf && !zBuf));
352
danielk1977a98d7b42008-01-18 13:42:54 +0000353 pNew = (WriteBuffer *)crash_malloc(sizeof(WriteBuffer) + nBuf);
drha018dc72007-12-14 17:22:23 +0000354 if( pNew==0 ){
355 fprintf(stderr, "out of memory in the crash simulator\n");
356 }
danielk1977a98d7b42008-01-18 13:42:54 +0000357 memset(pNew, 0, sizeof(WriteBuffer)+nBuf);
danielk197762079062007-08-15 17:08:46 +0000358 pNew->iOffset = iOffset;
359 pNew->nBuf = nBuf;
360 pNew->pFile = (CrashFile *)pFile;
361 if( zBuf ){
362 pNew->zBuf = (u8 *)&pNew[1];
363 memcpy(pNew->zBuf, zBuf, nBuf);
364 }
365
366 if( g.pWriteList ){
danielk1977967a4a12007-08-20 14:23:44 +0000367 assert(g.pWriteListEnd);
368 g.pWriteListEnd->pNext = pNew;
danielk197762079062007-08-15 17:08:46 +0000369 }else{
370 g.pWriteList = pNew;
371 }
danielk1977967a4a12007-08-20 14:23:44 +0000372 g.pWriteListEnd = pNew;
danielk197762079062007-08-15 17:08:46 +0000373
drh1a235932005-11-29 18:37:15 +0000374 return SQLITE_OK;
375}
376
377/*
danielk197762079062007-08-15 17:08:46 +0000378** Close a crash-file.
drh1a235932005-11-29 18:37:15 +0000379*/
danielk19771e536952007-08-16 10:09:01 +0000380static int cfClose(sqlite3_file *pFile){
danielk197762079062007-08-15 17:08:46 +0000381 CrashFile *pCrash = (CrashFile *)pFile;
382 writeListSync(pCrash, 0);
danielk1977f1da17a2007-08-21 13:07:46 +0000383 sqlite3OsClose(pCrash->pRealFile);
danielk197762079062007-08-15 17:08:46 +0000384 return SQLITE_OK;
drh1a235932005-11-29 18:37:15 +0000385}
386
387/*
danielk197762079062007-08-15 17:08:46 +0000388** Read data from a crash-file.
drh1a235932005-11-29 18:37:15 +0000389*/
danielk19771e536952007-08-16 10:09:01 +0000390static int cfRead(
391 sqlite3_file *pFile,
392 void *zBuf,
393 int iAmt,
394 sqlite_int64 iOfst
395){
danielk197762079062007-08-15 17:08:46 +0000396 CrashFile *pCrash = (CrashFile *)pFile;
danielk197762079062007-08-15 17:08:46 +0000397
398 /* Check the file-size to see if this is a short-read */
danielk1977967a4a12007-08-20 14:23:44 +0000399 if( pCrash->iSize<(iOfst+iAmt) ){
danielk197762079062007-08-15 17:08:46 +0000400 return SQLITE_IOERR_SHORT_READ;
401 }
402
danielk1977967a4a12007-08-20 14:23:44 +0000403 memcpy(zBuf, &pCrash->zData[iOfst], iAmt);
404 return SQLITE_OK;
drh18839212005-11-26 03:43:23 +0000405}
406
407/*
danielk197762079062007-08-15 17:08:46 +0000408** Write data to a crash-file.
danielk1977b4721172007-03-19 05:54:48 +0000409*/
danielk19771e536952007-08-16 10:09:01 +0000410static int cfWrite(
411 sqlite3_file *pFile,
412 const void *zBuf,
413 int iAmt,
414 sqlite_int64 iOfst
415){
danielk1977967a4a12007-08-20 14:23:44 +0000416 CrashFile *pCrash = (CrashFile *)pFile;
417 if( iAmt+iOfst>pCrash->iSize ){
418 pCrash->iSize = iAmt+iOfst;
419 }
420 while( pCrash->iSize>pCrash->nData ){
drh4a50aac2007-08-23 02:47:53 +0000421 u8 *zNew;
danielk1977967a4a12007-08-20 14:23:44 +0000422 int nNew = (pCrash->nData*2) + 4096;
danielk1977a98d7b42008-01-18 13:42:54 +0000423 zNew = crash_realloc(pCrash->zData, nNew);
danielk1977967a4a12007-08-20 14:23:44 +0000424 if( !zNew ){
425 return SQLITE_NOMEM;
426 }
427 memset(&zNew[pCrash->nData], 0, nNew-pCrash->nData);
428 pCrash->nData = nNew;
429 pCrash->zData = zNew;
430 }
431 memcpy(&pCrash->zData[iOfst], zBuf, iAmt);
danielk197762079062007-08-15 17:08:46 +0000432 return writeListAppend(pFile, iOfst, zBuf, iAmt);
danielk1977b4721172007-03-19 05:54:48 +0000433}
434
435/*
danielk197762079062007-08-15 17:08:46 +0000436** Truncate a crash-file.
drh054889e2005-11-30 03:20:31 +0000437*/
danielk19771e536952007-08-16 10:09:01 +0000438static int cfTruncate(sqlite3_file *pFile, sqlite_int64 size){
danielk1977967a4a12007-08-20 14:23:44 +0000439 CrashFile *pCrash = (CrashFile *)pFile;
440 assert(size>=0);
441 if( pCrash->iSize>size ){
442 pCrash->iSize = size;
443 }
danielk197762079062007-08-15 17:08:46 +0000444 return writeListAppend(pFile, size, 0, 0);
445}
446
447/*
448** Sync a crash-file.
449*/
danielk19771e536952007-08-16 10:09:01 +0000450static int cfSync(sqlite3_file *pFile, int flags){
danielk197762079062007-08-15 17:08:46 +0000451 CrashFile *pCrash = (CrashFile *)pFile;
452 int isCrash = 0;
453
danielk1977967a4a12007-08-20 14:23:44 +0000454 const char *zName = pCrash->zName;
455 const char *zCrashFile = g.zCrashFile;
456 int nName = strlen(zName);
457 int nCrashFile = strlen(zCrashFile);
458
459 if( nCrashFile>0 && zCrashFile[nCrashFile-1]=='*' ){
460 nCrashFile--;
461 if( nName>nCrashFile ) nName = nCrashFile;
462 }
463
464 if( nName==nCrashFile && 0==memcmp(zName, zCrashFile, nName) ){
465 if( (--g.iCrash)==0 ) isCrash = 1;
danielk197762079062007-08-15 17:08:46 +0000466 }
467
468 return writeListSync(pCrash, isCrash);
469}
470
471/*
472** Return the current file-size of the crash-file.
473*/
danielk19771e536952007-08-16 10:09:01 +0000474static int cfFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
danielk197762079062007-08-15 17:08:46 +0000475 CrashFile *pCrash = (CrashFile *)pFile;
danielk1977967a4a12007-08-20 14:23:44 +0000476 *pSize = (i64)pCrash->iSize;
danielk197762079062007-08-15 17:08:46 +0000477 return SQLITE_OK;
478}
479
480/*
481** Calls related to file-locks are passed on to the real file handle.
482*/
danielk19771e536952007-08-16 10:09:01 +0000483static int cfLock(sqlite3_file *pFile, int eLock){
danielk197762079062007-08-15 17:08:46 +0000484 return sqlite3OsLock(((CrashFile *)pFile)->pRealFile, eLock);
485}
danielk19771e536952007-08-16 10:09:01 +0000486static int cfUnlock(sqlite3_file *pFile, int eLock){
danielk197762079062007-08-15 17:08:46 +0000487 return sqlite3OsUnlock(((CrashFile *)pFile)->pRealFile, eLock);
488}
danielk1977861f7452008-06-05 11:39:11 +0000489static int cfCheckReservedLock(sqlite3_file *pFile, int *pResOut){
490 return sqlite3OsCheckReservedLock(((CrashFile *)pFile)->pRealFile, pResOut);
danielk197762079062007-08-15 17:08:46 +0000491}
drhcc6bb3e2007-08-31 16:11:35 +0000492static int cfFileControl(sqlite3_file *pFile, int op, void *pArg){
493 return sqlite3OsFileControl(((CrashFile *)pFile)->pRealFile, op, pArg);
danielk197762079062007-08-15 17:08:46 +0000494}
495
496/*
497** The xSectorSize() and xDeviceCharacteristics() functions return
498** the global values configured by the [sqlite_crashparams] tcl
499* interface.
500*/
danielk19771e536952007-08-16 10:09:01 +0000501static int cfSectorSize(sqlite3_file *pFile){
danielk197762079062007-08-15 17:08:46 +0000502 return g.iSectorSize;
503}
danielk19771e536952007-08-16 10:09:01 +0000504static int cfDeviceCharacteristics(sqlite3_file *pFile){
danielk197762079062007-08-15 17:08:46 +0000505 return g.iDeviceCharacteristics;
506}
507
508static const sqlite3_io_methods CrashFileVtab = {
509 1, /* iVersion */
510 cfClose, /* xClose */
511 cfRead, /* xRead */
512 cfWrite, /* xWrite */
513 cfTruncate, /* xTruncate */
514 cfSync, /* xSync */
515 cfFileSize, /* xFileSize */
516 cfLock, /* xLock */
517 cfUnlock, /* xUnlock */
518 cfCheckReservedLock, /* xCheckReservedLock */
drhcc6bb3e2007-08-31 16:11:35 +0000519 cfFileControl, /* xFileControl */
danielk197762079062007-08-15 17:08:46 +0000520 cfSectorSize, /* xSectorSize */
521 cfDeviceCharacteristics /* xDeviceCharacteristics */
drh054889e2005-11-30 03:20:31 +0000522};
523
drh054889e2005-11-30 03:20:31 +0000524/*
drhd677b3d2007-08-20 22:48:41 +0000525** Application data for the crash VFS
526*/
527struct crashAppData {
danielk1977f1da17a2007-08-21 13:07:46 +0000528 sqlite3_vfs *pOrig; /* Wrapped vfs structure */
drhd677b3d2007-08-20 22:48:41 +0000529};
530
531/*
danielk19770e87b702007-08-25 12:29:30 +0000532** Open a crash-file file handle.
danielk1977967a4a12007-08-20 14:23:44 +0000533**
534** The caller will have allocated pVfs->szOsFile bytes of space
535** at pFile. This file uses this space for the CrashFile structure
536** and allocates space for the "real" file structure using
537** sqlite3_malloc(). The assumption here is (pVfs->szOsFile) is
538** equal or greater than sizeof(CrashFile).
drh054889e2005-11-30 03:20:31 +0000539*/
danielk1977f1da17a2007-08-21 13:07:46 +0000540static int cfOpen(
danielk1977f55b8992007-08-24 08:15:53 +0000541 sqlite3_vfs *pCfVfs,
danielk197762079062007-08-15 17:08:46 +0000542 const char *zName,
543 sqlite3_file *pFile,
544 int flags,
545 int *pOutFlags
546){
danielk1977f55b8992007-08-24 08:15:53 +0000547 sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
danielk1977967a4a12007-08-20 14:23:44 +0000548 int rc;
danielk1977f1da17a2007-08-21 13:07:46 +0000549 CrashFile *pWrapper = (CrashFile *)pFile;
drh4a50aac2007-08-23 02:47:53 +0000550 sqlite3_file *pReal = (sqlite3_file*)&pWrapper[1];
danielk1977f1da17a2007-08-21 13:07:46 +0000551
552 memset(pWrapper, 0, sizeof(CrashFile));
553 rc = sqlite3OsOpen(pVfs, zName, pReal, flags, pOutFlags);
554
555 if( rc==SQLITE_OK ){
556 i64 iSize;
557 pWrapper->pMethod = &CrashFileVtab;
558 pWrapper->zName = (char *)zName;
559 pWrapper->pRealFile = pReal;
560 rc = sqlite3OsFileSize(pReal, &iSize);
561 pWrapper->iSize = (int)iSize;
562 }
563 if( rc==SQLITE_OK ){
564 pWrapper->nData = (4096 + pWrapper->iSize);
danielk1977a98d7b42008-01-18 13:42:54 +0000565 pWrapper->zData = crash_malloc(pWrapper->nData);
danielk1977f1da17a2007-08-21 13:07:46 +0000566 if( pWrapper->zData ){
567 memset(pWrapper->zData, 0, pWrapper->nData);
568 rc = sqlite3OsRead(pReal, pWrapper->zData, pWrapper->iSize, 0);
569 }else{
570 rc = SQLITE_NOMEM;
danielk197762079062007-08-15 17:08:46 +0000571 }
danielk1977f1da17a2007-08-21 13:07:46 +0000572 }
573 if( rc!=SQLITE_OK && pWrapper->pMethod ){
574 sqlite3OsClose(pFile);
danielk197762079062007-08-15 17:08:46 +0000575 }
576 return rc;
577}
578
danielk1977f55b8992007-08-24 08:15:53 +0000579static int cfDelete(sqlite3_vfs *pCfVfs, const char *zPath, int dirSync){
580 sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
581 return pVfs->xDelete(pVfs, zPath, dirSync);
danielk1977f1da17a2007-08-21 13:07:46 +0000582}
danielk1977861f7452008-06-05 11:39:11 +0000583static int cfAccess(
584 sqlite3_vfs *pCfVfs,
585 const char *zPath,
586 int flags,
587 int *pResOut
588){
danielk1977f55b8992007-08-24 08:15:53 +0000589 sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
danielk1977861f7452008-06-05 11:39:11 +0000590 return pVfs->xAccess(pVfs, zPath, flags, pResOut);
danielk1977f1da17a2007-08-21 13:07:46 +0000591}
danielk1977adfb9b02007-09-17 07:02:56 +0000592static int cfFullPathname(
593 sqlite3_vfs *pCfVfs,
594 const char *zPath,
595 int nPathOut,
596 char *zPathOut
597){
danielk1977f55b8992007-08-24 08:15:53 +0000598 sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
danielk1977adfb9b02007-09-17 07:02:56 +0000599 return pVfs->xFullPathname(pVfs, zPath, nPathOut, zPathOut);
danielk1977f1da17a2007-08-21 13:07:46 +0000600}
danielk1977f55b8992007-08-24 08:15:53 +0000601static void *cfDlOpen(sqlite3_vfs *pCfVfs, const char *zPath){
602 sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
603 return pVfs->xDlOpen(pVfs, zPath);
danielk1977f1da17a2007-08-21 13:07:46 +0000604}
danielk19770e87b702007-08-25 12:29:30 +0000605static void cfDlError(sqlite3_vfs *pCfVfs, int nByte, char *zErrMsg){
606 sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
607 pVfs->xDlError(pVfs, nByte, zErrMsg);
608}
609static void *cfDlSym(sqlite3_vfs *pCfVfs, void *pHandle, const char *zSymbol){
610 sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
611 return pVfs->xDlSym(pVfs, pHandle, zSymbol);
612}
613static void cfDlClose(sqlite3_vfs *pCfVfs, void *pHandle){
614 sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
615 pVfs->xDlClose(pVfs, pHandle);
616}
danielk1977f55b8992007-08-24 08:15:53 +0000617static int cfRandomness(sqlite3_vfs *pCfVfs, int nByte, char *zBufOut){
618 sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
619 return pVfs->xRandomness(pVfs, nByte, zBufOut);
danielk1977f1da17a2007-08-21 13:07:46 +0000620}
danielk1977f55b8992007-08-24 08:15:53 +0000621static int cfSleep(sqlite3_vfs *pCfVfs, int nMicro){
622 sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
623 return pVfs->xSleep(pVfs, nMicro);
danielk1977f1da17a2007-08-21 13:07:46 +0000624}
danielk1977f55b8992007-08-24 08:15:53 +0000625static int cfCurrentTime(sqlite3_vfs *pCfVfs, double *pTimeOut){
626 sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
627 return pVfs->xCurrentTime(pVfs, pTimeOut);
danielk1977f1da17a2007-08-21 13:07:46 +0000628}
629
danielk19772ca0f862007-08-23 08:06:44 +0000630static int processDevSymArgs(
631 Tcl_Interp *interp,
632 int objc,
633 Tcl_Obj *CONST objv[],
634 int *piDeviceChar,
635 int *piSectorSize
636){
637 struct DeviceFlag {
638 char *zName;
639 int iValue;
640 } aFlag[] = {
641 { "atomic", SQLITE_IOCAP_ATOMIC },
642 { "atomic512", SQLITE_IOCAP_ATOMIC512 },
643 { "atomic1k", SQLITE_IOCAP_ATOMIC1K },
644 { "atomic2k", SQLITE_IOCAP_ATOMIC2K },
645 { "atomic4k", SQLITE_IOCAP_ATOMIC4K },
646 { "atomic8k", SQLITE_IOCAP_ATOMIC8K },
647 { "atomic16k", SQLITE_IOCAP_ATOMIC16K },
648 { "atomic32k", SQLITE_IOCAP_ATOMIC32K },
649 { "atomic64k", SQLITE_IOCAP_ATOMIC64K },
650 { "sequential", SQLITE_IOCAP_SEQUENTIAL },
651 { "safe_append", SQLITE_IOCAP_SAFE_APPEND },
652 { 0, 0 }
653 };
654
655 int i;
656 int iDc = 0;
657 int iSectorSize = 0;
658 int setSectorsize = 0;
659 int setDeviceChar = 0;
660
661 for(i=0; i<objc; i+=2){
662 int nOpt;
663 char *zOpt = Tcl_GetStringFromObj(objv[i], &nOpt);
664
665 if( (nOpt>11 || nOpt<2 || strncmp("-sectorsize", zOpt, nOpt))
666 && (nOpt>16 || nOpt<2 || strncmp("-characteristics", zOpt, nOpt))
667 ){
668 Tcl_AppendResult(interp,
669 "Bad option: \"", zOpt,
670 "\" - must be \"-characteristics\" or \"-sectorsize\"", 0
671 );
672 return TCL_ERROR;
673 }
674 if( i==objc-1 ){
675 Tcl_AppendResult(interp, "Option requires an argument: \"", zOpt, "\"",0);
676 return TCL_ERROR;
677 }
678
679 if( zOpt[1]=='s' ){
680 if( Tcl_GetIntFromObj(interp, objv[i+1], &iSectorSize) ){
681 return TCL_ERROR;
682 }
683 setSectorsize = 1;
684 }else{
685 int j;
686 Tcl_Obj **apObj;
687 int nObj;
688 if( Tcl_ListObjGetElements(interp, objv[i+1], &nObj, &apObj) ){
689 return TCL_ERROR;
690 }
691 for(j=0; j<nObj; j++){
692 int rc;
693 int iChoice;
694 Tcl_Obj *pFlag = Tcl_DuplicateObj(apObj[j]);
695 Tcl_IncrRefCount(pFlag);
696 Tcl_UtfToLower(Tcl_GetString(pFlag));
697
698 rc = Tcl_GetIndexFromObjStruct(
699 interp, pFlag, aFlag, sizeof(aFlag[0]), "no such flag", 0, &iChoice
700 );
701 Tcl_DecrRefCount(pFlag);
702 if( rc ){
703 return TCL_ERROR;
704 }
705
706 iDc |= aFlag[iChoice].iValue;
707 }
708 setDeviceChar = 1;
709 }
710 }
711
712 if( setDeviceChar ){
713 *piDeviceChar = iDc;
714 }
715 if( setSectorsize ){
716 *piSectorSize = iSectorSize;
717 }
718
719 return TCL_OK;
720}
721
drh054889e2005-11-30 03:20:31 +0000722/*
danielk1977ca0c8972007-09-01 09:02:53 +0000723** tclcmd: sqlite_crash_enable ENABLE
724**
725** Parameter ENABLE must be a boolean value. If true, then the "crash"
726** vfs is added to the system. If false, it is removed.
727*/
728static int crashEnableCmd(
729 void * clientData,
730 Tcl_Interp *interp,
731 int objc,
732 Tcl_Obj *CONST objv[]
733){
734 int isEnable;
735 static sqlite3_vfs crashVfs = {
736 1, /* iVersion */
737 0, /* szOsFile */
738 0, /* mxPathname */
739 0, /* pNext */
740 "crash", /* zName */
741 0, /* pAppData */
742
743 cfOpen, /* xOpen */
744 cfDelete, /* xDelete */
745 cfAccess, /* xAccess */
danielk1977ca0c8972007-09-01 09:02:53 +0000746 cfFullPathname, /* xFullPathname */
747 cfDlOpen, /* xDlOpen */
748 cfDlError, /* xDlError */
749 cfDlSym, /* xDlSym */
750 cfDlClose, /* xDlClose */
751 cfRandomness, /* xRandomness */
752 cfSleep, /* xSleep */
753 cfCurrentTime /* xCurrentTime */
754 };
755
756 if( objc!=2 ){
757 Tcl_WrongNumArgs(interp, 1, objv, "ENABLE");
758 return TCL_ERROR;
759 }
760
761 if( Tcl_GetBooleanFromObj(interp, objv[1], &isEnable) ){
762 return TCL_ERROR;
763 }
764
765 if( (isEnable && crashVfs.pAppData) || (!isEnable && !crashVfs.pAppData) ){
766 return TCL_OK;
767 }
768
769 if( crashVfs.pAppData==0 ){
770 sqlite3_vfs *pOriginalVfs = sqlite3_vfs_find(0);
771 crashVfs.mxPathname = pOriginalVfs->mxPathname;
772 crashVfs.pAppData = (void *)pOriginalVfs;
773 crashVfs.szOsFile = sizeof(CrashFile) + pOriginalVfs->szOsFile;
774 sqlite3_vfs_register(&crashVfs, 0);
775 }else{
776 crashVfs.pAppData = 0;
777 sqlite3_vfs_unregister(&crashVfs);
778 }
779
780 return TCL_OK;
781}
782
783/*
danielk197762079062007-08-15 17:08:46 +0000784** tclcmd: sqlite_crashparams ?OPTIONS? DELAY CRASHFILE
drh9c06c952005-11-26 00:25:00 +0000785**
786** This procedure implements a TCL command that enables crash testing
787** in testfixture. Once enabled, crash testing cannot be disabled.
danielk197762079062007-08-15 17:08:46 +0000788**
789** Available options are "-characteristics" and "-sectorsize". Both require
790** an argument. For -sectorsize, this is the simulated sector size in
791** bytes. For -characteristics, the argument must be a list of io-capability
792** flags to simulate. Valid flags are "atomic", "atomic512", "atomic1K",
793** "atomic2K", "atomic4K", "atomic8K", "atomic16K", "atomic32K",
794** "atomic64K", "sequential" and "safe_append".
795**
796** Example:
797**
798** sqlite_crashparams -sect 1024 -char {atomic sequential} ./test.db 1
799**
drh9c06c952005-11-26 00:25:00 +0000800*/
801static int crashParamsObjCmd(
802 void * clientData,
803 Tcl_Interp *interp,
804 int objc,
805 Tcl_Obj *CONST objv[]
806){
danielk197762079062007-08-15 17:08:46 +0000807 int iDelay;
808 const char *zCrashFile;
drh153c62c2007-08-24 03:51:33 +0000809 int nCrashFile, iDc, iSectorSize;
drhd677b3d2007-08-20 22:48:41 +0000810
drh153c62c2007-08-24 03:51:33 +0000811 iDc = -1;
812 iSectorSize = -1;
danielk197762079062007-08-15 17:08:46 +0000813
danielk197762079062007-08-15 17:08:46 +0000814 if( objc<3 ){
815 Tcl_WrongNumArgs(interp, 1, objv, "?OPTIONS? DELAY CRASHFILE");
danielk1977b4b47412007-08-17 15:53:36 +0000816 goto error;
drh9c06c952005-11-26 00:25:00 +0000817 }
danielk197762079062007-08-15 17:08:46 +0000818
danielk1977967a4a12007-08-20 14:23:44 +0000819 zCrashFile = Tcl_GetStringFromObj(objv[objc-1], &nCrashFile);
danielk197762079062007-08-15 17:08:46 +0000820 if( nCrashFile>=sizeof(g.zCrashFile) ){
821 Tcl_AppendResult(interp, "Filename is too long: \"", zCrashFile, "\"", 0);
danielk1977b4b47412007-08-17 15:53:36 +0000822 goto error;
drh9c06c952005-11-26 00:25:00 +0000823 }
danielk197762079062007-08-15 17:08:46 +0000824 if( Tcl_GetIntFromObj(interp, objv[objc-2], &iDelay) ){
danielk1977b4b47412007-08-17 15:53:36 +0000825 goto error;
danielk197762079062007-08-15 17:08:46 +0000826 }
827
danielk19772ca0f862007-08-23 08:06:44 +0000828 if( processDevSymArgs(interp, objc-3, &objv[1], &iDc, &iSectorSize) ){
829 return TCL_ERROR;
danielk197759a33f92007-03-17 10:26:59 +0000830 }
danielk197762079062007-08-15 17:08:46 +0000831
danielk19772ca0f862007-08-23 08:06:44 +0000832 if( iDc>=0 ){
danielk197762079062007-08-15 17:08:46 +0000833 g.iDeviceCharacteristics = iDc;
834 }
danielk19772ca0f862007-08-23 08:06:44 +0000835 if( iSectorSize>=0 ){
danielk197762079062007-08-15 17:08:46 +0000836 g.iSectorSize = iSectorSize;
837 }
danielk19772ca0f862007-08-23 08:06:44 +0000838
danielk197762079062007-08-15 17:08:46 +0000839 g.iCrash = iDelay;
840 memcpy(g.zCrashFile, zCrashFile, nCrashFile+1);
drh66560ad2006-01-06 14:32:19 +0000841 sqlite3CrashTestEnable = 1;
drh9c06c952005-11-26 00:25:00 +0000842 return TCL_OK;
danielk1977b4b47412007-08-17 15:53:36 +0000843
844error:
danielk1977b4b47412007-08-17 15:53:36 +0000845 return TCL_ERROR;
drh9c06c952005-11-26 00:25:00 +0000846}
847
danielk19772ca0f862007-08-23 08:06:44 +0000848static int devSymObjCmd(
849 void * clientData,
850 Tcl_Interp *interp,
851 int objc,
852 Tcl_Obj *CONST objv[]
853){
danielk1977bf260972008-01-22 11:50:13 +0000854 void devsym_register(int iDeviceChar, int iSectorSize);
danielk19772ca0f862007-08-23 08:06:44 +0000855
856 int iDc = -1;
857 int iSectorSize = -1;
danielk1977bf260972008-01-22 11:50:13 +0000858
danielk19772ca0f862007-08-23 08:06:44 +0000859 if( processDevSymArgs(interp, objc-1, &objv[1], &iDc, &iSectorSize) ){
860 return TCL_ERROR;
861 }
danielk1977bf260972008-01-22 11:50:13 +0000862 devsym_register(iDc, iSectorSize);
danielk19772ca0f862007-08-23 08:06:44 +0000863
864 return TCL_OK;
865}
866
drh198bf392006-01-06 21:52:49 +0000867#endif /* SQLITE_OMIT_DISKIO */
868
drh9c06c952005-11-26 00:25:00 +0000869/*
870** This procedure registers the TCL procedures defined in this file.
871*/
872int Sqlitetest6_Init(Tcl_Interp *interp){
drh198bf392006-01-06 21:52:49 +0000873#ifndef SQLITE_OMIT_DISKIO
danielk1977ca0c8972007-09-01 09:02:53 +0000874 Tcl_CreateObjCommand(interp, "sqlite3_crash_enable", crashEnableCmd, 0, 0);
drh9c06c952005-11-26 00:25:00 +0000875 Tcl_CreateObjCommand(interp, "sqlite3_crashparams", crashParamsObjCmd, 0, 0);
danielk19772ca0f862007-08-23 08:06:44 +0000876 Tcl_CreateObjCommand(interp, "sqlite3_simulate_device", devSymObjCmd, 0, 0);
drh198bf392006-01-06 21:52:49 +0000877#endif
drh9c06c952005-11-26 00:25:00 +0000878 return TCL_OK;
879}
880
881#endif /* SQLITE_TEST */