resolve upstream merge conflict in distclean
[sqlcipher.git] / test / mmap1.test
blob3362f7187f3e92fcf7bd2c49700416d148978258
1 # 2013 March 20
3 # The author disclaims copyright to this source code.  In place of
4 # a legal notice, here is a blessing:
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.
10 #***********************************************************************
13 set testdir [file dirname $argv0]
14 source $testdir/tester.tcl
15 ifcapable !mmap||!incrblob {
16   finish_test
17   return
19 source $testdir/lock_common.tcl
20 set testprefix mmap1
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)
31 # Return a Tcl script that registers a user-defined scalar function 
32 # named rblob() with database handle $dbname. The function returns a
33 # sequence of pseudo-random blobs based on seed value $seed.
35 proc register_rblob_code {dbname seed} {
36   return [subst -nocommands {
37     set ::rcnt $seed
38     proc rblob {n} {
39       set ::rcnt [expr (([set ::rcnt] << 3) + [set ::rcnt] + 456) & 0xFFFFFFFF]
40       set str [format %.8x [expr [set ::rcnt] ^ 0xbdf20da3]]
41       string range [string repeat [set str] [expr [set n]/4]] 1 [set n]
42     }
43     $dbname func rblob rblob
44   }]
48 # For cases 1.1 and 1.4, the number of pages read using xRead() is 4 on
49 # unix and 9 on windows. The difference is that windows only ever maps
50 # an integer number of OS pages (i.e. creates mappings that are a multiple
51 # of 4KB in size). Whereas on unix any sized mapping may be created.
53 foreach {t mmap_size nRead c2init} {
54   1.1 { PRAGMA mmap_size = 67108864 } /[49]/ {PRAGMA mmap_size = 0}
55   1.2 { PRAGMA mmap_size =    53248 } 150    {PRAGMA mmap_size = 0}
56   1.3 { PRAGMA mmap_size =        0 } 344    {PRAGMA mmap_size = 0}
57   1.4 { PRAGMA mmap_size = 67108864 } /[49]/ {PRAGMA mmap_size = 67108864 }
58   1.5 { PRAGMA mmap_size =    53248 } 150    {PRAGMA mmap_size = 67108864 }
59   1.6 { PRAGMA mmap_size =        0 } 344    {PRAGMA mmap_size = 67108864 }
60 } {
62   do_multiclient_test tn {
63     sql1 {PRAGMA cache_size=2000}
64     sql2 {PRAGMA cache_size=2000}
66     sql1 {PRAGMA page_size=1024}
67     sql1 $mmap_size
68     sql2 $c2init
70     code2 [register_rblob_code db2 0]
72     sql2 {
73       PRAGMA page_size=1024;
74       PRAGMA auto_vacuum = 1;
75       CREATE TABLE t1(a, b, UNIQUE(a, b));
76       INSERT INTO t1 VALUES(rblob(500), rblob(500));
77       INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; --    2
78       INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; --    4
79       INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; --    8
80       INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; --   16
81       INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; --   32
82     }
83     do_test $t.$tn.1 {
84       sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count"
85     } {32 ok 77}
87     # Have connection 2 shrink the file. Check connection 1 can still read it.
88     sql2 { DELETE FROM t1 WHERE rowid%2; }
89     do_test $t.$tn.2 {
90       sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count"
91     } "16 ok [expr {42+[nonzero_reserved_bytes]}]"
93     # Have connection 2 grow the file. Check connection 1 can still read it.
94     sql2 { INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1 }
95     do_test $t.$tn.3 {
96       sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count"
97     } {32 ok 79}
99     # Have connection 2 grow the file again. Check connection 1 is still ok.
100     sql2 { INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1 }
101     do_test $t.$tn.4 {
102       sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count"
103     } {64 ok 149}
105     # Check that the number of pages read by connection 1 indicates that the
106     # "PRAGMA mmap_size" command worked.
107     if {[nonzero_reserved_bytes]==0} {
108       do_test $t.$tn.5 { nRead db } $nRead
109     }
110   }
113 set ::rcnt 0
114 proc rblob {n} {
115   set ::rcnt [expr (($::rcnt << 3) + $::rcnt + 456) & 0xFFFFFFFF]
116   set str [format %.8x [expr $::rcnt ^ 0xbdf20da3]]
117   string range [string repeat $str [expr $n/4]] 1 $n
120 reset_db
121 db func rblob rblob
123 ifcapable wal {
124   do_execsql_test 2.1 {
125     PRAGMA auto_vacuum = 1;
126     PRAGMA mmap_size = 67108864;
127     PRAGMA journal_mode = wal;
128     CREATE TABLE t1(a, b, UNIQUE(a, b));
129     INSERT INTO t1 VALUES(rblob(500), rblob(500));
130     INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; --    2
131     INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; --    4
132     INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; --    8
133     INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; --   16
134     INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; --   32
135     PRAGMA wal_checkpoint;
136   } {67108864 wal 0 103 103}
138   do_execsql_test 2.2 {
139     PRAGMA auto_vacuum;
140     SELECT count(*) FROM t1;
141   } {1 32}
143   if {[permutation] != "inmemory_journal"} {
144     do_test 2.3 {
145       sqlite3 db2 test.db
146       db2 func rblob rblob
147       db2 eval {
148         DELETE FROM t1 WHERE (rowid%4);
149           PRAGMA wal_checkpoint;
150       }
151       db2 eval {
152         INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; --    16
153         SELECT count(*) FROM t1;
154       }
155     } {16}
157     do_execsql_test 2.4 {
158       PRAGMA wal_checkpoint;
159     } {0 24 24}
160     db2 close
161   }
164 reset_db
165 execsql { PRAGMA mmap_size = 67108864; }
166 db func rblob rblob
167 do_execsql_test 3.1 {
168   PRAGMA auto_vacuum = 1;
170   CREATE TABLE t1(a, b, UNIQUE(a, b));
171   INSERT INTO t1 VALUES(rblob(500), rblob(500));
172   INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; --    2
173   INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; --    4
174   INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; --    8
176   CREATE TABLE t2(a, b, UNIQUE(a, b));
177   INSERT INTO t2 SELECT * FROM t1;
178 } {}
180 do_test 3.2 {
181   set nRow 0
182   db eval {SELECT * FROM t2 ORDER BY a, b} {
183     if {$nRow==4} { db eval { DELETE FROM t1 } }
184     incr nRow
185   }
186   set nRow
187 } {8}
189 #-------------------------------------------------------------------------
190 # Ensure that existing cursors using xFetch() pages see changes made
191 # to rows using the incrblob API.
193 reset_db
194 execsql { PRAGMA mmap_size = 67108864; }
195 set aaa [string repeat a 400]
196 set bbb [string repeat b 400]
197 set ccc [string repeat c 400]
198 set ddd [string repeat d 400]
199 set eee [string repeat e 400]
201 do_execsql_test 4.1 {
202   PRAGMA page_size = 1024;
203   CREATE TABLE t1(x);
204   INSERT INTO t1 VALUES($aaa);
205   INSERT INTO t1 VALUES($bbb);
206   INSERT INTO t1 VALUES($ccc);
207   INSERT INTO t1 VALUES($ddd);
208   SELECT * FROM t1;
209   BEGIN;
210 } [list $aaa $bbb $ccc $ddd]
212 do_test 4.2 {
213   set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY rowid" -1 dummy]
214   sqlite3_step $::STMT
215   sqlite3_column_text $::STMT 0
216 } $aaa
218 do_test 4.3 {
219   foreach r {2 3 4} {
220     set fd [db incrblob t1 x $r]
221     puts -nonewline $fd $eee
222     close $fd
223   }
225   set res [list]
226   while {"SQLITE_ROW" == [sqlite3_step $::STMT]} {
227     lappend res [sqlite3_column_text $::STMT 0]
228   }
229   set res
230 } [list $eee $eee $eee]
232 do_test 4.4 {
233   sqlite3_finalize $::STMT
234 } SQLITE_OK
236 do_execsql_test 4.5 { COMMIT }
238 #-------------------------------------------------------------------------
239 # Ensure that existing cursors holding xFetch() references are not
240 # confused if those pages are moved to make way for the root page of a
241 # new table or index.
243 reset_db
244 execsql { PRAGMA mmap_size = 67108864; }
245 do_execsql_test 5.1 {
246   PRAGMA auto_vacuum = 2;
247   PRAGMA page_size = 1024;
248   CREATE TABLE t1(x);
249   INSERT INTO t1 VALUES($aaa);
250   INSERT INTO t1 VALUES($bbb);
251   INSERT INTO t1 VALUES($ccc);
252   INSERT INTO t1 VALUES($ddd);
254   PRAGMA auto_vacuum;
255   SELECT * FROM t1;
256 } [list 2 $aaa $bbb $ccc $ddd]
258 do_test 5.2 {
259   set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY rowid" -1 dummy]
260   sqlite3_step $::STMT
261   sqlite3_column_text $::STMT 0
262 } $aaa
264 do_execsql_test 5.3 {
265   CREATE TABLE t2(x);
266   INSERT INTO t2 VALUES('tricked you!');
267   INSERT INTO t2 VALUES('tricked you!');
270 do_test 5.4 {
271   sqlite3_step $::STMT
272   sqlite3_column_text $::STMT 0
273 } $bbb
275 do_test 5.5 {
276   sqlite3_finalize $::STMT
277 } SQLITE_OK
280 # The "6.*" tests are designed to test the interaction of mmap with file
281 # truncation (e.g. on Win32) via the VACUUM command.
283 forcedelete test2.db
284 sqlite3 db2 test2.db
285 do_test 6.0 {
286   db2 eval {
287     PRAGMA auto_vacuum = 0;
288     PRAGMA page_size = 4096;
289   }
290 } {}
291 do_test 6.1 {
292   db2 eval {
293     CREATE TABLE t1(x);
294     INSERT INTO t1(x) VALUES(randomblob(1000000));
295   }
296 } {}
297 do_test 6.2 {
298   db2 eval {
299     PRAGMA mmap_size = 1048576;
300   }
301 } {1048576}
302 do_test 6.3 {
303   expr {[file size test2.db] > 1000000}
304 } {1}
305 do_test 6.4 {
306   db2 eval {
307     DELETE FROM t1;
308   }
309 } {}
310 do_test 6.5 {
311   expr {[file size test2.db] > 1000000}
312 } {1}
313 do_test 6.6 {
314   db2 eval {
315     VACUUM;
316   }
317 } {}
318 do_test 6.7 {
319   expr {[file size test2.db] < 1000000}
320 } {1}
321 db2 close
323 finish_test