summaryrefslogtreecommitdiff
path: root/storage/innobase/fsp/fsp0file.cc
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2021-04-07 18:01:13 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2021-04-07 18:01:13 +0300
commitcf552f5886968fc022122960d3a9274ce9f27819 (patch)
tree07e6d40bdd128c9c12ccd9f21a382371a65eb7c4 /storage/innobase/fsp/fsp0file.cc
parentc2a63ac526bf4cd269def30a3d55ff29fdba8f86 (diff)
downloadmariadb-git-cf552f5886968fc022122960d3a9274ce9f27819.tar.gz
MDEV-25312 Replace fil_space_t::name with fil_space_t::name()bb-10.6-MDEV-25312
A consistency check for fil_space_t::name is causing recovery failures in MDEV-25180 (Atomic ALTER TABLE). So, we'd better remove that field altogether. fil_space_t::name was more or less a copy of dict_table_t::name (except for some special cases), and it was not being used for anything useful. There used to be a name_hash, but it had been removed already in commit a75dbfd7183cc96680f3e3e684fd36500dac8158 (MDEV-12266). We will also remove os_normalize_path(), OS_PATH_SEPARATOR, OS_PATH_SEPATOR_ALT. On Microsoft Windows, we will treat \ and / roughly in the same way. The intention is that for per-table tablespaces, the filenames will always follow the pattern prefix/databasename/tablename.ibd. (Any \ in the prefix must not be converted.) ut_basename_noext(): Remove (unused function). read_link_file(): Replaces RemoteDatafile::read_link_file(). We will ensure that the last two path component separators are forward slashes (converting up to 2 trailing backslashes on Microsoft Windows), so that everywhere else we can assume that data file names end in "/databasename/tablename.ibd". Note: On Microsoft Windows, path names that start with \\?\ must not contain / as path component separators. Previously, such paths did work in the DATA DIRECTORY argument of InnoDB tables. Reviewed by: Vladislav Vaintroub
Diffstat (limited to 'storage/innobase/fsp/fsp0file.cc')
-rw-r--r--storage/innobase/fsp/fsp0file.cc295
1 files changed, 100 insertions, 195 deletions
diff --git a/storage/innobase/fsp/fsp0file.cc b/storage/innobase/fsp/fsp0file.cc
index 57164113647..77faf58edcf 100644
--- a/storage/innobase/fsp/fsp0file.cc
+++ b/storage/innobase/fsp/fsp0file.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2013, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, 2020, MariaDB Corporation.
+Copyright (c) 2017, 2021, 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
@@ -30,29 +30,12 @@ Created 2013-7-26 by Kevin Lewis
#include "page0page.h"
#include "srv0start.h"
-/** Initialize the name, size and order of this datafile
-@param[in] name tablespace name, will be copied
-@param[in] flags tablespace flags */
-void
-Datafile::init(
- const char* name,
- ulint flags)
-{
- ut_ad(m_name == NULL);
- ut_ad(name != NULL);
-
- m_name = mem_strdup(name);
- m_flags = flags;
-}
-
/** Release the resources. */
void
Datafile::shutdown()
{
close();
- ut_free(m_name);
- m_name = NULL;
free_filepath();
free_first_page();
}
@@ -119,13 +102,12 @@ Datafile::open_read_only(bool strict)
/** Open a data file in read-write mode during start-up so that
doublewrite pages can be restored and then it can be validated.*
-@param[in] read_only_mode if true, then readonly mode checks are enforced.
@return DB_SUCCESS or error code */
-dberr_t
-Datafile::open_read_write(bool read_only_mode)
+inline dberr_t Datafile::open_read_write()
{
bool success = false;
ut_ad(m_handle == OS_FILE_CLOSED);
+ ut_ad(!srv_read_only_mode);
/* This function can be called for file objects that do not need
to be opened, which is the case when the m_filepath is NULL */
@@ -136,7 +118,7 @@ Datafile::open_read_write(bool read_only_mode)
set_open_flags(OS_FILE_OPEN);
m_handle = os_file_create_simple_no_error_handling(
innodb_data_file_key, m_filepath, m_open_flags,
- OS_FILE_READ_WRITE, read_only_mode, &success);
+ OS_FILE_READ_WRITE, false, &success);
if (!success) {
m_last_os_error = os_file_get_last_error(true);
@@ -182,24 +164,17 @@ Datafile::close()
Prepend the dirpath to filename using the extension given.
If dirpath is NULL, prepend the default datadir to filepath.
Store the result in m_filepath.
-@param[in] dirpath directory path
-@param[in] filename filename or filepath
-@param[in] ext filename extension */
-void
-Datafile::make_filepath(
- const char* dirpath,
- const char* filename,
- ib_extention ext)
+@param dirpath directory path
+@param name tablespace (table) name
+@param ext filename extension */
+void Datafile::make_filepath(const char *dirpath, fil_space_t::name_type name,
+ ib_extention ext)
{
- ut_ad(dirpath != NULL || filename != NULL);
-
- free_filepath();
-
- m_filepath = fil_make_filepath(dirpath, filename, ext, false);
-
- ut_ad(m_filepath != NULL);
-
- set_filename();
+ ut_ad(dirpath || name.size());
+ free_filepath();
+ m_filepath= fil_make_filepath(dirpath, name, ext, false);
+ ut_ad(m_filepath);
+ set_filename();
}
/** Set the filepath by duplicating the filepath sent in. This is the
@@ -258,23 +233,6 @@ Datafile::same_as(
#endif /* WIN32 */
}
-/** Allocate and set the datafile or tablespace name in m_name.
-If a name is provided, use it; else extract a file-per-table
-tablespace name from m_filepath. The value of m_name
-will be freed in the destructor.
-@param[in] name tablespace name if known, NULL if not */
-void
-Datafile::set_name(const char* name)
-{
- ut_free(m_name);
-
- if (name != NULL) {
- m_name = mem_strdup(name);
- } else {
- m_name = fil_path_to_space_name(m_filepath);
- }
-}
-
/** Reads a few significant fields from the first page of the first
datafile. The Datafile must already be open.
@param[in] read_only_mode If true, then readonly mode checks are enforced.
@@ -454,7 +412,7 @@ Datafile::validate_for_recovery()
page 0 from doublewrite and read the space ID from a survey
of the first few pages. */
close();
- err = open_read_write(srv_read_only_mode);
+ err = open_read_write();
if (err != DB_SUCCESS) {
return(err);
}
@@ -476,10 +434,6 @@ Datafile::validate_for_recovery()
err = validate_first_page(0);
}
- if (err == DB_SUCCESS) {
- set_name(NULL);
- }
-
return(err);
}
@@ -491,11 +445,8 @@ m_is_valid is set true on success, else false.
@retval DB_SUCCESS on if the datafile is valid
@retval DB_CORRUPTION if the datafile is not readable
@retval DB_TABLESPACE_EXISTS if there is a duplicate space_id */
-dberr_t
-Datafile::validate_first_page(lsn_t* flush_lsn)
+dberr_t Datafile::validate_first_page(lsn_t *flush_lsn)
{
- char* prev_name;
- char* prev_filepath;
const char* error_txt = NULL;
m_is_valid = true;
@@ -576,26 +527,30 @@ err_exit:
goto err_exit;
}
- if (fil_space_read_name_and_filepath(
- m_space_id, &prev_name, &prev_filepath)) {
+ mysql_mutex_lock(&fil_system.mutex);
- if (0 == strcmp(m_filepath, prev_filepath)) {
- ut_free(prev_name);
- ut_free(prev_filepath);
- return(DB_SUCCESS);
+ fil_space_t* space = fil_space_get_by_id(m_space_id);
+
+ if (space) {
+ fil_node_t* node = UT_LIST_GET_FIRST(space->chain);
+
+ if (node && !strcmp(m_filepath, node->name)) {
+ mysql_mutex_unlock(&fil_system.mutex);
+ return DB_SUCCESS;
}
/* Make sure the space_id has not already been opened. */
ib::error() << "Attempted to open a previously opened"
- " tablespace. Previous tablespace " << prev_name
- << " at filepath: " << prev_filepath
- << " uses space ID: " << m_space_id
- << ". Cannot open filepath: " << m_filepath
- << " which uses the same space ID.";
+ " tablespace. Previous tablespace: "
+ << (node ? node->name : "(unknown)")
+ << " uses space ID: " << m_space_id
+ << ". Cannot open filepath: " << m_filepath
+ << " which uses the same space ID.";
+ }
- ut_free(prev_name);
- ut_free(prev_filepath);
+ mysql_mutex_unlock(&fil_system.mutex);
+ if (space) {
m_is_valid = false;
free_first_page();
@@ -809,68 +764,61 @@ Datafile::restore_from_doublewrite()
!= DB_SUCCESS);
}
-/** Create a link filename based on the contents of m_name,
-open that file, and read the contents into m_filepath.
-@retval DB_SUCCESS if remote linked tablespace file is opened and read.
-@retval DB_CANNOT_OPEN_FILE if the link file does not exist. */
-dberr_t
-RemoteDatafile::open_link_file()
-{
- if (m_link_filepath == NULL) {
- m_link_filepath = fil_make_filepath(NULL, name(), ISL, false);
- }
-
- m_filepath = read_link_file(m_link_filepath);
-
- return(m_filepath == NULL ? DB_CANNOT_OPEN_FILE : DB_SUCCESS);
-}
-
-/** Opens a handle to the file linked to in an InnoDB Symbolic Link file
-in read-only mode so that it can be validated.
-@param[in] strict whether to issue error messages
-@return DB_SUCCESS if remote linked tablespace file is found and opened. */
-dberr_t
-RemoteDatafile::open_read_only(bool strict)
+/** Read an InnoDB Symbolic Link (ISL) file by name.
+@param link_filepath filepath of the ISL file
+@return data file name (must be freed by the caller)
+@retval nullptr on error */
+static char *read_link_file(const char *link_filepath)
{
- if (m_filepath == NULL && open_link_file() == DB_CANNOT_OPEN_FILE) {
- return(DB_ERROR);
- }
-
- dberr_t err = Datafile::open_read_only(strict);
-
- if (err != DB_SUCCESS && strict) {
- /* The following call prints an error message */
- os_file_get_last_error(true);
- ib::error() << "A link file was found named '"
- << m_link_filepath << "' but the linked tablespace '"
- << m_filepath << "' could not be opened read-only.";
- }
-
- return(err);
+ if (FILE* file= fopen(link_filepath, "r+b" STR_O_CLOEXEC))
+ {
+ char *filepath= static_cast<char*>(ut_malloc_nokey(OS_FILE_MAX_PATH));
+
+ os_file_read_string(file, filepath, OS_FILE_MAX_PATH);
+ fclose(file);
+
+ if (size_t len= strlen(filepath))
+ {
+ /* Trim whitespace from end of filepath */
+ len--;
+ while (filepath[len] >= 0 && filepath[len] <= 0x20)
+ filepath[len--]= 0;
+ if (!*filepath)
+ return nullptr;
+ /* Ensure that the last 2 path separators are forward slashes,
+ because elsewhere we are assuming that tablespace file names end
+ in "/databasename/tablename.ibd". */
+ unsigned trailing_slashes= 0;
+ for (; len; len--)
+ {
+ switch (filepath[len]) {
+#ifdef _WIN32
+ case '\\':
+ filepath[len]= '/';
+ /* fall through */
+#endif
+ case '/':
+ if (++trailing_slashes >= 2)
+ return filepath;
+ }
+ }
+ }
+ }
+
+ return nullptr;
}
-/** Opens a handle to the file linked to in an InnoDB Symbolic Link file
-in read-write mode so that it can be restored from doublewrite and validated.
-@param[in] read_only_mode If true, then readonly mode checks are enforced.
-@return DB_SUCCESS if remote linked tablespace file is found and opened. */
-dberr_t
-RemoteDatafile::open_read_write(bool read_only_mode)
+/** Create a link filename,
+open that file, and read the contents into m_filepath.
+@param name table name
+@return filepath()
+@retval nullptr if the .isl file does not exist or cannot be read */
+const char *RemoteDatafile::open_link_file(const table_name_t &name)
{
- if (m_filepath == NULL && open_link_file() == DB_CANNOT_OPEN_FILE) {
- return(DB_ERROR);
- }
-
- dberr_t err = Datafile::open_read_write(read_only_mode);
-
- if (err != DB_SUCCESS) {
- /* The following call prints an error message */
- m_last_os_error = os_file_get_last_error(true);
- ib::error() << "A link file was found named '"
- << m_link_filepath << "' but the linked data file '"
- << m_filepath << "' could not be opened for writing.";
- }
-
- return(err);
+ if (!m_link_filepath)
+ m_link_filepath= fil_make_filepath(nullptr, name, ISL, false);
+ m_filepath= read_link_file(m_link_filepath);
+ return m_filepath;
}
/** Release the resources. */
@@ -885,16 +833,12 @@ RemoteDatafile::shutdown()
}
}
-/** Creates a new InnoDB Symbolic Link (ISL) file. It is always created
-under the 'datadir' of MySQL. The datadir is the directory of a
-running mysqld program. We can refer to it by simply using the path ".".
-@param[in] name tablespace name
-@param[in] filepath remote filepath of tablespace datafile
+/** Create InnoDB Symbolic Link (ISL) file.
+@param name tablespace name
+@param filepath full file name
@return DB_SUCCESS or error code */
-dberr_t
-RemoteDatafile::create_link_file(
- const char* name,
- const char* filepath)
+dberr_t RemoteDatafile::create_link_file(fil_space_t::name_type name,
+ const char *filepath)
{
bool success;
dberr_t err = DB_SUCCESS;
@@ -902,7 +846,6 @@ RemoteDatafile::create_link_file(
char* prev_filepath = NULL;
ut_ad(!srv_read_only_mode);
- ut_ad(0 == strcmp(&filepath[strlen(filepath) - 4], DOT_IBD));
link_filepath = fil_make_filepath(NULL, name, ISL, false);
@@ -915,7 +858,8 @@ RemoteDatafile::create_link_file(
/* Truncate (starting with MySQL 5.6, probably no
longer since MariaDB Server 10.2.19) used to call this
with an existing link file which contains the same filepath. */
- bool same = !strcmp(prev_filepath, filepath);
+ bool same = !strncmp(prev_filepath, name.data(), name.size())
+ && !strcmp(prev_filepath + name.size(), DOT_IBD);
ut_free(prev_filepath);
if (same) {
ut_free(link_filepath);
@@ -963,9 +907,8 @@ RemoteDatafile::create_link_file(
return(err);
}
- ulint rbytes = fwrite(filepath, 1, strlen(filepath), file);
-
- if (rbytes != strlen(filepath)) {
+ const size_t len = strlen(filepath);
+ if (fwrite(filepath, 1, len, file) != len) {
error = os_file_get_last_error(true);
ib::error() <<
"Cannot write link file: "
@@ -994,50 +937,12 @@ RemoteDatafile::delete_link_file(void)
}
/** Delete an InnoDB Symbolic Link (ISL) file by name.
-@param[in] name tablespace name */
-void
-RemoteDatafile::delete_link_file(
- const char* name)
-{
- char* link_filepath = fil_make_filepath(NULL, name, ISL, false);
-
- if (link_filepath != NULL) {
- os_file_delete_if_exists(
- innodb_data_file_key, link_filepath, NULL);
-
- ut_free(link_filepath);
- }
-}
-
-/** Read an InnoDB Symbolic Link (ISL) file by name.
-It is always created under the datadir of MySQL.
-For file-per-table tablespaces, the isl file is expected to be
-in a 'database' directory and called 'tablename.isl'.
-The caller must free the memory returned if it is not null.
-@param[in] link_filepath filepath of the ISL file
-@return Filepath of the IBD file read from the ISL file */
-char*
-RemoteDatafile::read_link_file(
- const char* link_filepath)
+@param name tablespace name */
+void RemoteDatafile::delete_link_file(fil_space_t::name_type name)
{
- FILE* file = fopen(link_filepath, "r+b" STR_O_CLOEXEC);
- if (file == NULL) {
- return(NULL);
- }
-
- char* filepath = static_cast<char*>(ut_malloc_nokey(OS_FILE_MAX_PATH));
-
- os_file_read_string(file, filepath, OS_FILE_MAX_PATH);
- fclose(file);
-
- if (filepath[0] != '\0') {
- /* Trim whitespace from end of filepath */
- ulint last_ch = strlen(filepath) - 1;
- while (last_ch > 4 && filepath[last_ch] <= 0x20) {
- filepath[last_ch--] = 0x00;
- }
- os_normalize_path(filepath);
- }
-
- return(filepath);
+ if (char *link_filepath= fil_make_filepath(NULL, name, ISL, false))
+ {
+ os_file_delete_if_exists(innodb_data_file_key, link_filepath, nullptr);
+ ut_free(link_filepath);
+ }
}