summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Lindström <jan.lindstrom@mariadb.com>2022-10-04 14:08:36 +0300
committerJan Lindström <jan.lindstrom@mariadb.com>2022-10-09 10:09:47 +0300
commite8acec89741777ebaf46b499fdfe191ad88c3a95 (patch)
tree39439ea1b3b29ed34e86d9c4f63ebdda047c7958
parentab3ec013c41db1b9943c5e34d3d44a35fa7538fb (diff)
downloadmariadb-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.result19
-rw-r--r--mysql-test/suite/galera/r/galera_repl_max_ws_size.result2
-rw-r--r--mysql-test/suite/galera/r/galera_var_max_ws_size.result2
-rw-r--r--mysql-test/suite/galera/t/MDEV-26597.test32
-rw-r--r--mysql-test/suite/galera/t/galera_repl_max_ws_size.test2
-rw-r--r--mysql-test/suite/galera/t/galera_var_max_ws_size.test2
-rw-r--r--sql/share/errmsg-utf8.txt2
-rw-r--r--sql/wsrep_mysqld.cc4
-rw-r--r--sql/wsrep_thd.h10
-rw-r--r--sql/wsrep_trans_observer.h22
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) ||