# 2014 December 04 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/wal_common.tcl set testprefix e_walauto # Do not run this test on OpenBSD, as it depends on read() and mmap both # accessing the same coherent view of the "test.db-shm" file. This doesn't # work on OpenBSD. # if {$tcl_platform(os) == "OpenBSD"} { finish_test return } # This module uses hard-coded offsets which do not work if the reserved_bytes # value is nonzero. if {[nonzero_reserved_bytes]} {finish_test; return;} proc read_nbackfill {} { seek $::shmfd 96 binary scan [read $::shmfd 4] n nBackfill set nBackfill } proc read_mxframe {} { seek $::shmfd 16 binary scan [read $::shmfd 4] n mxFrame set mxFrame } # Assuming that the main db for database handle # proc do_autocommit_threshold_test {tn value} { set nBackfillSaved [read_nbackfill] while {1} { db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } if {[read_mxframe] >= $value} break } set nBackfillNew [read_nbackfill] uplevel [list do_test $tn "expr $nBackfillNew > $nBackfillSaved" 1] } # EVIDENCE-OF: R-30135-06439 The wal_autocheckpoint pragma can be used # to invoke this interface from SQL. # # All tests in this file are run twice - once using the # sqlite3_wal_autocheckpoint() API, and once using "PRAGMA # wal_autocheckpoint". # foreach {tn code} { 1 { proc autocheckpoint {db value} { uplevel [list $db eval "PRAGMA wal_autocheckpoint = $value"] } } 2 { proc autocheckpoint {db value} { uplevel [list sqlite3_wal_autocheckpoint $db $value] return $value } } } { eval $code reset_db execsql { PRAGMA auto_vacuum = 0 } do_execsql_test 1.$tn.0 { PRAGMA journal_mode = WAL } {wal} do_execsql_test 1.$tn.1 { CREATE TABLE t1(a, b) } set shmfd [open "test.db-shm" rb] # EVIDENCE-OF: R-41531-51083 Every new database connection defaults to # having the auto-checkpoint enabled with a threshold of 1000 or # SQLITE_DEFAULT_WAL_AUTOCHECKPOINT pages. # do_autocommit_threshold_test 1.$tn.2 1000 db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } do_autocommit_threshold_test 1.$tn.3 1000 # EVIDENCE-OF: R-38128-34102 The sqlite3_wal_autocheckpoint(D,N) is a # wrapper around sqlite3_wal_hook() that causes any database on database # connection D to automatically checkpoint after committing a # transaction if there are N or more frames in the write-ahead log file. # do_test 1.$tn.4 { db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } autocheckpoint db 100 } {100} do_autocommit_threshold_test 1.$tn.5 100 do_test 1.$tn.6 { db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } autocheckpoint db 500 } {500} do_autocommit_threshold_test 1.$tn.7 500 # EVIDENCE-OF: R-26993-43540 Passing zero or a negative value as the # nFrame parameter disables automatic checkpoints entirely. # do_test 1.$tn.7 { autocheckpoint db 0 ;# Set to zero for {set i 0} {$i < 10000} {incr i} { db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } } expr {[file size test.db-wal] > (5 * 1024 * 1024)} } 1 do_test 1.$tn.8 { sqlite3_wal_checkpoint_v2 db truncate file size test.db-wal } 0 do_test 1.$tn.9 { autocheckpoint db -4 ;# Set to a negative value for {set i 0} {$i < 10000} {incr i} { db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } } expr {[file size test.db-wal] > (5 * 1024 * 1024)} } 1 # EVIDENCE-OF: R-10203-42688 The callback registered by this function # replaces any existing callback registered using sqlite3_wal_hook(). # set ::wal_hook_callback 0 proc wal_hook_callback {args} { incr ::wal_hook_callback ; return 0 } do_test 1.$tn.10.1 { db wal_hook wal_hook_callback db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } set ::wal_hook_callback } 2 do_test 1.$tn.10.2 { autocheckpoint db 100 db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } set ::wal_hook_callback } 2 # EVIDENCE-OF: R-17497-43474 Likewise, registering a callback using # sqlite3_wal_hook() disables the automatic checkpoint mechanism # configured by this function. do_test 1.$tn.11.1 { sqlite3_wal_checkpoint_v2 db truncate file size test.db-wal } 0 do_test 1.$tn.11.2 { autocheckpoint db 100 for {set i 0} {$i < 1000} {incr i} { db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } } expr {[file size test.db-wal] < (1 * 1024 * 1024)} } 1 do_test 1.$tn.11.3 { db wal_hook wal_hook_callback for {set i 0} {$i < 1000} {incr i} { db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } } expr {[file size test.db-wal] < (1 * 1024 * 1024)} } 0 # EVIDENCE-OF: R-33080-59193 Checkpoints initiated by this mechanism # are PASSIVE. # set ::busy_callback_count 0 proc busy_callback {args} { incr ::busy_callback_count return 0 } do_test 1.$tn.12.1 { sqlite3_wal_checkpoint_v2 db truncate autocheckpoint db 100 db busy busy_callback db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } } {} do_test 1.$tn.12.2 { sqlite3 db2 test.db db2 eval { BEGIN; SELECT * FROM t1 LIMIT 10; } read_nbackfill } {0} do_test 1.$tn.12.3 { for {set i 0} {$i < 1000} {incr i} { db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } } read_nbackfill } {2} do_test 1.$tn.12.4 { set ::busy_callback_count } {0} db2 close do_test 1.$tn.12.5 { db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) } read_nbackfill } {1559} db close close $shmfd } finish_test