[Commits] Rev 4615: MDEV-7458: Deadlock in parallel replication can allow following transaction to start replicating too early in http://bazaar.launchpad.net/~maria-captains/maria/10.0

knielsen at knielsen-hq.org knielsen at knielsen-hq.org
Fri Feb 20 15:17:51 EET 2015


At http://bazaar.launchpad.net/~maria-captains/maria/10.0

------------------------------------------------------------
revno: 4615
revision-id: knielsen at knielsen-hq.org-20150220131750-jzisvqbbhd8l1izu
parent: knielsen at knielsen-hq.org-20150220131711-k66nzlpzsrm4wq48
committer: Kristian Nielsen <knielsen at knielsen-hq.org>
branch nick: work-10.0
timestamp: Fri 2015-02-20 14:17:50 +0100
message:
  MDEV-7458: Deadlock in parallel replication can allow following transaction to start replicating too early
  
  In parallel replication, don't rollback inside ha_commit_trans() in case of
  error.
  
  The rollback will be done later, but the parallel replication code needs to
  run unmark_start_commit() before the rollback to properly control the
  sequencing of transactions.
  
  I did not manage to come up with a reliable automatic test case for this, but
  I tested it manually.
=== modified file 'mysql-test/suite/rpl/t/rpl_parallel.test'
--- a/mysql-test/suite/rpl/t/rpl_parallel.test	2015-01-07 13:45:39 +0000
+++ b/mysql-test/suite/rpl/t/rpl_parallel.test	2015-02-20 13:17:50 +0000
@@ -1843,6 +1843,84 @@ SET GLOBAL slave_parallel_threads=10;
 --source include/start_slave.inc
 
 
+--echo *** MDEV-7458: Deadlock in parallel replication can allow following transaction to start replicating too early ***
+
+--connection server_1
+INSERT INTO t2 VALUES (201);
+SET sql_log_bin=0;
+--delimiter ||
+CREATE FUNCTION f1(x INT) RETURNS INT DETERMINISTIC
+BEGIN
+  RETURN x;
+END
+||
+--delimiter ;
+SET sql_log_bin=1;
+--save_master_pos
+
+--connection server_2
+SET sql_log_bin=0;
+--delimiter ||
+CREATE FUNCTION f1(x INT) RETURNS INT DETERMINISTIC
+BEGIN
+  IF x=1 THEN
+    SET @a = SLEEP(0.4);
+  ELSEIF x=2 THEN
+    SET @a = SLEEP(0.2);
+  END IF;
+  INSERT INTO t2 VALUES (204);
+  DELETE FROM t2 WHERE a=204;
+  UPDATE t2 SET a=a+1 WHERE a=200+x;
+  RETURN x;
+END
+||
+--delimiter ;
+SET sql_log_bin=1;
+--sync_with_master
+
+--connection con_temp3
+SET @old_format= @@SESSION.binlog_format;
+SET binlog_format= STATEMENT;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued1 WAIT_FOR master_cont1';
+send INSERT INTO t3 VALUES (201, f1(1));
+
+--connection server_1
+SET debug_sync='now WAIT_FOR master_queued1';
+
+--connection con_temp4
+SET @old_format= @@SESSION.binlog_format;
+SET binlog_format= STATEMENT;
+SET debug_sync='commit_after_release_LOCK_prepare_ordered SIGNAL master_queued2';
+send INSERT INTO t3 VALUES (202, f1(2));
+
+--connection server_1
+SET debug_sync='now WAIT_FOR master_queued2';
+SET debug_sync='now SIGNAL master_cont1';
+
+--connection con_temp3
+REAP;
+SET BINLOG_FORMAT= @old_format;
+--connection con_temp4
+REAP;
+SET BINLOG_FORMAT= @old_format;
+
+--connection server_1
+SET @old_format= @@SESSION.binlog_format;
+SET binlog_format= STATEMENT;
+INSERT INTO t2 VALUES (202);
+SET BINLOG_FORMAT= @old_format;
+
+SHOW BINARY LOGS;
+SHOW BINLOG EVENTS IN 'master-bin.000005';
+SELECT * FROM t2 WHERE a >= 200 ORDER BY a;
+SELECT * FROM t3 WHERE a >= 200 ORDER BY a;
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+SELECT * FROM t2 WHERE a >= 200 ORDER BY a;
+SELECT * FROM t3 WHERE a >= 200 ORDER BY a;
+
 # Clean up.
 --connection server_2
 --source include/stop_slave.inc
@@ -1852,6 +1930,7 @@ SET DEBUG_SYNC= 'RESET';
 
 --connection server_1
 DROP function foo;
+DROP function f1;
 DROP TABLE t1,t2,t3,t4,t5,t6;
 SET DEBUG_SYNC= 'RESET';
 

=== modified file 'sql/handler.cc'
--- a/sql/handler.cc	2015-01-21 11:03:02 +0000
+++ b/sql/handler.cc	2015-02-20 13:17:50 +0000
@@ -1445,7 +1445,13 @@ int ha_commit_trans(THD *thd, bool all)
   /* Come here if error and we need to rollback. */
 err:
   error= 1;                                  /* Transaction was rolled back */
-  ha_rollback_trans(thd, all);
+  /*
+    In parallel replication, rollback is delayed, as there is extra replication
+    book-keeping to be done before rolling back and allowing a conflicting
+    transaction to continue (MDEV-7458).
+  */
+  if (!(thd->rgi_slave && thd->rgi_slave->is_parallel_exec))
+    ha_rollback_trans(thd, all);
 
 end:
   if (rw_trans && mdl_request.ticket)



More information about the commits mailing list