Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add some tests and fixes surrounding exclusive-access mode and the pager change-counter. (CVS 3716) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
72cb2e1a73cd09d32900bb473377f66f |
User & Date: | danielk1977 2007-03-26 10:27:19.000 |
Context
2007-03-26
| ||
12:26 | Run some malloc() tests with exclusive-access mode. (CVS 3717) (check-in: 1274549037 user: danielk1977 tags: trunk) | |
10:27 | Add some tests and fixes surrounding exclusive-access mode and the pager change-counter. (CVS 3716) (check-in: 72cb2e1a73 user: danielk1977 tags: trunk) | |
08:41 | Add some documentation for pragma locking_mode. (CVS 3715) (check-in: 394b174e59 user: danielk1977 tags: trunk) | |
Changes
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.296 2007/03/26 10:27:19 danielk1977 Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" #include "os.h" #include "pager.h" #include <assert.h> #include <string.h> |
︙ | ︙ | |||
923 924 925 926 927 928 929 | int rc = SQLITE_OK; assert( !MEMDB ); if( pPager->state<PAGER_RESERVED ){ return SQLITE_OK; } sqlite3PagerStmtCommit(pPager); if( pPager->stmtOpen && !pPager->exclusiveMode ){ | | | 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 | int rc = SQLITE_OK; assert( !MEMDB ); if( pPager->state<PAGER_RESERVED ){ return SQLITE_OK; } sqlite3PagerStmtCommit(pPager); if( pPager->stmtOpen && !pPager->exclusiveMode ){ if( !pPager->exclusiveMode ){ sqlite3OsClose(&pPager->stfd); pPager->stmtOpen = 0; }else{ sqlite3OsTruncate(pPager->stfd, 0); } } if( pPager->journalOpen ){ |
︙ | ︙ | |||
3893 3894 3895 3896 3897 3898 3899 | ** stored at byte 24 of the pager file. */ static int pager_incr_changecounter(Pager *pPager){ PgHdr *pPgHdr; u32 change_counter; int rc; | > | | | | | | | | | | | | | | | | | > | 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 | ** stored at byte 24 of the pager file. */ static int pager_incr_changecounter(Pager *pPager){ PgHdr *pPgHdr; u32 change_counter; int rc; if( !pPager->changeCountDone ){ /* Open page 1 of the file for writing. */ rc = sqlite3PagerGet(pPager, 1, &pPgHdr); if( rc!=SQLITE_OK ) return rc; rc = sqlite3PagerWrite(pPgHdr); if( rc!=SQLITE_OK ) return rc; /* Read the current value at byte 24. */ change_counter = retrieve32bits(pPgHdr, 24); /* Increment the value just read and write it back to byte 24. */ change_counter++; put32bits(((char*)PGHDR_TO_DATA(pPgHdr))+24, change_counter); pPager->iChangeCount = change_counter; /* Release the page reference. */ sqlite3PagerUnref(pPgHdr); pPager->changeCountDone = 1; } return SQLITE_OK; } /* ** Sync the database file for the pager pPager. zMaster points to the name ** of a master journal file that should be written into the individual ** journal file. zMaster may be NULL, which is interpreted as no master |
︙ | ︙ |
Changes to test/exclusive.test.
1 2 3 4 5 6 7 8 9 10 | # 2007 March 24 # # 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 | # 2007 March 24 # # 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 these tests is exclusive access mode (i.e. the thing activated by # "PRAGMA locking_mode = EXCLUSIVE"). # # $Id: exclusive.test,v 1.3 2007/03/26 10:27:19 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {!pager_pragmas} { finish_test return |
︙ | ︙ |
Added test/exclusive2.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 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 | # 2007 March 24 # # 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. # # $Id: exclusive2.test,v 1.1 2007/03/26 10:27:19 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {!pager_pragmas} { finish_test return } proc pagerChangeCounter {filename {new ""}} { set fd [open $filename a+] fconfigure $fd -translation binary -encoding binary if {$new ne ""} { seek $fd 24 set a [expr {($new&0xFF000000)>>24}] set b [expr {($new&0x00FF0000)>>16}] set c [expr {($new&0x0000FF00)>>8}] set d [expr {($new&0x000000FF)}] puts $fd [binary format cccc $a $b $c $d] } seek $fd 24 foreach {a b c d} [list 0 0 0 0] {} binary scan [read $fd 4] cccc a b c d set ret [expr ($a&0x000000FF)<<24] incr ret [expr ($b&0x000000FF)<<16] incr ret [expr ($c&0x000000FF)<<8] incr ret [expr ($d&0x000000FF)<<0] close $fd return $ret } proc t1sig {{db db}} { execsql {SELECT count(*), md5sum(a) FROM t1} $db } do_test exclusive2-1.0 { pagerChangeCounter test.db } {0} #----------------------------------------------------------------------- # The following tests - exclusive2-1.X - check that: # # 1-3: Build a database with connection 1, calculate a signature. # 4-9: Modify the database using a second connection, then reset # the pager change-counter to the value it had before the modifications. # 8: Check that using the first connection, the database signature # is still the same. This is because it uses the in-memory cache. # It can't tell the db has changed because we reset the change-counter. # 9: Increment the change-counter. # 10: Ensure that the first connection now sees the updated database. It # sees the change-counter has been incremented and discards the # invalid in-memory cache. # do_test exclusive2-1.1 { execsql { BEGIN; CREATE TABLE t1(a UNIQUE); INSERT INTO t1 VALUES(randstr(10, 400)); INSERT INTO t1 VALUES(randstr(10, 400)); INSERT INTO t1 SELECT randstr(10, 400) FROM t1; INSERT INTO t1 SELECT randstr(10, 400) FROM t1; INSERT INTO t1 SELECT randstr(10, 400) FROM t1; INSERT INTO t1 SELECT randstr(10, 400) FROM t1; INSERT INTO t1 SELECT randstr(10, 400) FROM t1; COMMIT; SELECT count(*) FROM t1; } } {64} do_test exclusive2-1.2 { set ::sig [t1sig] pagerChangeCounter test.db } {1} do_test exclusive2-1.3 { t1sig } $::sig do_test exclusive2-1.4 { sqlite3 db2 test.db t1sig db2 } $::sig do_test exclusive2-1.5 { execsql { DELETE FROM t1; } db2 expr {[t1sig db2] eq $::sig} } 0 do_test exclusive2-1.6 { pagerChangeCounter test.db } {2} do_test exclusive2-1.7 { pagerChangeCounter test.db 1 } {1} do_test exclusive2-1.9 { t1sig expr {[t1sig] eq $::sig} } {1} do_test exclusive2-1.10 { pagerChangeCounter test.db 2 } {2} do_test exclusive2-1.11 { expr {[t1sig] eq $::sig} } {0} #-------------------------------------------------------------------- # These tests - exclusive2-2.X - are similar to exclusive2-1.X, # except that they are run with locking_mode=EXCLUSIVE. # # 1-3: Build a database with exclusive-access connection 1, # calculate a signature. # 4: Corrupt the database by writing 10000 bytes of garbage # starting at the beginning of page 2. Check that connection 1 # still works. It should be accessing the in-memory cache. # 5-6: Modify the dataase change-counter. Connection 1 still works # entirely from in-memory cache, because it doesn't check the # change-counter. # 7-8 Set the locking-mode back to normal. After the db is unlocked, # SQLite detects the modified change-counter and discards the # in-memory cache. Then it finds the corruption caused in step 4.... # do_test exclusive2-2.1 { execsql {PRAGMA locking_mode = exclusive;} execsql { BEGIN; INSERT INTO t1 VALUES(randstr(10, 400)); INSERT INTO t1 VALUES(randstr(10, 400)); INSERT INTO t1 SELECT randstr(10, 400) FROM t1; INSERT INTO t1 SELECT randstr(10, 400) FROM t1; INSERT INTO t1 SELECT randstr(10, 400) FROM t1; INSERT INTO t1 SELECT randstr(10, 400) FROM t1; INSERT INTO t1 SELECT randstr(10, 400) FROM t1; COMMIT; SELECT count(*) FROM t1; } } {64} do_test exclusive2-2.2 { set ::sig [t1sig] pagerChangeCounter test.db } {3} do_test exclusive2-2.3 { t1sig } $::sig do_test exclusive2-2.4 { set fd [open test.db a] seek $fd 1024 puts -nonewline $fd [string repeat [binary format c 0] 10000] t1sig } $::sig do_test exclusive2-2.5 { pagerChangeCounter test.db 5 } {5} do_test exclusive2-2.6 { t1sig } $::sig do_test exclusive2-2.7 { execsql {PRAGMA locking_mode = normal} t1sig } $::sig do_test exclusive2-2.8 { set rc [catch {t1sig} msg] list $rc $msg } {1 {database disk image is malformed}} #-------------------------------------------------------------------- # These tests - exclusive2-3.X - verify that the pager change-counter # is only incremented by the first change when in exclusive access # mode. In normal mode, the change-counter is incremented once # per write-transaction. # db close db2 close file delete -force test.db file delete -force test.db-journal do_test exclusive2-3.0 { sqlite3 db test.db execsql { BEGIN; CREATE TABLE t1(a UNIQUE); INSERT INTO t1 VALUES(randstr(10, 400)); INSERT INTO t1 VALUES(randstr(10, 400)); COMMIT; } pagerChangeCounter test.db } {1} do_test exclusive2-3.1 { execsql { INSERT INTO t1 VALUES(randstr(10, 400)); } pagerChangeCounter test.db } {2} do_test exclusive2-3.2 { execsql { INSERT INTO t1 VALUES(randstr(10, 400)); } pagerChangeCounter test.db } {3} do_test exclusive2-3.3 { execsql { PRAGMA locking_mode = exclusive; INSERT INTO t1 VALUES(randstr(10, 400)); } pagerChangeCounter test.db } {4} do_test exclusive2-3.4 { execsql { INSERT INTO t1 VALUES(randstr(10, 400)); } pagerChangeCounter test.db } {4} do_test exclusive2-3.5 { execsql { PRAGMA locking_mode = normal; INSERT INTO t1 VALUES(randstr(10, 400)); } pagerChangeCounter test.db } {4} do_test exclusive2-3.6 { execsql { INSERT INTO t1 VALUES(randstr(10, 400)); } pagerChangeCounter test.db } {5} finish_test |