Skip to content

Commit b46fa62

Browse files
committed
MDEV-12352 InnoDB shutdown should not be blocked by a large transaction rollback
row_undo_step(), trx_rollback_active(): Abort the rollback of a recovered ordinary transaction if fast shutdown has been initiated. trx_rollback_resurrected(): Convert an aborted-rollback transaction into a fake XA PREPARE transaction, so that fast shutdown can proceed.
1 parent 6559ba7 commit b46fa62

File tree

8 files changed

+83
-14
lines changed

8 files changed

+83
-14
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ BEGIN;
4545
INSERT INTO t1 (a) SELECT NULL FROM t;
4646
UPDATE t1 SET a=a+100, b=a;
4747
DELETE FROM t1;
48+
INSERT INTO t1(a) SELECT NULL FROM t;
49+
INSERT INTO t1(a) SELECT NULL FROM t1;
50+
INSERT INTO t1(a) SELECT NULL FROM t1;
51+
INSERT INTO t1(a) SELECT NULL FROM t1;
52+
INSERT INTO t1(a) SELECT NULL FROM t1;
4853
SET GLOBAL innodb_flush_log_at_trx_commit=1;
4954
CREATE TABLE u(a SERIAL) ENGINE=INNODB;
5055
# Kill and restart

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ eval DELETE FROM t$c;
3131
dec $c;
3232
}
3333

34+
INSERT INTO t1(a) SELECT NULL FROM t;
35+
INSERT INTO t1(a) SELECT NULL FROM t1;
36+
INSERT INTO t1(a) SELECT NULL FROM t1;
37+
INSERT INTO t1(a) SELECT NULL FROM t1;
38+
INSERT INTO t1(a) SELECT NULL FROM t1;
39+
3440
--connection default
3541
SET GLOBAL innodb_flush_log_at_trx_commit=1;
3642
CREATE TABLE u(a SERIAL) ENGINE=INNODB;

storage/innobase/include/trx0roll.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*****************************************************************************
22
33
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
4+
Copyright (c) 2017, MariaDB Corporation.
45
56
This program is free software; you can redistribute it and/or modify it under
67
the terms of the GNU General Public License as published by the Free Software
@@ -32,7 +33,8 @@ Created 3/26/1996 Heikki Tuuri
3233
#include "mtr0mtr.h"
3334
#include "trx0sys.h"
3435

35-
extern booltrx_rollback_or_clean_is_active;
36+
extern booltrx_rollback_or_clean_is_active;
37+
extern const trx_t*trx_roll_crash_recv_trx;
3638

3739
/*******************************************************************//**
3840
Determines if this transaction is rolling back an incomplete transaction

storage/innobase/row/row0undo.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*****************************************************************************
22
33
Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved.
4+
Copyright (c) 2017, MariaDB Corporation.
45
56
This program is free software; you can redistribute it and/or modify it under
67
the terms of the GNU General Public License as published by the Free Software
@@ -44,6 +45,7 @@ Created 1/8/1997 Heikki Tuuri
4445
#include "row0upd.h"
4546
#include "row0mysql.h"
4647
#include "srv0srv.h"
48+
#include "srv0start.h"
4749

4850
/* How to undo row operations?
4951
(1) For an insert, we have stored a prefix of the clustered index record
@@ -348,6 +350,14 @@ row_undo_step(
348350

349351
ut_ad(que_node_get_type(node) == QUE_NODE_UNDO);
350352

353+
if (UNIV_UNLIKELY(trx == trx_roll_crash_recv_trx)
354+
&& trx_get_dict_operation(trx) == TRX_DICT_OP_NONE
355+
&& !srv_undo_sources && srv_fast_shutdown) {
356+
/* Shutdown has been initiated. */
357+
trx->error_state = DB_INTERRUPTED;
358+
return(NULL);
359+
}
360+
351361
err = row_undo(node, thr);
352362

353363
trx->error_state = err;

storage/innobase/trx/trx0roll.cc

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ rollback */
5555
booltrx_rollback_or_clean_is_active;
5656

