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