19af10620Sdan# 2014 December 04 29af10620Sdan# 39af10620Sdan# The author disclaims copyright to this source code. In place of 49af10620Sdan# a legal notice, here is a blessing: 59af10620Sdan# 69af10620Sdan# May you do good and not evil. 79af10620Sdan# May you find forgiveness for yourself and forgive others. 89af10620Sdan# May you share freely, never taking more than you give. 99af10620Sdan# 109af10620Sdan#*********************************************************************** 119af10620Sdan# 129af10620Sdan 139af10620Sdanset testdir [file dirname $argv0] 149af10620Sdansource $testdir/tester.tcl 159af10620Sdansource $testdir/wal_common.tcl 169af10620Sdanset testprefix e_walauto 179af10620Sdan 185f1731f6Sdan# Do not run this test on OpenBSD, as it depends on read() and mmap both 195f1731f6Sdan# accessing the same coherent view of the "test.db-shm" file. This doesn't 205f1731f6Sdan# work on OpenBSD. 215f1731f6Sdan# 225f1731f6Sdanif {$tcl_platform(os) == "OpenBSD"} { 235f1731f6Sdan finish_test 245f1731f6Sdan return 255f1731f6Sdan} 269af10620Sdan 27*7da56b4fSdrh# This module uses hard-coded offsets which do not work if the reserved_bytes 28*7da56b4fSdrh# value is nonzero. 29*7da56b4fSdrhif {[nonzero_reserved_bytes]} {finish_test; return;} 30*7da56b4fSdrh 31*7da56b4fSdrh 329af10620Sdanproc read_nbackfill {} { 339af10620Sdan seek $::shmfd 96 34e0e43029Sdrh binary scan [read $::shmfd 4] n nBackfill 359af10620Sdan set nBackfill 369af10620Sdan} 379af10620Sdanproc read_mxframe {} { 389af10620Sdan seek $::shmfd 16 39e0e43029Sdrh binary scan [read $::shmfd 4] n mxFrame 409af10620Sdan set mxFrame 419af10620Sdan} 429af10620Sdan 439af10620Sdan# Assuming that the main db for database handle 449af10620Sdan# 459af10620Sdanproc do_autocommit_threshold_test {tn value} { 469af10620Sdan 479af10620Sdan set nBackfillSaved [read_nbackfill] 489af10620Sdan while {1} { 499af10620Sdan db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } 509af10620Sdan if {[read_mxframe] >= $value} break 519af10620Sdan } 529af10620Sdan 539af10620Sdan set nBackfillNew [read_nbackfill] 549af10620Sdan uplevel [list do_test $tn "expr $nBackfillNew > $nBackfillSaved" 1] 559af10620Sdan} 569af10620Sdan 579af10620Sdan# EVIDENCE-OF: R-30135-06439 The wal_autocheckpoint pragma can be used 589af10620Sdan# to invoke this interface from SQL. 599af10620Sdan# 609af10620Sdan# All tests in this file are run twice - once using the 619af10620Sdan# sqlite3_wal_autocheckpoint() API, and once using "PRAGMA 629af10620Sdan# wal_autocheckpoint". 639af10620Sdan# 649af10620Sdanforeach {tn code} { 659af10620Sdan 1 { 669af10620Sdan proc autocheckpoint {db value} { 679af10620Sdan uplevel [list $db eval "PRAGMA wal_autocheckpoint = $value"] 689af10620Sdan } 699af10620Sdan } 709af10620Sdan 719af10620Sdan 2 { 729af10620Sdan proc autocheckpoint {db value} { 739af10620Sdan uplevel [list sqlite3_wal_autocheckpoint $db $value] 749af10620Sdan return $value 759af10620Sdan } 769af10620Sdan } 779af10620Sdan} { 789af10620Sdan 799af10620Sdan eval $code 809af10620Sdan 819af10620Sdan reset_db 8262031584Sdan execsql { PRAGMA auto_vacuum = 0 } 839af10620Sdan do_execsql_test 1.$tn.0 { PRAGMA journal_mode = WAL } {wal} 849af10620Sdan do_execsql_test 1.$tn.1 { CREATE TABLE t1(a, b) } 85e8d1777aSdrh set shmfd [open "test.db-shm" rb] 869af10620Sdan 879af10620Sdan # EVIDENCE-OF: R-41531-51083 Every new database connection defaults to 889af10620Sdan # having the auto-checkpoint enabled with a threshold of 1000 or 899af10620Sdan # SQLITE_DEFAULT_WAL_AUTOCHECKPOINT pages. 909af10620Sdan # 919af10620Sdan do_autocommit_threshold_test 1.$tn.2 1000 929af10620Sdan db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } 939af10620Sdan do_autocommit_threshold_test 1.$tn.3 1000 949af10620Sdan 959af10620Sdan # EVIDENCE-OF: R-38128-34102 The sqlite3_wal_autocheckpoint(D,N) is a 969af10620Sdan # wrapper around sqlite3_wal_hook() that causes any database on database 979af10620Sdan # connection D to automatically checkpoint after committing a 989af10620Sdan # transaction if there are N or more frames in the write-ahead log file. 999af10620Sdan # 1009af10620Sdan do_test 1.$tn.4 { 1019af10620Sdan db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } 1029af10620Sdan autocheckpoint db 100 1039af10620Sdan } {100} 1049af10620Sdan do_autocommit_threshold_test 1.$tn.5 100 1059af10620Sdan 1069af10620Sdan do_test 1.$tn.6 { 1079af10620Sdan db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } 1089af10620Sdan autocheckpoint db 500 1099af10620Sdan } {500} 1109af10620Sdan do_autocommit_threshold_test 1.$tn.7 500 1119af10620Sdan 1129af10620Sdan # EVIDENCE-OF: R-26993-43540 Passing zero or a negative value as the 1139af10620Sdan # nFrame parameter disables automatic checkpoints entirely. 1149af10620Sdan # 1159af10620Sdan do_test 1.$tn.7 { 1169af10620Sdan autocheckpoint db 0 ;# Set to zero 1179af10620Sdan for {set i 0} {$i < 10000} {incr i} { 1189af10620Sdan db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } 1199af10620Sdan } 1209af10620Sdan expr {[file size test.db-wal] > (5 * 1024 * 1024)} 1219af10620Sdan } 1 1229af10620Sdan do_test 1.$tn.8 { 1239af10620Sdan sqlite3_wal_checkpoint_v2 db truncate 1249af10620Sdan file size test.db-wal 1259af10620Sdan } 0 1269af10620Sdan do_test 1.$tn.9 { 1279af10620Sdan autocheckpoint db -4 ;# Set to a negative value 1289af10620Sdan for {set i 0} {$i < 10000} {incr i} { 1299af10620Sdan db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } 1309af10620Sdan } 1319af10620Sdan expr {[file size test.db-wal] > (5 * 1024 * 1024)} 1329af10620Sdan } 1 1339af10620Sdan 1349af10620Sdan # EVIDENCE-OF: R-10203-42688 The callback registered by this function 1359af10620Sdan # replaces any existing callback registered using sqlite3_wal_hook(). 1369af10620Sdan # 1379af10620Sdan set ::wal_hook_callback 0 1389af10620Sdan proc wal_hook_callback {args} { incr ::wal_hook_callback ; return 0 } 1399af10620Sdan do_test 1.$tn.10.1 { 1409af10620Sdan db wal_hook wal_hook_callback 1419af10620Sdan db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } 1429af10620Sdan db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } 1439af10620Sdan set ::wal_hook_callback 1449af10620Sdan } 2 1459af10620Sdan do_test 1.$tn.10.2 { 1469af10620Sdan autocheckpoint db 100 1479af10620Sdan db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } 1489af10620Sdan db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } 1499af10620Sdan set ::wal_hook_callback 1509af10620Sdan } 2 1519af10620Sdan 1529af10620Sdan # EVIDENCE-OF: R-17497-43474 Likewise, registering a callback using 1539af10620Sdan # sqlite3_wal_hook() disables the automatic checkpoint mechanism 1549af10620Sdan # configured by this function. 1559af10620Sdan do_test 1.$tn.11.1 { 1569af10620Sdan sqlite3_wal_checkpoint_v2 db truncate 1579af10620Sdan file size test.db-wal 1589af10620Sdan } 0 1599af10620Sdan do_test 1.$tn.11.2 { 1609af10620Sdan autocheckpoint db 100 1619af10620Sdan for {set i 0} {$i < 1000} {incr i} { 1629af10620Sdan db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } 1639af10620Sdan } 1649af10620Sdan expr {[file size test.db-wal] < (1 * 1024 * 1024)} 1659af10620Sdan } 1 1669af10620Sdan do_test 1.$tn.11.3 { 1679af10620Sdan db wal_hook wal_hook_callback 1689af10620Sdan for {set i 0} {$i < 1000} {incr i} { 1699af10620Sdan db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } 1709af10620Sdan } 1719af10620Sdan expr {[file size test.db-wal] < (1 * 1024 * 1024)} 1729af10620Sdan } 0 1739af10620Sdan 1749af10620Sdan # EVIDENCE-OF: R-33080-59193 Checkpoints initiated by this mechanism 1759af10620Sdan # are PASSIVE. 1769af10620Sdan # 1779af10620Sdan set ::busy_callback_count 0 1789af10620Sdan proc busy_callback {args} { 1799af10620Sdan incr ::busy_callback_count 1809af10620Sdan return 0 1819af10620Sdan } 1829af10620Sdan do_test 1.$tn.12.1 { 1839af10620Sdan sqlite3_wal_checkpoint_v2 db truncate 1849af10620Sdan autocheckpoint db 100 1859af10620Sdan db busy busy_callback 1869af10620Sdan db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } 1879af10620Sdan db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } 1889af10620Sdan } {} 1899af10620Sdan do_test 1.$tn.12.2 { 1909af10620Sdan sqlite3 db2 test.db 1919af10620Sdan db2 eval { BEGIN; SELECT * FROM t1 LIMIT 10; } 1929af10620Sdan read_nbackfill 1939af10620Sdan } {0} 1949af10620Sdan do_test 1.$tn.12.3 { 1959af10620Sdan for {set i 0} {$i < 1000} {incr i} { 1969af10620Sdan db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } 1979af10620Sdan } 1989af10620Sdan read_nbackfill 1999af10620Sdan } {2} 2009af10620Sdan do_test 1.$tn.12.4 { 2019af10620Sdan set ::busy_callback_count 2029af10620Sdan } {0} 2039af10620Sdan db2 close 2049af10620Sdan 2059af10620Sdan do_test 1.$tn.12.5 { 2069af10620Sdan db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } 2079af10620Sdan read_nbackfill 2089af10620Sdan } {1559} 2099af10620Sdan 2109af10620Sdan db close 2119af10620Sdan close $shmfd 2129af10620Sdan} 2139af10620Sdan 2149af10620Sdanfinish_test 215