Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(7)

Side by Side Diff: third_party/sqlite/src/test6.c

Issue 3108030: Move bundled copy of sqlite one level deeper to better separate it... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 10 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/sqlite/src/test5.c ('k') | third_party/sqlite/src/test7.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 ** $Id: test6.c,v 1.43 2009/02/11 14:27:04 danielk1977 Exp $
18 */
19 #if SQLITE_TEST /* This file is used for testing only */
20 #include "sqliteInt.h"
21 #include "tcl.h"
22
23 #ifndef SQLITE_OMIT_DISKIO /* This file is a no-op if disk I/O is disabled */
24
25 /* #define TRACE_CRASHTEST */
26
27 typedef struct CrashFile CrashFile;
28 typedef struct CrashGlobal CrashGlobal;
29 typedef 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 */
110
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 */
119 struct WriteBuffer {
120 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 */
126 };
127
128 struct CrashFile {
129 const sqlite3_io_methods *pMethod; /* Must be first */
130 sqlite3_file *pRealFile; /* Underlying "real" file handle */
131 char *zName;
132 int flags; /* Flags the file was opened with */
133
134 /* Cache of the entire file. This is used to speed up OsRead() and
135 ** OsFileSize() calls. Although both could be done by traversing the
136 ** write-list, in practice this is impractically slow.
137 */
138 int iSize; /* Size of file in bytes */
139 int nData; /* Size of buffer allocated at zData */
140 u8 *zData; /* Buffer containing file contents */
141 };
142
143 struct CrashGlobal {
144 WriteBuffer *pWriteList; /* Head of write-list */
145 WriteBuffer *pWriteListEnd; /* End of write-list */
146
147 int iSectorSize; /* Value of simulated sector size */
148 int iDeviceCharacteristics; /* Value of simulated device characteristics */
149
150 int iCrash; /* Crash on the iCrash'th call to xSync() */
151 char zCrashFile[500]; /* Crash during an xSync() on this file */
152 };
153
154 static CrashGlobal g = {0, 0, SQLITE_DEFAULT_SECTOR_SIZE, 0, 0};
155
156 /*
157 ** Set this global variable to 1 to enable crash testing.
158 */
159 static int sqlite3CrashTestEnable = 0;
160
161 static void *crash_malloc(int nByte){
162 return (void *)Tcl_Alloc((size_t)nByte);
163 }
164 static void crash_free(void *p){
165 Tcl_Free(p);
166 }
167 static void *crash_realloc(void *p, int n){
168 return (void *)Tcl_Realloc(p, (size_t)n);
169 }
170
171 /*
172 ** Wrapper around the sqlite3OsWrite() function that avoids writing to the
173 ** 512 byte block begining at offset PENDING_BYTE.
174 */
175 static int writeDbFile(CrashFile *p, u8 *z, i64 iAmt, i64 iOff){
176 int rc;
177 int iSkip = 0;
178 if( iOff==PENDING_BYTE && (p->flags&SQLITE_OPEN_MAIN_DB) ){
179 iSkip = 512;
180 }
181 if( (iAmt-iSkip)>0 ){
182 rc = sqlite3OsWrite(p->pRealFile, &z[iSkip], iAmt-iSkip, iOff+iSkip);
183 }
184 return rc;
185 }
186
187 /*
188 ** Flush the write-list as if xSync() had been called on file handle
189 ** pFile. If isCrash is true, simulate a crash.
190 */
191 static int writeListSync(CrashFile *pFile, int isCrash){
192 int rc = SQLITE_OK;
193 int iDc = g.iDeviceCharacteristics;
194
195 WriteBuffer *pWrite;
196 WriteBuffer **ppPtr;
197
198 /* If this is not a crash simulation, set pFinal to point to the
199 ** last element of the write-list that is associated with file handle
200 ** pFile.
201 **
202 ** If this is a crash simulation, set pFinal to an arbitrarily selected
203 ** element of the write-list.
204 */
205 WriteBuffer *pFinal = 0;
206 if( !isCrash ){
207 for(pWrite=g.pWriteList; pWrite; pWrite=pWrite->pNext){
208 if( pWrite->pFile==pFile ){
209 pFinal = pWrite;
210 }
211 }
212 }else if( iDc&(SQLITE_IOCAP_SEQUENTIAL|SQLITE_IOCAP_SAFE_APPEND) ){
213 int nWrite = 0;
214 int iFinal;
215 for(pWrite=g.pWriteList; pWrite; pWrite=pWrite->pNext) nWrite++;
216 sqlite3_randomness(sizeof(int), &iFinal);
217 iFinal = ((iFinal<0)?-1*iFinal:iFinal)%nWrite;
218 for(pWrite=g.pWriteList; iFinal>0; pWrite=pWrite->pNext) iFinal--;
219 pFinal = pWrite;
220 }
221
222 #ifdef TRACE_CRASHTEST
223 printf("Sync %s (is %s crash)\n", pFile->zName, (isCrash?"a":"not a"));
224 #endif
225
226 ppPtr = &g.pWriteList;
227 for(pWrite=*ppPtr; rc==SQLITE_OK && pWrite; pWrite=*ppPtr){
228 sqlite3_file *pRealFile = pWrite->pFile->pRealFile;
229
230 /* (eAction==1) -> write block out normally,
231 ** (eAction==2) -> do nothing,
232 ** (eAction==3) -> trash sectors.
233 */
234 int eAction = 0;
235 if( !isCrash ){
236 eAction = 2;
237 if( (pWrite->pFile==pFile || iDc&SQLITE_IOCAP_SEQUENTIAL) ){
238 eAction = 1;
239 }
240 }else{
241 char random;
242 sqlite3_randomness(1, &random);
243
244 /* Do not select option 3 (sector trashing) if the IOCAP_ATOMIC flag
245 ** is set or this is an OsTruncate(), not an Oswrite().
246 */
247 if( (iDc&SQLITE_IOCAP_ATOMIC) || (pWrite->zBuf==0) ){
248 random &= 0x01;
249 }
250
251 /* If IOCAP_SEQUENTIAL is set and this is not the final entry
252 ** in the truncated write-list, always select option 1 (write
253 ** out correctly).
254 */
255 if( (iDc&SQLITE_IOCAP_SEQUENTIAL && pWrite!=pFinal) ){
256 random = 0;
257 }
258
259 /* If IOCAP_SAFE_APPEND is set and this OsWrite() operation is
260 ** an append (first byte of the written region is 1 byte past the
261 ** current EOF), always select option 1 (write out correctly).
262 */
263 if( iDc&SQLITE_IOCAP_SAFE_APPEND && pWrite->zBuf ){
264 i64 iSize;
265 sqlite3OsFileSize(pRealFile, &iSize);
266 if( iSize==pWrite->iOffset ){
267 random = 0;
268 }
269 }
270
271 if( (random&0x06)==0x06 ){
272 eAction = 3;
273 }else{
274 eAction = ((random&0x01)?2:1);
275 }
276 }
277
278 switch( eAction ){
279 case 1: { /* Write out correctly */
280 if( pWrite->zBuf ){
281 rc = writeDbFile(
282 pWrite->pFile, pWrite->zBuf, pWrite->nBuf, pWrite->iOffset
283 );
284 }else{
285 rc = sqlite3OsTruncate(pRealFile, pWrite->iOffset);
286 }
287 *ppPtr = pWrite->pNext;
288 #ifdef TRACE_CRASHTEST
289 if( isCrash ){
290 printf("Writing %d bytes @ %d (%s)\n",
291 pWrite->nBuf, (int)pWrite->iOffset, pWrite->pFile->zName
292 );
293 }
294 #endif
295 crash_free(pWrite);
296 break;
297 }
298 case 2: { /* Do nothing */
299 ppPtr = &pWrite->pNext;
300 #ifdef TRACE_CRASHTEST
301 if( isCrash ){
302 printf("Omiting %d bytes @ %d (%s)\n",
303 pWrite->nBuf, (int)pWrite->iOffset, pWrite->pFile->zName
304 );
305 }
306 #endif
307 break;
308 }
309 case 3: { /* Trash sectors */
310 u8 *zGarbage;
311 int iFirst = (pWrite->iOffset/g.iSectorSize);
312 int iLast = (pWrite->iOffset+pWrite->nBuf-1)/g.iSectorSize;
313
314 assert(pWrite->zBuf);
315
316 #ifdef TRACE_CRASHTEST
317 printf("Trashing %d sectors @ sector %d (%s)\n",
318 1+iLast-iFirst, iFirst, pWrite->pFile->zName
319 );
320 #endif
321
322 zGarbage = crash_malloc(g.iSectorSize);
323 if( zGarbage ){
324 sqlite3_int64 i;
325 for(i=iFirst; rc==SQLITE_OK && i<=iLast; i++){
326 sqlite3_randomness(g.iSectorSize, zGarbage);
327 rc = writeDbFile(
328 pWrite->pFile, zGarbage, g.iSectorSize, i*g.iSectorSize
329 );
330 }
331 crash_free(zGarbage);
332 }else{
333 rc = SQLITE_NOMEM;
334 }
335
336 ppPtr = &pWrite->pNext;
337 break;
338 }
339
340 default:
341 assert(!"Cannot happen");
342 }
343
344 if( pWrite==pFinal ) break;
345 }
346
347 if( rc==SQLITE_OK && isCrash ){
348 exit(-1);
349 }
350
351 for(pWrite=g.pWriteList; pWrite && pWrite->pNext; pWrite=pWrite->pNext);
352 g.pWriteListEnd = pWrite;
353
354 return rc;
355 }
356
357 /*
358 ** Add an entry to the end of the write-list.
359 */
360 static int writeListAppend(
361 sqlite3_file *pFile,
362 sqlite3_int64 iOffset,
363 const u8 *zBuf,
364 int nBuf
365 ){
366 WriteBuffer *pNew;
367
368 assert((zBuf && nBuf) || (!nBuf && !zBuf));
369
370 pNew = (WriteBuffer *)crash_malloc(sizeof(WriteBuffer) + nBuf);
371 if( pNew==0 ){
372 fprintf(stderr, "out of memory in the crash simulator\n");
373 }
374 memset(pNew, 0, sizeof(WriteBuffer)+nBuf);
375 pNew->iOffset = iOffset;
376 pNew->nBuf = nBuf;
377 pNew->pFile = (CrashFile *)pFile;
378 if( zBuf ){
379 pNew->zBuf = (u8 *)&pNew[1];
380 memcpy(pNew->zBuf, zBuf, nBuf);
381 }
382
383 if( g.pWriteList ){
384 assert(g.pWriteListEnd);
385 g.pWriteListEnd->pNext = pNew;
386 }else{
387 g.pWriteList = pNew;
388 }
389 g.pWriteListEnd = pNew;
390
391 return SQLITE_OK;
392 }
393
394 /*
395 ** Close a crash-file.
396 */
397 static int cfClose(sqlite3_file *pFile){
398 CrashFile *pCrash = (CrashFile *)pFile;
399 writeListSync(pCrash, 0);
400 sqlite3OsClose(pCrash->pRealFile);
401 return SQLITE_OK;
402 }
403
404 /*
405 ** Read data from a crash-file.
406 */
407 static int cfRead(
408 sqlite3_file *pFile,
409 void *zBuf,
410 int iAmt,
411 sqlite_int64 iOfst
412 ){
413 CrashFile *pCrash = (CrashFile *)pFile;
414
415 /* Check the file-size to see if this is a short-read */
416 if( pCrash->iSize<(iOfst+iAmt) ){
417 return SQLITE_IOERR_SHORT_READ;
418 }
419
420 memcpy(zBuf, &pCrash->zData[iOfst], iAmt);
421 return SQLITE_OK;
422 }
423
424 /*
425 ** Write data to a crash-file.
426 */
427 static int cfWrite(
428 sqlite3_file *pFile,
429 const void *zBuf,
430 int iAmt,
431 sqlite_int64 iOfst
432 ){
433 CrashFile *pCrash = (CrashFile *)pFile;
434 if( iAmt+iOfst>pCrash->iSize ){
435 pCrash->iSize = iAmt+iOfst;
436 }
437 while( pCrash->iSize>pCrash->nData ){
438 u8 *zNew;
439 int nNew = (pCrash->nData*2) + 4096;
440 zNew = crash_realloc(pCrash->zData, nNew);
441 if( !zNew ){
442 return SQLITE_NOMEM;
443 }
444 memset(&zNew[pCrash->nData], 0, nNew-pCrash->nData);
445 pCrash->nData = nNew;
446 pCrash->zData = zNew;
447 }
448 memcpy(&pCrash->zData[iOfst], zBuf, iAmt);
449 return writeListAppend(pFile, iOfst, zBuf, iAmt);
450 }
451
452 /*
453 ** Truncate a crash-file.
454 */
455 static int cfTruncate(sqlite3_file *pFile, sqlite_int64 size){
456 CrashFile *pCrash = (CrashFile *)pFile;
457 assert(size>=0);
458 if( pCrash->iSize>size ){
459 pCrash->iSize = size;
460 }
461 return writeListAppend(pFile, size, 0, 0);
462 }
463
464 /*
465 ** Sync a crash-file.
466 */
467 static int cfSync(sqlite3_file *pFile, int flags){
468 CrashFile *pCrash = (CrashFile *)pFile;
469 int isCrash = 0;
470
471 const char *zName = pCrash->zName;
472 const char *zCrashFile = g.zCrashFile;
473 int nName = strlen(zName);
474 int nCrashFile = strlen(zCrashFile);
475
476 if( nCrashFile>0 && zCrashFile[nCrashFile-1]=='*' ){
477 nCrashFile--;
478 if( nName>nCrashFile ) nName = nCrashFile;
479 }
480
481 if( nName==nCrashFile && 0==memcmp(zName, zCrashFile, nName) ){
482 if( (--g.iCrash)==0 ) isCrash = 1;
483 }
484
485 return writeListSync(pCrash, isCrash);
486 }
487
488 /*
489 ** Return the current file-size of the crash-file.
490 */
491 static int cfFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
492 CrashFile *pCrash = (CrashFile *)pFile;
493 *pSize = (i64)pCrash->iSize;
494 return SQLITE_OK;
495 }
496
497 /*
498 ** Calls related to file-locks are passed on to the real file handle.
499 */
500 static int cfLock(sqlite3_file *pFile, int eLock){
501 return sqlite3OsLock(((CrashFile *)pFile)->pRealFile, eLock);
502 }
503 static int cfUnlock(sqlite3_file *pFile, int eLock){
504 return sqlite3OsUnlock(((CrashFile *)pFile)->pRealFile, eLock);
505 }
506 static int cfCheckReservedLock(sqlite3_file *pFile, int *pResOut){
507 return sqlite3OsCheckReservedLock(((CrashFile *)pFile)->pRealFile, pResOut);
508 }
509 static int cfFileControl(sqlite3_file *pFile, int op, void *pArg){
510 return sqlite3OsFileControl(((CrashFile *)pFile)->pRealFile, op, pArg);
511 }
512
513 /*
514 ** The xSectorSize() and xDeviceCharacteristics() functions return
515 ** the global values configured by the [sqlite_crashparams] tcl
516 * interface.
517 */
518 static int cfSectorSize(sqlite3_file *pFile){
519 return g.iSectorSize;
520 }
521 static int cfDeviceCharacteristics(sqlite3_file *pFile){
522 return g.iDeviceCharacteristics;
523 }
524
525 static const sqlite3_io_methods CrashFileVtab = {
526 1, /* iVersion */
527 cfClose, /* xClose */
528 cfRead, /* xRead */
529 cfWrite, /* xWrite */
530 cfTruncate, /* xTruncate */
531 cfSync, /* xSync */
532 cfFileSize, /* xFileSize */
533 cfLock, /* xLock */
534 cfUnlock, /* xUnlock */
535 cfCheckReservedLock, /* xCheckReservedLock */
536 cfFileControl, /* xFileControl */
537 cfSectorSize, /* xSectorSize */
538 cfDeviceCharacteristics /* xDeviceCharacteristics */
539 };
540
541 /*
542 ** Application data for the crash VFS
543 */
544 struct crashAppData {
545 sqlite3_vfs *pOrig; /* Wrapped vfs structure */
546 };
547
548 /*
549 ** Open a crash-file file handle.
550 **
551 ** The caller will have allocated pVfs->szOsFile bytes of space
552 ** at pFile. This file uses this space for the CrashFile structure
553 ** and allocates space for the "real" file structure using
554 ** sqlite3_malloc(). The assumption here is (pVfs->szOsFile) is
555 ** equal or greater than sizeof(CrashFile).
556 */
557 static int cfOpen(
558 sqlite3_vfs *pCfVfs,
559 const char *zName,
560 sqlite3_file *pFile,
561 int flags,
562 int *pOutFlags
563 ){
564 sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
565 int rc;
566 CrashFile *pWrapper = (CrashFile *)pFile;
567 sqlite3_file *pReal = (sqlite3_file*)&pWrapper[1];
568
569 memset(pWrapper, 0, sizeof(CrashFile));
570 rc = sqlite3OsOpen(pVfs, zName, pReal, flags, pOutFlags);
571
572 if( rc==SQLITE_OK ){
573 i64 iSize;
574 pWrapper->pMethod = &CrashFileVtab;
575 pWrapper->zName = (char *)zName;
576 pWrapper->pRealFile = pReal;
577 rc = sqlite3OsFileSize(pReal, &iSize);
578 pWrapper->iSize = (int)iSize;
579 pWrapper->flags = flags;
580 }
581 if( rc==SQLITE_OK ){
582 pWrapper->nData = (4096 + pWrapper->iSize);
583 pWrapper->zData = crash_malloc(pWrapper->nData);
584 if( pWrapper->zData ){
585 /* os_unix.c contains an assert() that fails if the caller attempts
586 ** to read data from the 512-byte locking region of a file opened
587 ** with the SQLITE_OPEN_MAIN_DB flag. This region of a database file
588 ** never contains valid data anyhow. So avoid doing such a read here.
589 */
590 const int isDb = (flags&SQLITE_OPEN_MAIN_DB);
591 i64 iChunk = pWrapper->iSize;
592 if( iChunk>PENDING_BYTE && isDb ){
593 iChunk = PENDING_BYTE;
594 }
595 memset(pWrapper->zData, 0, pWrapper->nData);
596 rc = sqlite3OsRead(pReal, pWrapper->zData, iChunk, 0);
597 if( SQLITE_OK==rc && pWrapper->iSize>(PENDING_BYTE+512) && isDb ){
598 i64 iOff = PENDING_BYTE+512;
599 iChunk = pWrapper->iSize - iOff;
600 rc = sqlite3OsRead(pReal, &pWrapper->zData[iOff], iChunk, iOff);
601 }
602 }else{
603 rc = SQLITE_NOMEM;
604 }
605 }
606 if( rc!=SQLITE_OK && pWrapper->pMethod ){
607 sqlite3OsClose(pFile);
608 }
609 return rc;
610 }
611
612 static int cfDelete(sqlite3_vfs *pCfVfs, const char *zPath, int dirSync){
613 sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
614 return pVfs->xDelete(pVfs, zPath, dirSync);
615 }
616 static int cfAccess(
617 sqlite3_vfs *pCfVfs,
618 const char *zPath,
619 int flags,
620 int *pResOut
621 ){
622 sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
623 return pVfs->xAccess(pVfs, zPath, flags, pResOut);
624 }
625 static int cfFullPathname(
626 sqlite3_vfs *pCfVfs,
627 const char *zPath,
628 int nPathOut,
629 char *zPathOut
630 ){
631 sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
632 return pVfs->xFullPathname(pVfs, zPath, nPathOut, zPathOut);
633 }
634 static void *cfDlOpen(sqlite3_vfs *pCfVfs, const char *zPath){
635 sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
636 return pVfs->xDlOpen(pVfs, zPath);
637 }
638 static void cfDlError(sqlite3_vfs *pCfVfs, int nByte, char *zErrMsg){
639 sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
640 pVfs->xDlError(pVfs, nByte, zErrMsg);
641 }
642 static void (*cfDlSym(sqlite3_vfs *pCfVfs, void *pH, const char *zSym))(void){
643 sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
644 return pVfs->xDlSym(pVfs, pH, zSym);
645 }
646 static void cfDlClose(sqlite3_vfs *pCfVfs, void *pHandle){
647 sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
648 pVfs->xDlClose(pVfs, pHandle);
649 }
650 static int cfRandomness(sqlite3_vfs *pCfVfs, int nByte, char *zBufOut){
651 sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
652 return pVfs->xRandomness(pVfs, nByte, zBufOut);
653 }
654 static int cfSleep(sqlite3_vfs *pCfVfs, int nMicro){
655 sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
656 return pVfs->xSleep(pVfs, nMicro);
657 }
658 static int cfCurrentTime(sqlite3_vfs *pCfVfs, double *pTimeOut){
659 sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
660 return pVfs->xCurrentTime(pVfs, pTimeOut);
661 }
662
663 static int processDevSymArgs(
664 Tcl_Interp *interp,
665 int objc,
666 Tcl_Obj *CONST objv[],
667 int *piDeviceChar,
668 int *piSectorSize
669 ){
670 struct DeviceFlag {
671 char *zName;
672 int iValue;
673 } aFlag[] = {
674 { "atomic", SQLITE_IOCAP_ATOMIC },
675 { "atomic512", SQLITE_IOCAP_ATOMIC512 },
676 { "atomic1k", SQLITE_IOCAP_ATOMIC1K },
677 { "atomic2k", SQLITE_IOCAP_ATOMIC2K },
678 { "atomic4k", SQLITE_IOCAP_ATOMIC4K },
679 { "atomic8k", SQLITE_IOCAP_ATOMIC8K },
680 { "atomic16k", SQLITE_IOCAP_ATOMIC16K },
681 { "atomic32k", SQLITE_IOCAP_ATOMIC32K },
682 { "atomic64k", SQLITE_IOCAP_ATOMIC64K },
683 { "sequential", SQLITE_IOCAP_SEQUENTIAL },
684 { "safe_append", SQLITE_IOCAP_SAFE_APPEND },
685 { 0, 0 }
686 };
687
688 int i;
689 int iDc = 0;
690 int iSectorSize = 0;
691 int setSectorsize = 0;
692 int setDeviceChar = 0;
693
694 for(i=0; i<objc; i+=2){
695 int nOpt;
696 char *zOpt = Tcl_GetStringFromObj(objv[i], &nOpt);
697
698 if( (nOpt>11 || nOpt<2 || strncmp("-sectorsize", zOpt, nOpt))
699 && (nOpt>16 || nOpt<2 || strncmp("-characteristics", zOpt, nOpt))
700 ){
701 Tcl_AppendResult(interp,
702 "Bad option: \"", zOpt,
703 "\" - must be \"-characteristics\" or \"-sectorsize\"", 0
704 );
705 return TCL_ERROR;
706 }
707 if( i==objc-1 ){
708 Tcl_AppendResult(interp, "Option requires an argument: \"", zOpt, "\"",0);
709 return TCL_ERROR;
710 }
711
712 if( zOpt[1]=='s' ){
713 if( Tcl_GetIntFromObj(interp, objv[i+1], &iSectorSize) ){
714 return TCL_ERROR;
715 }
716 setSectorsize = 1;
717 }else{
718 int j;
719 Tcl_Obj **apObj;
720 int nObj;
721 if( Tcl_ListObjGetElements(interp, objv[i+1], &nObj, &apObj) ){
722 return TCL_ERROR;
723 }
724 for(j=0; j<nObj; j++){
725 int rc;
726 int iChoice;
727 Tcl_Obj *pFlag = Tcl_DuplicateObj(apObj[j]);
728 Tcl_IncrRefCount(pFlag);
729 Tcl_UtfToLower(Tcl_GetString(pFlag));
730
731 rc = Tcl_GetIndexFromObjStruct(
732 interp, pFlag, aFlag, sizeof(aFlag[0]), "no such flag", 0, &iChoice
733 );
734 Tcl_DecrRefCount(pFlag);
735 if( rc ){
736 return TCL_ERROR;
737 }
738
739 iDc |= aFlag[iChoice].iValue;
740 }
741 setDeviceChar = 1;
742 }
743 }
744
745 if( setDeviceChar ){
746 *piDeviceChar = iDc;
747 }
748 if( setSectorsize ){
749 *piSectorSize = iSectorSize;
750 }
751
752 return TCL_OK;
753 }
754
755 /*
756 ** tclcmd: sqlite_crash_enable ENABLE
757 **
758 ** Parameter ENABLE must be a boolean value. If true, then the "crash"
759 ** vfs is added to the system. If false, it is removed.
760 */
761 static int crashEnableCmd(
762 void * clientData,
763 Tcl_Interp *interp,
764 int objc,
765 Tcl_Obj *CONST objv[]
766 ){
767 int isEnable;
768 static sqlite3_vfs crashVfs = {
769 1, /* iVersion */
770 0, /* szOsFile */
771 0, /* mxPathname */
772 0, /* pNext */
773 "crash", /* zName */
774 0, /* pAppData */
775
776 cfOpen, /* xOpen */
777 cfDelete, /* xDelete */
778 cfAccess, /* xAccess */
779 cfFullPathname, /* xFullPathname */
780 cfDlOpen, /* xDlOpen */
781 cfDlError, /* xDlError */
782 cfDlSym, /* xDlSym */
783 cfDlClose, /* xDlClose */
784 cfRandomness, /* xRandomness */
785 cfSleep, /* xSleep */
786 cfCurrentTime /* xCurrentTime */
787 };
788
789 if( objc!=2 ){
790 Tcl_WrongNumArgs(interp, 1, objv, "ENABLE");
791 return TCL_ERROR;
792 }
793
794 if( Tcl_GetBooleanFromObj(interp, objv[1], &isEnable) ){
795 return TCL_ERROR;
796 }
797
798 if( (isEnable && crashVfs.pAppData) || (!isEnable && !crashVfs.pAppData) ){
799 return TCL_OK;
800 }
801
802 if( crashVfs.pAppData==0 ){
803 sqlite3_vfs *pOriginalVfs = sqlite3_vfs_find(0);
804 crashVfs.mxPathname = pOriginalVfs->mxPathname;
805 crashVfs.pAppData = (void *)pOriginalVfs;
806 crashVfs.szOsFile = sizeof(CrashFile) + pOriginalVfs->szOsFile;
807 sqlite3_vfs_register(&crashVfs, 0);
808 }else{
809 crashVfs.pAppData = 0;
810 sqlite3_vfs_unregister(&crashVfs);
811 }
812
813 return TCL_OK;
814 }
815
816 /*
817 ** tclcmd: sqlite_crashparams ?OPTIONS? DELAY CRASHFILE
818 **
819 ** This procedure implements a TCL command that enables crash testing
820 ** in testfixture. Once enabled, crash testing cannot be disabled.
821 **
822 ** Available options are "-characteristics" and "-sectorsize". Both require
823 ** an argument. For -sectorsize, this is the simulated sector size in
824 ** bytes. For -characteristics, the argument must be a list of io-capability
825 ** flags to simulate. Valid flags are "atomic", "atomic512", "atomic1K",
826 ** "atomic2K", "atomic4K", "atomic8K", "atomic16K", "atomic32K",
827 ** "atomic64K", "sequential" and "safe_append".
828 **
829 ** Example:
830 **
831 ** sqlite_crashparams -sect 1024 -char {atomic sequential} ./test.db 1
832 **
833 */
834 static int crashParamsObjCmd(
835 void * clientData,
836 Tcl_Interp *interp,
837 int objc,
838 Tcl_Obj *CONST objv[]
839 ){
840 int iDelay;
841 const char *zCrashFile;
842 int nCrashFile, iDc, iSectorSize;
843
844 iDc = -1;
845 iSectorSize = -1;
846
847 if( objc<3 ){
848 Tcl_WrongNumArgs(interp, 1, objv, "?OPTIONS? DELAY CRASHFILE");
849 goto error;
850 }
851
852 zCrashFile = Tcl_GetStringFromObj(objv[objc-1], &nCrashFile);
853 if( nCrashFile>=sizeof(g.zCrashFile) ){
854 Tcl_AppendResult(interp, "Filename is too long: \"", zCrashFile, "\"", 0);
855 goto error;
856 }
857 if( Tcl_GetIntFromObj(interp, objv[objc-2], &iDelay) ){
858 goto error;
859 }
860
861 if( processDevSymArgs(interp, objc-3, &objv[1], &iDc, &iSectorSize) ){
862 return TCL_ERROR;
863 }
864
865 if( iDc>=0 ){
866 g.iDeviceCharacteristics = iDc;
867 }
868 if( iSectorSize>=0 ){
869 g.iSectorSize = iSectorSize;
870 }
871
872 g.iCrash = iDelay;
873 memcpy(g.zCrashFile, zCrashFile, nCrashFile+1);
874 sqlite3CrashTestEnable = 1;
875 return TCL_OK;
876
877 error:
878 return TCL_ERROR;
879 }
880
881 static int devSymObjCmd(
882 void * clientData,
883 Tcl_Interp *interp,
884 int objc,
885 Tcl_Obj *CONST objv[]
886 ){
887 void devsym_register(int iDeviceChar, int iSectorSize);
888
889 int iDc = -1;
890 int iSectorSize = -1;
891
892 if( processDevSymArgs(interp, objc-1, &objv[1], &iDc, &iSectorSize) ){
893 return TCL_ERROR;
894 }
895 devsym_register(iDc, iSectorSize);
896
897 return TCL_OK;
898 }
899
900 /*
901 ** tclcmd: register_jt_vfs ?-default? PARENT-VFS
902 */
903 static int jtObjCmd(
904 void * clientData,
905 Tcl_Interp *interp,
906 int objc,
907 Tcl_Obj *CONST objv[]
908 ){
909 int jt_register(char *, int);
910 char *zParent = 0;
911
912 if( objc!=2 && objc!=3 ){
913 Tcl_WrongNumArgs(interp, 1, objv, "?-default? PARENT-VFS");
914 return TCL_ERROR;
915 }
916 zParent = Tcl_GetString(objv[1]);
917 if( objc==3 ){
918 if( strcmp(zParent, "-default") ){
919 Tcl_AppendResult(interp,
920 "bad option \"", zParent, "\": must be -default", 0
921 );
922 return TCL_ERROR;
923 }
924 zParent = Tcl_GetString(objv[2]);
925 }
926
927 if( !(*zParent) ){
928 zParent = 0;
929 }
930 if( jt_register(zParent, objc==3) ){
931 Tcl_AppendResult(interp, "Error in jt_register", 0);
932 return TCL_ERROR;
933 }
934
935 return TCL_OK;
936 }
937
938 /*
939 ** tclcmd: unregister_jt_vfs
940 */
941 static int jtUnregisterObjCmd(
942 void * clientData,
943 Tcl_Interp *interp,
944 int objc,
945 Tcl_Obj *CONST objv[]
946 ){
947 void jt_unregister(void);
948
949 if( objc!=1 ){
950 Tcl_WrongNumArgs(interp, 1, objv, "");
951 return TCL_ERROR;
952 }
953
954 jt_unregister();
955 return TCL_OK;
956 }
957
958 #endif /* SQLITE_OMIT_DISKIO */
959
960 /*
961 ** This procedure registers the TCL procedures defined in this file.
962 */
963 int Sqlitetest6_Init(Tcl_Interp *interp){
964 #ifndef SQLITE_OMIT_DISKIO
965 Tcl_CreateObjCommand(interp, "sqlite3_crash_enable", crashEnableCmd, 0, 0);
966 Tcl_CreateObjCommand(interp, "sqlite3_crashparams", crashParamsObjCmd, 0, 0);
967 Tcl_CreateObjCommand(interp, "sqlite3_simulate_device", devSymObjCmd, 0, 0);
968 Tcl_CreateObjCommand(interp, "register_jt_vfs", jtObjCmd, 0, 0);
969 Tcl_CreateObjCommand(interp, "unregister_jt_vfs", jtUnregisterObjCmd, 0, 0);
970 #endif
971 return TCL_OK;
972 }
973
974 #endif /* SQLITE_TEST */
OLDNEW
« no previous file with comments | « third_party/sqlite/src/test5.c ('k') | third_party/sqlite/src/test7.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698