Skip to content

Commit daaa16a

Browse files
janlindstromsysprg
authored andcommitted
MDEV-25089 : Assertion `error.len > 0' failed in galera::ReplicatorSMM::handle_apply_error()
Problem is that Galera starts TOI (total order isolation) i.e. it sends query to all nodes. Later it is discovered that used engine or other feature is not supported by Galera. Because TOI is executed parallelly in all nodes appliers could execute given TOI and ignore the error and start inconsistency voting causing node to leave from cluster or we might have a crash as reported. For example SEQUENCE engine does not support GEOMETRY data type causing either inconsistency between nodes (because some errors are ignored on applier) or crash. Fixed my adding new function wsrep_check_support to check can Galera support provided CREATE TABLE/SEQUENCE before TOI is started and if not clear error message is provided to the user. Currently, not supported cases: * CREATE TABLE ... AS SELECT when streaming replication is used * CREATE TABLE ... WITH SYSTEM VERSIONING AS SELECT * CREATE TABLE ... ENGINE=SEQUENCE * CREATE SEQUENCE ... ENGINE!=InnoDB * ALTER TABLE t ... ENGINE!=InnoDB where table t is SEQUENCE Signed-off-by: Julius Goryavsky <julius.goryavsky@mariadb.com>
1 parent 3228c08 commit daaa16a

File tree

9 files changed

+121
-83
lines changed

9 files changed

+121
-83
lines changed

mysql-test/suite/galera/r/MDEV-24143.result

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ c1
1414
INSERT INTO t1 VALUES (4),(3),(1),(2);
1515
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
1616
CREATE TABLE t1 (pk INT PRIMARY KEY, b INT) ENGINE=SEQUENCE;
17-
ERROR 42S01: Table 't1' already exists
17+
ERROR 42000: This version of MariaDB doesn't yet support 'non-InnoDB sequences in Galera cluster'
1818
ALTER TABLE t1 DROP COLUMN c2;
1919
ERROR 42000: Can't DROP COLUMN `c2`; check that it exists
2020
SELECT get_lock ('test', 1.5);
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
connection node_2;
2+
connection node_1;
3+
SET GLOBAL wsrep_ignore_apply_errors=0;
4+
SET SESSION AUTOCOMMIT=0;
5+
SET SESSION max_error_count=0;
6+
CREATE TABLE t0 (id GEOMETRY,parent_id GEOMETRY)ENGINE=SEQUENCE;
7+
ERROR 42000: This version of MariaDB doesn't yet support 'non-InnoDB sequences in Galera cluster'
8+
connection node_2;
9+
SHOW CREATE TABLE t0;
10+
ERROR 42S02: Table 'test.t0' doesn't exist
11+
connection node_1;
12+
SET GLOBAL wsrep_ignore_apply_errors=DEFAULT;
Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,8 @@
11
connection node_2;
22
connection node_1;
33
connection node_1;
4-
connection node_2;
5-
connection node_1;
64
CREATE TABLE t ENGINE=InnoDB WITH SYSTEM VERSIONING AS SELECT 1 AS i;
7-
SHOW CREATE TABLE t;
8-
Table Create Table
9-
t CREATE TABLE `t` (
10-
`i` int(1) NOT NULL
11-
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci WITH SYSTEM VERSIONING
12-
SELECT * from t;
13-
i
14-
1
15-
DROP TABLE IF EXISTS t;
16-
COMMIT;
5+
ERROR 42000: This version of MariaDB doesn't yet support 'SYSTEM VERSIONING AS SELECT in Galera cluster'
176
connection node_2;
18-
SET SESSION wsrep_sync_wait=0;
19-
Killing server ...
20-
Starting server ...
21-
connection node_2;
22-
call mtr.add_suppression("WSREP: Event .*Write_rows_v1 apply failed:.*");
23-
call mtr.add_suppression("SREP: Failed to apply write set: gtid:.*");
7+
SHOW CREATE TABLE t;
8+
ERROR 42S02: Table 'test.t' doesn't exist

mysql-test/suite/galera/t/MDEV-24143.test

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ SET SESSION autocommit=0;
1111
SELECT * FROM t1 WHERE c1 <=0 ORDER BY c1 DESC;
1212
--error ER_LOCK_DEADLOCK
1313
INSERT INTO t1 VALUES (4),(3),(1),(2);
14-
--error ER_TABLE_EXISTS_ERROR
14+
#
15+
# This is because support for CREATE TABLE ENGINE=SEQUENCE
16+
# is done before we check does table exists already.
17+
#
18+
--error ER_NOT_SUPPORTED_YET
1519
CREATE TABLE t1 (pk INT PRIMARY KEY, b INT) ENGINE=SEQUENCE;
1620
--error ER_CANT_DROP_FIELD_OR_KEY
1721
ALTER TABLE t1 DROP COLUMN c2;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--source include/galera_cluster.inc
2+
--source include/have_sequence.inc
3+
4+
SET GLOBAL wsrep_ignore_apply_errors=0;
5+
SET SESSION AUTOCOMMIT=0;
6+
SET SESSION max_error_count=0;
7+
--error ER_NOT_SUPPORTED_YET
8+
CREATE TABLE t0 (id GEOMETRY,parent_id GEOMETRY)ENGINE=SEQUENCE;
9+
10+
--connection node_2
11+
--error ER_NO_SUCH_TABLE
12+
SHOW CREATE TABLE t0;
13+
14+
--connection node_1
15+
SET GLOBAL wsrep_ignore_apply_errors=DEFAULT;
16+
Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,15 @@
11
--source include/galera_cluster.inc
22

3-
--let $node_1 = node_1
4-
--let $node_2 = node_2
5-
--source include/auto_increment_offset_save.inc
6-
73
--connection node_1
8-
CREATE TABLE t ENGINE=InnoDB WITH SYSTEM VERSIONING AS SELECT 1 AS i;
9-
SHOW CREATE TABLE t;
10-
SELECT * from t;
11-
DROP TABLE IF EXISTS t;
12-
COMMIT;
13-
144
#
15-
# Restart node_2, force SST because database is inconsistent compared to node_1
5+
# Below should not cause nodes to be inconsistent (they could if we
6+
# allow TOI as some error are ignored on applier
167
#
17-
--connection node_2
18-
SET SESSION wsrep_sync_wait=0;
19-
--source include/kill_galera.inc
20-
--remove_file $MYSQLTEST_VARDIR/mysqld.2/data/grastate.dat
21-
--echo Starting server ...
22-
let $restart_noprint=2;
23-
--source include/start_mysqld.inc
24-
--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
25-
--source include/wait_condition.inc
26-
27-
--let $wait_condition = SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready';
28-
--source include/wait_condition.inc
8+
--error ER_NOT_SUPPORTED_YET
9+
CREATE TABLE t ENGINE=InnoDB WITH SYSTEM VERSIONING AS SELECT 1 AS i;
2910

3011
--connection node_2
31-
call mtr.add_suppression("WSREP: Event .*Write_rows_v1 apply failed:.*");
32-
call mtr.add_suppression("SREP: Failed to apply write set: gtid:.*");
12+
--error ER_NO_SUCH_TABLE
13+
SHOW CREATE TABLE t;
14+
3315

34-
--source include/auto_increment_offset_restore.inc

sql/sql_sequence.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
2727
#include "sql_acl.h"
2828
#ifdef WITH_WSREP
2929
#include "wsrep_mysqld.h"
30+
bool wsrep_check_sequence(THD* thd,
31+
const sequence_definition *seq,
32+
const bool used_engine);
3033
#endif
3134

3235
struct Field_definition
@@ -945,7 +948,8 @@ bool Sql_cmd_alter_sequence::execute(THD *thd)
945948
#ifdef WITH_WSREP
946949
if (WSREP(thd) && wsrep_thd_is_local(thd))
947950
{
948-
if (wsrep_check_sequence(thd, new_seq))
951+
const bool used_engine= lex->create_info.used_fields & HA_CREATE_USED_ENGINE;
952+
if (wsrep_check_sequence(thd, new_seq, used_engine))
949953
DBUG_RETURN(TRUE);
950954

951955
if (wsrep_to_isolation_begin(thd, first_table->db.str,

sql/sql_table.cc

Lines changed: 72 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5343,18 +5343,21 @@ int mysql_create_table_no_lock(THD *thd, const LEX_CSTRING *db,
53435343
#ifdef WITH_WSREP
53445344
/** Additional sequence checks for Galera cluster.
53455345
5346-
@param thd thread handle
5347-
@param seq sequence definition
5346+
@param thd thread handle
5347+
@param seq sequence definition
5348+
@param used_engine create used ENGINE=
53485349
@retval false success
53495350
@retval true failure
53505351
*/
5351-
bool wsrep_check_sequence(THD* thd, const sequence_definition *seq)
5352+
bool wsrep_check_sequence(THD* thd,
5353+
const sequence_definition *seq,
5354+
const bool used_engine)
53525355
{
53535356
enum legacy_db_type db_type;
53545357

53555358
DBUG_ASSERT(WSREP(thd));
53565359

5357-
if (thd->lex->create_info.used_fields & HA_CREATE_USED_ENGINE)
5360+
if (used_engine)
53585361
{
53595362
db_type= thd->lex->create_info.db_type->db_type;
53605363
}
@@ -5385,6 +5388,57 @@ bool wsrep_check_sequence(THD* thd, const sequence_definition *seq)
53855388

53865389
return (false);
53875390
}
5391+
5392+
/** Additional CREATE TABLE/SEQUENCE checks for Galera cluster.
5393+
5394+
@param thd thread handle
5395+
@param wsrep_ctas CREATE TABLE AS SELECT ?
5396+
@param used_engine CREATE TABLE ... ENGINE = ?
5397+
@param create_info Create information
5398+
5399+
@retval false Galera cluster does support used clause
5400+
@retval true Galera cluster does not support used clause
5401+
*/
5402+
static
5403+
bool wsrep_check_support(THD* thd,
5404+
const bool wsrep_ctas,
5405+
const bool used_engine,
5406+
const HA_CREATE_INFO* create_info)
5407+
{
5408+
/* CREATE TABLE ... AS SELECT */
5409+
if (wsrep_ctas &&
5410+
thd->variables.wsrep_trx_fragment_size > 0)
5411+
{
5412+
my_message(ER_NOT_ALLOWED_COMMAND,
5413+
"CREATE TABLE AS SELECT is not supported with streaming replication",
5414+
MYF(0));
5415+
return true;
5416+
}
5417+
/* CREATE TABLE .. WITH SYSTEM VERSIONING AS SELECT
5418+
is not supported in Galera cluster.
5419+
*/
5420+
if (wsrep_ctas &&
5421+
create_info->versioned())
5422+
{
5423+
my_error(ER_NOT_SUPPORTED_YET, MYF(0),
5424+
"SYSTEM VERSIONING AS SELECT in Galera cluster");
5425+
return true;
5426+
}
5427+
/*
5428+
CREATE TABLE ... ENGINE=SEQUENCE is not supported in
5429+
Galera cluster.
5430+
CREATE SEQUENCE ... ENGINE=xxx Galera cluster supports
5431+
only InnoDB-sequences.
5432+
*/
5433+
if (((used_engine && create_info->db_type &&
5434+
(create_info->db_type->db_type == DB_TYPE_SEQUENCE ||
5435+
create_info->db_type->db_type >= DB_TYPE_FIRST_DYNAMIC)) ||
5436+
thd->lex->sql_command == SQLCOM_CREATE_SEQUENCE) &&
5437+
wsrep_check_sequence(thd, create_info->seq_create_info, used_engine))
5438+
return true;
5439+
5440+
return false;
5441+
}
53885442
#endif /* WITH_WSREP */
53895443

53905444
/**
@@ -5442,15 +5496,6 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
54425496
if (!opt_explicit_defaults_for_timestamp)
54435497
promote_first_timestamp_column(&alter_info->create_list);
54445498

5445-
#ifdef WITH_WSREP
5446-
if (thd->lex->sql_command == SQLCOM_CREATE_SEQUENCE &&
5447-
WSREP(thd) && wsrep_thd_is_local_toi(thd))
5448-
{
5449-
if (wsrep_check_sequence(thd, create_info->seq_create_info))
5450-
DBUG_RETURN(true);
5451-
}
5452-
#endif /* WITH_WSREP */
5453-
54545499
/* We can abort create table for any table type */
54555500
thd->abort_on_warning= thd->is_strict_mode();
54565501

@@ -9764,6 +9809,7 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
97649809
TODO: this design is obsolete and will be removed.
97659810
*/
97669811
int table_kind= check_if_log_table(table_list, FALSE, NullS);
9812+
const bool used_engine= create_info->used_fields & HA_CREATE_USED_ENGINE;
97679813

97689814
if (table_kind)
97699815
{
@@ -9775,7 +9821,7 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
97759821
}
97769822

97779823
/* Disable alter of log tables to unsupported engine */
9778-
if ((create_info->used_fields & HA_CREATE_USED_ENGINE) &&
9824+
if ((used_engine) &&
97799825
(!create_info->db_type || /* unknown engine */
97809826
!(create_info->db_type->flags & HTON_SUPPORT_LOG_TABLES)))
97819827
{
@@ -9826,7 +9872,7 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
98269872
if we can support implementing storage engine.
98279873
*/
98289874
if (WSREP(thd) && table && table->s->sequence &&
9829-
wsrep_check_sequence(thd, thd->lex->create_info.seq_create_info))
9875+
wsrep_check_sequence(thd, thd->lex->create_info.seq_create_info, used_engine))
98309876
DBUG_RETURN(TRUE);
98319877
#endif /* WITH_WSREP */
98329878

@@ -10285,12 +10331,10 @@ do_continue:;
1028510331
#endif
1028610332

1028710333
#ifdef WITH_WSREP
10334+
// ALTER TABLE for sequence object, check can we support it
1028810335
if (table->s->sequence && WSREP(thd) &&
10289-
wsrep_thd_is_local_toi(thd))
10290-
{
10291-
if (wsrep_check_sequence(thd, create_info->seq_create_info))
10336+
wsrep_check_sequence(thd, create_info->seq_create_info, used_engine))
1029210337
DBUG_RETURN(TRUE);
10293-
}
1029410338
#endif /* WITH_WSREP */
1029510339

1029610340
/*
@@ -11744,17 +11788,11 @@ bool Sql_cmd_create_table_like::execute(THD *thd)
1174411788
#endif
1174511789

1174611790
#ifdef WITH_WSREP
11747-
if (wsrep_ctas)
11791+
if (WSREP(thd) &&
11792+
wsrep_check_support(thd, wsrep_ctas, used_engine, &create_info))
1174811793
{
11749-
if (thd->variables.wsrep_trx_fragment_size > 0)
11750-
{
11751-
my_message(
11752-
ER_NOT_ALLOWED_COMMAND,
11753-
"CREATE TABLE AS SELECT is not supported with streaming replication",
11754-
MYF(0));
11755-
res= 1;
11756-
goto end_with_restore_list;
11757-
}
11794+
res= 1;
11795+
goto end_with_restore_list;
1175811796
}
1175911797
#endif /* WITH_WSREP */
1176011798

@@ -11906,6 +11944,7 @@ bool Sql_cmd_create_table_like::execute(THD *thd)
1190611944
create_table->table_name, create_table->db))
1190711945
goto end_with_restore_list;
1190811946

11947+
#ifdef WITH_WSREP
1190911948
/*
1191011949
In STATEMENT format, we probably have to replicate also temporary
1191111950
tables, like mysql replication does. Also check if the requested
@@ -11914,15 +11953,15 @@ bool Sql_cmd_create_table_like::execute(THD *thd)
1191411953
if (WSREP(thd))
1191511954
{
1191611955
handlerton *orig_ht= create_info.db_type;
11956+
1191711957
if (!check_engine(thd, create_table->db.str,
1191811958
create_table->table_name.str,
1191911959
&create_info) &&
1192011960
(!thd->is_current_stmt_binlog_format_row() ||
1192111961
!create_info.tmp_table()))
1192211962
{
11923-
#ifdef WITH_WSREP
1192411963
if (thd->lex->sql_command == SQLCOM_CREATE_SEQUENCE &&
11925-
wsrep_check_sequence(thd, lex->create_info.seq_create_info))
11964+
wsrep_check_sequence(thd, lex->create_info.seq_create_info, used_engine))
1192611965
DBUG_RETURN(true);
1192711966

1192811967
WSREP_TO_ISOLATION_BEGIN_ALTER(create_table->db.str, create_table->table_name.str,
@@ -11932,13 +11971,14 @@ bool Sql_cmd_create_table_like::execute(THD *thd)
1193211971
res= true;
1193311972
goto end_with_restore_list;
1193411973
}
11935-
#endif /* WITH_WSREP */
1193611974
}
1193711975
// check_engine will set db_type to NULL if e.g. TEMPORARY is
1193811976
// not supported by the storage engine, this case is checked
1193911977
// again in mysql_create_table
1194011978
create_info.db_type= orig_ht;
1194111979
}
11980+
#endif /* WITH_WSREP */
11981+
1194211982
/* Regular CREATE TABLE */
1194311983
res= mysql_create_table(thd, create_table, &create_info, &alter_info);
1194411984
}

sql/sql_table.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -285,8 +285,4 @@ extern mysql_mutex_t LOCK_gdl;
285285

286286
bool check_engine(THD *, const char *, const char *, HA_CREATE_INFO *);
287287

288-
#ifdef WITH_WSREP
289-
bool wsrep_check_sequence(THD* thd, const class sequence_definition *seq);
290-
#endif
291-
292288
#endif /* SQL_TABLE_INCLUDED */

0 commit comments

Comments
 (0)