Skip to content

Commit 34d4c2d

Browse files
committed
Bug #30183982 LOB::PURGE AND Z_PURGE LEAD TO A DEADLOCK IF BLOB IS LARGER THAN BUFFERPOOL
Problem: Since the LOB purge operation is done using a single mtr, if the LOB is bigger than the buffer pool size, then the purge operation will fail. Solution: Use multiple mtrs to purge LOBs. rb#23038 approved by Kuba Lopuszanski <[email protected]>
1 parent 9baca83 commit 34d4c2d

24 files changed

+793
-45
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
CREATE TABLE t1 (id INT PRIMARY KEY NOT NULL, val LONGTEXT);
2+
INSERT INTO t1 VALUES (1, repeat('a',7000000));
3+
UPDATE t1 SET val = repeat('b',7000000);
4+
DROP TABLE t1;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
SET GLOBAL innodb_compression_level = 0;
2+
SET debug = '+d,zlob_reduce_chunk_size';
3+
CREATE TABLE t1 (id INT PRIMARY KEY NOT NULL, val LONGTEXT)
4+
ENGINE=InnoDB ROW_FORMAT=COMPRESSED;
5+
INSERT INTO t1 VALUES (1, repeat('a',7000000));
6+
UPDATE t1 SET val = repeat('b',7000000);
7+
DROP TABLE t1;
8+
SET GLOBAL innodb_compression_level = default;
9+
SET debug = '-d,zlob_reduce_chunk_size';

mysql-test/suite/innodb/r/zlob_fragments.result

Lines changed: 419 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
SET GLOBAL innodb_compression_level = 0;
2+
CREATE TABLE t1 (j1 JSON) ENGINE=InnoDB ROW_FORMAT=compressed;
3+
SHOW CREATE TABLE t1;
4+
Table Create Table
5+
t1 CREATE TABLE `t1` (
6+
`j1` json DEFAULT NULL
7+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=COMPRESSED
8+
SET @long_str = REPEAT('abcdefghijklmnopqrstuvwxyz1234', 60000);
9+
SET @medium_str_1 = REPEAT('a', 200);
10+
SET @medium_str_2 = REPEAT('b', 200);
11+
SET @json_doc = CONCAT('["', @long_str, '","', @medium_str_1 ,'" ]');
12+
INSERT INTO t1 (j1) VALUES (@json_doc);
13+
SELECT JSON_EXTRACT(j1, '$[1]') FROM t1;
14+
JSON_EXTRACT(j1, '$[1]')
15+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
16+
SET GLOBAL innodb_purge_stop_now = ON;
17+
SET GLOBAL innodb_purge_run_now = ON;
18+
DROP TABLE t1;
19+
SET GLOBAL innodb_compression_level = default;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--innodb-buffer-pool-size=5M
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
--source include/have_debug.inc
2+
3+
CREATE TABLE t1 (id INT PRIMARY KEY NOT NULL, val LONGTEXT);
4+
INSERT INTO t1 VALUES (1, repeat('a',7000000));
5+
UPDATE t1 SET val = repeat('b',7000000);
6+
7+
--source include/wait_innodb_all_purged.inc
8+
9+
DROP TABLE t1;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--innodb-buffer-pool-size=5M
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--source include/have_debug.inc
2+
--source include/have_innodb_max_16k.inc
3+
4+
SET GLOBAL innodb_compression_level = 0;
5+
SET debug = '+d,zlob_reduce_chunk_size';
6+
7+
CREATE TABLE t1 (id INT PRIMARY KEY NOT NULL, val LONGTEXT)
8+
ENGINE=InnoDB ROW_FORMAT=COMPRESSED;
9+
INSERT INTO t1 VALUES (1, repeat('a',7000000));
10+
UPDATE t1 SET val = repeat('b',7000000);
11+
12+
--source include/wait_innodb_all_purged.inc
13+
14+
DROP TABLE t1;
15+
16+
SET GLOBAL innodb_compression_level = default;
17+
SET debug = '-d,zlob_reduce_chunk_size';
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
--source include/big_test.inc
2+
--source include/have_debug.inc
3+
# Actually this test is tailored for 4k,
4+
# but it should pass for other sizes (8k, 16k) as well.
5+
--source include/have_innodb_max_16k.inc
6+
7+
SET GLOBAL innodb_compression_level = 0;
8+
CREATE TABLE t1 (j1 JSON) ENGINE=InnoDB ROW_FORMAT=compressed;
9+
SHOW CREATE TABLE t1;
10+
# Must be long enough to force external storage.
11+
# Also the length must be so that json_doc last "page" of last stream
12+
# is short enough to fit on fragment page.
13+
# I've used trial end error with `--manual-debug --initialize=--innodb-page-size=4k`
14+
# with conditional breakpoint inside z_insert_strm() for condition remain < size
15+
# to see what is the remaining size in last iteration, and then picking a lob size
16+
# such that the `remain` is smaller than 1991/4 which is a criterion used to decide
17+
# if we should use a fragment page.
18+
# This particular value (when run with --initialize=--innodb-page-size=4k) stores the
19+
# [1]-th element of JSON array in a fragment page.
20+
SET @long_str = REPEAT('abcdefghijklmnopqrstuvwxyz1234', 59921);
21+
# must be long enough to force new version (as opposed to storing diff in the undo log),
22+
# but must be short enough to not cause complete rewrite of the blob
23+
SET @medium_str_1 = REPEAT('a', 200);
24+
SET @medium_str_2 = REPEAT('b', 200);
25+
SET @json_doc = CONCAT('["', @long_str, '","', @medium_str_1 ,'" ]');
26+
27+
BEGIN;
28+
INSERT INTO t1 (j1) VALUES (@json_doc);
29+
30+
SELECT JSON_EXTRACT(j1, '$[1]') FROM t1;
31+
# We need to generate enough fragments so that the index of fragments
32+
# overflows first page and needs to allocate z_frag_node_page_t page.
33+
--let i=0
34+
while($i<50){
35+
UPDATE t1 SET j1 = JSON_REPLACE(j1, '$[1]', @medium_str_2);
36+
SELECT JSON_EXTRACT(j1, '$[1]') FROM t1;
37+
UPDATE t1 SET j1 = JSON_REPLACE(j1, '$[1]', @medium_str_1);
38+
SELECT JSON_EXTRACT(j1, '$[1]') FROM t1;
39+
--inc $i
40+
}
41+
ROLLBACK;
42+
43+
DROP TABLE t1;
44+
SET GLOBAL innodb_compression_level = default;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--innodb-buffer-pool-size=5M

0 commit comments

Comments
 (0)