From 90f222ea7dea4bebdb3ad93c4c1439e3ab08bbba Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Mon, 27 Jun 2016 18:21:00 -0400 Subject: [PATCH] MDEV-10235: Deadlock in CREATE TABLE .. AS SELECT .. if result set is empty in Galera In CTAS, handlers get registered under statement transaction (st_transactions::stmt), while ha_fake_trx_id(), used by CTAS, looked under standard transaction (st_transactions::all) for registered handlers, and thus it failed to grab a fake transaction ID. As a result, with no valid transaction ID, wsrep commit failed with an error. ha_fake_trx_id() now looks for handlers registered under 'stmt' in case 'all' is empty. Also modified the logic to print warning only once if none of the registered handlers have fake_trx_id. --- mysql-test/suite/galera/r/create.result | 13 +++++++++ mysql-test/suite/galera/suite.pm | 1 - mysql-test/suite/galera/t/create.test | 16 +++++++++++ mysql-test/suite/wsrep/r/binlog_format.result | 2 +- mysql-test/suite/wsrep/t/binlog_format.test | 2 +- sql/handler.cc | 27 +++++++++++++++---- 6 files changed, 53 insertions(+), 8 deletions(-) diff --git a/mysql-test/suite/galera/r/create.result b/mysql-test/suite/galera/r/create.result index d23fb186f5e..99b8022393d 100644 --- a/mysql-test/suite/galera/r/create.result +++ b/mysql-test/suite/galera/r/create.result @@ -68,4 +68,17 @@ CREATE TABLE `t2` (`c1` INT) ENGINE=INNODB SELECT * FROM t1; COMMIT; SET autocommit=1; DROP TABLE t1, t2; +# +# MDEV-10235: Deadlock in CREATE TABLE ... AS SELECT .. if result set +# is empty in Galera +# +CREATE TABLE t1(c1 INT) ENGINE=INNODB; +INSERT INTO t1 VALUES(1); +CREATE TABLE t2 AS SELECT * FROM t1 WHERE c1=2; +SELECT * FROM t1; +c1 +1 +SELECT * FROM t2; +c1 +DROP TABLE t1, t2; # End of tests diff --git a/mysql-test/suite/galera/suite.pm b/mysql-test/suite/galera/suite.pm index b3795b91666..2da2b3ad503 100644 --- a/mysql-test/suite/galera/suite.pm +++ b/mysql-test/suite/galera/suite.pm @@ -67,7 +67,6 @@ push @::global_suppressions, qr|WSREP: gcs_caused\(\) returned .*|, qr|WSREP: Protocol violation. JOIN message sender .* is not in state transfer \(SYNCED\). Message ignored.|, qr(WSREP: Action message in non-primary configuration from member [0-9]*), - qr(WSREP: cannot get fake InnoDB transaction ID), ); diff --git a/mysql-test/suite/galera/t/create.test b/mysql-test/suite/galera/t/create.test index 9d0ab215cbb..96a6640c21f 100644 --- a/mysql-test/suite/galera/t/create.test +++ b/mysql-test/suite/galera/t/create.test @@ -68,6 +68,22 @@ SET autocommit=1; # Cleanup DROP TABLE t1, t2; + +--echo # +--echo # MDEV-10235: Deadlock in CREATE TABLE ... AS SELECT .. if result set +--echo # is empty in Galera +--echo # +--connection node_1 +CREATE TABLE t1(c1 INT) ENGINE=INNODB; +INSERT INTO t1 VALUES(1); +CREATE TABLE t2 AS SELECT * FROM t1 WHERE c1=2; + +--connection node_2 +SELECT * FROM t1; +SELECT * FROM t2; +# Cleanup +DROP TABLE t1, t2; + --source include/galera_end.inc --echo # End of tests diff --git a/mysql-test/suite/wsrep/r/binlog_format.result b/mysql-test/suite/wsrep/r/binlog_format.result index d996371c056..1ca90bd626d 100644 --- a/mysql-test/suite/wsrep/r/binlog_format.result +++ b/mysql-test/suite/wsrep/r/binlog_format.result @@ -1,5 +1,5 @@ call mtr.add_suppression("WSREP: MariaDB Galera does not support binlog format.*"); -call mtr.add_suppression("WSREP: cannot get fake InnoDB transaction ID"); +call mtr.add_suppression("WSREP: Cannot get fake transaction ID from storage engine."); # # MDEV-4227: Galera server should stop crashing on setting binlog_format STATEMENT # diff --git a/mysql-test/suite/wsrep/t/binlog_format.test b/mysql-test/suite/wsrep/t/binlog_format.test index a2dc8542322..85864256862 100644 --- a/mysql-test/suite/wsrep/t/binlog_format.test +++ b/mysql-test/suite/wsrep/t/binlog_format.test @@ -2,7 +2,7 @@ --source include/have_binlog_format_row.inc call mtr.add_suppression("WSREP: MariaDB Galera does not support binlog format.*"); -call mtr.add_suppression("WSREP: cannot get fake InnoDB transaction ID"); +call mtr.add_suppression("WSREP: Cannot get fake transaction ID from storage engine."); --echo # --echo # MDEV-4227: Galera server should stop crashing on setting binlog_format STATEMENT diff --git a/sql/handler.cc b/sql/handler.cc index 49e451e3836..147221abb97 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6104,25 +6104,42 @@ int ha_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal) void ha_fake_trx_id(THD *thd) { DBUG_ENTER("ha_fake_trx_id"); + + bool no_fake_trx_id= true; + if (!WSREP(thd)) { DBUG_VOID_RETURN; } - THD_TRANS *trans= &thd->transaction.all; + /* Try statement transaction if standard one is not set. */ + THD_TRANS *trans= (thd->transaction.all.ha_list) ? &thd->transaction.all : + &thd->transaction.stmt; + Ha_trx_info *ha_info= trans->ha_list, *ha_info_next; for (; ha_info; ha_info= ha_info_next) { handlerton *hton= ha_info->ht(); - if (!hton->fake_trx_id) + if (hton->fake_trx_id) { - WSREP_WARN("cannot get fake InnoDB transaction ID"); - } - else hton->fake_trx_id(hton, thd); + + /* Got a fake trx id. */ + no_fake_trx_id= false; + + /* + We need transaction ID from just one storage engine providing + fake_trx_id (which will most likely be the case). + */ + break; + } ha_info_next= ha_info->next(); } + + if (unlikely(no_fake_trx_id)) + WSREP_WARN("Cannot get fake transaction ID from storage engine."); + DBUG_VOID_RETURN; } #endif /* WITH_WSREP */