Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 0 additions & 22 deletions mysql-test/suite/galera/r/galera_multi_level_fk_ddl_insert.result
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ connection node_2;
SET DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_toi_reached";
SET SESSION wsrep_sync_wait = 0;
connection node_1;
SET GLOBAL DEBUG_DBUG = '+d,wsrep_print_foreign_keys_table';
START TRANSACTION;
INSERT INTO t1 VALUES (3,0);
COMMIT;
Expand All @@ -62,10 +61,6 @@ connection node_1;
SET DEBUG_SYNC = 'RESET';
SET GLOBAL DEBUG_DBUG = "";
SET GLOBAL wsrep_slave_threads=DEFAULT;
connection node_1;
include/assert_grep.inc [Foreign key referenced table found: 2 tables]
include/assert_grep.inc [Foreign key referenced table found: test.t2]
include/assert_grep.inc [Foreign key referenced table found: test.t3]
connection node_2;
select * from t1;
id f2
Expand Down Expand Up @@ -146,7 +141,6 @@ connection node_2;
SET DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_toi_reached";
SET SESSION wsrep_sync_wait = 0;
connection node_1;
SET GLOBAL DEBUG_DBUG = '+d,wsrep_print_foreign_keys_table';
START TRANSACTION;
INSERT INTO t1 VALUES (3,0);
COMMIT;
Expand All @@ -160,11 +154,6 @@ connection node_1;
SET DEBUG_SYNC = 'RESET';
SET GLOBAL DEBUG_DBUG = "";
SET GLOBAL wsrep_slave_threads=DEFAULT;
connection node_1;
include/assert_grep.inc [Foreign key referenced table found: 3 tables]
include/assert_grep.inc [Foreign key referenced table found: test.t2]
include/assert_grep.inc [Foreign key referenced table found: test.t3]
include/assert_grep.inc [Foreign key referenced table found: test.t4]
connection node_2;
select * from t1;
id f2
Expand Down Expand Up @@ -233,7 +222,6 @@ connection node_2;
SET DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_toi_reached";
SET SESSION wsrep_sync_wait = 0;
connection node_1;
SET GLOBAL DEBUG_DBUG = '+d,wsrep_print_foreign_keys_table';
START TRANSACTION;
INSERT INTO t1 VALUES (3,0);
COMMIT;
Expand All @@ -247,11 +235,6 @@ connection node_1;
SET DEBUG_SYNC = 'RESET';
SET GLOBAL DEBUG_DBUG = "";
SET GLOBAL wsrep_slave_threads=DEFAULT;
connection node_1;
include/assert_grep.inc [Foreign key referenced table found: 2 tables]
include/assert_grep.inc [Foreign key referenced table found: test.t2]
include/assert_grep.inc [Foreign key referenced table found: test.t3]
include/assert_grep.inc [Foreign key referenced table found: test.t4]
connection node_2;
select * from t1;
id f2
Expand Down Expand Up @@ -323,7 +306,6 @@ connection node_2;
SET DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_toi_reached";
SET SESSION wsrep_sync_wait = 0;
connection node_1;
SET GLOBAL DEBUG_DBUG = '+d,wsrep_print_foreign_keys_table';
START TRANSACTION;
INSERT INTO t1 VALUES (3,0);
COMMIT;
Expand All @@ -337,10 +319,6 @@ connection node_1;
SET DEBUG_SYNC = 'RESET';
SET GLOBAL DEBUG_DBUG = "";
SET GLOBAL wsrep_slave_threads=DEFAULT;
connection node_1;
include/assert_grep.inc [Foreign key referenced table found: 1 tables]
include/assert_grep.inc [Foreign key referenced table found: test.t2]
include/assert_grep.inc [Foreign key referenced table found: test.t3]
connection node_2;
select * from t1;
id f2
Expand Down
137 changes: 8 additions & 129 deletions mysql-test/suite/galera/t/galera_multi_level_fk_ddl_insert.test
Original file line number Diff line number Diff line change
Expand Up @@ -72,35 +72,8 @@ INSERT INTO t4 VALUES (2,2,1234);

--let $fk_parent_query = DROP TABLE t4
--let $fk_child_query = INSERT INTO t1 VALUES (3,0)
--let $fk_mdl_lock_num = 3
--source galera_multi_level_foreign_key.inc


#
# Verify Foreign key for referenced table added.
#
--connection node_1
--let assert_text= Foreign key referenced table found: 2 tables
--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err
--let assert_count= 2
--let assert_select= Foreign key referenced table found:
--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_insert
--source include/assert_grep.inc

--let assert_text= Foreign key referenced table found: test.t2
--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err
--let assert_count= 1
--let assert_select= Foreign key referenced table found: test.t2
--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_insert
--source include/assert_grep.inc

--let assert_text= Foreign key referenced table found: test.t3
--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err
--let assert_count= 1
--let assert_select= Foreign key referenced table found: test.t3
--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_insert
--source include/assert_grep.inc

--let $fk_mdl_lock_num = 2
--source galera_multi_level_foreign_key_insert.inc

#
# Verify insert and drop table has succeded.
Expand Down Expand Up @@ -191,41 +164,8 @@ INSERT INTO t4 VALUES (2,2,1234);
# Issue a INSERT to table that references t1
#
--let $fk_child_query = INSERT INTO t1 VALUES (3,0)
--let $fk_mdl_lock_num = 4
--source galera_multi_level_foreign_key.inc


#
# Verify Foreign key for referenced table added.
#
--connection node_1
--let assert_text= Foreign key referenced table found: 3 tables
--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err
--let assert_count= 5
--let assert_select= Foreign key referenced table found:
--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_insert
--source include/assert_grep.inc

--let assert_text= Foreign key referenced table found: test.t2
--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err
--let assert_count= 2
--let assert_select= Foreign key referenced table found: test.t2
--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_insert
--source include/assert_grep.inc

--let assert_text= Foreign key referenced table found: test.t3
--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err
--let assert_count= 2
--let assert_select= Foreign key referenced table found: test.t3
--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_insert
--source include/assert_grep.inc

--let assert_text= Foreign key referenced table found: test.t4
--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err
--let assert_count= 1
--let assert_select= Foreign key referenced table found: test.t4
--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_insert
--source include/assert_grep.inc
--let $fk_mdl_lock_num = 2
--source galera_multi_level_foreign_key_insert.inc


#
Expand Down Expand Up @@ -296,42 +236,8 @@ INSERT INTO t3 VALUES (2,2,1234);

--let $fk_parent_query = CREATE TABLE t4 (id INT PRIMARY KEY, t3_id INT NOT NULL, f2 INTEGER NOT NULL, KEY key_t3_id(t3_id), CONSTRAINT key_t3_id FOREIGN KEY (t3_id) REFERENCES t3 (id) ON UPDATE CASCADE ON DELETE CASCADE)
--let $fk_child_query = INSERT INTO t1 VALUES (3,0)
--let $fk_mdl_lock_num = 4
--source galera_multi_level_foreign_key.inc


#
# Verify Foreign key for referenced table added.
#
--connection node_1
--let assert_text= Foreign key referenced table found: 2 tables
--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err
--let assert_count= 8
--let assert_select= Foreign key referenced table found:
--let $assert_only_after = CURRENT_TEST:
--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_insert
--source include/assert_grep.inc

--let assert_text= Foreign key referenced table found: test.t2
--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err
--let assert_count= 3
--let assert_select= Foreign key referenced table found: test.t2
--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_insert
--source include/assert_grep.inc

--let assert_text= Foreign key referenced table found: test.t3
--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err
--let assert_count= 3
--let assert_select= Foreign key referenced table found: test.t3
--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_insert
--source include/assert_grep.inc

--let assert_text= Foreign key referenced table found: test.t4
--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err
--let assert_count= 2
--let assert_select= Foreign key referenced table found: test.t4
--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_insert
--source include/assert_grep.inc
--let $fk_mdl_lock_num = 2
--source galera_multi_level_foreign_key_insert.inc


#
Expand Down Expand Up @@ -403,35 +309,8 @@ INSERT INTO t3 VALUES (2,2,1234);

--let $fk_parent_query = OPTIMIZE TABLE t3
--let $fk_child_query = INSERT INTO t1 VALUES (3,0)
--let $fk_mdl_lock_num = 3
--source galera_multi_level_foreign_key.inc


#
# Verify Foreign key for referenced table added.
#
--connection node_1
--let assert_text= Foreign key referenced table found: 1 tables
--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err
--let assert_count= 10
--let assert_select= Foreign key referenced table found:
--let $assert_only_after = CURRENT_TEST:
--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_insert
--source include/assert_grep.inc

--let assert_text= Foreign key referenced table found: test.t2
--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err
--let assert_count= 4
--let assert_select= Foreign key referenced table found: test.t2
--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_insert
--source include/assert_grep.inc

--let assert_text= Foreign key referenced table found: test.t3
--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err
--let assert_count= 4
--let assert_select= Foreign key referenced table found: test.t3
--let assert_only_after= CURRENT_TEST: galera.galera_multi_level_fk_ddl_insert
--source include/assert_grep.inc
--let $fk_mdl_lock_num = 2
--source galera_multi_level_foreign_key_insert.inc


#
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@

--connection node_2
SET GLOBAL DEBUG_DBUG = '+d,sync.wsrep_apply_toi';

--connection node_1
--eval $fk_parent_query

--connection node_2
SET DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_toi_reached";
SET SESSION wsrep_sync_wait = 0;

#
# Execute child query on node_1.
# If bug is present, expect the wait condition
# to timeout and when the child query applies, it
# will be granted a MDL lock on parent table.
# When resumed, the parent query will
# also try to acquire MDL lock on parent table,
# causing a BF-BF conflict on that MDL lock.
#
--connection node_1
START TRANSACTION;
--eval $fk_child_query
--let $wait_condition = SELECT COUNT(*) = $fk_mdl_lock_num FROM performance_schema.metadata_locks WHERE OBJECT_SCHEMA='test' AND LOCK_STATUS="GRANTED"
--source include/wait_condition.inc
COMMIT;


--connection node_2
SET GLOBAL DEBUG_DBUG = '-d,sync.wsrep_apply_toi';
SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_toi";


#
# Cleanup
#
SET DEBUG_SYNC = 'RESET';
SET GLOBAL DEBUG_DBUG = "";
SET GLOBAL wsrep_slave_threads=DEFAULT;

--connection node_1
SET DEBUG_SYNC = 'RESET';
SET GLOBAL DEBUG_DBUG = "";
SET GLOBAL wsrep_slave_threads=DEFAULT;
16 changes: 14 additions & 2 deletions sql/log_event_server.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8001,11 +8001,23 @@ Write_rows_log_event::do_exec_row(rpl_group_info *rgi)
#if defined(HAVE_REPLICATION)
uint8 Write_rows_log_event::get_trg_event_map()
{
return trg2bit(TRG_EVENT_INSERT) | trg2bit(TRG_EVENT_UPDATE) |
trg2bit(TRG_EVENT_DELETE);
/*
In SLAVE_EXEC_MODE_IDEMPOTENT mode, Write_rows_log_event event is
implicitly a REPLACE, deleting all conflicting rows which can cause
foreign key constraint cascade operations on FK referencing table.

In SLAVE_EXEC_MODE_STRICT mode, the Write_rows_log_event is pure INSERT,
will never cause foreign key constraint cascade operations on foreign key
referencing tables.
*/
if (slave_exec_mode_options == SLAVE_EXEC_MODE_IDEMPOTENT)
return trg2bit(TRG_EVENT_INSERT) | trg2bit(TRG_EVENT_DELETE);
else
return trg2bit(TRG_EVENT_INSERT);
}
#endif