5757
/** In crash recovery, the current trx to be rolled back; NULL otherwise */
58-
static const trx_t*trx_roll_crash_recv_trx = NULL;
58+
const trx_t*trx_roll_crash_recv_trx;
5959

6060
/** In crash recovery we set this to the undo n:o of the current trx to be
6161
rolled back. Then we can print how many % the rollback has progressed. */
@@ -605,6 +605,14 @@ trx_rollback_active(
605605

606606
que_run_threads(roll_node->undo_thr);
607607

608+
if (trx->error_state != DB_SUCCESS) {
609+
ut_ad(trx->error_state == DB_INTERRUPTED);
610+
ut_ad(!srv_undo_sources);
611+
ut_ad(srv_fast_shutdown);
612+
ut_ad(!dictionary_locked);
613+
goto func_exit;
614+
}
615+
608616
trx_rollback_finish(thr_get_trx(roll_node->undo_thr));
609617

610618
/* Free the memory reserved by the undo graph */
@@ -649,13 +657,14 @@ trx_rollback_active(
649657
}
650658
}
651659

660+
ib_logf(IB_LOG_LEVEL_INFO,
661+
"Rollback of trx with id " TRX_ID_FMT " completed", trx->id);
662+
663+
func_exit:
652664
if (dictionary_locked) {
653665
row_mysql_unlock_data_dictionary(trx);
654666
}
655667

656-
ib_logf(IB_LOG_LEVEL_INFO,
657-
"Rollback of trx with id " TRX_ID_FMT " completed", trx->id);
658-
659668
mem_heap_free(heap);
660669

