Commit ee80c196 authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-26551 InnoDB crash on multiple concurrent SHOW TABLE STATUS

dict_get_and_save_data_dir_path(): Protect the operation with
dict_table_t::lock_mutex and avoid unnecessary memory allocation.
parent 31ad9277
......@@ -2078,74 +2078,26 @@ const char *dict_load_table_low(const span<const char> &name,
return(NULL);
}
/********************************************************************//**
Using the table->heap, copy the null-terminated filepath into
table->data_dir_path and replace the 'databasename/tablename.ibd'
portion with 'tablename'.
This allows SHOW CREATE TABLE to return the correct DATA DIRECTORY path.
Make this data directory path only if it has not yet been saved. */
static
void
dict_save_data_dir_path(
/*====================*/
dict_table_t* table, /*!< in/out: table */
const char* filepath) /*!< in: filepath of tablespace */
{
ut_ad(dict_sys.frozen());
ut_a(DICT_TF_HAS_DATA_DIR(table->flags));
ut_a(!table->data_dir_path);
ut_a(filepath);
/* Be sure this filepath is not the default filepath. */
if (char* default_filepath = fil_make_filepath(nullptr, table->name,
IBD, false)) {
if (0 != strcmp(filepath, default_filepath)) {
ulint pathlen = strlen(filepath);
ut_a(pathlen < OS_FILE_MAX_PATH);
ut_a(0 == strcmp(filepath + pathlen - 4, DOT_IBD));
table->data_dir_path = mem_heap_strdup(
table->heap, filepath);
os_file_make_data_dir_path(table->data_dir_path);
}
ut_free(default_filepath);
}
}
/** Make sure the data_file_name is saved in dict_table_t if needed.
@param[in,out] table Table object
@param[in] dict_locked dict_sys.frozen() */
void dict_get_and_save_data_dir_path(dict_table_t* table, bool dict_locked)
@param[in,out] table Table object */
void dict_get_and_save_data_dir_path(dict_table_t *table)
{
ut_ad(!table->is_temporary());
ut_ad(!table->space || table->space->id == table->space_id);
if (!table->data_dir_path && table->space_id && table->space) {
if (!dict_locked) {
dict_sys.freeze(SRW_LOCK_CALL);
}
table->flags |= 1 << DICT_TF_POS_DATA_DIR
& ((1U << DICT_TF_BITS) - 1);
dict_save_data_dir_path(table,
table->space->chain.start->name);
if (table->data_dir_path == NULL) {
/* Since we did not set the table data_dir_path,
unset the flag. This does not change
SYS_TABLES or FSP_SPACE_FLAGS on the header page
of the tablespace, but it makes dict_table_t
consistent. */
table->flags &= ~DICT_TF_MASK_DATA_DIR
& ((1U << DICT_TF_BITS) - 1);
}
ut_ad(!table->is_temporary());
ut_ad(!table->space || table->space->id == table->space_id);
if (!dict_locked) {
dict_sys.unfreeze();
}
}
if (!table->data_dir_path && table->space_id && table->space)
{
const char *filepath= table->space->chain.start->name;
if (strncmp(fil_path_to_mysql_datadir, filepath,
strlen(fil_path_to_mysql_datadir)))
{
table->lock_mutex_lock();
table->flags|= 1 << DICT_TF_POS_DATA_DIR & ((1U << DICT_TF_BITS) - 1);
table->data_dir_path= mem_heap_strdup(table->heap, filepath);
os_file_make_data_dir_path(table->data_dir_path);
table->lock_mutex_unlock();
}
}
}
/** Opens a tablespace for dict_load_table_one()
......@@ -2199,7 +2151,7 @@ dict_load_tablespace(
char* filepath = NULL;
if (DICT_TF_HAS_DATA_DIR(table->flags)) {
/* This will set table->data_dir_path from fil_system */
dict_get_and_save_data_dir_path(table, true);
dict_get_and_save_data_dir_path(table);
if (table->data_dir_path) {
filepath = fil_make_filepath(
......
......@@ -11427,7 +11427,7 @@ ha_innobase::update_create_info(
return;
}
dict_get_and_save_data_dir_path(m_prebuilt->table, false);
dict_get_and_save_data_dir_path(m_prebuilt->table);
if (m_prebuilt->table->data_dir_path) {
create_info->data_file_name = m_prebuilt->table->data_dir_path;
......@@ -13842,7 +13842,7 @@ int ha_innobase::truncate()
mem_heap_t* heap = mem_heap_create(1000);
dict_get_and_save_data_dir_path(ib_table, false);
dict_get_and_save_data_dir_path(ib_table);
info.data_file_name = ib_table->data_dir_path;
const char* temp_name = dict_mem_create_temporary_tablename(
heap, ib_table->name.m_name, ib_table->id);
......
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 2021, MariaDB Corporation.
Copyright (c) 2017, 2022, 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
......@@ -53,9 +53,8 @@ We also scan the biggest space id, and store it to fil_system. */
void dict_check_tablespaces_and_store_max_id();
/** Make sure the data_file_name is saved in dict_table_t if needed.
@param[in,out] table Table object
@param[in] dict_locked dict_sys.frozen() */
void dict_get_and_save_data_dir_path(dict_table_t* table, bool dict_locked);
@param[in,out] table Table object */
void dict_get_and_save_data_dir_path(dict_table_t* table);
/***********************************************************************//**
Loads a table object based on the table id.
......
......@@ -3128,7 +3128,7 @@ and apply it to dict_table_t
static dberr_t handle_instant_metadata(dict_table_t *table,
const row_import &cfg)
{
dict_get_and_save_data_dir_path(table, false);
dict_get_and_save_data_dir_path(table);
char *filepath;
if (DICT_TF_HAS_DATA_DIR(table->flags))
......@@ -4167,7 +4167,7 @@ fil_tablespace_iterate(
return(DB_CORRUPTION););
/* Make sure the data_dir_path is set. */
dict_get_and_save_data_dir_path(table, false);
dict_get_and_save_data_dir_path(table);
ut_ad(!DICT_TF_HAS_DATA_DIR(table->flags) || table->data_dir_path);
......@@ -4488,7 +4488,7 @@ row_import_for_mysql(
/* If the table is stored in a remote tablespace, we need to
determine that filepath from the link file and system tables.
Find the space ID in SYS_TABLES since this is an ALTER TABLE. */
dict_get_and_save_data_dir_path(table, true);
dict_get_and_save_data_dir_path(table);
ut_ad(!DICT_TF_HAS_DATA_DIR(table->flags) || table->data_dir_path);
const char *data_dir_path = DICT_TF_HAS_DATA_DIR(table->flags)
......
......@@ -2072,7 +2072,7 @@ srv_get_meta_data_filename(
char* path;
/* Make sure the data_dir_path is set. */
dict_get_and_save_data_dir_path(table, false);
dict_get_and_save_data_dir_path(table);
const char* data_dir_path = DICT_TF_HAS_DATA_DIR(table->flags)
? table->data_dir_path : nullptr;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment