Merge 10.0 into 10.1

This commit is contained in:
Marko Mäkelä 2017-06-12 14:26:32 +03:00
commit fa57479fcd
25 changed files with 373 additions and 447 deletions

View file

@ -1899,8 +1899,8 @@ error:
return(TRUE); return(TRUE);
} }
static my_bool static void
innodb_end(void) innodb_end()
{ {
srv_fast_shutdown = (ulint) innobase_fast_shutdown; srv_fast_shutdown = (ulint) innobase_fast_shutdown;
innodb_inited = 0; innodb_inited = 0;
@ -1908,9 +1908,7 @@ innodb_end(void)
msg("xtrabackup: starting shutdown with innodb_fast_shutdown = %lu\n", msg("xtrabackup: starting shutdown with innodb_fast_shutdown = %lu\n",
srv_fast_shutdown); srv_fast_shutdown);
if (innobase_shutdown_for_mysql() != DB_SUCCESS) { innodb_shutdown();
goto error;
}
free(internal_innobase_data_file_path); free(internal_innobase_data_file_path);
internal_innobase_data_file_path = NULL; internal_innobase_data_file_path = NULL;
@ -1921,12 +1919,6 @@ innodb_end(void)
// pthread_mutex_destroy(&commit_threads_m); // pthread_mutex_destroy(&commit_threads_m);
// pthread_mutex_destroy(&commit_cond_m); // pthread_mutex_destroy(&commit_cond_m);
// pthread_cond_destroy(&commit_cond); // pthread_cond_destroy(&commit_cond);
return(FALSE);
error:
msg("xtrabackup: innodb_end(): Error occured.\n");
return(TRUE);
} }
/* ================= common ================= */ /* ================= common ================= */
@ -4819,8 +4811,7 @@ end:
xb_filters_free(); xb_filters_free();
/* shutdown InnoDB */ /* shutdown InnoDB */
if(innodb_end()) innodb_end();
exit(EXIT_FAILURE);
} }
/* ================= prepare ================= */ /* ================= prepare ================= */
@ -6763,8 +6754,7 @@ next_node:
xb_write_galera_info(xtrabackup_incremental); xb_write_galera_info(xtrabackup_incremental);
#endif #endif
if(innodb_end()) innodb_end();
goto error_cleanup;
innodb_free_param(); innodb_free_param();
@ -6850,9 +6840,7 @@ next_node:
if(innodb_init()) if(innodb_init())
goto error; goto error;
if(innodb_end()) innodb_end();
goto error;
innodb_free_param(); innodb_free_param();
} }

View 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;

View file

@ -0,0 +1,75 @@
--source include/innodb_page_size.inc
# Embedded mode doesn't allow restarting
--source include/not_embedded.inc
# MDEV-13059 XtraDB hangs on Windows due to failing to release
# block->lock X-latch in innodb_read_only mode
if (`SELECT count(*) FROM information_schema.plugins WHERE
plugin_name = 'innodb' AND plugin_status = 'active' AND
plugin_description LIKE '%xtradb%'`){
if (`SELECT @@version_compile_os IN ('Win32','Win64','Windows')`) {
skip MDEV-13059 XtraDB hangs on Windows in innodb_read_only mode;
}
}
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;

View file

@ -1,4 +1,4 @@
SET @start_value = @@GLOBAL.innodb_sched_priority_cleaner; SET GLOBAL innodb_sched_priority_cleaner=39;
SELECT @@GLOBAL.innodb_sched_priority_cleaner; SELECT @@GLOBAL.innodb_sched_priority_cleaner;
@@GLOBAL.innodb_sched_priority_cleaner @@GLOBAL.innodb_sched_priority_cleaner
19 19

View file

@ -4,7 +4,15 @@
# A dynamic, global variable # A dynamic, global variable
SET @start_value = @@GLOBAL.innodb_sched_priority_cleaner; # Test in read-only mode
--let $restart_parameters= --innodb-read-only
--source include/restart_mysqld.inc
--let $restart_parameters=
# This has no actual effect in innodb_read_only mode
SET GLOBAL innodb_sched_priority_cleaner=39;
--source include/restart_mysqld.inc
# Default value # Default value
SELECT @@GLOBAL.innodb_sched_priority_cleaner; SELECT @@GLOBAL.innodb_sched_priority_cleaner;

View file

