Commit dd127799 authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-15832 With innodb_fast_shutdown=3, skip the rollback of connected transactions

row_undo_step(): If innodb_fast_shutdown=3 has been requested,
abort the rollback of any non-DDL transactions. Starting with
MDEV-12323, we aborted the rollback of recovered transactions. The
transactions would be rolled back on subsequent server startup.

trx_roll_report_progress(): Renamed from trx_roll_must_shutdown(),
now that the shutdown check has been moved to the only caller.

trx_commit_low(): Allow mtr=NULL for transactions that are aborted
on rollback.

trx_rollback_finish(): Clean up aborted transactions to avoid
assertion failures and memory leaks on shutdown. This code was
previously in trx_rollback_active().

trx_rollback_to_savepoint_low(), trx_rollback_for_mysql_low():
Remove some redundant assertions.
parent 8334aced
......@@ -28,6 +28,7 @@ COUNT(*)
1
START TRANSACTION;
connection default;
SET GLOBAL innodb_fast_shutdown=3;
SELECT COUNT(*) FROM worklog5743;
COUNT(*)
1
......@@ -53,6 +54,7 @@ worklog5743;
col_1_text = REPEAT("a", 3500) col_2_text = REPEAT("o", 3500)
1 1
connection default;
SET GLOBAL innodb_fast_shutdown=3;
SELECT COUNT(*) FROM worklog5743;
COUNT(*)
1
......@@ -76,6 +78,7 @@ worklog5743;
col_1_text = REPEAT("b", 3500) col_2_text = REPEAT("o", 3500)
1 1
connection default;
SET GLOBAL innodb_fast_shutdown=3;
SELECT COUNT(*) FROM worklog5743;
COUNT(*)
1
......
......@@ -49,6 +49,7 @@ START TRANSACTION;
--connection default
# Restart the server
SET GLOBAL innodb_fast_shutdown=3;
-- source include/restart_mysqld.inc
SELECT COUNT(*) FROM worklog5743;
SELECT col_1_text = REPEAT("a", 3500) , col_2_text = REPEAT("o", 3500) FROM
......@@ -69,6 +70,7 @@ worklog5743;
--connection default
# Restart the server
SET GLOBAL innodb_fast_shutdown=3;
-- source include/restart_mysqld.inc
SELECT COUNT(*) FROM worklog5743;
SELECT col_1_text = REPEAT("a", 3500) , col_2_text = REPEAT("o", 3500) FROM
......@@ -87,6 +89,7 @@ worklog5743;
--connection default
# Restart the server
SET GLOBAL innodb_fast_shutdown=3;
-- source include/restart_mysqld.inc
SELECT COUNT(*) FROM worklog5743;
SELECT col_1_text = REPEAT("a", 3500) , col_2_text = REPEAT("o", 3500) FROM
......
......@@ -33,6 +33,10 @@ SET @@global.innodb_fast_shutdown = 2;
SELECT @@global.innodb_fast_shutdown;
@@global.innodb_fast_shutdown
2
SET @@global.innodb_fast_shutdown = 3;
SELECT @@global.innodb_fast_shutdown;
@@global.innodb_fast_shutdown
3
'#--------------------FN_DYNVARS_042_04-------------------------#'
SET @@global.innodb_fast_shutdown = -1;
Warnings:
......
......@@ -882,9 +882,9 @@ GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 1
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE INT UNSIGNED
VARIABLE_COMMENT Speeds up the shutdown process of the InnoDB storage engine. Possible values are 0, 1 (faster) or 2 (fastest - crash-like).
VARIABLE_COMMENT Speeds up the shutdown process of the InnoDB storage engine. Possible values are 0, 1 (faster), 2 (crash-like), 3 (fastest clean).
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 2
NUMERIC_MAX_VALUE 3
NUMERIC_BLOCK_SIZE 0
ENUM_VALUE_LIST NULL
READ_ONLY NO
......
......@@ -5,7 +5,7 @@
# Access Type: Dynamic #
# Data Type: numeric #
# Default Value: 1 #
# Valid Values: 0,1,2 #
# Valid Values: 0,1,2,3 #
# #
# #
# Creation Date: 2008-02-20 #
......@@ -81,6 +81,8 @@ SELECT @@global.innodb_fast_shutdown;
SET @@global.innodb_fast_shutdown = 2;
SELECT @@global.innodb_fast_shutdown;
SET @@global.innodb_fast_shutdown = 3;
SELECT @@global.innodb_fast_shutdown;
--echo '#--------------------FN_DYNVARS_042_04-------------------------#'
###########################################################################
......
......@@ -19424,8 +19424,8 @@ static MYSQL_SYSVAR_ULONG(sync_array_size, srv_sync_array_size,
static MYSQL_SYSVAR_UINT(fast_shutdown, srv_fast_shutdown,
PLUGIN_VAR_OPCMDARG,
"Speeds up the shutdown process of the InnoDB storage engine. Possible"
" values are 0, 1 (faster) or 2 (fastest - crash-like).",
fast_shutdown_validate, NULL, 1, 0, 2, 0);
" values are 0, 1 (faster), 2 (crash-like), 3 (fastest clean).",
fast_shutdown_validate, NULL, 1, 0, 3, 0);
static MYSQL_SYSVAR_BOOL(file_per_table, srv_file_per_table,
PLUGIN_VAR_NOCMDARG,
......
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015, 2017, MariaDB Corporation.
Copyright (c) 2015, 2018, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
......@@ -63,10 +63,8 @@ trx_undo_rec_t*
trx_roll_pop_top_rec_of_trx(trx_t* trx, roll_ptr_t* roll_ptr, mem_heap_t* heap)
MY_ATTRIBUTE((nonnull, warn_unused_result));
/** Report progress when rolling back a row of a recovered transaction.
@return whether the rollback should be aborted due to pending shutdown */
bool
trx_roll_must_shutdown();
/** Report progress when rolling back a row of a recovered transaction. */
void trx_roll_report_progress();
/*******************************************************************//**
Rollback or clean up any incomplete transactions which were
encountered in crash recovery. If the transaction already was
......
......@@ -203,14 +203,10 @@ trx_commit(
/*=======*/
trx_t* trx); /*!< in/out: transaction */
/****************************************************************//**
Commits a transaction and a mini-transaction. */
void
trx_commit_low(
/*===========*/
trx_t* trx, /*!< in/out: transaction */
mtr_t* mtr); /*!< in/out: mini-transaction (will be committed),
or NULL if trx made no modifications */
/** Commit a transaction and a mini-transaction.
@param[in,out] trx transaction
@param[in,out] mtr mini-transaction (NULL if no modifications) */
void trx_commit_low(trx_t* trx, mtr_t* mtr);
/**********************************************************************//**
Does the transaction commit for MySQL.
@return DB_SUCCESS or error number */
......
......@@ -42,6 +42,7 @@ Created 1/8/1997 Heikki Tuuri
#include "row0upd.h"
#include "row0mysql.h"
#include "srv0srv.h"
#include "srv0start.h"
/* How to undo row operations?
(1) For an insert, we have stored a prefix of the clustered index record
......@@ -345,11 +346,17 @@ row_undo_step(
ut_ad(que_node_get_type(node) == QUE_NODE_UNDO);
if (UNIV_UNLIKELY(trx == trx_roll_crash_recv_trx)
&& trx_roll_must_shutdown()) {
if (UNIV_UNLIKELY(trx_get_dict_operation(trx) == TRX_DICT_OP_NONE
&& !srv_undo_sources
&& !srv_is_being_started)
&& (srv_fast_shutdown == 3 || trx == trx_roll_crash_recv_trx)) {
/* Shutdown has been initiated. */
trx->error_state = DB_INTERRUPTED;
return(NULL);
return NULL;
}
if (UNIV_UNLIKELY(trx == trx_roll_crash_recv_trx)) {
trx_roll_report_progress();
}
err = row_undo(node, thr);
......
......@@ -58,13 +58,47 @@ bool trx_rollback_is_active;
/** In crash recovery, the current trx to be rolled back; NULL otherwise */
const trx_t* trx_roll_crash_recv_trx;
/****************************************************************//**
Finishes a transaction rollback. */
static
void
trx_rollback_finish(
/*================*/
trx_t* trx); /*!< in: transaction */
/** Finish transaction rollback.
@param[in,out] trx transaction
@return whether the rollback was completed normally
@retval false if the rollback was aborted by shutdown */
static bool trx_rollback_finish(trx_t* trx)
{
trx->mod_tables.clear();
bool finished = trx->error_state == DB_SUCCESS;
if (UNIV_LIKELY(finished)) {
trx_commit(trx);
} else {
ut_a(trx->error_state == DB_INTERRUPTED);
ut_ad(!srv_is_being_started);
ut_a(!srv_undo_sources);
ut_ad(srv_fast_shutdown);
ut_d(trx->in_rollback = false);
if (trx_undo_t*& undo = trx->rsegs.m_redo.old_insert) {
UT_LIST_REMOVE(trx->rsegs.m_redo.rseg->old_insert_list,
undo);
ut_free(undo);
undo = NULL;
}
if (trx_undo_t*& undo = trx->rsegs.m_redo.undo) {
UT_LIST_REMOVE(trx->rsegs.m_redo.rseg->undo_list,
undo);
ut_free(undo);
undo = NULL;
}
if (trx_undo_t*& undo = trx->rsegs.m_noredo.undo) {
UT_LIST_REMOVE(trx->rsegs.m_noredo.rseg->undo_list,
undo);
ut_free(undo);
undo = NULL;
}
trx_commit_low(trx, NULL);
}
trx->lock.que_state = TRX_QUE_RUNNING;
return finished;
}
/*******************************************************************//**
Rollback a transaction used in MySQL. */
......@@ -119,6 +153,7 @@ trx_rollback_to_savepoint_low(
trx_rollback_finish(trx);
MONITOR_INC(MONITOR_TRX_ROLLBACK);
} else {
ut_a(trx->error_state == DB_SUCCESS);
const undo_no_t limit = savept->least_undo_no;
for (trx_mod_tables_t::iterator i = trx->mod_tables.begin();
i != trx->mod_tables.end(); ) {
......@@ -132,9 +167,6 @@ trx_rollback_to_savepoint_low(
MONITOR_INC(MONITOR_TRX_ROLLBACK_SAVEPOINT);
}
ut_a(trx->error_state == DB_SUCCESS);
ut_a(trx->lock.que_state == TRX_QUE_RUNNING);
mem_heap_free(heap);
/* There might be work for utility threads.*/
......@@ -183,8 +215,6 @@ trx_rollback_for_mysql_low(
trx->op_info = "";
ut_a(trx->error_state == DB_SUCCESS);
return(trx->error_state);
}
......@@ -639,23 +669,14 @@ trx_rollback_active(
que_run_threads(roll_node->undo_thr);
if (trx->error_state != DB_SUCCESS) {
ut_ad(trx->error_state == DB_INTERRUPTED);
ut_ad(!srv_is_being_started);
ut_ad(!srv_undo_sources);
ut_ad(srv_fast_shutdown);
que_graph_free(
static_cast<que_t*>(roll_node->undo_thr->common.parent));
if (UNIV_UNLIKELY(!trx_rollback_finish(trx))) {
ut_ad(!dictionary_locked);
que_graph_free(static_cast<que_t*>(
roll_node->undo_thr->common.parent));
goto func_exit;
}
trx_rollback_finish(thr_get_trx(roll_node->undo_thr));
/* Free the memory reserved by the undo graph */
que_graph_free(static_cast<que_t*>(
roll_node->undo_thr->common.parent));
ut_a(trx->lock.que_state == TRX_QUE_RUNNING);
if (trx_get_dict_operation(trx) != TRX_DICT_OP_NONE
......@@ -718,23 +739,9 @@ static my_bool trx_roll_count_callback(rw_trx_hash_element_t *element,
return 0;
}
/** Report progress when rolling back a row of a recovered transaction.
@return whether the rollback should be aborted due to pending shutdown */
bool
trx_roll_must_shutdown()
/** Report progress when rolling back a row of a recovered transaction. */
void trx_roll_report_progress()
{
const trx_t* trx = trx_roll_crash_recv_trx;
ut_ad(trx);
ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE));
ut_ad(trx->in_rollback);
if (trx_get_dict_operation(trx) == TRX_DICT_OP_NONE
&& !srv_is_being_started
&& !srv_undo_sources && srv_fast_shutdown) {
return true;
}
ib_time_t time = ut_time();
mutex_enter(&recv_sys->mutex);
bool report = recv_sys->report(time);
......@@ -754,7 +761,6 @@ trx_roll_must_shutdown()
sd_notifyf(0, "STATUS=To roll back: " UINT32PF " transactions,"
" " UINT64PF " rows", arg.n_trx, arg.n_rows);
}
return false;
}
......@@ -1114,19 +1120,6 @@ trx_rollback_start(
return(que_fork_start_command(roll_graph));
}
/****************************************************************//**
Finishes a transaction rollback. */
static
void
trx_rollback_finish(
/*================*/
trx_t* trx) /*!< in: transaction */
{
trx->mod_tables.clear();
trx_commit(trx);
trx->lock.que_state = TRX_QUE_RUNNING;
}
/*********************************************************************//**
Creates a rollback command node struct.
@return own: rollback node struct */
......
......@@ -1457,19 +1457,18 @@ trx_commit_in_memory(
srv_wake_purge_thread_if_not_active();
}
/****************************************************************//**
Commits a transaction and a mini-transaction. */
void
trx_commit_low(
/*===========*/
trx_t* trx, /*!< in/out: transaction */
mtr_t* mtr) /*!< in/out: mini-transaction (will be committed),
or NULL if trx made no modifications */
/** Commit a transaction and a mini-transaction.
@param[in,out] trx transaction
@param[in,out] mtr mini-transaction (NULL if no modifications) */
void trx_commit_low(trx_t* trx, mtr_t* mtr)
{
assert_trx_nonlocking_or_in_list(trx);
ut_ad(!trx_state_eq(trx, TRX_STATE_COMMITTED_IN_MEMORY));
ut_ad(!mtr || mtr->is_active());
ut_ad(!mtr == !trx->has_logged_or_recovered());
ut_d(bool aborted = trx->in_rollback
&& trx->error_state == DB_DEADLOCK);
ut_ad(!mtr == (aborted || !trx->has_logged_or_recovered()));
ut_ad(!mtr || !aborted);
/* undo_no is non-zero if we're doing the final commit. */
if (trx->fts_trx != NULL && trx->undo_no != 0) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment