xref: /sqlite-3.40.0/test/walvfs.test (revision cf2ad7ae)
18d69a581Sdan# 2018 December 23
28d69a581Sdan#
38d69a581Sdan# The author disclaims copyright to this source code.  In place of
48d69a581Sdan# a legal notice, here is a blessing:
58d69a581Sdan#
68d69a581Sdan#    May you do good and not evil.
78d69a581Sdan#    May you find forgiveness for yourself and forgive others.
88d69a581Sdan#    May you share freely, never taking more than you give.
98d69a581Sdan#
108d69a581Sdan#***********************************************************************
118d69a581Sdan# This file implements regression tests for SQLite library.  The
128d69a581Sdan# focus of this file is testing the operation of the library in
138d69a581Sdan# "PRAGMA journal_mode=WAL" mode.
148d69a581Sdan#
15*cf2ad7aeSdan# TESTRUNNER: slow
168d69a581Sdan
178d69a581Sdanset testdir [file dirname $argv0]
188d69a581Sdansource $testdir/tester.tcl
198d69a581Sdansource $testdir/lock_common.tcl
208d69a581Sdansource $testdir/malloc_common.tcl
218d69a581Sdansource $testdir/wal_common.tcl
228d69a581Sdanset testprefix walvfs
238d69a581Sdan
248d69a581Sdanifcapable !wal {finish_test ; return }
258d69a581Sdan
268d69a581Sdandb close
278d69a581Sdantestvfs tvfs
288d69a581Sdantvfs script xSync
298d69a581Sdantvfs filter xSync
308d69a581Sdanset ::sync_count 0
318d69a581Sdanproc xSync {method file args} {
328d69a581Sdan  if {[file tail $file]=="test.db-wal"} {
338d69a581Sdan    incr ::sync_count
348d69a581Sdan  }
358d69a581Sdan}
368d69a581Sdan
3789dec01eSdan
388d69a581Sdan#-------------------------------------------------------------------------
398d69a581Sdan# Test that if IOCAP_SEQUENTIAL is set, the wal-header is not synced to
408d69a581Sdan# disk immediately after it is written.
418d69a581Sdan#
428d69a581Sdansqlite3 db test.db -vfs tvfs
438d69a581Sdando_execsql_test 1.0 {
448d69a581Sdan  PRAGMA auto_vacuum = 0;
458d69a581Sdan  PRAGMA journal_mode = wal;
468d69a581Sdan  PRAGMA synchronous = normal;
478d69a581Sdan  CREATE TABLE t1(a, b, c);
488d69a581Sdan  INSERT INTO t1 VALUES(1, 2, 3);
498d69a581Sdan  INSERT INTO t1 VALUES(4, 5, 6);
508d69a581Sdan  INSERT INTO t1 VALUES(7, 8, 9);
518d69a581Sdan  PRAGMA wal_checkpoint;
528d69a581Sdan} {wal 0 5 5}
538d69a581Sdan
548d69a581Sdanset ::sync_count 0
558d69a581Sdando_test 1.1 {
568d69a581Sdan  execsql { INSERT INTO t1 VALUES(10, 11, 12) }
578d69a581Sdan  set ::sync_count
588d69a581Sdan} 1
598d69a581Sdan
608d69a581Sdandb close
618d69a581Sdantvfs devchar sequential
628d69a581Sdansqlite3 db test.db -vfs tvfs
638d69a581Sdando_execsql_test 1.2 {
648d69a581Sdan  PRAGMA synchronous = normal;
658d69a581Sdan  INSERT INTO t1 VALUES(13, 14, 15);
668d69a581Sdan  INSERT INTO t1 VALUES(16, 17, 18);
678d69a581Sdan  PRAGMA wal_checkpoint;
688d69a581Sdan} {0 4 4}
698d69a581Sdan
708d69a581Sdanset ::sync_count 0
718d69a581Sdando_test 1.3 {
728d69a581Sdan  execsql { INSERT INTO t1 VALUES(10, 11, 12) }
738d69a581Sdan  set ::sync_count
748d69a581Sdan} 0
758d69a581Sdan
768d69a581Sdan#-------------------------------------------------------------------------
778d69a581Sdan# Test that "PRAGMA journal_size_limit" works in wal mode.
788d69a581Sdan#
798d69a581Sdanreset_db
808d69a581Sdando_execsql_test 2.0 {
818d69a581Sdan  PRAGMA journal_size_limit = 10000;
828d69a581Sdan  CREATE TABLE t1(x);
838d69a581Sdan  PRAGMA journal_mode = wal;
848d69a581Sdan  WITH s(i) AS (
858d69a581Sdan    SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 20
868d69a581Sdan  )
878d69a581Sdan  INSERT INTO t1 SELECT randomblob(750) FROM s;
888d69a581Sdan} {10000 wal}
898d69a581Sdando_test 2.1 {
908d69a581Sdan  expr [file size test.db-wal]>12000
918d69a581Sdan} {1}
928d69a581Sdando_test 2.2 {
938d69a581Sdan  execsql {
948d69a581Sdan    PRAGMA wal_checkpoint;
958d69a581Sdan    INSERT INTO t1 VALUES(randomblob(750));
968d69a581Sdan  }
978d69a581Sdan  file size test.db-wal
988d69a581Sdan} {10000}
998d69a581Sdando_test 2.3 {
1008d69a581Sdan  execsql {
1018d69a581Sdan    PRAGMA journal_size_limit = 8000;
1028d69a581Sdan    PRAGMA wal_checkpoint;
1038d69a581Sdan    INSERT INTO t1 VALUES(randomblob(750));
1048d69a581Sdan  }
1058d69a581Sdan  file size test.db-wal
1068d69a581Sdan} {8000}
1078d69a581Sdan
1088d69a581Sdan#-------------------------------------------------------------------------
1098d69a581Sdan# Test that a checkpoint may be interrupted using sqlite3_interrupt().
11089dec01eSdan# And that the error code is SQLITE_NOMEM, not SQLITE_INTERRUPT, if
11189dec01eSdan# an OOM error occurs just before the sqlite3_interrupt() call.
1128d69a581Sdan#
1138d69a581Sdanreset_db
1148d69a581Sdandb close
1158d69a581Sdansqlite3 db test.db -vfs tvfs
1168d69a581Sdantvfs filter {}
1178d69a581Sdan
1188d69a581Sdando_execsql_test 3.0 {
1198d69a581Sdan  CREATE TABLE t1(x);
1208d69a581Sdan  PRAGMA journal_mode = wal;
1218d69a581Sdan  WITH s(i) AS (
1228d69a581Sdan    SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 20
1238d69a581Sdan  )
1248d69a581Sdan  INSERT INTO t1 SELECT randomblob(750) FROM s;
1258d69a581Sdan} {wal}
1268d69a581Sdan
1278d69a581Sdantvfs filter xWrite
1288d69a581Sdantvfs script xWrite
1298d69a581Sdanset ::cnt 2
1308d69a581Sdanproc xWrite {method file args} {
1318d69a581Sdan  if {[file tail $file]=="test.db"} {
1328d69a581Sdan    incr ::cnt -1
1338d69a581Sdan    if {$::cnt==0} {
1348d69a581Sdan      sqlite3_interrupt db
1358d69a581Sdan    }
1368d69a581Sdan  }
1378d69a581Sdan  return SQLITE_OK
1388d69a581Sdan}
1398d69a581Sdan
1408d69a581Sdando_catchsql_test 3.1 {
1418d69a581Sdan  PRAGMA wal_checkpoint
1428d69a581Sdan} {1 interrupted}
1438d69a581Sdan
14489dec01eSdanset ::cnt 2
14589dec01eSdanproc xWrite {method file args} {
14689dec01eSdan  if {[file tail $file]=="test.db"} {
14789dec01eSdan    incr ::cnt -1
14889dec01eSdan    if {$::cnt==0} {
149ed0af52cSdan      sqlite3_memdebug_fail 1 -repeat 0
150ee822185Sdan      # For this test to pass, the following statement must call malloc() at
151ee822185Sdan      # least once. Even if the lookaside is enabled.
152ee822185Sdan      set ::xwrite_stmt_res [catchsql { SELECT hex(randomblob(4000)) }]
15389dec01eSdan      sqlite3_interrupt db
15489dec01eSdan    }
15589dec01eSdan  }
15689dec01eSdan  return SQLITE_OK
15789dec01eSdan}
15889dec01eSdan
159ee822185Sdanset ::xwrite_stmt_res ""
16089dec01eSdando_catchsql_test 3.2 {
16189dec01eSdan  PRAGMA wal_checkpoint
16289dec01eSdan} {1 {out of memory}}
163ee822185Sdando_test 3.2.2 {
164ee822185Sdan  set ::xwrite_stmt_res
165ee822185Sdan} {1 {out of memory}}
166ee822185Sdanunset ::xwrite_stmt_res
16789dec01eSdan
1688d69a581Sdan#-------------------------------------------------------------------------
1698d69a581Sdan#
1708d69a581Sdanreset_db
1718d69a581Sdandb close
1728d69a581Sdando_test 4.0 {
1738d69a581Sdan  sqlite3 db test.db -vfs tvfs
1748d69a581Sdan  execsql {
1758d69a581Sdan    CREATE TABLE t1(x);
1768d69a581Sdan    PRAGMA journal_mode = wal;
1778d69a581Sdan    WITH s(i) AS (
1788d69a581Sdan        SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 20
1798d69a581Sdan    )
1808d69a581Sdan    INSERT INTO t1 SELECT randomblob(750) FROM s;
1818d69a581Sdan  } db
1828d69a581Sdan} {wal}
1838d69a581Sdandb close
1848d69a581Sdan
1858d69a581Sdantvfs filter xShmMap
1868d69a581Sdantvfs script xShmMap
1878d69a581Sdanproc xShmMap {method file args} {
1888d69a581Sdan  return SQLITE_READONLY
1898d69a581Sdan}
1908d69a581Sdansqlite3 db test.db -vfs tvfs
1918d69a581Sdando_catchsql_test 4.1 {
1928d69a581Sdan  SELECT count(*) FROM t1
1938d69a581Sdan} {1 {attempt to write a readonly database}}
1948d69a581Sdan
1958d69a581Sdanset ::cnt 5
1968d69a581Sdantvfs filter {xShmMap xShmLock}
1978d69a581Sdanproc xShmMap {method file name args} {
1988d69a581Sdan  switch -- $method {
1998d69a581Sdan    xShmMap {  return SQLITE_READONLY }
2008d69a581Sdan    xShmLock {
2018d69a581Sdan      if {$args == "{0 1 lock shared}"} {
2028d69a581Sdan        incr ::cnt -1
2038d69a581Sdan        if {$::cnt>0} { return SQLITE_BUSY }
2048d69a581Sdan      }
2058d69a581Sdan    }
2068d69a581Sdan  }
2078d69a581Sdan  return SQLITE_OK
2088d69a581Sdan}
2098d69a581Sdando_catchsql_test 4.2 {
2108d69a581Sdan  SELECT count(*) FROM t1
2118d69a581Sdan} {1 {attempt to write a readonly database}}
2128d69a581Sdan
21376e4990bSdan#-------------------------------------------------------------------------
21476e4990bSdan#
21576e4990bSdanreset_db
21676e4990bSdandb close
21776e4990bSdansqlite3 db test.db -vfs tvfs
21876e4990bSdantvfs filter {}
21976e4990bSdando_execsql_test 5.0 {
22076e4990bSdan  PRAGMA auto_vacuum = 0;
22176e4990bSdan  PRAGMA page_size = 1024;
22276e4990bSdan  CREATE TABLE t1(x);
22376e4990bSdan  PRAGMA journal_mode = wal;
22476e4990bSdan  WITH s(i) AS (
22576e4990bSdan      SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 20
22676e4990bSdan  )
22776e4990bSdan  INSERT INTO t1 SELECT randomblob(750) FROM s;
22876e4990bSdan} {wal}
22976e4990bSdan
23076e4990bSdando_execsql_test 5.1 {
23176e4990bSdan  SELECT count(*) FROM t1
23276e4990bSdan} {20}
23376e4990bSdan
23476e4990bSdando_test 5.2 {
23576e4990bSdan  vfs_set_readmark db main 1 100
23676e4990bSdan  vfs_set_readmark db main 2 100
23776e4990bSdan  vfs_set_readmark db main 3 100
23876e4990bSdan  vfs_set_readmark db main 4 100
23976e4990bSdan} {100}
24076e4990bSdan
24176e4990bSdando_execsql_test 5.3 {
24276e4990bSdan  SELECT count(*) FROM t1
24376e4990bSdan} {20}
24476e4990bSdan
24576e4990bSdando_test 5.3 {
24676e4990bSdan  list [vfs_set_readmark db main 1] \
24776e4990bSdan       [vfs_set_readmark db main 2] \
24876e4990bSdan       [vfs_set_readmark db main 3] \
24976e4990bSdan       [vfs_set_readmark db main 4]
25076e4990bSdan} {24 100 100 100}
25176e4990bSdan
25276e4990bSdantvfs script xShmLock
25376e4990bSdantvfs filter xShmLock
25476e4990bSdanset ::cnt 20
25576e4990bSdanproc xShmLock {args} {
25676e4990bSdan  incr ::cnt -1
25776e4990bSdan  if {$::cnt>0} { return SQLITE_BUSY }
25876e4990bSdan  return SQLITE_OK
25976e4990bSdan}
26076e4990bSdan
26176e4990bSdando_test 5.4 {
26276e4990bSdan  vfs_set_readmark db main 1 100
26376e4990bSdan  execsql { SELECT count(*) FROM t1 }
26476e4990bSdan} {20}
26576e4990bSdan
26689dec01eSdanvfs_set_readmark db main 1 100
26789dec01eSdanvfs_set_readmark db main 2 100
26889dec01eSdanvfs_set_readmark db main 3 100
26989dec01eSdanvfs_set_readmark db main 4 100
27089dec01eSdan
27189dec01eSdantvfs script xShmMapLock
27289dec01eSdantvfs filter {xShmLock xShmMap}
27389dec01eSdanproc xShmMapLock {method args} {
27489dec01eSdan  if {$method=="xShmMap"} {
27589dec01eSdan    return "SQLITE_READONLY"
27689dec01eSdan  }
27789dec01eSdan  return SQLITE_BUSY
27889dec01eSdan}
27989dec01eSdan
28089dec01eSdansqlite3 db2 test.db -vfs tvfs
28189dec01eSdanbreakpoint
28289dec01eSdando_test 5.5 {
28389dec01eSdan  list [catch { execsql { SELECT count(*) FROM t1 } db2 } msg] $msg
28489dec01eSdan} {1 {attempt to write a readonly database}}
28589dec01eSdan
28689dec01eSdantvfs filter {}
28789dec01eSdanvfs_set_readmark db main 1 1
28889dec01eSdan
28989dec01eSdando_test 5.6 {
29089dec01eSdan  list [catch { execsql { SELECT count(*) FROM t1 } db2 } msg] $msg
29189dec01eSdan} {0 20}
29289dec01eSdandb2 close
29389dec01eSdandb close
29489dec01eSdan
29576e4990bSdan#-------------------------------------------------------------------------
29676e4990bSdan# Cause an SQLITE_PROTOCOL while attempting to restart the wal file.
29792107a38Sdan#
29876e4990bSdanreset_db
29976e4990bSdantvfs filter {}
30076e4990bSdandb close
30176e4990bSdansqlite3 db test.db -vfs tvfs
30276e4990bSdando_execsql_test 6.0 {
30376e4990bSdan  PRAGMA auto_vacuum = 0;
30476e4990bSdan  PRAGMA page_size = 1024;
30576e4990bSdan  CREATE TABLE t1(x);
30676e4990bSdan  PRAGMA journal_mode = wal;
30776e4990bSdan  WITH s(i) AS (
30876e4990bSdan      SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 20
30976e4990bSdan  )
31076e4990bSdan  INSERT INTO t1 SELECT randomblob(750) FROM s;
31176e4990bSdan} {wal}
31276e4990bSdan
31376e4990bSdando_test 6.1 {
31476e4990bSdan  execsql { PRAGMA wal_checkpoint }
31576e4990bSdan  set {} {}
31676e4990bSdan} {}
31776e4990bSdan
31876e4990bSdantvfs filter xShmLock
31989dec01eSdantvfs script xShmLock
32076e4990bSdanset ::flag 0
32176e4990bSdanproc xShmLock {method file handle spec} {
32276e4990bSdan  if {$::flag && [lrange $spec 2 end]=="lock shared"} {
32376e4990bSdan    return SQLITE_BUSY
32476e4990bSdan  }
32576e4990bSdan  if {$spec=="3 1 unlock shared"} {
32676e4990bSdan    set ::flag 1
32776e4990bSdan  }
32876e4990bSdan  return SQLITE_OK
32976e4990bSdan}
33076e4990bSdan
33176e4990bSdanputs "# WARNING: This next test takes around 12 seconds"
33276e4990bSdando_catchsql_test 6.2 {
33376e4990bSdan  INSERT INTO t1 VALUES(1);
33476e4990bSdan} {1 {locking protocol}}
33576e4990bSdan
33692107a38Sdan#-------------------------------------------------------------------------
33792107a38Sdan# Check that a checkpoint fails if it cannot get the CHECKPOINTER lock
33892107a38Sdan#
33992107a38Sdanreset_db
34092107a38Sdantvfs filter {}
34192107a38Sdandb close
34292107a38Sdansqlite3 db test.db -vfs tvfs
34392107a38Sdando_execsql_test 7.0 {
34492107a38Sdan  PRAGMA auto_vacuum = 0;
34592107a38Sdan  PRAGMA page_size = 1024;
34692107a38Sdan  CREATE TABLE t1(x);
34792107a38Sdan  PRAGMA journal_mode = wal;
34892107a38Sdan  WITH s(i) AS (
34992107a38Sdan      SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 20
35092107a38Sdan  )
35192107a38Sdan  INSERT INTO t1 SELECT randomblob(750) FROM s;
35292107a38Sdan} {wal}
35392107a38Sdan
35492107a38Sdantvfs script xShmLock
35592107a38Sdantvfs filter xShmLock
35692107a38Sdanproc xShmLock {method file handle spec} {
35792107a38Sdan  if {$spec=="1 1 lock exclusive"} {
35892107a38Sdan    return SQLITE_BUSY
35992107a38Sdan  }
36092107a38Sdan  return SQLITE_OK
36192107a38Sdan}
36292107a38Sdan
36392107a38Sdando_execsql_test 7.1 {
36492107a38Sdan  PRAGMA wal_checkpoint
36592107a38Sdan} {1 -1 -1}
36692107a38Sdan
36789dec01eSdan#-------------------------------------------------------------------------
36889dec01eSdan# Check that the page cache is correctly flushed if a checkpointer using
36989dec01eSdan# a version 2 VFS makes a checkpoint with an out-of-date cache.
37089dec01eSdan#
37189dec01eSdanreset_db
37289dec01eSdantestvfs tvfs2 -iversion 2
3738d69a581Sdandb close
37489dec01eSdansqlite3 db test.db -vfs tvfs2
37589dec01eSdando_execsql_test 8.0 {
37689dec01eSdan  PRAGMA auto_vacuum = 0;
37789dec01eSdan  PRAGMA page_size = 1024;
37889dec01eSdan  CREATE TABLE t1(x);
37989dec01eSdan  PRAGMA journal_mode = wal;
38089dec01eSdan  WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 20 )
38189dec01eSdan  INSERT INTO t1 SELECT randomblob(75) FROM s;
38289dec01eSdan} {wal}
38389dec01eSdan
38489dec01eSdando_execsql_test 8.1 { SELECT count(*) FROM t1 } {20}
38589dec01eSdan
38689dec01eSdando_test 8.2 {
38789dec01eSdan  sqlite3 db2 test.db -vfs tvfs2
38889dec01eSdan  execsql {
38989dec01eSdan    INSERT INTO t1 VALUES(randomblob(75));
39089dec01eSdan  } db2
39189dec01eSdan  db2 close
39289dec01eSdan} {}
39389dec01eSdan
39489dec01eSdando_execsql_test 8.3 {
39589dec01eSdan  PRAGMA wal_checkpoint;
39689dec01eSdan  SELECT count(*) FROM t1
39789dec01eSdan} {0 5 5 21}
39883420823Sdandb close
39989dec01eSdantvfs2 delete
40089dec01eSdan
40189dec01eSdan#-------------------------------------------------------------------------
40289dec01eSdanreset_db
40389dec01eSdandb close
40489dec01eSdansqlite3 db test.db -vfs tvfs
40589dec01eSdando_execsql_test 9.0 {
40689dec01eSdan  PRAGMA auto_vacuum = 0;
40789dec01eSdan  PRAGMA page_size = 1024;
40889dec01eSdan  CREATE TABLE t1(x);
40989dec01eSdan  PRAGMA journal_mode = wal;
41089dec01eSdan  WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 20 )
41189dec01eSdan  INSERT INTO t1 SELECT randomblob(75) FROM s;
41289dec01eSdan} {wal}
41389dec01eSdan
41489dec01eSdansqlite3 db2 test.db -vfs tvfs
41589dec01eSdantvfs filter {xShmMap xShmLock}
41689dec01eSdantvfs script xShmMap
41789dec01eSdanproc xShmMap {method file handle args} {
41889dec01eSdan  switch -- $method {
41989dec01eSdan    xShmMap {
42089dec01eSdan      return "SQLITE_READONLY_CANTINIT"
42189dec01eSdan    }
42289dec01eSdan    xShmLock {
42389dec01eSdan      if {$args=="{3 1 lock shared}"} {
42489dec01eSdan        return "SQLITE_IOERR"
42589dec01eSdan      }
42689dec01eSdan    }
42789dec01eSdan  }
42889dec01eSdan}
42989dec01eSdan
43089dec01eSdando_test 9.1 {
43189dec01eSdan  catchsql { SELECT count(*) FROM t1 } db2
43289dec01eSdan} {1 {disk I/O error}}
43389dec01eSdan
43489dec01eSdandb close
43589dec01eSdandb2 close
4368d69a581Sdantvfs delete
4378d69a581Sdanfinish_test
438