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