aboutsummaryrefslogtreecommitdiff
path: root/test/walsetlk2.test
blob: 7ffd8f03ded3f33fa7195bbb740d12677c3acb42 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
# 2025 Jan 24
#
# 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.
#
#***********************************************************************
#
# TESTRUNNER: slow
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lock_common.tcl
set testprefix walsetlk2

ifcapable !wal {finish_test ; return }
ifcapable !setlk_timeout {finish_test ; return }

#-------------------------------------------------------------------------
# Check that xShmLock calls are as expected for write transactions in
# setlk mode.
#
reset_db

do_execsql_test 1.0 {
  PRAGMA journal_mode = wal;
  CREATE TABLE t1(a, b, c);
  INSERT INTO t1 VALUES(1, 2, 3);
} {wal}
db close

testvfs tvfs
tvfs script xShmLock_callback
tvfs filter xShmLock

set ::xshmlock [list]
proc xShmLock_callback {method path name detail} {
  lappend ::xshmlock $detail
}

sqlite3 db test.db -vfs tvfs
db timeout 1000

do_execsql_test 1.1 {
  SELECT * FROM t1
} {1 2 3}

do_execsql_test 1.2 {
  INSERT INTO t1 VALUES(4, 5, 6);
}

set ::xshmlock [list]
do_execsql_test 1.3 {
  INSERT INTO t1 VALUES(7, 8, 9);
}

do_test 1.4 {
  set ::xshmlock
} [list \
  {0 1 lock exclusive}                             \
  {4 1 lock exclusive} {4 1 unlock exclusive}      \
  {4 1 lock shared}                                \
  {0 1 unlock exclusive}                           \
  {4 1 unlock shared}
]

do_execsql_test 1.5.1 { SELECT * FROM t1 } {1 2 3 4 5 6 7 8 9}
set ::xshmlock [list]
do_execsql_test 1.5.2 {
  INSERT INTO t1 VALUES(10, 11, 12);
}
do_test 1.5.3 {
  set ::xshmlock
} [list \
  {0 1 lock exclusive}                             \
  {4 1 lock shared}                                \
  {0 1 unlock exclusive}                           \
  {4 1 unlock shared}
]

db close
tvfs delete

#-------------------------------------------------------------------------
# Check that if sqlite3_setlk_timeout() is used, blocking locks timeout
# but other operations do not use the retry mechanism.
#
reset_db
db close
sqlite3 db test.db -fullmutex 1

do_execsql_test 2.0 {
  CREATE TABLE t1(a, b);
  INSERT INTO t1 VALUES(1, 2), (3, 4);
}

sqlite3_setlk_timeout db 2000

# Launch a non-blocking testfixture process to write-lock the 
# database for 2000 ms.
testfixture_nb done {
  sqlite3 db test.db
  db eval {
    BEGIN EXCLUSIVE;
      INSERT INTO t1 VALUES(5, 6);
  }
  after 2000
  db eval {
    COMMIT
  }
  db close
}

after 500 {set ok 1}
vwait ok

do_catchsql_test 2.1 {
  INSERT INTO t1 VALUES(7, 8);
} {1 {database is locked}}

sqlite3_busy_timeout db 2000

do_catchsql_test 2.2 {
  INSERT INTO t1 VALUES(7, 8);
} {0 {}}

do_execsql_test 2.3 {
  SELECT * FROM t1
} {1 2 3 4 5 6 7 8}

do_execsql_test 2.4 {
  PRAGMA journal_mode = wal;
} {wal}

db close
sqlite3 db test.db

do_execsql_test 2.5 {
  INSERT INTO t1 VALUES(9, 10);
}

if {$::sqlite_options(setlk_timeout)==1} {

sqlite3_setlk_timeout db 2000

# Launch a non-blocking testfixture process to write-lock the 
# database for 2000 ms.
testfixture_nb done {
  sqlite3 db test.db
  db eval {
    BEGIN EXCLUSIVE;
      INSERT INTO t1 VALUES(11, 12);
  }
  after 2000
  db eval {
    COMMIT
  }
  db close
}

after 500 {set ok 1}
vwait ok

do_catchsql_test 2.6 {
  INSERT INTO t1 VALUES(13, 14);
} {0 {}}

do_execsql_test 2.7 {
  SELECT * FROM t1
} {1 2 3 4 5 6 7 8 9 10 11 12 13 14}

}


#-------------------------------------------------------------------------
# Check that if sqlite3_setlk_timeout(-1) is called, blocking locks are
# enabled and last for a few seconds at least. Difficult to test that they
# really do block indefinitely.
#
reset_db

if {$::sqlite_options(setlk_timeout)==1} {
do_execsql_test 3.0 {
  PRAGMA journal_mode = wal;
  CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
  INSERT INTO t1 VALUES(1, 'one'), (3, 'three');
} {wal}

sqlite3_setlk_timeout db -1

# Launch a non-blocking testfixture process to write-lock the 
# database for 2000 ms.
testfixture_nb done {
  sqlite3 db test.db
  db eval {
    BEGIN EXCLUSIVE;
      INSERT INTO t1 VALUES(5, 'five');
  }
  after 2000
  db eval {
    COMMIT
  }
  db close
}

after 500 {set ok 1}
vwait ok

breakpoint
do_catchsql_test 3.1 {
  INSERT INTO t1 VALUES(7, 'seven');
} {0 {}}

# Launch another non-blocking testfixture process to write-lock the 
# database for 2000 ms.
testfixture_nb done {
  sqlite3 db test.db
  db eval {
    BEGIN EXCLUSIVE;
      INSERT INTO t1 VALUES(9, 'nine');
  }
  after 2000
  db eval {
    COMMIT
  }
  db close
}

after 500 {set ok 1}
vwait ok

do_catchsql_test 3.2 {
  INSERT INTO t1 VALUES(9, 'ten');
} {1 {UNIQUE constraint failed: t1.a}}

do_execsql_test 3.3 {
  SELECT * FROM t1
} {1 one 3 three 5 five 7 seven 9 nine}

db close

# Launch another non-blocking testfixture process to write-lock the 
# database for 2000 ms.
testfixture_nb done {
  sqlite3 db test.db
  db eval {
    BEGIN EXCLUSIVE;
      INSERT INTO t1 VALUES(11, 'eleven');
  }
  after 2000
  db eval {
    COMMIT
  }
}

sqlite3 db test.db
sqlite3_setlk_timeout db -1
do_catchsql_test 3.4 {
  INSERT INTO t1 VALUES(13, 'thirteen');
} {0 {}}

}

finish_test