diff options
author | Jan Lindström <jan.lindstrom@mariadb.com> | 2022-10-04 14:08:36 +0300 |
---|---|---|
committer | Jan Lindström <jan.lindstrom@mariadb.com> | 2022-10-09 10:09:47 +0300 |
commit | e8acec89741777ebaf46b499fdfe191ad88c3a95 (patch) | |
tree | 39439ea1b3b29ed34e86d9c4f63ebdda047c7958 | |
parent | ab3ec013c41db1b9943c5e34d3d44a35fa7538fb (diff) | |
download | mariadb-git-e8acec89741777ebaf46b499fdfe191ad88c3a95.tar.gz |
MDEV-26597 : Assertion `!wsrep_has_changes(thd) || (thd->lex->sql_command == SQLCOM_CREATE_TABLE && !thd->is_current_stmt_binlog_format_row())' failed.
If repl.max_ws_size is set too low following CREATE TABLE could fail
during commit. In this case wsrep_commit_empty should allow rolling
it back if provider state is s_aborted.
Furhermore, original ER_ERROR_DURING_COMMIT does not really tell anything
clear for user. Therefore, this commit adds a new error
ER_TOO_BIG_WRITESET. This will change some test cases output.
-rw-r--r-- | mysql-test/suite/galera/r/MDEV-26597.result | 19 | ||||
-rw-r--r-- | mysql-test/suite/galera/r/galera_repl_max_ws_size.result | 2 | ||||
-rw-r--r-- | mysql-test/suite/galera/r/galera_var_max_ws_size.result | 2 | ||||
-rw-r--r-- | mysql-test/suite/galera/t/MDEV-26597.test | 32 | ||||
-rw-r--r-- | mysql-test/suite/galera/t/galera_repl_max_ws_size.test | 2 | ||||
-rw-r--r-- | mysql-test/suite/galera/t/galera_var_max_ws_size.test | 2 | ||||
-rw-r--r-- | sql/share/errmsg-utf8.txt | 2 | ||||
-rw-r--r-- | sql/wsrep_mysqld.cc | 4 | ||||
-rw-r--r-- | sql/wsrep_thd.h | 10 | ||||
-rw-r--r-- | sql/wsrep_trans_observer.h | 22 |
10 files changed, 81 insertions, 16 deletions
diff --git a/mysql-test/suite/galera/r/MDEV-26597.result b/mysql-test/suite/galera/r/MDEV-26597.result new file mode 100644 index 00000000000..76730b56db1 --- /dev/null +++ b/mysql-test/suite/galera/r/MDEV-26597.result @@ -0,0 +1,19 @@ +connection node_2; +connection node_1; +connection node_1; +connection node_2; +connection node_2; +CREATE TABLE t3 (c1 INTEGER NOT NULL PRIMARY KEY, c2 FLOAT(3,2)); +SET GLOBAL wsrep_provider_options = 'repl.max_ws_size=512'; +SET @@autocommit=0; +INSERT INTO t3 VALUES (1000,0.00),(1001,0.25),(1002,0.50),(1003,0.75),(1008,1.00),(1009,1.25),(1010,1.50),(1011,1.75); +CREATE TABLE t1 ( pk int primary key) ENGINE=INNODB; +ERROR HY000: Maximum writeset size exceeded +SHOW WARNINGS; +Level Code Message +Error 4160 Maximum writeset size exceeded +connection node_2; +SET SESSION wsrep_sync_wait = 0; +Killing server ... +connection node_1; +DROP TABLE t3; diff --git a/mysql-test/suite/galera/r/galera_repl_max_ws_size.result b/mysql-test/suite/galera/r/galera_repl_max_ws_size.result index 0528df7b9f6..343381b99ea 100644 --- a/mysql-test/suite/galera/r/galera_repl_max_ws_size.result +++ b/mysql-test/suite/galera/r/galera_repl_max_ws_size.result @@ -4,7 +4,7 @@ connection node_1; CREATE TABLE t1 (f1 VARCHAR(512)) ENGINE=InnoDB; SET GLOBAL wsrep_provider_options = 'repl.max_ws_size=512'; INSERT INTO t1 VALUES (REPEAT('a', 512)); -ERROR HY000: Got error 5 "Input/output error" during COMMIT +ERROR HY000: Maximum writeset size exceeded SELECT COUNT(*) = 0 FROM t1; COUNT(*) = 0 1 diff --git a/mysql-test/suite/galera/r/galera_var_max_ws_size.result b/mysql-test/suite/galera/r/galera_var_max_ws_size.result index 89c9698eed4..bd712ef9b55 100644 --- a/mysql-test/suite/galera/r/galera_var_max_ws_size.result +++ b/mysql-test/suite/galera/r/galera_var_max_ws_size.result @@ -4,7 +4,7 @@ connection node_1; CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 VARCHAR(1024)) Engine=InnoDB; SET GLOBAL wsrep_max_ws_size = 1024; INSERT INTO t1 VALUES (DEFAULT, REPEAT('X', 1024)); -ERROR HY000: Got error 5 "Input/output error" during COMMIT +ERROR HY000: Maximum writeset size exceeded SELECT COUNT(*) = 0 FROM t1; COUNT(*) = 0 1 diff --git a/mysql-test/suite/galera/t/MDEV-26597.test b/mysql-test/suite/galera/t/MDEV-26597.test new file mode 100644 index 00000000000..3162cefcc22 --- /dev/null +++ b/mysql-test/suite/galera/t/MDEV-26597.test @@ -0,0 +1,32 @@ +--source include/galera_cluster.inc + +# Save original auto_increment_offset values. +--let $node_1=node_1 +--let $node_2=node_2 +--source include/auto_increment_offset_save.inc + +--connection node_2 +CREATE TABLE t3 (c1 INTEGER NOT NULL PRIMARY KEY, c2 FLOAT(3,2)); +SET GLOBAL wsrep_provider_options = 'repl.max_ws_size=512'; +SET @@autocommit=0; +INSERT INTO t3 VALUES (1000,0.00),(1001,0.25),(1002,0.50),(1003,0.75),(1008,1.00),(1009,1.25),(1010,1.50),(1011,1.75); +--error ER_TOO_BIG_WRITESET +CREATE TABLE t1 ( pk int primary key) ENGINE=INNODB; +SHOW WARNINGS; + +--connection node_2 +SET SESSION wsrep_sync_wait = 0; +--source include/kill_galera.inc + +--let $start_mysqld_params = "" +--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.2.expect +--source include/start_mysqld.inc + +# +# Cleanup +# +--source ../../galera/include/auto_increment_offset_restore.inc +--connection node_1 +DROP TABLE t3; + + diff --git a/mysql-test/suite/galera/t/galera_repl_max_ws_size.test b/mysql-test/suite/galera/t/galera_repl_max_ws_size.test index 60b866ae018..896ad99f3d8 100644 --- a/mysql-test/suite/galera/t/galera_repl_max_ws_size.test +++ b/mysql-test/suite/galera/t/galera_repl_max_ws_size.test @@ -12,7 +12,7 @@ CREATE TABLE t1 (f1 VARCHAR(512)) ENGINE=InnoDB; SET GLOBAL wsrep_provider_options = 'repl.max_ws_size=512'; ---error ER_ERROR_DURING_COMMIT +--error ER_TOO_BIG_WRITESET INSERT INTO t1 VALUES (REPEAT('a', 512)); SELECT COUNT(*) = 0 FROM t1; diff --git a/mysql-test/suite/galera/t/galera_var_max_ws_size.test b/mysql-test/suite/galera/t/galera_var_max_ws_size.test index 8eb93bda9be..440b3dea2a3 100644 --- a/mysql-test/suite/galera/t/galera_var_max_ws_size.test +++ b/mysql-test/suite/galera/t/galera_var_max_ws_size.test @@ -12,7 +12,7 @@ CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 VARCHAR(1024)) Engine --let $wsrep_max_ws_size_orig = `SELECT @@wsrep_max_ws_size` SET GLOBAL wsrep_max_ws_size = 1024; ---error ER_ERROR_DURING_COMMIT +--error ER_TOO_BIG_WRITESET INSERT INTO t1 VALUES (DEFAULT, REPEAT('X', 1024)); SELECT COUNT(*) = 0 FROM t1; diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index dde8337f01c..8d9bf5c6ebb 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -9090,3 +9090,5 @@ ER_PERIOD_CONSTRAINT_DROP ER_TOO_LONG_KEYPART 42000 S1009 chi "指定的索引部分太长;最大索引部分长度为 %u 个字节" eng "Specified key part was too long; max key part length is %u bytes" +ER_TOO_BIG_WRITESET + eng "Maximum writeset size exceeded" diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index ccf191b2e21..d7cbc545161 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -1,4 +1,4 @@ -/* Copyright 2008-2021 Codership Oy <http://www.codership.com> +/* Copyright 2008-2022 Codership Oy <http://www.codership.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -2153,7 +2153,7 @@ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table, ret, (thd->db.str ? thd->db.str : "(null)"), wsrep_thd_query(thd)); - my_error(ER_ERROR_DURING_COMMIT, MYF(0), WSREP_SIZE_EXCEEDED); + my_error(ER_TOO_BIG_WRITESET, MYF(0)); break; case wsrep::e_deadlock_error: WSREP_WARN("TO isolation failed for: %d, schema: %s, sql: %s. " diff --git a/sql/wsrep_thd.h b/sql/wsrep_thd.h index 40e5ed98e9b..32663e9fc3b 100644 --- a/sql/wsrep_thd.h +++ b/sql/wsrep_thd.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2021 Codership Oy <info@codership.com> +/* Copyright (C) 2013-2022 Codership Oy <info@codership.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -210,7 +210,6 @@ static inline void wsrep_override_error(THD *thd, uint error, !da->is_set() || (da->is_error() && da->sql_errno() != error && - da->sql_errno() != ER_ERROR_DURING_COMMIT && da->sql_errno() != ER_LOCK_DEADLOCK)) { da->reset_diagnostics_area(); @@ -226,7 +225,10 @@ static inline void wsrep_override_error(THD* thd, switch (ce) { case wsrep::e_error_during_commit: - wsrep_override_error(thd, ER_ERROR_DURING_COMMIT, status); + if (status == wsrep::provider::error_size_exceeded) + wsrep_override_error(thd, ER_TOO_BIG_WRITESET); + else + wsrep_override_error(thd, ER_ERROR_DURING_COMMIT, status); break; case wsrep::e_deadlock_error: wsrep_override_error(thd, ER_LOCK_DEADLOCK); @@ -235,7 +237,7 @@ static inline void wsrep_override_error(THD* thd, wsrep_override_error(thd, ER_QUERY_INTERRUPTED); break; case wsrep::e_size_exceeded_error: - wsrep_override_error(thd, ER_ERROR_DURING_COMMIT, status); + wsrep_override_error(thd, ER_TOO_BIG_WRITESET); break; case wsrep::e_append_fragment_error: /* TODO: Figure out better error number */ diff --git a/sql/wsrep_trans_observer.h b/sql/wsrep_trans_observer.h index cde8163cf4f..f1d0eebf6dd 100644 --- a/sql/wsrep_trans_observer.h +++ b/sql/wsrep_trans_observer.h @@ -1,4 +1,4 @@ -/* Copyright 2016-2019 Codership Oy <http://www.codership.com> +/* Copyright 2016-2022 Codership Oy <http://www.codership.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -531,18 +531,28 @@ wsrep_current_error_status(THD* thd) static inline void wsrep_commit_empty(THD* thd, bool all) { DBUG_ENTER("wsrep_commit_empty"); - WSREP_DEBUG("wsrep_commit_empty(%llu)", thd->thread_id); + WSREP_DEBUG("wsrep_commit_empty for %llu client_state %s client_mode" + " %s trans_state %s sql %s", + thd_get_thread_id(thd), + wsrep::to_c_string(thd->wsrep_cs().state()), + wsrep::to_c_string(thd->wsrep_cs().mode()), + wsrep::to_c_string(thd->wsrep_cs().transaction().state()), + wsrep_thd_query(thd)); + if (wsrep_is_real(thd, all) && wsrep_thd_is_local(thd) && thd->wsrep_trx().active() && thd->wsrep_trx().state() != wsrep::transaction::s_committed) { - /* @todo CTAS with STATEMENT binlog format and empty result set - seems to be committing empty. Figure out why and try to fix - elsewhere. */ + /* Here transaction is either empty (i.e. no changes) or + it was CREATE TABLE with no row binlog format or + we have already aborted transaction e.g. because max writeset size + has been reached. */ DBUG_ASSERT(!wsrep_has_changes(thd) || (thd->lex->sql_command == SQLCOM_CREATE_TABLE && - !thd->is_current_stmt_binlog_format_row())); + !thd->is_current_stmt_binlog_format_row()) || + thd->wsrep_cs().transaction().state() == wsrep::transaction::s_aborted); + bool have_error= wsrep_current_error(thd); int ret= wsrep_before_rollback(thd, all) || wsrep_after_rollback(thd, all) || |