diff --git a/mysql-test/suite/galera/r/galera_multi_level_fk_ddl_insert.result b/mysql-test/suite/galera/r/galera_multi_level_fk_ddl_insert.result index aa120e87cb9af..f799d372484a7 100644 --- a/mysql-test/suite/galera/r/galera_multi_level_fk_ddl_insert.result +++ b/mysql-test/suite/galera/r/galera_multi_level_fk_ddl_insert.result @@ -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; @@ -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 @@ -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; @@ -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 @@ -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; @@ -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 @@ -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; @@ -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 diff --git a/mysql-test/suite/galera/t/galera_multi_level_fk_ddl_insert.test b/mysql-test/suite/galera/t/galera_multi_level_fk_ddl_insert.test index d4a1874d51aab..36fcb3947d51d 100644 --- a/mysql-test/suite/galera/t/galera_multi_level_fk_ddl_insert.test +++ b/mysql-test/suite/galera/t/galera_multi_level_fk_ddl_insert.test @@ -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. @@ -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 # @@ -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 # @@ -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 # diff --git a/mysql-test/suite/galera/t/galera_multi_level_foreign_key_insert.inc b/mysql-test/suite/galera/t/galera_multi_level_foreign_key_insert.inc new file mode 100644 index 0000000000000..5cb79bd474136 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_multi_level_foreign_key_insert.inc @@ -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; diff --git a/sql/log_event_server.cc b/sql/log_event_server.cc index 9ad2c5ebb1e28..5beccb1e88c52 100644 --- a/sql/log_event_server.cc +++ b/sql/log_event_server.cc @@ -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 **************************************************************************/ diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 34d4098879384..b9d6497d2ce2d 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -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) { @@ -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); @@ -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 @@ -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)) diff --git a/sql/table.h b/sql/table.h index 341532b634545..d44ceaebd7971 100644 --- a/sql/table.h +++ b/sql/table.h @@ -2383,8 +2383,7 @@ struct TABLE_LIST const LEX_CSTRING *table_name_arg, const LEX_CSTRING *alias_arg, enum thr_lock_type lock_type_arg, prelocking_types prelocking_type, TABLE_LIST *belong_to_view_arg, uint8 trg_event_map_arg, - TABLE_LIST ***last_ptr, my_bool insert_data, - my_bool override_fk_ignore_table= FALSE) + TABLE_LIST ***last_ptr, my_bool insert_data) { init_one_table(db_arg, table_name_arg, alias_arg, lock_type_arg); cacheable_table= 1; @@ -2395,8 +2394,7 @@ struct TABLE_LIST belong_to_view= belong_to_view_arg; trg_event_map= trg_event_map_arg; /* MDL is enough for read-only FK checks, we don't need the table */ - if (prelocking_type == PRELOCK_FK && lock_type < TL_FIRST_WRITE && - !override_fk_ignore_table) + if (prelocking_type == PRELOCK_FK && lock_type < TL_FIRST_WRITE) open_strategy= OPEN_STUB; **last_ptr= this; diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index a5840875ff73a..bb6e491feddf2 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -4127,7 +4127,7 @@ bool wsrep_foreign_key_append(THD *thd, FOREIGN_KEY_INFO *fk) if (WSREP(thd) && !thd->wsrep_applier && wsrep_is_active(thd) && (sql_command_flags[thd->lex->sql_command] & - (CF_UPDATES_DATA | CF_DELETES_DATA | CF_INSERTS_DATA))) + (CF_UPDATES_DATA | CF_DELETES_DATA))) { wsrep::key key(wsrep::key::shared); key.append_key_part(fk->foreign_db->str, fk->foreign_db->length);