@ -62,7 +62,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 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 need to protect it by a mutex. It is only ever read by the thread
doing the shutdown */ doing the shutdown */
UNIV_INTERN ibool buf_page_cleaner_is_active = FALSE; UNIV_INTERN bool buf_page_cleaner_is_active;
#ifdef UNIV_PFS_THREAD #ifdef UNIV_PFS_THREAD
UNIV_INTERN mysql_pfs_key_t buf_page_cleaner_thread_key; UNIV_INTERN mysql_pfs_key_t buf_page_cleaner_thread_key;
@ -2326,7 +2326,6 @@ DECLARE_THREAD(buf_flush_page_cleaner_thread)(
fprintf(stderr, "InnoDB: page_cleaner thread running, id %lu\n", fprintf(stderr, "InnoDB: page_cleaner thread running, id %lu\n",
os_thread_pf(os_thread_get_curr_id())); os_thread_pf(os_thread_get_curr_id()));
#endif /* UNIV_DEBUG_THREAD_CREATION */ #endif /* UNIV_DEBUG_THREAD_CREATION */
buf_page_cleaner_is_active = TRUE;
while (srv_shutdown_state == SRV_SHUTDOWN_NONE) { while (srv_shutdown_state == SRV_SHUTDOWN_NONE) {
@ -2422,7 +2421,7 @@ DECLARE_THREAD(buf_flush_page_cleaner_thread)(
/* We have lived our life. Time to die. */ /* We have lived our life. Time to die. */
thread_exit: thread_exit:
buf_page_cleaner_is_active = FALSE; buf_page_cleaner_is_active = false;
my_thread_end(); my_thread_end();
/* We count the number of threads in os_thread_exit(). A created /* We count the number of threads in os_thread_exit(). A created

View file

@ -1,7 +1,7 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 2012, 2017, Oracle and/or its affiliates. All Rights Reserved. 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 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
@ -39,12 +39,18 @@ Created Apr 25, 2012 Vasil Dimov
/** Minimum time interval between stats recalc for a given table */ /** Minimum time interval between stats recalc for a given table */
#define MIN_RECALC_INTERVAL 10 /* seconds */ #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() /** Event to wake up dict_stats_thread on dict_stats_recalc_pool_add()
or shutdown. Not protected by any mutex. */ or shutdown. Not protected by any mutex. */
UNIV_INTERN os_event_t dict_stats_event; 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. */ /** This mutex protects the "recalc_pool" variable. */
static ib_mutex_t recalc_pool_mutex; static ib_mutex_t recalc_pool_mutex;
static ib_mutex_t defrag_pool_mutex; static ib_mutex_t defrag_pool_mutex;
@ -340,11 +346,11 @@ Must be called before dict_stats_thread() is started. */
UNIV_INTERN UNIV_INTERN
void void
dict_stats_thread_init() dict_stats_thread_init()
/*====================*/
{ {
ut_a(!srv_read_only_mode); ut_a(!srv_read_only_mode);
dict_stats_event = os_event_create(); dict_stats_event = os_event_create();
dict_stats_shutdown_event = os_event_create();
/* The recalc_pool_mutex is acquired from: /* The recalc_pool_mutex is acquired from:
1) the background stats gathering thread before any other latch 1) the background stats gathering thread before any other latch
@ -389,6 +395,9 @@ dict_stats_thread_deinit()
os_event_free(dict_stats_event); os_event_free(dict_stats_event);
dict_stats_event = NULL; dict_stats_event = NULL;
os_event_free(dict_stats_shutdown_event);
dict_stats_shutdown_event = NULL;
dict_stats_start_shutdown = false;
} }
/*****************************************************************//** /*****************************************************************//**
@ -532,7 +541,7 @@ DECLARE_THREAD(dict_stats_thread)(void*)
my_thread_init(); my_thread_init();
ut_a(!srv_read_only_mode); ut_a(!srv_read_only_mode);
while (!SHUTTING_DOWN()) { while (!dict_stats_start_shutdown) {
/* Wake up periodically even if not signaled. This is /* Wake up periodically even if not signaled. This is
because we may lose an event - if the below call to because we may lose an event - if the below call to
@ -542,7 +551,7 @@ DECLARE_THREAD(dict_stats_thread)(void*)
os_event_wait_time( os_event_wait_time(
dict_stats_event, MIN_RECALC_INTERVAL * 1000000); dict_stats_event, MIN_RECALC_INTERVAL * 1000000);
if (SHUTTING_DOWN()) { if (dict_stats_start_shutdown) {
break; break;
} }
@ -556,6 +565,7 @@ DECLARE_THREAD(dict_stats_thread)(void*)
srv_dict_stats_thread_active = false; srv_dict_stats_thread_active = false;
os_event_set(dict_stats_shutdown_event);
my_thread_end(); my_thread_end();
/* We count the number of threads in os_thread_exit(). A created /* We count the number of threads in os_thread_exit(). A created
thread should always use that to exit instead of return(). */ thread should always use that to exit instead of return(). */
@ -563,3 +573,12 @@ DECLARE_THREAD(dict_stats_thread)(void*)
OS_THREAD_DUMMY_RETURN; 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);
}

View file

@ -2731,7 +2731,6 @@ fsp_reserve_free_extents(
ibool success; ibool success;
ulint n_pages_added; ulint n_pages_added;
size_t total_reserved = 0; size_t total_reserved = 0;
ulint rounds = 0;
ut_ad(mtr); ut_ad(mtr);
*n_reserved = n_ext; *n_reserved = n_ext;
@ -2811,17 +2810,7 @@ try_to_extend:
space_header, mtr); space_header, mtr);
if (success && n_pages_added > 0) { if (success && n_pages_added > 0) {
rounds++;
total_reserved += n_pages_added; total_reserved += n_pages_added;
if (rounds > 50) {
ib_logf(IB_LOG_LEVEL_INFO,
"Space id %lu trying to reserve %lu extents actually reserved %lu "
" reserve %lu free %lu size %lu rounds %lu total_reserved %llu",
space, n_ext, n_pages_added, reserve, n_free, size, rounds, (ullint) total_reserved);
}
goto try_again; goto try_again;
} }

View file

@ -1380,14 +1380,11 @@ innobase_drop_database(
the path is used as the database name: the path is used as the database name:
for example, in 'mysql/data/test' the for example, in 'mysql/data/test' the
database name is 'test' */ database name is 'test' */
/*******************************************************************//** /** Shut down the InnoDB storage engine.
Closes an InnoDB database. */ @return 0 */
static static
int int
innobase_end( innobase_end(handlerton*, ha_panic_function);
/*=========*/
handlerton* hton, /* in: Innodb handlerton */
ha_panic_function type);
/*****************************************************************//** /*****************************************************************//**
Creates an InnoDB transaction struct for the thd if it does not yet have one. Creates an InnoDB transaction struct for the thd if it does not yet have one.
@ -4011,21 +4008,13 @@ error:
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
/*******************************************************************//** /** Shut down the InnoDB storage engine.
Closes an InnoDB database. @return 0 */
@return TRUE if error */
static static
int int
innobase_end( innobase_end(handlerton*, ha_panic_function)
/*=========*/
handlerton* hton, /*!< in/out: InnoDB handlerton */
ha_panic_function type MY_ATTRIBUTE((unused)))
/*!< in: ha_panic() parameter */
{ {
int err= 0;
DBUG_ENTER("innobase_end"); DBUG_ENTER("innobase_end");
DBUG_ASSERT(hton == innodb_hton_ptr);
if (innodb_inited) { if (innodb_inited) {
@ -4042,9 +4031,7 @@ innobase_end(
innodb_inited = 0; innodb_inited = 0;
hash_table_free(innobase_open_tables); hash_table_free(innobase_open_tables);
innobase_open_tables = NULL; innobase_open_tables = NULL;
if (innobase_shutdown_for_mysql() != DB_SUCCESS) { innodb_shutdown();
err = 1;
}
srv_free_paths_and_sizes(); srv_free_paths_and_sizes();
my_free(internal_innobase_data_file_path); my_free(internal_innobase_data_file_path);
mysql_mutex_destroy(&innobase_share_mutex); mysql_mutex_destroy(&innobase_share_mutex);
@ -4053,7 +4040,7 @@ innobase_end(
mysql_mutex_destroy(&pending_checkpoint_mutex); mysql_mutex_destroy(&pending_checkpoint_mutex);
} }
DBUG_RETURN(err); DBUG_RETURN(0);
} }
/****************************************************************//** /****************************************************************//**

View file

@ -35,7 +35,7 @@ Created 11/5/1995 Heikki Tuuri
#include "buf0types.h" #include "buf0types.h"
/** Flag indicating if the page_cleaner is in active state. */ /** Flag indicating if the page_cleaner is in active state. */
extern ibool buf_page_cleaner_is_active; extern bool buf_page_cleaner_is_active;
/** Event to synchronise with the flushing. */ /** Event to synchronise with the flushing. */
extern os_event_t buf_flush_event; extern os_event_t buf_flush_event;

View file

@ -1,7 +1,7 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 2012, 2016, Oracle and/or its affiliates. All Rights Reserved. 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 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
@ -144,6 +144,10 @@ DECLARE_THREAD(dict_stats_thread)(
void* arg); /*!< in: a dummy parameter void* arg); /*!< in: a dummy parameter
required by os_thread_create */ required by os_thread_create */
/** Shut down the dict_stats_thread. */
void
dict_stats_shutdown();
# ifndef UNIV_NONINL # ifndef UNIV_NONINL
# include "dict0stats_bg.ic" # include "dict0stats_bg.ic"
# endif # endif

View file

@ -1,6 +1,7 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved. 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 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
@ -76,22 +77,12 @@ are not found and the user wants.
@return DB_SUCCESS or error code */ @return DB_SUCCESS or error code */
UNIV_INTERN UNIV_INTERN
dberr_t dberr_t
innobase_start_or_create_for_mysql(void); innobase_start_or_create_for_mysql();
/*====================================*/
/****************************************************************//**
Shuts down the Innobase database.
@return DB_SUCCESS or error code */
UNIV_INTERN
dberr_t
innobase_shutdown_for_mysql(void);
/******************************************************************** /** Shut down InnoDB. */
Signal all per-table background threads to shutdown, and wait for them to do
so. */
UNIV_INTERN UNIV_INTERN
void void
srv_shutdown_table_bg_threads(void); innodb_shutdown();
/*=============================*/
/*************************************************************//** /*************************************************************//**
Copy the file path component of the physical file to parameter. It will Copy the file path component of the physical file to parameter. It will
@ -159,6 +150,9 @@ enum srv_shutdown_state {
SRV_SHUTDOWN_EXIT_THREADS/*!< Exit all threads */ 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 /** At a shutdown this value climbs from SRV_SHUTDOWN_NONE to
SRV_SHUTDOWN_CLEANUP and then to SRV_SHUTDOWN_LAST_PHASE, and so on */ SRV_SHUTDOWN_CLEANUP and then to SRV_SHUTDOWN_LAST_PHASE, and so on */
extern enum srv_shutdown_state srv_shutdown_state; extern enum srv_shutdown_state srv_shutdown_state;

View file

@ -2528,31 +2528,29 @@ suspend_thread:
goto loop; goto loop;
} }
/*********************************************************************//** /** Check if purge should stop.
Check if purge should stop. @param[in] n_purged pages purged in the last batch
@return true if it should shutdown. */ @return whether purge should exit */
static static
bool bool
srv_purge_should_exit( srv_purge_should_exit(ulint n_purged)
/*==============*/
ulint n_purged) /*!< in: pages purged in last batch */
{ {
switch (srv_shutdown_state) { ut_ad(srv_shutdown_state == SRV_SHUTDOWN_NONE
case SRV_SHUTDOWN_NONE: || srv_shutdown_state == SRV_SHUTDOWN_CLEANUP);
/* Normal operation. */
break;
case SRV_SHUTDOWN_CLEANUP: if (srv_undo_sources) {
case SRV_SHUTDOWN_EXIT_THREADS: return(false);
/* 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_fast_shutdown) {
return(false); 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);
} }
/*********************************************************************//** /*********************************************************************//**
@ -2813,7 +2811,7 @@ srv_purge_coordinator_suspend(
} }
rw_lock_x_unlock(&purge_sys->latch); rw_lock_x_unlock(&purge_sys->latch);
} while (stop); } while (stop && srv_undo_sources);
srv_resume_thread(slot, 0, false); srv_resume_thread(slot, 0, false);
} }
@ -2864,6 +2862,7 @@ DECLARE_THREAD(srv_purge_coordinator_thread)(
purge didn't purge any records then wait for activity. */ purge didn't purge any records then wait for activity. */
if (srv_shutdown_state == SRV_SHUTDOWN_NONE if (srv_shutdown_state == SRV_SHUTDOWN_NONE
&& srv_undo_sources
&& (purge_sys->state == PURGE_STATE_STOP && (purge_sys->state == PURGE_STATE_STOP
|| n_total_purged == 0)) { || n_total_purged == 0)) {
@ -2880,36 +2879,8 @@ DECLARE_THREAD(srv_purge_coordinator_thread)(
rseg_history_len = srv_do_purge( rseg_history_len = srv_do_purge(
srv_n_purge_threads, &n_total_purged); srv_n_purge_threads, &n_total_purged);
} while (!srv_purge_should_exit(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 /* The task queue should always be empty, independent of fast
shutdown state. */ shutdown state. */
ut_a(srv_get_task_queue_length() == 0); ut_a(srv_get_task_queue_length() == 0);

View file

@ -129,7 +129,11 @@ UNIV_INTERN ibool srv_is_being_started = FALSE;
/** TRUE if the server was successfully started */ /** TRUE if the server was successfully started */
UNIV_INTERN ibool srv_was_started = FALSE; UNIV_INTERN ibool srv_was_started = FALSE;
/** TRUE if innobase_start_or_create_for_mysql() has been called */ /** 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;
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
/** InnoDB system tablespace to set during recovery */ /** InnoDB system tablespace to set during recovery */
UNIV_INTERN uint srv_sys_space_size_debug; UNIV_INTERN uint srv_sys_space_size_debug;
@ -1620,8 +1624,7 @@ are not found and the user wants.
@return DB_SUCCESS or error code */ @return DB_SUCCESS or error code */
UNIV_INTERN UNIV_INTERN
dberr_t dberr_t
innobase_start_or_create_for_mysql(void) innobase_start_or_create_for_mysql()
/*====================================*/
{ {
bool create_new_db; bool create_new_db;
lsn_t flushed_lsn; lsn_t flushed_lsn;
@ -2776,8 +2779,8 @@ files_checked:
} }
} }
srv_startup_is_before_trx_rollback_phase = FALSE;
recv_recovery_rollback_active(); recv_recovery_rollback_active();
srv_startup_is_before_trx_rollback_phase = FALSE;
/* It is possible that file_format tag has never /* It is possible that file_format tag has never
been set. In this case we initialize it to minimum been set. In this case we initialize it to minimum
@ -2903,6 +2906,16 @@ files_checked:
srv_master_thread, srv_master_thread,
NULL, thread_ids + (1 + SRV_MAX_N_IO_THREADS)); NULL, thread_ids + (1 + SRV_MAX_N_IO_THREADS));
thread_started[1 + SRV_MAX_N_IO_THREADS] = true; 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 if (!srv_read_only_mode
@ -2946,6 +2959,7 @@ files_checked:
(thread_ids + 6 + 32)); (thread_ids + 6 + 32));
} }
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_handle = os_thread_create(buf_flush_page_cleaner_thread, NULL, NULL);
buf_flush_page_cleaner_thread_started = true; buf_flush_page_cleaner_thread_started = true;
} }
@ -2989,10 +3003,10 @@ files_checked:
if (!wsrep_recovery) { if (!wsrep_recovery) {
#endif /* WITH_WSREP */ #endif /* WITH_WSREP */
/* Create the buffer pool dump/load thread */ /* Create the buffer pool dump/load thread */
srv_buf_dump_thread_active = true;
buf_dump_thread_handle= buf_dump_thread_handle=
os_thread_create(buf_dump_thread, NULL, NULL); os_thread_create(buf_dump_thread, NULL, NULL);
srv_buf_dump_thread_active = true;
buf_dump_thread_started = true; buf_dump_thread_started = true;
#ifdef WITH_WSREP #ifdef WITH_WSREP
} else { } else {
@ -3002,15 +3016,6 @@ files_checked:
} }
#endif /* WITH_WSREP */ #endif /* WITH_WSREP */
/* Create the dict stats gathering thread */
dict_stats_thread_handle = os_thread_create(
dict_stats_thread, NULL, NULL);
srv_dict_stats_thread_active = true;
dict_stats_thread_started = true;
/* Create the thread that will optimize the FTS sub-system. */
fts_optimize_init();
/* Create thread(s) that handles key rotation */ /* Create thread(s) that handles key rotation */
fil_system_enter(); fil_system_enter();
fil_crypt_threads_init(); fil_crypt_threads_init();
@ -3060,13 +3065,10 @@ srv_fts_close(void)
} }
#endif #endif
/****************************************************************//** /** Shut down InnoDB. */
Shuts down the InnoDB database.
@return DB_SUCCESS or error code */
UNIV_INTERN UNIV_INTERN
dberr_t void
innobase_shutdown_for_mysql(void) innodb_shutdown()
/*=============================*/
{ {
ulint i; ulint i;
@ -3076,15 +3078,20 @@ innobase_shutdown_for_mysql(void)
"Shutting down an improperly started, " "Shutting down an improperly started, "
"or created database!"); "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. */ /* Shutdown the FTS optimize sub system. */
fts_optimize_start_shutdown(); fts_optimize_start_shutdown();
fts_optimize_end(); 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 /* 1. Flush the buffer pool to disk, write the current lsn to
@ -3297,89 +3304,9 @@ innobase_shutdown_for_mysql(void)
srv_was_started = FALSE; srv_was_started = FALSE;
srv_start_has_been_called = FALSE; srv_start_has_been_called = FALSE;
return(DB_SUCCESS);
} }
#endif /* !UNIV_HOTBACKUP */ #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. */ Get the meta-data filename from the table name. */
UNIV_INTERN UNIV_INTERN

View file

@ -243,6 +243,19 @@ trx_purge_add_update_undo_to_history(
hist_size + undo->size, MLOG_4BYTES, mtr); 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 */ /* Add the log as the first in the history list */
flst_add_first(rseg_header + TRX_RSEG_HISTORY, flst_add_first(rseg_header + TRX_RSEG_HISTORY,
undo_header + TRX_UNDO_HISTORY_NODE, mtr); undo_header + TRX_UNDO_HISTORY_NODE, mtr);

View file

@ -62,10 +62,10 @@ 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 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 need to protect it by a mutex. It is only ever read by the thread
doing the shutdown */ 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. */ /** Flag indicating if the lru_manager is in active state. */
UNIV_INTERN bool buf_lru_manager_is_active = false; UNIV_INTERN bool buf_lru_manager_is_active;
#ifdef UNIV_PFS_THREAD #ifdef UNIV_PFS_THREAD
UNIV_INTERN mysql_pfs_key_t buf_page_cleaner_thread_key; UNIV_INTERN mysql_pfs_key_t buf_page_cleaner_thread_key;
@ -2799,8 +2799,6 @@ DECLARE_THREAD(buf_flush_page_cleaner_thread)(
os_thread_pf(os_thread_get_curr_id())); os_thread_pf(os_thread_get_curr_id()));
#endif /* UNIV_DEBUG_THREAD_CREATION */ #endif /* UNIV_DEBUG_THREAD_CREATION */
buf_page_cleaner_is_active = TRUE;
while (srv_shutdown_state == SRV_SHUTDOWN_NONE) { while (srv_shutdown_state == SRV_SHUTDOWN_NONE) {
ulint page_cleaner_sleep_time; ulint page_cleaner_sleep_time;
@ -2909,7 +2907,7 @@ DECLARE_THREAD(buf_flush_page_cleaner_thread)(
/* We have lived our life. Time to die. */ /* We have lived our life. Time to die. */
thread_exit: thread_exit:
buf_page_cleaner_is_active = FALSE; buf_page_cleaner_is_active = false;
my_thread_end(); my_thread_end();
/* We count the number of threads in os_thread_exit(). A created /* We count the number of threads in os_thread_exit(). A created
@ -2950,8 +2948,6 @@ DECLARE_THREAD(buf_flush_lru_manager_thread)(
os_thread_pf(os_thread_get_curr_id())); os_thread_pf(os_thread_get_curr_id()));
#endif /* UNIV_DEBUG_THREAD_CREATION */ #endif /* UNIV_DEBUG_THREAD_CREATION */
buf_lru_manager_is_active = true;
/* On server shutdown, the LRU manager thread runs through cleanup /* On server shutdown, the LRU manager thread runs through cleanup
phase to provide free pages for the master and purge threads. */ phase to provide free pages for the master and purge threads. */
while (srv_shutdown_state == SRV_SHUTDOWN_NONE while (srv_shutdown_state == SRV_SHUTDOWN_NONE

View file

@ -1,7 +1,7 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 2012, 2017, Oracle and/or its affiliates. All Rights Reserved. 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 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
@ -39,12 +39,18 @@ Created Apr 25, 2012 Vasil Dimov
/** Minimum time interval between stats recalc for a given table */ /** Minimum time interval between stats recalc for a given table */
#define MIN_RECALC_INTERVAL 10 /* seconds */ #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() /** Event to wake up dict_stats_thread on dict_stats_recalc_pool_add()
or shutdown. Not protected by any mutex. */ or shutdown. Not protected by any mutex. */
UNIV_INTERN os_event_t dict_stats_event; 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. */ /** This mutex protects the "recalc_pool" variable. */
static ib_mutex_t recalc_pool_mutex; static ib_mutex_t recalc_pool_mutex;
static ib_mutex_t defrag_pool_mutex; static ib_mutex_t defrag_pool_mutex;
@ -341,11 +347,11 @@ Must be called before dict_stats_thread() is started. */
UNIV_INTERN UNIV_INTERN
void void
dict_stats_thread_init() dict_stats_thread_init()
/*====================*/
{ {
ut_a(!srv_read_only_mode); ut_a(!srv_read_only_mode);
dict_stats_event = os_event_create(); dict_stats_event = os_event_create();
dict_stats_shutdown_event = os_event_create();
/* The recalc_pool_mutex is acquired from: /* The recalc_pool_mutex is acquired from:
1) the background stats gathering thread before any other latch 1) the background stats gathering thread before any other latch
@ -390,6 +396,9 @@ dict_stats_thread_deinit()
os_event_free(dict_stats_event); os_event_free(dict_stats_event);
dict_stats_event = NULL; dict_stats_event = NULL;
os_event_free(dict_stats_shutdown_event);
dict_stats_shutdown_event = NULL;
dict_stats_start_shutdown = false;
} }
/*****************************************************************//** /*****************************************************************//**
@ -533,7 +542,7 @@ DECLARE_THREAD(dict_stats_thread)(void*)
my_thread_init(); my_thread_init();
ut_a(!srv_read_only_mode); ut_a(!srv_read_only_mode);
while (!SHUTTING_DOWN()) { while (!dict_stats_start_shutdown) {
/* Wake up periodically even if not signaled. This is /* Wake up periodically even if not signaled. This is
because we may lose an event - if the below call to because we may lose an event - if the below call to
@ -543,7 +552,7 @@ DECLARE_THREAD(dict_stats_thread)(void*)
os_event_wait_time( os_event_wait_time(
dict_stats_event, MIN_RECALC_INTERVAL * 1000000); dict_stats_event, MIN_RECALC_INTERVAL * 1000000);
if (SHUTTING_DOWN()) { if (dict_stats_start_shutdown) {
break; break;
} }
@ -557,6 +566,7 @@ DECLARE_THREAD(dict_stats_thread)(void*)
srv_dict_stats_thread_active = false; srv_dict_stats_thread_active = false;
os_event_set(dict_stats_shutdown_event);
my_thread_end(); my_thread_end();
/* We count the number of threads in os_thread_exit(). A created /* We count the number of threads in os_thread_exit(). A created
thread should always use that to exit instead of return(). */ thread should always use that to exit instead of return(). */
@ -564,3 +574,12 @@ DECLARE_THREAD(dict_stats_thread)(void*)
OS_THREAD_DUMMY_RETURN; 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);
}

View file

@ -2740,7 +2740,6 @@ fsp_reserve_free_extents(
ibool success; ibool success;
ulint n_pages_added; ulint n_pages_added;
size_t total_reserved = 0; size_t total_reserved = 0;
ulint rounds = 0;
ut_ad(mtr); ut_ad(mtr);
*n_reserved = n_ext; *n_reserved = n_ext;
@ -2819,17 +2818,7 @@ try_to_extend:
success = fsp_try_extend_data_file(&n_pages_added, space, success = fsp_try_extend_data_file(&n_pages_added, space,
space_header, mtr); space_header, mtr);
if (success && n_pages_added > 0) { if (success && n_pages_added > 0) {
rounds++;
total_reserved += n_pages_added; total_reserved += n_pages_added;
if (rounds > 50) {
ib_logf(IB_LOG_LEVEL_INFO,
"Space id %lu trying to reserve %lu extents actually reserved %lu "
" reserve %lu free %lu size %lu rounds %lu total_reserved %llu",
space, n_ext, n_pages_added, reserve, n_free, size, rounds, (ullint) total_reserved);
}
goto try_again; goto try_again;
} }

View file

@ -1610,14 +1610,11 @@ innobase_drop_database(
the path is used as the database name: the path is used as the database name:
for example, in 'mysql/data/test' the for example, in 'mysql/data/test' the
database name is 'test' */ database name is 'test' */
/*******************************************************************//** /** Shut down the InnoDB storage engine.
Closes an InnoDB database. */ @return 0 */
static static
int int
innobase_end( innobase_end(handlerton*, ha_panic_function);
/*=========*/
handlerton* hton, /* in: Innodb handlerton */
ha_panic_function type);
#if NOT_USED #if NOT_USED
/*****************************************************************//** /*****************************************************************//**
@ -4493,21 +4490,13 @@ error:
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
/*******************************************************************//** /** Shut down the InnoDB storage engine.
Closes an InnoDB database. @return 0 */
@return TRUE if error */
static static
int int
innobase_end( innobase_end(handlerton*, ha_panic_function)
/*=========*/
handlerton* hton, /*!< in/out: InnoDB handlerton */
ha_panic_function type MY_ATTRIBUTE((unused)))
/*!< in: ha_panic() parameter */
{ {
int err= 0;
DBUG_ENTER("innobase_end"); DBUG_ENTER("innobase_end");
DBUG_ASSERT(hton == innodb_hton_ptr);
if (innodb_inited) { if (innodb_inited) {
@ -4524,9 +4513,7 @@ innobase_end(
innodb_inited = 0; innodb_inited = 0;
hash_table_free(innobase_open_tables); hash_table_free(innobase_open_tables);
innobase_open_tables = NULL; innobase_open_tables = NULL;
if (innobase_shutdown_for_mysql() != DB_SUCCESS) { innodb_shutdown();
err = 1;
}
srv_free_paths_and_sizes(); srv_free_paths_and_sizes();
my_free(internal_innobase_data_file_path); my_free(internal_innobase_data_file_path);
mysql_mutex_destroy(&innobase_share_mutex); mysql_mutex_destroy(&innobase_share_mutex);
@ -4535,7 +4522,7 @@ innobase_end(
mysql_mutex_destroy(&pending_checkpoint_mutex); mysql_mutex_destroy(&pending_checkpoint_mutex);
} }
DBUG_RETURN(err); DBUG_RETURN(0);
} }
/****************************************************************//** /****************************************************************//**
@ -18818,6 +18805,10 @@ innodb_sched_priority_cleaner_update(
const void* save) /*!< in: immediate result const void* save) /*!< in: immediate result
from check function */ from check function */
{ {
if (srv_read_only_mode) {
return;
}
ulint priority = *static_cast<const ulint *>(save); ulint priority = *static_cast<const ulint *>(save);
ulint actual_priority; ulint actual_priority;
ulint nice = 0; ulint nice = 0;
@ -18844,10 +18835,6 @@ innodb_sched_priority_cleaner_update(
} }
/* Set the priority for the page cleaner thread */ /* Set the priority for the page cleaner thread */
if (srv_read_only_mode) {
return;
}
ut_ad(buf_page_cleaner_is_active); ut_ad(buf_page_cleaner_is_active);
nice = os_thread_get_priority(srv_cleaner_tid); nice = os_thread_get_priority(srv_cleaner_tid);

View file

@ -34,7 +34,7 @@ Created 11/5/1995 Heikki Tuuri
#include "buf0types.h" #include "buf0types.h"
/** Flag indicating if the page_cleaner is in active state. */ /** 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. */ /** Flag indicating if the lru_manager is in active state. */
extern bool buf_lru_manager_is_active; extern bool buf_lru_manager_is_active;

View file

@ -1,7 +1,7 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 2012, 2016, Oracle and/or its affiliates. All Rights Reserved. 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 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
@ -144,6 +144,10 @@ DECLARE_THREAD(dict_stats_thread)(
void* arg); /*!< in: a dummy parameter void* arg); /*!< in: a dummy parameter
required by os_thread_create */ required by os_thread_create */
/** Shut down the dict_stats_thread. */
void
dict_stats_shutdown();
# ifndef UNIV_NONINL # ifndef UNIV_NONINL
# include "dict0stats_bg.ic" # include "dict0stats_bg.ic"
# endif # endif

View file

@ -1,6 +1,7 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved. 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 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
@ -75,22 +76,12 @@ are not found and the user wants.
@return DB_SUCCESS or error code */ @return DB_SUCCESS or error code */
UNIV_INTERN UNIV_INTERN
dberr_t dberr_t
innobase_start_or_create_for_mysql(void); innobase_start_or_create_for_mysql();
/*====================================*/
/****************************************************************//**
Shuts down the Innobase database.
@return DB_SUCCESS or error code */
UNIV_INTERN
dberr_t
innobase_shutdown_for_mysql(void);
/******************************************************************** /** Shut down InnoDB. */
Signal all per-table background threads to shutdown, and wait for them to do
so. */
UNIV_INTERN UNIV_INTERN
void void
srv_shutdown_table_bg_threads(void); innodb_shutdown();
/*=============================*/
/*************************************************************//** /*************************************************************//**
Copy the file path component of the physical file to parameter. It will 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 */ 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 /** At a shutdown this value climbs from SRV_SHUTDOWN_NONE to
SRV_SHUTDOWN_CLEANUP and then to SRV_SHUTDOWN_LAST_PHASE, and so on */ SRV_SHUTDOWN_CLEANUP and then to SRV_SHUTDOWN_LAST_PHASE, and so on */
extern enum srv_shutdown_state srv_shutdown_state; extern enum srv_shutdown_state srv_shutdown_state;

View file

@ -3214,31 +3214,29 @@ suspend_thread:
goto loop; goto loop;
} }
/*********************************************************************//** /** Check if purge should stop.
Check if purge should stop. @param[in] n_purged pages purged in the last batch
@return true if it should shutdown. */ @return whether purge should exit */
static static
bool bool
srv_purge_should_exit( srv_purge_should_exit(ulint n_purged)
/*==============*/
ulint n_purged) /*!< in: pages purged in last batch */
{ {
switch (srv_shutdown_state) { ut_ad(srv_shutdown_state == SRV_SHUTDOWN_NONE
case SRV_SHUTDOWN_NONE: || srv_shutdown_state == SRV_SHUTDOWN_CLEANUP);
/* Normal operation. */
break;
case SRV_SHUTDOWN_CLEANUP: if (srv_undo_sources) {
case SRV_SHUTDOWN_EXIT_THREADS: return(false);
/* 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_fast_shutdown) {
return(false); 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);
} }
/*********************************************************************//** /*********************************************************************//**
@ -3513,7 +3511,7 @@ srv_purge_coordinator_suspend(
} }
rw_lock_x_unlock(&purge_sys->latch); rw_lock_x_unlock(&purge_sys->latch);
} while (stop); } while (stop && srv_undo_sources);
srv_resume_thread(slot, 0, false); srv_resume_thread(slot, 0, false);
} }
@ -3567,6 +3565,7 @@ DECLARE_THREAD(srv_purge_coordinator_thread)(
purge didn't purge any records then wait for activity. */ purge didn't purge any records then wait for activity. */
if (srv_shutdown_state == SRV_SHUTDOWN_NONE if (srv_shutdown_state == SRV_SHUTDOWN_NONE
&& srv_undo_sources
&& (purge_sys->state == PURGE_STATE_STOP && (purge_sys->state == PURGE_STATE_STOP
|| n_total_purged == 0)) { || n_total_purged == 0)) {
@ -3587,36 +3586,8 @@ DECLARE_THREAD(srv_purge_coordinator_thread)(
srv_n_purge_threads, &n_total_purged); srv_n_purge_threads, &n_total_purged);
srv_inc_activity_count(); srv_inc_activity_count();
} while (!srv_purge_should_exit(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 /* The task queue should always be empty, independent of fast
shutdown state. */ shutdown state. */
ut_a(srv_get_task_queue_length() == 0); ut_a(srv_get_task_queue_length() == 0);

View file

@ -132,7 +132,11 @@ UNIV_INTERN ibool srv_is_being_started = FALSE;
/** TRUE if the server was successfully started */ /** TRUE if the server was successfully started */
UNIV_INTERN ibool srv_was_started = FALSE; UNIV_INTERN ibool srv_was_started = FALSE;
/** TRUE if innobase_start_or_create_for_mysql() has been called */ /** 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;
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
/** InnoDB system tablespace to set during recovery */ /** InnoDB system tablespace to set during recovery */
UNIV_INTERN uint srv_sys_space_size_debug; UNIV_INTERN uint srv_sys_space_size_debug;
@ -1684,8 +1688,7 @@ are not found and the user wants.
@return DB_SUCCESS or error code */ @return DB_SUCCESS or error code */
UNIV_INTERN UNIV_INTERN
dberr_t dberr_t
innobase_start_or_create_for_mysql(void) innobase_start_or_create_for_mysql()
/*====================================*/
{ {
bool create_new_db; bool create_new_db;
lsn_t flushed_lsn; lsn_t flushed_lsn;
@ -2862,8 +2865,8 @@ files_checked:
} }
} }
srv_startup_is_before_trx_rollback_phase = FALSE;
recv_recovery_rollback_active(); recv_recovery_rollback_active();
srv_startup_is_before_trx_rollback_phase = FALSE;
/* It is possible that file_format tag has never /* It is possible that file_format tag has never
been set. In this case we initialize it to minimum been set. In this case we initialize it to minimum
@ -2995,6 +2998,16 @@ files_checked:
srv_master_thread, srv_master_thread,
NULL, thread_ids + (1 + SRV_MAX_N_IO_THREADS)); NULL, thread_ids + (1 + SRV_MAX_N_IO_THREADS));
thread_started[1 + SRV_MAX_N_IO_THREADS] = true; 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 if (!srv_read_only_mode
@ -3039,12 +3052,16 @@ files_checked:
} }
buf_flush_page_cleaner_thread_handle = os_thread_create(buf_flush_page_cleaner_thread, NULL, NULL); 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; buf_flush_page_cleaner_thread_started = true;
}
buf_flush_lru_manager_thread_handle = os_thread_create(buf_flush_lru_manager_thread, NULL, NULL); buf_lru_manager_is_active = true;
buf_flush_lru_manager_thread_started = true; buf_flush_lru_manager_thread_handle = os_thread_create(
buf_flush_lru_manager_thread, NULL, NULL);
buf_flush_lru_manager_thread_started = true;
}
if (!srv_file_per_table && srv_pass_corrupt_table) { if (!srv_file_per_table && srv_pass_corrupt_table) {
fprintf(stderr, "InnoDB: Warning:" fprintf(stderr, "InnoDB: Warning:"
@ -3092,10 +3109,10 @@ files_checked:
if (!wsrep_recovery) { if (!wsrep_recovery) {
#endif /* WITH_WSREP */ #endif /* WITH_WSREP */
/* Create the buffer pool dump/load thread */ /* Create the buffer pool dump/load thread */
srv_buf_dump_thread_active = true;
buf_dump_thread_handle= buf_dump_thread_handle=
os_thread_create(buf_dump_thread, NULL, NULL); os_thread_create(buf_dump_thread, NULL, NULL);
srv_buf_dump_thread_active = true;
buf_dump_thread_started = true; buf_dump_thread_started = true;
#ifdef WITH_WSREP #ifdef WITH_WSREP
} else { } else {
@ -3105,15 +3122,6 @@ files_checked:
} }
#endif /* WITH_WSREP */ #endif /* WITH_WSREP */
/* Create the dict stats gathering thread */
dict_stats_thread_handle = os_thread_create(
dict_stats_thread, NULL, NULL);
srv_dict_stats_thread_active = true;
dict_stats_thread_started = true;
/* Create the thread that will optimize the FTS sub-system. */
fts_optimize_init();
/* Create thread(s) that handles key rotation */ /* Create thread(s) that handles key rotation */
fil_system_enter(); fil_system_enter();
fil_crypt_threads_init(); fil_crypt_threads_init();
@ -3163,13 +3171,10 @@ srv_fts_close(void)
} }
#endif #endif
/****************************************************************//** /** Shut down InnoDB. */
Shuts down the InnoDB database.
@return DB_SUCCESS or error code */
UNIV_INTERN UNIV_INTERN
dberr_t void
innobase_shutdown_for_mysql(void) innodb_shutdown()
/*=============================*/
{ {
ulint i; ulint i;
@ -3179,15 +3184,20 @@ innobase_shutdown_for_mysql(void)
"Shutting down an improperly started, " "Shutting down an improperly started, "
"or created database!"); "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. */ /* Shutdown the FTS optimize sub system. */
fts_optimize_start_shutdown(); fts_optimize_start_shutdown();
fts_optimize_end(); 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 /* 1. Flush the buffer pool to disk, write the current lsn to
@ -3402,88 +3412,9 @@ innobase_shutdown_for_mysql(void)
srv_start_has_been_called = FALSE; srv_start_has_been_called = FALSE;
/* reset io_tid_i, in case current process does second innodb start (xtrabackup might do that).*/ /* reset io_tid_i, in case current process does second innodb start (xtrabackup might do that).*/
io_tid_i = 0; io_tid_i = 0;
return(DB_SUCCESS);
} }
#endif /* !UNIV_HOTBACKUP */ #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. */ Get the meta-data filename from the table name. */
UNIV_INTERN UNIV_INTERN

View file

@ -247,6 +247,19 @@ trx_purge_add_update_undo_to_history(
hist_size + undo->size, MLOG_4BYTES, mtr); 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 */ /* Add the log as the first in the history list */
flst_add_first(rseg_header + TRX_RSEG_HISTORY, flst_add_first(rseg_header + TRX_RSEG_HISTORY,
undo_header + TRX_UNDO_HISTORY_NODE, mtr); undo_header + TRX_UNDO_HISTORY_NODE, mtr);