146abae81Sdanielk1977# 2007 August 21 246abae81Sdanielk1977# 346abae81Sdanielk1977# The author disclaims copyright to this source code. In place of 446abae81Sdanielk1977# a legal notice, here is a blessing: 546abae81Sdanielk1977# 646abae81Sdanielk1977# May you do good and not evil. 746abae81Sdanielk1977# May you find forgiveness for yourself and forgive others. 846abae81Sdanielk1977# May you share freely, never taking more than you give. 946abae81Sdanielk1977# 1046abae81Sdanielk1977#*********************************************************************** 1146abae81Sdanielk1977# 1246abae81Sdanielk1977# The focus of this file is testing some specific characteristics of the 1346abae81Sdanielk1977# IO traffic generated by SQLite (making sure SQLite is not writing out 1446abae81Sdanielk1977# more database pages than it has to, stuff like that). 1546abae81Sdanielk1977# 1646abae81Sdanielk1977 1746abae81Sdanielk1977set testdir [file dirname $argv0] 1846abae81Sdanielk1977source $testdir/tester.tcl 194eb9b721Smistachkinset ::testprefix io 2046abae81Sdanielk1977 21bf260978Sdanielk1977db close 22bf260978Sdanielk1977sqlite3_simulate_device 23bf260978Sdanielk1977sqlite3 db test.db -vfs devsym 24bf260978Sdanielk1977 252ca0f863Sdanielk1977# Test summary: 262ca0f863Sdanielk1977# 272ca0f863Sdanielk1977# io-1.* - Test that quick-balance does not journal pages unnecessarily. 286897ca30Sdanielk1977# 296897ca30Sdanielk1977# io-2.* - Test the "atomic-write optimization". 306897ca30Sdanielk1977# 316897ca30Sdanielk1977# io-3.* - Test the IO traffic enhancements triggered when the 326897ca30Sdanielk1977# IOCAP_SEQUENTIAL device capability flag is set (no 336897ca30Sdanielk1977# fsync() calls on the journal file). 346897ca30Sdanielk1977# 356897ca30Sdanielk1977# io-4.* - Test the IO traffic enhancements triggered when the 366897ca30Sdanielk1977# IOCAP_SAFE_APPEND device capability flag is set (fewer 376897ca30Sdanielk1977# fsync() calls on the journal file, no need to set nRec 386897ca30Sdanielk1977# field in the single journal header). 392ca0f863Sdanielk1977# 409663b8f9Sdanielk1977# io-5.* - Test that the default page size is selected and used 419663b8f9Sdanielk1977# correctly. 429663b8f9Sdanielk1977# 438e4714b3Sdan# io-6.* - Test that the pager-cache is not being flushed unnecessarily 448e4714b3Sdan# after a transaction that uses the special atomic-write path 458e4714b3Sdan# is committed. 468e4714b3Sdan# 472ca0f863Sdanielk1977 4846abae81Sdanielk1977set ::nWrite 0 4946abae81Sdanielk1977proc nWrite {db} { 5046abae81Sdanielk1977 set bt [btree_from_db $db] 5127641703Sdrh db_enter $db 5246abae81Sdanielk1977 array set stats [btree_pager_stats $bt] 5327641703Sdrh db_leave $db 5446abae81Sdanielk1977 set res [expr $stats(write) - $::nWrite] 5546abae81Sdanielk1977 set ::nWrite $stats(write) 5646abae81Sdanielk1977 set res 5746abae81Sdanielk1977} 5846abae81Sdanielk1977 592ca0f863Sdanielk1977set ::nSync 0 602ca0f863Sdanielk1977proc nSync {} { 612ca0f863Sdanielk1977 set res [expr {$::sqlite_sync_count - $::nSync}] 622ca0f863Sdanielk1977 set ::nSync $::sqlite_sync_count 632ca0f863Sdanielk1977 set res 642ca0f863Sdanielk1977} 652ca0f863Sdanielk1977 6646abae81Sdanielk1977do_test io-1.1 { 6746abae81Sdanielk1977 execsql { 68c2ded2afSdrh PRAGMA auto_vacuum = OFF; 6946abae81Sdanielk1977 PRAGMA page_size = 1024; 7046abae81Sdanielk1977 CREATE TABLE abc(a,b); 7146abae81Sdanielk1977 } 7246abae81Sdanielk1977 nWrite db 7346abae81Sdanielk1977} {2} 7446abae81Sdanielk1977 7546abae81Sdanielk1977# Insert into the table 4 records of aproximately 240 bytes each. 7646abae81Sdanielk1977# This should completely fill the root-page of the table. Each 7746abae81Sdanielk1977# INSERT causes 2 db pages to be written - the root-page of "abc" 7846abae81Sdanielk1977# and page 1 (db change-counter page). 7946abae81Sdanielk1977do_test io-1.2 { 8046abae81Sdanielk1977 set ret [list] 8146abae81Sdanielk1977 execsql { INSERT INTO abc VALUES(1,randstr(230,230)); } 8246abae81Sdanielk1977 lappend ret [nWrite db] 8346abae81Sdanielk1977 execsql { INSERT INTO abc VALUES(2,randstr(230,230)); } 8446abae81Sdanielk1977 lappend ret [nWrite db] 8546abae81Sdanielk1977 execsql { INSERT INTO abc VALUES(3,randstr(230,230)); } 8646abae81Sdanielk1977 lappend ret [nWrite db] 8746abae81Sdanielk1977 execsql { INSERT INTO abc VALUES(4,randstr(230,230)); } 8846abae81Sdanielk1977 lappend ret [nWrite db] 8946abae81Sdanielk1977} {2 2 2 2} 9046abae81Sdanielk1977 9146abae81Sdanielk1977# Insert another 240 byte record. This causes two leaf pages 9246abae81Sdanielk1977# to be added to the root page of abc. 4 pages in total 9346abae81Sdanielk1977# are written to the db file - the two leaf pages, the root 9446abae81Sdanielk1977# of abc and the change-counter page. 9546abae81Sdanielk1977do_test io-1.3 { 9646abae81Sdanielk1977 execsql { INSERT INTO abc VALUES(5,randstr(230,230)); } 9746abae81Sdanielk1977 nWrite db 9846abae81Sdanielk1977} {4} 9946abae81Sdanielk1977 10046abae81Sdanielk1977# Insert another 3 240 byte records. After this, the tree consists of 10146abae81Sdanielk1977# the root-node, which is close to empty, and two leaf pages, both of 10246abae81Sdanielk1977# which are full. 10346abae81Sdanielk1977do_test io-1.4 { 10446abae81Sdanielk1977 set ret [list] 10546abae81Sdanielk1977 execsql { INSERT INTO abc VALUES(6,randstr(230,230)); } 10646abae81Sdanielk1977 lappend ret [nWrite db] 10746abae81Sdanielk1977 execsql { INSERT INTO abc VALUES(7,randstr(230,230)); } 10846abae81Sdanielk1977 lappend ret [nWrite db] 10946abae81Sdanielk1977 execsql { INSERT INTO abc VALUES(8,randstr(230,230)); } 11046abae81Sdanielk1977 lappend ret [nWrite db] 11146abae81Sdanielk1977} {2 2 2} 11246abae81Sdanielk1977 11346abae81Sdanielk1977# This insert should use the quick-balance trick to add a third leaf 11446abae81Sdanielk1977# to the b-tree used to store table abc. It should only be necessary to 11546abae81Sdanielk1977# write to 3 pages to do this: the change-counter, the root-page and 11646abae81Sdanielk1977# the new leaf page. 11746abae81Sdanielk1977do_test io-1.5 { 11846abae81Sdanielk1977 execsql { INSERT INTO abc VALUES(9,randstr(230,230)); } 11946abae81Sdanielk1977 nWrite db 12046abae81Sdanielk1977} {3} 12146abae81Sdanielk1977 122d6b9386cSdrhifcapable atomicwrite { 1232ca0f863Sdanielk1977 1242ca0f863Sdanielk1977#---------------------------------------------------------------------- 1252ca0f863Sdanielk1977# Test cases io-2.* test the atomic-write optimization. 1262ca0f863Sdanielk1977# 1272ca0f863Sdanielk1977do_test io-2.1 { 1282ca0f863Sdanielk1977 execsql { DELETE FROM abc; VACUUM; } 1292ca0f863Sdanielk1977} {} 1302ca0f863Sdanielk1977 1312ca0f863Sdanielk1977# Clear the write and sync counts. 1322ca0f863Sdanielk1977nWrite db ; nSync 1332ca0f863Sdanielk1977 1342ca0f863Sdanielk1977# The following INSERT updates 2 pages and requires 4 calls to fsync(): 1352ca0f863Sdanielk1977# 1362ca0f863Sdanielk1977# 1) The directory in which the journal file is created, 1372ca0f863Sdanielk1977# 2) The journal file (to sync the page data), 1382ca0f863Sdanielk1977# 3) The journal file (to sync the journal file header), 1392ca0f863Sdanielk1977# 4) The database file. 1402ca0f863Sdanielk1977# 1412ca0f863Sdanielk1977do_test io-2.2 { 1422ca0f863Sdanielk1977 execsql { INSERT INTO abc VALUES(1, 2) } 1432ca0f863Sdanielk1977 list [nWrite db] [nSync] 1442ca0f863Sdanielk1977} {2 4} 1452ca0f863Sdanielk1977 1462ca0f863Sdanielk1977# Set the device-characteristic mask to include the SQLITE_IOCAP_ATOMIC, 1472ca0f863Sdanielk1977# then do another INSERT similar to the one in io-2.2. This should 1482ca0f863Sdanielk1977# only write 1 page and require a single fsync(). 1492ca0f863Sdanielk1977# 1502ca0f863Sdanielk1977# The single fsync() is the database file. Only one page is reported as 1512ca0f863Sdanielk1977# written because page 1 - the change-counter page - is written using 1522ca0f863Sdanielk1977# an out-of-band method that bypasses the write counter. 1532ca0f863Sdanielk1977# 1547a9fc59eSdan# UPDATE: As of [05f98d4eec] (adding SQLITE_DBSTATUS_CACHE_WRITE), the 1557a9fc59eSdan# second write is also counted. So this now reports two writes and a 1567a9fc59eSdan# single fsync. 1577a9fc59eSdan# 1582ca0f863Sdanielk1977sqlite3_simulate_device -char atomic 1592ca0f863Sdanielk1977do_test io-2.3 { 1602ca0f863Sdanielk1977 execsql { INSERT INTO abc VALUES(3, 4) } 1612ca0f863Sdanielk1977 list [nWrite db] [nSync] 1627a9fc59eSdan} {2 1} 1632ca0f863Sdanielk1977 1642ca0f863Sdanielk1977# Test that the journal file is not created and the change-counter is 1652ca0f863Sdanielk1977# updated when the atomic-write optimization is used. 1662ca0f863Sdanielk1977# 1672ca0f863Sdanielk1977do_test io-2.4.1 { 1682ca0f863Sdanielk1977 execsql { 1692ca0f863Sdanielk1977 BEGIN; 1702ca0f863Sdanielk1977 INSERT INTO abc VALUES(5, 6); 1712ca0f863Sdanielk1977 } 172bf260978Sdanielk1977 sqlite3 db2 test.db -vfs devsym 1732ca0f863Sdanielk1977 execsql { SELECT * FROM abc } db2 1742ca0f863Sdanielk1977} {1 2 3 4} 1752ca0f863Sdanielk1977do_test io-2.4.2 { 1762ca0f863Sdanielk1977 file exists test.db-journal 1772ca0f863Sdanielk1977} {0} 1782ca0f863Sdanielk1977do_test io-2.4.3 { 1792ca0f863Sdanielk1977 execsql { COMMIT } 1802ca0f863Sdanielk1977 execsql { SELECT * FROM abc } db2 1812ca0f863Sdanielk1977} {1 2 3 4 5 6} 1822ca0f863Sdanielk1977db2 close 1832ca0f863Sdanielk1977 1842ca0f863Sdanielk1977# Test that the journal file is created and sync()d if the transaction 1852ca0f863Sdanielk1977# modifies more than one database page, even if the IOCAP_ATOMIC flag 1862ca0f863Sdanielk1977# is set. 1872ca0f863Sdanielk1977# 1882ca0f863Sdanielk1977do_test io-2.5.1 { 1892ca0f863Sdanielk1977 execsql { CREATE TABLE def(d, e) } 1902ca0f863Sdanielk1977 nWrite db ; nSync 1912ca0f863Sdanielk1977 execsql { 1922ca0f863Sdanielk1977 BEGIN; 1932ca0f863Sdanielk1977 INSERT INTO abc VALUES(7, 8); 1942ca0f863Sdanielk1977 } 1952ca0f863Sdanielk1977 file exists test.db-journal 1962ca0f863Sdanielk1977} {0} 1972ca0f863Sdanielk1977do_test io-2.5.2 { 1982ca0f863Sdanielk1977 execsql { INSERT INTO def VALUES('a', 'b'); } 1992ca0f863Sdanielk1977 file exists test.db-journal 2002ca0f863Sdanielk1977} {1} 2012ca0f863Sdanielk1977do_test io-2.5.3 { 2022ca0f863Sdanielk1977 execsql { COMMIT } 2032ca0f863Sdanielk1977 list [nWrite db] [nSync] 2042ca0f863Sdanielk1977} {3 4} 2052ca0f863Sdanielk1977 2062ca0f863Sdanielk1977# Test that the journal file is created and sync()d if the transaction 2072ca0f863Sdanielk1977# modifies a single database page and also appends a page to the file. 2082ca0f863Sdanielk1977# Internally, this case is handled differently to the one above. The 2092ca0f863Sdanielk1977# journal file is not actually created until the 'COMMIT' statement 2102ca0f863Sdanielk1977# is executed. 2112ca0f863Sdanielk1977# 2125e0ccc21Sdrh# Changed 2010-03-27: The size of the database is now stored in 2135e0ccc21Sdrh# bytes 28..31 and so when a page is added to the database, page 1 2145e0ccc21Sdrh# is immediately modified and the journal file immediately comes into 21548864df9Smistachkin# existence. To fix this test, the BEGIN is changed into a a 2165e0ccc21Sdrh# BEGIN IMMEDIATE and the INSERT is omitted. 2175e0ccc21Sdrh# 2182ca0f863Sdanielk1977do_test io-2.6.1 { 2192ca0f863Sdanielk1977 execsql { 2205e0ccc21Sdrh BEGIN IMMEDIATE; 2215e0ccc21Sdrh -- INSERT INTO abc VALUES(9, randstr(1000,1000)); 2222ca0f863Sdanielk1977 } 2232ca0f863Sdanielk1977 file exists test.db-journal 2242ca0f863Sdanielk1977} {0} 2252ca0f863Sdanielk1977do_test io-2.6.2 { 2262ca0f863Sdanielk1977 # Create a file at "test.db-journal". This will prevent SQLite from 2272ca0f863Sdanielk1977 # opening the journal for exclusive access. As a result, the COMMIT 2282ca0f863Sdanielk1977 # should fail with SQLITE_CANTOPEN and the transaction rolled back. 2292ca0f863Sdanielk1977 # 2308594373aSdanielk1977 file mkdir test.db-journal 2315e0ccc21Sdrh catchsql { 2325e0ccc21Sdrh INSERT INTO abc VALUES(9, randstr(1000,1000)); 2335e0ccc21Sdrh COMMIT 2345e0ccc21Sdrh } 2352ca0f863Sdanielk1977} {1 {unable to open database file}} 2362ca0f863Sdanielk1977do_test io-2.6.3 { 237fda06befSmistachkin forcedelete test.db-journal 2382ca0f863Sdanielk1977 catchsql { COMMIT } 2395e0ccc21Sdrh} {0 {}} 2402ca0f863Sdanielk1977do_test io-2.6.4 { 2412ca0f863Sdanielk1977 execsql { SELECT * FROM abc } 2422ca0f863Sdanielk1977} {1 2 3 4 5 6 7 8} 2432ca0f863Sdanielk1977 2442ca0f863Sdanielk1977# Test that if the database modification is part of multi-file commit, 2452ca0f863Sdanielk1977# the journal file is always created. In this case, the journal file 2462ca0f863Sdanielk1977# is created during execution of the COMMIT statement, so we have to 2472ca0f863Sdanielk1977# use the same technique to check that it is created as in the above 2482ca0f863Sdanielk1977# block. 249fda06befSmistachkinforcedelete test2.db test2.db-journal 2505a8f9374Sdanielk1977ifcapable attach { 2512ca0f863Sdanielk1977 do_test io-2.7.1 { 2522ca0f863Sdanielk1977 execsql { 2532ca0f863Sdanielk1977 ATTACH 'test2.db' AS aux; 2549663b8f9Sdanielk1977 PRAGMA aux.page_size = 1024; 2552ca0f863Sdanielk1977 CREATE TABLE aux.abc2(a, b); 2562ca0f863Sdanielk1977 BEGIN; 2572ca0f863Sdanielk1977 INSERT INTO abc VALUES(9, 10); 2582ca0f863Sdanielk1977 } 2592ca0f863Sdanielk1977 file exists test.db-journal 2602ca0f863Sdanielk1977 } {0} 2612ca0f863Sdanielk1977 do_test io-2.7.2 { 2622ca0f863Sdanielk1977 execsql { INSERT INTO abc2 SELECT * FROM abc } 2632ca0f863Sdanielk1977 file exists test2.db-journal 2642ca0f863Sdanielk1977 } {0} 2652ca0f863Sdanielk1977 do_test io-2.7.3 { 2662ca0f863Sdanielk1977 execsql { SELECT * FROM abc UNION ALL SELECT * FROM abc2 } 2672ca0f863Sdanielk1977 } {1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10} 2682ca0f863Sdanielk1977 do_test io-2.7.4 { 2698594373aSdanielk1977 file mkdir test2.db-journal 2702ca0f863Sdanielk1977 catchsql { COMMIT } 2712ca0f863Sdanielk1977 } {1 {unable to open database file}} 2722ca0f863Sdanielk1977 do_test io-2.7.5 { 273fda06befSmistachkin forcedelete test2.db-journal 2742ca0f863Sdanielk1977 catchsql { COMMIT } 2752ca0f863Sdanielk1977 } {1 {cannot commit - no transaction is active}} 2762ca0f863Sdanielk1977 do_test io-2.7.6 { 2772ca0f863Sdanielk1977 execsql { SELECT * FROM abc UNION ALL SELECT * FROM abc2 } 2782ca0f863Sdanielk1977 } {1 2 3 4 5 6 7 8} 2795a8f9374Sdanielk1977} 2802ca0f863Sdanielk1977 2812ca0f863Sdanielk1977# Try an explicit ROLLBACK before the journal file is created. 2822ca0f863Sdanielk1977# 2832ca0f863Sdanielk1977do_test io-2.8.1 { 2842ca0f863Sdanielk1977 execsql { 2852ca0f863Sdanielk1977 BEGIN; 2862ca0f863Sdanielk1977 DELETE FROM abc; 2872ca0f863Sdanielk1977 } 2882ca0f863Sdanielk1977 file exists test.db-journal 2892ca0f863Sdanielk1977} {0} 2902ca0f863Sdanielk1977do_test io-2.8.2 { 2912ca0f863Sdanielk1977 execsql { SELECT * FROM abc } 2922ca0f863Sdanielk1977} {} 2932ca0f863Sdanielk1977do_test io-2.8.3 { 2942ca0f863Sdanielk1977 execsql { 2952ca0f863Sdanielk1977 ROLLBACK; 2962ca0f863Sdanielk1977 SELECT * FROM abc; 2972ca0f863Sdanielk1977 } 2982ca0f863Sdanielk1977} {1 2 3 4 5 6 7 8} 2992ca0f863Sdanielk1977 300f8940aefSdanielk1977# Test that the atomic write optimisation is not enabled if the sector 301f8940aefSdanielk1977# size is larger than the page-size. 302f8940aefSdanielk1977# 303f8940aefSdanielk1977do_test io-2.9.1 { 3048a526873Sdrh db close 3058a526873Sdrh sqlite3 db test.db 306f8940aefSdanielk1977 sqlite3_simulate_device -char atomic -sectorsize 2048 307f8940aefSdanielk1977 execsql { 308f8940aefSdanielk1977 BEGIN; 309f8940aefSdanielk1977 INSERT INTO abc VALUES(9, 10); 310f8940aefSdanielk1977 } 311f8940aefSdanielk1977 file exists test.db-journal 312f8940aefSdanielk1977} {1} 313f8940aefSdanielk1977do_test io-2.9.2 { 314f8940aefSdanielk1977 execsql { ROLLBACK; } 315f8940aefSdanielk1977 db close 316fda06befSmistachkin forcedelete test.db test.db-journal 317bf260978Sdanielk1977 sqlite3 db test.db -vfs devsym 318f8940aefSdanielk1977 execsql { 319c2ded2afSdrh PRAGMA auto_vacuum = OFF; 320f8940aefSdanielk1977 PRAGMA page_size = 2048; 321f8940aefSdanielk1977 CREATE TABLE abc(a, b); 322f8940aefSdanielk1977 } 323f8940aefSdanielk1977 execsql { 324f8940aefSdanielk1977 BEGIN; 325f8940aefSdanielk1977 INSERT INTO abc VALUES(9, 10); 326f8940aefSdanielk1977 } 327f8940aefSdanielk1977 file exists test.db-journal 328f8940aefSdanielk1977} {0} 329f8940aefSdanielk1977do_test io-2.9.3 { 330f8940aefSdanielk1977 execsql { COMMIT } 331f8940aefSdanielk1977} {} 332f8940aefSdanielk1977 333f8940aefSdanielk1977# Test a couple of the more specific IOCAP_ATOMIC flags 334f8940aefSdanielk1977# (i.e IOCAP_ATOMIC2K etc.). 335f8940aefSdanielk1977# 336f8940aefSdanielk1977do_test io-2.10.1 { 337f8940aefSdanielk1977 sqlite3_simulate_device -char atomic1k 338f8940aefSdanielk1977 execsql { 339f8940aefSdanielk1977 BEGIN; 340f8940aefSdanielk1977 INSERT INTO abc VALUES(11, 12); 341f8940aefSdanielk1977 } 342f8940aefSdanielk1977 file exists test.db-journal 343f8940aefSdanielk1977} {1} 344f8940aefSdanielk1977do_test io-2.10.2 { 345f8940aefSdanielk1977 execsql { ROLLBACK } 346f8940aefSdanielk1977 sqlite3_simulate_device -char atomic2k 347f8940aefSdanielk1977 execsql { 348f8940aefSdanielk1977 BEGIN; 349f8940aefSdanielk1977 INSERT INTO abc VALUES(11, 12); 350f8940aefSdanielk1977 } 351f8940aefSdanielk1977 file exists test.db-journal 352f8940aefSdanielk1977} {0} 3536897ca30Sdanielk1977do_test io-2.10.3 { 3546897ca30Sdanielk1977 execsql { ROLLBACK } 3556897ca30Sdanielk1977} {} 356880c15beSdanielk1977 357880c15beSdanielk1977do_test io-2.11.0 { 358880c15beSdanielk1977 execsql { 359880c15beSdanielk1977 PRAGMA locking_mode = exclusive; 360880c15beSdanielk1977 PRAGMA locking_mode; 361880c15beSdanielk1977 } 362880c15beSdanielk1977} {exclusive exclusive} 363880c15beSdanielk1977do_test io-2.11.1 { 364880c15beSdanielk1977 execsql { 365880c15beSdanielk1977 INSERT INTO abc VALUES(11, 12); 366880c15beSdanielk1977 } 367880c15beSdanielk1977 file exists test.db-journal 368880c15beSdanielk1977} {0} 369880c15beSdanielk1977 370880c15beSdanielk1977do_test io-2.11.2 { 371880c15beSdanielk1977 execsql { 372880c15beSdanielk1977 PRAGMA locking_mode = normal; 373880c15beSdanielk1977 INSERT INTO abc VALUES(13, 14); 374880c15beSdanielk1977 } 375880c15beSdanielk1977 file exists test.db-journal 376880c15beSdanielk1977} {0} 377880c15beSdanielk1977 378d6b9386cSdrh} ;# /* ifcapable atomicwrite */ 3796897ca30Sdanielk1977 3806897ca30Sdanielk1977#---------------------------------------------------------------------- 3816897ca30Sdanielk1977# Test cases io-3.* test the IOCAP_SEQUENTIAL optimization. 3826897ca30Sdanielk1977# 3836897ca30Sdanielk1977sqlite3_simulate_device -char sequential -sectorsize 0 3844152e677Sdanielk1977ifcapable pager_pragmas { 3856897ca30Sdanielk1977 do_test io-3.1 { 3866897ca30Sdanielk1977 db close 387fda06befSmistachkin forcedelete test.db test.db-journal 388bf260978Sdanielk1977 sqlite3 db test.db -vfs devsym 389c2ded2afSdrh db eval { 390c2ded2afSdrh PRAGMA auto_vacuum=OFF; 391c2ded2afSdrh } 3925462624dSdrh # File size might be 1 due to the hack to work around ticket #3260. 3935462624dSdrh # Search for #3260 in os_unix.c for additional information. 3945462624dSdrh expr {[file size test.db]>1} 3956897ca30Sdanielk1977 } {0} 3966897ca30Sdanielk1977 do_test io-3.2 { 3976897ca30Sdanielk1977 execsql { CREATE TABLE abc(a, b) } 3986897ca30Sdanielk1977 nSync 3996897ca30Sdanielk1977 execsql { 4008c0a791aSdanielk1977 PRAGMA temp_store = memory; 4016897ca30Sdanielk1977 PRAGMA cache_size = 10; 4026897ca30Sdanielk1977 BEGIN; 4036897ca30Sdanielk1977 INSERT INTO abc VALUES('hello', 'world'); 4046897ca30Sdanielk1977 INSERT INTO abc SELECT * FROM abc; 4056897ca30Sdanielk1977 INSERT INTO abc SELECT * FROM abc; 4066897ca30Sdanielk1977 INSERT INTO abc SELECT * FROM abc; 4076897ca30Sdanielk1977 INSERT INTO abc SELECT * FROM abc; 4086897ca30Sdanielk1977 INSERT INTO abc SELECT * FROM abc; 4096897ca30Sdanielk1977 INSERT INTO abc SELECT * FROM abc; 4106897ca30Sdanielk1977 INSERT INTO abc SELECT * FROM abc; 4116897ca30Sdanielk1977 INSERT INTO abc SELECT * FROM abc; 4126897ca30Sdanielk1977 INSERT INTO abc SELECT * FROM abc; 4136897ca30Sdanielk1977 INSERT INTO abc SELECT * FROM abc; 4146897ca30Sdanielk1977 INSERT INTO abc SELECT * FROM abc; 4156897ca30Sdanielk1977 } 4166897ca30Sdanielk1977 # File has grown - showing there was a cache-spill - but there 4173e37f5dfSdanielk1977 # have been no calls to fsync(). The file is probably about 30KB. 4183e37f5dfSdanielk1977 # But some VFS implementations (symbian) buffer writes so the actual 4193e37f5dfSdanielk1977 # size may be a little less than that. So this test case just tests 4203e37f5dfSdanielk1977 # that the file is now greater than 20000 bytes in size. 4213e37f5dfSdanielk1977 list [expr [file size test.db]>20000] [nSync] 4223e37f5dfSdanielk1977 } {1 0} 4236897ca30Sdanielk1977 do_test io-3.3 { 4246897ca30Sdanielk1977 # The COMMIT requires a single fsync() - to the database file. 4256897ca30Sdanielk1977 execsql { COMMIT } 4266897ca30Sdanielk1977 list [file size test.db] [nSync] 4277da56b4fSdrh } "[expr {[nonzero_reserved_bytes]?40960:39936}] 1" 4284152e677Sdanielk1977} 4296897ca30Sdanielk1977 4306897ca30Sdanielk1977#---------------------------------------------------------------------- 4316897ca30Sdanielk1977# Test cases io-4.* test the IOCAP_SAFE_APPEND optimization. 4326897ca30Sdanielk1977# 4336897ca30Sdanielk1977sqlite3_simulate_device -char safe_append 4346897ca30Sdanielk1977 4356897ca30Sdanielk1977# With the SAFE_APPEND flag set, simple transactions require 3, rather 4366897ca30Sdanielk1977# than 4, calls to fsync(). The fsync() calls are on: 4376897ca30Sdanielk1977# 438dec6fae9Sdrh# 1) The directory in which the journal file is created, (unix only) 4396897ca30Sdanielk1977# 2) The journal file (to sync the page data), 4406897ca30Sdanielk1977# 3) The database file. 4416897ca30Sdanielk1977# 4426897ca30Sdanielk1977# Normally, when the SAFE_APPEND flag is not set, there is another fsync() 4436897ca30Sdanielk1977# on the journal file between steps (2) and (3) above. 4446897ca30Sdanielk1977# 445dec6fae9Sdrhset expected_sync_count 2 4466c533203Sshaneif {$::tcl_platform(platform)=="unix"} { 4476c533203Sshane ifcapable dirsync { 4486c533203Sshane incr expected_sync_count 449dec6fae9Sdrh } 4506c533203Sshane} 4516c533203Sshane 4526897ca30Sdanielk1977do_test io-4.1 { 4536897ca30Sdanielk1977 execsql { DELETE FROM abc } 4546897ca30Sdanielk1977 nSync 4556897ca30Sdanielk1977 execsql { INSERT INTO abc VALUES('a', 'b') } 4566897ca30Sdanielk1977 nSync 457dec6fae9Sdrh} $expected_sync_count 4586897ca30Sdanielk1977 4596897ca30Sdanielk1977# With SAFE_APPEND set, the nRec field of the journal file header should 4606897ca30Sdanielk1977# be set to 0xFFFFFFFF before the first journal sync. The nRec field 4616897ca30Sdanielk1977# occupies bytes 8-11 of the journal file. 4626897ca30Sdanielk1977# 4636897ca30Sdanielk1977do_test io-4.2.1 { 4646897ca30Sdanielk1977 execsql { BEGIN } 4656897ca30Sdanielk1977 execsql { INSERT INTO abc VALUES('c', 'd') } 4666897ca30Sdanielk1977 file exists test.db-journal 4676897ca30Sdanielk1977} {1} 468dec6fae9Sdrhif {$::tcl_platform(platform)=="unix"} { 4696897ca30Sdanielk1977 do_test io-4.2.2 { 470039edbb4Sdrh hexio_read test.db-journal 8 4 471039edbb4Sdrh } {FFFFFFFF} 472dec6fae9Sdrh} 4736897ca30Sdanielk1977do_test io-4.2.3 { 4746897ca30Sdanielk1977 execsql { COMMIT } 4756897ca30Sdanielk1977 nSync 476dec6fae9Sdrh} $expected_sync_count 4776897ca30Sdanielk1977sqlite3_simulate_device -char safe_append 4786897ca30Sdanielk1977 4796897ca30Sdanielk1977# With SAFE_APPEND set, there should only ever be one journal-header 4806897ca30Sdanielk1977# written to the database, even though the sync-mode is "full". 4816897ca30Sdanielk1977# 4826897ca30Sdanielk1977do_test io-4.3.1 { 4836897ca30Sdanielk1977 execsql { 4846897ca30Sdanielk1977 INSERT INTO abc SELECT * FROM abc; 4856897ca30Sdanielk1977 INSERT INTO abc SELECT * FROM abc; 4866897ca30Sdanielk1977 INSERT INTO abc SELECT * FROM abc; 4876897ca30Sdanielk1977 INSERT INTO abc SELECT * FROM abc; 4886897ca30Sdanielk1977 INSERT INTO abc SELECT * FROM abc; 4896897ca30Sdanielk1977 INSERT INTO abc SELECT * FROM abc; 4906897ca30Sdanielk1977 INSERT INTO abc SELECT * FROM abc; 4916897ca30Sdanielk1977 INSERT INTO abc SELECT * FROM abc; 4926897ca30Sdanielk1977 INSERT INTO abc SELECT * FROM abc; 4936897ca30Sdanielk1977 INSERT INTO abc SELECT * FROM abc; 4946897ca30Sdanielk1977 INSERT INTO abc SELECT * FROM abc; 4956897ca30Sdanielk1977 } 4966897ca30Sdanielk1977 expr {[file size test.db]/1024} 4976897ca30Sdanielk1977} {43} 4984152e677Sdanielk1977ifcapable pager_pragmas { 4996897ca30Sdanielk1977 do_test io-4.3.2 { 5006897ca30Sdanielk1977 execsql { 5016897ca30Sdanielk1977 PRAGMA synchronous = full; 5026897ca30Sdanielk1977 PRAGMA cache_size = 10; 5036897ca30Sdanielk1977 PRAGMA synchronous; 5046897ca30Sdanielk1977 } 5056897ca30Sdanielk1977 } {2} 5064152e677Sdanielk1977} 5076897ca30Sdanielk1977do_test io-4.3.3 { 5086897ca30Sdanielk1977 execsql { 5096897ca30Sdanielk1977 BEGIN; 5106897ca30Sdanielk1977 UPDATE abc SET a = 'x'; 5116897ca30Sdanielk1977 } 5126897ca30Sdanielk1977 file exists test.db-journal 5136897ca30Sdanielk1977} {1} 5143e37f5dfSdanielk1977if {$tcl_platform(platform) != "symbian"} { 5153e37f5dfSdanielk1977 # This test is not run on symbian because the file-buffer makes it 5163e37f5dfSdanielk1977 # difficult to predict the exact size of the file as reported by 5173e37f5dfSdanielk1977 # [file size]. 5186897ca30Sdanielk1977 do_test io-4.3.4 { 5196897ca30Sdanielk1977 # The UPDATE statement in the statement above modifies 41 pages 5206897ca30Sdanielk1977 # (all pages in the database except page 1 and the root page of 5216897ca30Sdanielk1977 # abc). Because the cache_size is set to 10, this must have required 5226897ca30Sdanielk1977 # at least 4 cache-spills. If there were no journal headers written 5236897ca30Sdanielk1977 # to the journal file after the cache-spill, then the size of the 5246897ca30Sdanielk1977 # journal file is give by: 5256897ca30Sdanielk1977 # 5266897ca30Sdanielk1977 # <jrnl file size> = <jrnl header size> + nPage * (<page-size> + 8) 5276897ca30Sdanielk1977 # 5286897ca30Sdanielk1977 # If the journal file contains additional headers, this formula 5296897ca30Sdanielk1977 # will not predict the size of the journal file. 5306897ca30Sdanielk1977 # 5316897ca30Sdanielk1977 file size test.db-journal 532334c80d6Sdrh } [expr 512 + (1024+8)*41] 5333e37f5dfSdanielk1977} 534f8940aefSdanielk1977 5359663b8f9Sdanielk1977#---------------------------------------------------------------------- 5369663b8f9Sdanielk1977# Test cases io-5.* test that the default page size is selected and 5379663b8f9Sdanielk1977# used correctly. 5389663b8f9Sdanielk1977# 5399663b8f9Sdanielk1977set tn 0 5409663b8f9Sdanielk1977foreach {char sectorsize pgsize} { 5419663b8f9Sdanielk1977 {} 512 1024 5429663b8f9Sdanielk1977 {} 1024 1024 5439663b8f9Sdanielk1977 {} 2048 2048 5449663b8f9Sdanielk1977 {} 8192 8192 5459663b8f9Sdanielk1977 {} 16384 8192 5469663b8f9Sdanielk1977 {atomic} 512 8192 5479663b8f9Sdanielk1977 {atomic512} 512 1024 5489663b8f9Sdanielk1977 {atomic2K} 512 2048 5499663b8f9Sdanielk1977 {atomic2K} 4096 4096 5509663b8f9Sdanielk1977 {atomic2K atomic} 512 8192 5519663b8f9Sdanielk1977 {atomic64K} 512 1024 5529663b8f9Sdanielk1977} { 5539663b8f9Sdanielk1977 incr tn 554c2ded2afSdrh if {$pgsize>$::SQLITE_MAX_PAGE_SIZE} continue 5559663b8f9Sdanielk1977 db close 556fda06befSmistachkin forcedelete test.db test.db-journal 5579663b8f9Sdanielk1977 sqlite3_simulate_device -char $char -sectorsize $sectorsize 558bf260978Sdanielk1977 sqlite3 db test.db -vfs devsym 559c2ded2afSdrh db eval { 560c2ded2afSdrh PRAGMA auto_vacuum=OFF; 561c2ded2afSdrh } 562d6b9386cSdrh ifcapable !atomicwrite { 563d6b9386cSdrh if {[regexp {^atomic} $char]} continue 564d6b9386cSdrh } 5659663b8f9Sdanielk1977 do_test io-5.$tn { 5669663b8f9Sdanielk1977 execsql { 5679663b8f9Sdanielk1977 CREATE TABLE abc(a, b, c); 5689663b8f9Sdanielk1977 } 5699663b8f9Sdanielk1977 expr {[file size test.db]/2} 5709663b8f9Sdanielk1977 } $pgsize 5719663b8f9Sdanielk1977} 5729663b8f9Sdanielk1977 5738e4714b3Sdan#---------------------------------------------------------------------- 5748e4714b3Sdan# 5758e4714b3Sdando_test io-6.1 { 5768e4714b3Sdan db close 5778e4714b3Sdan sqlite3_simulate_device -char atomic 5788e4714b3Sdan forcedelete test.db 5798e4714b3Sdan sqlite3 db test.db -vfs devsym 5808e4714b3Sdan execsql { 5818e4714b3Sdan PRAGMA mmap_size = 0; 5828e4714b3Sdan PRAGMA page_size = 1024; 5835b04dc51Sdan PRAGMA cache_size = 2000; 5848e4714b3Sdan CREATE TABLE t1(x); 5858e4714b3Sdan CREATE TABLE t2(x); 5868e4714b3Sdan CREATE TABLE t3(x); 5878e4714b3Sdan CREATE INDEX i3 ON t3(x); 5888e4714b3Sdan INSERT INTO t3 VALUES(randomblob(100)); 5898e4714b3Sdan INSERT INTO t3 SELECT randomblob(100) FROM t3; 5908e4714b3Sdan INSERT INTO t3 SELECT randomblob(100) FROM t3; 5918e4714b3Sdan INSERT INTO t3 SELECT randomblob(100) FROM t3; 5928e4714b3Sdan INSERT INTO t3 SELECT randomblob(100) FROM t3; 5938e4714b3Sdan INSERT INTO t3 SELECT randomblob(100) FROM t3; 5948e4714b3Sdan INSERT INTO t3 SELECT randomblob(100) FROM t3; 5958e4714b3Sdan INSERT INTO t3 SELECT randomblob(100) FROM t3; 5968e4714b3Sdan INSERT INTO t3 SELECT randomblob(100) FROM t3; 5978e4714b3Sdan INSERT INTO t3 SELECT randomblob(100) FROM t3; 5988e4714b3Sdan INSERT INTO t3 SELECT randomblob(100) FROM t3; 5998e4714b3Sdan INSERT INTO t3 SELECT randomblob(100) FROM t3; 6008e4714b3Sdan } 6018e4714b3Sdan 6028e4714b3Sdan db_save_and_close 6038e4714b3Sdan} {} 6048e4714b3Sdan 6058e4714b3Sdanforeach {tn sql} { 6068e4714b3Sdan 1 { BEGIN; 6078e4714b3Sdan INSERT INTO t1 VALUES('123'); 6088e4714b3Sdan INSERT INTO t2 VALUES('456'); 6098e4714b3Sdan COMMIT; 6108e4714b3Sdan } 6118e4714b3Sdan 2 { BEGIN; 6128e4714b3Sdan INSERT INTO t1 VALUES('123'); 6138e4714b3Sdan COMMIT; 6148e4714b3Sdan } 6158e4714b3Sdan} { 6164c5aeeccSdan 6174c5aeeccSdan # These tests don't work with memsubsys1, as it causes the effective page 6184c5aeeccSdan # cache size to become too small to hold the entire db in memory. 6194c5aeeccSdan if {[permutation] == "memsubsys1"} continue 6204c5aeeccSdan 6218e4714b3Sdan db_restore 6228e4714b3Sdan sqlite3 db test.db -vfs devsym 6238e4714b3Sdan execsql { 6245b04dc51Sdan PRAGMA cache_size = 2000; 6258e4714b3Sdan PRAGMA mmap_size = 0; 6268e4714b3Sdan SELECT x FROM t3 ORDER BY rowid; 6278e4714b3Sdan SELECT x FROM t3 ORDER BY x; 6288e4714b3Sdan } 6298e4714b3Sdan do_execsql_test 6.2.$tn.1 { PRAGMA integrity_check } {ok} 6308e4714b3Sdan do_execsql_test 6.2.$tn.2 $sql 6318e4714b3Sdan 6328e4714b3Sdan # Corrupt the database file on disk. This should not matter for the 6338e4714b3Sdan # purposes of the following "PRAGMA integrity_check", as the entire 6348e4714b3Sdan # database should be cached in the pager-cache. If corruption is 6358e4714b3Sdan # reported, it indicates that executing $sql caused the pager cache 6368e4714b3Sdan # to be flushed. Which is a bug. 6378e4714b3Sdan hexio_write test.db [expr 1024 * 5] [string repeat 00 2048] 6388e4714b3Sdan do_execsql_test 6.2.$tn.3 { PRAGMA integrity_check } {ok} 6394eb9b721Smistachkin db close 6408e4714b3Sdan} 6418e4714b3Sdan 6422ca0f863Sdanielk1977sqlite3_simulate_device -char {} -sectorsize 0 643*37c906e6Sdanunregister_devsim 644*37c906e6Sdan 64546abae81Sdanielk1977finish_test 646