diff options
author | sjaakola <seppo.jaakola@iki.fi> | 2021-01-14 18:18:06 +0200 |
---|---|---|
committer | Jan Lindström <jan.lindstrom@mariadb.com> | 2021-01-20 08:11:13 +0200 |
commit | 9377e9ba0c8c2b6a89d47e545eb292a6973ad2fb (patch) | |
tree | 8c006c284262be3e47ca13b545a59453d7f01bae | |
parent | 8bcddb02b7ba9399677e866a01d86279047beae1 (diff) | |
download | mariadb-git-9377e9ba0c8c2b6a89d47e545eb292a6973ad2fb.tar.gz |
MDEV-21153 Replica nodes crash due to indexed virtual columns and FK cascading delete
Fix for MDEV-23033 fixes a problem in replication applying of transactions, which contain cascading foreign key delete for a table, which has indexed virtual column.
This fix adds slave_fk_event_map flag for table, to mark when the prelocking is needed for applying of a transaction.
See commit 608b0ee52ef3e854ce14a407e64e936adbbeba23 for more details.
However, this fix is targeted for async replication only, Rows_log_event::do_apply_event() has condition to rule out galera replication from the fix domain, and use cases suffering from MDEV-23033 and related MDEV-21153 will fail in galera cluster.
The fix in this commit removes the condition to rule out the setting of slave_fk_event_map flag from galera replication, and makes the fix in MDEV-23033 effective for galera replication as well.
However, the above fix has caused regressions for some galera_sr suite tests, which run tests for streaming replication.
This regression can be observed e.g. by: /mtr galera_sr.galera_sr_multirow_rollback --mysqld=--slave_run_triggers_for_rbr=yes
These galera_sr suite tests were failing in last phase of replication applying, where actual transaction is already applied, and streaming replication related meta data needs to be updated in wsrep system tables.
Opening the wsrep system tables failed for corrupt data in THD::lex:query_tables_list. The fix in this commit uses back query table list for the duration of fragment update operation.
Finally, a mtr test for virtual column support has been added. galera.galera_virtual_column.test has as first test a scenario from MDEV-21153
new fix
Reviewed-by: Jan Lindström <jan.lindstrom@mariadb.com>
-rw-r--r-- | mysql-test/suite/galera/r/galera_virtual_column.result | 19 | ||||
-rw-r--r-- | mysql-test/suite/galera/t/galera_virtual_column.test | 42 | ||||
-rw-r--r-- | sql/log_event.cc | 2 | ||||
-rw-r--r-- | sql/wsrep_schema.cc | 21 |
4 files changed, 83 insertions, 1 deletions
diff --git a/mysql-test/suite/galera/r/galera_virtual_column.result b/mysql-test/suite/galera/r/galera_virtual_column.result new file mode 100644 index 00000000000..71820ed8225 --- /dev/null +++ b/mysql-test/suite/galera/r/galera_virtual_column.result @@ -0,0 +1,19 @@ +connection node_2; +connection node_1; +connection node_1; +CREATE TABLE p (id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT) ENGINE = InnoDB; +CREATE TABLE c (id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, pid INT UNSIGNED, bitmap TINYINT UNSIGNED NOT NULL DEFAULT 0, bitmap5 TINYINT UNSIGNED GENERATED ALWAYS AS (bitmap&(1<<5)) VIRTUAL, FOREIGN KEY (pid) REFERENCES p (id) ON DELETE CASCADE ON UPDATE CASCADE); +CREATE INDEX bitmap5 ON c(bitmap5) USING BTREE; +INSERT INTO p VALUES(1); +INSERT INTO c(pid) VALUES(1); +connection node_2; +connection node_1; +DELETE FROM p WHERE id=1; +SELECT * FROM p; +id +SELECT * FROM c; +id pid bitmap bitmap5 +connection node_2; +connection node_1; +DROP TABLE c; +DROP TABLE p; diff --git a/mysql-test/suite/galera/t/galera_virtual_column.test b/mysql-test/suite/galera/t/galera_virtual_column.test new file mode 100644 index 00000000000..84e1da024f1 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_virtual_column.test @@ -0,0 +1,42 @@ +# +# This test is for testing virtual columnm support in galera cluster +# +--source include/galera_cluster.inc +--source include/have_innodb.inc + +# +# test case for verifying that cascaded delete in a table with virtual column does not crash slave node +# + +--connection node_1 + +CREATE TABLE p (id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT) ENGINE = InnoDB; +CREATE TABLE c (id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, pid INT UNSIGNED, bitmap TINYINT UNSIGNED NOT NULL DEFAULT 0, bitmap5 TINYINT UNSIGNED GENERATED ALWAYS AS (bitmap&(1<<5)) VIRTUAL, FOREIGN KEY (pid) REFERENCES p (id) ON DELETE CASCADE ON UPDATE CASCADE); + +# not sure of this index is needed for the test +CREATE INDEX bitmap5 ON c(bitmap5) USING BTREE; + +INSERT INTO p VALUES(1); +INSERT INTO c(pid) VALUES(1); + + +--connection node_2 +# wait until both INSERTS have arrived in node_2 +--let $wait_condition = SELECT COUNT(*) = 1 FROM c +--source include/wait_condition.inc + +--connection node_1 +# delete from parent table, it will cascade into child table +# node_2 might have problem in applying this cascaded delete +DELETE FROM p WHERE id=1; + +SELECT * FROM p; +SELECT * FROM c; + +--connection node_2 +--let $wait_condition = SELECT COUNT(*) = 0 FROM c; +--source include/wait_condition.inc + +--connection node_1 +DROP TABLE c; +DROP TABLE p; diff --git a/sql/log_event.cc b/sql/log_event.cc index e3079c5f9b9..20a41dc8aee 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -11392,7 +11392,7 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi) tables->trg_event_map= new_trg_event_map; lex->query_tables_last= &tables->next_global; } - else if (!WSREP_ON) + else { tables->slave_fk_event_map= new_trg_event_map; lex->query_tables_last= &tables->next_global; diff --git a/sql/wsrep_schema.cc b/sql/wsrep_schema.cc index 8a47bbec9b0..9a09fbc8902 100644 --- a/sql/wsrep_schema.cc +++ b/sql/wsrep_schema.cc @@ -899,6 +899,13 @@ int Wsrep_schema::append_fragment(THD* thd, thd->thread_id, os.str().c_str(), transaction_id.get()); + /* use private query table list for the duration of fragment storing, + populated query table list from "parent DML" may cause problems .e.g + for virtual column handling + */ + Query_tables_list query_tables_list_backup; + thd->lex->reset_n_backup_query_tables_list(&query_tables_list_backup); + Wsrep_schema_impl::binlog_off binlog_off(thd); Wsrep_schema_impl::init_stmt(thd); @@ -906,6 +913,7 @@ int Wsrep_schema::append_fragment(THD* thd, if (Wsrep_schema_impl::open_for_write(thd, sr_table_str.c_str(), &frag_table)) { trans_rollback_stmt(thd); + thd->lex->restore_backup_query_tables_list(&query_tables_list_backup); DBUG_RETURN(1); } @@ -919,9 +927,11 @@ int Wsrep_schema::append_fragment(THD* thd, if ((error= Wsrep_schema_impl::insert(frag_table))) { WSREP_ERROR("Failed to write to frag table: %d", error); trans_rollback_stmt(thd); + thd->lex->restore_backup_query_tables_list(&query_tables_list_backup); DBUG_RETURN(1); } Wsrep_schema_impl::finish_stmt(thd); + thd->lex->restore_backup_query_tables_list(&query_tables_list_backup); DBUG_RETURN(0); } @@ -938,6 +948,13 @@ int Wsrep_schema::update_fragment_meta(THD* thd, ws_meta.seqno().get()); DBUG_ASSERT(ws_meta.seqno().is_undefined() == false); + /* use private query table list for the duration of fragment storing, + populated query table list from "parent DML" may cause problems .e.g + for virtual column handling + */ + Query_tables_list query_tables_list_backup; + thd->lex->reset_n_backup_query_tables_list(&query_tables_list_backup); + Wsrep_schema_impl::binlog_off binlog_off(thd); int error; uchar key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; @@ -947,6 +964,7 @@ int Wsrep_schema::update_fragment_meta(THD* thd, Wsrep_schema_impl::init_stmt(thd); if (Wsrep_schema_impl::open_for_write(thd, sr_table_str.c_str(), &frag_table)) { + thd->lex->restore_backup_query_tables_list(&query_tables_list_backup); DBUG_RETURN(1); } @@ -967,6 +985,7 @@ int Wsrep_schema::update_fragment_meta(THD* thd, error); } Wsrep_schema_impl::finish_stmt(thd); + thd->lex->restore_backup_query_tables_list(&query_tables_list_backup); DBUG_RETURN(1); } @@ -982,11 +1001,13 @@ int Wsrep_schema::update_fragment_meta(THD* thd, frag_table->s->table_name.str, error); Wsrep_schema_impl::finish_stmt(thd); + thd->lex->restore_backup_query_tables_list(&query_tables_list_backup); DBUG_RETURN(1); } int ret= Wsrep_schema_impl::end_index_scan(frag_table); Wsrep_schema_impl::finish_stmt(thd); + thd->lex->restore_backup_query_tables_list(&query_tables_list_backup); DBUG_RETURN(ret); } |