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