661670
trx_roll_crash_recv_trx = NULL;
@@ -700,8 +709,8 @@ trx_rollback_resurrected(
700709
trx_free_for_background(trx);
701710
return(TRUE);
702711
case TRX_STATE_ACTIVE:
703-
if (srv_shutdown_state != SRV_SHUTDOWN_NONE
704-
&& srv_fast_shutdown) {
712+
if (!srv_undo_sources && srv_fast_shutdown) {
713+
fake_prepared:
705714
trx->state = TRX_STATE_PREPARED;
706715
trx_sys->n_prepared_trx++;
707716
trx_sys->n_prepared_recovered_trx++;
@@ -713,6 +722,14 @@ trx_rollback_resurrected(
713722
if (*all || trx_get_dict_operation(trx) != TRX_DICT_OP_NONE) {
714723
mutex_exit(&trx_sys->mutex);
715724
trx_rollback_active(trx);
725+
if (trx->error_state != DB_SUCCESS) {
726+
ut_ad(trx->error_state == DB_INTERRUPTED);
727+
ut_ad(!srv_undo_sources);
728+
ut_ad(srv_fast_shutdown);
729+
mutex_enter(&trx_sys->mutex);
730+
trx_mutex_enter(trx);
731+
goto fake_prepared;
732+
}
716733
trx_free_for_background(trx);
717734
return(TRUE);
718735
}

storage/xtradb/include/trx0roll.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*****************************************************************************
22
33
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
4+
Copyright (c) 2017, MariaDB Corporation.
45
56
This program is free software; you can redistribute it and/or modify it under
67
the terms of the GNU General Public License as published by the Free Software
@@ -33,7 +34,8 @@ Created 3/26/1996 Heikki Tuuri
3334
#include "mtr0mtr.h"
3435
#include "trx0sys.h"
3536

36-
extern booltrx_rollback_or_clean_is_active;
37+
extern booltrx_rollback_or_clean_is_active;
38+
extern const trx_t*trx_roll_crash_recv_trx;
3739

3840
/*******************************************************************//**
3941
Determines if this transaction is rolling back an incomplete transaction

storage/xtradb/row/row0undo.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*****************************************************************************
22
33
Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved.
4+
Copyright (c) 2017, MariaDB Corporation.
45
56
This program is free software; you can redistribute it and/or modify it under
67
the terms of the GNU General Public License as published by the Free Software
@@ -44,6 +45,7 @@ Created 1/8/1997 Heikki Tuuri
4445
#include "row0upd.h"
4546
#include "row0mysql.h"
4647
#include "srv0srv.h"
48+
#include "srv0start.h"
4749

4850
/* How to undo row operations?
4951
(1) For an insert, we have stored a prefix of the clustered index record
@@ -348,6 +350,14 @@ row_undo_step(
348350

349351
ut_ad(que_node_get_type(node) == QUE_NODE_UNDO);
350352

353+
if (UNIV_UNLIKELY(trx == trx_roll_crash_recv_trx)
354+
&& trx_get_dict_operation(trx) == TRX_DICT_OP_NONE
355+
&& !srv_undo_sources && srv_fast_shutdown) {
356+
/* Shutdown has been initiated. */
357+
trx->error_state = DB_INTERRUPTED;
358+
return(NULL);
359+
}
360+
351361
err = row_undo(node, thr);
352362

353363
trx->error_state = err;

storage/xtradb/trx/trx0roll.cc

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ rollback */
5555
booltrx_rollback_or_clean_is_active;
5656

5757
/** In crash recovery, the current trx to be rolled back; NULL otherwise */
58-
static const trx_t*trx_roll_crash_recv_trx = NULL;
58+
const trx_t*trx_roll_crash_recv_trx;
5959

6060
/** In crash recovery we set this to the undo n:o of the current trx to be
6161
rolled back. Then we can print how many % the rollback has progressed. */
@@ -605,6 +605,14 @@ trx_rollback_active(
605605

606606
que_run_threads(roll_node->undo_thr);
607607

608+
if (trx->error_state != DB_SUCCESS) {
609+
ut_ad(trx->error_state == DB_INTERRUPTED);
610+
ut_ad(!srv_undo_sources);
611+
ut_ad(srv_fast_shutdown);
612+
ut_ad(!dictionary_locked);
613+
goto func_exit;
614+
}
615+
608616
trx_rollback_finish(thr_get_trx(roll_node->undo_thr));
609617

610618
/* Free the memory reserved by the undo graph */
@@ -649,13 +657,14 @@ trx_rollback_active(
649657
}
650658
}
651659

660+
ib_logf(IB_LOG_LEVEL_INFO,
661+
"Rollback of trx with id " TRX_ID_FMT " completed", trx->id);
662+
663+
func_exit:
652664
if (dictionary_locked) {
653665
row_mysql_unlock_data_dictionary(trx);
654666
}
655667

656-
ib_logf(IB_LOG_LEVEL_INFO,
657-
"Rollback of trx with id " TRX_ID_FMT " completed", trx->id);
658-
659668
mem_heap_free(heap);
660669

661670
trx_roll_crash_recv_trx = NULL;
@@ -700,8 +709,8 @@ trx_rollback_resurrected(
700709
trx_free_for_background(trx);
701710
return(TRUE);
702711
case TRX_STATE_ACTIVE:
703-
if (srv_shutdown_state != SRV_SHUTDOWN_NONE
704-
&& srv_fast_shutdown) {
712+
if (!srv_undo_sources && srv_fast_shutdown) {
713+
fake_prepared:
705714
trx->state = TRX_STATE_PREPARED;
706715
trx_sys->n_prepared_trx++;
707716
trx_sys->n_prepared_recovered_trx++;
@@ -713,6 +722,14 @@ trx_rollback_resurrected(
713722
if (*all || trx_get_dict_operation(trx) != TRX_DICT_OP_NONE) {
714723
mutex_exit(&trx_sys->mutex);
715724
trx_rollback_active(trx);
725+
if (trx->error_state != DB_SUCCESS) {
726+
ut_ad(trx->error_state == DB_INTERRUPTED);
727+
ut_ad(!srv_undo_sources);
728+
ut_ad(srv_fast_shutdown);
729+
mutex_enter(&trx_sys->mutex);
730+
trx_mutex_enter(trx);
731+
goto fake_prepared;
732+
}
716733
trx_free_for_background(trx);
717734
return(TRUE);
718735
}

0 commit comments

Comments
 (0)