gitlab.com/CoiaPrant/sqlite3@v1.19.1/testdata/tcl/mmap1.test (about) 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 13 set testdir [file dirname $argv0] 14 source $testdir/tester.tcl 15 ifcapable !mmap||!incrblob { 16 finish_test 17 return 18 } 19 source $testdir/lock_common.tcl 20 set testprefix mmap1 21 22 proc 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 # 35 proc 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 # 53 foreach {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 113 set ::rcnt 0 114 proc 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 120 reset_db 121 db func rblob rblob 122 123 ifcapable 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 164 reset_db 165 execsql { PRAGMA mmap_size = 67108864; } 166 db func rblob rblob 167 do_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 180 do_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 # 193 reset_db 194 execsql { PRAGMA mmap_size = 67108864; } 195 set aaa [string repeat a 400] 196 set bbb [string repeat b 400] 197 set ccc [string repeat c 400] 198 set ddd [string repeat d 400] 199 set eee [string repeat e 400] 200 201 do_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 212 do_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 218 do_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 232 do_test 4.4 { 233 sqlite3_finalize $::STMT 234 } SQLITE_OK 235 236 do_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 # 243 reset_db 244 execsql { PRAGMA mmap_size = 67108864; } 245 do_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 258 do_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 264 do_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 270 do_test 5.4 { 271 sqlite3_step $::STMT 272 sqlite3_column_text $::STMT 0 273 } $bbb 274 275 do_test 5.5 { 276 sqlite3_finalize $::STMT 277 } SQLITE_OK 278 279 # 280 # The "6.*" tests are designed to test the interaction of mmap with file 281 # truncation (e.g. on Win32) via the VACUUM command. 282 # 283 forcedelete test2.db 284 sqlite3 db2 test2.db 285 do_test 6.0 { 286 db2 eval { 287 PRAGMA auto_vacuum = 0; 288 PRAGMA page_size = 4096; 289 } 290 } {} 291 do_test 6.1 { 292 db2 eval { 293 CREATE TABLE t1(x); 294 INSERT INTO t1(x) VALUES(randomblob(1000000)); 295 } 296 } {} 297 do_test 6.2 { 298 db2 eval { 299 PRAGMA mmap_size = 1048576; 300 } 301 } {1048576} 302 do_test 6.3 { 303 expr {[file size test2.db] > 1000000} 304 } {1} 305 do_test 6.4 { 306 db2 eval { 307 DELETE FROM t1; 308 } 309 } {} 310 do_test 6.5 { 311 expr {[file size test2.db] > 1000000} 312 } {1} 313 do_test 6.6 { 314 db2 eval { 315 VACUUM; 316 } 317 } {} 318 do_test 6.7 { 319 expr {[file size test2.db] < 1000000} 320 } {1} 321 db2 close 322 323 finish_test