summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/suite/galera/r/MW-402.result200
-rw-r--r--mysql-test/suite/galera/t/MW-402.test180
-rw-r--r--mysql-test/suite/innodb/t/log_data_file_size.test18
-rw-r--r--sql/wsrep_hton.cc1
-rw-r--r--storage/innobase/row/row0ins.cc3
-rw-r--r--storage/innobase/row/row0upd.cc26
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: