Skip to content

Commit f1abcce

Browse files
committed
Bug #30197056 INNODB: ASSERTION FAILURE: PAGE_TYPE == FIL_PAGE_TYPE_ZLOB_FIRST AT ZLOB0READ.CC
Problem: Consider the scenario where the zlob (compressed LOB) is stored in old format using a single zlib stream. The purge will process this zlob by removing the first page of the LOB repeatedly. There seems to be a race condition b/w purge thread and an update thread that is reusing a delete marked record. Because of this the update thread sees a lob whose first page is of type FIL_PAGE_TYPE_ZBLOB2, which suggests that the zlob is partially purged. The test case just demonstrates that it is possible for the first page of LOB to be FIL_PAGE_TYPE_ZBLOB2 because of partial purging. Solution: I think we can remove the failing assert. rb#23293 approved by Kuba <[email protected]>
1 parent 545f511 commit f1abcce

File tree

8 files changed

+76
-10
lines changed

8 files changed

+76
-10
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#
2+
# Bug #30197056 INNODB: ASSERTION FAILURE: PAGE_TYPE ==
3+
# FIL_PAGE_TYPE_ZLOB_FIRST AT ZLOB0READ.CC
4+
#
5+
SET GLOBAL innodb_compression_level = 0;
6+
CREATE TABLE t1 (f1 INT PRIMARY KEY, f2 LONGBLOB) ROW_FORMAT=COMPRESSED;
7+
INSERT INTO t1 VALUES (1, REPEAT('+', 40000));
8+
SET DEBUG = '+d,lob_insert_single_zstream';
9+
START TRANSACTION;
10+
INSERT INTO t1 VALUES (2, REPEAT('~', 40000));
11+
SET DEBUG = '+d,ib_zlob_deleter_middle_crash';
12+
ROLLBACK;
13+
ERROR HY000: Lost connection to MySQL server during query
14+
# restart
15+
SELECT f1, LENGTH(f2) FROM t1 FOR UPDATE;
16+
f1 LENGTH(f2)
17+
1 40000
18+
DROP TABLE t1;
19+
SET GLOBAL innodb_compression_level = DEFAULT;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
--source include/have_debug.inc
2+
--source include/have_innodb_max_16k.inc
3+
4+
--echo #
5+
--echo # Bug #30197056 INNODB: ASSERTION FAILURE: PAGE_TYPE ==
6+
--echo # FIL_PAGE_TYPE_ZLOB_FIRST AT ZLOB0READ.CC
7+
--echo #
8+
9+
SET GLOBAL innodb_compression_level = 0;
10+
11+
CREATE TABLE t1 (f1 INT PRIMARY KEY, f2 LONGBLOB) ROW_FORMAT=COMPRESSED;
12+
13+
# The size of the BLOB is specified as 40000 bytes so that it will be
14+
# stored externally.
15+
INSERT INTO t1 VALUES (1, REPEAT('+', 40000));
16+
17+
SET DEBUG = '+d,lob_insert_single_zstream';
18+
19+
START TRANSACTION;
20+
INSERT INTO t1 VALUES (2, REPEAT('~', 40000));
21+
22+
--source include/expect_crash.inc
23+
24+
SET DEBUG = '+d,ib_zlob_deleter_middle_crash';
25+
--error 2013
26+
ROLLBACK;
27+
28+
--source include/start_mysqld.inc
29+
30+
SELECT f1, LENGTH(f2) FROM t1 FOR UPDATE;
31+
DROP TABLE t1;
32+
33+
SET GLOBAL innodb_compression_level = DEFAULT;
34+

storage/innobase/include/mtr0mtr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@ struct mtr_t {
430430
return (m_impl.m_log.size() + (m_impl.m_n_log_recs > 1 ? 1 : 0));
431431
}
432432

433+
void wait_for_flush();
433434
#endif /* UNIV_DEBUG */
434435

435436
/** @return true if a record was added to the mini-transaction */

