diff options
-rw-r--r-- | mysql-test/suite/galera/r/MW-402.result | 200 | ||||
-rw-r--r-- | mysql-test/suite/galera/t/MW-402.test | 180 | ||||
-rw-r--r-- | mysql-test/suite/innodb/t/log_data_file_size.test | 18 | ||||
-rw-r--r-- | sql/wsrep_hton.cc | 1 | ||||
-rw-r--r-- | storage/innobase/row/row0ins.cc | 3 | ||||
-rw-r--r-- | storage/innobase/row/row0upd.cc | 26 |
6 files changed, 411 insertions, 17 deletions
diff --git a/mysql-test/suite/galera/r/MW-402.result b/mysql-test/suite/galera/r/MW-402.result new file mode 100644 index 00000000000..9be98d629fb --- /dev/null +++ b/mysql-test/suite/galera/r/MW-402.result @@ -0,0 +1,200 @@ +connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1; +connection node_1; +CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB; +CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER, f2 INTEGER, +CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1) ON DELETE CASCADE); +INSERT INTO p VALUES (1, 0); +INSERT INTO p VALUES (2, 0); +INSERT INTO c VALUES (1, 1, 0); +connection node_1a; +connection node_1; +SET AUTOCOMMIT=ON; +START TRANSACTION; +UPDATE c SET f2=1 where f1=1; +connection node_1a; +SET SESSION wsrep_sync_wait = 0; +SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; +connection node_2; +DELETE FROM p WHERE f1 = 1; +connection node_1a; +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync'; +connection node_1; +COMMIT; +connection node_1a; +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; +SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync'; +SET GLOBAL wsrep_provider_options = 'dbug='; +connection node_1; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +connection node_2; +SELECT * FROM p; +f1 f2 +2 0 +SELECT * FROM c; +f1 p_id f2 +DROP TABLE c; +DROP TABLE p; +connection node_1; +CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB; +CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER, f2 INTEGER, +CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1) ON UPDATE CASCADE); +INSERT INTO p VALUES (1, 0); +INSERT INTO p VALUES (2, 0); +INSERT INTO c VALUES (1, 1, 0); +connection node_1a; +connection node_1; +SET AUTOCOMMIT=ON; +START TRANSACTION; +UPDATE c SET f2=2 where f1=1; +connection node_1a; +SET SESSION wsrep_sync_wait = 0; +SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; +connection node_2; +UPDATE p set f1=11 WHERE f1 = 1; +connection node_1a; +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync'; +connection node_1; +COMMIT; +connection node_1a; +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; +SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync'; +SET GLOBAL wsrep_provider_options = 'dbug='; +connection node_1; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +connection node_2; +SELECT * FROM p; +f1 f2 +2 0 +11 0 +SELECT * FROM c; +f1 p_id f2 +1 11 0 +DROP TABLE c; +DROP TABLE p; +connection node_1; +CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB; +CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER, f2 INTEGER, +CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1) ON UPDATE CASCADE); +INSERT INTO p VALUES (1, 0); +INSERT INTO p VALUES (2, 0); +INSERT INTO c VALUES (1, 1, 0); +connection node_1a; +connection node_1; +SET AUTOCOMMIT=ON; +START TRANSACTION; +UPDATE c SET p_id=2 where f1=1; +connection node_1a; +SET SESSION wsrep_sync_wait = 0; +SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; +connection node_2; +UPDATE p set f1=11 WHERE f1 = 1; +connection node_1a; +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync'; +connection node_1; +COMMIT; +connection node_1a; +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; +SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync'; +SET GLOBAL wsrep_provider_options = 'dbug='; +connection node_1; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +connection node_2; +SELECT * FROM p; +f1 f2 +2 0 +11 0 +SELECT * FROM c; +f1 p_id f2 +1 11 0 +connection node_1a; +connection node_1; +SET AUTOCOMMIT=ON; +START TRANSACTION; +UPDATE p set f1=21 WHERE f1 = 11; +connection node_1a; +SET SESSION wsrep_sync_wait = 0; +SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; +connection node_2; +UPDATE c SET p_id=2 where f1=1; +connection node_1a; +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync'; +connection node_1; +COMMIT; +connection node_1a; +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; +SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync'; +SET GLOBAL wsrep_provider_options = 'dbug='; +connection node_1; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +connection node_2; +SELECT * FROM p; +f1 f2 +2 0 +11 0 +SELECT * FROM c; +f1 p_id f2 +1 2 0 +DROP TABLE c; +DROP TABLE p; +connection node_1; +CREATE TABLE p1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB; +CREATE TABLE p2 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB; +CREATE TABLE c (f1 INTEGER PRIMARY KEY, p1_id INTEGER, p2_id INTEGER, f2 INTEGER, +CONSTRAINT fk_1 FOREIGN KEY (p1_id) REFERENCES p1 (f1) ON DELETE CASCADE, +CONSTRAINT fk_2 FOREIGN KEY (p2_id) REFERENCES p2 (f1)); +INSERT INTO p1 VALUES (1, 0); +INSERT INTO p2 VALUES (1, 0); +INSERT INTO c VALUES (1, 1, 1, 0); +connection node_1a; +connection node_1; +SET AUTOCOMMIT=ON; +START TRANSACTION; +UPDATE p2 SET f2=2 where f1=1; +connection node_1a; +SET SESSION wsrep_sync_wait = 0; +SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; +connection node_2; +DELETE FROM p1 WHERE f1 = 1; +connection node_1a; +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +SET GLOBAL wsrep_provider_options = 'dbug=d,local_monitor_enter_sync'; +connection node_1; +COMMIT; +connection node_1a; +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; +SET GLOBAL wsrep_provider_options = 'signal=local_monitor_enter_sync'; +SET GLOBAL wsrep_provider_options = 'dbug='; +connection node_1; +connection node_2; +SELECT * FROM p1; +f1 f2 +SELECT * FROM p2; +f1 f2 +1 2 +SELECT * FROM c; +f1 p1_id p2_id f2 +DROP TABLE c,p1,p2; diff --git a/mysql-test/suite/galera/t/MW-402.test b/mysql-test/suite/galera/t/MW-402.test new file mode 100644 index 00000000000..36b691c6295 --- /dev/null +++ b/mysql-test/suite/galera/t/MW-402.test @@ -0,0 +1,180 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc +--source suite/galera/include/galera_have_debug_sync.inc + +# +# we must open connection node_1a here, MW-369.inc will use it later +# +--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1 + +# +# cascading delete operation is replicated from node2 +# and this conflicts with an update for child table in node1 +# +# As a result, the update should fail for certification error +# +--connection node_1 + +CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB; +CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER, f2 INTEGER, + CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1) ON DELETE CASCADE); + +INSERT INTO p VALUES (1, 0); +INSERT INTO p VALUES (2, 0); + +INSERT INTO c VALUES (1, 1, 0); + +--let $mw_369_parent_query = UPDATE c SET f2=1 where f1=1 +--let $mw_369_child_query = DELETE FROM p WHERE f1 = 1 + +--connection node_1a +--source MW-369.inc + +# Commit fails +--connection node_1 +--error ER_LOCK_DEADLOCK +--reap + +--connection node_2 +SELECT * FROM p; +SELECT * FROM c; + +DROP TABLE c; +DROP TABLE p; + +# +# cascading update operation is replicated from node2 +# and this conflicts with an update for child table in node1 +# +# As a result, the update should fail for certification error +# +--connection node_1 + +CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB; +CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER, f2 INTEGER, + CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1) ON UPDATE CASCADE); + + +INSERT INTO p VALUES (1, 0); +INSERT INTO p VALUES (2, 0); + +INSERT INTO c VALUES (1, 1, 0); + +--let $mw_369_parent_query = UPDATE c SET f2=2 where f1=1 +--let $mw_369_child_query = UPDATE p set f1=11 WHERE f1 = 1 + +--connection node_1a +--source MW-369.inc + +# Commit fails +--connection node_1 +--error ER_LOCK_DEADLOCK +--reap + +--connection node_2 +SELECT * FROM p; +SELECT * FROM c; + +DROP TABLE c; +DROP TABLE p; + +# +# ON UPDATE CASCADE tests +# Here we update primary key of parent table to cause cascaded update +# on child table +# +# cascading update operation is replicated from node2 +# and this conflicts with an update for child table in node1 +# +# As a result, the update should fail for certification error +# +--connection node_1 + +CREATE TABLE p (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB; +CREATE TABLE c (f1 INTEGER PRIMARY KEY, p_id INTEGER, f2 INTEGER, + CONSTRAINT fk_1 FOREIGN KEY (p_id) REFERENCES p (f1) ON UPDATE CASCADE); + + +INSERT INTO p VALUES (1, 0); +INSERT INTO p VALUES (2, 0); + +INSERT INTO c VALUES (1, 1, 0); + +--let $mw_369_parent_query = UPDATE c SET p_id=2 where f1=1 +--let $mw_369_child_query = UPDATE p set f1=11 WHERE f1 = 1 + +--connection node_1a +--source MW-369.inc + +# Commit fails +--connection node_1 +--error ER_LOCK_DEADLOCK +--reap + +# same as previous, but statements in different order +--connection node_2 +SELECT * FROM p; +SELECT * FROM c; + +--let $mw_369_parent_query = UPDATE p set f1=21 WHERE f1 = 11 +--let $mw_369_child_query = UPDATE c SET p_id=2 where f1=1 + +--connection node_1a +--source MW-369.inc + +# Commit fails +--connection node_1 +--error ER_LOCK_DEADLOCK +--reap + + +--connection node_2 +SELECT * FROM p; +SELECT * FROM c; + +DROP TABLE c; +DROP TABLE p; + + +# +# CASCADE DELETE tests with two parent tables +# Here we cause cascaded operation on child table through +# one parent table and have other operation on the other +# parent table +# +# cascading update operation is replicated from node2 +# but this does not conflict with an update for the other parent table in node1 +# +# As a result, the update on p2 should succeed +# +--connection node_1 + +CREATE TABLE p1 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB; +CREATE TABLE p2 (f1 INTEGER PRIMARY KEY, f2 INTEGER) ENGINE=INNODB; +CREATE TABLE c (f1 INTEGER PRIMARY KEY, p1_id INTEGER, p2_id INTEGER, f2 INTEGER, + CONSTRAINT fk_1 FOREIGN KEY (p1_id) REFERENCES p1 (f1) ON DELETE CASCADE, + CONSTRAINT fk_2 FOREIGN KEY (p2_id) REFERENCES p2 (f1)); + + +INSERT INTO p1 VALUES (1, 0); +INSERT INTO p2 VALUES (1, 0); + +INSERT INTO c VALUES (1, 1, 1, 0); + +--let $mw_369_parent_query = UPDATE p2 SET f2=2 where f1=1 +--let $mw_369_child_query = DELETE FROM p1 WHERE f1 = 1 + +--connection node_1a +--source MW-369.inc + +# Commit succeeds +--connection node_1 +--reap + +# same as previous, but statements in different order +--connection node_2 +SELECT * FROM p1; +SELECT * FROM p2; +SELECT * FROM c; + +DROP TABLE c,p1,p2; diff --git a/mysql-test/suite/innodb/t/log_data_file_size.test b/mysql-test/suite/innodb/t/log_data_file_size.test index 8a0e88efc76..7928fc45520 100644 --- a/mysql-test/suite/innodb/t/log_data_file_size.test +++ b/mysql-test/suite/innodb/t/log_data_file_size.test @@ -23,13 +23,13 @@ use Fcntl 'SEEK_CUR', 'SEEK_END'; my $page_size = $ENV{'INNODB_PAGE_SIZE'}; my $restart; +open(FILE, "+<", "$ENV{'MYSQLD_DATADIR'}ibdata1") or die; if ($ENV{'MYSQLD_IS_DEBUG'}) { # It is impractical to ensure that CREATE TABLE t will extend ibdata1. # We rely on innodb_system_tablespace_extend_debug=1 # to recover from this fault injection if no size change was redo-logged. my $root = $ENV{'INNODB_ROOT_PAGE'}; - open(FILE, "+<", "$ENV{'MYSQLD_DATADIR'}ibdata1") or die; my $size = sysseek(FILE, 0, SEEK_END) / $page_size; seek(FILE, $page_size * ($root + 1), SEEK_SET) or die; my $empty_tail= 1; @@ -39,8 +39,22 @@ if ($ENV{'MYSQLD_IS_DEBUG'}) $restart = "--innodb-data-file-size-debug=$size"; truncate(FILE, $page_size * $root); } - close FILE; } +# Clear the doublewrite buffer entries for our tables. +sysseek(FILE, 6 * $page_size - 190, 0)||die "Unable to seek ibdata1\n"; +sysread(FILE, $_, 12) == 12||die "Unable to read TRX_SYS\n"; +my($magic,$d1,$d2)=unpack "NNN", $_; +die "magic=$magic, $d1, $d2\n" unless $magic == 536853855 && $d2 >= $d1 + 64; +sysseek(FILE, $d1 * $page_size, 0)||die "Unable to seek ibdata1\n"; +# Find the pages in the doublewrite buffer +for (my $d = $d1; $d < $d2 + 64; $d++) { + sysread(FILE, $_, $page_size)==$page_size||die "Cannot read doublewrite\n"; + my($space_id,$offset)=unpack "x[4]Nx[26]N",$_; + next unless $space_id && $offset > 3; + sysseek(FILE, $d * $page_size, 0)||die "Unable to seek ibdata1\n"; + syswrite(FILE, chr(0) x $page_size)==$page_size||die; +} +close FILE; open(FILE, ">$ENV{MYSQLTEST_VARDIR}/log/start_mysqld.txt") || die; print FILE "--let \$restart_parameters=$restart\n" if $restart; print FILE "--source include/start_mysqld.inc\n"; diff --git a/sql/wsrep_hton.cc b/sql/wsrep_hton.cc index 1063b82fb8a..d047c3580ef 100644 --- a/sql/wsrep_hton.cc +++ b/sql/wsrep_hton.cc @@ -539,6 +539,7 @@ wsrep_run_wsrep_commit(THD *thd, bool all) break; case WSREP_BF_ABORT: DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno != WSREP_SEQNO_UNDEFINED); + /* fall through */ case WSREP_TRX_FAIL: WSREP_DEBUG("commit failed for reason: %d", rcode); DBUG_PRINT("wsrep", ("replicating commit fail")); diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index b5b2a703c2b..b7f28e633a3 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -1442,8 +1442,7 @@ row_ins_foreign_check_on_constraint( foreign, clust_rec, clust_index, - FALSE, - (node) ? TRUE : FALSE); + FALSE, FALSE); if (err != DB_SUCCESS) { fprintf(stderr, "WSREP: foreign key append failed: %d\n", err); diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index 76fd0e75427..6a76de39dca 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -460,19 +460,18 @@ func_exit: @param[in] node query node @param[in] trx transaction @return whether the node cannot be ignored */ -static +inline bool wsrep_must_process_fk(const upd_node_t* node, const trx_t* trx) { - if (que_node_get_type(node->common.parent) != QUE_NODE_UPDATE - || !wsrep_on(trx->mysql_thd)) { + if (que_node_get_type(node->common.parent) != QUE_NODE_UPDATE || + !wsrep_on(trx->mysql_thd)) { return false; } - const upd_cascade_t& nodes = *static_cast<const upd_node_t*>( - node->common.parent)->cascade_upd_nodes; - const upd_cascade_t::const_iterator end = nodes.end(); - return std::find(nodes.begin(), end, node) == end; + const upd_node_t* parent = static_cast<const upd_node_t*>(node->common.parent); + + return parent->cascade_upd_nodes->empty(); } #endif /* WITH_WSREP */ @@ -2443,6 +2442,7 @@ row_upd_sec_index_entry( if (!referenced && foreign && wsrep_must_process_fk(node, trx) && !wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + ulint* offsets = rec_get_offsets( rec, index, NULL, ULINT_UNDEFINED, &heap); @@ -2749,6 +2749,9 @@ check_fk: } #ifdef WITH_WSREP } else if (foreign && wsrep_must_process_fk(node, trx)) { + err = wsrep_row_upd_check_foreign_constraints( + node, pcur, table, index, offsets, thr, mtr); + switch (err) { case DB_SUCCESS: case DB_NO_REFERENCED_ROW: @@ -2760,16 +2763,11 @@ check_fk: << " index " << index->name << " table " << index->table->name; } - break; + goto err_exit; default: ib::error() << "WSREP: referenced FK check fail: " << ut_strerr(err) << " index " << index->name << " table " << index->table->name; - - break; - } - - if (err != DB_SUCCESS) { goto err_exit; } #endif /* WITH_WSREP */ @@ -2956,6 +2954,7 @@ row_upd_del_mark_clust_rec( dberr_t err; rec_t* rec; trx_t* trx = thr_get_trx(thr); + ut_ad(node); ut_ad(dict_index_is_clust(index)); ut_ad(node->is_delete); @@ -2988,6 +2987,7 @@ row_upd_del_mark_clust_rec( } else if (foreign && wsrep_must_process_fk(node, trx)) { err = wsrep_row_upd_check_foreign_constraints( node, pcur, index->table, index, offsets, thr, mtr); + switch (err) { case DB_SUCCESS: case DB_NO_REFERENCED_ROW: |