1: # 2007 March 24
2: #
3: # The author disclaims copyright to this source code. In place of
4: # a legal notice, here is a blessing:
5: #
6: # May you do good and not evil.
7: # May you find forgiveness for yourself and forgive others.
8: # May you share freely, never taking more than you give.
9: #
10: #***********************************************************************
11: # This file implements regression tests for SQLite library.
12: #
13: # $Id: exclusive2.test,v 1.1.1.1 2012/02/21 17:04:16 misho Exp $
14:
15: set testdir [file dirname $argv0]
16: source $testdir/tester.tcl
17:
18: # Do not use a codec for tests in this file, as the database file is
19: # manipulated directly using tcl scripts (using the [hexio_write] command).
20: #
21: do_not_use_codec
22:
23: ifcapable {!pager_pragmas} {
24: finish_test
25: return
26: }
27:
28: # This module does not work right if the cache spills at unexpected
29: # moments. So disable the soft-heap-limit.
30: #
31: sqlite3_soft_heap_limit 0
32:
33: proc pagerChangeCounter {filename new {fd ""}} {
34: if {$fd==""} {
35: set fd [open $filename RDWR]
36: fconfigure $fd -translation binary -encoding binary
37: set needClose 1
38: } else {
39: set needClose 0
40: }
41: if {$new ne ""} {
42: seek $fd 24
43: set a [expr {($new&0xFF000000)>>24}]
44: set b [expr {($new&0x00FF0000)>>16}]
45: set c [expr {($new&0x0000FF00)>>8}]
46: set d [expr {($new&0x000000FF)}]
47: puts -nonewline $fd [binary format cccc $a $b $c $d]
48: flush $fd
49: }
50:
51: seek $fd 24
52: foreach {a b c d} [list 0 0 0 0] {}
53: binary scan [read $fd 4] cccc a b c d
54: set ret [expr ($a&0x000000FF)<<24]
55: incr ret [expr ($b&0x000000FF)<<16]
56: incr ret [expr ($c&0x000000FF)<<8]
57: incr ret [expr ($d&0x000000FF)<<0]
58:
59: if {$needClose} {close $fd}
60: return $ret
61: }
62:
63: proc readPagerChangeCounter {filename} {
64: set fd [open $filename RDONLY]
65: fconfigure $fd -translation binary -encoding binary
66:
67: seek $fd 24
68: foreach {a b c d} [list 0 0 0 0] {}
69: binary scan [read $fd 4] cccc a b c d
70: set ret [expr ($a&0x000000FF)<<24]
71: incr ret [expr ($b&0x000000FF)<<16]
72: incr ret [expr ($c&0x000000FF)<<8]
73: incr ret [expr ($d&0x000000FF)<<0]
74:
75: close $fd
76: return $ret
77: }
78:
79:
80: proc t1sig {{db db}} {
81: execsql {SELECT count(*), md5sum(a) FROM t1} $db
82: }
83: do_test exclusive2-1.0 {
84: readPagerChangeCounter test.db
85: } {0}
86:
87: #-----------------------------------------------------------------------
88: # The following tests - exclusive2-1.X - check that:
89: #
90: # 1-3: Build a database with connection 1, calculate a signature.
91: # 4-7: Modify the database using a second connection in a way that
92: # does not modify the freelist, then reset the pager change-counter
93: # to the value it had before the modifications.
94: # 8: Check that using the first connection, the database signature
95: # is still the same. This is because it uses the in-memory cache.
96: # It can't tell the db has changed because we reset the change-counter.
97: # 9: Increment the change-counter.
98: # 10: Ensure that the first connection now sees the updated database. It
99: # sees the change-counter has been incremented and discards the
100: # invalid in-memory cache.
101: #
102: # This will only work if the database cache is large enough to hold
103: # the entire database. In the case of 1024 byte pages, this means
104: # the cache size must be at least 17. Otherwise, some pages will be
105: # loaded from the database file in step 8.
106: #
107: # For similar reasons, this test does not work with the memsubsys1 permutation.
108: # Permutation memsubsys1 configures the pcache subsystem to use a static
109: # allocation of 24 pages (shared between all pagers). This is not enough for
110: # this test.
111: #
112: do_test exclusive2-1.1 {
113: execsql {
114: BEGIN;
115: CREATE TABLE t1(a, b);
116: INSERT INTO t1(a) VALUES(randstr(10, 400));
117: INSERT INTO t1(a) VALUES(randstr(10, 400));
118: INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
119: INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
120: INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
121: INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
122: INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
123: COMMIT;
124: SELECT count(*) FROM t1;
125: }
126: } {64}
127: do_test exclusive2-1.2.1 {
128: # Make sure the pager cache is large enough to store the
129: # entire database.
130: set nPage [expr [file size test.db]/1024]
131: if {$::SQLITE_DEFAULT_CACHE_SIZE < $nPage} {
132: execsql "PRAGMA cache_size = $nPage"
133: }
134: expr {[execsql {PRAGMA cache_size}] >= $nPage}
135: } {1}
136: do_test exclusive2-1.2 {
137: set ::sig [t1sig]
138: readPagerChangeCounter test.db
139: } {1}
140: do_test exclusive2-1.3 {
141: t1sig
142: } $::sig
143: do_test exclusive2-1.4 {
144: sqlite3 db2 test.db
145: t1sig db2
146: } $::sig
147: do_test exclusive2-1.5 {
148: execsql {
149: UPDATE t1 SET b=a, a=NULL;
150: } db2
151: expr {[t1sig db2] eq $::sig}
152: } 0
153: do_test exclusive2-1.6 {
154: readPagerChangeCounter test.db
155: } {2}
156: do_test exclusive2-1.7 {
157: pagerChangeCounter test.db 1
158: } {1}
159: if {[permutation] != "memsubsys1"} {
160: do_test exclusive2-1.9 {
161: t1sig
162: expr {[t1sig] eq $::sig}
163: } {1}
164: }
165: do_test exclusive2-1.10 {
166: pagerChangeCounter test.db 2
167: } {2}
168: do_test exclusive2-1.11 {
169: expr {[t1sig] eq $::sig}
170: } {0}
171: db2 close
172:
173: #--------------------------------------------------------------------
174: # These tests - exclusive2-2.X - are similar to exclusive2-1.X,
175: # except that they are run with locking_mode=EXCLUSIVE.
176: #
177: # 1-3: Build a database with exclusive-access connection 1,
178: # calculate a signature.
179: # 4: Corrupt the database by writing 10000 bytes of garbage
180: # starting at the beginning of page 2. Check that connection 1
181: # still works. It should be accessing the in-memory cache.
182: # 5-6: Modify the dataase change-counter. Connection 1 still works
183: # entirely from in-memory cache, because it doesn't check the
184: # change-counter.
185: # 7-8 Set the locking-mode back to normal. After the db is unlocked,
186: # SQLite detects the modified change-counter and discards the
187: # in-memory cache. Then it finds the corruption caused in step 4....
188: #
189: # As above, this test is only applicable if the pager cache is
190: # large enough to hold the entire database. With 1024 byte pages,
191: # this means 19 pages. We also need to disable the soft-heap-limit
192: # to prevent memory-induced cache spills.
193: #
194: do_test exclusive2-2.1 {
195: execsql {PRAGMA cache_size=1000;}
196: execsql {PRAGMA locking_mode = exclusive;}
197: execsql {
198: BEGIN;
199: DELETE FROM t1;
200: INSERT INTO t1(a) VALUES(randstr(10, 400));
201: INSERT INTO t1(a) VALUES(randstr(10, 400));
202: INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
203: INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
204: INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
205: INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
206: INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
207: COMMIT;
208: SELECT count(*) FROM t1;
209: }
210: } {64}
211: do_test exclusive2-2.2.1 {
212: # Make sure the pager cache is large enough to store the
213: # entire database.
214: set nPage [expr [file size test.db]/1024]
215: if {$::SQLITE_DEFAULT_CACHE_SIZE < $nPage} {
216: execsql "PRAGMA cache_size = $nPage"
217: }
218: expr {[execsql {PRAGMA cache_size}] >= $nPage}
219: } {1}
220: do_test exclusive2-2.2 {
221: set ::sig [t1sig]
222: readPagerChangeCounter test.db
223: } {3}
224: do_test exclusive2-2.3 {
225: t1sig
226: } $::sig
227:
228: do_test exclusive2-2.4 {
229: set ::fd [open test.db RDWR]
230: fconfigure $::fd -translation binary
231: seek $::fd 1024
232: puts -nonewline $::fd [string repeat [binary format c 0] 10000]
233: flush $::fd
234: t1sig
235: } $::sig
236:
237: do_test exclusive2-2.5 {
238: pagerChangeCounter test.db 5 $::fd
239: } {5}
240: do_test exclusive2-2.6 {
241: t1sig
242: } $::sig
243: do_test exclusive2-2.7 {
244: execsql {PRAGMA locking_mode = normal}
245: t1sig
246: } $::sig
247:
248: do_test exclusive2-2.8 {
249: set rc [catch {t1sig} msg]
250: list $rc $msg
251: } {1 {database disk image is malformed}}
252:
253: #--------------------------------------------------------------------
254: # These tests - exclusive2-3.X - verify that the pager change-counter
255: # is only incremented by the first change when in exclusive access
256: # mode. In normal mode, the change-counter is incremented once
257: # per write-transaction.
258: #
259:
260: db close
261: catch {close $::fd}
262: forcedelete test.db
263: forcedelete test.db-journal
264:
265: do_test exclusive2-3.0 {
266: sqlite3 db test.db
267: execsql {
268: BEGIN;
269: CREATE TABLE t1(a UNIQUE);
270: INSERT INTO t1 VALUES(randstr(200, 200));
271: INSERT INTO t1 VALUES(randstr(200, 200));
272: COMMIT;
273: }
274: readPagerChangeCounter test.db
275: } {1}
276: do_test exclusive2-3.1 {
277: execsql {
278: INSERT INTO t1 VALUES(randstr(200, 200));
279: }
280: readPagerChangeCounter test.db
281: } {2}
282: do_test exclusive2-3.2 {
283: execsql {
284: INSERT INTO t1 VALUES(randstr(200, 200));
285: }
286: readPagerChangeCounter test.db
287: } {3}
288: do_test exclusive2-3.3 {
289: execsql {
290: PRAGMA locking_mode = exclusive;
291: INSERT INTO t1 VALUES(randstr(200, 200));
292: }
293: readPagerChangeCounter test.db
294: } {4}
295: do_test exclusive2-3.4 {
296: breakpoint
297: execsql {
298: INSERT INTO t1 VALUES(randstr(200, 200));
299: }
300: readPagerChangeCounter test.db
301: } {4}
302: do_test exclusive2-3.5 {
303: execsql {
304: PRAGMA locking_mode = normal;
305: INSERT INTO t1 VALUES(randstr(200, 200));
306: }
307: readPagerChangeCounter test.db
308: } {4}
309: do_test exclusive2-3.6 {
310: execsql {
311: INSERT INTO t1 VALUES(randstr(200, 200));
312: }
313: readPagerChangeCounter test.db
314: } {5}
315: sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit)
316:
317: finish_test
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>