| Bug #116319 | When locks exhaust the BP, an incorret assert about semi_consistent causes crash | ||
|---|---|---|---|
| Submitted: | 9 Oct 2024 6:50 | Modified: | 9 Oct 2024 12:24 |
| Reporter: | mengchu shi (OCA) | Email Updates: | |
| Status: | Verified | Impact on me: | |
| Category: | MySQL Server: InnoDB storage engine | Severity: | S2 (Serious) |
| Version: | 8.0, 8.4, 8.0.39 | OS: | Any |
| Assigned to: | CPU Architecture: | Any | |
| Tags: | Contribution, DML, lock, semi_consistent | ||
[9 Oct 2024 12:24]
MySQL Verification Team
Hello mengchu shi, Thank you for the report and feedback. regards, Umesh
[9 Oct 2024 12:25]
MySQL Verification Team
8.0.39 test results
Attachment: 116319.results.txt (text/plain), 2.78 MiB.
[10 Oct 2024 2:19]
mengchu shi
patch to fix the bug incorrect_assert_if_use_semi_consistent_when_table_lock_full (*) I confirm the code being submitted is offered under the terms of the OCA, and that I am authorized to contribute it.
Contribution: bugfix_incorrect_assert_if_use_semi_consistent_when_table_lock_full.gitlog (application/octet-stream, text), 3.26 KiB.
[10 Oct 2024 2:19]
mengchu shi
patch to fix the bug incorrect_assert_if_use_semi_consistent_when_table_lock_full (*) I confirm the code being submitted is offered under the terms of the OCA, and that I am authorized to contribute it.
Contribution: bugfix_incorrect_assert_if_use_semi_consistent_when_table_lock_full.gitlog (application/octet-stream, text), 3.26 KiB.
[10 Oct 2024 3:58]
MySQL Verification Team
Thank you for the Contribution. regards, Umesh

Description: an assert about semi_consistent in function `row_search_mvcc` is incorrect and may cause crash when the lock structs exhaust the BP. The code analysis as following: In function `row_search_mvcc`, if `use_semi_consistent` is true, call `sel_set_rec_lock` with `SELECT_SKIP_LOCKED` mode and `DB_SKIP_LOCKED` is excepted to be returned. However, `sel_set_rec_lock` may return `DB_LOCK_TABLE_FULL` if locks exhaust the BP so that less than 25 % of BP is available. So the following `switch` of row_search_mvcc will enter `default:`, assert !use_semi_consistent failed and crash. How to repeat: Use debug injection to simulate the situation of lock table full: ``` --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -1149,6 +1149,10 @@ static inline dberr_t sel_set_rec_lock(btr_pcur_t *pcur, const rec_t *rec, trx = thr_get_trx(thr); ut_ad(trx_can_be_handled_by_current_thread(trx)); + DBUG_EXECUTE_IF( + "simulate_lock_table_full", + if (sel_mode == SELECT_SKIP_LOCKED) return (DB_LOCK_TABLE_FULL);); + if (UT_LIST_GET_LEN(trx->lock.trx_locks) > 10000) { if (buf_LRU_buf_pool_running_out()) { return (DB_LOCK_TABLE_FULL); ``` And test as following: ``` ##### Prepare # Try to use semi-consistent read: # 1. transaction_isolation="READ-COMMITTED" # 2. do update # 3. mustn't use the unique search SET SESSION transaction_isolation="READ-COMMITTED"; CREATE TABLE t1(id INT, name VARCHAR(200)); INSERT INTO t1 VALUES(1, "before"); ##### Debug inject # Simulate the situation of lock table full SET GLOBAL debug="+d,simulate_lock_table_full"; ##### Test # Before this patch, a crash will occur here # After this patch, this query will fail --error ER_LOCK_TABLE_FULL UPDATE t1 SET name="after" WHERE id=1; ##### Clear DROP TABLE t1; SET GLOBAL debug="-d,simulate_lock_table_full"; ``` Suggested fix: Correct the assert ``` --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -5287,7 +5291,7 @@ rec_loop: } default: - ut_a(!use_semi_consistent); + ut_a(!use_semi_consistent || err == DB_LOCK_TABLE_FULL); goto lock_wait_or_error; } if (err == DB_SUCCESS && !row_to_range_relation.row_can_be_in_range) { ```