xref: /sqlite-3.40.0/test/io.test (revision 37c906e6)
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