Skip to content

Commit c08853f

Browse files
committed
Bug#31236217 : NOT HANDLING ERROR RETURNED FROM DDL_LOG_TABLE::INSERT MIGHT
BREAK ATOMIC DDL Issue: If there is an error while inserting log in ddl_log table, then returned error was lost and not returned. So impression is that ddl_log is inserted but it actually is not. Fix: Handle returned error in above scenario and return error to run the DDL. Fixed issue where trx wasn't registered while doing tablespace encryption RB : 24387 reviewed by : Kevin Lewis <[email protected]>
1 parent 7461802 commit c08853f

File tree

7 files changed

+144
-28
lines changed

7 files changed

+144
-28
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Setup
2+
CREATE TABLE t1 (c1 INT);
3+
CREATE TABLESPACE my_ts ADD DATAFILE "my_ts.ibd";
4+
SET SESSION DEBUG="+d,ddl_log_return_error_from_insert";
5+
# Run few DDLs. All DDLs should give error now.
6+
ALTER TABLE t1 RENAME to t2;
7+
ERROR HY000: Error on rename of './test/t1' to './test/t2' (errno: 168 - Unknown (generic) error from engine)
8+
ALTER TABLE t1 ADD COLUMN c2 INT, ALGORITHM=COPY;
9+
ERROR HY000: Got error 168 - 'Unknown (generic) error from engine' from storage engine
10+
ALTER TABLE t1 ADD COLUMN c2 INT, ALGORITHM=INPLACE;
11+
ERROR HY000: Got error 11 - 'InnoDB error' from storage engine
12+
DROP TABLE t1;
13+
ERROR HY000: Storage engine can't drop table 'test.t1'
14+
SET SESSION DEBUG="-d,ddl_log_return_error_from_insert";
15+
# Restart with keyring plugin
16+
SET SESSION DEBUG="+d,ddl_log_return_error_from_insert";
17+
ALTER TABLESPACE my_ts ENCRYPTION='Y';
18+
ERROR HY000: Failed to alter: TABLESPACE my_ts
19+
SET SESSION DEBUG="-d,ddl_log_return_error_from_insert";
20+
# Cleanup
21+
DROP TABLE t1;
22+
# Restarting server without keyring to restore server state
23+
# restart:

