From cd8b8bb964c1f1faffecb124ed3030144e658f00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Thu, 18 Jul 2024 10:10:26 +0300 Subject: [PATCH] MDEV-34594 : Assertion `client_state.transaction().active()' failed in int wsrep_thd_append_key(THD*, const wsrep_key*, int, Wsrep_service_key_type) CREATE TABLE [SELECT|REPLACE SELECT] is CTAS and idea was that we force ROW format. However, it was not correctly enforced and keys were appended before wsrep transaction was started. At THD::decide_logging_format we should force used stmt binlog format to ROW in CTAS case and produce a warning if used binlog format was not ROW. At ha_innodb::update_row we should not append keys similarly as in ha_innodb::write_row if sql_command is SQLCOM_CREATE_TABLE. Improved error logging on ::write_row, ::update_row and ::delete_row if wsrep key append fails. Signed-off-by: Julius Goryavsky --- mysql-test/suite/galera/r/MDEV-34594.result | 88 +++++++++++++++++++ mysql-test/suite/galera/t/MDEV-34594.test | 68 ++++++++++++++ mysql-test/suite/wsrep/r/binlog_format.result | 8 ++ sql/sql_class.cc | 18 ++++ storage/innobase/handler/ha_innodb.cc | 24 +++-- 5 files changed, 199 insertions(+), 7 deletions(-) create mode 100644 mysql-test/suite/galera/r/MDEV-34594.result create mode 100644 mysql-test/suite/galera/t/MDEV-34594.test diff --git a/mysql-test/suite/galera/r/MDEV-34594.result b/mysql-test/suite/galera/r/MDEV-34594.result new file mode 100644 index 00000000000..f9caeba8e59 --- /dev/null +++ b/mysql-test/suite/galera/r/MDEV-34594.result @@ -0,0 +1,88 @@ +connection node_2; +connection node_1; +# +# Case 1: test with binlog_format ROW +# +connection node_1; +SET @@binlog_format=ROW; +CREATE TABLE t1 (a INT UNIQUE) SELECT 1 AS a,2 AS b UNION SELECT 2 AS a,3 AS c; +CREATE TABLE t2 (a INT UNIQUE) REPLACE SELECT 1 AS a,2 AS b UNION SELECT 1 AS a,3 AS c; +SELECT * FROM t1; +a b +1 2 +2 3 +SELECT * FROM t2; +a b +1 3 +connection node_2; +SELECT * FROM t1; +a b +1 2 +2 3 +SELECT * FROM t2; +a b +1 3 +DROP TABLE t1,t2; +# +# Case 2: test with binlog_format MIXED +# +connection node_1; +SET @@binlog_format=MIXED; +Warnings: +Warning 1105 MariaDB Galera and flashback do not support binlog format: MIXED +CREATE TABLE t1 (a INT UNIQUE) SELECT 1 AS a,2 AS b UNION SELECT 2 AS a,3 AS c; +Warnings: +Warning 1105 Galera does not support binlog_format = MIXED in CREATE TABLE [SELECT|REPLACE] forcing ROW +Warning 1105 Galera does not support binlog_format = MIXED in CREATE TABLE [SELECT|REPLACE] forcing ROW +CREATE TABLE t2 (a INT UNIQUE) REPLACE SELECT 1 AS a,2 AS b UNION SELECT 1 AS a,3 AS c; +Warnings: +Warning 1105 Galera does not support binlog_format = MIXED in CREATE TABLE [SELECT|REPLACE] forcing ROW +Warning 1105 Galera does not support binlog_format = MIXED in CREATE TABLE [SELECT|REPLACE] forcing ROW +SELECT * FROM t1; +a b +1 2 +2 3 +SELECT * FROM t2; +a b +1 3 +connection node_2; +SELECT * FROM t1; +a b +1 2 +2 3 +SELECT * FROM t2; +a b +1 3 +DROP TABLE t1,t2; +# +# Case 3: test with binlog_format STATEMENT +# +connection node_1; +SET @@binlog_format=STATEMENT; +Warnings: +Warning 1105 MariaDB Galera and flashback do not support binlog format: STATEMENT +CREATE TABLE t1 (a INT UNIQUE) SELECT 1 AS a,2 AS b UNION SELECT 2 AS a,3 AS c; +Warnings: +Warning 1105 Galera does not support binlog_format = MIXED in CREATE TABLE [SELECT|REPLACE] forcing ROW +Warning 1105 Galera does not support binlog_format = MIXED in CREATE TABLE [SELECT|REPLACE] forcing ROW +CREATE TABLE t2 (a INT UNIQUE) REPLACE SELECT 1 AS a,2 AS b UNION SELECT 1 AS a,3 AS c; +Warnings: +Warning 1105 Galera does not support binlog_format = MIXED in CREATE TABLE [SELECT|REPLACE] forcing ROW +Warning 1105 Galera does not support binlog_format = MIXED in CREATE TABLE [SELECT|REPLACE] forcing ROW +SELECT * FROM t1; +a b +1 2 +2 3 +SELECT * FROM t2; +a b +1 3 +connection node_2; +SELECT * FROM t1; +a b +1 2 +2 3 +SELECT * FROM t2; +a b +1 3 +DROP TABLE t1,t2; +connection node_1; diff --git a/mysql-test/suite/galera/t/MDEV-34594.test b/mysql-test/suite/galera/t/MDEV-34594.test new file mode 100644 index 00000000000..256070cf40d --- /dev/null +++ b/mysql-test/suite/galera/t/MDEV-34594.test @@ -0,0 +1,68 @@ +--source include/galera_cluster.inc +--source include/log_bin.inc + +--echo # +--echo # Case 1: test with binlog_format ROW +--echo # +--connection node_1 +SET @@binlog_format=ROW; +CREATE TABLE t1 (a INT UNIQUE) SELECT 1 AS a,2 AS b UNION SELECT 2 AS a,3 AS c; +# +# Note that this has two rows (1,2) and (1,3) where (1,3) contains duplicate key +# but we requested REPLACE --> ::update_row() is called to update (1,2) --> (1,3) +# +CREATE TABLE t2 (a INT UNIQUE) REPLACE SELECT 1 AS a,2 AS b UNION SELECT 1 AS a,3 AS c; +SELECT * FROM t1; +SELECT * FROM t2; + +--connection node_2 +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't2' +--source include/wait_condition.inc + +SELECT * FROM t1; +SELECT * FROM t2; +DROP TABLE t1,t2; + +--echo # +--echo # Case 2: test with binlog_format MIXED +--echo # +--connection node_1 +--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't2' +--source include/wait_condition.inc +SET @@binlog_format=MIXED; +CREATE TABLE t1 (a INT UNIQUE) SELECT 1 AS a,2 AS b UNION SELECT 2 AS a,3 AS c; +CREATE TABLE t2 (a INT UNIQUE) REPLACE SELECT 1 AS a,2 AS b UNION SELECT 1 AS a,3 AS c; +SELECT * FROM t1; +SELECT * FROM t2; + +--connection node_2 +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't2' +--source include/wait_condition.inc + +SELECT * FROM t1; +SELECT * FROM t2; +DROP TABLE t1,t2; + +--echo # +--echo # Case 3: test with binlog_format STATEMENT +--echo # +--connection node_1 +--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't2' +--source include/wait_condition.inc +SET @@binlog_format=STATEMENT; +CREATE TABLE t1 (a INT UNIQUE) SELECT 1 AS a,2 AS b UNION SELECT 2 AS a,3 AS c; +CREATE TABLE t2 (a INT UNIQUE) REPLACE SELECT 1 AS a,2 AS b UNION SELECT 1 AS a,3 AS c; +SELECT * FROM t1; +SELECT * FROM t2; + +--connection node_2 +--let $wait_condition = SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't2' OR TABLE_NAME = 't1' +--source include/wait_condition.inc + +SELECT * FROM t1; +SELECT * FROM t2; +DROP TABLE t1,t2; + +--connection node_1 +--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't2' +--source include/wait_condition.inc diff --git a/mysql-test/suite/wsrep/r/binlog_format.result b/mysql-test/suite/wsrep/r/binlog_format.result index 079ceb975dd..ce4b45319bc 100644 --- a/mysql-test/suite/wsrep/r/binlog_format.result +++ b/mysql-test/suite/wsrep/r/binlog_format.result @@ -16,6 +16,9 @@ SHOW VARIABLES LIKE 'binlog_format'; Variable_name Value binlog_format STATEMENT CREATE TABLE IF NOT EXISTS test.t1 AS SELECT * FROM information_schema.routines WHERE 1 = 0; +Warnings: +Warning 1105 Galera does not support binlog_format = MIXED in CREATE TABLE [SELECT|REPLACE] forcing ROW +Warning 1105 Galera does not support binlog_format = MIXED in CREATE TABLE [SELECT|REPLACE] forcing ROW SET binlog_format=MIXED; Warnings: Warning 1105 MariaDB Galera and flashback do not support binlog format: MIXED @@ -26,9 +29,14 @@ SHOW VARIABLES LIKE 'binlog_format'; Variable_name Value binlog_format MIXED CREATE TABLE IF NOT EXISTS test.t2 AS SELECT * FROM information_schema.routines WHERE 1 = 0; +Warnings: +Warning 1105 Galera does not support binlog_format = MIXED in CREATE TABLE [SELECT|REPLACE] forcing ROW +Warning 1105 Galera does not support binlog_format = MIXED in CREATE TABLE [SELECT|REPLACE] forcing ROW SET binlog_format=ROW; SHOW WARNINGS; Level Code Message +Warning 1105 Galera does not support binlog_format = MIXED in CREATE TABLE [SELECT|REPLACE] forcing ROW +Warning 1105 Galera does not support binlog_format = MIXED in CREATE TABLE [SELECT|REPLACE] forcing ROW SHOW VARIABLES LIKE 'binlog_format'; Variable_name Value binlog_format ROW diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 124ed6e051d..fc04f5436f3 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -6372,6 +6372,24 @@ int THD::decide_logging_format(TABLE_LIST *tables) } set_current_stmt_binlog_format_row(); } + + /* If user has requested binlog_format STMT OR MIXED + in CREATE TABLE [SELECT|REPLACE] we will fall back + to ROW. + + Note that we can't use local binlog_format variable + here because wsrep_binlog_format sets it to ROW. + */ + if (wsrep_ctas && variables.binlog_format != BINLOG_FORMAT_ROW) + { + push_warning_printf(this, Sql_condition::WARN_LEVEL_WARN, + ER_UNKNOWN_ERROR, + "Galera does not support binlog_format = %s " + "in CREATE TABLE [SELECT|REPLACE] forcing ROW", + binlog_format == BINLOG_FORMAT_STMT ? + "STMT" : "MIXED"); + set_current_stmt_binlog_format_row(); + } #endif /* WITH_WSREP */ if (WSREP_EMULATE_BINLOG_NNULL(this) || diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 08229b21839..d249cb205f4 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -7858,7 +7858,10 @@ set_max_autoinc: if (wsrep_append_keys(m_user_thd, WSREP_SERVICE_KEY_EXCLUSIVE, record, NULL)) { - DBUG_PRINT("wsrep", ("row key failed")); + WSREP_DEBUG("::write_rows::wsrep_append_keys failed THD %ld for %s.%s", + thd_get_thread_id(m_user_thd), + table->s->db.str, + table->s->table_name.str); error_result = HA_ERR_INTERNAL_ERROR; goto func_exit; } @@ -8558,16 +8561,20 @@ func_exit: #ifdef WITH_WSREP if (error == DB_SUCCESS && trx->is_wsrep() && wsrep_thd_is_local(m_user_thd) - && !wsrep_thd_ignore_table(m_user_thd)) { - DBUG_PRINT("wsrep", ("update row key")); + && !wsrep_thd_ignore_table(m_user_thd) + && (thd_sql_command(m_user_thd) != SQLCOM_CREATE_TABLE) + && (thd_sql_command(m_user_thd) != SQLCOM_LOAD || + thd_binlog_format(m_user_thd) == BINLOG_FORMAT_ROW)) { if (wsrep_append_keys(m_user_thd, wsrep_protocol_version >= 4 ? WSREP_SERVICE_KEY_UPDATE : WSREP_SERVICE_KEY_EXCLUSIVE, - old_row, new_row)){ - WSREP_DEBUG("WSREP: UPDATE_ROW_KEY FAILED"); - DBUG_PRINT("wsrep", ("row key failed")); + old_row, new_row)) { + WSREP_DEBUG("::update_rows::wsrep_append_keys failed THD %ld for %s.%s", + thd_get_thread_id(m_user_thd), + table->s->db.str, + table->s->table_name.str); DBUG_RETURN(HA_ERR_INTERNAL_ERROR); } } @@ -8620,7 +8627,10 @@ ha_innobase::delete_row( if (wsrep_append_keys(m_user_thd, WSREP_SERVICE_KEY_EXCLUSIVE, record, NULL)) { - DBUG_PRINT("wsrep", ("delete fail")); + WSREP_DEBUG("::delete_rows::wsrep_append_keys failed THD %ld for %s.%s", + thd_get_thread_id(m_user_thd), + table->s->db.str, + table->s->table_name.str); DBUG_RETURN(HA_ERR_INTERNAL_ERROR); } }