Repository navigation
MDEV-41395 fil_space_t::create() may release fil_system.mutex - #5823
Conversation
|
|
| fil_node_t* node = space->add(path, OS_FILE_CLOSED, size, false, true); | ||
| space->set_stopped(); | ||
| mysql_mutex_unlock(&fil_system.mutex); | ||
| fil_crypt_threads_signal(); |
There was a problem hiding this comment.
Encryption threads wakes up and skips the tablespace which are stopped. We're calling fil_crypt_threads_signal() after space->set_stopped()
There was a problem hiding this comment.
diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc
index 3b6d8282aba..9878b2854d3 100644
--- a/storage/innobase/fil/fil0fil.cc
+++ b/storage/innobase/fil/fil0fil.cc
@@ -2022,7 +2022,6 @@ fil_ibd_create(
fil_node_t* node = space->add(path, OS_FILE_CLOSED, size, false, true);
space->set_stopped();
mysql_mutex_unlock(&fil_system.mutex);
- fil_crypt_threads_signal();
buf_block_t *header[2];
{
@@ -2132,6 +2131,7 @@ fil_ibd_create(
space->release();
}
mysql_mutex_unlock(&fil_system.mutex);
+ fil_crypt_threads_signal();
goto func_exit;
}
|
|
||
| mysql_mutex_lock(&fil_system.mutex); | ||
| space->clear_stopped(); | ||
| node->handle = file; |
There was a problem hiding this comment.
we need to signal here after clear_stopped?
| prebuilt->trx->op_info = ""; | ||
|
|
||
| DBUG_EXECUTE_IF("ib_import_before_checkpoint_crash", DBUG_SUICIDE();); | ||
| fil_crypt_threads_signal(); |
There was a problem hiding this comment.
err = row_import_for_mysql(m_prebuilt->table, m_prebuilt);
if (err == DB_SUCCESS) {
info(HA_STATUS_TIME
| HA_STATUS_CONST
| HA_STATUS_VARIABLE
| HA_STATUS_AUTO);
fil_crypt_add_imported_space(m_prebuilt->table->space);
}
fil_crypt_add_imported_space() is already signaling the fil_crypt_threads_cond
There was a problem hiding this comment.
Do we need the signal here?
8214825 to
7d81395
Compare
If fil_space_t::create() ends up releasing fil_system.mutex for invoking fil_crypt_threads_signal(), another thread may grab fil_system.mutex and find a tablespace that contains no data files. Let us fix this race condition and remove some checks that now are redundant. By default fil_crypt_must_default_encrypt() holds, and then fil_crypt_thread() waits indefinitely in wait_for_work() once the default_encrypt list has been exhausted. A tablespace for which no fil_crypt_threads_signal() is issued would therefore never be encrypted at all. fil_space_t::create(): Do not invoke fil_crypt_threads_init(); let the caller do that. During database startup, before fil_crypt_threads_init() has been invoked, there is no point to invoke this function; the encryption queues will be properly set up for the tablespaces that have been opened by that time. fil_ibd_create(): Invoke fil_crypt_threads_signal() after invoking fil_space_t::clear_stopped() and releasing fil_system.mutex. fil_crypt_threads_signal(): Check that fil_crypt_threads_init() has been called. The function dict_table_open_on_name() will be invoked during early server startup. dict_table_open_on_name(): Invoke fil_crypt_threads_init() at the end if the table was loaded into the cache and the tablespace likely as well. This should be the main code path through which old tablespaces are opened via SQL. dict_load_tablespace(): Invoke fil_crypt_threads_signal(), because fil_ibd_open() may have added the tablespace to fil_system.default_encrypt_tables. This is the single point through which every dictionary-driven tablespace open passes; it is only invoked by dict_load_table_one(), hence by dict_sys_t::load_table(). We will not invoke fil_crypt_threads_init() in dict_load_table_on_id() or dict_sys.load_table(); it will instead be invoked at a higher level, typically when a table definition is first loaded by name, in dict_table_open_on_name(). buf_dump_load_func(): After the non-first buf_load(), invoke fil_crypt_threads_signal() in order to start the encryption of any newly loaded tablespaces. drop_garbage_tables_after_restore(), wsrep_append_foreign_key(), ha_innobase::create(), ha_innobase::truncate(), row_rename_table_for_mysql(), i_s_sys_tables_fill_table(), i_s_sys_tables_fill_table_stats(): Invoke fil_crypt_threads_signal() in case some tablespace metadata was loaded. row_import_cleanup(): Invoke fil_crypt_threads_signal() to register the imported tablespace. i_s_sys_tablespaces_fill_table(), fil_system_t::find(), Datafile::validate_first_page(), fil_space_t::name(), fil_space_t::read_page0(), fil_space_t::prepare_acquired(), fil_space_t::try_to_close(), fil_crypt_default_encrypt_tables_fill(), fil_system_t::default_encrypt_next(): Remove a now-redundant check for a tablespace that contains no files. srv_n_fil_crypt_threads_started: Declare as Atomic_relaxed<uint>, for the unlocked read in fil_crypt_threads_signal(). Co-developed by: Thirunarayanan Balathandayuthapani
If
fil_space_t::create()ends up releasingfil_system.mutexfor invokingfil_crypt_threads_signal(), another thread may grabfil_system.mutexand find a tablespace that contains no data files. Let us fix this race condition and remove some checks that now are redundant.fil_space_t::create(): Do not invokefil_crypt_threads_init(); let the caller do that. During database startup, beforefil_crypt_threads_init()has been invoked, there is no point to invoke this function; the encryption queues will be properly set up for the tablespaces that have been opened by that time.fil_ibd_create(): Invokefil_crypt_threads_signal()after releasingfil_system.mutex.fil_crypt_threads_signal(): Check thatfil_crypt_threads_init()has been called. The functiondict_table_open_on_name()will be invoked during early server startup.dict_table_open_on_name(): Invokefil_crypt_threads_init()at the end if the table was loaded into the cache and the tablespace likely as well. This should be the main code path through which old tablespaces are opened via SQL.We will not invoke
fil_crypt_threads_init()indict_load_table_on_id()ordict_sys.load_table(); it will instead be invoked at a higher level, typically when a table definition is first loaded by name, indict_table_open_on_name().buf_dump_load_func(): After the non-firstbuf_load(), invokefil_crypt_threads_signal()in order to start the encryption of any newly loaded tablespaces.drop_garbage_tables_after_restore(),wsrep_append_foreign_key(),ha_innobase::create(),ha_innobase::truncate(),row_rename_table_for_mysql(),i_s_sys_tables_fill_table(),i_s_sys_tables_fill_table_stats(): Invokefil_crypt_threads_signal()in case some tablespace metadata was loaded.row_import_cleanup(): Invokefil_crypt_threads_signal()to register the imported tablespace.i_s_sys_tablespaces_fill_table(),fil_system_t::find(),Datafile::validate_first_page(),fil_space_t::name(),fil_space_t::read_page0(),fil_space_t::prepare_acquired(),fil_space_t::try_to_close(),fil_crypt_default_encrypt_tables_fill(),fil_system_t::default_encrypt_next(): Remove a now-redundant check for a tablespace that contains no files.