000001 # 2014 December 04
000002 #
000003 # The author disclaims copyright to this source code. In place of
000004 # a legal notice, here is a blessing:
000005 #
000006 # May you do good and not evil.
000007 # May you find forgiveness for yourself and forgive others.
000008 # May you share freely, never taking more than you give.
000009 #
000010 #***********************************************************************
000011 #
000012
000013 set testdir [file dirname $argv0]
000014 source $testdir/tester.tcl
000015 source $testdir/wal_common.tcl
000016 set testprefix e_walauto
000017
000018 # Do not run this test on OpenBSD, as it depends on read() and mmap both
000019 # accessing the same coherent view of the "test.db-shm" file. This doesn't
000020 # work on OpenBSD.
000021 #
000022 if {$tcl_platform(os) == "OpenBSD"} {
000023 finish_test
000024 return
000025 }
000026
000027 # This module uses hard-coded offsets which do not work if the reserved_bytes
000028 # value is nonzero.
000029 if {[nonzero_reserved_bytes]} {finish_test; return;}
000030
000031
000032 proc read_nbackfill {} {
000033 seek $::shmfd 96
000034 binary scan [read $::shmfd 4] n nBackfill
000035 set nBackfill
000036 }
000037 proc read_mxframe {} {
000038 seek $::shmfd 16
000039 binary scan [read $::shmfd 4] n mxFrame
000040 set mxFrame
000041 }
000042
000043 # Assuming that the main db for database handle
000044 #
000045 proc do_autocommit_threshold_test {tn value} {
000046
000047 set nBackfillSaved [read_nbackfill]
000048 while {1} {
000049 db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
000050 if {[read_mxframe] >= $value} break
000051 }
000052
000053 set nBackfillNew [read_nbackfill]
000054 uplevel [list do_test $tn "expr $nBackfillNew > $nBackfillSaved" 1]
000055 }
000056
000057 # EVIDENCE-OF: R-30135-06439 The wal_autocheckpoint pragma can be used
000058 # to invoke this interface from SQL.
000059 #
000060 # All tests in this file are run twice - once using the
000061 # sqlite3_wal_autocheckpoint() API, and once using "PRAGMA
000062 # wal_autocheckpoint".
000063 #
000064 foreach {tn code} {
000065 1 {
000066 proc autocheckpoint {db value} {
000067 uplevel [list $db eval "PRAGMA wal_autocheckpoint = $value"]
000068 }
000069 }
000070
000071 2 {
000072 proc autocheckpoint {db value} {
000073 uplevel [list sqlite3_wal_autocheckpoint $db $value]
000074 return $value
000075 }
000076 }
000077 } {
000078
000079 eval $code
000080
000081 reset_db
000082 execsql { PRAGMA auto_vacuum = 0 }
000083 do_execsql_test 1.$tn.0 { PRAGMA journal_mode = WAL } {wal}
000084 do_execsql_test 1.$tn.1 { CREATE TABLE t1(a, b) }
000085 set shmfd [open "test.db-shm" rb]
000086
000087 # EVIDENCE-OF: R-41531-51083 Every new database connection defaults to
000088 # having the auto-checkpoint enabled with a threshold of 1000 or
000089 # SQLITE_DEFAULT_WAL_AUTOCHECKPOINT pages.
000090 #
000091 do_autocommit_threshold_test 1.$tn.2 1000
000092 db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
000093 do_autocommit_threshold_test 1.$tn.3 1000
000094
000095 # EVIDENCE-OF: R-38128-34102 The sqlite3_wal_autocheckpoint(D,N) is a
000096 # wrapper around sqlite3_wal_hook() that causes any database on database
000097 # connection D to automatically checkpoint after committing a
000098 # transaction if there are N or more frames in the write-ahead log file.
000099 #
000100 do_test 1.$tn.4 {
000101 db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
000102 autocheckpoint db 100
000103 } {100}
000104 do_autocommit_threshold_test 1.$tn.5 100
000105
000106 do_test 1.$tn.6 {
000107 db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
000108 autocheckpoint db 500
000109 } {500}
000110 do_autocommit_threshold_test 1.$tn.7 500
000111
000112 # EVIDENCE-OF: R-26993-43540 Passing zero or a negative value as the
000113 # nFrame parameter disables automatic checkpoints entirely.
000114 #
000115 do_test 1.$tn.7 {
000116 autocheckpoint db 0 ;# Set to zero
000117 for {set i 0} {$i < 10000} {incr i} {
000118 db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
000119 }
000120 expr {[file size test.db-wal] > (5 * 1024 * 1024)}
000121 } 1
000122 do_test 1.$tn.8 {
000123 sqlite3_wal_checkpoint_v2 db truncate
000124 file size test.db-wal
000125 } 0
000126 do_test 1.$tn.9 {
000127 autocheckpoint db -4 ;# Set to a negative value
000128 for {set i 0} {$i < 10000} {incr i} {
000129 db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
000130 }
000131 expr {[file size test.db-wal] > (5 * 1024 * 1024)}
000132 } 1
000133
000134 # EVIDENCE-OF: R-10203-42688 The callback registered by this function
000135 # replaces any existing callback registered using sqlite3_wal_hook().
000136 #
000137 set ::wal_hook_callback 0
000138 proc wal_hook_callback {args} { incr ::wal_hook_callback ; return 0 }
000139 do_test 1.$tn.10.1 {
000140 db wal_hook wal_hook_callback
000141 db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
000142 db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
000143 set ::wal_hook_callback
000144 } 2
000145 do_test 1.$tn.10.2 {
000146 autocheckpoint db 100
000147 db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
000148 db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
000149 set ::wal_hook_callback
000150 } 2
000151
000152 # EVIDENCE-OF: R-17497-43474 Likewise, registering a callback using
000153 # sqlite3_wal_hook() disables the automatic checkpoint mechanism
000154 # configured by this function.
000155 do_test 1.$tn.11.1 {
000156 sqlite3_wal_checkpoint_v2 db truncate
000157 file size test.db-wal
000158 } 0
000159 do_test 1.$tn.11.2 {
000160 autocheckpoint db 100
000161 for {set i 0} {$i < 1000} {incr i} {
000162 db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
000163 }
000164 expr {[file size test.db-wal] < (1 * 1024 * 1024)}
000165 } 1
000166 do_test 1.$tn.11.3 {
000167 db wal_hook wal_hook_callback
000168 for {set i 0} {$i < 1000} {incr i} {
000169 db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
000170 }
000171 expr {[file size test.db-wal] < (1 * 1024 * 1024)}
000172 } 0
000173
000174 # EVIDENCE-OF: R-33080-59193 Checkpoints initiated by this mechanism
000175 # are PASSIVE.
000176 #
000177 set ::busy_callback_count 0
000178 proc busy_callback {args} {
000179 incr ::busy_callback_count
000180 return 0
000181 }
000182 do_test 1.$tn.12.1 {
000183 sqlite3_wal_checkpoint_v2 db truncate
000184 autocheckpoint db 100
000185 db busy busy_callback
000186 db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
000187 db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
000188 } {}
000189 do_test 1.$tn.12.2 {
000190 sqlite3 db2 test.db
000191 db2 eval { BEGIN; SELECT * FROM t1 LIMIT 10; }
000192 read_nbackfill
000193 } {0}
000194 do_test 1.$tn.12.3 {
000195 for {set i 0} {$i < 1000} {incr i} {
000196 db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
000197 }
000198 read_nbackfill
000199 } {2}
000200 do_test 1.$tn.12.4 {
000201 set ::busy_callback_count
000202 } {0}
000203 db2 close
000204
000205 do_test 1.$tn.12.5 {
000206 db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
000207 read_nbackfill
000208 } {1559}
000209
000210 db close
000211 close $shmfd
000212 }
000213
000214 finish_test