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
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
|
--source include/not_embedded.inc
--source include/have_query_cache.inc
--source include/have_debug_sync.inc
--source include/long_test.inc
set global query_cache_type= ON;
set @save_query_cache_size=@@global.query_cache_size;
SET @save_concurrent_insert= @@GLOBAL.concurrent_insert;
#
# Bug #30887 Server crashes on SET GLOBAL query_cache_size=0
#
flush status;
set query_cache_type=DEMAND;
set global query_cache_size= 1024*768;
--disable_warnings
drop table if exists t1;
--enable_warnings
create table t1 (a varchar(100));
insert into t1 values ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb');
connect (bug30887con1, localhost, root, ,test);
connect (bug30887con2, localhost, root, ,test);
connection bug30887con1;
--echo Activate debug hook and attempt to retrieve the statement from the cache.
set debug_sync="wait_in_query_cache_insert SIGNAL parked WAIT_FOR go";
--send select SQL_CACHE * from t1;
connection default;
set debug_sync="now WAIT_FOR parked";
connection bug30887con2;
--echo clear the query cache.
show status like 'Qcache_queries_in_cache';
set global query_cache_size= 0;
connection default;
--echo Signal the debug hook to release the lock.
set debug_sync="now SIGNAL go";
--echo Show query cache status.
show status like 'Qcache_queries_in_cache';
connection bug30887con1;
--reap
disconnect bug30887con1;
disconnect bug30887con2;
connection default;
set debug_sync= 'RESET';
set global query_cache_size= 0;
use test;
drop table t1;
#
# Bug#41098: Query Cache returns wrong result with concurrent insert
#
--disable_warnings
DROP TABLE IF EXISTS t1, t2;
--enable_warnings
CREATE TABLE t1 (a INT);
CREATE TABLE t2 (a INT);
INSERT INTO t1 VALUES (1),(2),(3);
SET GLOBAL concurrent_insert= 1;
SET GLOBAL query_cache_size= 1024*512;
SET GLOBAL query_cache_type= ON;
connect(con1,localhost,root,,test,,);
connect(con2,localhost,root,,test,,);
connection con1;
SET DEBUG_SYNC = "wait_after_query_cache_invalidate SIGNAL parked WAIT_FOR go";
--echo # Send concurrent insert, will wait in the query cache table invalidate
--send INSERT INTO t1 VALUES (4)
connection default;
--echo # Wait for concurrent insert to reach the debug point
SET DEBUG_SYNC = "now WAIT_FOR parked";
connection con2;
--echo # Send SELECT that shouldn't be cached
SELECT * FROM t1;
connection default;
--echo # Notify the concurrent insert to proceed
SET DEBUG_SYNC = "now SIGNAL go";
connection con1;
--echo # Gather insert result
--reap
SHOW STATUS LIKE "Qcache_queries_in_cache";
--echo # Test that it's cacheable
SELECT * FROM t1;
SHOW STATUS LIKE "Qcache_queries_in_cache";
disconnect con1;
disconnect con2;
connection default;
--echo # Restore defaults
SET DEBUG_SYNC= 'RESET';
RESET QUERY CACHE;
DROP TABLE t1,t2;
SET GLOBAL concurrent_insert= DEFAULT;
SET GLOBAL query_cache_size= DEFAULT;
SET GLOBAL query_cache_type= DEFAULT;
--echo #
--echo # Bug43758 Query cache can lock up threads in 'freeing items' state
--echo #
FLUSH STATUS;
SET GLOBAL query_cache_type=DEMAND;
SET GLOBAL query_cache_size= 1024*768;
--disable_warnings
DROP TABLE IF EXISTS t1,t2,t3,t4,t5;
--enable_warnings
CREATE TABLE t1 (a VARCHAR(100));
CREATE TABLE t2 (a VARCHAR(100));
CREATE TABLE t3 (a VARCHAR(100));
CREATE TABLE t4 (a VARCHAR(100));
CREATE TABLE t5 (a VARCHAR(100));
INSERT INTO t1 VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb');
INSERT INTO t2 VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb');
INSERT INTO t3 VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb');
INSERT INTO t4 VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb');
INSERT INTO t5 VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb');
connect (thd2, localhost, root, ,test);
connect (thd3, localhost, root, ,test);
connect (thd1, localhost, root, ,test);
connection thd1;
--echo **
--echo ** Load Query Cache with a result set and one table.
--echo **
SELECT SQL_CACHE * FROM t1;
--echo *************************************************************************
--echo ** We want to accomplish the following state:
--echo ** - Query cache status: TABLE_FLUSH_IN_PROGRESS
--echo ** - THD1: invalidate_table_internal (iterating query blocks)
--echo ** - THD2: query_cache_insert (cond_wait)
--echo ** - THD3: query_cache_insert (cond_wait)
--echo ** - No thread should be holding the structure_guard_mutex.
--echo **
--echo ** First step is to place a DELETE-statement on the debug hook just
--echo ** before the mutex lock in invalidate_table_internal.
--echo ** This will allow new result sets to be written into the QC.
--echo **
SET DEBUG_SYNC="wait_in_query_cache_invalidate1 SIGNAL parked1_1 WAIT_FOR go1_1";
SET DEBUG_SYNC="wait_in_query_cache_invalidate2 SIGNAL parked1_2 WAIT_FOR go1_2";
--send DELETE FROM t1 WHERE a like '%a%';
connection default;
--echo ** Assert that the expect process status is obtained.
SET DEBUG_SYNC="now WAIT_FOR parked1_1";
-- echo **
connection thd2;
--echo ** On THD2: Insert a result into the cache. This attempt will be blocked
--echo ** because of a debug hook placed just before the mutex lock after which
--echo ** the first part of the result set is written.
SET DEBUG_SYNC="wait_in_query_cache_insert SIGNAL parked2 WAIT_FOR go2 EXECUTE 1";
--send SELECT SQL_CACHE * FROM t2 UNION SELECT * FROM t3
connection default;
--echo ** Assert that the SELECT-stmt thread reaches the sync point.
SET DEBUG_SYNC="now WAIT_FOR parked2";
--echo **
--echo **
connection thd3;
--echo ** On THD3: Insert another result into the cache and block on the same
--echo ** debug hook.
SET DEBUG_SYNC="wait_in_query_cache_insert SIGNAL parked3 WAIT_FOR go3 EXECUTE 1";
--send SELECT SQL_CACHE * FROM t4 UNION SELECT * FROM t5
connection default;
--echo ** Assert that the SELECT-stmt thread reaches the sync point.
SET DEBUG_SYNC="now WAIT_FOR parked3";
--echo **
--echo **
--echo ** Signal the DELETE thread, THD1, to continue. It will enter the mutex
--echo ** lock and set query cache status to TABLE_FLUSH_IN_PROGRESS and then
--echo ** unlock the mutex before stopping on the next debug hook.
SET DEBUG_SYNC="now SIGNAL go1_1";
--echo ** Assert that we reach the next debug hook.
SET DEBUG_SYNC="now WAIT_FOR parked1_2";
--echo **
--echo ** Signal the remaining debug hooks blocking THD2 and THD3.
--echo ** The threads will grab the guard mutex enter the wait condition and
--echo ** and finally release the mutex. The threads will continue to wait
--echo ** until a broadcast signal reaches them causing both threads to
--echo ** come alive and check the condition.
SET DEBUG_SYNC="now SIGNAL go2";
SET DEBUG_SYNC="now SIGNAL go3";
--echo **
--echo ** Finally signal the DELETE statement on THD1 one last time.
--echo ** The stmt will complete the query cache invalidation and return
--echo ** cache status to NO_FLUSH_IN_PROGRESS. On the status change
--echo ** One signal will be sent to the thread group waiting for executing
--echo ** invalidations and a broadcast signal will be sent to the thread
--echo ** group holding result set writers.
SET DEBUG_SYNC="now SIGNAL go1_2";
--echo **
--echo *************************************************************************
--echo ** No tables should be locked
connection thd2;
reap;
DELETE FROM t1;
DELETE FROM t2;
DELETE FROM t3;
connection thd3;
reap;
DELETE FROM t4;
DELETE FROM t5;
connection thd1;
reap;
--echo ** Done.
connection default;
disconnect thd1;
disconnect thd2;
disconnect thd3;
SET DEBUG_SYNC= 'RESET';
SET GLOBAL query_cache_size= 0;
connection default;
--echo # Restore defaults
RESET QUERY CACHE;
FLUSH STATUS;
DROP TABLE t1,t2,t3,t4,t5;
SET GLOBAL query_cache_size= DEFAULT;
SET GLOBAL query_cache_type= DEFAULT;
--echo #
--echo # Bug#56822: Add a thread state for sessions waiting on the query cache lock
--echo #
--disable_warnings
DROP TABLE IF EXISTS t1;
--enable_warnings
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1),(2),(3);
SET GLOBAL concurrent_insert= 1;
SET GLOBAL query_cache_size= 1024*512;
SET GLOBAL query_cache_type= ON;
connect(con1,localhost,root,,test,,);
connect(con2,localhost,root,,test,,);
connection con1;
SET DEBUG_SYNC = "wait_in_query_cache_invalidate2 SIGNAL parked WAIT_FOR go";
--echo # Send INSERT, will wait in the query cache table invalidation
--send INSERT INTO t1 VALUES (4);
connection default;
--echo # Wait for insert to reach the debug point
SET DEBUG_SYNC = "now WAIT_FOR parked";
connection con2;
--echo # Send a query that should wait on the query cache lock
--send RESET QUERY CACHE
connection default;
--echo # Wait for the state to be reflected in the processlist
let $wait_condition=
SELECT COUNT(*) = 1 FROM information_schema.processlist
WHERE state = "Waiting for query cache lock" AND info = "RESET QUERY CACHE";
--source include/wait_condition.inc
--echo # Signal that the query cache can be unlocked
SET DEBUG_SYNC="now SIGNAL go";
connection con1;
--reap
disconnect con1;
connection con2;
--reap
disconnect con2;
connection default;
--echo # Restore defaults
SET DEBUG_SYNC= 'RESET';
RESET QUERY CACHE;
DROP TABLE t1;
SET GLOBAL query_cache_size= @save_query_cache_size;
SET GLOBAL query_cache_type= DEFAULT;
--echo #
--echo # MDEV-14526: MariaDB keeps crashing under load when
--echo # query_cache_type is changed
--echo #
CREATE TABLE t1 (
`id` int(10) NOT NULL AUTO_INCREMENT,
`k` int(10) default '0',
PRIMARY KEY (`id`))
ENGINE=MyISAM;
INSERT IGNORE INTO t1 VALUES
(NULL,1),(NULL,8),(NULL,NULL),(NULL,NULL),(NULL,4),(NULL,9),(NULL,7),
(NULL,3),(NULL,NULL),(NULL,2),(NULL,3),(NULL,NULL),(NULL,2),(NULL,7),
(NULL,1),(NULL,2),(NULL,4),(NULL,NULL),(NULL,1),(NULL,1),(NULL,4);
SET GLOBAL query_cache_size= 1024*1024;
SET GLOBAL query_cache_type= 1;
--connect (con2,localhost,root,,test)
--connect (con1,localhost,root,,test)
set debug_sync="wait_in_query_cache_store_query SIGNAL parked WAIT_FOR go";
--send SELECT DISTINCT id FROM t1 WHERE id BETWEEN 5603 AND 16218 ORDER BY k
--connection default
set debug_sync="now WAIT_FOR parked";
--connection con2
--send SET GLOBAL query_cache_type= 0;
--connection default
set debug_sync="now SIGNAL go";
--connection con1
--reap
--connection con2
--reap
# Cleanup
--disconnect con1
--disconnect con2
--connection default
set debug_sync= 'RESET';
DROP TABLE t1;
SET GLOBAL query_cache_size=@save_query_cache_size;
SET GLOBAL query_cache_type= DEFAULT;
SET @@GLOBAL.concurrent_insert=@save_concurrent_insert;
--echo # End of 5.5 tests
|