Commit e8acec89 authored by Jan Lindström's avatar Jan Lindström

MDEV-26597 : Assertion `!wsrep_has_changes(thd) || (thd->lex->sql_command ==...

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.
parent ab3ec013
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;
...@@ -4,7 +4,7 @@ connection node_1; ...@@ -4,7 +4,7 @@ connection node_1;
CREATE TABLE t1 (f1 VARCHAR(512)) ENGINE=InnoDB; CREATE TABLE t1 (f1 VARCHAR(512)) ENGINE=InnoDB;
SET GLOBAL wsrep_provider_options = 'repl.max_ws_size=512'; SET GLOBAL wsrep_provider_options = 'repl.max_ws_size=512';
INSERT INTO t1 VALUES (REPEAT('a', 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; SELECT COUNT(*) = 0 FROM t1;
COUNT(*) = 0 COUNT(*) = 0
1 1
......
...@@ -4,7 +4,7 @@ connection node_1; ...@@ -4,7 +4,7 @@ connection node_1;
CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 VARCHAR(1024)) Engine=InnoDB; CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 VARCHAR(1024)) Engine=InnoDB;
SET GLOBAL wsrep_max_ws_size = 1024; SET GLOBAL wsrep_max_ws_size = 1024;
INSERT INTO t1 VALUES (DEFAULT, REPEAT('X', 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; SELECT COUNT(*) = 0 FROM t1;
COUNT(*) = 0 COUNT(*) = 0
1 1
......
--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;
...@@ -12,7 +12,7 @@ CREATE TABLE t1 (f1 VARCHAR(512)) ENGINE=InnoDB; ...@@ -12,7 +12,7 @@ CREATE TABLE t1 (f1 VARCHAR(512)) ENGINE=InnoDB;
SET GLOBAL wsrep_provider_options = 'repl.max_ws_size=512'; 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)); INSERT INTO t1 VALUES (REPEAT('a', 512));
SELECT COUNT(*) = 0 FROM t1; SELECT COUNT(*) = 0 FROM t1;
......
...@@ -12,7 +12,7 @@ CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 VARCHAR(1024)) Engine ...@@ -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` --let $wsrep_max_ws_size_orig = `SELECT @@wsrep_max_ws_size`
SET GLOBAL wsrep_max_ws_size = 1024; 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)); INSERT INTO t1 VALUES (DEFAULT, REPEAT('X', 1024));
SELECT COUNT(*) = 0 FROM t1; SELECT COUNT(*) = 0 FROM t1;
......
...@@ -9090,3 +9090,5 @@ ER_PERIOD_CONSTRAINT_DROP ...@@ -9090,3 +9090,5 @@ ER_PERIOD_CONSTRAINT_DROP
ER_TOO_LONG_KEYPART 42000 S1009 ER_TOO_LONG_KEYPART 42000 S1009
chi "指定的索引部分太长;最大索引部分长度为 %u 个字节" chi "指定的索引部分太长;最大索引部分长度为 %u 个字节"
eng "Specified key part was too long; max key part length is %u bytes" eng "Specified key part was too long; max key part length is %u bytes"
ER_TOO_BIG_WRITESET
eng "Maximum writeset size exceeded"
/* 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 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 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, ...@@ -2153,7 +2153,7 @@ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table,
ret, ret,
(thd->db.str ? thd->db.str : "(null)"), (thd->db.str ? thd->db.str : "(null)"),
wsrep_thd_query(thd)); wsrep_thd_query(thd));
my_error(ER_ERROR_DURING_COMMIT, MYF(0), WSREP_SIZE_EXCEEDED); my_error(ER_TOO_BIG_WRITESET, MYF(0));
break; break;
case wsrep::e_deadlock_error: case wsrep::e_deadlock_error:
WSREP_WARN("TO isolation failed for: %d, schema: %s, sql: %s. " WSREP_WARN("TO isolation failed for: %d, schema: %s, sql: %s. "
......
/* 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 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 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, ...@@ -210,7 +210,6 @@ static inline void wsrep_override_error(THD *thd, uint error,
!da->is_set() || !da->is_set() ||
(da->is_error() && (da->is_error() &&
da->sql_errno() != error && da->sql_errno() != error &&
da->sql_errno() != ER_ERROR_DURING_COMMIT &&
da->sql_errno() != ER_LOCK_DEADLOCK)) da->sql_errno() != ER_LOCK_DEADLOCK))
{ {
da->reset_diagnostics_area(); da->reset_diagnostics_area();
...@@ -226,7 +225,10 @@ static inline void wsrep_override_error(THD* thd, ...@@ -226,7 +225,10 @@ static inline void wsrep_override_error(THD* thd,
switch (ce) switch (ce)
{ {
case wsrep::e_error_during_commit: 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; break;
case wsrep::e_deadlock_error: case wsrep::e_deadlock_error:
wsrep_override_error(thd, ER_LOCK_DEADLOCK); wsrep_override_error(thd, ER_LOCK_DEADLOCK);
...@@ -235,7 +237,7 @@ static inline void wsrep_override_error(THD* thd, ...@@ -235,7 +237,7 @@ static inline void wsrep_override_error(THD* thd,
wsrep_override_error(thd, ER_QUERY_INTERRUPTED); wsrep_override_error(thd, ER_QUERY_INTERRUPTED);
break; break;
case wsrep::e_size_exceeded_error: case wsrep::e_size_exceeded_error:
wsrep_override_error(thd, ER_ERROR_DURING_COMMIT, status); wsrep_override_error(thd, ER_TOO_BIG_WRITESET);
break; break;
case wsrep::e_append_fragment_error: case wsrep::e_append_fragment_error:
/* TODO: Figure out better error number */ /* TODO: Figure out better error number */
......
/* 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 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 it under the terms of the GNU General Public License as published by
...@@ -531,18 +531,28 @@ wsrep_current_error_status(THD* thd) ...@@ -531,18 +531,28 @@ wsrep_current_error_status(THD* thd)
static inline void wsrep_commit_empty(THD* thd, bool all) static inline void wsrep_commit_empty(THD* thd, bool all)
{ {
DBUG_ENTER("wsrep_commit_empty"); 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) && if (wsrep_is_real(thd, all) &&
wsrep_thd_is_local(thd) && wsrep_thd_is_local(thd) &&
thd->wsrep_trx().active() && thd->wsrep_trx().active() &&
thd->wsrep_trx().state() != wsrep::transaction::s_committed) thd->wsrep_trx().state() != wsrep::transaction::s_committed)
{ {
/* @todo CTAS with STATEMENT binlog format and empty result set /* Here transaction is either empty (i.e. no changes) or
seems to be committing empty. Figure out why and try to fix it was CREATE TABLE with no row binlog format or
elsewhere. */ we have already aborted transaction e.g. because max writeset size
has been reached. */
DBUG_ASSERT(!wsrep_has_changes(thd) || DBUG_ASSERT(!wsrep_has_changes(thd) ||
(thd->lex->sql_command == SQLCOM_CREATE_TABLE && (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); bool have_error= wsrep_current_error(thd);
int ret= wsrep_before_rollback(thd, all) || int ret= wsrep_before_rollback(thd, all) ||
wsrep_after_rollback(thd, all) || wsrep_after_rollback(thd, all) ||
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment