Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add tests to ensure that an sqlite3_snapshot_open() client cannot be tricked into reading a corrupt snapshot even if another process fails mid-checkpoint. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | snapshot-get |
Files: | files | file ages | folders |
SHA1: |
b908048b6cfa1ee2fe1f7a17bae475dd |
User & Date: | dan 2015-12-10 18:06:21.050 |
Context
2015-12-10
| ||
19:11 | Return SQLITE_BUSY (not SQLITE_BUSY_SNAPSHOT) if sqlite3_snapshot_open() fails to obtain the shared checkpointer lock. (check-in: 5343060bcc user: dan tags: snapshot-get) | |
18:06 | Add tests to ensure that an sqlite3_snapshot_open() client cannot be tricked into reading a corrupt snapshot even if another process fails mid-checkpoint. (check-in: b908048b6c user: dan tags: snapshot-get) | |
15:45 | Have sqlite3_snapshot_open() avoid a race condition by taking a shared CHECKPOINTER lock while checking pInfo->nBackfillAttempted. (check-in: 8084eae0bc user: dan tags: snapshot-get) | |
Changes
Changes to test/snapshot.test.
1 2 3 4 5 6 7 8 9 10 | # 2015 December 7 # # 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 | # 2015 December 7 # # 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 implements regression tests for SQLite library. The focus # of this file is the sqlite3_snapshot_xxx() APIs. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix snapshot #------------------------------------------------------------------------- # Check some error conditions in snapshot_get(). It is an error if: |
︙ | ︙ |
Added test/snapshot_fault.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 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 | # 2015 December 10 # # 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 implements regression tests for SQLite library. The focus # of this file is the sqlite3_snapshot_xxx() APIs. # set testdir [file dirname $argv0] source $testdir/tester.tcl 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 { faultsim_delete_and_reopen sqlite3 db2 test.db db2 eval { CREATE TABLE t1(a, b UNIQUE, c UNIQUE); INSERT INTO t1 VALUES(1, randomblob(500), randomblob(500)); INSERT INTO t1 VALUES(2, randomblob(500), randomblob(500)); PRAGMA journal_mode = wal; INSERT INTO t1 VALUES(3, randomblob(500), randomblob(500)); BEGIN; SELECT a FROM t1; } set ::snapshot [sqlite3_snapshot_get db2 main] db2 eval COMMIT db2 eval { UPDATE t1 SET b=randomblob(501), c=randomblob(501) WHERE a=1; INSERT INTO t1 VALUES(4, randomblob(500), randomblob(500)); INSERT INTO t1 VALUES(5, randomblob(500), randomblob(500)); INSERT INTO t1 VALUES(6, randomblob(500), randomblob(500)); } } -body { db eval { PRAGMA wal_checkpoint } } -test { db2 eval BEGIN if {[catch { sqlite3_snapshot_open db2 main $::snapshot } msg]} { if {$msg != "SQLITE_BUSY_SNAPSHOT" && $msg != "SQLITE_BUSY"} { error "error is $msg" } } else { set res [db2 eval { SELECT a FROM t1; PRAGMA integrity_check; }] if {$res != "1 2 3 ok"} { error "res is $res" } } sqlite3_snapshot_free $::snapshot } #------------------------------------------------------------------------- # This test is similar to the previous one. Except, after the # "PRAGMA wal_checkpoint" command fails the db is closed and reopened # so as to require wal file recovery. It should not be possible to open # a snapshot that is part of the body of a recovered wal file. # do_faultsim_test 2.0 -prep { faultsim_delete_and_reopen db eval { CREATE TABLE t1(a, b UNIQUE, c UNIQUE); INSERT INTO t1 VALUES(1, randomblob(500), randomblob(500)); INSERT INTO t1 VALUES(2, randomblob(500), randomblob(500)); PRAGMA journal_mode = wal; INSERT INTO t1 VALUES(3, randomblob(500), randomblob(500)); BEGIN; SELECT a FROM t1; } set ::snapshot [sqlite3_snapshot_get db main] db eval COMMIT db eval { UPDATE t1 SET b=randomblob(501), c=randomblob(501) WHERE a=1; INSERT INTO t1 VALUES(4, randomblob(500), randomblob(500)); INSERT INTO t1 VALUES(5, randomblob(500), randomblob(500)); INSERT INTO t1 VALUES(6, randomblob(500), randomblob(500)); } } -body { db eval { PRAGMA wal_checkpoint } } -test { db_save db close db_restore_and_reopen db eval { SELECT * FROM t1 } db eval BEGIN if {[catch { sqlite3_snapshot_open db main $::snapshot } msg]} { if {$msg != "SQLITE_BUSY_SNAPSHOT" && $msg != "SQLITE_BUSY"} { error "error is $msg" } } else { # This branch should actually never be taken. But it was useful in # determining whether or not this test was actually working (by # running a modified version of SQLite that allowed snapshots to be # opened following a recovery). error "TEST HAS FAILED" set res [db eval { SELECT a FROM t1; PRAGMA integrity_check; }] if {$res != "1 2 3 ok"} { error "res is $res" } } sqlite3_snapshot_free $::snapshot } #------------------------------------------------------------------------- # Test the handling of faults that occur within sqlite3_snapshot_open(). # do_faultsim_test 3.0 -prep { faultsim_delete_and_reopen db eval { CREATE TABLE t1(a, b UNIQUE, c UNIQUE); INSERT INTO t1 VALUES(1, randomblob(500), randomblob(500)); INSERT INTO t1 VALUES(2, randomblob(500), randomblob(500)); PRAGMA journal_mode = wal; INSERT INTO t1 VALUES(3, randomblob(500), randomblob(500)); BEGIN; SELECT a FROM t1; } set ::snapshot [sqlite3_snapshot_get db main] db eval COMMIT db eval { UPDATE t1 SET b=randomblob(501), c=randomblob(501) WHERE a=1; INSERT INTO t1 VALUES(4, randomblob(500), randomblob(500)); INSERT INTO t1 VALUES(5, randomblob(500), randomblob(500)); INSERT INTO t1 VALUES(6, randomblob(500), randomblob(500)); BEGIN; } } -body { if { [catch { sqlite3_snapshot_open db main $::snapshot } msg] } { error $msg } } -test { faultsim_test_result {0 {}} {1 SQLITE_IOERR} \ {1 SQLITE_IOERR_NOMEM} {1 SQLITE_IOERR_READ} if {$testrc==0} { set res [db eval { SELECT a FROM t1; PRAGMA integrity_check; }] if {$res != "1 2 3 ok"} { error "res is $res" } } sqlite3_snapshot_free $::snapshot } finish_test |