mysql-test/suite/innodb/r/sdi_fail.result

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ t1 CREATE TABLE `t1` (
1212
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1313
SET DEBUG='+d,ib_create_table_fail_too_many_trx';
1414
ALTER TABLE t1 ADD INDEX (c2), ADD INDEX (c3);
15-
ERROR HY000: Failed to delete SDI 'test.t1' in tablespace 'test/t1'.
15+
ERROR HY000: Too many active concurrent transactions
1616
SET DEBUG='-d,ib_create_table_fail_too_many_trx';
1717
drop table t1;
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#
2+
# BUG#31236217 : NOT HANDLING ERROR RETURNED FROM DDL_LOG_TABLE::INSERT MIGHT
3+
# BREAK ATOMIC DDL
4+
#
5+
6+
--source include/have_debug.inc
7+
8+
--disable_query_log
9+
call mtr.add_suppression("\\[Error\\] \\[[^]]*\\] \\[[^]]*\\] Couldn't insert entry in ddl log for ddl.");
10+
call mtr.add_suppression("\\[Error\\] \\[[^]]*\\] \\[[^]]*\\] Couldn't write DDL LOG for");
11+
--enable_query_log
12+
13+
--echo # Setup
14+
CREATE TABLE t1 (c1 INT);
15+
CREATE TABLESPACE my_ts ADD DATAFILE "my_ts.ibd";
16+
17+
# Return error from insert into ddl_log
18+
SET SESSION DEBUG="+d,ddl_log_return_error_from_insert";
19+
20+
--echo # Run few DDLs. All DDLs should give error now.
21+
22+
--error ER_ERROR_ON_RENAME
23+
ALTER TABLE t1 RENAME to t2;
24+
25+
--error ER_GET_ERRNO
26+
ALTER TABLE t1 ADD COLUMN c2 INT, ALGORITHM=COPY;
27+
28+
--error ER_GET_ERRNO
29+
ALTER TABLE t1 ADD COLUMN c2 INT, ALGORITHM=INPLACE;
30+
31+
--error ER_ENGINE_CANT_DROP_TABLE
32+
DROP TABLE t1;
33+
34+
SET SESSION DEBUG="-d,ddl_log_return_error_from_insert";
35+
36+
37+
--echo # Restart with keyring plugin
38+
let $restart_parameters = restart: --early-plugin-load=keyring_file=$KEYRING_PLUGIN --loose-keyring_file_data=$MYSQL_TMP_DIR/mysecret_keyring $KEYRING_PLUGIN_OPT;
39+
--source include/restart_mysqld_no_echo.inc
40+
41+
# Return error from insert into ddl_log
42+
SET SESSION DEBUG="+d,ddl_log_return_error_from_insert";
43+
44+
--error ER_ALTER_FILEGROUP_FAILED
45+
ALTER TABLESPACE my_ts ENCRYPTION='Y';
46+
47+
SET SESSION DEBUG="-d,ddl_log_return_error_from_insert";
48+
49+
--echo # Cleanup
50+
DROP TABLE t1;
51+
remove_file $MYSQL_TMP_DIR/mysecret_keyring;
52+
53+
--echo # Restarting server without keyring to restore server state
54+
let $restart_parameters = restart: ;
55+
--source include/restart_mysqld.inc

mysql-test/suite/innodb/t/sdi_fail.test

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@
77
--disable_query_log
88
call mtr.add_suppression("sdi_delete failed: tablespace_id:");
99
call mtr.add_suppression("Cannot save table statistics for table");
10+
call mtr.add_suppression("\\[Error\\] \\[[^]]*\\] \\[[^]]*\\] Couldn't insert entry in ddl log for ddl.");
1011
--enable_query_log
1112

1213
create table t1(c1 int primary key, c2 char(1), c3 int unsigned);
1314
show create table t1;
1415

1516
SET DEBUG='+d,ib_create_table_fail_too_many_trx';
1617

17-
--error ER_SDI_OPERATION_FAILED,
18+
--error ER_TOO_MANY_CONCURRENT_TRXS
1819
ALTER TABLE t1 ADD INDEX (c2), ADD INDEX (c3);
1920

2021
SET DEBUG='-d,ib_create_table_fail_too_many_trx';

share/messages_to_error_log.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10910,6 +10910,10 @@ ER_AUTHCACHE_DEFAULT_ROLES_IGNORED_EMPTY_NAME
1091010910

1091110911
ER_AUTHCACHE_DEFAULT_ROLES_UNKNOWN_AUTHORIZATION_ID
1091210912
eng "Found an entry in the 'default_roles' table with unknown authorization ID '%s'; Skipped"
10913+
10914+
ER_IB_ERR_DDL_LOG_INSERT_FAILURE
10915+
eng "Couldn't insert entry in ddl log for ddl."
10916+
1091310917
# DO NOT add server-to-client messages here;
1091410918
# they go in messages_to_clients.txt
1091510919
# in the same directory as this file.

storage/innobase/handler/ha_innodb.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15017,6 +15017,8 @@ static int innobase_alter_encrypt_tablespace(handlerton *hton, THD *thd,
1501715017

1501815018
/* Get the transaction associated with the current thd */
1501915019
trx = check_trx_exists(thd);
15020+
innobase_register_trx(hton, thd, trx);
15021+
1502015022
trx_start_if_not_started(trx, true);
1502115023

1502215024
/* Make an entry in DDL LOG for this tablespace. */

storage/innobase/log/log0ddl.cc

Lines changed: 57 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*****************************************************************************
22
3-
Copyright (c) 2017, 2019, Oracle and/or its affiliates. All Rights Reserved.
3+
Copyright (c) 2017, 2020, Oracle and/or its affiliates.
44
55
Portions of this file contain modifications contributed and copyrighted by
66
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -470,15 +470,32 @@ dberr_t DDL_Log_Table::insert(const DDL_Record &record) {
470470
create_tuple(record);
471471
entry = row_build_index_entry(m_tuple, nullptr, index, m_heap);
472472

473-
error = row_ins_clust_index_entry_low(flags, BTR_MODIFY_LEAF, index,
474-
index->n_uniq, entry, m_thr, false);
473+
#ifdef UNIV_DEBUG
474+
bool insert = true;
475+
DBUG_EXECUTE_IF("ddl_log_return_error_from_insert", insert = false;);
476+
477+
if (insert) {
478+
#endif
479+
error = row_ins_clust_index_entry_low(flags, BTR_MODIFY_LEAF, index,
480+
index->n_uniq, entry, m_thr, false);
481+
#ifdef UNIV_DEBUG
482+
} else {
483+
error = DB_ERROR;
484+
}
485+
#endif
475486

476487
if (error == DB_FAIL) {
477488
error = row_ins_clust_index_entry_low(flags, BTR_MODIFY_TREE, index,
478489
index->n_uniq, entry, m_thr, false);
479490
ut_ad(error == DB_SUCCESS);
480491
}
481492

493+
if (error != DB_SUCCESS) {
494+
ib::error(ER_IB_ERR_DDL_LOG_INSERT_FAILURE);
495+
mem_heap_free(offsets_heap);
496+
return error;
497+
}
498+
482499
index = index->next();
483500

484501
entry = row_build_index_entry(m_tuple, nullptr, index, m_heap);
@@ -860,15 +877,19 @@ dberr_t Log_DDL::write_free_tree_log(trx_t *trx, const dict_index_t *index,
860877
if (is_drop_table) {
861878
/* Drop index case, if committed, will be redo only */
862879
err = insert_free_tree_log(trx, index, id, thread_id);
863-
ut_ad(err == DB_SUCCESS);
880+
if (err != DB_SUCCESS) {
881+
return err;
882+
}
864883

865884
DBUG_INJECT_CRASH("ddl_log_crash_after_free_tree_log",
866885
crash_after_free_tree_log_counter++);
867886
} else {
868887
/* This is the case of building index during create table
869888
scenario. The index will be dropped if ddl is rolled back */
870889
err = insert_free_tree_log(nullptr, index, id, thread_id);
871-
ut_ad(err == DB_SUCCESS);
890+
if (err != DB_SUCCESS) {
891+
return err;
892+
}
872893

873894
DBUG_INJECT_CRASH("ddl_log_crash_after_free_tree_log",
874895
crash_after_free_tree_log_counter++);
@@ -917,15 +938,14 @@ dberr_t Log_DDL::insert_free_tree_log(trx_t *trx, const dict_index_t *index,
917938
{
918939
DDL_Log_Table ddl_log(trx);
919940
error = ddl_log.insert(record);
920-
ut_ad(error == DB_SUCCESS);
921941
}
922942

923943
if (!has_dd_trx) {
924944
trx_commit_for_mysql(trx);
925945
trx_free_for_background(trx);
926946
}
927947

928-
if (srv_print_ddl_logs) {
948+
if (error == DB_SUCCESS && srv_print_ddl_logs) {
929949
ib::info(ER_IB_MSG_647) << "DDL log insert : " << record;
930950
}
931951

@@ -955,14 +975,18 @@ dberr_t Log_DDL::write_delete_space_log(trx_t *trx, const dict_table_t *table,
955975
if (is_drop) {
956976
err = insert_delete_space_log(trx, id, thread_id, space_id, file_path,
957977
dict_locked);
958-
ut_ad(err == DB_SUCCESS);
978+
if (err != DB_SUCCESS) {
979+
return err;
980+
}
959981

960982
DBUG_INJECT_CRASH("ddl_log_crash_after_delete_space_log",
961983
crash_after_delete_space_log_counter++);
962984
} else {
963985
err = insert_delete_space_log(nullptr, id, thread_id, space_id, file_path,
964986
dict_locked);
965-
ut_ad(err == DB_SUCCESS);
987+
if (err != DB_SUCCESS) {
988+
return err;
989+
}
966990

967991
DBUG_INJECT_CRASH("ddl_log_crash_after_delete_space_log",
968992
crash_after_delete_space_log_counter++);
@@ -1014,7 +1038,6 @@ dberr_t Log_DDL::insert_delete_space_log(trx_t *trx, uint64_t id,
10141038
{
10151039
DDL_Log_Table ddl_log(trx);
10161040
error = ddl_log.insert(record);
1017-
ut_ad(error == DB_SUCCESS);
10181041
}
10191042

10201043
if (dict_locked) {
@@ -1026,7 +1049,7 @@ dberr_t Log_DDL::insert_delete_space_log(trx_t *trx, uint64_t id,
10261049
trx_free_for_background(trx);
10271050
}
10281051

1029-
if (srv_print_ddl_logs) {
1052+
if (error == DB_SUCCESS && srv_print_ddl_logs) {
10301053
ib::info(ER_IB_MSG_648) << "DDL log insert : " << record;
10311054
}
10321055

@@ -1062,11 +1085,16 @@ dberr_t Log_DDL::write_rename_space_log(space_id_t space_id,
10621085

10631086
dberr_t err = insert_rename_space_log(id, thread_id, space_id, old_file_path,
10641087
new_file_path);
1065-
ut_ad(err == DB_SUCCESS);
1088+
if (err != DB_SUCCESS) {
1089+
return err;
1090+
}
10661091

10671092
DBUG_INJECT_CRASH("ddl_log_crash_after_rename_space_log",
10681093
crash_after_rename_space_log_counter++);
10691094

1095+
DBUG_EXECUTE_IF("ddl_log_crash_after_rename_space_log_insert",
1096+
DBUG_SUICIDE(););
1097+
10701098
DBUG_EXECUTE_IF("DDL_Log_remove_inject_error_4",
10711099
srv_inject_too_many_concurrent_trxs = true;);
10721100

@@ -1105,15 +1133,14 @@ dberr_t Log_DDL::insert_rename_space_log(uint64_t id, ulint thread_id,
11051133
{
11061134
DDL_Log_Table ddl_log(trx);
11071135
error = ddl_log.insert(record);
1108-
ut_ad(error == DB_SUCCESS);
11091136
}
11101137

11111138
mutex_enter(&dict_sys->mutex);
11121139

11131140
trx_commit_for_mysql(trx);
11141141
trx_free_for_background(trx);
11151142

1116-
if (srv_print_ddl_logs) {
1143+
if (error == DB_SUCCESS && srv_print_ddl_logs) {
11171144
ib::info(ER_IB_MSG_649) << "DDL log insert : " << record;
11181145
}
11191146

@@ -1141,7 +1168,9 @@ dberr_t Log_DDL::write_alter_encrypt_space_log(space_id_t space_id) {
11411168
crash_before_alter_encrypt_space_log_counter++);
11421169

11431170
dberr_t err = insert_alter_encrypt_space_log(id, thread_id, space_id);
1144-
ut_ad(err == DB_SUCCESS);
1171+
if (err != DB_SUCCESS) {
1172+
return err;
1173+
}
11451174

11461175
DBUG_INJECT_CRASH("ddl_log_crash_after_alter_encrypt_space_log",
11471176
crash_after_alter_encrypt_space_log_counter++);
@@ -1168,15 +1197,14 @@ dberr_t Log_DDL::insert_alter_encrypt_space_log(uint64_t id, ulint thread_id,
11681197
{
11691198
DDL_Log_Table ddl_log(trx);
11701199
error = ddl_log.insert(record);
1171-
ut_ad(error == DB_SUCCESS);
11721200
}
11731201

11741202
mutex_enter(&dict_sys->mutex);
11751203

11761204
trx_commit_for_mysql(trx);
11771205
trx_free_for_background(trx);
11781206

1179-
if (srv_print_ddl_logs) {
1207+
if (error == DB_SUCCESS && srv_print_ddl_logs) {
11801208
ib::info(ER_IB_MSG_1284) << "DDL log insert : " << record;
11811209
}
11821210

@@ -1198,7 +1226,9 @@ dberr_t Log_DDL::write_drop_log(trx_t *trx, const table_id_t table_id) {
11981226

11991227
dberr_t err;
12001228
err = insert_drop_log(trx, id, thread_id, table_id);
1201-
ut_ad(err == DB_SUCCESS);
1229+
if (err != DB_SUCCESS) {
1230+
return err;
1231+
}
12021232

12031233
DBUG_INJECT_CRASH("ddl_log_crash_after_drop_log",
12041234
crash_after_drop_log_counter++);
@@ -1225,12 +1255,11 @@ dberr_t Log_DDL::insert_drop_log(trx_t *trx, uint64_t id, ulint thread_id,
12251255
{
12261256
DDL_Log_Table ddl_log(trx);
12271257
error = ddl_log.insert(record);
1228-
ut_ad(error == DB_SUCCESS);
12291258
}
12301259

12311260
mutex_enter(&dict_sys->mutex);
12321261

1233-
if (srv_print_ddl_logs) {
1262+
if (error == DB_SUCCESS && srv_print_ddl_logs) {
12341263
ib::info(ER_IB_MSG_650) << "DDL log insert : " << record;
12351264
}
12361265

@@ -1253,7 +1282,9 @@ dberr_t Log_DDL::write_rename_table_log(dict_table_t *table,
12531282

12541283
dberr_t err =
12551284
insert_rename_table_log(id, thread_id, table->id, old_name, new_name);
1256-
ut_ad(err == DB_SUCCESS);
1285+
if (err != DB_SUCCESS) {
1286+
return err;
1287+
}
12571288

12581289
DBUG_EXECUTE_IF("DDL_Log_remove_inject_error_5",
12591290
srv_inject_too_many_concurrent_trxs = true;);
@@ -1290,15 +1321,14 @@ dberr_t Log_DDL::insert_rename_table_log(uint64_t id, ulint thread_id,
12901321
{
12911322
DDL_Log_Table ddl_log(trx);
12921323
error = ddl_log.insert(record);
1293-
ut_ad(error == DB_SUCCESS);
12941324
}
12951325

12961326
mutex_enter(&dict_sys->mutex);
12971327

12981328
trx_commit_for_mysql(trx);
12991329
trx_free_for_background(trx);
13001330

1301-
if (srv_print_ddl_logs) {
1331+
if (error == DB_SUCCESS && srv_print_ddl_logs) {
13021332
ib::info(ER_IB_MSG_651) << "DDL log insert : " << record;
13031333
}
13041334

@@ -1319,7 +1349,9 @@ dberr_t Log_DDL::write_remove_cache_log(trx_t *trx, dict_table_t *table) {
13191349

13201350
dberr_t err =
13211351
insert_remove_cache_log(id, thread_id, table->id, table->name.m_name);
1322-
ut_ad(err == DB_SUCCESS);
1352+
if (err != DB_SUCCESS) {
1353+
return err;
1354+
}
13231355

13241356
DBUG_EXECUTE_IF("DDL_Log_remove_inject_error_3",
13251357
srv_inject_too_many_concurrent_trxs = true;);
@@ -1351,13 +1383,12 @@ dberr_t Log_DDL::insert_remove_cache_log(uint64_t id, ulint thread_id,
13511383
{
13521384
DDL_Log_Table ddl_log(trx);
13531385
error = ddl_log.insert(record);
1354-
ut_ad(error == DB_SUCCESS);
13551386
}
13561387

13571388
trx_commit_for_mysql(trx);
13581389
trx_free_for_background(trx);
13591390

1360-
if (srv_print_ddl_logs) {
1391+
if (error == DB_SUCCESS && srv_print_ddl_logs) {
13611392
ib::info(ER_IB_MSG_652) << "DDL log insert : " << record;
13621393
}
13631394

0 commit comments

Comments
 (0)