Commit f5373db8 authored by Vlad Lesin's avatar Vlad Lesin Committed by Marko Mäkelä

MDEV-33004 innodb.cursor-restore-locking test fails

THE FIX MUST NOT BE MERGED TO 10.6+, BECAUSE 10.6+ IS NOT AFFECTED!

The test is waiting for delete-marked record purging. But this does not
happen under the following conditions:

1. "START TRANSACTION WITH CONSISTENT SNAPSHOT" - is active, has not
been rolled back yet
2. "DELETE FROM t WHERE b = 20 # trx_1" - is committed
3. "INSERT INTO t VALUES(10, 20) # trx_2" - hanging on
"ib_after_row_insert" sync point, waiting for "first_ins_cont" signal
4. "DELETE FROM t WHERE b = 20 # trx_3" - blocked on delete-marked by
trx_1 record, waiting for trx_2
5. connection "default" is waiting on
'now WAIT_FOR row_purge_del_mark_finished'

purge_coordinator_callback_low() sets

purge_state.m_history_length= srv_do_purge(&n_total_purged);

even if nothing was purged, like in our case. Nothing was purged because
transaction with consistent snapshot was still alive during purging
procedure.

Then purge_coordinator_timer_callback() does not wake purge thread if
the following condition is true:

purge_state.m_history_length == trx_sys.rseg_history_len

The above condition is true for our case, because we are waiting for
delete-marked record purging, and trx_sys.rseg_history_len does not
grow.

Only 10.5 is affected, because there is no such condition in 10.6, i.e.
purge thread is woken up even if history size was not changed during
purge coordinator thread suspending.