storage/innobase/lob/lob0del.cc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*****************************************************************************
22
3-
Copyright (c) 2015, 2018, Oracle and/or its affiliates. All Rights Reserved.
3+
Copyright (c) 2015, 2019, Oracle and/or its affiliates. All Rights Reserved.
44
55
This program is free software; you can redistribute it and/or modify it under
66
the terms of the GNU General Public License, version 2.0, as published by the
@@ -120,6 +120,11 @@ dberr_t Deleter::destroy() {
120120
if (err != DB_SUCCESS) {
121121
break;
122122
}
123+
124+
DBUG_EXECUTE_IF("ib_zlob_deleter_middle_crash", {
125+
m_mtr.wait_for_flush();
126+
DBUG_SUICIDE();
127+
});
123128
}
124129

125130
return (err);

storage/innobase/lob/lob0first.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,9 @@ buf_block_t *first_page_t::load_x(const page_id_t &page_id,
359359
case FIL_PAGE_SDI_ZBLOB:
360360
case FIL_PAGE_SDI_BLOB:
361361
/* Valid first page type.*/
362+
case FIL_PAGE_TYPE_ZBLOB2:
363+
/* Because of partially purged ZBLOB, we might see this page type as
364+
the first page of the ZBLOB. */
362365
break;
363366
default:
364367
std::cerr << "Unexpected LOB first page type=" << page_type << std::endl;

storage/innobase/lob/lob0purge.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -449,8 +449,10 @@ void purge(DeleteContext *ctx, dict_index_t *index, trx_id_t trxid,
449449
page_type_t page_type =
450450
first_page_t::get_page_type(index, page_id, page_size);
451451

452-
if (page_type == FIL_PAGE_TYPE_ZBLOB || page_type == FIL_PAGE_TYPE_BLOB ||
453-
page_type == FIL_PAGE_SDI_BLOB || page_type == FIL_PAGE_SDI_ZBLOB) {
452+
if (page_type == FIL_PAGE_TYPE_ZBLOB ||
453+
page_type == FIL_PAGE_TYPE_ZBLOB2 || /* Partially purged ZBLOB */
454+
page_type == FIL_PAGE_TYPE_BLOB || page_type == FIL_PAGE_SDI_BLOB ||
455+
page_type == FIL_PAGE_SDI_ZBLOB) {
454456
lob::Deleter free_blob(*ctx);
455457
free_blob.destroy();
456458
return;

storage/innobase/lob/zlob0read.cc

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,11 @@ ulint z_read(ReadContext *ctx, lob::ref_t ref, ulint offset, ulint len,
9090
return (reader.length());
9191
}
9292

93-
ut_ad(page_type == FIL_PAGE_TYPE_ZLOB_FIRST);
94-
9593
if (page_type != FIL_PAGE_TYPE_ZLOB_FIRST) {
96-
/* In the optimized build, assume that the BLOB has been freed and return
97-
without taking further action. This condition is hit when there are stale
98-
LOB references in the clustered index record, especially when there are
99-
server crashes during updation of delete-marked clustered index record
100-
with external fields. */
94+
/* Assume that the BLOB has been freed and return without taking further
95+
action. This condition is hit when there are stale LOB references in the
96+
clustered index record, especially when there are server crashes during
97+
updation of delete-marked clustered index record with external fields. */
10198
mtr_commit(&mtr);
10299
return (0);
103100
}

storage/innobase/mtr/mtr0mtr.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -879,5 +879,10 @@ void mtr_commit_mlog_test_filling_block(log_t &log, size_t req_space_left) {
879879
mtr_commit_mlog_test_filling_block_low(log, req_space_left, 1);
880880
}
881881

882+
void mtr_t::wait_for_flush() {
883+
ut_ad(commit_lsn() > 0);
884+
log_write_up_to(*log_sys, commit_lsn(), true);
885+
}
886+
882887
#endif /* UNIV_DEBUG */
883888
#endif /* !UNIV_HOTBACKUP */

0 commit comments

Comments
 (0)