Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix a problem causing sqlite3_snapshot_recover() to return SQLITE_IOERR_SHORT_READ. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | serializable-snapshot |
Files: | files | file ages | folders |
SHA1: |
525f75fa9fd4a95acc3fb3b0a01dabe2 |
User & Date: | dan 2016-11-19 16:35:53.322 |
Context
2016-11-19
| ||
17:20 | Add another fault-injection test for sqlite3_snapshot_recover(). (check-in: 7e04040613 user: dan tags: serializable-snapshot) | |
16:35 | Fix a problem causing sqlite3_snapshot_recover() to return SQLITE_IOERR_SHORT_READ. (check-in: 525f75fa9f user: dan tags: serializable-snapshot) | |
14:53 | Fix a bug in sqlite3_snapshot_recover() that could cause subsequent read transactions to use out-of-data cache entries. (check-in: 9abeb7980a user: dan tags: serializable-snapshot) | |
Changes
Changes to src/wal.c.
︙ | ︙ | |||
2388 2389 2390 2391 2392 2393 2394 | rc = sqlite3WalBeginReadTransaction(pWal, &dummy); if( rc==SQLITE_OK ){ rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1); if( rc==SQLITE_OK ){ volatile WalCkptInfo *pInfo = walCkptInfo(pWal); int szPage = (int)pWal->szPage; | > > > > | | < | | | | | | | | | | | < > | > > | | | < | | | | | | | > | | | | | > | 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 | rc = sqlite3WalBeginReadTransaction(pWal, &dummy); if( rc==SQLITE_OK ){ rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1); if( rc==SQLITE_OK ){ volatile WalCkptInfo *pInfo = walCkptInfo(pWal); int szPage = (int)pWal->szPage; i64 szDb; /* Size of db file in bytes */ rc = sqlite3OsFileSize(pWal->pDbFd, &szDb); if( rc==SQLITE_OK ){ void *pBuf1 = sqlite3_malloc(szPage); void *pBuf2 = sqlite3_malloc(szPage); if( pBuf1==0 || pBuf2==0 ){ rc = SQLITE_NOMEM; }else{ u32 i = pInfo->nBackfillAttempted; for(i=pInfo->nBackfillAttempted; i>pInfo->nBackfill; i--){ volatile ht_slot *dummy; volatile u32 *aPgno; /* Array of page numbers */ u32 iZero; /* Frame corresponding to aPgno[0] */ u32 pgno; /* Page number in db file */ i64 iDbOff; /* Offset of db file entry */ i64 iWalOff; /* Offset of wal file entry */ rc = walHashGet(pWal, walFramePage(i), &dummy, &aPgno, &iZero); if( rc!=SQLITE_OK ) break; pgno = aPgno[i-iZero]; iDbOff = (i64)(pgno-1) * szPage; if( iDbOff+szPage<=szDb ){ iWalOff = walFrameOffset(i, szPage) + WAL_FRAME_HDRSIZE; rc = sqlite3OsRead(pWal->pWalFd, pBuf1, szPage, iWalOff); if( rc==SQLITE_OK ){ rc = sqlite3OsRead(pWal->pDbFd, pBuf2, szPage, iDbOff); } if( rc!=SQLITE_OK || 0==memcmp(pBuf1, pBuf2, szPage) ){ break; } } pInfo->nBackfillAttempted = i-1; } } sqlite3_free(pBuf1); sqlite3_free(pBuf2); } walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1); } /* End the read transaction opened above. Also zero the cache of the ** wal-index header to force the pager-cache to be flushed when the next ** read transaction is open, as it may not match the current contents of ** pWal->hdr. */ |
︙ | ︙ |
Changes to test/snapshot_fault.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # of this file is the sqlite3_snapshot_xxx() APIs. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !snapshot {finish_test; return} set testprefix snapshot_fault #------------------------------------------------------------------------- # Check that an sqlite3_snapshot_open() client cannot be tricked into # reading a corrupt snapshot even if a second client fails while # checkpointing the db. # do_faultsim_test 1.0 -prep { | > > | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | # of this file is the sqlite3_snapshot_xxx() APIs. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !snapshot {finish_test; return} set testprefix snapshot_fault if 1 { #------------------------------------------------------------------------- # Check that an sqlite3_snapshot_open() client cannot be tricked into # reading a corrupt snapshot even if a second client fails while # checkpointing the db. # do_faultsim_test 1.0 -prep { |
︙ | ︙ | |||
155 156 157 158 159 160 161 | }] if {$res != "1 2 3 ok"} { error "res is $res" } } sqlite3_snapshot_free $::snapshot } | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | }] if {$res != "1 2 3 ok"} { error "res is $res" } } sqlite3_snapshot_free $::snapshot } } #------------------------------------------------------------------------- # Test the handling of faults that occur within sqlite3_snapshot_recover(). # reset_db do_execsql_test 4.0 { PRAGMA journal_mode = wal; CREATE TABLE t1(zzz); INSERT INTO t1 VALUES('abc'); INSERT INTO t1 VALUES('def'); } {wal} faultsim_save_and_close do_test 4.1 { faultsim_restore_and_reopen db eval { SELECT * FROM sqlite_master } sqlite3_snapshot_recover db main } {} db close do_faultsim_test 4 -faults oom* -prep { faultsim_restore_and_reopen db eval { SELECT * FROM sqlite_master } } -body { sqlite3_snapshot_recover db main } -test { faultsim_test_result {0 {}} {1 SQLITE_NOMEM} {1 SQLITE_IOERR_NOMEM} } finish_test |