Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix a problem where an SQLITE_BUSY in the checkpoint code was being treated as an IO error (abandoning, instead of just limiting, the checkpoint). |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
02c4040ce2b4c970b3dee09f7c9ad5a2 |
User & Date: | dan 2010-06-04 10:37:06.000 |
Context
2010-06-04
| ||
11:56 | If an attempt to sync the database file as part of a checkpoint fails, do not update the shared "nBackfill" variable. Otherwise, another process could wrap the log and overwrite content before it is synced into the database. (check-in: b813233d76 user: dan tags: trunk) | |
10:37 | Fix a problem where an SQLITE_BUSY in the checkpoint code was being treated as an IO error (abandoning, instead of just limiting, the checkpoint). (check-in: 02c4040ce2 user: dan tags: trunk) | |
2010-06-03
| ||
19:10 | Fix another problem in test_vfs.c. (check-in: df7d59899c user: dan tags: trunk) | |
Changes
Changes to src/test_vfs.c.
︙ | ︙ | |||
592 593 594 595 596 597 598 | ){ int rc = SQLITE_OK; TestvfsFile *pFd = (TestvfsFile *)pFile; Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); if( p->pScript && p->mask&TESTVFS_SHMGET_MASK ){ tvfsExecTcl(p, "xShmGet", | | > | 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 | ){ int rc = SQLITE_OK; TestvfsFile *pFd = (TestvfsFile *)pFile; Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); if( p->pScript && p->mask&TESTVFS_SHMGET_MASK ){ tvfsExecTcl(p, "xShmGet", Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, Tcl_NewIntObj(reqMapSize) ); tvfsResultCode(p, &rc); } if( rc==SQLITE_OK && p->mask&TESTVFS_SHMGET_MASK && tvfsInjectIoerr(p) ){ rc = SQLITE_IOERR; } |
︙ | ︙ |
Changes to src/wal.c.
︙ | ︙ | |||
1295 1296 1297 1298 1299 1300 1301 | WalIterator *p; /* Return value */ int nSegment; /* Number of segments to merge */ u32 iLast; /* Last frame in log */ int nByte; /* Number of bytes to allocate */ int i; /* Iterator variable */ int nFinal; /* Number of unindexed entries */ u8 *aTmp; /* Temp space used by merge-sort */ | < | < < < | 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 | WalIterator *p; /* Return value */ int nSegment; /* Number of segments to merge */ u32 iLast; /* Last frame in log */ int nByte; /* Number of bytes to allocate */ int i; /* Iterator variable */ int nFinal; /* Number of unindexed entries */ u8 *aTmp; /* Temp space used by merge-sort */ u8 *aSpace; /* Surplus space on the end of the allocation */ /* Make sure the wal-index is mapped into local memory */ assert( pWal->pWiData && pWal->szWIndex>=walMappingSize(pWal->hdr.mxFrame) ); /* This routine only runs while holding SQLITE_SHM_CHECKPOINT. No other ** thread is able to write to shared memory while this routine is ** running (or, indeed, while the WalIterator object exists). Hence, ** we can cast off the volatile qualifacation from shared memory */ assert( pWal->ckptLock ); |
︙ | ︙ | |||
1356 1357 1358 1359 1360 1361 1362 | /* ** Free an iterator allocated by walIteratorInit(). */ static void walIteratorFree(WalIterator *p){ sqlite3_free(p); } | < | 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 | /* ** Free an iterator allocated by walIteratorInit(). */ static void walIteratorFree(WalIterator *p){ sqlite3_free(p); } /* ** Copy as much content as we can from the WAL back into the database file ** in response to an sqlite3_wal_checkpoint() request or the equivalent. ** ** The amount of information copies from WAL to database might be limited ** by active readers. This routine will never overwrite a database page ** that a concurrent reader might be using. |
︙ | ︙ | |||
1407 1408 1409 1410 1411 1412 1413 | int i; /* Loop counter */ volatile WalIndexHdr *pHdr; /* The actual wal-index header in SHM */ volatile WalCkptInfo *pInfo; /* The checkpoint status information */ /* Allocate the iterator */ rc = walIteratorInit(pWal, &pIter); if( rc!=SQLITE_OK || pWal->hdr.mxFrame==0 ){ | | < < | > | | | | | < | 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 | int i; /* Loop counter */ volatile WalIndexHdr *pHdr; /* The actual wal-index header in SHM */ volatile WalCkptInfo *pInfo; /* The checkpoint status information */ /* Allocate the iterator */ rc = walIteratorInit(pWal, &pIter); if( rc!=SQLITE_OK || pWal->hdr.mxFrame==0 ){ goto walcheckpoint_out; } /*** TODO: Move this test out to the caller. Make it an assert() here ***/ if( pWal->hdr.szPage!=nBuf ){ rc = SQLITE_CORRUPT_BKPT; goto walcheckpoint_out; } /* Compute in mxSafeFrame the index of the last frame of the WAL that is ** safe to write into the database. Frames beyond mxSafeFrame might ** overwrite database pages that are in use by active readers and thus ** cannot be backfilled from the WAL. */ mxSafeFrame = pWal->hdr.mxFrame; pHdr = (volatile WalIndexHdr*)pWal->pWiData; pInfo = (volatile WalCkptInfo*)&pHdr[2]; assert( pInfo==walCkptInfo(pWal) ); for(i=1; i<WAL_NREADER; i++){ u32 y = pInfo->aReadMark[i]; if( y>0 && mxSafeFrame>=y ){ assert( y<=pWal->hdr.mxFrame ); rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1); if( rc==SQLITE_OK ){ pInfo->aReadMark[i] = 0; walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1); }else if( rc==SQLITE_BUSY ){ mxSafeFrame = y-1; }else{ goto walcheckpoint_out; } } } if( pInfo->nBackfill<mxSafeFrame && (rc = walLockExclusive(pWal, WAL_READ_LOCK(0), 1))==SQLITE_OK ){ |
︙ | ︙ | |||
1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 | }else if( rc==SQLITE_BUSY ){ /* Reset the return code so as not to report a checkpoint failure ** just because active readers prevent any backfill. */ rc = SQLITE_OK; } walIteratorFree(pIter); return rc; } /* ** Close a connection to a log file. */ | > | 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 | }else if( rc==SQLITE_BUSY ){ /* Reset the return code so as not to report a checkpoint failure ** just because active readers prevent any backfill. */ rc = SQLITE_OK; } walcheckpoint_out: walIteratorFree(pIter); return rc; } /* ** Close a connection to a log file. */ |
︙ | ︙ |
Changes to test/wal3.test.
︙ | ︙ | |||
105 106 107 108 109 110 111 112 113 | } $str do_test wal3-1.$i.7 { execsql { PRAGMA integrity_check } db2 } {ok} db2 close } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 191 192 193 194 195 196 | } $str do_test wal3-1.$i.7 { execsql { PRAGMA integrity_check } db2 } {ok} db2 close } db close foreach code [list { proc code2 {tcl} { uplevel #0 $tcl } proc code3 {tcl} { uplevel #0 $tcl } set tn singleproc } { set ::code2_chan [launch_testfixture] set ::code3_chan [launch_testfixture] proc code2 {tcl} { testfixture $::code2_chan $tcl } proc code3 {tcl} { testfixture $::code3_chan $tcl } set tn multiproc }] { file delete -force test.db test.db-wal test.db-journal sqlite3 db test.db eval $code # Open connections [db2] and [db3]. Depending on which iteration this # is, the connections may be created in this interpreter, or in # interpreters running in other OS processes. As such, the [db2] and [db3] # commands should only be accessed within [code2] and [code3] blocks, # respectively. # code2 { sqlite3 db2 test.db ; db2 eval { PRAGMA journal_mode = WAL } } code3 { sqlite3 db3 test.db ; db3 eval { PRAGMA journal_mode = WAL } } # Shorthand commands. Execute SQL using database connection [db], [db2] # or [db3]. Return the results. # proc sql {sql} { db eval $sql } proc sql2 {sql} { code2 [list db2 eval $sql] } proc sql3 {sql} { code3 [list db3 eval $sql] } do_test wal3-2.$tn.1 { sql { PRAGMA page_size = 1024; PRAGMA auto_vacuum = OFF; PRAGMA journal_mode = WAL; } sql { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 'one'); BEGIN; SELECT * FROM t1; } } {1 one} do_test wal3-2.$tn.2 { sql2 { CREATE TABLE t2(a, b); INSERT INTO t2 VALUES(2, 'two'); BEGIN; SELECT * FROM t2; } } {2 two} do_test wal3-2.$tn.3 { sql3 { CREATE TABLE t3(a, b); INSERT INTO t3 VALUES(3, 'three'); BEGIN; SELECT * FROM t3; } } {3 three} # Try to checkpoint the database using [db]. It should be possible to # checkpoint everything except the frames added by [db3] (checkpointing # these frames would clobber the snapshot currently being used by [db2]). # do_test wal3-2.$tn.4 { sql { COMMIT; PRAGMA wal_checkpoint; } } {} do_test wal3-2.$tn.5 { file size test.db } [expr 3*1024] catch { db close } catch { code2 { db2 close } } catch { code3 { db3 close } } catch { close $::code2_chan } catch { close $::code3_chan } } finish_test |
Changes to test/walfault.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # focus of this file is testing the operation of the library in # "PRAGMA journal_mode=WAL" mode. # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/malloc_common.tcl ifcapable !wal {finish_test ; return } #------------------------------------------------------------------------- # This test case, walfault-1-*, simulates faults while executing a # # PRAGMA journal_mode = WAL; | > | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # focus of this file is testing the operation of the library in # "PRAGMA journal_mode=WAL" mode. # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/malloc_common.tcl source $testdir/lock_common.tcl ifcapable !wal {finish_test ; return } #------------------------------------------------------------------------- # This test case, walfault-1-*, simulates faults while executing a # # PRAGMA journal_mode = WAL; |
︙ | ︙ | |||
317 318 319 320 321 322 323 | catch { db eval { ROLLBACK TO spoint } } catch { db eval { COMMIT } } set n [db one {SELECT count(*) FROM abc}] if {$n != 1 && $n != 2} { error "Incorrect number of rows: $n" } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 318 319 320 321 322 323 324 325 326 | catch { db eval { ROLLBACK TO spoint } } catch { db eval { COMMIT } } set n [db one {SELECT count(*) FROM abc}] if {$n != 1 && $n != 2} { error "Incorrect number of rows: $n" } } finish_test |