Skip to content

Commit 7b9486d

Browse files
committed
MDEV-14693 XA: Assertion `!clust_index->online_log' failed in rollback_inplace_alter_table
ha_innobase::commit_inplace_alter_table(): Defer the freeing of ctx->trx until after the operation has been successfully committed. In this way, rollback on a partitioned table will be possible. rollback_inplace_alter_table(): Handle ctx->new_table == NULL when ctx->trx != NULL.
1 parent 3c07ed1 commit 7b9486d

File tree

4 files changed

+104
-46
lines changed

4 files changed

+104
-46
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#
2+
# MDEV-14693 XA: Assertion `!clust_index->online_log' failed
3+
# in rollback_inplace_alter_table
4+
#
5+
CREATE TABLE t1 (a INT, b INT) ENGINE=InnoDB PARTITION BY HASH(a) PARTITIONS 2;
6+
XA START 'xid';
7+
INSERT INTO t1 VALUES (1,10);
8+
CREATE DATABASE IF NOT EXISTS db;
9+
ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the ACTIVE state
10+
SET innodb_lock_wait_timeout= 1, lock_wait_timeout= 2;
11+
ALTER TABLE t1 FORCE;
12+
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
13+
XA END 'xid';
14+
XA ROLLBACK 'xid';
15+
DROP TABLE t1;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
--source include/have_innodb.inc
2+
--source include/have_partition.inc
3+
4+
--echo #
5+
--echo # MDEV-14693 XA: Assertion `!clust_index->online_log' failed
6+
--echo # in rollback_inplace_alter_table
7+
--echo #
8+
9+
# A bug in meta-data locking (MDL) for XA transactions causes
10+
# a bug in InnoDB error handling for ALTER TABLE to be triggered.
11+
CREATE TABLE t1 (a INT, b INT) ENGINE=InnoDB PARTITION BY HASH(a) PARTITIONS 2;
12+
XA START 'xid';
13+
INSERT INTO t1 VALUES (1,10);
14+
# XA bug: The following releases the MDL on t1!
15+
--error ER_XAER_RMFAIL
16+
CREATE DATABASE IF NOT EXISTS db;
17+
18+
--connect (con1,localhost,root,,test)
19+
SET innodb_lock_wait_timeout= 1, lock_wait_timeout= 2;
20+
# Here, innodb_lock_wait_timeout would be exceeded, causing the operation
21+
# to roll back when InnoDB is attempting to commit.
22+
# (Instead, lock_wait_timeout should be exceeded!)
23+
--error ER_LOCK_WAIT_TIMEOUT
24+
ALTER TABLE t1 FORCE;
25+
26+
# Cleanup
27+
--disconnect con1
28+
--connection default
29+
XA END 'xid';
30+
XA ROLLBACK 'xid';
31+
DROP TABLE t1;

storage/innobase/handler/handler0alter.cc

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4296,12 +4296,16 @@ rollback_inplace_alter_table(
42964296
row_mysql_lock_data_dictionary(ctx->trx);
42974297

42984298
if (ctx->need_rebuild()) {
4299-
dberr_t err;
4300-
ulint flags = ctx->new_table->flags;
4301-
43024299
/* DML threads can access ctx->new_table via the
43034300
online rebuild log. Free it first. */
43044301
innobase_online_rebuild_log_free(prebuilt->table);
4302+
}
4303+
4304+
if (!ctx->new_table) {
4305+
ut_ad(ctx->need_rebuild());
4306+
} else if (ctx->need_rebuild()) {
4307+
dberr_t err;
4308+
ulint flags = ctx->new_table->flags;
43054309

43064310
/* Since the FTS index specific auxiliary tables has
43074311
not yet registered with "table->fts" by fts_add_index(),
@@ -5669,21 +5673,6 @@ ha_innobase::commit_inplace_alter_table(
56695673
ut_ad(prebuilt->table == ctx0->old_table);
56705674
ha_alter_info->group_commit_ctx = NULL;
56715675

5672-
/* Free the ctx->trx of other partitions, if any. We will only
5673-
use the ctx0->trx here. Others may have been allocated in
5674-
the prepare stage. */
5675-
5676-
for (inplace_alter_handler_ctx** pctx = &ctx_array[1]; *pctx;
5677-
pctx++) {
5678-
ha_innobase_inplace_ctx* ctx
5679-
= static_cast<ha_innobase_inplace_ctx*>(*pctx);
5680-
5681-
if (ctx->trx) {
5682-
trx_free_for_mysql(ctx->trx);
5683-
ctx->trx = NULL;
5684-
}
5685-
}
5686-
56875676
trx_start_if_not_started_xa(prebuilt->trx);
56885677

56895678
for (inplace_alter_handler_ctx** pctx = ctx_array; *pctx; pctx++) {
@@ -6056,10 +6045,6 @@ ha_innobase::commit_inplace_alter_table(
60566045
covering all partitions. */
60576046
share->idx_trans_tbl.index_count = 0;
60586047

6059-
if (trx == ctx0->trx) {
6060-
ctx0->trx = NULL;
6061-
}
6062-
60636048
/* Tell the InnoDB server that there might be work for
60646049
utility threads: */
60656050

@@ -6082,10 +6067,31 @@ ha_innobase::commit_inplace_alter_table(
60826067
}
60836068

60846069
row_mysql_unlock_data_dictionary(trx);
6085-
trx_free_for_mysql(trx);
6070+
if (trx != ctx0->trx) {
6071+
trx_free_for_mysql(trx);
6072+
}
60866073
DBUG_RETURN(true);
60876074
}
60886075

6076+
if (trx == ctx0->trx) {
6077+
ctx0->trx = NULL;
6078+
}
6079+
6080+
/* Free the ctx->trx of other partitions, if any. We will only
6081+
use the ctx0->trx here. Others may have been allocated in
6082+
the prepare stage. */
6083+
6084+
for (inplace_alter_handler_ctx** pctx = &ctx_array[1]; *pctx;
6085+
pctx++) {
6086+
ha_innobase_inplace_ctx* ctx
6087+
= static_cast<ha_innobase_inplace_ctx*>(*pctx);
6088+
6089+
if (ctx->trx) {
6090+
trx_free_for_mysql(ctx->trx);
6091+
ctx->trx = NULL;
6092+
}
6093+
}
6094+
60896095
/* Release the table locks. */
60906096
trx_commit_for_mysql(prebuilt->trx);
60916097

storage/xtradb/handler/handler0alter.cc

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4310,12 +4310,16 @@ rollback_inplace_alter_table(
43104310
row_mysql_lock_data_dictionary(ctx->trx);
43114311

43124312
if (ctx->need_rebuild()) {
4313-
dberr_t err;
4314-
ulint flags = ctx->new_table->flags;
4315-
43164313
/* DML threads can access ctx->new_table via the
43174314
online rebuild log. Free it first. */
43184315
innobase_online_rebuild_log_free(prebuilt->table);
4316+
}
4317+
4318+
if (!ctx->new_table) {
4319+
ut_ad(ctx->need_rebuild());
4320+
} else if (ctx->need_rebuild()) {
4321+
dberr_t err;
4322+
ulint flags = ctx->new_table->flags;
43194323

43204324
/* Since the FTS index specific auxiliary tables has
43214325
not yet registered with "table->fts" by fts_add_index(),
@@ -5677,21 +5681,6 @@ ha_innobase::commit_inplace_alter_table(
56775681
ut_ad(prebuilt->table == ctx0->old_table);
56785682
ha_alter_info->group_commit_ctx = NULL;
56795683

5680-
/* Free the ctx->trx of other partitions, if any. We will only
5681-
use the ctx0->trx here. Others may have been allocated in
5682-
the prepare stage. */
5683-
5684-
for (inplace_alter_handler_ctx** pctx = &ctx_array[1]; *pctx;
5685-
pctx++) {
5686-
ha_innobase_inplace_ctx* ctx
5687-
= static_cast<ha_innobase_inplace_ctx*>(*pctx);
5688-
5689-
if (ctx->trx) {
5690-
trx_free_for_mysql(ctx->trx);
5691-
ctx->trx = NULL;
5692-
}
5693-
}
5694-
56955684
trx_start_if_not_started_xa(prebuilt->trx);
56965685

56975686
for (inplace_alter_handler_ctx** pctx = ctx_array; *pctx; pctx++) {
@@ -6057,10 +6046,6 @@ ha_innobase::commit_inplace_alter_table(
60576046
covering all partitions. */
60586047
share->idx_trans_tbl.index_count = 0;
60596048

6060-
if (trx == ctx0->trx) {
6061-
ctx0->trx = NULL;
6062-
}
6063-
60646049
/* Tell the InnoDB server that there might be work for
60656050
utility threads: */
60666051

@@ -6083,10 +6068,31 @@ ha_innobase::commit_inplace_alter_table(
60836068
}
60846069

60856070
row_mysql_unlock_data_dictionary(trx);
6086-
trx_free_for_mysql(trx);
6071+
if (trx != ctx0->trx) {
6072+
trx_free_for_mysql(trx);
6073+
}
60876074
DBUG_RETURN(true);
60886075
}
60896076

6077+
if (trx == ctx0->trx) {
6078+
ctx0->trx = NULL;
6079+
}
6080+
6081+
/* Free the ctx->trx of other partitions, if any. We will only
6082+
use the ctx0->trx here. Others may have been allocated in
6083+
the prepare stage. */
6084+
6085+
for (inplace_alter_handler_ctx** pctx = &ctx_array[1]; *pctx;
6086+
pctx++) {
6087+
ha_innobase_inplace_ctx* ctx
6088+
= static_cast<ha_innobase_inplace_ctx*>(*pctx);
6089+
6090+
if (ctx->trx) {
6091+
trx_free_for_mysql(ctx->trx);
6092+
ctx->trx = NULL;
6093+
}
6094+
}
6095+
60906096
/* Release the table locks. */
60916097
trx_commit_for_mysql(prebuilt->trx);
60926098

0 commit comments

Comments
 (0)