Skip to content

Commit

Permalink
MDEV-11638 Encryption causes race conditions in InnoDB shutdown
Browse files Browse the repository at this point in the history
InnoDB shutdown failed to properly take fil_crypt_thread() into account.
The encryption threads were signalled to shut down together with other
non-critical tasks. This could be much too early in case of slow shutdown,
which could need minutes to complete the purge. Furthermore, InnoDB
failed to wait for the fil_crypt_thread() to actually exit before
proceeding to the final steps of shutdown, causing the race conditions.

Furthermore, the log_scrub_thread() was shut down way too early.
Also it should remain until the SRV_SHUTDOWN_FLUSH_PHASE.

fil_crypt_threads_end(): Remove. This would cause the threads to
be terminated way too early.

srv_buf_dump_thread_active, srv_dict_stats_thread_active,
lock_sys->timeout_thread_active, log_scrub_thread_active,
srv_monitor_active, srv_error_monitor_active: Remove a race condition
between startup and shutdown, by setting these in the startup thread
that creates threads, not in each created thread. In this way, once the
flag is cleared, it will remain cleared during shutdown.

srv_n_fil_crypt_threads_started, fil_crypt_threads_event: Declare in
global rather than static scope.

log_scrub_event, srv_log_scrub_thread_active, log_scrub_thread():
Declare in static rather than global scope. Let these be created by
log_init() and freed by log_shutdown().

rotate_thread_t::should_shutdown(): Do not shut down before the
SRV_SHUTDOWN_FLUSH_PHASE.

srv_any_background_threads_are_active(): Remove. These checks now
exist in logs_empty_and_mark_files_at_shutdown().

logs_empty_and_mark_files_at_shutdown(): Shut down the threads in
the proper order. Keep fil_crypt_thread() and log_scrub_thread() alive
until SRV_SHUTDOWN_FLUSH_PHASE, and check that they actually terminate.
  • Loading branch information
dr-m committed Jan 4, 2017
1 parent 0f8e17a commit 719321e
Show file tree
Hide file tree
Showing 22 changed files with 339 additions and 578 deletions.
10 changes: 3 additions & 7 deletions storage/innobase/buf/buf0dump.cc
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 2011, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, MariaDB Corporation. All Rights Reserved.
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
Expand Down Expand Up @@ -682,15 +683,10 @@ again.
@return this function does not return, it calls os_thread_exit() */
extern "C" UNIV_INTERN
os_thread_ret_t
DECLARE_THREAD(buf_dump_thread)(
/*============================*/
void* arg MY_ATTRIBUTE((unused))) /*!< in: a dummy parameter
required by os_thread_create */
DECLARE_THREAD(buf_dump_thread)(void*)
{
ut_ad(!srv_read_only_mode);

srv_buf_dump_thread_active = TRUE;

buf_dump_status(STATUS_INFO, "Dumping buffer pool(s) not yet started");
buf_load_status(STATUS_INFO, "Loading buffer pool(s) not yet started");

Expand Down Expand Up @@ -720,7 +716,7 @@ DECLARE_THREAD(buf_dump_thread)(
keep going even if we are in a shutdown state */);
}

srv_buf_dump_thread_active = FALSE;
srv_buf_dump_thread_active = false;

/* We count the number of threads in os_thread_exit(). A created
thread should always use that to exit and not use return() to exit. */
Expand Down
10 changes: 3 additions & 7 deletions storage/innobase/dict/dict0stats_bg.cc
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 2012, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, MariaDB Corporation. All Rights Reserved.
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
Expand Down Expand Up @@ -525,15 +526,10 @@ statistics.
@return this function does not return, it calls os_thread_exit() */
extern "C" UNIV_INTERN
os_thread_ret_t
DECLARE_THREAD(dict_stats_thread)(
/*==============================*/
void* arg MY_ATTRIBUTE((unused))) /*!< in: a dummy parameter
required by os_thread_create */
DECLARE_THREAD(dict_stats_thread)(void*)
{
ut_a(!srv_read_only_mode);

srv_dict_stats_thread_active = TRUE;

while (!SHUTTING_DOWN()) {

/* Wake up periodically even if not signaled. This is
Expand All @@ -556,7 +552,7 @@ DECLARE_THREAD(dict_stats_thread)(
os_event_reset(dict_stats_event);
}

srv_dict_stats_thread_active = FALSE;
srv_dict_stats_thread_active = false;

/* We count the number of threads in os_thread_exit(). A created
thread should always use that to exit instead of return(). */
Expand Down
35 changes: 17 additions & 18 deletions storage/innobase/fil/fil0crypt.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (C) 2013, 2015, Google Inc. All Rights Reserved.
Copyright (C) 2014, 2016, MariaDB Corporation. All Rights Reserved.
Copyright (c) 2014, 2017, MariaDB Corporation. All Rights Reserved.
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
Expand Down Expand Up @@ -56,7 +56,7 @@ UNIV_INTERN ulong srv_encrypt_tables = 0;
UNIV_INTERN uint srv_n_fil_crypt_threads = 0;

/** No of key rotation threads started */
static uint srv_n_fil_crypt_threads_started = 0;
UNIV_INTERN uint srv_n_fil_crypt_threads_started = 0;

/** At this age or older a space/page will be rotated */
UNIV_INTERN uint srv_fil_crypt_rotate_key_age = 1;
Expand All @@ -65,7 +65,7 @@ UNIV_INTERN uint srv_fil_crypt_rotate_key_age = 1;
static os_event_t fil_crypt_event;

/** Event to signal TO the key rotation threads. */
static os_event_t fil_crypt_threads_event;
UNIV_INTERN os_event_t fil_crypt_threads_event;

/** Event for waking up threads throttle */
static os_event_t fil_crypt_throttle_sleep_event;
Expand Down Expand Up @@ -1303,10 +1303,20 @@ struct rotate_thread_t {
btr_scrub_t scrub_data; /* thread local data used by btr_scrub-functions
* when iterating pages of tablespace */

/* check if this thread should shutdown */
/** @return whether this thread should terminate */
bool should_shutdown() const {
return ! (srv_shutdown_state == SRV_SHUTDOWN_NONE &&
thread_no < srv_n_fil_crypt_threads);
switch (srv_shutdown_state) {
case SRV_SHUTDOWN_NONE:
case SRV_SHUTDOWN_CLEANUP:
return thread_no >= srv_n_fil_crypt_threads;
case SRV_SHUTDOWN_FLUSH_PHASE:
return true;
case SRV_SHUTDOWN_LAST_PHASE:
case SRV_SHUTDOWN_EXIT_THREADS:
break;
}
ut_ad(0);
return true;
}
};

Expand Down Expand Up @@ -2458,18 +2468,6 @@ fil_crypt_threads_init()
}
}

/*********************************************************************
End threads for key rotation */
UNIV_INTERN
void
fil_crypt_threads_end()
/*===================*/
{
if (fil_crypt_threads_inited) {
fil_crypt_set_thread_cnt(0);
}
}

/*********************************************************************
Clean up key rotation threads resources */
UNIV_INTERN
Expand All @@ -2480,6 +2478,7 @@ fil_crypt_threads_cleanup()
if (!fil_crypt_threads_inited) {
return;
}
ut_a(!srv_n_fil_crypt_threads_started);
os_event_free(fil_crypt_event);
os_event_free(fil_crypt_threads_event);
mutex_free(&fil_crypt_threads_mutex);
Expand Down
4 changes: 1 addition & 3 deletions storage/innobase/handler/ha_innodb.cc
@@ -1,10 +1,10 @@
/*****************************************************************************

Copyright (c) 2000, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2013, 2017, MariaDB Corporation.
Copyright (c) 2008, 2009 Google Inc.
Copyright (c) 2009, Percona Inc.
Copyright (c) 2012, Facebook Inc.
Copyright (c) 2013, 2016, MariaDB Corporation.

Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
Expand Down Expand Up @@ -73,7 +73,6 @@ MYSQL_PLUGIN_IMPORT extern char mysql_unpacked_real_data_home[];
#include "srv0srv.h"
#include "trx0roll.h"
#include "trx0trx.h"

#include "trx0sys.h"
#include "rem0types.h"
#include "row0ins.h"
Expand Down Expand Up @@ -248,7 +247,6 @@ static char* internal_innobase_data_file_path = NULL;

static char* innodb_version_str = (char*) INNODB_VERSION_STR;

extern uint srv_n_fil_crypt_threads;
extern uint srv_fil_crypt_rotate_key_age;
extern uint srv_n_fil_crypt_iops;

Expand Down
12 changes: 5 additions & 7 deletions storage/innobase/include/fil0crypt.h
@@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (C) 2013, 2015, Google Inc. All Rights Reserved.
Copyright (c) 2015, 2016, MariaDB Corporation.
Copyright (c) 2015, 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
Expand All @@ -26,6 +26,8 @@ Created 04/01/2015 Jan Lindström
#ifndef fil0crypt_h
#define fil0crypt_h

#include "os0sync.h"

/**
* Magic pattern in start of crypt data on page 0
*/
Expand All @@ -45,6 +47,8 @@ typedef enum {
FIL_SPACE_ENCRYPTION_OFF = 2 /* Tablespace is not encrypted */
} fil_encryption_t;

extern os_event_t fil_crypt_threads_event;

/**
* CRYPT_SCHEME_UNENCRYPTED
*
Expand Down Expand Up @@ -391,12 +395,6 @@ fil_crypt_set_thread_cnt(
/*=====================*/
uint new_cnt); /*!< in: requested #threads */

/*********************************************************************
End threads for key rotation */
UNIV_INTERN
void
fil_crypt_threads_end();

/*********************************************************************
Cleanup resources for threads for key rotation */
UNIV_INTERN
Expand Down
14 changes: 1 addition & 13 deletions storage/innobase/include/log0log.h
Expand Up @@ -2,6 +2,7 @@
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2009, Google Inc.
Copyright (c) 2017, MariaDB Corporation
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
Expand Down Expand Up @@ -1013,22 +1014,9 @@ struct log_t{
/* @} */
#endif /* UNIV_LOG_ARCHIVE */

extern os_event_t log_scrub_event;
/* log scrubbing speed, in bytes/sec */
extern ulonglong innodb_scrub_log_speed;

/*****************************************************************//**
This is the main thread for log scrub. It waits for an event and
when waked up fills current log block with dummy records and
sleeps again.
@return this function does not return, it calls os_thread_exit() */
extern "C" UNIV_INTERN
os_thread_ret_t
DECLARE_THREAD(log_scrub_thread)(
/*===============================*/
void* arg); /*!< in: a dummy parameter
required by os_thread_create */

#ifndef UNIV_NONINL
#include "log0log.ic"
#endif
Expand Down
24 changes: 8 additions & 16 deletions storage/innobase/include/srv0srv.h
Expand Up @@ -3,7 +3,7 @@
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2008, 2009, Google Inc.
Copyright (c) 2009, Percona Inc.
Copyright (c) 2013, 2016, MariaDB Corporation
Copyright (c) 2013, 2017, MariaDB Corporation
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
Expand Down Expand Up @@ -328,6 +328,9 @@ extern char** srv_data_file_names;
extern ulint* srv_data_file_sizes;
extern ulint* srv_data_file_is_raw_partition;

extern uint srv_n_fil_crypt_threads;
extern uint srv_n_fil_crypt_threads_started;

extern ibool srv_auto_extend_last_data_file;
extern ulint srv_last_file_size_max;
extern char* srv_log_group_home_dir;
Expand Down Expand Up @@ -478,19 +481,17 @@ extern ibool srv_print_verbose_log;
"tables instead, see " REFMAN "innodb-i_s-tables.html"
extern ibool srv_print_innodb_table_monitor;

extern ibool srv_monitor_active;
extern ibool srv_error_monitor_active;
extern bool srv_monitor_active;
extern bool srv_error_monitor_active;

/* TRUE during the lifetime of the buffer pool dump/load thread */
extern ibool srv_buf_dump_thread_active;
extern bool 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;

/* TRUE if enable log scrubbing */
extern my_bool srv_scrub_log;
/* TRUE during the lifetime of the log scrub thread */
extern ibool srv_log_scrub_thread_active;

extern ulong srv_n_spin_wait_rounds;
extern ulong srv_n_free_tickets_to_enter;
Expand Down Expand Up @@ -899,15 +900,6 @@ srv_release_threads(
enum srv_thread_type type, /*!< in: thread type */
ulint n); /*!< in: number of threads to release */

/**********************************************************************//**
Check whether any background thread are active. If so print which thread
is active. Send the threads wakeup signal.
@return name of thread that is active or NULL */
UNIV_INTERN
const char*
srv_any_background_threads_are_active(void);
/*=======================================*/

/**********************************************************************//**
Wakeup the purge threads. */
UNIV_INTERN
Expand Down
9 changes: 2 additions & 7 deletions storage/innobase/lock/lock0wait.cc
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, MariaDB Corporation. All Rights Reserved.
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
Expand Down Expand Up @@ -510,11 +511,7 @@ A thread which wakes up threads whose lock wait may have lasted too long.
@return a dummy parameter */
extern "C" UNIV_INTERN
os_thread_ret_t
DECLARE_THREAD(lock_wait_timeout_thread)(
/*=====================================*/
void* arg MY_ATTRIBUTE((unused)))
/* in: a dummy parameter required by
os_thread_create */
DECLARE_THREAD(lock_wait_timeout_thread)(void*)
{
ib_int64_t sig_count = 0;
os_event_t event = lock_sys->timeout_event;
Expand All @@ -525,8 +522,6 @@ DECLARE_THREAD(lock_wait_timeout_thread)(
pfs_register_thread(srv_lock_timeout_thread_key);
#endif /* UNIV_PFS_THREAD */

lock_sys->timeout_thread_active = true;

do {
srv_slot_t* slot;

Expand Down

0 comments on commit 719321e

Please sign in to comment.