summaryrefslogtreecommitdiff
path: root/storage/xtradb
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2017-06-08 15:43:06 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2017-06-09 16:20:42 +0300
commit417434f12dba3ccf5b79ca4e7afe72fe27807fd0 (patch)
tree1b61d0cf4ddf39b255cc44c31a72f2dac98adc76 /storage/xtradb
parenta9117c90083d3f26e43c460073e06f9562b66f44 (diff)
downloadmariadb-git-417434f12dba3ccf5b79ca4e7afe72fe27807fd0.tar.gz
MDEV-13039 innodb_fast_shutdown=0 may fail to purge all undo log
When a slow shutdown is performed soon after spawning some work for background threads that can create or commit transactions, it is possible that new transactions are started or committed after the purge has finished. This is violating the specification of innodb_fast_shutdown=0, namely that the purge must be completed. (None of the history of the recent transactions would be purged.) Also, it is possible that the purge threads would exit in slow shutdown while there exist active transactions, such as recovered incomplete transactions that are being rolled back. Thus, the slow shutdown could fail to purge some undo log that becomes purgeable after the transaction commit or rollback. srv_undo_sources: A flag that indicates if undo log can be generated or the persistent, whether by background threads or by user SQL. Even when this flag is clear, active transactions that already exist in the system may be committed or rolled back. innodb_shutdown(): Renamed from innobase_shutdown_for_mysql(). Do not return an error code; the operation never fails. Clear the srv_undo_sources flag, and also ensure that the background DROP TABLE queue is empty. srv_purge_should_exit(): Do not allow the purge to exit if srv_undo_sources are active or the background DROP TABLE queue is not empty, or in slow shutdown, if any active transactions exist (and are being rolled back). srv_purge_coordinator_thread(): Remove some previous workarounds for this bug. innobase_start_or_create_for_mysql(): Set buf_page_cleaner_is_active and srv_dict_stats_thread_active directly. Set srv_undo_sources before starting the purge subsystem, to prevent immediate shutdown of the purge. Create dict_stats_thread and fts_optimize_thread immediately after setting srv_undo_sources, so that shutdown can use this flag to determine if these subsystems were started. dict_stats_shutdown(): Shut down dict_stats_thread. Backported from 10.2. srv_shutdown_table_bg_threads(): Remove (unused).
Diffstat (limited to 'storage/xtradb')
-rw-r--r--storage/xtradb/buf/buf0flu.cc8
-rw-r--r--storage/xtradb/dict/dict0stats_bg.cc35
-rw-r--r--storage/xtradb/handler/ha_innodb.cc29
-rw-r--r--storage/xtradb/include/buf0flu.h2
-rw-r--r--storage/xtradb/include/dict0stats_bg.h6
-rw-r--r--storage/xtradb/include/srv0srv.h2
-rw-r--r--storage/xtradb/include/srv0start.h20
-rw-r--r--storage/xtradb/srv/srv0srv.cc71
-rw-r--r--storage/xtradb/srv/srv0start.cc128
-rw-r--r--storage/xtradb/trx/trx0purge.cc13
10 files changed, 113 insertions, 201 deletions
diff --git a/storage/xtradb/buf/buf0flu.cc b/storage/xtradb/buf/buf0flu.cc
index 4781b874032..955be5a6161 100644
--- a/storage/xtradb/buf/buf0flu.cc
+++ b/storage/xtradb/buf/buf0flu.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, MariaDB Corporation. All Rights Reserved.
+Copyright (c) 2017, 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
@@ -58,7 +58,7 @@ is set to TRUE by the page_cleaner thread when it is spawned and is set
back to FALSE at shutdown by the page_cleaner as well. Therefore no
need to protect it by a mutex. It is only ever read by the thread
doing the shutdown */
-UNIV_INTERN ibool buf_page_cleaner_is_active = FALSE;
+UNIV_INTERN bool buf_page_cleaner_is_active;
/** Flag indicating if the lru_manager is in active state. */
UNIV_INTERN bool buf_lru_manager_is_active = false;
@@ -2718,8 +2718,6 @@ DECLARE_THREAD(buf_flush_page_cleaner_thread)(
os_thread_pf(os_thread_get_curr_id()));
#endif /* UNIV_DEBUG_THREAD_CREATION */
- buf_page_cleaner_is_active = TRUE;
-
while (srv_shutdown_state == SRV_SHUTDOWN_NONE) {
ulint page_cleaner_sleep_time;
@@ -2829,7 +2827,7 @@ DECLARE_THREAD(buf_flush_page_cleaner_thread)(
/* We have lived our life. Time to die. */
thread_exit:
- buf_page_cleaner_is_active = FALSE;
+ buf_page_cleaner_is_active = false;
my_thread_end();
/* We count the number of threads in os_thread_exit(). A created
diff --git a/storage/xtradb/dict/dict0stats_bg.cc b/storage/xtradb/dict/dict0stats_bg.cc
index 8cb419c6c37..4d646ed3081 100644
--- a/storage/xtradb/dict/dict0stats_bg.cc
+++ b/storage/xtradb/dict/dict0stats_bg.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2012, 2017, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, MariaDB Corporation. All Rights Reserved.
+Copyright (c) 2017, 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
@@ -38,12 +38,18 @@ Created Apr 25, 2012 Vasil Dimov
/** Minimum time interval between stats recalc for a given table */
#define MIN_RECALC_INTERVAL 10 /* seconds */
-#define SHUTTING_DOWN() (srv_shutdown_state != SRV_SHUTDOWN_NONE)
-
/** Event to wake up dict_stats_thread on dict_stats_recalc_pool_add()
or shutdown. Not protected by any mutex. */
UNIV_INTERN os_event_t dict_stats_event;
+/** Variable to initiate shutdown the dict stats thread. Note we don't
+use 'srv_shutdown_state' because we want to shutdown dict stats thread
+before purge thread. */
+static bool dict_stats_start_shutdown;
+
+/** Event to wait for shutdown of the dict stats thread */
+static os_event_t dict_stats_shutdown_event;
+
/** This mutex protects the "recalc_pool" variable. */
static ib_mutex_t recalc_pool_mutex;
#ifdef HAVE_PSI_INTERFACE
@@ -207,11 +213,11 @@ Must be called before dict_stats_thread() is started. */
UNIV_INTERN
void
dict_stats_thread_init()
-/*====================*/
{
ut_a(!srv_read_only_mode);
dict_stats_event = os_event_create();
+ dict_stats_shutdown_event = os_event_create();
/* The recalc_pool_mutex is acquired from:
1) the background stats gathering thread before any other latch
@@ -250,6 +256,9 @@ dict_stats_thread_deinit()
os_event_free(dict_stats_event);
dict_stats_event = NULL;
+ os_event_free(dict_stats_shutdown_event);
+ dict_stats_shutdown_event = NULL;
+ dict_stats_start_shutdown = false;
}
/*****************************************************************//**
@@ -339,9 +348,7 @@ DECLARE_THREAD(dict_stats_thread)(
my_thread_init();
ut_a(!srv_read_only_mode);
- srv_dict_stats_thread_active = TRUE;
-
- while (!SHUTTING_DOWN()) {
+ while (!dict_stats_start_shutdown) {
/* Wake up periodically even if not signaled. This is
because we may lose an event - if the below call to
@@ -351,7 +358,7 @@ DECLARE_THREAD(dict_stats_thread)(
os_event_wait_time(
dict_stats_event, MIN_RECALC_INTERVAL * 1000000);
- if (SHUTTING_DOWN()) {
+ if (dict_stats_start_shutdown) {
break;
}
@@ -360,8 +367,9 @@ DECLARE_THREAD(dict_stats_thread)(
os_event_reset(dict_stats_event);
}
- srv_dict_stats_thread_active = FALSE;
+ srv_dict_stats_thread_active = false;
+ os_event_set(dict_stats_shutdown_event);
my_thread_end();
/* We count the number of threads in os_thread_exit(). A created
thread should always use that to exit instead of return(). */
@@ -369,3 +377,12 @@ DECLARE_THREAD(dict_stats_thread)(
OS_THREAD_DUMMY_RETURN;
}
+
+/** Shut down the dict_stats_thread. */
+void
+dict_stats_shutdown()
+{
+ dict_stats_start_shutdown = true;
+ os_event_set(dict_stats_event);
+ os_event_wait(dict_stats_shutdown_event);
+}
diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc
index 7d1ed3da5fd..9717136e030 100644
--- a/storage/xtradb/handler/ha_innodb.cc
+++ b/storage/xtradb/handler/ha_innodb.cc
@@ -1366,14 +1366,11 @@ innobase_drop_database(
the path is used as the database name:
for example, in 'mysql/data/test' the
database name is 'test' */
-/*******************************************************************//**
-Closes an InnoDB database. */
+/** Shut down the InnoDB storage engine.
+@return 0 */
static
int
-innobase_end(
-/*=========*/
- handlerton* hton, /* in: Innodb handlerton */
- ha_panic_function type);
+innobase_end(handlerton*, ha_panic_function);
#if NOT_USED
/*****************************************************************//**
@@ -4140,21 +4137,13 @@ error:
DBUG_RETURN(TRUE);
}
-/*******************************************************************//**
-Closes an InnoDB database.
-@return TRUE if error */
+/** Shut down the InnoDB storage engine.
+@return 0 */
static
int
-innobase_end(
-/*=========*/
- handlerton* hton, /*!< in/out: InnoDB handlerton */
- ha_panic_function type MY_ATTRIBUTE((unused)))
- /*!< in: ha_panic() parameter */
+innobase_end(handlerton*, ha_panic_function)
{
- int err= 0;
-
DBUG_ENTER("innobase_end");
- DBUG_ASSERT(hton == innodb_hton_ptr);
if (innodb_inited) {
@@ -4171,9 +4160,7 @@ innobase_end(
innodb_inited = 0;
hash_table_free(innobase_open_tables);
innobase_open_tables = NULL;
- if (innobase_shutdown_for_mysql() != DB_SUCCESS) {
- err = 1;
- }
+ innodb_shutdown();
srv_free_paths_and_sizes();
my_free(internal_innobase_data_file_path);
mysql_mutex_destroy(&innobase_share_mutex);
@@ -4182,7 +4169,7 @@ innobase_end(
mysql_mutex_destroy(&pending_checkpoint_mutex);
}
- DBUG_RETURN(err);
+ DBUG_RETURN(0);
}
/****************************************************************//**
diff --git a/storage/xtradb/include/buf0flu.h b/storage/xtradb/include/buf0flu.h
index 96035452e6e..384014939ae 100644
--- a/storage/xtradb/include/buf0flu.h
+++ b/storage/xtradb/include/buf0flu.h
@@ -34,7 +34,7 @@ Created 11/5/1995 Heikki Tuuri
#include "buf0types.h"
/** Flag indicating if the page_cleaner is in active state. */
-extern ibool buf_page_cleaner_is_active;
+extern bool buf_page_cleaner_is_active;
/** Flag indicating if the lru_manager is in active state. */
extern bool buf_lru_manager_is_active;
diff --git a/storage/xtradb/include/dict0stats_bg.h b/storage/xtradb/include/dict0stats_bg.h
index 1973380d197..2bd441d5f5e 100644
--- a/storage/xtradb/include/dict0stats_bg.h
+++ b/storage/xtradb/include/dict0stats_bg.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2012, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, MariaDB Corporation. All Rights Reserved.
+Copyright (c) 2017, 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
@@ -122,6 +122,10 @@ DECLARE_THREAD(dict_stats_thread)(
void* arg); /*!< in: a dummy parameter
required by os_thread_create */
+/** Shut down the dict_stats_thread. */
+void
+dict_stats_shutdown();
+
# ifndef UNIV_NONINL
# include "dict0stats_bg.ic"
# endif
diff --git a/storage/xtradb/include/srv0srv.h b/storage/xtradb/include/srv0srv.h
index cfd961d9c46..f27ed9857ec 100644
--- a/storage/xtradb/include/srv0srv.h
+++ b/storage/xtradb/include/srv0srv.h
@@ -499,7 +499,7 @@ extern ibool srv_error_monitor_active;
extern ibool srv_buf_dump_thread_active;
/* TRUE during the lifetime of the stats thread */
-extern ibool srv_dict_stats_thread_active;
+extern bool srv_dict_stats_thread_active;
extern ulong srv_n_spin_wait_rounds;
extern ulong srv_n_free_tickets_to_enter;
diff --git a/storage/xtradb/include/srv0start.h b/storage/xtradb/include/srv0start.h
index a60776a4665..b055a9d834f 100644
--- a/storage/xtradb/include/srv0start.h
+++ b/storage/xtradb/include/srv0start.h
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2017, 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
@@ -75,22 +76,12 @@ are not found and the user wants.
@return DB_SUCCESS or error code */
UNIV_INTERN
dberr_t
-innobase_start_or_create_for_mysql(void);
-/*====================================*/
-/****************************************************************//**
-Shuts down the Innobase database.
-@return DB_SUCCESS or error code */
-UNIV_INTERN
-dberr_t
-innobase_shutdown_for_mysql(void);
+innobase_start_or_create_for_mysql();
-/********************************************************************
-Signal all per-table background threads to shutdown, and wait for them to do
-so. */
+/** Shut down InnoDB. */
UNIV_INTERN
void
-srv_shutdown_table_bg_threads(void);
-/*=============================*/
+innodb_shutdown();
/*************************************************************//**
Copy the file path component of the physical file to parameter. It will
@@ -158,6 +149,9 @@ enum srv_shutdown_state {
SRV_SHUTDOWN_EXIT_THREADS/*!< Exit all threads */
};
+/** Whether any undo log records can be generated */
+extern bool srv_undo_sources;
+
/** At a shutdown this value climbs from SRV_SHUTDOWN_NONE to
SRV_SHUTDOWN_CLEANUP and then to SRV_SHUTDOWN_LAST_PHASE, and so on */
extern enum srv_shutdown_state srv_shutdown_state;
diff --git a/storage/xtradb/srv/srv0srv.cc b/storage/xtradb/srv/srv0srv.cc
index 2fa3be014a5..e11697081c6 100644
--- a/storage/xtradb/srv/srv0srv.cc
+++ b/storage/xtradb/srv/srv0srv.cc
@@ -92,7 +92,7 @@ UNIV_INTERN ibool srv_error_monitor_active = FALSE;
UNIV_INTERN ibool srv_buf_dump_thread_active = FALSE;
-UNIV_INTERN ibool srv_dict_stats_thread_active = FALSE;
+UNIV_INTERN bool srv_dict_stats_thread_active;
UNIV_INTERN const char* srv_main_thread_op_info = "";
@@ -3097,31 +3097,29 @@ suspend_thread:
goto loop;
}
-/*********************************************************************//**
-Check if purge should stop.
-@return true if it should shutdown. */
+/** Check if purge should stop.
+@param[in] n_purged pages purged in the last batch
+@return whether purge should exit */
static
bool
-srv_purge_should_exit(
-/*==============*/
- ulint n_purged) /*!< in: pages purged in last batch */
+srv_purge_should_exit(ulint n_purged)
{
- switch (srv_shutdown_state) {
- case SRV_SHUTDOWN_NONE:
- /* Normal operation. */
- break;
+ ut_ad(srv_shutdown_state == SRV_SHUTDOWN_NONE
+ || srv_shutdown_state == SRV_SHUTDOWN_CLEANUP);
- case SRV_SHUTDOWN_CLEANUP:
- case SRV_SHUTDOWN_EXIT_THREADS:
- /* Exit unless slow shutdown requested or all done. */
- return(srv_fast_shutdown != 0 || n_purged == 0);
-
- case SRV_SHUTDOWN_LAST_PHASE:
- case SRV_SHUTDOWN_FLUSH_PHASE:
- ut_error;
+ if (srv_undo_sources) {
+ return(false);
}
-
- return(false);
+ if (srv_fast_shutdown) {
+ return(true);
+ }
+ /* Slow shutdown was requested. */
+ if (n_purged) {
+ /* The previous round still did some work. */
+ return(false);
+ }
+ /* Exit if there are no active transactions to roll back. */
+ return(trx_sys_any_active_transactions() == 0);
}
/*********************************************************************//**
@@ -3396,7 +3394,7 @@ srv_purge_coordinator_suspend(
}
rw_lock_x_unlock(&purge_sys->latch);
- } while (stop);
+ } while (stop && srv_undo_sources);
srv_resume_thread(slot, 0, false);
}
@@ -3450,6 +3448,7 @@ DECLARE_THREAD(srv_purge_coordinator_thread)(
purge didn't purge any records then wait for activity. */
if (srv_shutdown_state == SRV_SHUTDOWN_NONE
+ && srv_undo_sources
&& (purge_sys->state == PURGE_STATE_STOP
|| n_total_purged == 0)) {
@@ -3470,36 +3469,8 @@ DECLARE_THREAD(srv_purge_coordinator_thread)(
srv_n_purge_threads, &n_total_purged);
srv_inc_activity_count();
-
} while (!srv_purge_should_exit(n_total_purged));
- /* Ensure that we don't jump out of the loop unless the
- exit condition is satisfied. */
-
- ut_a(srv_purge_should_exit(n_total_purged));
-
- ulint n_pages_purged = ULINT_MAX;
-
- /* Ensure that all records are purged if it is not a fast shutdown.
- This covers the case where a record can be added after we exit the
- loop above. */
- while (srv_fast_shutdown == 0 && n_pages_purged > 0) {
- n_pages_purged = trx_purge(1, srv_purge_batch_size, false);
- }
-
- /* This trx_purge is called to remove any undo records (added by
- background threads) after completion of the above loop. When
- srv_fast_shutdown != 0, a large batch size can cause significant
- delay in shutdown ,so reducing the batch size to magic number 20
- (which was default in 5.5), which we hope will be sufficient to
- remove all the undo records */
- const uint temp_batch_size = 20;
-
- n_pages_purged = trx_purge(1, srv_purge_batch_size <= temp_batch_size
- ? srv_purge_batch_size : temp_batch_size,
- true);
- ut_a(n_pages_purged == 0 || srv_fast_shutdown != 0);
-
/* The task queue should always be empty, independent of fast
shutdown state. */
ut_a(srv_get_task_queue_length() == 0);
diff --git a/storage/xtradb/srv/srv0start.cc b/storage/xtradb/srv/srv0start.cc
index e5b06a4919c..525c985f71b 100644
--- a/storage/xtradb/srv/srv0start.cc
+++ b/storage/xtradb/srv/srv0start.cc
@@ -123,7 +123,10 @@ UNIV_INTERN ibool srv_is_being_started = FALSE;
/** TRUE if the server was successfully started */
UNIV_INTERN ibool srv_was_started = FALSE;
/** TRUE if innobase_start_or_create_for_mysql() has been called */
-static ibool srv_start_has_been_called = FALSE;
+static ibool srv_start_has_been_called;
+
+/** Whether any undo log records can be generated */
+UNIV_INTERN bool srv_undo_sources;
/** At a shutdown this value climbs from SRV_SHUTDOWN_NONE to
SRV_SHUTDOWN_CLEANUP and then to SRV_SHUTDOWN_LAST_PHASE, and so on */
@@ -1623,8 +1626,7 @@ are not found and the user wants.
@return DB_SUCCESS or error code */
UNIV_INTERN
dberr_t
-innobase_start_or_create_for_mysql(void)
-/*====================================*/
+innobase_start_or_create_for_mysql()
{
ibool create_new_db;
lsn_t min_flushed_lsn;
@@ -2777,8 +2779,8 @@ files_checked:
}
}
- srv_startup_is_before_trx_rollback_phase = FALSE;
recv_recovery_rollback_active();
+ srv_startup_is_before_trx_rollback_phase = FALSE;
/* It is possible that file_format tag has never
been set. In this case we initialize it to minimum
@@ -2905,6 +2907,16 @@ files_checked:
srv_master_thread,
NULL, thread_ids + (1 + SRV_MAX_N_IO_THREADS));
thread_started[1 + SRV_MAX_N_IO_THREADS] = true;
+
+ srv_undo_sources = true;
+ /* Create the dict stats gathering thread */
+ srv_dict_stats_thread_active = true;
+ dict_stats_thread_handle = os_thread_create(
+ dict_stats_thread, NULL, NULL);
+ dict_stats_thread_started = true;
+
+ /* Create the thread that will optimize the FTS sub-system. */
+ fts_optimize_init();
}
if (!srv_read_only_mode
@@ -2934,6 +2946,7 @@ files_checked:
}
if (!srv_read_only_mode) {
+ buf_page_cleaner_is_active = true;
buf_flush_page_cleaner_thread_handle = os_thread_create(buf_flush_page_cleaner_thread, NULL, NULL);
buf_flush_page_cleaner_thread_started = true;
}
@@ -2973,13 +2986,6 @@ files_checked:
/* Create the buffer pool dump/load thread */
buf_dump_thread_handle = os_thread_create(buf_dump_thread, NULL, NULL);
buf_dump_thread_started = true;
-
- /* Create the dict stats gathering thread */
- dict_stats_thread_handle = os_thread_create(dict_stats_thread, NULL, NULL);
- dict_stats_thread_started = true;
-
- /* Create the thread that will optimize the FTS sub-system. */
- fts_optimize_init();
}
srv_was_started = TRUE;
@@ -3017,13 +3023,10 @@ srv_fts_close(void)
}
#endif
-/****************************************************************//**
-Shuts down the InnoDB database.
-@return DB_SUCCESS or error code */
+/** Shut down InnoDB. */
UNIV_INTERN
-dberr_t
-innobase_shutdown_for_mysql(void)
-/*=============================*/
+void
+innodb_shutdown()
{
ulint i;
@@ -3033,15 +3036,20 @@ innobase_shutdown_for_mysql(void)
"Shutting down an improperly started, "
"or created database!");
}
-
- return(DB_SUCCESS);
}
- if (!srv_read_only_mode) {
+ if (srv_undo_sources) {
+ ut_ad(!srv_read_only_mode);
/* Shutdown the FTS optimize sub system. */
fts_optimize_start_shutdown();
fts_optimize_end();
+ dict_stats_shutdown();
+ while (row_get_background_drop_list_len_low()) {
+ srv_wake_master_thread();
+ os_thread_yield();
+ }
+ srv_undo_sources = false;
}
/* 1. Flush the buffer pool to disk, write the current lsn to
@@ -3245,89 +3253,9 @@ innobase_shutdown_for_mysql(void)
srv_was_started = FALSE;
srv_start_has_been_called = FALSE;
-
- return(DB_SUCCESS);
}
#endif /* !UNIV_HOTBACKUP */
-
-/********************************************************************
-Signal all per-table background threads to shutdown, and wait for them to do
-so. */
-UNIV_INTERN
-void
-srv_shutdown_table_bg_threads(void)
-/*===============================*/
-{
- dict_table_t* table;
- dict_table_t* first;
- dict_table_t* last = NULL;
-
- mutex_enter(&dict_sys->mutex);
-
- /* Signal all threads that they should stop. */
- table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
- first = table;
- while (table) {
- dict_table_t* next;
- fts_t* fts = table->fts;
-
- if (fts != NULL) {
- fts_start_shutdown(table, fts);
- }
-
- next = UT_LIST_GET_NEXT(table_LRU, table);
-
- if (!next) {
- last = table;
- }
-
- table = next;
- }
-
- /* We must release dict_sys->mutex here; if we hold on to it in the
- loop below, we will deadlock if any of the background threads try to
- acquire it (for example, the FTS thread by calling que_eval_sql).
-
- Releasing it here and going through dict_sys->table_LRU without
- holding it is safe because:
-
- a) MySQL only starts the shutdown procedure after all client
- threads have been disconnected and no new ones are accepted, so no
- new tables are added or old ones dropped.
-
- b) Despite its name, the list is not LRU, and the order stays
- fixed.
-
- To safeguard against the above assumptions ever changing, we store
- the first and last items in the list above, and then check that
- they've stayed the same below. */
-
- mutex_exit(&dict_sys->mutex);
-
- /* Wait for the threads of each table to stop. This is not inside
- the above loop, because by signaling all the threads first we can
- overlap their shutting down delays. */
- table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
- ut_a(first == table);
- while (table) {
- dict_table_t* next;
- fts_t* fts = table->fts;
-
- if (fts != NULL) {
- fts_shutdown(table, fts);
- }
-
- next = UT_LIST_GET_NEXT(table_LRU, table);
-
- if (table == last) {
- ut_a(!next);
- }
-
- table = next;
- }
-}
-
/*****************************************************************//**
Get the meta-data filename from the table name. */
UNIV_INTERN
diff --git a/storage/xtradb/trx/trx0purge.cc b/storage/xtradb/trx/trx0purge.cc
index 474ca077ce5..a4463744a69 100644
--- a/storage/xtradb/trx/trx0purge.cc
+++ b/storage/xtradb/trx/trx0purge.cc
@@ -247,6 +247,19 @@ trx_purge_add_update_undo_to_history(
hist_size + undo->size, MLOG_4BYTES, mtr);
}
+ /* Before any transaction-generating background threads or the
+ purge have been started, recv_recovery_rollback_active() can
+ start transactions in row_merge_drop_temp_indexes() and
+ fts_drop_orphaned_tables(), and roll back recovered transactions.
+ After the purge thread has been given permission to exit,
+ in fast shutdown, we may roll back transactions (trx->undo_no==0)
+ in THD::cleanup() invoked from unlink_thd(). */
+ ut_ad(srv_undo_sources
+ || ((srv_startup_is_before_trx_rollback_phase
+ || trx_rollback_or_clean_is_active)
+ && purge_sys->state == PURGE_STATE_INIT)
+ || (trx->undo_no == 0 && srv_fast_shutdown));
+
/* Add the log as the first in the history list */
flst_add_first(rseg_header + TRX_RSEG_HISTORY,
undo_header + TRX_UNDO_HISTORY_NODE, mtr);