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 116ifcapable wal { 117 do_execsql_test 2.1 { 118 PRAGMA auto_vacuum = 1; 119 PRAGMA mmap_size = 67108864; 120 PRAGMA journal_mode = wal; 121 CREATE TABLE t1(a, b, UNIQUE(a, b)); 122 INSERT INTO t1 VALUES(rblob(500), rblob(500)); 123 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2 124 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4 125 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8 126 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16 127 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 32 128 PRAGMA wal_checkpoint; 129 } {67108864 wal 0 103 103} 130 131 do_execsql_test 2.2 { 132 PRAGMA auto_vacuum; 133 SELECT count(*) FROM t1; 134 } {1 32} 135 136 if {[permutation] != "inmemory_journal"} { 137 do_test 2.3 { 138 sqlite3 db2 test.db 139 db2 func rblob rblob 140 db2 eval { 141 DELETE FROM t1 WHERE (rowid%4); 142 PRAGMA wal_checkpoint; 143 } 144 db2 eval { 145 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16 146 SELECT count(*) FROM t1; 147 } 148 } {16} 149 150 do_execsql_test 2.4 { 151 PRAGMA wal_checkpoint; 152 } {0 24 24} 153 db2 close 154 } 155} 156 157reset_db 158execsql { PRAGMA mmap_size = 67108864; } 159db func rblob rblob 160do_execsql_test 3.1 { 161 PRAGMA auto_vacuum = 1; 162 163 CREATE TABLE t1(a, b, UNIQUE(a, b)); 164 INSERT INTO t1 VALUES(rblob(500), rblob(500)); 165 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2 166 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4 167 INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8 168 169 CREATE TABLE t2(a, b, UNIQUE(a, b)); 170 INSERT INTO t2 SELECT * FROM t1; 171} {} 172 173do_test 3.2 { 174 set nRow 0 175 db eval {SELECT * FROM t2 ORDER BY a, b} { 176 if {$nRow==4} { db eval { DELETE FROM t1 } } 177 incr nRow 178 } 179 set nRow 180} {8} 181 182#------------------------------------------------------------------------- 183# Ensure that existing cursors using xFetch() pages see changes made 184# to rows using the incrblob API. 185# 186reset_db 187execsql { PRAGMA mmap_size = 67108864; } 188set aaa [string repeat a 400] 189set bbb [string repeat b 400] 190set ccc [string repeat c 400] 191set ddd [string repeat d 400] 192set eee [string repeat e 400] 193 194do_execsql_test 4.1 { 195 PRAGMA page_size = 1024; 196 CREATE TABLE t1(x); 197 INSERT INTO t1 VALUES($aaa); 198 INSERT INTO t1 VALUES($bbb); 199 INSERT INTO t1 VALUES($ccc); 200 INSERT INTO t1 VALUES($ddd); 201 SELECT * FROM t1; 202 BEGIN; 203} [list $aaa $bbb $ccc $ddd] 204 205do_test 4.2 { 206 set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY rowid" -1 dummy] 207 sqlite3_step $::STMT 208 sqlite3_column_text $::STMT 0 209} $aaa 210 211do_test 4.3 { 212 foreach r {2 3 4} { 213 set fd [db incrblob t1 x $r] 214 puts -nonewline $fd $eee 215 close $fd 216 } 217 218 set res [list] 219 while {"SQLITE_ROW" == [sqlite3_step $::STMT]} { 220 lappend res [sqlite3_column_text $::STMT 0] 221 } 222 set res 223} [list $eee $eee $eee] 224 225do_test 4.4 { 226 sqlite3_finalize $::STMT 227} SQLITE_OK 228 229do_execsql_test 4.5 { COMMIT } 230 231#------------------------------------------------------------------------- 232# Ensure that existing cursors holding xFetch() references are not 233# confused if those pages are moved to make way for the root page of a 234# new table or index. 235# 236reset_db 237execsql { PRAGMA mmap_size = 67108864; } 238do_execsql_test 5.1 { 239 PRAGMA auto_vacuum = 2; 240 PRAGMA page_size = 1024; 241 CREATE TABLE t1(x); 242 INSERT INTO t1 VALUES($aaa); 243 INSERT INTO t1 VALUES($bbb); 244 INSERT INTO t1 VALUES($ccc); 245 INSERT INTO t1 VALUES($ddd); 246 247 PRAGMA auto_vacuum; 248 SELECT * FROM t1; 249} [list 2 $aaa $bbb $ccc $ddd] 250 251do_test 5.2 { 252 set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY rowid" -1 dummy] 253 sqlite3_step $::STMT 254 sqlite3_column_text $::STMT 0 255} $aaa 256 257do_execsql_test 5.3 { 258 CREATE TABLE t2(x); 259 INSERT INTO t2 VALUES('tricked you!'); 260 INSERT INTO t2 VALUES('tricked you!'); 261} 262 263do_test 5.4 { 264 sqlite3_step $::STMT 265 sqlite3_column_text $::STMT 0 266} $bbb 267 268do_test 5.5 { 269 sqlite3_finalize $::STMT 270} SQLITE_OK 271 272#------------------------------------------------------------------------- 273# Test various mmap_size settings. 274# 275foreach {tn1 mmap1 mmap2} { 276 1 6144 167773 277 2 18432 140399 278 3 43008 401302 279 4 92160 253899 280 5 190464 2 281 6 387072 752431 282 7 780288 291143 283 8 1566720 594306 284 9 3139584 829137 285 10 6285312 793963 286 11 12576768 1015590 287} { 288 do_multiclient_test tn { 289 sql1 { 290 CREATE TABLE t1(a PRIMARY KEY); 291 CREATE TABLE t2(x); 292 INSERT INTO t2 VALUES(''); 293 } 294 295 code1 [register_rblob_code db 0] 296 code2 [register_rblob_code db2 444] 297 298 sql1 "PRAGMA mmap_size = $mmap1" 299 sql2 "PRAGMA mmap_size = $mmap2" 300 301 do_test $tn1.$tn { 302 for {set i 1} {$i <= 100} {incr i} { 303 if {$i % 2} { 304 set c1 sql1 305 set c2 sql2 306 } else { 307 set c1 sql2 308 set c2 sql1 309 } 310 311 $c1 { 312 INSERT INTO t1 VALUES( rblob(5000) ); 313 UPDATE t2 SET x = (SELECT md5sum(a) FROM t1); 314 } 315 316 set res [$c2 { 317 SELECT count(*) FROM t1; 318 SELECT x == (SELECT md5sum(a) FROM t1) FROM t2; 319 PRAGMA integrity_check; 320 }] 321 if {$res != [list $i 1 ok]} { 322 do_test $tn1.$tn.$i { 323 set ::res 324 } [list $i 1 ok] 325 } 326 } 327 set res 1 328 } {1} 329 } 330} 331 332 333finish_test 334