xref: /sqlite-3.40.0/test/e_walauto.test (revision 7da56b4f)
1# 2014 December 04
2#
3# The author disclaims copyright to this source code.  In place of
4# a legal notice, here is a blessing:
5#
6#    May you do good and not evil.
7#    May you find forgiveness for yourself and forgive others.
8#    May you share freely, never taking more than you give.
9#
10#***********************************************************************
11#
12
13set testdir [file dirname $argv0]
14source $testdir/tester.tcl
15source $testdir/wal_common.tcl
16set testprefix e_walauto
17
18# Do not run this test on OpenBSD, as it depends on read() and mmap both
19# accessing the same coherent view of the "test.db-shm" file. This doesn't
20# work on OpenBSD.
21#
22if {$tcl_platform(os) == "OpenBSD"} {
23  finish_test
24  return
25}
26
27# This module uses hard-coded offsets which do not work if the reserved_bytes
28# value is nonzero.
29if {[nonzero_reserved_bytes]} {finish_test; return;}
30
31
32proc read_nbackfill {} {
33  seek $::shmfd 96
34  binary scan [read $::shmfd 4] n nBackfill
35  set nBackfill
36}
37proc read_mxframe {} {
38  seek $::shmfd 16
39  binary scan [read $::shmfd 4] n mxFrame
40  set mxFrame
41}
42
43# Assuming that the main db for database handle
44#
45proc do_autocommit_threshold_test {tn value} {
46
47  set nBackfillSaved [read_nbackfill]
48  while {1} {
49    db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
50    if {[read_mxframe] >= $value} break
51  }
52
53  set nBackfillNew [read_nbackfill]
54  uplevel [list do_test $tn "expr $nBackfillNew > $nBackfillSaved" 1]
55}
56
57# EVIDENCE-OF: R-30135-06439 The wal_autocheckpoint pragma can be used
58# to invoke this interface from SQL.
59#
60#   All tests in this file are run twice - once using the
61#   sqlite3_wal_autocheckpoint() API, and once using "PRAGMA
62#   wal_autocheckpoint".
63#
64foreach {tn code} {
65  1 {
66    proc autocheckpoint {db value} {
67      uplevel [list $db eval "PRAGMA wal_autocheckpoint = $value"]
68    }
69  }
70
71  2 {
72    proc autocheckpoint {db value} {
73      uplevel [list sqlite3_wal_autocheckpoint $db $value]
74      return $value
75    }
76  }
77} {
78
79  eval $code
80
81  reset_db
82  execsql { PRAGMA auto_vacuum = 0 }
83  do_execsql_test 1.$tn.0 { PRAGMA journal_mode = WAL } {wal}
84  do_execsql_test 1.$tn.1 { CREATE TABLE t1(a, b) }
85  set shmfd [open "test.db-shm" rb]
86
87  # EVIDENCE-OF: R-41531-51083 Every new database connection defaults to
88  # having the auto-checkpoint enabled with a threshold of 1000 or
89  # SQLITE_DEFAULT_WAL_AUTOCHECKPOINT pages.
90  #
91  do_autocommit_threshold_test 1.$tn.2 1000
92  db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
93  do_autocommit_threshold_test 1.$tn.3 1000
94
95  # EVIDENCE-OF: R-38128-34102 The sqlite3_wal_autocheckpoint(D,N) is a
96  # wrapper around sqlite3_wal_hook() that causes any database on database
97  # connection D to automatically checkpoint after committing a
98  # transaction if there are N or more frames in the write-ahead log file.
99  #
100  do_test 1.$tn.4 {
101    db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
102    autocheckpoint db 100
103  } {100}
104  do_autocommit_threshold_test 1.$tn.5 100
105
106  do_test 1.$tn.6 {
107    db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
108    autocheckpoint db 500
109  } {500}
110  do_autocommit_threshold_test 1.$tn.7 500
111
112  # EVIDENCE-OF: R-26993-43540 Passing zero or a negative value as the
113  # nFrame parameter disables automatic checkpoints entirely.
114  #
115  do_test 1.$tn.7 {
116    autocheckpoint db 0    ;# Set to zero
117    for {set i 0} {$i < 10000} {incr i} {
118      db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
119    }
120    expr {[file size test.db-wal] > (5 * 1024 * 1024)}
121  } 1
122  do_test 1.$tn.8 {
123    sqlite3_wal_checkpoint_v2 db truncate
124    file size test.db-wal
125  } 0
126  do_test 1.$tn.9 {
127    autocheckpoint db -4    ;# Set to a negative value
128    for {set i 0} {$i < 10000} {incr i} {
129      db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
130    }
131    expr {[file size test.db-wal] > (5 * 1024 * 1024)}
132  } 1
133
134  # EVIDENCE-OF: R-10203-42688 The callback registered by this function
135  # replaces any existing callback registered using sqlite3_wal_hook().
136  #
137  set ::wal_hook_callback 0
138  proc wal_hook_callback {args} { incr ::wal_hook_callback ; return 0 }
139  do_test 1.$tn.10.1 {
140    db wal_hook wal_hook_callback
141    db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
142    db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
143    set ::wal_hook_callback
144  } 2
145  do_test 1.$tn.10.2 {
146    autocheckpoint db 100
147    db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
148    db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
149    set ::wal_hook_callback
150  } 2
151
152  # EVIDENCE-OF: R-17497-43474 Likewise, registering a callback using
153  # sqlite3_wal_hook() disables the automatic checkpoint mechanism
154  # configured by this function.
155  do_test 1.$tn.11.1 {
156    sqlite3_wal_checkpoint_v2 db truncate
157    file size test.db-wal
158  } 0
159  do_test 1.$tn.11.2 {
160    autocheckpoint db 100
161    for {set i 0} {$i < 1000} {incr i} {
162      db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
163    }
164    expr {[file size test.db-wal] < (1 * 1024 * 1024)}
165  } 1
166  do_test 1.$tn.11.3 {
167    db wal_hook wal_hook_callback
168    for {set i 0} {$i < 1000} {incr i} {
169      db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
170    }
171    expr {[file size test.db-wal] < (1 * 1024 * 1024)}
172  } 0
173
174  # EVIDENCE-OF: R-33080-59193 Checkpoints initiated by this mechanism
175  # are PASSIVE.
176  #
177  set ::busy_callback_count 0
178  proc busy_callback {args} {
179    incr ::busy_callback_count
180    return 0
181  }
182  do_test 1.$tn.12.1 {
183    sqlite3_wal_checkpoint_v2 db truncate
184    autocheckpoint db 100
185    db busy busy_callback
186    db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
187    db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
188  } {}
189  do_test 1.$tn.12.2 {
190    sqlite3 db2 test.db
191    db2 eval { BEGIN; SELECT * FROM t1 LIMIT 10; }
192    read_nbackfill
193  } {0}
194  do_test 1.$tn.12.3 {
195    for {set i 0} {$i < 1000} {incr i} {
196      db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
197    }
198    read_nbackfill
199  } {2}
200  do_test 1.$tn.12.4 {
201    set ::busy_callback_count
202  } {0}
203  db2 close
204
205  do_test 1.$tn.12.5 {
206    db eval { INSERT INTO t1 VALUES(randomblob(100), randomblob(100)) }
207    read_nbackfill
208  } {1559}
209
210  db close
211  close $shmfd
212}
213
214finish_test
215