mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 12:32:27 +01:00
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).
This commit is contained in:
parent
a9117c9008
commit
417434f12d
22 changed files with 339 additions and 402 deletions
48
mysql-test/suite/innodb/r/row_format_redundant.result
Normal file
48
mysql-test/suite/innodb/r/row_format_redundant.result
Normal file
|
@ -0,0 +1,48 @@
|
|||
create table t1 (a int not null, d varchar(15) not null, b
|
||||
varchar(198) not null, c char(156),
|
||||
fulltext ftsic(c)) engine=InnoDB
|
||||
row_format=redundant;
|
||||
insert into t1 values(123, 'abcdef', 'jghikl', 'mnop');
|
||||
insert into t1 values(456, 'abcdef', 'jghikl', 'mnop');
|
||||
insert into t1 values(789, 'abcdef', 'jghikl', 'mnop');
|
||||
insert into t1 values(134, 'kasdfsdsadf', 'adfjlasdkfjasd', 'adfsadflkasdasdfljasdf');
|
||||
insert into t1 select * from t1;
|
||||
insert into t1 select * from t1;
|
||||
insert into t1 select * from t1;
|
||||
insert into t1 select * from t1;
|
||||
insert into t1 select * from t1;
|
||||
insert into t1 select * from t1;
|
||||
insert into t1 select * from t1;
|
||||
insert into t1 select * from t1;
|
||||
insert into t1 select * from t1;
|
||||
insert into t1 select * from t1;
|
||||
SET GLOBAL innodb_file_per_table=OFF;
|
||||
create table t2 (a int not null, d varchar(15) not null, b
|
||||
varchar(198) not null, c char(156), fulltext ftsic(c)) engine=InnoDB
|
||||
row_format=redundant;
|
||||
insert into t2 select * from t1;
|
||||
create table t3 (a int not null, d varchar(15) not null, b varchar(198),
|
||||
c varchar(150), index k1(c(99), b(56)), index k2(b(5), c(10))) engine=InnoDB
|
||||
row_format=redundant;
|
||||
insert into t3 values(444, 'dddd', 'bbbbb', 'aaaaa');
|
||||
insert into t3 values(555, 'eeee', 'ccccc', 'aaaaa');
|
||||
SET GLOBAL innodb_fast_shutdown=0;
|
||||
SELECT COUNT(*) FROM t1;
|
||||
COUNT(*)
|
||||
4096
|
||||
SELECT COUNT(*) FROM t2;
|
||||
COUNT(*)
|
||||
4096
|
||||
SELECT COUNT(*) FROM t3;
|
||||
COUNT(*)
|
||||
2
|
||||
TRUNCATE TABLE t1;
|
||||
ERROR HY000: Table 't1' is read only
|
||||
TRUNCATE TABLE t2;
|
||||
ERROR HY000: Table 't2' is read only
|
||||
TRUNCATE TABLE t3;
|
||||
ERROR HY000: Table 't3' is read only
|
||||
TRUNCATE TABLE t1;
|
||||
TRUNCATE TABLE t2;
|
||||
TRUNCATE TABLE t3;
|
||||
DROP TABLE t1,t2,t3;
|
65
mysql-test/suite/innodb/t/row_format_redundant.test
Normal file
65
mysql-test/suite/innodb/t/row_format_redundant.test
Normal file
|
@ -0,0 +1,65 @@
|
|||
--source include/innodb_page_size.inc
|
||||
# Embedded mode doesn't allow restarting
|
||||
--source include/not_embedded.inc
|
||||
|
||||
create table t1 (a int not null, d varchar(15) not null, b
|
||||
varchar(198) not null, c char(156),
|
||||
fulltext ftsic(c)) engine=InnoDB
|
||||
row_format=redundant;
|
||||
|
||||
insert into t1 values(123, 'abcdef', 'jghikl', 'mnop');
|
||||
insert into t1 values(456, 'abcdef', 'jghikl', 'mnop');
|
||||
insert into t1 values(789, 'abcdef', 'jghikl', 'mnop');
|
||||
insert into t1 values(134, 'kasdfsdsadf', 'adfjlasdkfjasd', 'adfsadflkasdasdfljasdf');
|
||||
insert into t1 select * from t1;
|
||||
insert into t1 select * from t1;
|
||||
insert into t1 select * from t1;
|
||||
insert into t1 select * from t1;
|
||||
insert into t1 select * from t1;
|
||||
insert into t1 select * from t1;
|
||||
insert into t1 select * from t1;
|
||||
insert into t1 select * from t1;
|
||||
insert into t1 select * from t1;
|
||||
insert into t1 select * from t1;
|
||||
|
||||
SET GLOBAL innodb_file_per_table=OFF;
|
||||
create table t2 (a int not null, d varchar(15) not null, b
|
||||
varchar(198) not null, c char(156), fulltext ftsic(c)) engine=InnoDB
|
||||
row_format=redundant;
|
||||
|
||||
insert into t2 select * from t1;
|
||||
|
||||
create table t3 (a int not null, d varchar(15) not null, b varchar(198),
|
||||
c varchar(150), index k1(c(99), b(56)), index k2(b(5), c(10))) engine=InnoDB
|
||||
row_format=redundant;
|
||||
|
||||
insert into t3 values(444, 'dddd', 'bbbbb', 'aaaaa');
|
||||
insert into t3 values(555, 'eeee', 'ccccc', 'aaaaa');
|
||||
|
||||
# read-only restart requires the change buffer to be empty; therefore we
|
||||
# do a slow shutdown.
|
||||
SET GLOBAL innodb_fast_shutdown=0;
|
||||
--let $restart_parameters = --innodb-read-only
|
||||
--source include/restart_mysqld.inc
|
||||
|
||||
SELECT COUNT(*) FROM t1;
|
||||
SELECT COUNT(*) FROM t2;
|
||||
SELECT COUNT(*) FROM t3;
|
||||
|
||||
--error ER_OPEN_AS_READONLY
|
||||
TRUNCATE TABLE t1;
|
||||
--error ER_OPEN_AS_READONLY
|
||||
TRUNCATE TABLE t2;
|
||||
--error ER_OPEN_AS_READONLY
|
||||
TRUNCATE TABLE t3;
|
||||
|
||||
--let $restart_parameters =
|
||||
--source include/restart_mysqld.inc
|
||||
|
||||
TRUNCATE TABLE t1;
|
||||
TRUNCATE TABLE t2;
|
||||
TRUNCATE TABLE t3;
|
||||
|
||||
# TODO: Shutdown, corrupt the SYS_TABLES.TYPE of the tables, restart
|
||||
|
||||
DROP TABLE t1,t2,t3;
|
|
@ -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;
|
||||
|
||||
/** LRU flush batch is further divided into this chunk size to
|
||||
reduce the wait time for the threads waiting for a clean block */
|
||||
|
@ -2422,8 +2422,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) {
|
||||
|
||||
page_cleaner_sleep_if_needed(next_loop_time);
|
||||
|
@ -2517,7 +2515,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
|
||||
|
|
|
@ -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
|
||||
|
@ -217,11 +223,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
|
||||
|
@ -260,6 +266,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;
|
||||
}
|
||||
|
||||
/*****************************************************************//**
|
||||
|
@ -349,9 +358,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
|
||||
|
@ -361,7 +368,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;
|
||||
}
|
||||
|
||||
|
@ -370,8 +377,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(). */
|
||||
|
@ -379,3 +387,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);
|
||||
}
|
||||
|
|
|
@ -1142,14 +1142,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);
|
||||
|
||||
/*****************************************************************//**
|
||||
Creates an InnoDB transaction struct for the thd if it does not yet have one.
|
||||
|
@ -3651,21 +3648,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) {
|
||||
|
||||
|
@ -3682,9 +3671,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);
|
||||
|
@ -3693,7 +3680,7 @@ innobase_end(
|
|||
mysql_mutex_destroy(&pending_checkpoint_mutex);
|
||||
}
|
||||
|
||||
DBUG_RETURN(err);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/****************************************************************//**
|
||||
|
|
|
@ -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;
|
||||
|
||||
/********************************************************************//**
|
||||
Remove a block from the flush list of modified blocks. */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -398,7 +398,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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -84,7 +84,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 = "";
|
||||
|
||||
|
@ -2424,31 +2424,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);
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
|
@ -2709,7 +2707,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);
|
||||
}
|
||||
|
@ -2760,6 +2758,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)) {
|
||||
|
||||
|
@ -2776,36 +2775,8 @@ DECLARE_THREAD(srv_purge_coordinator_thread)(
|
|||
|
||||
rseg_history_len = srv_do_purge(
|
||||
srv_n_purge_threads, &n_total_purged);
|
||||
|
||||
} 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);
|
||||
|
|
|
@ -121,7 +121,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 */
|
||||
|
@ -1565,8 +1568,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;
|
||||
|
@ -2705,8 +2707,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
|
||||
|
@ -2827,6 +2829,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
|
||||
|
@ -2856,6 +2868,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;
|
||||
}
|
||||
|
@ -2885,13 +2898,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;
|
||||
|
@ -2929,13 +2935,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;
|
||||
|
||||
|
@ -2945,15 +2948,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
|
||||
|
@ -3156,89 +3164,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
|
||||
|
|
|
@ -243,6 +243,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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/****************************************************************//**
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue