Skip to content

Commit e39c497

Browse files
denis-protivenskysysprg
authored andcommitted
MDEV-22232: Fix CTAS replay & retry in case it gets BF-aborted
- Add selected tables as shared keys for CTAS certification - Set proper security context on the replayer thread - Disallow CTAS command retry Signed-off-by: Julius Goryavsky <julius.goryavsky@mariadb.com>
1 parent 671f665 commit e39c497

File tree

7 files changed

+157
-32
lines changed

7 files changed

+157
-32
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
connection node_2;
2+
connection node_1;
3+
connect con1,127.0.0.1,root,,test,$NODE_MYPORT_1;
4+
--- CTAS with empty result set ---
5+
CREATE TABLE t1 (a INT) ENGINE=InnoDB;
6+
SET DEBUG_SYNC = 'create_table_select_before_create SIGNAL may_alter WAIT_FOR bf_abort';
7+
CREATE TABLE t2 SELECT * FROM t1;
8+
connection node_1;
9+
SET DEBUG_SYNC = 'now WAIT_FOR may_alter';
10+
ALTER TABLE t1 DROP FOREIGN KEY b, ALGORITHM=COPY;
11+
connection con1;
12+
ERROR 70100: Query execution was interrupted
13+
SET DEBUG_SYNC = 'RESET';
14+
--- CTAS with non-empty result set ---
15+
INSERT INTO t1 VALUES (10), (20), (30);
16+
SET DEBUG_SYNC = 'create_table_select_before_create SIGNAL may_alter WAIT_FOR bf_abort';
17+
CREATE TABLE t2 SELECT * FROM t1;
18+
connection node_1;
19+
SET DEBUG_SYNC = 'now WAIT_FOR may_alter';
20+
ALTER TABLE t1 DROP FOREIGN KEY b, ALGORITHM=COPY;
21+
connection con1;
22+
ERROR 70100: Query execution was interrupted
23+
SET DEBUG_SYNC = 'RESET';
24+
DROP TABLE t1;
25+
disconnect con1;
26+
disconnect node_2;
27+
disconnect node_1;
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#
2+
# MDEV-22232: CTAS execution crashes during replay.
3+
#
4+
# There were multiple problems and two failing scenarios with empty result set
5+
# and with non-empty result set:
6+
# - CTAS didn't add shared keys for selected tables
7+
# - Security context wasn't set on the replayer thread
8+
# - CTAS was retried after failure - now retry disabled
9+
10+
--source include/galera_cluster.inc
11+
--source include/have_debug_sync.inc
12+
--source include/have_debug.inc
13+
14+
--connect con1,127.0.0.1,root,,test,$NODE_MYPORT_1
15+
16+
# Scenario 1
17+
--echo --- CTAS with empty result set ---
18+
CREATE TABLE t1 (a INT) ENGINE=InnoDB;
19+
20+
# Run CTAS until the resulting table gets created,
21+
# then it gets BF aborted by ALTER.
22+
SET DEBUG_SYNC = 'create_table_select_before_create SIGNAL may_alter WAIT_FOR bf_abort';
23+
--send
24+
CREATE TABLE t2 SELECT * FROM t1;
25+
26+
# Wait for CTAS to reach the table create point,
27+
# start executing ALTER and BF abort CTAS.
28+
--connection node_1
29+
SET DEBUG_SYNC = 'now WAIT_FOR may_alter';
30+
--disable_result_log
31+
--error ER_ERROR_ON_RENAME
32+
ALTER TABLE t1 DROP FOREIGN KEY b, ALGORITHM=COPY;
33+
--enable_result_log
34+
35+
--connection con1
36+
# CTAS gets BF aborted.
37+
--error ER_QUERY_INTERRUPTED
38+
--reap
39+
40+
# Cleanup
41+
SET DEBUG_SYNC = 'RESET';
42+
43+
44+
# Scenario 2
45+
--echo --- CTAS with non-empty result set ---
46+
INSERT INTO t1 VALUES (10), (20), (30);
47+
48+
# Run CTAS until the resulting table gets created,
49+
# then it gets BF aborted by ALTER.
50+
SET DEBUG_SYNC = 'create_table_select_before_create SIGNAL may_alter WAIT_FOR bf_abort';
51+
--send
52+
CREATE TABLE t2 SELECT * FROM t1;
53+
54+
# Wait for CTAS to reach the table create point,
55+
# start executing ALTER and BF abort CTAS.
56+
--connection node_1
57+
SET DEBUG_SYNC = 'now WAIT_FOR may_alter';
58+
--disable_result_log
59+
--error ER_ERROR_ON_RENAME
60+
ALTER TABLE t1 DROP FOREIGN KEY b, ALGORITHM=COPY;
61+
--enable_result_log
62+
63+
--connection con1
64+
# CTAS gets BF aborted.
65+
--error ER_QUERY_INTERRUPTED
66+
--reap
67+
68+
# Cleanup
69+
SET DEBUG_SYNC = 'RESET';
70+
DROP TABLE t1;
71+
--disconnect con1
72+
--source include/galera_end.inc

sql/sql_insert.cc

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
#include "debug_sync.h"
8585

8686
#ifdef WITH_WSREP
87+
#include "wsrep_mysqld.h" /* wsrep_append_table_keys() */
8788
#include "wsrep_trans_observer.h" /* wsrep_start_transction() */
8889
#endif /* WITH_WSREP */
8990

@@ -4802,17 +4803,13 @@ bool select_create::send_eof()
48024803
thd->wsrep_trx_id(), thd->thread_id, thd->query_id);
48034804

48044805
/*
4805-
append table level exclusive key for CTAS
4806+
For CTAS, append table level exclusive key for created table
4807+
and table level shared key for selected table.
48064808
*/
4807-
wsrep_key_arr_t key_arr= {0, 0};
4808-
wsrep_prepare_keys_for_isolation(thd,
4809-
create_table->db.str,
4810-
create_table->table_name.str,
4811-
table_list,
4812-
&key_arr);
4813-
int rcode= wsrep_thd_append_key(thd, key_arr.keys, key_arr.keys_len,
4814-
WSREP_SERVICE_KEY_EXCLUSIVE);
4815-
wsrep_keys_free(&key_arr);
4809+
int rcode= wsrep_append_table_keys(thd, create_table, table_list,
4810+
WSREP_SERVICE_KEY_EXCLUSIVE);
4811+
rcode= rcode || wsrep_append_table_keys(thd, nullptr, select_tables,
4812+
WSREP_SERVICE_KEY_SHARED);
48164813
if (rcode)
48174814
{
48184815
DBUG_PRINT("wsrep", ("row key failed: %d", rcode));

sql/sql_table.cc

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11634,8 +11634,18 @@ bool Sql_cmd_create_table_like::execute(THD *thd)
1163411634
Alter_info alter_info(lex->alter_info, thd->mem_root);
1163511635

1163611636
#ifdef WITH_WSREP
11637+
bool wsrep_ctas= false;
1163711638
// If CREATE TABLE AS SELECT and wsrep_on
11638-
const bool wsrep_ctas= (select_lex->item_list.elements && WSREP(thd));
11639+
if (WSREP(thd) && (select_lex->item_list.elements ||
11640+
// Only CTAS may be applied not using TOI.
11641+
(wsrep_thd_is_applying(thd) && !wsrep_thd_is_toi(thd))))
11642+
{
11643+
wsrep_ctas= true;
11644+
11645+
// MDEV-22232: Disable CTAS retry by setting the retry counter to the
11646+
// threshold value.
11647+
thd->wsrep_retry_counter= thd->variables.wsrep_retry_autocommit;
11648+
}
1163911649

1164011650
// This will be used in THD::decide_logging_format if CTAS
1164111651
Enable_wsrep_ctas_guard wsrep_ctas_guard(thd, wsrep_ctas);

sql/wsrep_client_service.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,13 @@ enum wsrep::provider::status Wsrep_client_service::replay()
283283
original THD state during replication event applying.
284284
*/
285285
THD *replayer_thd= new THD(true, true);
286+
// Replace the security context of the replayer with the security context
287+
// of the original THD. Since security context class doesn't have proper
288+
// copy constructors, we need to store the original one and set it back
289+
// before destruction so that THD desctruction doesn't cause double-free
290+
// on the replaced security context.
291+
Security_context old_ctx = replayer_thd->main_security_ctx;
292+
replayer_thd->main_security_ctx = m_thd->main_security_ctx;
286293
replayer_thd->thread_stack= m_thd->thread_stack;
287294
replayer_thd->real_id= pthread_self();
288295
replayer_thd->prior_thr_create_utime=
@@ -299,6 +306,7 @@ enum wsrep::provider::status Wsrep_client_service::replay()
299306
replayer_service.replay_status(ret);
300307
}
301308

309+
replayer_thd->main_security_ctx = old_ctx;
302310
delete replayer_thd;
303311
DBUG_RETURN(ret);
304312
}

sql/wsrep_mysqld.cc

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,7 +1266,13 @@ bool wsrep_sync_wait(THD* thd, enum enum_sql_command command)
12661266
return res;
12671267
}
12681268

1269-
void wsrep_keys_free(wsrep_key_arr_t* key_arr)
1269+
typedef struct wsrep_key_arr
1270+
{
1271+
wsrep_key_t* keys;
1272+
size_t keys_len;
1273+
} wsrep_key_arr_t;
1274+
1275+
static void wsrep_keys_free(wsrep_key_arr_t* key_arr)
12701276
{
12711277
for (size_t i= 0; i < key_arr->keys_len; ++i)
12721278
{
@@ -1516,18 +1522,30 @@ static bool wsrep_prepare_keys_for_isolation(THD* thd,
15161522
}
15171523

15181524
/*
1519-
* Prepare key list from db/table and table_list
1525+
* Prepare key list from db/table and table_list and append it to Wsrep
1526+
* with the given key type.
15201527
*
15211528
* Return zero in case of success, 1 in case of failure.
15221529
*/
1523-
1524-
bool wsrep_prepare_keys_for_isolation(THD* thd,
1525-
const char* db,
1526-
const char* table,
1527-
const TABLE_LIST* table_list,
1528-
wsrep_key_arr_t* ka)
1529-
{
1530-
return wsrep_prepare_keys_for_isolation(thd, db, table, table_list, NULL, ka);
1530+
int wsrep_append_table_keys(THD* thd,
1531+
TABLE_LIST* first_table,
1532+
TABLE_LIST* table_list,
1533+
Wsrep_service_key_type key_type)
1534+
{
1535+
wsrep_key_arr_t key_arr= {0, 0};
1536+
const char* db_name= first_table ? first_table->db.str : NULL;
1537+
const char* table_name= first_table ? first_table->table_name.str : NULL;
1538+
int rcode= wsrep_prepare_keys_for_isolation(thd, db_name, table_name,
1539+
table_list, NULL, &key_arr);
1540+
1541+
if (!rcode && key_arr.keys_len)
1542+
{
1543+
rcode= wsrep_thd_append_key(thd, key_arr.keys,
1544+
key_arr.keys_len, key_type);
1545+
}
1546+
1547+
wsrep_keys_free(&key_arr);
1548+
return rcode;
15311549
}
15321550

15331551
bool wsrep_prepare_key(const uchar* cache_key, size_t cache_key_len,

sql/wsrep_mysqld.h

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -347,17 +347,10 @@ int wsrep_must_ignore_error(THD* thd);
347347

348348
bool wsrep_replicate_GTID(THD* thd);
349349

350-
typedef struct wsrep_key_arr
351-
{
352-
wsrep_key_t* keys;
353-
size_t keys_len;
354-
} wsrep_key_arr_t;
355-
bool wsrep_prepare_keys_for_isolation(THD* thd,
356-
const char* db,
357-
const char* table,
358-
const TABLE_LIST* table_list,
359-
wsrep_key_arr_t* ka);
360-
void wsrep_keys_free(wsrep_key_arr_t* key_arr);
350+
int wsrep_append_table_keys(THD* thd,
351+
TABLE_LIST* first_table,
352+
TABLE_LIST* table_list,
353+
Wsrep_service_key_type key_type);
361354

362355
extern void
363356
wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,

0 commit comments

Comments
 (0)