Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add tests to simulate power-failure on devices that support IOCAP_SEQUENTIAL or IOCAP_SAFE_APPEND. (CVS 4284) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
bdf5cb8d25d93d48220ce46acad2ccf9 |
User & Date: | danielk1977 2007-08-24 08:15:54.000 |
Context
2007-08-24
| ||
11:43 | Remove unnecessary sqlite3MallocDisallow() that was preventing win32 from running. (CVS 4285) (check-in: eb6c98fc10 user: drh tags: trunk) | |
08:15 | Add tests to simulate power-failure on devices that support IOCAP_SEQUENTIAL or IOCAP_SAFE_APPEND. (CVS 4284) (check-in: bdf5cb8d25 user: danielk1977 tags: trunk) | |
04:15 | Bug fix in the memory leak trace output. (CVS 4283) (check-in: a1b495c28a user: drh tags: trunk) | |
Changes
Changes to src/journal.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** 2007 August 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* ** 2007 August 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** @(#) $Id: journal.c,v 1.3 2007/08/24 08:15:54 danielk1977 Exp $ */ #ifdef SQLITE_ENABLE_ATOMIC_WRITE /* ** This file implements a special kind of sqlite3_file object used ** by SQLite to create journal files if the atomic-write optimization |
︙ | ︙ | |||
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | p->pMethod = &JournalFileMethods; p->nBuf = nBuf; p->flags = flags; p->zJournal = zName; p->pVfs = pVfs; return SQLITE_OK; } /* ** Return the number of bytes required to store a JournalFile that uses vfs ** pVfs to create the underlying on-disk files. */ int sqlite3JournalSize(sqlite3_vfs *pVfs){ return (pVfs->szOsFile+sizeof(JournalFile)); } #endif | > > > > > > > > > > > | 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | p->pMethod = &JournalFileMethods; p->nBuf = nBuf; p->flags = flags; p->zJournal = zName; p->pVfs = pVfs; return SQLITE_OK; } /* ** If the argument p points to a JournalFile structure, and the underlying ** file has not yet been created, create it now. */ int sqlite3JournalCreate(sqlite3_file *p){ if( p->pMethods!=&JournalFileMethods ){ return SQLITE_OK; } return createFile((JournalFile *)p); } /* ** Return the number of bytes required to store a JournalFile that uses vfs ** pVfs to create the underlying on-disk files. */ int sqlite3JournalSize(sqlite3_vfs *pVfs){ return (pVfs->szOsFile+sizeof(JournalFile)); } #endif |
Changes to src/pager.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 | ** The pager is used to access a database disk file. It implements ** atomic commit and rollback through the use of a journal file that ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. ** | | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ** The pager is used to access a database disk file. It implements ** atomic commit and rollback through the use of a journal file that ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. ** ** @(#) $Id: pager.c,v 1.373 2007/08/24 08:15:54 danielk1977 Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" #include <assert.h> #include <string.h> /* |
︙ | ︙ | |||
4188 4189 4190 4191 4192 4193 4194 | pagerEnter(pPager); /* If this is an in-memory db, or no pages have been written to, or this ** function has already been called, it is a no-op. */ if( pPager->state!=PAGER_SYNCED && !MEMDB && pPager->dirtyCache ){ PgHdr *pPg; | < > > | > | | > | > > > > > > | 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 | pagerEnter(pPager); /* If this is an in-memory db, or no pages have been written to, or this ** function has already been called, it is a no-op. */ if( pPager->state!=PAGER_SYNCED && !MEMDB && pPager->dirtyCache ){ PgHdr *pPg; #ifdef SQLITE_ENABLE_ATOMIC_WRITE /* The atomic-write optimization can be used if all of the ** following are true: ** ** + The file-system supports the atomic-write property for ** blocks of size page-size, and ** + This commit is not part of a multi-file transaction, and ** + Exactly one page has been modified and store in the journal file. ** ** If the optimization can be used, then the journal file will never ** be created for this transaction. */ int useAtomicWrite = ( !zMaster && pPager->journalOff==jrnlBufferSize(pPager) && nTrunc==0 && (0==pPager->pDirty || 0==pPager->pDirty->pDirty) ); if( useAtomicWrite ){ /* Update the nRec field in the journal file. */ int offset = pPager->journalHdr + sizeof(aJournalMagic); assert(pPager->nRec==1); rc = write32bits(pPager->jfd, offset, pPager->nRec); /* Update the db file change counter. The following call will modify ** the in-memory representation of page 1 to include the updated ** change counter and then write page 1 directly to the database ** file. Because of the atomic-write property of the host file-system, ** this is safe. */ rc = pager_incr_changecounter(pPager, 1); }else{ rc = sqlite3JournalCreate(pPager->jfd); if( rc!=SQLITE_OK ) goto sync_exit; } if( !useAtomicWrite ) #endif /* If a master journal file name has already been written to the ** journal file, then no sync is required. This happens when it is ** written, then the process fails to upgrade from a RESERVED to an ** EXCLUSIVE lock. The next time the process tries to commit the ** transaction the m-j name will have already been written. */ if( !pPager->setMaster ){ assert( pPager->journalOpen ); rc = pager_incr_changecounter(pPager, 0); if( rc!=SQLITE_OK ) goto sync_exit; #ifndef SQLITE_OMIT_AUTOVACUUM if( nTrunc!=0 ){ /* If this transaction has made the database smaller, then all pages ** being discarded by the truncation must be written to the journal ** file. |
︙ | ︙ |
Changes to src/sqliteInt.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** ** @(#) $Id: sqliteInt.h,v 1.599 2007/08/24 08:15:54 danielk1977 Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ #include "sqliteLimit.h" #if defined(SQLITE_TCL) || defined(TCLSH) |
︙ | ︙ | |||
1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 | int sqlite3Reprepare(Vdbe*); void sqlite3ExprListCheckLength(Parse*, ExprList*, int, const char*); CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *); #ifdef SQLITE_ENABLE_ATOMIC_WRITE int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int); int sqlite3JournalSize(sqlite3_vfs *); #else #define sqlite3JournalSize(pVfs) ((pVfs)->szOsFile) #endif #if SQLITE_MAX_EXPR_DEPTH>0 void sqlite3ExprSetHeight(Expr *); int sqlite3SelectExprHeight(Select *); | > | 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 | int sqlite3Reprepare(Vdbe*); void sqlite3ExprListCheckLength(Parse*, ExprList*, int, const char*); CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *); #ifdef SQLITE_ENABLE_ATOMIC_WRITE int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int); int sqlite3JournalSize(sqlite3_vfs *); int sqlite3JournalCreate(sqlite3_file *); #else #define sqlite3JournalSize(pVfs) ((pVfs)->szOsFile) #endif #if SQLITE_MAX_EXPR_DEPTH>0 void sqlite3ExprSetHeight(Expr *); int sqlite3SelectExprHeight(Select *); |
︙ | ︙ |
Changes to src/test6.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ****************************************************************************** ** ** This file contains code that modified the OS layer in order to simulate ** the effect on the database file of an OS crash or power failure. This ** is used to test the ability of SQLite to recover from those situations. */ | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ** ****************************************************************************** ** ** This file contains code that modified the OS layer in order to simulate ** the effect on the database file of an OS crash or power failure. This ** is used to test the ability of SQLite to recover from those situations. */ #if SQLITE_TEST /* This file is used for testing only */ #include "sqliteInt.h" #include "tcl.h" #ifndef SQLITE_OMIT_DISKIO /* This file is a no-op if disk I/O is disabled */ /* #define TRACE_CRASHTEST */ |
︙ | ︙ | |||
158 159 160 161 162 163 164 | /* ** Flush the write-list as if xSync() had been called on file handle ** pFile. If isCrash is true, simulate a crash. */ static int writeListSync(CrashFile *pFile, int isCrash){ int rc = SQLITE_OK; int iDc = g.iDeviceCharacteristics; | < > | | > > > > > > > > > > > < < > > > | > > > > > > > > > > > > > > > > > > > > | > > | > > | > > | 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 | /* ** Flush the write-list as if xSync() had been called on file handle ** pFile. If isCrash is true, simulate a crash. */ static int writeListSync(CrashFile *pFile, int isCrash){ int rc = SQLITE_OK; int iDc = g.iDeviceCharacteristics; WriteBuffer *pWrite; WriteBuffer **ppPtr; /* If this is not a crash simulation, set pFinal to point to the ** last element of the write-list that is associated with file handle ** pFile. ** ** If this is a crash simulation, set pFinal to an arbitrarily selected ** element of the write-list. */ WriteBuffer *pFinal = 0; if( !isCrash ){ for(pWrite=g.pWriteList; pWrite; pWrite=pWrite->pNext){ if( pWrite->pFile==pFile ){ pFinal = pWrite; } } }else if( iDc&(SQLITE_IOCAP_SEQUENTIAL|SQLITE_IOCAP_SAFE_APPEND) ){ int nWrite = 0; int iFinal; for(pWrite=g.pWriteList; pWrite; pWrite=pWrite->pNext) nWrite++; sqlite3Randomness(sizeof(int), &iFinal); iFinal = ((iFinal<0)?-1*iFinal:iFinal)%nWrite; for(pWrite=g.pWriteList; iFinal>0; pWrite=pWrite->pNext) iFinal--; pFinal = pWrite; } #ifdef TRACE_CRASHTEST printf("Sync %s (is %s crash)\n", pFile->zName, (isCrash?"a":"not a")); #endif ppPtr = &g.pWriteList; for(pWrite=*ppPtr; rc==SQLITE_OK && pWrite; pWrite=*ppPtr){ sqlite3_file *pRealFile = pWrite->pFile->pRealFile; /* (eAction==1) -> write block out normally, ** (eAction==2) -> do nothing, ** (eAction==3) -> trash sectors. */ int eAction = 0; if( !isCrash ){ eAction = 2; if( (pWrite->pFile==pFile || iDc&SQLITE_IOCAP_SEQUENTIAL) ){ eAction = 1; } }else{ char random; sqlite3Randomness(1, &random); /* Do not select option 3 (sector trashing) if the IOCAP_ATOMIC flag ** is set or this is an OsTruncate(), not an Oswrite(). */ if( (iDc&SQLITE_IOCAP_ATOMIC) || (pWrite->zBuf==0) ){ random &= 0x01; } /* If IOCAP_SEQUENTIAL is set and this is not the final entry ** in the truncated write-list, always select option 1 (write ** out correctly). */ if( (iDc&SQLITE_IOCAP_SEQUENTIAL && pWrite!=pFinal) ){ random = 0; } /* If IOCAP_SAFE_APPEND is set and this OsWrite() operation is ** an append (first byte of the written region is 1 byte past the ** current EOF), always select option 1 (write out correctly). */ if( iDc&SQLITE_IOCAP_SAFE_APPEND && pWrite->zBuf ){ i64 iSize; sqlite3OsFileSize(pRealFile, &iSize); if( iSize==pWrite->iOffset ){ random = 0; } } if( (random&0x06)==0x06 ){ eAction = 3; }else{ eAction = ((random&0x01)?2:1); } } switch( eAction ){ case 1: { /* Write out correctly */ if( pWrite->zBuf ){ rc = sqlite3OsWrite( pRealFile, pWrite->zBuf, pWrite->nBuf, pWrite->iOffset ); }else{ rc = sqlite3OsTruncate(pRealFile, pWrite->iOffset); } *ppPtr = pWrite->pNext; #ifdef TRACE_CRASHTEST if( isCrash ){ printf("Writing %d bytes @ %d (%s)\n", pWrite->nBuf, (int)pWrite->iOffset, pWrite->pFile->zName ); } #endif sqlite3_free(pWrite); break; } case 2: { /* Do nothing */ ppPtr = &pWrite->pNext; #ifdef TRACE_CRASHTEST if( isCrash ){ printf("Omiting %d bytes @ %d (%s)\n", pWrite->nBuf, (int)pWrite->iOffset, pWrite->pFile->zName ); } #endif break; } case 3: { /* Trash sectors */ u8 *zGarbage; int iFirst = (pWrite->iOffset/g.iSectorSize); int iLast = (pWrite->iOffset+pWrite->nBuf-1)/g.iSectorSize; assert(pWrite->zBuf); #ifdef TRACE_CRASHTEST printf("Trashing %d sectors @ sector %d (%s)\n", 1+iLast-iFirst, iFirst, pWrite->pFile->zName ); #endif zGarbage = sqlite3_malloc(g.iSectorSize); if( zGarbage ){ sqlite3_int64 i; for(i=iFirst; rc==SQLITE_OK && i<=iLast; i++){ sqlite3Randomness(g.iSectorSize, zGarbage); |
︙ | ︙ | |||
485 486 487 488 489 490 491 | ** The caller will have allocated pVfs->szOsFile bytes of space ** at pFile. This file uses this space for the CrashFile structure ** and allocates space for the "real" file structure using ** sqlite3_malloc(). The assumption here is (pVfs->szOsFile) is ** equal or greater than sizeof(CrashFile). */ static int cfOpen( | | | | 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 | ** The caller will have allocated pVfs->szOsFile bytes of space ** at pFile. This file uses this space for the CrashFile structure ** and allocates space for the "real" file structure using ** sqlite3_malloc(). The assumption here is (pVfs->szOsFile) is ** equal or greater than sizeof(CrashFile). */ static int cfOpen( sqlite3_vfs *pCfVfs, const char *zName, sqlite3_file *pFile, int flags, int *pOutFlags ){ sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData; int rc; CrashFile *pWrapper = (CrashFile *)pFile; sqlite3_file *pReal = (sqlite3_file*)&pWrapper[1]; memset(pWrapper, 0, sizeof(CrashFile)); rc = sqlite3OsOpen(pVfs, zName, pReal, flags, pOutFlags); |
︙ | ︙ | |||
523 524 525 526 527 528 529 | } if( rc!=SQLITE_OK && pWrapper->pMethod ){ sqlite3OsClose(pFile); } return rc; } | | | | | | | | | | | | | | | | | | | | | | | | | | 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 | } if( rc!=SQLITE_OK && pWrapper->pMethod ){ sqlite3OsClose(pFile); } return rc; } static int cfDelete(sqlite3_vfs *pCfVfs, const char *zPath, int dirSync){ sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData; return pVfs->xDelete(pVfs, zPath, dirSync); } static int cfAccess(sqlite3_vfs *pCfVfs, const char *zPath, int flags){ sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData; return pVfs->xAccess(pVfs, zPath, flags); } static int cfGetTempName(sqlite3_vfs *pCfVfs, char *zBufOut){ sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData; return pVfs->xGetTempName(pVfs, zBufOut); } static int cfFullPathname(sqlite3_vfs *pCfVfs, const char *zPath, char *zPathOut){ sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData; return pVfs->xFullPathname(pVfs, zPath, zPathOut); } static void *cfDlOpen(sqlite3_vfs *pCfVfs, const char *zPath){ sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData; return pVfs->xDlOpen(pVfs, zPath); } static int cfRandomness(sqlite3_vfs *pCfVfs, int nByte, char *zBufOut){ sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData; return pVfs->xRandomness(pVfs, nByte, zBufOut); } static int cfSleep(sqlite3_vfs *pCfVfs, int nMicro){ sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData; return pVfs->xSleep(pVfs, nMicro); } static int cfCurrentTime(sqlite3_vfs *pCfVfs, double *pTimeOut){ sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData; return pVfs->xCurrentTime(pVfs, pTimeOut); } static int processDevSymArgs( Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], int *piDeviceChar, |
︙ | ︙ |
Changes to test/crash3.test.
1 2 3 4 5 6 7 8 9 10 11 | # 2007 August 23 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # | > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # 2007 August 23 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # This file contains tests that verify that SQLite can correctly rollback # databases after crashes when using the special IO modes triggered # by device IOCAP flags. # # $Id: crash3.test,v 1.2 2007/08/24 08:15:54 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !crashtest { finish_test return |
︙ | ︙ | |||
30 31 32 33 34 35 36 37 38 39 40 41 42 43 | } set res } {{$res1} or {$res2}} }] uplevel $script } # Each iteration of the following loop sets up the database to contain # the following schema and data: # # CREATE TABLE abc(a, b, c); # INSERT INTO abc VALUES(1, 2, 3); # # Then execute the SQL statement, scheduling a crash for part-way through | > > | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | } set res } {{$res1} or {$res2}} }] uplevel $script } # This block tests crash-recovery when the IOCAP_ATOMIC flags is set. # # Each iteration of the following loop sets up the database to contain # the following schema and data: # # CREATE TABLE abc(a, b, c); # INSERT INTO abc VALUES(1, 2, 3); # # Then execute the SQL statement, scheduling a crash for part-way through |
︙ | ︙ | |||
91 92 93 94 95 96 97 98 99 100 | do_test2 crash3-1.$tn.3 { execsql { SELECT * FROM abc } } {1 2 3} $res2 incr tn } } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | do_test2 crash3-1.$tn.3 { execsql { SELECT * FROM abc } } {1 2 3} $res2 incr tn } } # This block tests both the IOCAP_SEQUENTIAL and IOCAP_SAFE_APPEND flags. # db close file delete -force test.db test.db-journal sqlite3 db test.db do_test crash3-2.0 { execsql { BEGIN; CREATE TABLE abc(a PRIMARY KEY, b, c); CREATE TABLE def(d PRIMARY KEY, e, f); PRAGMA default_cache_size = 10; INSERT INTO abc VALUES(randstr(10,1000),randstr(10,1000),randstr(10,1000)); INSERT INTO abc SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000) FROM abc; INSERT INTO abc SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000) FROM abc; INSERT INTO abc SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000) FROM abc; INSERT INTO abc SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000) FROM abc; INSERT INTO abc SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000) FROM abc; INSERT INTO abc SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000) FROM abc; COMMIT; } } {} set tn 1 foreach {::crashfile ::delay ::char} { test.db 1 sequential test.db 1 safe_append test.db-journal 1 sequential test.db-journal 1 safe_append test.db-journal 2 safe_append test.db-journal 2 sequential test.db-journal 3 sequential test.db-journal 3 safe_append } { for {set ii 0} {$ii < 100} {incr ii} { set ::SQL [subst { SELECT randstr($ii,$ii+10); BEGIN; DELETE FROM abc WHERE random()%5; INSERT INTO abc SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000) FROM abc WHERE (random()%5)==0; DELETE FROM def WHERE random()%5; INSERT INTO def SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000) FROM def WHERE (random()%5)==0; COMMIT; }] do_test crash3-2.$tn.$ii { crashsql -file $::crashfile -delay $::delay -char $::char $::SQL db close sqlite3 db test.db execsql {PRAGMA integrity_check} } {ok} } incr tn } # The following block tests an interaction between IOCAP_ATOMIC and # IOCAP_SEQUENTIAL. At one point, if both flags were set, small # journal files that contained only a single page, but were required # for some other reason (i.e. nTrunk) were not being written to # disk. # for {set ii 0} {$ii < 10} {incr ii} { db close file delete -force test.db test.db-journal crashsql -file test.db -char {sequential atomic} { CREATE TABLE abc(a, b, c); } sqlite3 db test.db do_test crash3-3.$ii { execsql {PRAGMA integrity_check} } {ok} } finish_test |