The easiest way to fix it is just to remove the test from 10.5.
parent c31b1ee2
SET @save_freq=@@GLOBAL.innodb_purge_rseg_truncate_frequency;
SET GLOBAL innodb_purge_rseg_truncate_frequency=1;
CREATE TABLE t (a int PRIMARY KEY, b int NOT NULL UNIQUE) engine = InnoDB, STATS_PERSISTENT=0;
InnoDB 0 transactions not purged
connect prevent_purge,localhost,root,,;
start transaction with consistent snapshot;
connect con_del_1,localhost,root,,;
INSERT INTO t VALUES (20,20);
SET DEBUG_SYNC = 'innodb_row_search_for_mysql_exit SIGNAL first_del_row_search_mvcc_finished WAIT_FOR first_del_cont';
DELETE FROM t WHERE b = 20 # trx_1;
connect con_ins_1,localhost,root,,;
SET DEBUG_SYNC = 'now WAIT_FOR first_del_row_search_mvcc_finished';
SET DEBUG_SYNC = 'lock_wait_suspend_thread_enter SIGNAL first_ins_locked';
SET DEBUG_SYNC = 'ib_after_row_insert SIGNAL first_ins_row_inserted WAIT_FOR first_ins_cont';
INSERT INTO t VALUES(10, 20) # trx_2;
connect con_del_2,localhost,root,,;
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET DEBUG_SYNC = 'now WAIT_FOR first_ins_locked';
SET DEBUG_SYNC = 'lock_wait_suspend_thread_enter SIGNAL second_del_locked';
DELETE FROM t WHERE b = 20 # trx_3;
connection default;
SET DEBUG_SYNC = 'now WAIT_FOR second_del_locked';
SET @saved_dbug = @@GLOBAL.debug_dbug;
SET @@GLOBAL.debug_dbug="d,enable_row_purge_del_mark_exit_sync_point";
SET DEBUG_SYNC = 'now SIGNAL first_del_cont';
SET DEBUG_SYNC = 'now WAIT_FOR first_ins_row_inserted';
connection con_del_1;
connection default;
disconnect prevent_purge;
SET DEBUG_SYNC = 'now WAIT_FOR row_purge_del_mark_finished';
SET @@GLOBAL.debug_dbug = @saved_dbug;
SET DEBUG_SYNC = 'now SIGNAL first_ins_cont';
connection con_del_2;
connection con_ins_1;
connection default;
INSERT INTO t VALUES(30, 20);
disconnect con_ins_1;
disconnect con_del_1;
disconnect con_del_2;
connection default;
SET DEBUG_SYNC = 'RESET';
DROP TABLE t;
SET GLOBAL innodb_purge_rseg_truncate_frequency=@save_freq;
--source include/have_innodb.inc
--source include/count_sessions.inc
source include/have_debug.inc;
source include/have_debug_sync.inc;
SET @save_freq=@@GLOBAL.innodb_purge_rseg_truncate_frequency;
SET GLOBAL innodb_purge_rseg_truncate_frequency=1;
CREATE TABLE t (a int PRIMARY KEY, b int NOT NULL UNIQUE) engine = InnoDB, STATS_PERSISTENT=0;
--source include/wait_all_purged.inc
--connect(prevent_purge,localhost,root,,)
start transaction with consistent snapshot;
--connect(con_del_1,localhost,root,,)
INSERT INTO t VALUES (20,20);
SET DEBUG_SYNC = 'innodb_row_search_for_mysql_exit SIGNAL first_del_row_search_mvcc_finished WAIT_FOR first_del_cont';
--send DELETE FROM t WHERE b = 20 # trx_1
--connect(con_ins_1,localhost,root,,)
SET DEBUG_SYNC = 'now WAIT_FOR first_del_row_search_mvcc_finished';
# It's supposed the following INSERT will be suspended just after
# lock_wait_suspend_thread_enter syncpoint, and will be awaken
# after trx_1 DELETE commits. ib_after_row_insert will be executed
# after the trx_2 INSERT is woken up. The trx_1 DELETE will wait for
# first_del_cont signal before commit, and this signal will be sent later.
# So it's safe to use two signals in a row here, it's guaranted the first
# signal will be received before the second signal is sent.
SET DEBUG_SYNC = 'lock_wait_suspend_thread_enter SIGNAL first_ins_locked';
SET DEBUG_SYNC = 'ib_after_row_insert SIGNAL first_ins_row_inserted WAIT_FOR first_ins_cont';
--send INSERT INTO t VALUES(10, 20) # trx_2
--connect(con_del_2,localhost,root,,)
# After MDEV-30225 is fixed, the following DELETE creates next-key lock for
# unqique search for RR, and the above INSERT kills it as deadlock victim.
# But it still requests not-gap lock for RC.
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET DEBUG_SYNC = 'now WAIT_FOR first_ins_locked';
SET DEBUG_SYNC = 'lock_wait_suspend_thread_enter SIGNAL second_del_locked';
##############################################################################
# trx_3 DELETE is locked by trx_1 DELETE, after trx_1 DELETE is
# committed, it will still be locked by trx_2 INSERT on delete-marked
# heap_no 2 record. After trx_2 INSERT inserted the record with heap_no 3,
# and after heap_no 2 record is purged, trx_3 DELETE will be unlocked and
# must restore persistent cursor position at heap_no 3 record, as it has the
# same secondary key value as former heap_no 2 record. Then it must be blocked
# by trx_2 INSERT, and after trx_2 INSERT is committed, it must
# delete the record, inserted by trx_2 INSERT, and trx_4 INSERT(see
# below) must be finished without error. But instead this DELETE restores
# persistent cursor position to supremum, as a result, it does not delete the
# record, inserted by trx_2 INSERT, and trx_4 INSERT is finished with
# duplicate key check error.
###############################################################################
--send DELETE FROM t WHERE b = 20 # trx_3
--connection default
SET DEBUG_SYNC = 'now WAIT_FOR second_del_locked';
SET @saved_dbug = @@GLOBAL.debug_dbug;
SET @@GLOBAL.debug_dbug="d,enable_row_purge_del_mark_exit_sync_point";
SET DEBUG_SYNC = 'now SIGNAL first_del_cont';
SET DEBUG_SYNC = 'now WAIT_FOR first_ins_row_inserted';
--connection con_del_1
--reap
--connection default
--disconnect prevent_purge
SET DEBUG_SYNC = 'now WAIT_FOR row_purge_del_mark_finished';
SET @@GLOBAL.debug_dbug = @saved_dbug;
SET DEBUG_SYNC = 'now SIGNAL first_ins_cont';
--connection con_del_2
--reap
--connection con_ins_1
--reap
--connection default
###############################################################################
# Duplicate key error is expected if the bug is not fixed.
###############################################################################
INSERT INTO t VALUES(30, 20); # trx_4
--disconnect con_ins_1
--disconnect con_del_1
--disconnect con_del_2
--connection default
SET DEBUG_SYNC = 'RESET';
DROP TABLE t;
SET GLOBAL innodb_purge_rseg_truncate_frequency=@save_freq;
--source include/wait_until_count_sessions.inc
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment