diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2018-04-10 18:01:21 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2018-04-11 05:39:36 +0300 |
commit | dd127799bc179da10cc24c5d5cd105c9a5584730 (patch) | |
tree | 18d1f0f295cf0c13af61660140c75419164f07d8 /storage | |
parent | 8334aced009e9748e17ce697191e00c9f14e78b9 (diff) | |
download | mariadb-git-dd127799bc179da10cc24c5d5cd105c9a5584730.tar.gz |
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.
Diffstat (limited to 'storage')
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 4 | ||||
-rw-r--r-- | storage/innobase/include/trx0roll.h | 8 | ||||
-rw-r--r-- | storage/innobase/include/trx0trx.h | 12 | ||||
-rw-r--r-- | storage/innobase/row/row0undo.cc | 13 | ||||
-rw-r--r-- | storage/innobase/trx/trx0roll.cc | 103 | ||||
-rw-r--r-- | storage/innobase/trx/trx0trx.cc | 17 |
6 files changed, 75 insertions, 82 deletions
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index d9c3995f305..c13237ce18d 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -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, diff --git a/storage/innobase/include/trx0roll.h b/storage/innobase/include/trx0roll.h index ba9c901d4f7..e1718294f6e 100644 --- a/storage/innobase/include/trx0roll.h +++ b/storage/innobase/include/trx0roll.h @@ -1,7 +1,7 @@ /***************************************************************************** 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 diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 8a4a1151b46..4b7ca171740 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -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 */ diff --git a/storage/innobase/row/row0undo.cc b/storage/innobase/row/row0undo.cc index 2fcfecd5c11..a85b817d5cb 100644 --- a/storage/innobase/row/row0undo.cc +++ b/storage/innobase/row/row0undo.cc @@ -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); diff --git a/storage/innobase/trx/trx0roll.cc b/storage/innobase/trx/trx0roll.cc index 6874f929726..bd994dec765 100644 --- a/storage/innobase/trx/trx0roll.cc +++ b/storage/innobase/trx/trx0roll.cc @@ -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 */ diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index 6690d3e7676..9b3e67a9043 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -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) { |