OLD | NEW |
| (Empty) |
1 # 2013 March 20 | |
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 # | |
12 | |
13 set testdir [file dirname $argv0] | |
14 source $testdir/tester.tcl | |
15 ifcapable !mmap { | |
16 finish_test | |
17 return | |
18 } | |
19 source $testdir/lock_common.tcl | |
20 set testprefix mmap1 | |
21 | |
22 proc nRead {db} { | |
23 set bt [btree_from_db $db] | |
24 db_enter $db | |
25 array set stats [btree_pager_stats $bt] | |
26 db_leave $db | |
27 # puts [array get stats] | |
28 return $stats(read) | |
29 } | |
30 | |
31 proc register_rblob_code {dbname seed} { | |
32 return [subst -nocommands { | |
33 set ::rcnt $seed | |
34 proc rblob {n} { | |
35 set ::rcnt [expr (([set ::rcnt] << 3) + [set ::rcnt] + 456) & 0xFFFFFFFF] | |
36 set str [format %.8x [expr [set ::rcnt] ^ 0xbdf20da3]] | |
37 string range [string repeat [set str] [expr [set n]/4]] 1 [set n] | |
38 } | |
39 $dbname func rblob rblob | |
40 }] | |
41 } | |
42 | |
43 # For cases 1.1 and 1.4, the number of pages read using xRead() is 4 on | |
44 # unix and 9 on windows. The difference is that windows only ever maps | |
45 # an integer number of OS pages (i.e. creates mappings that are a multiple | |
46 # of 4KB in size). Whereas on unix any sized mapping may be created. | |
47 # | |
48 foreach {t mmap_size nRead c2init} { | |
49 1.1 { PRAGMA mmap_size = 67108864 } /[49]/ {PRAGMA mmap_size = 0} | |
50 1.2 { PRAGMA mmap_size = 53248 } 150 {PRAGMA mmap_size = 0} | |
51 1.3 { PRAGMA mmap_size = 0 } 344 {PRAGMA mmap_size = 0} | |
52 1.4 { PRAGMA mmap_size = 67108864 } /[49]/ {PRAGMA mmap_size = 67108864 } | |
53 1.5 { PRAGMA mmap_size = 53248 } 150 {PRAGMA mmap_size = 67108864 } | |
54 1.6 { PRAGMA mmap_size = 0 } 344 {PRAGMA mmap_size = 67108864 } | |
55 } { | |
56 | |
57 do_multiclient_test tn { | |
58 sql1 {PRAGMA cache_size=2000} | |
59 sql2 {PRAGMA cache_size=2000} | |
60 | |
61 sql1 {PRAGMA page_size=1024} | |
62 sql1 $mmap_size | |
63 sql2 $c2init | |
64 | |
65 code2 [register_rblob_code db2 0] | |
66 | |
67 sql2 { | |
68 PRAGMA page_size=1024; | |
69 PRAGMA auto_vacuum = 1; | |
70 CREATE TABLE t1(a, b, UNIQUE(a, b)); | |
71 INSERT INTO t1 VALUES(rblob(500), rblob(500)); | |
72 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2 | |
73 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4 | |
74 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8 | |
75 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16 | |
76 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 32 | |
77 } | |
78 do_test $t.$tn.1 { | |
79 sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count" | |
80 } {32 ok 77} | |
81 | |
82 # Have connection 2 shrink the file. Check connection 1 can still read it. | |
83 sql2 { DELETE FROM t1 WHERE rowid%2; } | |
84 do_test $t.$tn.2 { | |
85 sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count" | |
86 } {16 ok 42} | |
87 | |
88 # Have connection 2 grow the file. Check connection 1 can still read it. | |
89 sql2 { INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1 } | |
90 do_test $t.$tn.3 { | |
91 sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count" | |
92 } {32 ok 79} | |
93 | |
94 # Have connection 2 grow the file again. Check connection 1 is still ok. | |
95 sql2 { INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1 } | |
96 do_test $t.$tn.4 { | |
97 sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count" | |
98 } {64 ok 149} | |
99 | |
100 # Check that the number of pages read by connection 1 indicates that the | |
101 # "PRAGMA mmap_size" command worked. | |
102 do_test $t.$tn.5 { nRead db } $nRead | |
103 } | |
104 } | |
105 | |
106 set ::rcnt 0 | |
107 proc rblob {n} { | |
108 set ::rcnt [expr (($::rcnt << 3) + $::rcnt + 456) & 0xFFFFFFFF] | |
109 set str [format %.8x [expr $::rcnt ^ 0xbdf20da3]] | |
110 string range [string repeat $str [expr $n/4]] 1 $n | |
111 } | |
112 | |
113 reset_db | |
114 db func rblob rblob | |
115 | |
116 do_execsql_test 2.1 { | |
117 PRAGMA auto_vacuum = 1; | |
118 PRAGMA mmap_size = 67108864; | |
119 PRAGMA journal_mode = wal; | |
120 CREATE TABLE t1(a, b, UNIQUE(a, b)); | |
121 INSERT INTO t1 VALUES(rblob(500), rblob(500)); | |
122 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2 | |
123 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4 | |
124 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8 | |
125 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16 | |
126 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 32 | |
127 PRAGMA wal_checkpoint; | |
128 } {67108864 wal 0 103 103} | |
129 | |
130 do_execsql_test 2.2 { | |
131 PRAGMA auto_vacuum; | |
132 SELECT count(*) FROM t1; | |
133 } {1 32} | |
134 | |
135 if {[permutation] != "inmemory_journal"} { | |
136 do_test 2.3 { | |
137 sqlite3 db2 test.db | |
138 db2 func rblob rblob | |
139 db2 eval { | |
140 DELETE FROM t1 WHERE (rowid%4); | |
141 PRAGMA wal_checkpoint; | |
142 } | |
143 db2 eval { | |
144 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16 | |
145 SELECT count(*) FROM t1; | |
146 } | |
147 } {16} | |
148 | |
149 do_execsql_test 2.4 { | |
150 PRAGMA wal_checkpoint; | |
151 } {0 24 24} | |
152 db2 close | |
153 } | |
154 | |
155 reset_db | |
156 execsql { PRAGMA mmap_size = 67108864; } | |
157 db func rblob rblob | |
158 do_execsql_test 3.1 { | |
159 PRAGMA auto_vacuum = 1; | |
160 | |
161 CREATE TABLE t1(a, b, UNIQUE(a, b)); | |
162 INSERT INTO t1 VALUES(rblob(500), rblob(500)); | |
163 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2 | |
164 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4 | |
165 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8 | |
166 | |
167 CREATE TABLE t2(a, b, UNIQUE(a, b)); | |
168 INSERT INTO t2 SELECT * FROM t1; | |
169 } {} | |
170 | |
171 do_test 3.2 { | |
172 set nRow 0 | |
173 db eval {SELECT * FROM t2 ORDER BY a, b} { | |
174 if {$nRow==4} { db eval { DELETE FROM t1 } } | |
175 incr nRow | |
176 } | |
177 set nRow | |
178 } {8} | |
179 | |
180 #------------------------------------------------------------------------- | |
181 # Ensure that existing cursors using xFetch() pages see changes made | |
182 # to rows using the incrblob API. | |
183 # | |
184 reset_db | |
185 execsql { PRAGMA mmap_size = 67108864; } | |
186 set aaa [string repeat a 400] | |
187 set bbb [string repeat b 400] | |
188 set ccc [string repeat c 400] | |
189 set ddd [string repeat d 400] | |
190 set eee [string repeat e 400] | |
191 | |
192 do_execsql_test 4.1 { | |
193 PRAGMA page_size = 1024; | |
194 CREATE TABLE t1(x); | |
195 INSERT INTO t1 VALUES($aaa); | |
196 INSERT INTO t1 VALUES($bbb); | |
197 INSERT INTO t1 VALUES($ccc); | |
198 INSERT INTO t1 VALUES($ddd); | |
199 SELECT * FROM t1; | |
200 BEGIN; | |
201 } [list $aaa $bbb $ccc $ddd] | |
202 | |
203 do_test 4.2 { | |
204 set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY rowid" -1 dummy] | |
205 sqlite3_step $::STMT | |
206 sqlite3_column_text $::STMT 0 | |
207 } $aaa | |
208 | |
209 do_test 4.3 { | |
210 foreach r {2 3 4} { | |
211 set fd [db incrblob t1 x $r] | |
212 puts -nonewline $fd $eee | |
213 close $fd | |
214 } | |
215 | |
216 set res [list] | |
217 while {"SQLITE_ROW" == [sqlite3_step $::STMT]} { | |
218 lappend res [sqlite3_column_text $::STMT 0] | |
219 } | |
220 set res | |
221 } [list $eee $eee $eee] | |
222 | |
223 do_test 4.4 { | |
224 sqlite3_finalize $::STMT | |
225 } SQLITE_OK | |
226 | |
227 do_execsql_test 4.5 { COMMIT } | |
228 | |
229 #------------------------------------------------------------------------- | |
230 # Ensure that existing cursors holding xFetch() references are not | |
231 # confused if those pages are moved to make way for the root page of a | |
232 # new table or index. | |
233 # | |
234 reset_db | |
235 execsql { PRAGMA mmap_size = 67108864; } | |
236 do_execsql_test 5.1 { | |
237 PRAGMA auto_vacuum = 2; | |
238 PRAGMA page_size = 1024; | |
239 CREATE TABLE t1(x); | |
240 INSERT INTO t1 VALUES($aaa); | |
241 INSERT INTO t1 VALUES($bbb); | |
242 INSERT INTO t1 VALUES($ccc); | |
243 INSERT INTO t1 VALUES($ddd); | |
244 | |
245 PRAGMA auto_vacuum; | |
246 SELECT * FROM t1; | |
247 } [list 2 $aaa $bbb $ccc $ddd] | |
248 | |
249 do_test 5.2 { | |
250 set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY rowid" -1 dummy] | |
251 sqlite3_step $::STMT | |
252 sqlite3_column_text $::STMT 0 | |
253 } $aaa | |
254 | |
255 do_execsql_test 5.3 { | |
256 CREATE TABLE t2(x); | |
257 INSERT INTO t2 VALUES('tricked you!'); | |
258 INSERT INTO t2 VALUES('tricked you!'); | |
259 } | |
260 | |
261 do_test 5.4 { | |
262 sqlite3_step $::STMT | |
263 sqlite3_column_text $::STMT 0 | |
264 } $bbb | |
265 | |
266 do_test 5.5 { | |
267 sqlite3_finalize $::STMT | |
268 } SQLITE_OK | |
269 | |
270 #------------------------------------------------------------------------- | |
271 # Test various mmap_size settings. | |
272 # | |
273 foreach {tn1 mmap1 mmap2} { | |
274 1 6144 167773 | |
275 2 18432 140399 | |
276 3 43008 401302 | |
277 4 92160 253899 | |
278 5 190464 2 | |
279 6 387072 752431 | |
280 7 780288 291143 | |
281 8 1566720 594306 | |
282 9 3139584 829137 | |
283 10 6285312 793963 | |
284 11 12576768 1015590 | |
285 } { | |
286 do_multiclient_test tn { | |
287 sql1 { | |
288 CREATE TABLE t1(a PRIMARY KEY); | |
289 CREATE TABLE t2(x); | |
290 INSERT INTO t2 VALUES(''); | |
291 } | |
292 | |
293 code1 [register_rblob_code db 0] | |
294 code2 [register_rblob_code db2 444] | |
295 | |
296 sql1 "PRAGMA mmap_size = $mmap1" | |
297 sql2 "PRAGMA mmap_size = $mmap2" | |
298 | |
299 do_test $tn1.$tn { | |
300 for {set i 1} {$i <= 100} {incr i} { | |
301 if {$i % 2} { | |
302 set c1 sql1 | |
303 set c2 sql2 | |
304 } else { | |
305 set c1 sql2 | |
306 set c2 sql1 | |
307 } | |
308 | |
309 $c1 { | |
310 INSERT INTO t1 VALUES( rblob(5000) ); | |
311 UPDATE t2 SET x = (SELECT md5sum(a) FROM t1); | |
312 } | |
313 | |
314 set res [$c2 { | |
315 SELECT count(*) FROM t1; | |
316 SELECT x == (SELECT md5sum(a) FROM t1) FROM t2; | |
317 PRAGMA integrity_check; | |
318 }] | |
319 if {$res != [list $i 1 ok]} { | |
320 do_test $tn1.$tn.$i { | |
321 set ::res | |
322 } [list $i 1 ok] | |
323 } | |
324 } | |
325 set res 1 | |
326 } {1} | |
327 } | |
328 } | |
329 | |
330 | |
331 finish_test | |
OLD | NEW |