Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix a pager bug that might have made multi-database commits non-atomic if a power failure occurred at just the wrong moment. (CVS 1900) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
b6eb4bf8c7763ef73723fc3d3697af43 |
User & Date: | drh 2004-08-21 19:20:42.000 |
Context
2004-08-24
| ||
15:23 | Fix a bug in the parsing of wildcards that begin with '$'. (CVS 1901) (check-in: 054dd8901d user: drh tags: trunk) | |
2004-08-21
| ||
19:20 | Fix a pager bug that might have made multi-database commits non-atomic if a power failure occurred at just the wrong moment. (CVS 1900) (check-in: b6eb4bf8c7 user: drh tags: trunk) | |
17:54 | Optimizations to the code generator. (CVS 1899) (check-in: bd6649c5aa user: drh tags: trunk) | |
Changes
Changes to src/os_test.c.
︙ | ︙ | |||
92 93 94 95 96 97 98 | sqlite3OsEnterMutex(); n = strlen(zCrashFile); if( zCrashFile[n-1]=='*' ){ n--; }else if( strlen(zPath)>n ){ n = strlen(zPath); } | | > | < | | > > | 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | sqlite3OsEnterMutex(); n = strlen(zCrashFile); if( zCrashFile[n-1]=='*' ){ n--; }else if( strlen(zPath)>n ){ n = strlen(zPath); } r = 0; if( iCrashDelay>0 && strncmp(zPath, zCrashFile, n)==0 ){ iCrashDelay--; if( iCrashDelay<=0 ){ r = 1; } } sqlite3OsLeaveMutex(); return r; } static OsTestFile *pAllFiles = 0; |
︙ | ︙ | |||
153 154 155 156 157 158 159 160 161 162 163 164 165 166 | /* ** Load block 'blk' into the cache of pFile. */ static int cacheBlock(OsTestFile *pFile, int blk){ if( blk>=pFile->nBlk ){ int n = ((pFile->nBlk * 2) + 100 + blk); pFile->apBlk = (u8 **)sqliteRealloc(pFile->apBlk, n * sizeof(u8*)); if( !pFile->apBlk ) return SQLITE_NOMEM; memset(&pFile->apBlk[pFile->nBlk], 0, (n - pFile->nBlk)*sizeof(u8*)); pFile->nBlk = n; } if( !pFile->apBlk[blk] ){ | > | 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | /* ** Load block 'blk' into the cache of pFile. */ static int cacheBlock(OsTestFile *pFile, int blk){ if( blk>=pFile->nBlk ){ int n = ((pFile->nBlk * 2) + 100 + blk); /* if( pFile->nBlk==0 ){ printf("DIRTY %s\n", pFile->zName); } */ pFile->apBlk = (u8 **)sqliteRealloc(pFile->apBlk, n * sizeof(u8*)); if( !pFile->apBlk ) return SQLITE_NOMEM; memset(&pFile->apBlk[pFile->nBlk], 0, (n - pFile->nBlk)*sizeof(u8*)); pFile->nBlk = n; } if( !pFile->apBlk[blk] ){ |
︙ | ︙ | |||
279 280 281 282 283 284 285 286 287 288 289 290 291 292 | /* ** Close the file. */ int sqlite3OsClose(OsFile *id){ if( !(*id) ) return SQLITE_OK; if( (*id)->fd.isOpen ){ writeCache(*id); sqlite3RealClose(&(*id)->fd); } closeFile(id); return SQLITE_OK; } | > | 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 | /* ** Close the file. */ int sqlite3OsClose(OsFile *id){ if( !(*id) ) return SQLITE_OK; if( (*id)->fd.isOpen ){ /* printf("CLOSE %s (%d blocks)\n", (*id)->zName, (*id)->nBlk); */ writeCache(*id); sqlite3RealClose(&(*id)->fd); } closeFile(id); return SQLITE_OK; } |
︙ | ︙ | |||
382 383 384 385 386 387 388 | } /* ** Sync the file. First flush the write-cache to disk, then call the ** real sync() function. */ int sqlite3OsSync(OsFile *id){ | > > | | 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 | } /* ** Sync the file. First flush the write-cache to disk, then call the ** real sync() function. */ int sqlite3OsSync(OsFile *id){ int rc; /* printf("SYNC %s (%d blocks)\n", (*id)->zName, (*id)->nBlk); */ rc = writeCache(*id); if( rc!=SQLITE_OK ) return rc; rc = sqlite3RealSync(&(*id)->fd); return rc; } /* ** Truncate the file. Set the internal OsFile.nMaxWrite variable to the new |
︙ | ︙ |
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.160 2004/08/21 19:20:42 drh Exp $ */ #include "os.h" /* Must be first to enable large file support */ #include "sqliteInt.h" #include "pager.h" #include <assert.h> #include <string.h> |
︙ | ︙ | |||
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | u8 readOnly; /* True for a read-only database */ u8 needSync; /* True if an fsync() is needed on the journal */ u8 dirtyCache; /* True if cached pages have changed */ u8 alwaysRollback; /* Disable dont_rollback() for all pages */ u8 memDb; /* True to inhibit all file I/O */ u8 *aInJournal; /* One bit for each page in the database file */ u8 *aInStmt; /* One bit for each page in the database */ BusyHandler *pBusyHandler; /* Pointer to sqlite.busyHandler */ PgHdr *pFirst, *pLast; /* List of free pages */ PgHdr *pFirstSynced; /* First free page with PgHdr.needSync==0 */ PgHdr *pAll; /* List of all pages */ PgHdr *pStmt; /* List of pages in the statement subjournal */ PgHdr *aHash[N_PG_HASH]; /* Hash table to map page number to PgHdr */ off_t journalOff; /* Current byte offset in the journal file */ off_t journalHdr; /* Byte offset to previous journal header */ off_t stmtHdrOff; /* First journal header written this statement */ off_t stmtCksum; /* cksumInit when statement was started */ int sectorSize; /* Assumed sector size during rollback */ | > < | 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 | u8 readOnly; /* True for a read-only database */ u8 needSync; /* True if an fsync() is needed on the journal */ u8 dirtyCache; /* True if cached pages have changed */ u8 alwaysRollback; /* Disable dont_rollback() for all pages */ u8 memDb; /* True to inhibit all file I/O */ u8 *aInJournal; /* One bit for each page in the database file */ u8 *aInStmt; /* One bit for each page in the database */ u8 setMaster; /* True if a m-j name has been written to jrnl */ BusyHandler *pBusyHandler; /* Pointer to sqlite.busyHandler */ PgHdr *pFirst, *pLast; /* List of free pages */ PgHdr *pFirstSynced; /* First free page with PgHdr.needSync==0 */ PgHdr *pAll; /* List of all pages */ PgHdr *pStmt; /* List of pages in the statement subjournal */ PgHdr *aHash[N_PG_HASH]; /* Hash table to map page number to PgHdr */ off_t journalOff; /* Current byte offset in the journal file */ off_t journalHdr; /* Byte offset to previous journal header */ off_t stmtHdrOff; /* First journal header written this statement */ off_t stmtCksum; /* cksumInit when statement was started */ int sectorSize; /* Assumed sector size during rollback */ }; /* ** These are bits that can be set in Pager.errMask. */ #define PAGER_ERR_FULL 0x01 /* a write() failed */ #define PAGER_ERR_MEM 0x02 /* malloc() failed */ |
︙ | ︙ | |||
656 657 658 659 660 661 662 663 664 665 666 667 668 669 | rc = write32bits(&pPager->jfd, len); if( rc!=SQLITE_OK ) return rc; rc = write32bits(&pPager->jfd, cksum); if( rc!=SQLITE_OK ) return rc; rc = sqlite3OsWrite(&pPager->jfd, aJournalMagic, sizeof(aJournalMagic)); return rc; } /* ** Add or remove a page from the list of all pages that are in the ** statement journal. ** | > | 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 | rc = write32bits(&pPager->jfd, len); if( rc!=SQLITE_OK ) return rc; rc = write32bits(&pPager->jfd, cksum); if( rc!=SQLITE_OK ) return rc; rc = sqlite3OsWrite(&pPager->jfd, aJournalMagic, sizeof(aJournalMagic)); pPager->needSync = 1; return rc; } /* ** Add or remove a page from the list of all pages that are in the ** statement journal. ** |
︙ | ︙ |
Changes to test/crash.test.
︙ | ︙ | |||
16 17 18 19 20 21 22 | # module "crashtest" compiled with the special "os_test.c" backend is used. # The os_test.c simulates the kind of file corruption that can occur # when writes are happening at the moment of power loss. # # The special crash-test module with its os_test.c backend only works # on Unix. # | | | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | # module "crashtest" compiled with the special "os_test.c" backend is used. # The os_test.c simulates the kind of file corruption that can occur # when writes are happening at the moment of power loss. # # The special crash-test module with its os_test.c backend only works # on Unix. # # $Id: crash.test,v 1.9 2004/08/21 19:20:42 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # set repeats 100 set repeats 10 |
︙ | ︙ | |||
269 270 271 272 273 274 275 | signature } $sig do_test crash-4.1.$i.3 { signature2 } $sig2 } set i 0 | < | 269 270 271 272 273 274 275 276 277 278 279 280 281 282 | signature } $sig do_test crash-4.1.$i.3 { signature2 } $sig2 } set i 0 while {[incr i]} { set sig [signature] set sig2 [signature2] set ::fin 0 do_test crash-4.2.$i.1 { set c [crashsql $i test2.db-journal " ATTACH 'test2.db' AS aux; |
︙ | ︙ |