mirror of
https://github.com/MariaDB/server.git
synced 2026-10-23 18:49:29 +03:00
MDEV-39056 : sporadic test failures with galera.galera_toi_ddl_nonconflicting
The test sent ALTER TABLE t1 ADD COLUMN f3 INTEGER; INSERT INTO t1 VALUES (NULL, 10000, 10000); from node_2 as a single --send. Nothing ordered that INSERT against the CREATE UNIQUE INDEX issued from node_1, so the second DDL could reach node_2 while the INSERT was still executing there and BF-abort it. The automatic autocommit retry then replicated with last_seen_seqno behind the seqno of the DDL and failed certification against its exclusive key on test.t1. As wsrep_retry_autocommit defaults to 1 there was no second retry and the client got ER_LOCK_DEADLOCK. Send only the ALTER TABLE and execute the INSERT after both DDL statements have completed on both nodes. Waiting for the second DDL by polling INFORMATION_SCHEMA.PROCESSLIST did not prove that it had been ordered either: wsrep_TOI_begin() sets the "Waiting to execute in isolation" stage before it replicates the writeset, so that state can be observed before the DDL has reached total order. Wait on node_2 for the new index to appear instead, which happens only once the DDL has been ordered behind the parked ALTER TABLE, and record on node_1 that neither DDL has been applied there while the first one is still parked. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
committed by
Jan Lindström
parent
75fe7a5118
commit
7ba0776692
@@ -13,7 +13,7 @@ SET SESSION wsrep_sync_wait=0;
|
||||
SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync';
|
||||
connection node_2;
|
||||
# DDL 1
|
||||
ALTER TABLE t1 ADD COLUMN f3 INTEGER; INSERT INTO t1 VALUES (NULL, 10000, 10000);;
|
||||
ALTER TABLE t1 ADD COLUMN f3 INTEGER;
|
||||
connection node_1a;
|
||||
SET SESSION wsrep_on = 0;
|
||||
SET SESSION wsrep_on = 1;
|
||||
@@ -21,14 +21,22 @@ SET GLOBAL wsrep_provider_options = 'dbug=';
|
||||
# This will block on acquiring total order isolation
|
||||
connection node_1;
|
||||
# DDL 2
|
||||
CREATE UNIQUE INDEX i1 ON t1(f2);;
|
||||
CREATE UNIQUE INDEX i1 ON t1(f2);
|
||||
connection node_2a;
|
||||
# Neither DDL has been applied on node_1 yet
|
||||
connection node_1a;
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
|
||||
EXPECT_2
|
||||
2
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_NAME = 't1';
|
||||
EXPECT_1
|
||||
1
|
||||
# Signal DDL 1
|
||||
SET GLOBAL wsrep_provider_options = 'dbug=';
|
||||
SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync';
|
||||
connection node_2;
|
||||
connection node_1;
|
||||
connection node_2;
|
||||
INSERT INTO t1 VALUES (NULL, 10000, 10000);
|
||||
SELECT COUNT(*) AS EXPECT_3 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
|
||||
EXPECT_3
|
||||
3
|
||||
|
||||
@@ -28,32 +28,49 @@ SET SESSION wsrep_sync_wait=0;
|
||||
--let $galera_sync_point = apply_monitor_slave_enter_sync
|
||||
--source include/galera_set_sync_point.inc
|
||||
|
||||
#
|
||||
# DDL 1 is a TOI operation, it completes on node_2 as soon as it has been
|
||||
# replicated, it does not wait for node_1. On node_1 its writeset is parked
|
||||
# in the apply monitor by the sync point above, so node_1 cannot advance
|
||||
# past it.
|
||||
#
|
||||
--connection node_2
|
||||
--echo # DDL 1
|
||||
--send ALTER TABLE t1 ADD COLUMN f3 INTEGER; INSERT INTO t1 VALUES (NULL, 10000, 10000);
|
||||
--send ALTER TABLE t1 ADD COLUMN f3 INTEGER
|
||||
|
||||
--connection node_1a
|
||||
--source include/galera_wait_sync_point.inc
|
||||
--source include/galera_clear_sync_point.inc
|
||||
|
||||
#
|
||||
# DDL 2 is issued on node_1 while DDL 1 is still parked there. It is therefore
|
||||
# assigned a later seqno and has to wait for DDL 1 to be applied before it can
|
||||
# acquire total order isolation.
|
||||
#
|
||||
--echo # This will block on acquiring total order isolation
|
||||
--connection node_1
|
||||
--echo # DDL 2
|
||||
--send CREATE UNIQUE INDEX i1 ON t1(f2);
|
||||
--send CREATE UNIQUE INDEX i1 ON t1(f2)
|
||||
|
||||
--connection node_1a
|
||||
#
|
||||
# "acquiring total order isolation" is not listed here: wsrep_TOI_begin()
|
||||
# sets it with thd_proc_info() and THD_STAGE_INFO() overwrites it two lines
|
||||
# later, so it never reaches the process list. "Waiting for TOI DDL" is the
|
||||
# stage restored when a statement that already holds total order isolation
|
||||
# leaves one of the one second metadata lock wait slices.
|
||||
# Wait until DDL 2 has been replicated and applied on node_2. That proves that
|
||||
# DDL 2 has reached total order after DDL 1 and is now waiting on node_1.
|
||||
#
|
||||
--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE LIKE 'Waiting for table metadata lock%' OR STATE LIKE 'Waiting for TOI DDL%' OR STATE LIKE 'Waiting to execute in isolation%';
|
||||
# Polling INFORMATION_SCHEMA.PROCESSLIST on node_1 for the state of the DDL 2
|
||||
# thread is not a reliable substitute: wsrep_TOI_begin() sets the
|
||||
# "Waiting to execute in isolation" stage before it replicates the writeset,
|
||||
# so that state can be observed before DDL 2 has been ordered at all.
|
||||
#
|
||||
--connection node_2a
|
||||
--let $wait_condition = SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_NAME = 't1';
|
||||
--source include/wait_condition.inc
|
||||
|
||||
--echo # Neither DDL has been applied on node_1 yet
|
||||
--connection node_1a
|
||||
SELECT COUNT(*) AS EXPECT_2 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
|
||||
SELECT COUNT(*) AS EXPECT_1 FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_NAME = 't1';
|
||||
|
||||
--echo # Signal DDL 1
|
||||
--source include/galera_clear_sync_point.inc
|
||||
--let $galera_sync_point = apply_monitor_slave_enter_sync
|
||||
--source include/galera_signal_sync_point.inc
|
||||
|
||||
@@ -63,7 +80,16 @@ SET SESSION wsrep_sync_wait=0;
|
||||
--connection node_1
|
||||
--reap
|
||||
|
||||
#
|
||||
# The DML is executed only after both DDLs are done on both nodes. When it was
|
||||
# sent together with DDL 1 in the same --send, its writeset raced with DDL 2:
|
||||
# the DDL 2 TOI could reach node_2 while the INSERT was still executing there
|
||||
# and BF-abort it, and the automatic autocommit retry then failed certification
|
||||
# against the DDL 2 writeset, so the client got ER_LOCK_DEADLOCK.
|
||||
#
|
||||
--connection node_2
|
||||
INSERT INTO t1 VALUES (NULL, 10000, 10000);
|
||||
|
||||
--let $wait_condition = SELECT COUNT(*) = 3 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 't1';
|
||||
--source include/wait_condition.inc
|
||||
--let $wait_condition = SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_NAME = 't1';
|
||||
|
||||
Reference in New Issue
Block a user