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 15ifcapable !mmap { 16 finish_test 17 return 18} 19source $testdir/lock_common.tcl 20set testprefix mmap1 21 22proc 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# 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. 34# 35proc 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 }] 45} 46 47 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. 52# 53foreach {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} { 61 62 do_multiclient_test tn { 63 sql1 {PRAGMA cache_size=2000} 64 sql2 {PRAGMA cache_size=2000} 65 66 sql1 {PRAGMA page_size=1024} 67 sql1 $mmap_size 68 sql2 $c2init 69 70 code2 [register_rblob_code db2 0] 71 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} 86 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 42} 92 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} 98 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} 104 105 # Check that the number of pages read by connection 1 indicates that the 106 # "PRAGMA mmap_size" command worked. 107 do_test $t.$tn.5 { nRead db } $nRead 108 } 109} 110 111set ::rcnt 0 112proc rblob {n} { 113 set ::rcnt [expr (($::rcnt << 3) + $::rcnt + 456) & 0xFFFFFFFF] 114 set str [format %.8x [expr $::rcnt ^ 0xbdf20da3]] 115 string range [string repeat $str [expr $n/4]] 1 $n 116} 117 118reset_db 119db func rblob rblob 120 121ifcapable wal { 122 do_execsql_test 2.1 { 123 PRAGMA auto_vacuum = 1; 124 PRAGMA mmap_size = 67108864; 125 PRAGMA journal_mode = wal; 126 CREATE TABLE t1(a, b, UNIQUE(a, b)); 127 INSERT INTO t1 VALUES(rblob(500), rblob(500)); 128 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2 129 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4 130 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8 131 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16 132 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 32 133 PRAGMA wal_checkpoint; 134 } {67108864 wal 0 103 103} 135 136 do_execsql_test 2.2 { 137 PRAGMA auto_vacuum; 138 SELECT count(*) FROM t1; 139 } {1 32} 140 141 if {[permutation] != "inmemory_journal"} { 142 do_test 2.3 { 143 sqlite3 db2 test.db 144 db2 func rblob rblob 145 db2 eval { 146 DELETE FROM t1 WHERE (rowid%4); 147 PRAGMA wal_checkpoint; 148 } 149 db2 eval { 150 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16 151 SELECT count(*) FROM t1; 152 } 153 } {16} 154 155 do_execsql_test 2.4 { 156 PRAGMA wal_checkpoint; 157 } {0 24 24} 158 db2 close 159 } 160} 161 162reset_db 163execsql { PRAGMA mmap_size = 67108864; } 164db func rblob rblob 165do_execsql_test 3.1 { 166 PRAGMA auto_vacuum = 1; 167 168 CREATE TABLE t1(a, b, UNIQUE(a, b)); 169 INSERT INTO t1 VALUES(rblob(500), rblob(500)); 170 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2 171 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4 172 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8 173 174 CREATE TABLE t2(a, b, UNIQUE(a, b)); 175 INSERT INTO t2 SELECT * FROM t1; 176} {} 177 178do_test 3.2 { 179 set nRow 0 180 db eval {SELECT * FROM t2 ORDER BY a, b} { 181 if {$nRow==4} { db eval { DELETE FROM t1 } } 182 incr nRow 183 } 184 set nRow 185} {8} 186 187#------------------------------------------------------------------------- 188# Ensure that existing cursors using xFetch() pages see changes made 189# to rows using the incrblob API. 190# 191reset_db 192execsql { PRAGMA mmap_size = 67108864; } 193set aaa [string repeat a 400] 194set bbb [string repeat b 400] 195set ccc [string repeat c 400] 196set ddd [string repeat d 400] 197set eee [string repeat e 400] 198 199do_execsql_test 4.1 { 200 PRAGMA page_size = 1024; 201 CREATE TABLE t1(x); 202 INSERT INTO t1 VALUES($aaa); 203 INSERT INTO t1 VALUES($bbb); 204 INSERT INTO t1 VALUES($ccc); 205 INSERT INTO t1 VALUES($ddd); 206 SELECT * FROM t1; 207 BEGIN; 208} [list $aaa $bbb $ccc $ddd] 209 210do_test 4.2 { 211 set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY rowid" -1 dummy] 212 sqlite3_step $::STMT 213 sqlite3_column_text $::STMT 0 214} $aaa 215 216do_test 4.3 { 217 foreach r {2 3 4} { 218 set fd [db incrblob t1 x $r] 219 puts -nonewline $fd $eee 220 close $fd 221 } 222 223 set res [list] 224 while {"SQLITE_ROW" == [sqlite3_step $::STMT]} { 225 lappend res [sqlite3_column_text $::STMT 0] 226 } 227 set res 228} [list $eee $eee $eee] 229 230do_test 4.4 { 231 sqlite3_finalize $::STMT 232} SQLITE_OK 233 234do_execsql_test 4.5 { COMMIT } 235 236#------------------------------------------------------------------------- 237# Ensure that existing cursors holding xFetch() references are not 238# confused if those pages are moved to make way for the root page of a 239# new table or index. 240# 241reset_db 242execsql { PRAGMA mmap_size = 67108864; } 243do_execsql_test 5.1 { 244 PRAGMA auto_vacuum = 2; 245 PRAGMA page_size = 1024; 246 CREATE TABLE t1(x); 247 INSERT INTO t1 VALUES($aaa); 248 INSERT INTO t1 VALUES($bbb); 249 INSERT INTO t1 VALUES($ccc); 250 INSERT INTO t1 VALUES($ddd); 251 252 PRAGMA auto_vacuum; 253 SELECT * FROM t1; 254} [list 2 $aaa $bbb $ccc $ddd] 255 256do_test 5.2 { 257 set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY rowid" -1 dummy] 258 sqlite3_step $::STMT 259 sqlite3_column_text $::STMT 0 260} $aaa 261 262do_execsql_test 5.3 { 263 CREATE TABLE t2(x); 264 INSERT INTO t2 VALUES('tricked you!'); 265 INSERT INTO t2 VALUES('tricked you!'); 266} 267 268do_test 5.4 { 269 sqlite3_step $::STMT 270 sqlite3_column_text $::STMT 0 271} $bbb 272 273do_test 5.5 { 274 sqlite3_finalize $::STMT 275} SQLITE_OK 276 277 278finish_test 279