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