OLD | NEW |
1 # 2007 August 21 | 1 # 2007 August 21 |
2 # | 2 # |
3 # The author disclaims copyright to this source code. In place of | 3 # The author disclaims copyright to this source code. In place of |
4 # a legal notice, here is a blessing: | 4 # a legal notice, here is a blessing: |
5 # | 5 # |
6 # May you do good and not evil. | 6 # May you do good and not evil. |
7 # May you find forgiveness for yourself and forgive others. | 7 # May you find forgiveness for yourself and forgive others. |
8 # May you share freely, never taking more than you give. | 8 # May you share freely, never taking more than you give. |
9 # | 9 # |
10 #*********************************************************************** | 10 #*********************************************************************** |
11 # | 11 # |
12 # The focus of this file is testing some specific characteristics of the | 12 # The focus of this file is testing some specific characteristics of the |
13 # IO traffic generated by SQLite (making sure SQLite is not writing out | 13 # IO traffic generated by SQLite (making sure SQLite is not writing out |
14 # more database pages than it has to, stuff like that). | 14 # more database pages than it has to, stuff like that). |
15 # | 15 # |
16 | 16 |
17 set testdir [file dirname $argv0] | 17 set testdir [file dirname $argv0] |
18 source $testdir/tester.tcl | 18 source $testdir/tester.tcl |
| 19 set ::testprefix io |
19 | 20 |
20 db close | 21 db close |
21 sqlite3_simulate_device | 22 sqlite3_simulate_device |
22 sqlite3 db test.db -vfs devsym | 23 sqlite3 db test.db -vfs devsym |
23 | 24 |
24 # Test summary: | 25 # Test summary: |
25 # | 26 # |
26 # io-1.* - Test that quick-balance does not journal pages unnecessarily. | 27 # io-1.* - Test that quick-balance does not journal pages unnecessarily. |
27 # | 28 # |
28 # io-2.* - Test the "atomic-write optimization". | 29 # io-2.* - Test the "atomic-write optimization". |
29 # | 30 # |
30 # io-3.* - Test the IO traffic enhancements triggered when the | 31 # io-3.* - Test the IO traffic enhancements triggered when the |
31 # IOCAP_SEQUENTIAL device capability flag is set (no | 32 # IOCAP_SEQUENTIAL device capability flag is set (no |
32 # fsync() calls on the journal file). | 33 # fsync() calls on the journal file). |
33 # | 34 # |
34 # io-4.* - Test the IO traffic enhancements triggered when the | 35 # io-4.* - Test the IO traffic enhancements triggered when the |
35 # IOCAP_SAFE_APPEND device capability flag is set (fewer | 36 # IOCAP_SAFE_APPEND device capability flag is set (fewer |
36 # fsync() calls on the journal file, no need to set nRec | 37 # fsync() calls on the journal file, no need to set nRec |
37 # field in the single journal header). | 38 # field in the single journal header). |
38 # | 39 # |
39 # io-5.* - Test that the default page size is selected and used | 40 # io-5.* - Test that the default page size is selected and used |
40 # correctly. | 41 # correctly. |
| 42 # |
| 43 # io-6.* - Test that the pager-cache is not being flushed unnecessarily |
| 44 # after a transaction that uses the special atomic-write path |
| 45 # is committed. |
41 # | 46 # |
42 | 47 |
43 set ::nWrite 0 | 48 set ::nWrite 0 |
44 proc nWrite {db} { | 49 proc nWrite {db} { |
45 set bt [btree_from_db $db] | 50 set bt [btree_from_db $db] |
46 db_enter $db | 51 db_enter $db |
47 array set stats [btree_pager_stats $bt] | 52 array set stats [btree_pager_stats $bt] |
48 db_leave $db | 53 db_leave $db |
49 set res [expr $stats(write) - $::nWrite] | 54 set res [expr $stats(write) - $::nWrite] |
50 set ::nWrite $stats(write) | 55 set ::nWrite $stats(write) |
(...skipping 88 matching lines...) Loading... |
139 } {2 4} | 144 } {2 4} |
140 | 145 |
141 # Set the device-characteristic mask to include the SQLITE_IOCAP_ATOMIC, | 146 # Set the device-characteristic mask to include the SQLITE_IOCAP_ATOMIC, |
142 # then do another INSERT similar to the one in io-2.2. This should | 147 # then do another INSERT similar to the one in io-2.2. This should |
143 # only write 1 page and require a single fsync(). | 148 # only write 1 page and require a single fsync(). |
144 # | 149 # |
145 # The single fsync() is the database file. Only one page is reported as | 150 # The single fsync() is the database file. Only one page is reported as |
146 # written because page 1 - the change-counter page - is written using | 151 # written because page 1 - the change-counter page - is written using |
147 # an out-of-band method that bypasses the write counter. | 152 # an out-of-band method that bypasses the write counter. |
148 # | 153 # |
| 154 # UPDATE: As of [05f98d4eec] (adding SQLITE_DBSTATUS_CACHE_WRITE), the |
| 155 # second write is also counted. So this now reports two writes and a |
| 156 # single fsync. |
| 157 # |
149 sqlite3_simulate_device -char atomic | 158 sqlite3_simulate_device -char atomic |
150 do_test io-2.3 { | 159 do_test io-2.3 { |
151 execsql { INSERT INTO abc VALUES(3, 4) } | 160 execsql { INSERT INTO abc VALUES(3, 4) } |
152 list [nWrite db] [nSync] | 161 list [nWrite db] [nSync] |
153 } {1 1} | 162 } {2 1} |
154 | 163 |
155 # Test that the journal file is not created and the change-counter is | 164 # Test that the journal file is not created and the change-counter is |
156 # updated when the atomic-write optimization is used. | 165 # updated when the atomic-write optimization is used. |
157 # | 166 # |
158 do_test io-2.4.1 { | 167 do_test io-2.4.1 { |
159 execsql { | 168 execsql { |
160 BEGIN; | 169 BEGIN; |
161 INSERT INTO abc VALUES(5, 6); | 170 INSERT INTO abc VALUES(5, 6); |
162 } | 171 } |
163 sqlite3 db2 test.db -vfs devsym | 172 sqlite3 db2 test.db -vfs devsym |
(...skipping 32 matching lines...) Loading... |
196 | 205 |
197 # Test that the journal file is created and sync()d if the transaction | 206 # Test that the journal file is created and sync()d if the transaction |
198 # modifies a single database page and also appends a page to the file. | 207 # modifies a single database page and also appends a page to the file. |
199 # Internally, this case is handled differently to the one above. The | 208 # Internally, this case is handled differently to the one above. The |
200 # journal file is not actually created until the 'COMMIT' statement | 209 # journal file is not actually created until the 'COMMIT' statement |
201 # is executed. | 210 # is executed. |
202 # | 211 # |
203 # Changed 2010-03-27: The size of the database is now stored in | 212 # Changed 2010-03-27: The size of the database is now stored in |
204 # bytes 28..31 and so when a page is added to the database, page 1 | 213 # bytes 28..31 and so when a page is added to the database, page 1 |
205 # is immediately modified and the journal file immediately comes into | 214 # is immediately modified and the journal file immediately comes into |
206 # existance. To fix this test, the BEGIN is changed into a a | 215 # existence. To fix this test, the BEGIN is changed into a a |
207 # BEGIN IMMEDIATE and the INSERT is omitted. | 216 # BEGIN IMMEDIATE and the INSERT is omitted. |
208 # | 217 # |
209 do_test io-2.6.1 { | 218 do_test io-2.6.1 { |
210 execsql { | 219 execsql { |
211 BEGIN IMMEDIATE; | 220 BEGIN IMMEDIATE; |
212 -- INSERT INTO abc VALUES(9, randstr(1000,1000)); | 221 -- INSERT INTO abc VALUES(9, randstr(1000,1000)); |
213 } | 222 } |
214 file exists test.db-journal | 223 file exists test.db-journal |
215 } {0} | 224 } {0} |
216 do_test io-2.6.2 { | 225 do_test io-2.6.2 { |
217 # Create a file at "test.db-journal". This will prevent SQLite from | 226 # Create a file at "test.db-journal". This will prevent SQLite from |
218 # opening the journal for exclusive access. As a result, the COMMIT | 227 # opening the journal for exclusive access. As a result, the COMMIT |
219 # should fail with SQLITE_CANTOPEN and the transaction rolled back. | 228 # should fail with SQLITE_CANTOPEN and the transaction rolled back. |
220 # | 229 # |
221 file mkdir test.db-journal | 230 file mkdir test.db-journal |
222 catchsql { | 231 catchsql { |
223 INSERT INTO abc VALUES(9, randstr(1000,1000)); | 232 INSERT INTO abc VALUES(9, randstr(1000,1000)); |
224 COMMIT | 233 COMMIT |
225 } | 234 } |
226 } {1 {unable to open database file}} | 235 } {1 {unable to open database file}} |
227 do_test io-2.6.3 { | 236 do_test io-2.6.3 { |
228 file delete -force test.db-journal | 237 forcedelete test.db-journal |
229 catchsql { COMMIT } | 238 catchsql { COMMIT } |
230 } {0 {}} | 239 } {0 {}} |
231 do_test io-2.6.4 { | 240 do_test io-2.6.4 { |
232 execsql { SELECT * FROM abc } | 241 execsql { SELECT * FROM abc } |
233 } {1 2 3 4 5 6 7 8} | 242 } {1 2 3 4 5 6 7 8} |
234 | 243 |
235 # Test that if the database modification is part of multi-file commit, | 244 # Test that if the database modification is part of multi-file commit, |
236 # the journal file is always created. In this case, the journal file | 245 # the journal file is always created. In this case, the journal file |
237 # is created during execution of the COMMIT statement, so we have to | 246 # is created during execution of the COMMIT statement, so we have to |
238 # use the same technique to check that it is created as in the above | 247 # use the same technique to check that it is created as in the above |
239 # block. | 248 # block. |
240 file delete -force test2.db test2.db-journal | 249 forcedelete test2.db test2.db-journal |
241 ifcapable attach { | 250 ifcapable attach { |
242 do_test io-2.7.1 { | 251 do_test io-2.7.1 { |
243 execsql { | 252 execsql { |
244 ATTACH 'test2.db' AS aux; | 253 ATTACH 'test2.db' AS aux; |
245 PRAGMA aux.page_size = 1024; | 254 PRAGMA aux.page_size = 1024; |
246 CREATE TABLE aux.abc2(a, b); | 255 CREATE TABLE aux.abc2(a, b); |
247 BEGIN; | 256 BEGIN; |
248 INSERT INTO abc VALUES(9, 10); | 257 INSERT INTO abc VALUES(9, 10); |
249 } | 258 } |
250 file exists test.db-journal | 259 file exists test.db-journal |
251 } {0} | 260 } {0} |
252 do_test io-2.7.2 { | 261 do_test io-2.7.2 { |
253 execsql { INSERT INTO abc2 SELECT * FROM abc } | 262 execsql { INSERT INTO abc2 SELECT * FROM abc } |
254 file exists test2.db-journal | 263 file exists test2.db-journal |
255 } {0} | 264 } {0} |
256 do_test io-2.7.3 { | 265 do_test io-2.7.3 { |
257 execsql { SELECT * FROM abc UNION ALL SELECT * FROM abc2 } | 266 execsql { SELECT * FROM abc UNION ALL SELECT * FROM abc2 } |
258 } {1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10} | 267 } {1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10} |
259 do_test io-2.7.4 { | 268 do_test io-2.7.4 { |
260 file mkdir test2.db-journal | 269 file mkdir test2.db-journal |
261 catchsql { COMMIT } | 270 catchsql { COMMIT } |
262 } {1 {unable to open database file}} | 271 } {1 {unable to open database file}} |
263 do_test io-2.7.5 { | 272 do_test io-2.7.5 { |
264 file delete -force test2.db-journal | 273 forcedelete test2.db-journal |
265 catchsql { COMMIT } | 274 catchsql { COMMIT } |
266 } {1 {cannot commit - no transaction is active}} | 275 } {1 {cannot commit - no transaction is active}} |
267 do_test io-2.7.6 { | 276 do_test io-2.7.6 { |
268 execsql { SELECT * FROM abc UNION ALL SELECT * FROM abc2 } | 277 execsql { SELECT * FROM abc UNION ALL SELECT * FROM abc2 } |
269 } {1 2 3 4 5 6 7 8} | 278 } {1 2 3 4 5 6 7 8} |
270 } | 279 } |
271 | 280 |
272 # Try an explicit ROLLBACK before the journal file is created. | 281 # Try an explicit ROLLBACK before the journal file is created. |
273 # | 282 # |
274 do_test io-2.8.1 { | 283 do_test io-2.8.1 { |
(...skipping 22 matching lines...) Loading... |
297 sqlite3_simulate_device -char atomic -sectorsize 2048 | 306 sqlite3_simulate_device -char atomic -sectorsize 2048 |
298 execsql { | 307 execsql { |
299 BEGIN; | 308 BEGIN; |
300 INSERT INTO abc VALUES(9, 10); | 309 INSERT INTO abc VALUES(9, 10); |
301 } | 310 } |
302 file exists test.db-journal | 311 file exists test.db-journal |
303 } {1} | 312 } {1} |
304 do_test io-2.9.2 { | 313 do_test io-2.9.2 { |
305 execsql { ROLLBACK; } | 314 execsql { ROLLBACK; } |
306 db close | 315 db close |
307 file delete -force test.db test.db-journal | 316 forcedelete test.db test.db-journal |
308 sqlite3 db test.db -vfs devsym | 317 sqlite3 db test.db -vfs devsym |
309 execsql { | 318 execsql { |
310 PRAGMA auto_vacuum = OFF; | 319 PRAGMA auto_vacuum = OFF; |
311 PRAGMA page_size = 2048; | 320 PRAGMA page_size = 2048; |
312 CREATE TABLE abc(a, b); | 321 CREATE TABLE abc(a, b); |
313 } | 322 } |
314 execsql { | 323 execsql { |
315 BEGIN; | 324 BEGIN; |
316 INSERT INTO abc VALUES(9, 10); | 325 INSERT INTO abc VALUES(9, 10); |
317 } | 326 } |
(...skipping 50 matching lines...) Loading... |
368 | 377 |
369 } ;# /* ifcapable atomicwrite */ | 378 } ;# /* ifcapable atomicwrite */ |
370 | 379 |
371 #---------------------------------------------------------------------- | 380 #---------------------------------------------------------------------- |
372 # Test cases io-3.* test the IOCAP_SEQUENTIAL optimization. | 381 # Test cases io-3.* test the IOCAP_SEQUENTIAL optimization. |
373 # | 382 # |
374 sqlite3_simulate_device -char sequential -sectorsize 0 | 383 sqlite3_simulate_device -char sequential -sectorsize 0 |
375 ifcapable pager_pragmas { | 384 ifcapable pager_pragmas { |
376 do_test io-3.1 { | 385 do_test io-3.1 { |
377 db close | 386 db close |
378 file delete -force test.db test.db-journal | 387 forcedelete test.db test.db-journal |
379 sqlite3 db test.db -vfs devsym | 388 sqlite3 db test.db -vfs devsym |
380 db eval { | 389 db eval { |
381 PRAGMA auto_vacuum=OFF; | 390 PRAGMA auto_vacuum=OFF; |
382 } | 391 } |
383 # File size might be 1 due to the hack to work around ticket #3260. | 392 # File size might be 1 due to the hack to work around ticket #3260. |
384 # Search for #3260 in os_unix.c for additional information. | 393 # Search for #3260 in os_unix.c for additional information. |
385 expr {[file size test.db]>1} | 394 expr {[file size test.db]>1} |
386 } {0} | 395 } {0} |
387 do_test io-3.2 { | 396 do_test io-3.2 { |
388 execsql { CREATE TABLE abc(a, b) } | 397 execsql { CREATE TABLE abc(a, b) } |
(...skipping 148 matching lines...) Loading... |
537 {atomic} 512 8192 | 546 {atomic} 512 8192 |
538 {atomic512} 512 1024 | 547 {atomic512} 512 1024 |
539 {atomic2K} 512 2048 | 548 {atomic2K} 512 2048 |
540 {atomic2K} 4096 4096 | 549 {atomic2K} 4096 4096 |
541 {atomic2K atomic} 512 8192 | 550 {atomic2K atomic} 512 8192 |
542 {atomic64K} 512 1024 | 551 {atomic64K} 512 1024 |
543 } { | 552 } { |
544 incr tn | 553 incr tn |
545 if {$pgsize>$::SQLITE_MAX_PAGE_SIZE} continue | 554 if {$pgsize>$::SQLITE_MAX_PAGE_SIZE} continue |
546 db close | 555 db close |
547 file delete -force test.db test.db-journal | 556 forcedelete test.db test.db-journal |
548 sqlite3_simulate_device -char $char -sectorsize $sectorsize | 557 sqlite3_simulate_device -char $char -sectorsize $sectorsize |
549 sqlite3 db test.db -vfs devsym | 558 sqlite3 db test.db -vfs devsym |
550 db eval { | 559 db eval { |
551 PRAGMA auto_vacuum=OFF; | 560 PRAGMA auto_vacuum=OFF; |
552 } | 561 } |
553 ifcapable !atomicwrite { | 562 ifcapable !atomicwrite { |
554 if {[regexp {^atomic} $char]} continue | 563 if {[regexp {^atomic} $char]} continue |
555 } | 564 } |
556 do_test io-5.$tn { | 565 do_test io-5.$tn { |
557 execsql { | 566 execsql { |
558 CREATE TABLE abc(a, b, c); | 567 CREATE TABLE abc(a, b, c); |
559 } | 568 } |
560 expr {[file size test.db]/2} | 569 expr {[file size test.db]/2} |
561 } $pgsize | 570 } $pgsize |
562 } | 571 } |
563 | 572 |
| 573 #---------------------------------------------------------------------- |
| 574 # |
| 575 do_test io-6.1 { |
| 576 db close |
| 577 sqlite3_simulate_device -char atomic |
| 578 forcedelete test.db |
| 579 sqlite3 db test.db -vfs devsym |
| 580 execsql { |
| 581 PRAGMA mmap_size = 0; |
| 582 PRAGMA page_size = 1024; |
| 583 PRAGMA cache_size = 2000; |
| 584 CREATE TABLE t1(x); |
| 585 CREATE TABLE t2(x); |
| 586 CREATE TABLE t3(x); |
| 587 CREATE INDEX i3 ON t3(x); |
| 588 INSERT INTO t3 VALUES(randomblob(100)); |
| 589 INSERT INTO t3 SELECT randomblob(100) FROM t3; |
| 590 INSERT INTO t3 SELECT randomblob(100) FROM t3; |
| 591 INSERT INTO t3 SELECT randomblob(100) FROM t3; |
| 592 INSERT INTO t3 SELECT randomblob(100) FROM t3; |
| 593 INSERT INTO t3 SELECT randomblob(100) FROM t3; |
| 594 INSERT INTO t3 SELECT randomblob(100) FROM t3; |
| 595 INSERT INTO t3 SELECT randomblob(100) FROM t3; |
| 596 INSERT INTO t3 SELECT randomblob(100) FROM t3; |
| 597 INSERT INTO t3 SELECT randomblob(100) FROM t3; |
| 598 INSERT INTO t3 SELECT randomblob(100) FROM t3; |
| 599 INSERT INTO t3 SELECT randomblob(100) FROM t3; |
| 600 } |
| 601 |
| 602 db_save_and_close |
| 603 } {} |
| 604 |
| 605 foreach {tn sql} { |
| 606 1 { BEGIN; |
| 607 INSERT INTO t1 VALUES('123'); |
| 608 INSERT INTO t2 VALUES('456'); |
| 609 COMMIT; |
| 610 } |
| 611 2 { BEGIN; |
| 612 INSERT INTO t1 VALUES('123'); |
| 613 COMMIT; |
| 614 } |
| 615 } { |
| 616 |
| 617 # These tests don't work with memsubsys1, as it causes the effective page |
| 618 # cache size to become too small to hold the entire db in memory. |
| 619 if {[permutation] == "memsubsys1"} continue |
| 620 |
| 621 db_restore |
| 622 sqlite3 db test.db -vfs devsym |
| 623 execsql { |
| 624 PRAGMA cache_size = 2000; |
| 625 PRAGMA mmap_size = 0; |
| 626 SELECT x FROM t3 ORDER BY rowid; |
| 627 SELECT x FROM t3 ORDER BY x; |
| 628 } |
| 629 do_execsql_test 6.2.$tn.1 { PRAGMA integrity_check } {ok} |
| 630 do_execsql_test 6.2.$tn.2 $sql |
| 631 |
| 632 # Corrupt the database file on disk. This should not matter for the |
| 633 # purposes of the following "PRAGMA integrity_check", as the entire |
| 634 # database should be cached in the pager-cache. If corruption is |
| 635 # reported, it indicates that executing $sql caused the pager cache |
| 636 # to be flushed. Which is a bug. |
| 637 hexio_write test.db [expr 1024 * 5] [string repeat 00 2048] |
| 638 do_execsql_test 6.2.$tn.3 { PRAGMA integrity_check } {ok} |
| 639 db close |
| 640 } |
| 641 |
564 sqlite3_simulate_device -char {} -sectorsize 0 | 642 sqlite3_simulate_device -char {} -sectorsize 0 |
565 finish_test | 643 finish_test |
OLD | NEW |