mmap1.test 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  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. set testdir [file dirname $argv0]
  13. source $testdir/tester.tcl
  14. ifcapable !mmap {
  15. finish_test
  16. return
  17. }
  18. source $testdir/lock_common.tcl
  19. set testprefix mmap1
  20. proc nRead {db} {
  21. set bt [btree_from_db $db]
  22. db_enter $db
  23. array set stats [btree_pager_stats $bt]
  24. db_leave $db
  25. # puts [array get stats]
  26. return $stats(read)
  27. }
  28. proc register_rblob_code {dbname seed} {
  29. return [subst -nocommands {
  30. set ::rcnt $seed
  31. proc rblob {n} {
  32. set ::rcnt [expr (([set ::rcnt] << 3) + [set ::rcnt] + 456) & 0xFFFFFFFF]
  33. set str [format %.8x [expr [set ::rcnt] ^ 0xbdf20da3]]
  34. string range [string repeat [set str] [expr [set n]/4]] 1 [set n]
  35. }
  36. $dbname func rblob rblob
  37. }]
  38. }
  39. # For cases 1.1 and 1.4, the number of pages read using xRead() is 4 on
  40. # unix and 9 on windows. The difference is that windows only ever maps
  41. # an integer number of OS pages (i.e. creates mappings that are a multiple
  42. # of 4KB in size). Whereas on unix any sized mapping may be created.
  43. #
  44. foreach {t mmap_size nRead c2init} {
  45. 1.1 { PRAGMA mmap_size = 67108864 } /[49]/ {PRAGMA mmap_size = 0}
  46. 1.2 { PRAGMA mmap_size = 53248 } 150 {PRAGMA mmap_size = 0}
  47. 1.3 { PRAGMA mmap_size = 0 } 344 {PRAGMA mmap_size = 0}
  48. 1.4 { PRAGMA mmap_size = 67108864 } /[49]/ {PRAGMA mmap_size = 67108864 }
  49. 1.5 { PRAGMA mmap_size = 53248 } 150 {PRAGMA mmap_size = 67108864 }
  50. 1.6 { PRAGMA mmap_size = 0 } 344 {PRAGMA mmap_size = 67108864 }
  51. } {
  52. do_multiclient_test tn {
  53. sql1 {PRAGMA cache_size=2000}
  54. sql2 {PRAGMA cache_size=2000}
  55. sql1 {PRAGMA page_size=1024}
  56. sql1 $mmap_size
  57. sql2 $c2init
  58. code2 [register_rblob_code db2 0]
  59. sql2 {
  60. PRAGMA page_size=1024;
  61. PRAGMA auto_vacuum = 1;
  62. CREATE TABLE t1(a, b, UNIQUE(a, b));
  63. INSERT INTO t1 VALUES(rblob(500), rblob(500));
  64. INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2
  65. INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4
  66. INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8
  67. INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16
  68. INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 32
  69. }
  70. do_test $t.$tn.1 {
  71. sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count"
  72. } {32 ok 77}
  73. # Have connection 2 shrink the file. Check connection 1 can still read it.
  74. sql2 { DELETE FROM t1 WHERE rowid%2; }
  75. do_test $t.$tn.2 {
  76. sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count"
  77. } {16 ok 42}
  78. # Have connection 2 grow the file. Check connection 1 can still read it.
  79. sql2 { INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1 }
  80. do_test $t.$tn.3 {
  81. sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count"
  82. } {32 ok 79}
  83. # Have connection 2 grow the file again. Check connection 1 is still ok.
  84. sql2 { INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1 }
  85. do_test $t.$tn.4 {
  86. sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count"
  87. } {64 ok 149}
  88. # Check that the number of pages read by connection 1 indicates that the
  89. # "PRAGMA mmap_size" command worked.
  90. do_test $t.$tn.5 { nRead db } $nRead
  91. }
  92. }
  93. set ::rcnt 0
  94. proc rblob {n} {
  95. set ::rcnt [expr (($::rcnt << 3) + $::rcnt + 456) & 0xFFFFFFFF]
  96. set str [format %.8x [expr $::rcnt ^ 0xbdf20da3]]
  97. string range [string repeat $str [expr $n/4]] 1 $n
  98. }
  99. reset_db
  100. db func rblob rblob
  101. do_execsql_test 2.1 {
  102. PRAGMA auto_vacuum = 1;
  103. PRAGMA mmap_size = 67108864;
  104. PRAGMA journal_mode = wal;
  105. CREATE TABLE t1(a, b, UNIQUE(a, b));
  106. INSERT INTO t1 VALUES(rblob(500), rblob(500));
  107. INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2
  108. INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4
  109. INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8
  110. INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16
  111. INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 32
  112. PRAGMA wal_checkpoint;
  113. } {67108864 wal 0 103 103}
  114. do_execsql_test 2.2 {
  115. PRAGMA auto_vacuum;
  116. SELECT count(*) FROM t1;
  117. } {1 32}
  118. if {[permutation] != "inmemory_journal"} {
  119. do_test 2.3 {
  120. sqlite3 db2 test.db
  121. db2 func rblob rblob
  122. db2 eval {
  123. DELETE FROM t1 WHERE (rowid%4);
  124. PRAGMA wal_checkpoint;
  125. }
  126. db2 eval {
  127. INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16
  128. SELECT count(*) FROM t1;
  129. }
  130. } {16}
  131. do_execsql_test 2.4 {
  132. PRAGMA wal_checkpoint;
  133. } {0 24 24}
  134. db2 close
  135. }
  136. reset_db
  137. execsql { PRAGMA mmap_size = 67108864; }
  138. db func rblob rblob
  139. do_execsql_test 3.1 {
  140. PRAGMA auto_vacuum = 1;
  141. CREATE TABLE t1(a, b, UNIQUE(a, b));
  142. INSERT INTO t1 VALUES(rblob(500), rblob(500));
  143. INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2
  144. INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4
  145. INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8
  146. CREATE TABLE t2(a, b, UNIQUE(a, b));
  147. INSERT INTO t2 SELECT * FROM t1;
  148. } {}
  149. do_test 3.2 {
  150. set nRow 0
  151. db eval {SELECT * FROM t2 ORDER BY a, b} {
  152. if {$nRow==4} { db eval { DELETE FROM t1 } }
  153. incr nRow
  154. }
  155. set nRow
  156. } {8}
  157. #-------------------------------------------------------------------------
  158. # Ensure that existing cursors using xFetch() pages see changes made
  159. # to rows using the incrblob API.
  160. #
  161. reset_db
  162. execsql { PRAGMA mmap_size = 67108864; }
  163. set aaa [string repeat a 400]
  164. set bbb [string repeat b 400]
  165. set ccc [string repeat c 400]
  166. set ddd [string repeat d 400]
  167. set eee [string repeat e 400]
  168. do_execsql_test 4.1 {
  169. PRAGMA page_size = 1024;
  170. CREATE TABLE t1(x);
  171. INSERT INTO t1 VALUES($aaa);
  172. INSERT INTO t1 VALUES($bbb);
  173. INSERT INTO t1 VALUES($ccc);
  174. INSERT INTO t1 VALUES($ddd);
  175. SELECT * FROM t1;
  176. BEGIN;
  177. } [list $aaa $bbb $ccc $ddd]
  178. do_test 4.2 {
  179. set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY rowid" -1 dummy]
  180. sqlite3_step $::STMT
  181. sqlite3_column_text $::STMT 0
  182. } $aaa
  183. do_test 4.3 {
  184. foreach r {2 3 4} {
  185. set fd [db incrblob t1 x $r]
  186. puts -nonewline $fd $eee
  187. close $fd
  188. }
  189. set res [list]
  190. while {"SQLITE_ROW" == [sqlite3_step $::STMT]} {
  191. lappend res [sqlite3_column_text $::STMT 0]
  192. }
  193. set res
  194. } [list $eee $eee $eee]
  195. do_test 4.4 {
  196. sqlite3_finalize $::STMT
  197. } SQLITE_OK
  198. do_execsql_test 4.5 { COMMIT }
  199. #-------------------------------------------------------------------------
  200. # Ensure that existing cursors holding xFetch() references are not
  201. # confused if those pages are moved to make way for the root page of a
  202. # new table or index.
  203. #
  204. reset_db
  205. execsql { PRAGMA mmap_size = 67108864; }
  206. do_execsql_test 5.1 {
  207. PRAGMA auto_vacuum = 2;
  208. PRAGMA page_size = 1024;
  209. CREATE TABLE t1(x);
  210. INSERT INTO t1 VALUES($aaa);
  211. INSERT INTO t1 VALUES($bbb);
  212. INSERT INTO t1 VALUES($ccc);
  213. INSERT INTO t1 VALUES($ddd);
  214. PRAGMA auto_vacuum;
  215. SELECT * FROM t1;
  216. } [list 2 $aaa $bbb $ccc $ddd]
  217. do_test 5.2 {
  218. set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY rowid" -1 dummy]
  219. sqlite3_step $::STMT
  220. sqlite3_column_text $::STMT 0
  221. } $aaa
  222. do_execsql_test 5.3 {
  223. CREATE TABLE t2(x);
  224. INSERT INTO t2 VALUES('tricked you!');
  225. INSERT INTO t2 VALUES('tricked you!');
  226. }
  227. do_test 5.4 {
  228. sqlite3_step $::STMT
  229. sqlite3_column_text $::STMT 0
  230. } $bbb
  231. do_test 5.5 {
  232. sqlite3_finalize $::STMT
  233. } SQLITE_OK
  234. #-------------------------------------------------------------------------
  235. # Test various mmap_size settings.
  236. #
  237. foreach {tn1 mmap1 mmap2} {
  238. 1 6144 167773
  239. 2 18432 140399
  240. 3 43008 401302
  241. 4 92160 253899
  242. 5 190464 2
  243. 6 387072 752431
  244. 7 780288 291143
  245. 8 1566720 594306
  246. 9 3139584 829137
  247. 10 6285312 793963
  248. 11 12576768 1015590
  249. } {
  250. do_multiclient_test tn {
  251. sql1 {
  252. CREATE TABLE t1(a PRIMARY KEY);
  253. CREATE TABLE t2(x);
  254. INSERT INTO t2 VALUES('');
  255. }
  256. code1 [register_rblob_code db 0]
  257. code2 [register_rblob_code db2 444]
  258. sql1 "PRAGMA mmap_size = $mmap1"
  259. sql2 "PRAGMA mmap_size = $mmap2"
  260. do_test $tn1.$tn {
  261. for {set i 1} {$i <= 100} {incr i} {
  262. if {$i % 2} {
  263. set c1 sql1
  264. set c2 sql2
  265. } else {
  266. set c1 sql2
  267. set c2 sql1
  268. }
  269. $c1 {
  270. INSERT INTO t1 VALUES( rblob(5000) );
  271. UPDATE t2 SET x = (SELECT md5sum(a) FROM t1);
  272. }
  273. set res [$c2 {
  274. SELECT count(*) FROM t1;
  275. SELECT x == (SELECT md5sum(a) FROM t1) FROM t2;
  276. PRAGMA integrity_check;
  277. }]
  278. if {$res != [list $i 1 ok]} {
  279. do_test $tn1.$tn.$i {
  280. set ::res
  281. } [list $i 1 ok]
  282. }
  283. }
  284. set res 1
  285. } {1}
  286. }
  287. }
  288. finish_test