summaryrefslogtreecommitdiff
path: root/test/mmap1.test
diff options
context:
space:
mode:
Diffstat (limited to 'test/mmap1.test')
-rw-r--r--test/mmap1.test331
1 files changed, 331 insertions, 0 deletions
diff --git a/test/mmap1.test b/test/mmap1.test
new file mode 100644
index 0000000..ece3e02
--- /dev/null
+++ b/test/mmap1.test
@@ -0,0 +1,331 @@
+# 2013 March 20
+#
+# 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.
+#
+#***********************************************************************
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+ifcapable !mmap {
+ finish_test
+ return
+}
+source $testdir/lock_common.tcl
+set testprefix mmap1
+
+proc nRead {db} {
+ set bt [btree_from_db $db]
+ db_enter $db
+ array set stats [btree_pager_stats $bt]
+ db_leave $db
+ # puts [array get stats]
+ return $stats(read)
+}
+
+proc register_rblob_code {dbname seed} {
+ return [subst -nocommands {
+ set ::rcnt $seed
+ proc rblob {n} {
+ set ::rcnt [expr (([set ::rcnt] << 3) + [set ::rcnt] + 456) & 0xFFFFFFFF]
+ set str [format %.8x [expr [set ::rcnt] ^ 0xbdf20da3]]
+ string range [string repeat [set str] [expr [set n]/4]] 1 [set n]
+ }
+ $dbname func rblob rblob
+ }]
+}
+
+# For cases 1.1 and 1.4, the number of pages read using xRead() is 4 on
+# unix and 9 on windows. The difference is that windows only ever maps
+# an integer number of OS pages (i.e. creates mappings that are a multiple
+# of 4KB in size). Whereas on unix any sized mapping may be created.
+#
+foreach {t mmap_size nRead c2init} {
+ 1.1 { PRAGMA mmap_size = 67108864 } /[49]/ {PRAGMA mmap_size = 0}
+ 1.2 { PRAGMA mmap_size = 53248 } 150 {PRAGMA mmap_size = 0}
+ 1.3 { PRAGMA mmap_size = 0 } 344 {PRAGMA mmap_size = 0}
+ 1.4 { PRAGMA mmap_size = 67108864 } /[49]/ {PRAGMA mmap_size = 67108864 }
+ 1.5 { PRAGMA mmap_size = 53248 } 150 {PRAGMA mmap_size = 67108864 }
+ 1.6 { PRAGMA mmap_size = 0 } 344 {PRAGMA mmap_size = 67108864 }
+} {
+
+ do_multiclient_test tn {
+ sql1 {PRAGMA cache_size=2000}
+ sql2 {PRAGMA cache_size=2000}
+
+ sql1 {PRAGMA page_size=1024}
+ sql1 $mmap_size
+ sql2 $c2init
+
+ code2 [register_rblob_code db2 0]
+
+ sql2 {
+ PRAGMA page_size=1024;
+ PRAGMA auto_vacuum = 1;
+ CREATE TABLE t1(a, b, UNIQUE(a, b));
+ INSERT INTO t1 VALUES(rblob(500), rblob(500));
+ INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2
+ INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4
+ INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8
+ INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16
+ INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 32
+ }
+ do_test $t.$tn.1 {
+ sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count"
+ } {32 ok 77}
+
+ # Have connection 2 shrink the file. Check connection 1 can still read it.
+ sql2 { DELETE FROM t1 WHERE rowid%2; }
+ do_test $t.$tn.2 {
+ sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count"
+ } {16 ok 42}
+
+ # Have connection 2 grow the file. Check connection 1 can still read it.
+ sql2 { INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1 }
+ do_test $t.$tn.3 {
+ sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count"
+ } {32 ok 79}
+
+ # Have connection 2 grow the file again. Check connection 1 is still ok.
+ sql2 { INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1 }
+ do_test $t.$tn.4 {
+ sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count"
+ } {64 ok 149}
+
+ # Check that the number of pages read by connection 1 indicates that the
+ # "PRAGMA mmap_size" command worked.
+ do_test $t.$tn.5 { nRead db } $nRead
+ }
+}
+
+set ::rcnt 0
+proc rblob {n} {
+ set ::rcnt [expr (($::rcnt << 3) + $::rcnt + 456) & 0xFFFFFFFF]
+ set str [format %.8x [expr $::rcnt ^ 0xbdf20da3]]
+ string range [string repeat $str [expr $n/4]] 1 $n
+}
+
+reset_db
+db func rblob rblob
+
+do_execsql_test 2.1 {
+ PRAGMA auto_vacuum = 1;
+ PRAGMA mmap_size = 67108864;
+ PRAGMA journal_mode = wal;
+ CREATE TABLE t1(a, b, UNIQUE(a, b));
+ INSERT INTO t1 VALUES(rblob(500), rblob(500));
+ INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2
+ INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4
+ INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8
+ INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16
+ INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 32
+ PRAGMA wal_checkpoint;
+} {67108864 wal 0 103 103}
+
+do_execsql_test 2.2 {
+ PRAGMA auto_vacuum;
+ SELECT count(*) FROM t1;
+} {1 32}
+
+if {[permutation] != "inmemory_journal"} {
+ do_test 2.3 {
+ sqlite3 db2 test.db
+ db2 func rblob rblob
+ db2 eval {
+ DELETE FROM t1 WHERE (rowid%4);
+ PRAGMA wal_checkpoint;
+ }
+ db2 eval {
+ INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16
+ SELECT count(*) FROM t1;
+ }
+ } {16}
+
+ do_execsql_test 2.4 {
+ PRAGMA wal_checkpoint;
+ } {0 24 24}
+ db2 close
+}
+
+reset_db
+execsql { PRAGMA mmap_size = 67108864; }
+db func rblob rblob
+do_execsql_test 3.1 {
+ PRAGMA auto_vacuum = 1;
+
+ CREATE TABLE t1(a, b, UNIQUE(a, b));
+ INSERT INTO t1 VALUES(rblob(500), rblob(500));
+ INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2
+ INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4
+ INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8
+
+ CREATE TABLE t2(a, b, UNIQUE(a, b));
+ INSERT INTO t2 SELECT * FROM t1;
+} {}
+
+do_test 3.2 {
+ set nRow 0
+ db eval {SELECT * FROM t2 ORDER BY a, b} {
+ if {$nRow==4} { db eval { DELETE FROM t1 } }
+ incr nRow
+ }
+ set nRow
+} {8}
+
+#-------------------------------------------------------------------------
+# Ensure that existing cursors using xFetch() pages see changes made
+# to rows using the incrblob API.
+#
+reset_db
+execsql { PRAGMA mmap_size = 67108864; }
+set aaa [string repeat a 400]
+set bbb [string repeat b 400]
+set ccc [string repeat c 400]
+set ddd [string repeat d 400]
+set eee [string repeat e 400]
+
+do_execsql_test 4.1 {
+ PRAGMA page_size = 1024;
+ CREATE TABLE t1(x);
+ INSERT INTO t1 VALUES($aaa);
+ INSERT INTO t1 VALUES($bbb);
+ INSERT INTO t1 VALUES($ccc);
+ INSERT INTO t1 VALUES($ddd);
+ SELECT * FROM t1;
+ BEGIN;
+} [list $aaa $bbb $ccc $ddd]
+
+do_test 4.2 {
+ set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY rowid" -1 dummy]
+ sqlite3_step $::STMT
+ sqlite3_column_text $::STMT 0
+} $aaa
+
+do_test 4.3 {
+ foreach r {2 3 4} {
+ set fd [db incrblob t1 x $r]
+ puts -nonewline $fd $eee
+ close $fd
+ }
+
+ set res [list]
+ while {"SQLITE_ROW" == [sqlite3_step $::STMT]} {
+ lappend res [sqlite3_column_text $::STMT 0]
+ }
+ set res
+} [list $eee $eee $eee]
+
+do_test 4.4 {
+ sqlite3_finalize $::STMT
+} SQLITE_OK
+
+do_execsql_test 4.5 { COMMIT }
+
+#-------------------------------------------------------------------------
+# Ensure that existing cursors holding xFetch() references are not
+# confused if those pages are moved to make way for the root page of a
+# new table or index.
+#
+reset_db
+execsql { PRAGMA mmap_size = 67108864; }
+do_execsql_test 5.1 {
+ PRAGMA auto_vacuum = 2;
+ PRAGMA page_size = 1024;
+ CREATE TABLE t1(x);
+ INSERT INTO t1 VALUES($aaa);
+ INSERT INTO t1 VALUES($bbb);
+ INSERT INTO t1 VALUES($ccc);
+ INSERT INTO t1 VALUES($ddd);
+
+ PRAGMA auto_vacuum;
+ SELECT * FROM t1;
+} [list 2 $aaa $bbb $ccc $ddd]
+
+do_test 5.2 {
+ set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY rowid" -1 dummy]
+ sqlite3_step $::STMT
+ sqlite3_column_text $::STMT 0
+} $aaa
+
+do_execsql_test 5.3 {
+ CREATE TABLE t2(x);
+ INSERT INTO t2 VALUES('tricked you!');
+ INSERT INTO t2 VALUES('tricked you!');
+}
+
+do_test 5.4 {
+ sqlite3_step $::STMT
+ sqlite3_column_text $::STMT 0
+} $bbb
+
+do_test 5.5 {
+ sqlite3_finalize $::STMT
+} SQLITE_OK
+
+#-------------------------------------------------------------------------
+# Test various mmap_size settings.
+#
+foreach {tn1 mmap1 mmap2} {
+ 1 6144 167773
+ 2 18432 140399
+ 3 43008 401302
+ 4 92160 253899
+ 5 190464 2
+ 6 387072 752431
+ 7 780288 291143
+ 8 1566720 594306
+ 9 3139584 829137
+ 10 6285312 793963
+ 11 12576768 1015590
+} {
+ do_multiclient_test tn {
+ sql1 {
+ CREATE TABLE t1(a PRIMARY KEY);
+ CREATE TABLE t2(x);
+ INSERT INTO t2 VALUES('');
+ }
+
+ code1 [register_rblob_code db 0]
+ code2 [register_rblob_code db2 444]
+
+ sql1 "PRAGMA mmap_size = $mmap1"
+ sql2 "PRAGMA mmap_size = $mmap2"
+
+ do_test $tn1.$tn {
+ for {set i 1} {$i <= 100} {incr i} {
+ if {$i % 2} {
+ set c1 sql1
+ set c2 sql2
+ } else {
+ set c1 sql2
+ set c2 sql1
+ }
+
+ $c1 {
+ INSERT INTO t1 VALUES( rblob(5000) );
+ UPDATE t2 SET x = (SELECT md5sum(a) FROM t1);
+ }
+
+ set res [$c2 {
+ SELECT count(*) FROM t1;
+ SELECT x == (SELECT md5sum(a) FROM t1) FROM t2;
+ PRAGMA integrity_check;
+ }]
+ if {$res != [list $i 1 ok]} {
+ do_test $tn1.$tn.$i {
+ set ::res
+ } [list $i 1 ok]
+ }
+ }
+ set res 1
+ } {1}
+ }
+}
+
+
+finish_test