/**************************************************************************
Delete_rows_log_event member functions
**************************************************************************/
Expand Down
45 changes: 1 addition & 44 deletions sql/sql_base.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3965,15 +3965,6 @@ bool extend_table_list(THD *thd, TABLE_LIST *tables,
(tables->updating && tables->lock_type >= TL_FIRST_WRITE)
|| thd->lex->default_used;

#ifdef WITH_WSREP
if (WSREP(thd) && !thd->wsrep_applier &&
wsrep_is_active(thd) &&
(sql_command_flags[thd->lex->sql_command] & CF_INSERTS_DATA) &&
tables->lock_type == TL_READ) {
maybe_need_prelocking= true;
}
#endif

if (thd->locked_tables_mode <= LTM_LOCK_TABLES &&
! has_prelocking_list && maybe_need_prelocking)
{
Expand Down Expand Up @@ -5106,7 +5097,6 @@ prepare_fk_prelocking_list(THD *thd, Query_tables_list *prelocking_ctx,
Query_arena *arena, backup;
TABLE *table= table_list->table;
bool error= FALSE;
bool override_fk_ignore_table= FALSE;

if (!table->file->referenced_by_foreign_key())
DBUG_RETURN(FALSE);
Expand All @@ -5123,37 +5113,6 @@ prepare_fk_prelocking_list(THD *thd, Query_tables_list *prelocking_ctx,

*need_prelocking= TRUE;

#ifdef WITH_WSREP
/*
MDL is enough for read-only FK checks, we don't need the table,
but on galera applier node lock_type is set to TL_FIRST_WRITE and not
TL_READ, which is due to Write_rows_log_event event logged for INSERT
is used to record insert, update and delete
(Write_rows_log_event::get_trg_event_map()), and therefore all child
tables will be opened and MDL locks will be taken on applier node, while
opening of multiple child tables is ignored on write node by setting
open_strategy= OPEN_STUB in init_one_table_for_prelocking().
This difference in write and applier node can result in MDL deadlock.
Tables with foreign keys: t1<-t2<-t3<-t4
Conflicting transactions: INSERT t1 and DROP TABLE t4
Wsrep certification keys taken on write node:
- for INSERT t1: t1 and t2
- for DROP TABLE t4: t4
On applier node MDL deadlock happened between two transaction because
MDL locks for INSERT t1 were taken on t1, t2, t3 and t4, which conflicted
with MDL lock on t4 taken by DROP TABLE t4.
The Wsrep certification keys does helps in resolving in transactions
getting MDL deadlock. But to generate Wsrep certification keys it needs
to open and take MDL locks on all child tables. So that conflicting
transactions can be prioritize and scheduled.
*/
if (WSREP(thd) && !thd->wsrep_applier &&
wsrep_is_active(thd) &&
(sql_command_flags[thd->lex->sql_command] & CF_INSERTS_DATA)) {
override_fk_ignore_table= TRUE;
}
#endif // WITH_WSREP

while ((fk= fk_list_it++))
{
// FK_OPTION_RESTRICT and FK_OPTION_NO_ACTION only need read access
Expand All @@ -5177,15 +5136,13 @@ prepare_fk_prelocking_list(THD *thd, Query_tables_list *prelocking_ctx,
TABLE_LIST::PRELOCK_FK,
table_list->belong_to_view, op,
&prelocking_ctx->query_tables_last,
table_list->for_insert_data,
override_fk_ignore_table);
table_list->for_insert_data);

#ifdef WITH_WSREP
/*
Append table level shared key for the referenced/foreign table for:
- statement that updates existing rows (UPDATE, multi-update)
- statement that deletes existing rows (DELETE, DELETE_MULTI)
- statement that inserts new rows (INSERT, REPLACE, LOAD, ALTER TABLE)
This is done to avoid potential MDL conflicts with concurrent DDLs.
*/
if (wsrep_foreign_key_append(thd, fk))
Expand Down
Loading