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 31proc 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# 48foreach {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 106set ::rcnt 0 107proc 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 113reset_db 114db func rblob rblob 115 116do_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 130do_execsql_test 2.2 { 131 PRAGMA auto_vacuum; 132 SELECT count(*) FROM t1; 133} {1 32} 134 135if {[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 155reset_db 156execsql { PRAGMA mmap_size = 67108864; } 157db func rblob rblob 158do_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 171do_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# 184reset_db 185execsql { PRAGMA mmap_size = 67108864; } 186set aaa [string repeat a 400] 187set bbb [string repeat b 400] 188set ccc [string repeat c 400] 189set ddd [string repeat d 400] 190set eee [string repeat e 400] 191 192do_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 203do_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 209do_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 223do_test 4.4 { 224 sqlite3_finalize $::STMT 225} SQLITE_OK 226 227do_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# 234reset_db 235execsql { PRAGMA mmap_size = 67108864; } 236do_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 249do_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 255do_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 261do_test 5.4 { 262 sqlite3_step $::STMT 263 sqlite3_column_text $::STMT 0 264} $bbb 265 266do_test 5.5 { 267 sqlite3_finalize $::STMT 268} SQLITE_OK 269 270#------------------------------------------------------------------------- 271# Test various mmap_size settings. 272# 273foreach {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 331finish_test 332