MDEV-25312 Replace fil_space_t::name with fil_space_t::name()

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
This commit is contained in:
Marko Mäkelä 2021-04-07 18:01:13 +03:00
parent c2a63ac526
commit cf552f5886
37 changed files with 766 additions and 1138 deletions

View File

@ -273,7 +273,6 @@ datadir_iter_next_database(datadir_iter_t *it)
} }
snprintf(it->dbpath, it->dbpath_len, "%s/%s", snprintf(it->dbpath, it->dbpath_len, "%s/%s",
it->datadir_path, it->dbinfo.name); it->datadir_path, it->dbinfo.name);
os_normalize_path(it->dbpath);
if (it->dbinfo.type == OS_FILE_TYPE_FILE) { if (it->dbinfo.type == OS_FILE_TYPE_FILE) {
it->is_file = true; it->is_file = true;
@ -1133,13 +1132,12 @@ read_link_file(const char *ibd_filepath, const char *link_filepath)
os_file_read_string(file, filepath, OS_FILE_MAX_PATH); os_file_read_string(file, filepath, OS_FILE_MAX_PATH);
fclose(file); fclose(file);
if (strlen(filepath)) { if (size_t len = strlen(filepath)) {
/* Trim whitespace from end of filepath */ /* Trim whitespace from end of filepath */
ulint lastch = strlen(filepath) - 1; ulint lastch = len - 1;
while (lastch > 4 && filepath[lastch] <= 0x20) { while (lastch > 4 && filepath[lastch] <= 0x20) {
filepath[lastch--] = 0x00; filepath[lastch--] = 0x00;
} }
os_normalize_path(filepath);
} }
tablespace_locations[ibd_filepath] = filepath; tablespace_locations[ibd_filepath] = filepath;
@ -1852,9 +1850,8 @@ copy_back()
end(srv_sys_space.end()); end(srv_sys_space.end());
iter != end; iter != end;
++iter) { ++iter) {
const char *filename = base_name(iter->name()); const char *filepath = iter->filepath();
if (!(ret = copy_or_move_file(base_name(filepath), filepath,
if (!(ret = copy_or_move_file(filename, iter->name(),
dst_dir, 1))) { dst_dir, 1))) {
goto cleanup; goto cleanup;
} }
@ -1877,7 +1874,6 @@ copy_back()
const char *filename; const char *filename;
char c_tmp; char c_tmp;
int i_tmp; int i_tmp;
bool is_ibdata_file;
if (strstr(node.filepath,"/" ROCKSDB_BACKUP_DIR "/") if (strstr(node.filepath,"/" ROCKSDB_BACKUP_DIR "/")
#ifdef _WIN32 #ifdef _WIN32
@ -1932,23 +1928,19 @@ copy_back()
} }
/* skip innodb data files */ /* skip innodb data files */
is_ibdata_file = false;
for (Tablespace::const_iterator iter(srv_sys_space.begin()), for (Tablespace::const_iterator iter(srv_sys_space.begin()),
end(srv_sys_space.end()); iter != end; ++iter) { end(srv_sys_space.end()); iter != end; ++iter) {
const char *ibfile = base_name(iter->name()); if (!strcmp(base_name(iter->filepath()), filename)) {
if (strcmp(ibfile, filename) == 0) { goto next_file;
is_ibdata_file = true;
break;
} }
} }
if (is_ibdata_file) {
continue;
}
if (!(ret = copy_or_move_file(node.filepath, node.filepath_rel, if (!(ret = copy_or_move_file(node.filepath, node.filepath_rel,
mysql_data_home, 1))) { mysql_data_home, 1))) {
goto cleanup; goto cleanup;
} }
next_file:
continue;
} }
/* copy buffer pool dump */ /* copy buffer pool dump */
@ -2123,7 +2115,14 @@ static bool backup_files_from_datadir(const char *dir_path)
if (info.type != OS_FILE_TYPE_FILE) if (info.type != OS_FILE_TYPE_FILE)
continue; continue;
const char *pname = strrchr(info.name, OS_PATH_SEPARATOR); const char *pname = strrchr(info.name, '/');
#ifdef _WIN32
if (const char *last = strrchr(info.name, '\\')) {
if (!pname || last >pname) {
pname = last;
}
}
#endif
if (!pname) if (!pname)
pname = info.name; pname = info.name;
@ -2140,7 +2139,7 @@ static bool backup_files_from_datadir(const char *dir_path)
unlink(info.name); unlink(info.name);
std::string full_path(dir_path); std::string full_path(dir_path);
full_path.append(1, OS_PATH_SEPARATOR).append(info.name); full_path.append(1, '/').append(info.name);
if (!(ret = copy_file(ds_data, full_path.c_str() , info.name, 1))) if (!(ret = copy_file(ds_data, full_path.c_str() , info.name, 1)))
break; break;
} }

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "my_dbug.h" #include "my_dbug.h"
#ifndef DBUG_OFF #ifndef DBUG_OFF
extern char *dbug_mariabackup_get_val(const char *event, const char *key); char *dbug_mariabackup_get_val(const char *event, fil_space_t::name_type key);
/* /*
In debug mode, execute SQL statement that was passed via environment. In debug mode, execute SQL statement that was passed via environment.
To use this facility, you need to To use this facility, you need to
@ -14,19 +14,11 @@ To use this facility, you need to
for the variable) for the variable)
3. start mariabackup with --dbug=+d,debug_mariabackup_events 3. start mariabackup with --dbug=+d,debug_mariabackup_events
*/ */
extern void dbug_mariabackup_event( #define DBUG_EXECUTE_FOR_KEY(EVENT, KEY, CODE) \
const char *event,const char *key); DBUG_EXECUTE_IF("mariabackup_inject_code", \
#define DBUG_MARIABACKUP_EVENT(A, B) \ { char *dbug_val= dbug_mariabackup_get_val(EVENT, KEY); \
DBUG_EXECUTE_IF("mariabackup_events", \ if (dbug_val) CODE })
dbug_mariabackup_event(A,B););
#define DBUG_EXECUTE_FOR_KEY(EVENT, KEY, CODE) \
DBUG_EXECUTE_IF("mariabackup_inject_code", {\
char *dbug_val = dbug_mariabackup_get_val(EVENT, KEY); \
if (dbug_val && *dbug_val) CODE \
})
#else #else
#define DBUG_MARIABACKUP_EVENT(A,B)
#define DBUG_MARIABACKUP_EVENT_LOCK(A,B)
#define DBUG_EXECUTE_FOR_KEY(EVENT, KEY, CODE) #define DBUG_EXECUTE_FOR_KEY(EVENT, KEY, CODE)
#endif #endif

View File

@ -65,17 +65,21 @@ xb_get_relative_path(
prev = NULL; prev = NULL;
cur = path; cur = path;
while ((next = strchr(cur, OS_PATH_SEPARATOR)) != NULL) { #ifdef _WIN32
while ((next = strchr(cur, '\\')) != NULL) {
prev = cur;
cur = next + 1;
}
#endif
while ((next = strchr(cur, '/')) != NULL) {
prev = cur; prev = cur;
cur = next + 1; cur = next + 1;
} }
if (is_system) { if (is_system) {
return(cur); return(cur);
} else { } else {
return((prev == NULL) ? cur : prev); return((prev == NULL) ? cur : prev);
} }
@ -462,7 +466,8 @@ read_retry:
goto read_retry; goto read_retry;
} }
} }
DBUG_EXECUTE_FOR_KEY("add_corrupted_page_for", cursor->node->space->name, DBUG_EXECUTE_FOR_KEY("add_corrupted_page_for",
cursor->node->space->name(),
{ {
unsigned corrupted_page_no = unsigned corrupted_page_no =
static_cast<unsigned>(strtoul(dbug_val, NULL, 10)); static_cast<unsigned>(strtoul(dbug_val, NULL, 10));

View File

@ -362,7 +362,7 @@ struct ddl_tracker_t {
static ddl_tracker_t ddl_tracker; static ddl_tracker_t ddl_tracker;
// Convert non-null terminated filename to space name // Convert non-null terminated filename to space name
std::string filename_to_spacename(const byte *filename, size_t len); static std::string filename_to_spacename(const void *filename, size_t len);
CorruptedPages::CorruptedPages() { ut_a(!pthread_mutex_init(&m_mutex, NULL)); } CorruptedPages::CorruptedPages() { ut_a(!pthread_mutex_init(&m_mutex, NULL)); }
@ -374,11 +374,9 @@ void CorruptedPages::add_page_no_lock(const char *space_name, ulint space_id,
{ {
space_info_t &space_info = m_spaces[space_id]; space_info_t &space_info = m_spaces[space_id];
if (space_info.space_name.empty()) if (space_info.space_name.empty())
space_info.space_name= space_info.space_name= convert_space_name
convert_space_name ? filename_to_spacename(space_name, strlen(space_name))
? filename_to_spacename(reinterpret_cast<const byte *>(space_name), : space_name;
strlen(space_name))
: space_name;
(void)space_info.pages.insert(page_no); (void)space_info.pages.insert(page_no);
} }
@ -724,21 +722,25 @@ end:
void mdl_lock_all() void mdl_lock_all()
{ {
mdl_lock_init(); mdl_lock_init();
datafiles_iter_t it; datafiles_iter_t it;
while (fil_node_t *node = datafiles_iter_next(&it)) { while (fil_node_t *node= datafiles_iter_next(&it))
if (fil_is_user_tablespace_id(node->space->id) {
&& check_if_skip_table(node->space->name)) const auto id= node->space->id;
continue; if (const char *name= (fil_is_user_tablespace_id(id) &&
node->space->chain.start)
mdl_lock_table(node->space->id); ? node->space->chain.start->name : nullptr)
} if (check_if_skip_table(filename_to_spacename(name,
strlen(name)).c_str()))
continue;
mdl_lock_table(id);
}
} }
// Convert non-null terminated filename to space name // Convert non-null terminated filename to space name
std::string filename_to_spacename(const byte *filename, size_t len) static std::string filename_to_spacename(const void *filename, size_t len)
{ {
// null- terminate filename // null- terminate filename
char *f = (char *)malloc(len + 1); char *f = (char *)malloc(len + 1);
@ -2045,7 +2047,6 @@ static bool innodb_init_param()
innobase_data_file_path); innobase_data_file_path);
srv_sys_space.set_space_id(TRX_SYS_SPACE); srv_sys_space.set_space_id(TRX_SYS_SPACE);
srv_sys_space.set_name("innodb_system");
srv_sys_space.set_path(srv_data_home); srv_sys_space.set_path(srv_data_home);
switch (srv_checksum_algorithm) { switch (srv_checksum_algorithm) {
case SRV_CHECKSUM_ALGORITHM_FULL_CRC32: case SRV_CHECKSUM_ALGORITHM_FULL_CRC32:
@ -2077,8 +2078,6 @@ static bool innodb_init_param()
msg("innodb_log_group_home_dir = %s", msg("innodb_log_group_home_dir = %s",
srv_log_group_home_dir); srv_log_group_home_dir);
os_normalize_path(srv_log_group_home_dir);
if (strchr(srv_log_group_home_dir, ';')) { if (strchr(srv_log_group_home_dir, ';')) {
msg("syntax error in innodb_log_group_home_dir, "); msg("syntax error in innodb_log_group_home_dir, ");
goto error; goto error;
@ -2531,7 +2530,15 @@ check_if_skip_database_by_path(
return(FALSE); return(FALSE);
} }
const char* db_name = strrchr(path, OS_PATH_SEPARATOR); const char* db_name = strrchr(path, '/');
#ifdef _WIN32
if (const char* last = strrchr(path, '\\')) {
if (!db_name || last > db_name) {
db_name = last;
}
}
#endif
if (db_name == NULL) { if (db_name == NULL) {
db_name = path; db_name = path;
} else { } else {
@ -2690,21 +2697,11 @@ static my_bool xtrabackup_copy_datafile(fil_node_t *node, uint thread_n,
xb_read_filt_t *read_filter; xb_read_filt_t *read_filter;
my_bool rc = FALSE; my_bool rc = FALSE;
/* Get the name and the path for the tablespace. node->name always
contains the path (which may be absolute for remote tablespaces in
5.6+). space->name contains the tablespace name in the form
"./database/table.ibd" (in 5.5-) or "database/table" (in 5.6+). For a
multi-node shared tablespace, space->name contains the name of the first
node, but that's irrelevant, since we only need node_name to match them
against filters, and the shared tablespace is always copied regardless
of the filters value. */
const char* const node_name = node->space->name;
const char* const node_path = node->name;
if (fil_is_user_tablespace_id(node->space->id) if (fil_is_user_tablespace_id(node->space->id)
&& check_if_skip_table(node_name)) { && check_if_skip_table(filename_to_spacename(node->name,
msg(thread_n, "Skipping %s.", node_name); strlen(node->name)).
c_str())) {
msg(thread_n, "Skipping %s.", node->name);
return(FALSE); return(FALSE);
} }
@ -2759,9 +2756,10 @@ static my_bool xtrabackup_copy_datafile(fil_node_t *node, uint thread_n,
action = xb_get_copy_action(); action = xb_get_copy_action();
if (xtrabackup_stream) { if (xtrabackup_stream) {
msg(thread_n, "%s %s", action, node_path); msg(thread_n, "%s %s", action, node->name);
} else { } else {
msg(thread_n, "%s %s to %s", action, node_path, dstfile->path); msg(thread_n, "%s %s to %s", action, node->name,
dstfile->path);
} }
/* The main copy loop */ /* The main copy loop */
@ -2779,11 +2777,15 @@ static my_bool xtrabackup_copy_datafile(fil_node_t *node, uint thread_n,
if (write_filter.finalize if (write_filter.finalize
&& !write_filter.finalize(&write_filt_ctxt, dstfile)) { && !write_filter.finalize(&write_filt_ctxt, dstfile)) {
goto error; goto error;
} } else {
const fil_space_t::name_type name = node->space->name();
pthread_mutex_lock(&backup_mutex); pthread_mutex_lock(&backup_mutex);
ddl_tracker.tables_in_backup[node->space->id] = node_name; ddl_tracker.tables_in_backup.emplace(node->space->id,
pthread_mutex_unlock(&backup_mutex); std::string(name.data(),
name.size()));
pthread_mutex_unlock(&backup_mutex);
}
/* close */ /* close */
msg(thread_n," ...done"); msg(thread_n," ...done");
@ -2815,7 +2817,7 @@ skip:
if (write_filter.deinit) { if (write_filter.deinit) {
write_filter.deinit(&write_filt_ctxt); write_filter.deinit(&write_filt_ctxt);
} }
msg(thread_n,"Warning: We assume the table was dropped during xtrabackup execution and ignore the tablespace %s", node_name); msg(thread_n,"Warning: We assume the table was dropped during xtrabackup execution and ignore the tablespace %s", node->name);
return(FALSE); return(FALSE);
} }
@ -3032,19 +3034,23 @@ static void *io_watching_thread(void*)
} }
#ifndef DBUG_OFF #ifndef DBUG_OFF
char *dbug_mariabackup_get_val(const char *event, const char *key) char *dbug_mariabackup_get_val(const char *event,
const fil_space_t::name_type key)
{ {
char envvar[FN_REFLEN]; char envvar[FN_REFLEN];
if (key) { strncpy(envvar, event, sizeof envvar - 1);
snprintf(envvar, sizeof(envvar), "%s_%s", event, key); envvar[(sizeof envvar) - 1] = '\0';
char *slash = strchr(envvar, '/');
if (slash) if (key.size() && key.size() + strlen(envvar) < (sizeof envvar) - 2)
*slash = '_'; {
} else { strcat(envvar, "_");
strncpy(envvar, event, sizeof envvar - 1); strncat(envvar, key.data(), key.size());
envvar[sizeof envvar - 1] = '\0'; if (char *slash= strchr(envvar, '/'))
} *slash= '_';
return getenv(envvar); }
char *val = getenv(envvar);
return val && *val ? val : nullptr;
} }
/* /*
@ -3059,7 +3065,8 @@ To use this facility, you need to
for the variable) for the variable)
3. start mariabackup with --dbug=+d,debug_mariabackup_events 3. start mariabackup with --dbug=+d,debug_mariabackup_events
*/ */
void dbug_mariabackup_event(const char *event,const char *key) static void dbug_mariabackup_event(const char *event,
const fil_space_t::name_type key)
{ {
char *sql = dbug_mariabackup_get_val(event, key); char *sql = dbug_mariabackup_get_val(event, key);
if (sql && *sql) { if (sql && *sql) {
@ -3067,6 +3074,10 @@ void dbug_mariabackup_event(const char *event,const char *key)
xb_mysql_query(mysql_connection, sql, false, true); xb_mysql_query(mysql_connection, sql, false, true);
} }
} }
# define DBUG_MARIABACKUP_EVENT(A, B) \
DBUG_EXECUTE_IF("mariabackup_events", dbug_mariabackup_event(A,B);)
#else
# define DBUG_MARIABACKUP_EVENT(A, B) /* empty */
#endif // DBUG_OFF #endif // DBUG_OFF
/** Datafiles copying thread.*/ /** Datafiles copying thread.*/
@ -3085,8 +3096,9 @@ static void data_copy_thread_func(data_thread_ctxt_t *ctxt) /* thread context */
debug_sync_point("data_copy_thread_func"); debug_sync_point("data_copy_thread_func");
while ((node = datafiles_iter_next(ctxt->it)) != NULL) { while ((node = datafiles_iter_next(ctxt->it)) != NULL) {
DBUG_MARIABACKUP_EVENT("before_copy", node->space->name); DBUG_MARIABACKUP_EVENT("before_copy", node->space->name());
DBUG_EXECUTE_FOR_KEY("wait_innodb_redo_before_copy", node->space->name, DBUG_EXECUTE_FOR_KEY("wait_innodb_redo_before_copy",
node->space->name(),
backup_wait_for_lsn(get_current_lsn(mysql_connection));); backup_wait_for_lsn(get_current_lsn(mysql_connection)););
/* copy the datafile */ /* copy the datafile */
if (xtrabackup_copy_datafile(node, num, NULL, if (xtrabackup_copy_datafile(node, num, NULL,
@ -3094,8 +3106,7 @@ static void data_copy_thread_func(data_thread_ctxt_t *ctxt) /* thread context */
*ctxt->corrupted_pages)) *ctxt->corrupted_pages))
die("failed to copy datafile."); die("failed to copy datafile.");
DBUG_MARIABACKUP_EVENT("after_copy", node->space->name); DBUG_MARIABACKUP_EVENT("after_copy", node->space->name());
} }
pthread_mutex_lock(ctxt->count_mutex); pthread_mutex_lock(ctxt->count_mutex);
@ -3209,23 +3220,6 @@ xb_fil_io_init()
fil_system.space_id_reuse_warned = true; fil_system.space_id_reuse_warned = true;
} }
static
Datafile*
xb_new_datafile(const char *name, bool is_remote)
{
if (is_remote) {
RemoteDatafile *remote_file = new RemoteDatafile();
remote_file->set_name(name);
return(remote_file);
} else {
Datafile *file = new Datafile();
file->set_name(name);
file->make_filepath(".", name, IBD);
return(file);
}
}
/** Load tablespace. /** Load tablespace.
@param[in] dirname directory name of the tablespace to open @param[in] dirname directory name of the tablespace to open
@ -3273,7 +3267,20 @@ static void xb_load_single_table_tablespace(const char *dirname,
name[pathlen - 5] = 0; name[pathlen - 5] = 0;
} }
Datafile *file = xb_new_datafile(name, is_remote); Datafile *file;
if (is_remote) {
RemoteDatafile* rf = new RemoteDatafile();
if (!rf->open_link_file(name)) {
die("Can't open datafile %s", name);
}
file = rf;
} else {
file = new Datafile();
file->make_filepath(".",
fil_space_t::name_type{name, strlen(name)},
IBD);
}
if (file->open_read_only(true) != DB_SUCCESS) { if (file->open_read_only(true) != DB_SUCCESS) {
die("Can't open datafile %s", name); die("Can't open datafile %s", name);
@ -3292,7 +3299,7 @@ static void xb_load_single_table_tablespace(const char *dirname,
if (err == DB_SUCCESS && file->space_id() != SRV_TMP_SPACE_ID) { if (err == DB_SUCCESS && file->space_id() != SRV_TMP_SPACE_ID) {
space = fil_space_t::create( space = fil_space_t::create(
name, file->space_id(), file->flags(), file->space_id(), file->flags(),
FIL_TYPE_TABLESPACE, NULL/* TODO: crypt_data */); FIL_TYPE_TABLESPACE, NULL/* TODO: crypt_data */);
ut_a(space != NULL); ut_a(space != NULL);
@ -3407,7 +3414,6 @@ static dberr_t enumerate_ibd_files(process_single_tablespace_func_t callback)
} }
snprintf(dbpath, dbpath_len, snprintf(dbpath, dbpath_len,
"%s/%s", fil_path_to_mysql_datadir, dbinfo.name); "%s/%s", fil_path_to_mysql_datadir, dbinfo.name);
os_normalize_path(dbpath);
if (check_if_skip_database_by_path(dbpath)) { if (check_if_skip_database_by_path(dbpath)) {
fprintf(stderr, "Skipping db: %s\n", dbpath); fprintf(stderr, "Skipping db: %s\n", dbpath);
@ -3622,7 +3628,7 @@ xb_load_tablespaces()
} }
debug_sync_point("xtrabackup_load_tablespaces_pause"); debug_sync_point("xtrabackup_load_tablespaces_pause");
DBUG_MARIABACKUP_EVENT("after_load_tablespaces", 0); DBUG_MARIABACKUP_EVENT("after_load_tablespaces", {});
return(DB_SUCCESS); return(DB_SUCCESS);
} }
@ -4386,7 +4392,7 @@ fail_before_log_copying_thread_start:
if (log_copy_failed) if (log_copy_failed)
goto fail_before_log_copying_thread_start; goto fail_before_log_copying_thread_start;
DBUG_MARIABACKUP_EVENT("before_innodb_log_copy_thread_started",0); DBUG_MARIABACKUP_EVENT("before_innodb_log_copy_thread_started", {});
mysql_cond_init(0, &log_copying_stop, nullptr); mysql_cond_init(0, &log_copying_stop, nullptr);
std::thread(log_copying_thread).detach(); std::thread(log_copying_thread).detach();
@ -4528,7 +4534,7 @@ void backup_fix_ddl(CorruptedPages &corrupted_pages)
log_file_op = backup_file_op_fail; log_file_op = backup_file_op_fail;
pthread_mutex_unlock(&backup_mutex); pthread_mutex_unlock(&backup_mutex);
DBUG_MARIABACKUP_EVENT("backup_fix_ddl",0); DBUG_MARIABACKUP_EVENT("backup_fix_ddl", {});
for (space_id_to_name_t::iterator iter = ddl_tracker.tables_in_backup.begin(); for (space_id_to_name_t::iterator iter = ddl_tracker.tables_in_backup.begin();
iter != ddl_tracker.tables_in_backup.end(); iter != ddl_tracker.tables_in_backup.end();
@ -4624,10 +4630,10 @@ void backup_fix_ddl(CorruptedPages &corrupted_pages)
datafiles_iter_t it2; datafiles_iter_t it2;
while (fil_node_t *node = datafiles_iter_next(&it2)) { while (fil_node_t *node = datafiles_iter_next(&it2)) {
fil_space_t * space = node->space; if (!fil_is_user_tablespace_id(node->space->id))
if (!fil_is_user_tablespace_id(space->id))
continue; continue;
std::string dest_name(node->space->name); std::string dest_name= filename_to_spacename(
node->name, strlen(node->name));
dest_name.append(".new"); dest_name.append(".new");
xtrabackup_copy_datafile(node, 0, dest_name.c_str(), wf_write_through, xtrabackup_copy_datafile(node, 0, dest_name.c_str(), wf_write_through,
corrupted_pages); corrupted_pages);
@ -4746,10 +4752,15 @@ xb_space_create_file(
static fil_space_t* fil_space_get_by_name(const char* name) static fil_space_t* fil_space_get_by_name(const char* name)
{ {
mysql_mutex_assert_owner(&fil_system.mutex); mysql_mutex_assert_owner(&fil_system.mutex);
for (fil_space_t& space :fil_system.space_list) for (fil_space_t &space : fil_system.space_list)
if (!strcmp(space.name, name)) return &space; if (space.chain.start)
return NULL; if (const char *str= strstr(space.chain.start->name, name))
if (!strcmp(str + strlen(name), ".ibd") &&
(str == space.chain.start->name ||
IF_WIN(str[-1] == '\\' ||,) str[-1] == '/'))
return &space;
return nullptr;
} }
/*********************************************************************** /***********************************************************************
@ -4784,20 +4795,15 @@ xb_delta_open_matching_space(
if (dbname) { if (dbname) {
snprintf(dest_dir, FN_REFLEN, "%s/%s", snprintf(dest_dir, FN_REFLEN, "%s/%s",
xtrabackup_target_dir, dbname); xtrabackup_target_dir, dbname);
os_normalize_path(dest_dir);
snprintf(dest_space_name, FN_REFLEN, "%s/%s", dbname, name); snprintf(dest_space_name, FN_REFLEN, "%s/%s", dbname, name);
} else { } else {
snprintf(dest_dir, FN_REFLEN, "%s", xtrabackup_target_dir); snprintf(dest_dir, FN_REFLEN, "%s", xtrabackup_target_dir);
os_normalize_path(dest_dir);
snprintf(dest_space_name, FN_REFLEN, "%s", name); snprintf(dest_space_name, FN_REFLEN, "%s", name);
} }
snprintf(real_name, real_name_len, snprintf(real_name, real_name_len,
"%s/%s", "%s/%s",
xtrabackup_target_dir, dest_space_name); xtrabackup_target_dir, dest_space_name);
os_normalize_path(real_name);
/* Truncate ".ibd" */ /* Truncate ".ibd" */
dest_space_name[strlen(dest_space_name) - 4] = '\0'; dest_space_name[strlen(dest_space_name) - 4] = '\0';
@ -4867,12 +4873,12 @@ exit:
dbname, fil_space->id); dbname, fil_space->id);
msg("mariabackup: Renaming %s to %s.ibd", msg("mariabackup: Renaming %s to %s.ibd",
fil_space->name, tmpname); fil_space->chain.start->name, tmpname);
if (fil_space->rename(tmpname, NULL, false) if (fil_space->rename(tmpname, NULL, false)
!= DB_SUCCESS) { != DB_SUCCESS) {
msg("mariabackup: Cannot rename %s to %s", msg("mariabackup: Cannot rename %s to %s",
fil_space->name, tmpname); fil_space->chain.start->name, tmpname);
goto exit; goto exit;
} }
} }
@ -4889,15 +4895,14 @@ exit:
if (fil_space != NULL) { if (fil_space != NULL) {
char tmpname[FN_REFLEN]; char tmpname[FN_REFLEN];
strncpy(tmpname, dest_space_name, FN_REFLEN); snprintf(tmpname, sizeof tmpname, "%s.ibd", dest_space_name);
msg("mariabackup: Renaming %s to %s", msg("mariabackup: Renaming %s to %s",
fil_space->name, dest_space_name); fil_space->chain.start->name, tmpname);
if (fil_space->rename(tmpname, NULL, false) != DB_SUCCESS) if (fil_space->rename(tmpname, false) != DB_SUCCESS) {
{
msg("mariabackup: Cannot rename %s to %s", msg("mariabackup: Cannot rename %s to %s",
fil_space->name, dest_space_name); fil_space->chain.start->name, tmpname);
goto exit; goto exit;
} }
@ -4920,7 +4925,7 @@ exit:
ut_ad(fil_space_t::zip_size(flags) == info.zip_size); ut_ad(fil_space_t::zip_size(flags) == info.zip_size);
ut_ad(fil_space_t::physical_size(flags) == info.page_size); ut_ad(fil_space_t::physical_size(flags) == info.page_size);
if (fil_space_t::create(dest_space_name, info.space_id, flags, if (fil_space_t::create(info.space_id, flags,
FIL_TYPE_TABLESPACE, 0)) { FIL_TYPE_TABLESPACE, 0)) {
*success = xb_space_create_file(real_name, info.space_id, *success = xb_space_create_file(real_name, info.space_id,
flags, &file); flags, &file);
@ -4985,10 +4990,6 @@ xtrabackup_apply_delta(
goto error; goto error;
} }
os_normalize_path(dst_path);
os_normalize_path(src_path);
os_normalize_path(meta_path);
if (!xb_read_delta_metadata(meta_path, &info)) { if (!xb_read_delta_metadata(meta_path, &info)) {
goto error; goto error;
} }
@ -5380,8 +5381,6 @@ next_file_item_1:
OS_FILE_MAX_PATH/2-1, OS_FILE_MAX_PATH/2-1,
dbinfo.name); dbinfo.name);
os_normalize_path(dbpath);
dbdir = os_file_opendir(dbpath, FALSE); dbdir = os_file_opendir(dbpath, FALSE);
if (dbdir != NULL) { if (dbdir != NULL) {
@ -5502,8 +5501,7 @@ static void rename_table_in_prepare(const std::string &datadir, const std::strin
if (file_exists(dest)) { if (file_exists(dest)) {
ren2= std::string(datadir) + "/" + to + ".ren"; ren2= std::string(datadir) + "/" + to + ".ren";
if (!file_exists(ren2)) { if (!file_exists(ren2)) {
msg("ERROR : File %s was not found, but expected during rename processing\n", ren2.c_str()); die("ERROR : File %s was not found, but expected during rename processing\n", ren2.c_str());
ut_a(0);
} }
tmp = to + "#"; tmp = to + "#";
rename_table_in_prepare(datadir, to, tmp); rename_table_in_prepare(datadir, to, tmp);

View File

@ -31,7 +31,7 @@ SELECT * FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb' WHERE engine = 'innodb'
AND support IN ('YES', 'DEFAULT', 'ENABLED'); AND support IN ('YES', 'DEFAULT', 'ENABLED');
ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS
FOUND 1 /The innodb_system data file 'ibdata1' was not found but one of the other data files 'ibdata2' exists/ in mysqld.1.err FOUND 1 /The data file '.*ibdata1' was not found but one of the other data files '.*ibdata2' exists/ in mysqld.1.err
bak_ib_logfile0 bak_ib_logfile0
bak_ibdata1 bak_ibdata1
bak_ibdata2 bak_ibdata2

View File

@ -14,7 +14,7 @@ call mtr.add_suppression("InnoDB: The error means the system cannot find the pat
call mtr.add_suppression("InnoDB: If you are installing InnoDB, remember that you must create directories yourself"); call mtr.add_suppression("InnoDB: If you are installing InnoDB, remember that you must create directories yourself");
call mtr.add_suppression("InnoDB: File .path.to.non-existent.ib_logfile101: 'create' returned OS error \d+"); call mtr.add_suppression("InnoDB: File .path.to.non-existent.ib_logfile101: 'create' returned OS error \d+");
call mtr.add_suppression("InnoDB: Cannot create .path.to.non-existent.ib_logfile101"); call mtr.add_suppression("InnoDB: Cannot create .path.to.non-existent.ib_logfile101");
call mtr.add_suppression("InnoDB: The innodb_system data file 'ibdata1' was not found but one of the other data files 'ibdata2' exists"); call mtr.add_suppression("InnoDB: The data file '.*ibdata1' was not found but one of the other data files '.*ibdata2' exists");
call mtr.add_suppression("InnoDB: Tablespace size stored in header is \d+ pages, but the sum of data file sizes is \d+ pages"); call mtr.add_suppression("InnoDB: Tablespace size stored in header is \d+ pages, but the sum of data file sizes is \d+ pages");
call mtr.add_suppression("InnoDB: Cannot start InnoDB. The tail of the system tablespace is missing"); call mtr.add_suppression("InnoDB: Cannot start InnoDB. The tail of the system tablespace is missing");
call mtr.add_suppression("InnoDB: undo tablespace '.*undo001' exists\. Creating system tablespace with existing undo tablespaces is not supported\. Please delete all undo tablespaces before creating new system tablespace\."); call mtr.add_suppression("InnoDB: undo tablespace '.*undo001' exists\. Creating system tablespace with existing undo tablespaces is not supported\. Please delete all undo tablespaces before creating new system tablespace\.");
@ -90,7 +90,7 @@ eval $check_yes_innodb;
--source include/start_mysqld.inc --source include/start_mysqld.inc
eval $check_no_innodb; eval $check_no_innodb;
--source include/shutdown_mysqld.inc --source include/shutdown_mysqld.inc
let SEARCH_PATTERN=The innodb_system data file 'ibdata1' was not found but one of the other data files 'ibdata2' exists; let SEARCH_PATTERN=The data file '.*ibdata1' was not found but one of the other data files '.*ibdata2' exists;
--source include/search_pattern_in_file.inc --source include/search_pattern_in_file.inc
# clean up & Restore # clean up & Restore

View File

@ -48,6 +48,15 @@ close OUT or die;
die unless open OUT, ">", "$ENV{MYSQL_TMP_DIR}/test/td.ibd"; die unless open OUT, ">", "$ENV{MYSQL_TMP_DIR}/test/td.ibd";
print OUT "xyz " x $ENV{page_size}; print OUT "xyz " x $ENV{page_size};
close OUT or die; close OUT or die;
die unless open ISL, "+<", "$ENV{datadir}/test/td.isl";
$_=<ISL>;
if (m|^[a-zA-Z]:|)
{
tr|/|\\|;
seek(ISL, 0, SEEK_SET) or die;
print ISL or die;
}
close ISL or die;
EOF EOF
--let $restart_parameters= --skip-innodb-buffer-pool-load-at-startup --let $restart_parameters= --skip-innodb-buffer-pool-load-at-startup

View File

@ -374,7 +374,7 @@ void buf_dblwr_t::recover()
if (!srv_is_undo_tablespace(space_id)) if (!srv_is_undo_tablespace(space_id))
ib::warn() << "A copy of page " << page_no ib::warn() << "A copy of page " << page_no
<< " in the doublewrite buffer slot " << page_no_dblwr << " in the doublewrite buffer slot " << page_no_dblwr
<< " is beyond the end of tablespace " << space->name << " is beyond the end of " << space->chain.start->name
<< " (" << space->size << " pages)"; << " (" << space->size << " pages)";
next_page: next_page:
space->release(); space->release();
@ -395,7 +395,7 @@ next_page:
if (UNIV_UNLIKELY(fio.err != DB_SUCCESS)) if (UNIV_UNLIKELY(fio.err != DB_SUCCESS))
ib::warn() << "Double write buffer recovery: " << page_id ib::warn() << "Double write buffer recovery: " << page_id
<< " (tablespace '" << space->name << " ('" << space->chain.start->name
<< "') read failed with error: " << fio.err; << "') read failed with error: " << fio.err;
if (buf_is_zeroes(span<const byte>(read_buf, physical_size))) if (buf_is_zeroes(span<const byte>(read_buf, physical_size)))

View File

@ -181,8 +181,8 @@ static void buf_dump_generate_path(char *path, size_t path_size)
char buf[FN_REFLEN]; char buf[FN_REFLEN];
mysql_mutex_lock(&LOCK_global_system_variables); mysql_mutex_lock(&LOCK_global_system_variables);
snprintf(buf, sizeof(buf), "%s%c%s", get_buf_dump_dir(), snprintf(buf, sizeof buf, "%s/%s", get_buf_dump_dir(),
OS_PATH_SEPARATOR, srv_buf_dump_filename); srv_buf_dump_filename);
mysql_mutex_unlock(&LOCK_global_system_variables); mysql_mutex_unlock(&LOCK_global_system_variables);
os_file_type_t type; os_file_type_t type;
@ -205,19 +205,21 @@ static void buf_dump_generate_path(char *path, size_t path_size)
char srv_data_home_full[FN_REFLEN]; char srv_data_home_full[FN_REFLEN];
my_realpath(srv_data_home_full, get_buf_dump_dir(), 0); my_realpath(srv_data_home_full, get_buf_dump_dir(), 0);
const char *format;
if (srv_data_home_full[strlen(srv_data_home_full) - 1] switch (srv_data_home_full[strlen(srv_data_home_full) - 1]) {
== OS_PATH_SEPARATOR) { #ifdef _WIN32
case '\\':
snprintf(path, path_size, "%s%s", #endif
srv_data_home_full, case '/':
srv_buf_dump_filename); format = "%s%s";
} else { break;
snprintf(path, path_size, "%s%c%s", default:
srv_data_home_full, format = "%s/%s";
OS_PATH_SEPARATOR,
srv_buf_dump_filename);
} }
snprintf(path, path_size, format,
srv_data_home_full, srv_buf_dump_filename);
} }
} }

View File

@ -407,11 +407,11 @@ dict_build_table_def_step(
bool has_data_dir = DICT_TF_HAS_DATA_DIR(table->flags); bool has_data_dir = DICT_TF_HAS_DATA_DIR(table->flags);
ulint fsp_flags = dict_tf_to_fsp_flags(table->flags); ulint fsp_flags = dict_tf_to_fsp_flags(table->flags);
ut_ad(!has_data_dir || table->data_dir_path); ut_ad(!has_data_dir || table->data_dir_path);
char* filepath = has_data_dir char* filepath = fil_make_filepath(has_data_dir
? fil_make_filepath(table->data_dir_path, ? table->data_dir_path
table->name.m_name, IBD, true) : nullptr,
: fil_make_filepath(NULL, table->name, IBD,
table->name.m_name, IBD, false); has_data_dir);
/* We create a new single-table tablespace for the table. /* We create a new single-table tablespace for the table.
We initially let it be 4 pages: We initially let it be 4 pages:
@ -423,7 +423,7 @@ dict_build_table_def_step(
dberr_t err; dberr_t err;
table->space = fil_ibd_create( table->space = fil_ibd_create(
space_id, table->name.m_name, filepath, fsp_flags, space_id, table->name, filepath, fsp_flags,
FIL_IBD_FILE_INITIAL_SIZE, FIL_IBD_FILE_INITIAL_SIZE,
node->mode, node->key_id, &err); node->mode, node->key_id, &err);

View File

@ -1603,16 +1603,12 @@ dict_table_rename_in_cache(
/* Make sure the data_dir_path is set. */ /* Make sure the data_dir_path is set. */
dict_get_and_save_data_dir_path(table, true); dict_get_and_save_data_dir_path(table, true);
if (DICT_TF_HAS_DATA_DIR(table->flags)) { const char* data_dir = DICT_TF_HAS_DATA_DIR(table->flags)
ut_a(table->data_dir_path); ? table->data_dir_path : nullptr;
ut_ad(data_dir || !DICT_TF_HAS_DATA_DIR(table->flags));
filepath = fil_make_filepath( filepath = fil_make_filepath(data_dir, table->name, IBD,
table->data_dir_path, table->name.m_name, data_dir != nullptr);
IBD, true);
} else {
filepath = fil_make_filepath(
NULL, table->name.m_name, IBD, false);
}
if (filepath == NULL) { if (filepath == NULL) {
return(DB_OUT_OF_MEMORY); return(DB_OUT_OF_MEMORY);
@ -1637,11 +1633,14 @@ dict_table_rename_in_cache(
ut_ad(!table->is_temporary()); ut_ad(!table->is_temporary());
const fil_space_t::name_type new_space_name{
new_name, strlen(new_name)};
if (DICT_TF_HAS_DATA_DIR(table->flags)) { if (DICT_TF_HAS_DATA_DIR(table->flags)) {
new_path = os_file_make_new_pathname( new_path = os_file_make_new_pathname(
old_path, new_name); old_path, new_name);
err = RemoteDatafile::create_link_file( err = RemoteDatafile::create_link_file(
new_name, new_path); new_space_name, new_path);
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
ut_free(new_path); ut_free(new_path);
@ -1649,24 +1648,30 @@ dict_table_rename_in_cache(
} }
} else { } else {
new_path = fil_make_filepath( new_path = fil_make_filepath(
NULL, new_name, IBD, false); NULL, new_space_name, IBD, false);
} }
/* New filepath must not exist. */ /* New filepath must not exist. */
err = table->space->rename(new_name, new_path, true, err = table->space->rename(new_path, true, replace_new_file);
replace_new_file);
ut_free(new_path); ut_free(new_path);
/* If the tablespace is remote, a new .isl file was created /* If the tablespace is remote, a new .isl file was created
If success, delete the old one. If not, delete the new one. */ If success, delete the old one. If not, delete the new one. */
if (DICT_TF_HAS_DATA_DIR(table->flags)) {
RemoteDatafile::delete_link_file(
err == DB_SUCCESS ? old_name : new_name);
}
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
if (DICT_TF_HAS_DATA_DIR(table->flags)) {
RemoteDatafile::delete_link_file(
new_space_name);
}
return err; return err;
} }
if (DICT_TF_HAS_DATA_DIR(table->flags)) {
RemoteDatafile::delete_link_file(
{old_name, strlen(old_name)});
}
} }
/* Remove table from the hash tables of tables */ /* Remove table from the hash tables of tables */

View File

@ -1050,15 +1050,12 @@ next:
newly created or rebuilt tables or partitions, but newly created or rebuilt tables or partitions, but
will otherwise ignore the flag. */ will otherwise ignore the flag. */
/* Now that we have the proper name for this tablespace, if (fil_space_for_table_exists_in_mem(space_id, flags)) {
look to see if it is already in the tablespace cache. */
if (fil_space_for_table_exists_in_mem(
space_id, table_name.m_name, flags)) {
goto next; goto next;
} }
char* filepath = fil_make_filepath( char* filepath = fil_make_filepath(nullptr, table_name,
NULL, table_name.m_name, IBD, false); IBD, false);
/* Check that the .ibd file exists. */ /* Check that the .ibd file exists. */
if (!fil_ibd_open( if (!fil_ibd_open(
@ -2278,9 +2275,8 @@ dict_save_data_dir_path(
ut_a(filepath); ut_a(filepath);
/* Be sure this filepath is not the default filepath. */ /* Be sure this filepath is not the default filepath. */
char* default_filepath = fil_make_filepath( if (char* default_filepath = fil_make_filepath(nullptr, table->name,
NULL, table->name.m_name, IBD, false); IBD, false)) {
if (default_filepath) {
if (0 != strcmp(filepath, default_filepath)) { if (0 != strcmp(filepath, default_filepath)) {
ulint pathlen = strlen(filepath); ulint pathlen = strlen(filepath);
ut_a(pathlen < OS_FILE_MAX_PATH); ut_a(pathlen < OS_FILE_MAX_PATH);
@ -2397,8 +2393,8 @@ dict_load_tablespace(
} }
/* The tablespace may already be open. */ /* The tablespace may already be open. */
table->space = fil_space_for_table_exists_in_mem( table->space = fil_space_for_table_exists_in_mem(table->space_id,
table->space_id, table->name.m_name, table->flags); table->flags);
if (table->space) { if (table->space) {
return; return;
} }
@ -2425,8 +2421,7 @@ dict_load_tablespace(
if (table->data_dir_path) { if (table->data_dir_path) {
filepath = fil_make_filepath( filepath = fil_make_filepath(
table->data_dir_path, table->data_dir_path, table->name, IBD, true);
table->name.m_name, IBD, true);
} }
} }

View File

@ -2362,7 +2362,7 @@ fil_space_crypt_close_tablespace(
ib::warn() << "Waited " ib::warn() << "Waited "
<< now - start << now - start
<< " seconds to drop space: " << " seconds to drop space: "
<< space->name << " (" << space->chain.start->name << " ("
<< space->id << ") active threads " << space->id << ") active threads "
<< crypt_data->rotate_state.active_threads << crypt_data->rotate_state.active_threads
<< "flushing=" << "flushing="

View File

@ -114,8 +114,6 @@ bool fil_space_t::try_to_close(bool print_info)
The tablespace must exist in the memory cache. The tablespace must exist in the memory cache.
@param[in] id tablespace identifier @param[in] id tablespace identifier
@param[in] old_path old file name @param[in] old_path old file name
@param[in] new_name new table name in the
databasename/tablename format
@param[in] new_path_in new file name, @param[in] new_path_in new file name,
or NULL if it is located in the normal data directory or NULL if it is located in the normal data directory
@return true if success */ @return true if success */
@ -123,7 +121,6 @@ static bool
fil_rename_tablespace( fil_rename_tablespace(
ulint id, ulint id,
const char* old_path, const char* old_path,
const char* new_name,
const char* new_path_in); const char* new_path_in);
/* /*
@ -842,7 +839,6 @@ fil_space_free_low(
fil_space_destroy_crypt_data(&space->crypt_data); fil_space_destroy_crypt_data(&space->crypt_data);
space->~fil_space_t(); space->~fil_space_t();
ut_free(space->name);
ut_free(space); ut_free(space);
} }
@ -903,7 +899,7 @@ fil_space_free(
@param mode encryption mode @param mode encryption mode
@return pointer to created tablespace, to be filled in with add() @return pointer to created tablespace, to be filled in with add()
@retval nullptr on failure (such as when the same tablespace exists) */ @retval nullptr on failure (such as when the same tablespace exists) */
fil_space_t *fil_space_t::create(const char *name, ulint id, ulint flags, fil_space_t *fil_space_t::create(ulint id, ulint flags,
fil_type_t purpose, fil_type_t purpose,
fil_space_crypt_t *crypt_data, fil_space_crypt_t *crypt_data,
fil_encryption_t mode) fil_encryption_t mode)
@ -921,7 +917,6 @@ fil_space_t *fil_space_t::create(const char *name, ulint id, ulint flags,
space= new (ut_zalloc_nokey(sizeof(*space))) fil_space_t; space= new (ut_zalloc_nokey(sizeof(*space))) fil_space_t;
space->id = id; space->id = id;
space->name = mem_strdup(name);
UT_LIST_INIT(space->chain, &fil_node_t::chain); UT_LIST_INIT(space->chain, &fil_node_t::chain);
@ -932,11 +927,10 @@ fil_space_t *fil_space_t::create(const char *name, ulint id, ulint flags,
space->crypt_data = crypt_data; space->crypt_data = crypt_data;
space->n_pending.store(CLOSING, std::memory_order_relaxed); space->n_pending.store(CLOSING, std::memory_order_relaxed);
DBUG_LOG("tablespace", DBUG_LOG("tablespace", "Created metadata for " << id);
"Created metadata for " << id << " name " << name);
if (crypt_data) { if (crypt_data) {
DBUG_LOG("crypt", DBUG_LOG("crypt",
"Tablespace " << id << " name " << name "Tablespace " << id
<< " encryption " << crypt_data->encryption << " encryption " << crypt_data->encryption
<< " key id " << crypt_data->key_id << " key id " << crypt_data->key_id
<< ":" << fil_crypt_get_mode(crypt_data) << ":" << fil_crypt_get_mode(crypt_data)
@ -958,13 +952,14 @@ fil_space_t *fil_space_t::create(const char *name, ulint id, ulint flags,
mysql_mutex_lock(&fil_system.mutex); mysql_mutex_lock(&fil_system.mutex);
if (const fil_space_t *old_space = fil_space_get_by_id(id)) { if (const fil_space_t *old_space = fil_space_get_by_id(id)) {
ib::error() << "Trying to add tablespace '" << name ib::error() << "Trying to add tablespace with id " << id
<< "' with id " << id << " to the cache, but tablespace '"
<< " to the tablespace memory cache, but tablespace '" << (old_space->chain.start
<< old_space->name << "' already exists in the cache!"; ? old_space->chain.start->name
: "")
<< "' already exists in the cache!";
mysql_mutex_unlock(&fil_system.mutex); mysql_mutex_unlock(&fil_system.mutex);
space->~fil_space_t(); space->~fil_space_t();
ut_free(space->name);
ut_free(space); ut_free(space);
return(NULL); return(NULL);
} }
@ -989,7 +984,7 @@ fil_space_t *fil_space_t::create(const char *name, ulint id, ulint flags,
} }
if (!fil_system.space_id_reuse_warned) { if (!fil_system.space_id_reuse_warned) {
ib::warn() << "Allocated tablespace ID " << id ib::warn() << "Allocated tablespace ID " << id
<< " for " << name << ", old maximum was " << ", old maximum was "
<< fil_system.max_assigned_id; << fil_system.max_assigned_id;
} }
@ -1471,7 +1466,7 @@ inline void mtr_t::log_file_op(mfile_type_t type, ulint space_id,
/* fil_name_parse() requires that there be at least one path /* fil_name_parse() requires that there be at least one path
separator and that the file path end with ".ibd". */ separator and that the file path end with ".ibd". */
ut_ad(strchr(path, OS_PATH_SEPARATOR) != NULL); ut_ad(strchr(path, '/'));
ut_ad(!strcmp(&path[strlen(path) - strlen(DOT_IBD)], DOT_IBD)); ut_ad(!strcmp(&path[strlen(path) - strlen(DOT_IBD)], DOT_IBD));
flag_modified(); flag_modified();
@ -1509,7 +1504,7 @@ inline void mtr_t::log_file_op(mfile_type_t type, ulint space_id,
if (type == FILE_RENAME) if (type == FILE_RENAME)
{ {
ut_ad(strchr(new_path, OS_PATH_SEPARATOR)); ut_ad(strchr(new_path, '/'));
m_log.push(reinterpret_cast<const byte*>(path), uint32_t(len + 1)); m_log.push(reinterpret_cast<const byte*>(path), uint32_t(len + 1));
m_log.push(reinterpret_cast<const byte*>(new_path), uint32_t(new_len)); m_log.push(reinterpret_cast<const byte*>(new_path), uint32_t(new_len));
} }
@ -1583,7 +1578,7 @@ static ulint fil_check_pending_ops(const fil_space_t* space, ulint count)
/* Give a warning every 10 second, starting after 1 second */ /* Give a warning every 10 second, starting after 1 second */
if ((count % 500) == 50) { if ((count % 500) == 50) {
ib::warn() << "Trying to delete" ib::warn() << "Trying to delete"
" tablespace '" << space->name " tablespace '" << space->chain.start->name
<< "' but there are " << n_pending_ops << "' but there are " << n_pending_ops
<< " pending operations on it."; << " pending operations on it.";
} }
@ -1619,7 +1614,7 @@ fil_check_pending_io(
/* Give a warning every 10 second, starting after 1 second */ /* Give a warning every 10 second, starting after 1 second */
if ((count % 500) == 50) { if ((count % 500) == 50) {
ib::info() << "Trying to delete" ib::info() << "Trying to delete"
" tablespace '" << space->name " tablespace '" << space->chain.start->name
<< "' but there are " << p << "' but there are " << p
<< " pending i/o's on it."; << " pending i/o's on it.";
} }
@ -1745,7 +1740,8 @@ void fil_close_tablespace(ulint id)
/* If it is a delete then also delete any generated files, otherwise /* If it is a delete then also delete any generated files, otherwise
when we drop the database the remove directory will fail. */ when we drop the database the remove directory will fail. */
if (char* cfg_name = fil_make_filepath(path, NULL, CFG, false)) { if (char* cfg_name = fil_make_filepath(path, fil_space_t::name_type{},
CFG, false)) {
os_file_delete_if_exists(innodb_data_file_key, cfg_name, NULL); os_file_delete_if_exists(innodb_data_file_key, cfg_name, NULL);
ut_free(cfg_name); ut_free(cfg_name);
} }
@ -1819,16 +1815,17 @@ dberr_t fil_delete_tablespace(ulint id, bool if_exists,
written to the redo log. */ written to the redo log. */
log_write_up_to(mtr.commit_lsn(), true); log_write_up_to(mtr.commit_lsn(), true);
char* cfg_name = fil_make_filepath(path, NULL, CFG, false); if (char* cfg_name = fil_make_filepath(
if (cfg_name != NULL) { path, fil_space_t::name_type{}, CFG, false)) {
os_file_delete_if_exists(innodb_data_file_key, cfg_name, NULL); os_file_delete_if_exists(innodb_data_file_key,
cfg_name, nullptr);
ut_free(cfg_name); ut_free(cfg_name);
} }
} }
/* Delete the link file pointing to the ibd file we are deleting. */ /* Delete the link file pointing to the ibd file we are deleting. */
if (FSP_FLAGS_HAS_DATA_DIR(space->flags)) { if (FSP_FLAGS_HAS_DATA_DIR(space->flags)) {
RemoteDatafile::delete_link_file(space->name); RemoteDatafile::delete_link_file(space->name());
} }
mysql_mutex_lock(&fil_system.mutex); mysql_mutex_lock(&fil_system.mutex);
@ -1889,25 +1886,21 @@ fil_space_t *fil_truncate_prepare(ulint space_id)
Allocates and builds a file name from a path, a table or tablespace name Allocates and builds a file name from a path, a table or tablespace name
and a suffix. The string must be freed by caller with ut_free(). and a suffix. The string must be freed by caller with ut_free().
@param[in] path NULL or the directory path or the full path and filename. @param[in] path NULL or the directory path or the full path and filename.
@param[in] name NULL if path is full, or Table/Tablespace name @param[in] name {} if path is full, or Table/Tablespace name
@param[in] suffix NULL or the file extention to use. @param[in] ext the file extension to use
@param[in] trim_name true if the last name on the path should be trimmed. @param[in] trim_name true if the last name on the path should be trimmed.
@return own: file name */ @return own: file name */
char* char* fil_make_filepath(const char *path, const fil_space_t::name_type &name,
fil_make_filepath( ib_extention ext, bool trim_name)
const char* path,
const char* name,
ib_extention ext,
bool trim_name)
{ {
/* The path may contain the basename of the file, if so we do not /* The path may contain the basename of the file, if so we do not
need the name. If the path is NULL, we can use the default path, need the name. If the path is NULL, we can use the default path,
but there needs to be a name. */ but there needs to be a name. */
ut_ad(path != NULL || name != NULL); ut_ad(path || name.data());
/* If we are going to strip a name off the path, there better be a /* If we are going to strip a name off the path, there better be a
path and a new name to put back on. */ path and a new name to put back on. */
ut_ad(!trim_name || (path != NULL && name != NULL)); ut_ad(!trim_name || (path && name.data()));
if (path == NULL) { if (path == NULL) {
path = fil_path_to_mysql_datadir; path = fil_path_to_mysql_datadir;
@ -1915,20 +1908,20 @@ fil_make_filepath(
ulint len = 0; /* current length */ ulint len = 0; /* current length */
ulint path_len = strlen(path); ulint path_len = strlen(path);
ulint name_len = (name ? strlen(name) : 0);
const char* suffix = dot_ext[ext]; const char* suffix = dot_ext[ext];
ulint suffix_len = strlen(suffix); ulint suffix_len = strlen(suffix);
ulint full_len = path_len + 1 + name_len + suffix_len + 1; ulint full_len = path_len + 1 + name.size() + suffix_len + 1;
char* full_name = static_cast<char*>(ut_malloc_nokey(full_len)); char* full_name = static_cast<char*>(ut_malloc_nokey(full_len));
if (full_name == NULL) { if (full_name == NULL) {
return NULL; return NULL;
} }
/* If the name is a relative path, do not prepend "./". */ /* If the name is a relative or absolute path, do not prepend "./". */
if (path[0] == '.' if (path[0] == '.'
&& (path[1] == '\0' || path[1] == OS_PATH_SEPARATOR) && (path[1] == '\0' || path[1] == '/' IF_WIN(|| path[1] == '\\',))
&& name != NULL && name[0] == '.') { && name.size() && (name.data()[0] == '.'
|| is_absolute_path(name.data()))) {
path = NULL; path = NULL;
path_len = 0; path_len = 0;
} }
@ -1937,31 +1930,36 @@ fil_make_filepath(
memcpy(full_name, path, path_len); memcpy(full_name, path, path_len);
len = path_len; len = path_len;
full_name[len] = '\0'; full_name[len] = '\0';
os_normalize_path(full_name);
} }
if (trim_name) { if (trim_name) {
/* Find the offset of the last DIR separator and set it to /* Find the offset of the last DIR separator and set it to
null in order to strip off the old basename from this path. */ null in order to strip off the old basename from this path. */
char* last_dir_sep = strrchr(full_name, OS_PATH_SEPARATOR); char* last_dir_sep = strrchr(full_name, '/');
#ifdef _WIN32
if (char *last = strrchr(full_name, '\\')) {
if (last > last_dir_sep) {
last_dir_sep = last;
}
}
#endif
if (last_dir_sep) { if (last_dir_sep) {
last_dir_sep[0] = '\0'; last_dir_sep[0] = '\0';
len = strlen(full_name); len = strlen(full_name);
} }
} }
if (name != NULL) { if (name.size()) {
if (len && full_name[len - 1] != OS_PATH_SEPARATOR) { if (len && full_name[len - 1] != '/') {
/* Add a DIR separator */ /* Add a DIR separator */
full_name[len] = OS_PATH_SEPARATOR; full_name[len] = '/';
full_name[++len] = '\0'; full_name[++len] = '\0';
} }
char* ptr = &full_name[len]; char* ptr = &full_name[len];
memcpy(ptr, name, name_len); memcpy(ptr, name.data(), name.size());
len += name_len; len += name.size();
full_name[len] = '\0'; full_name[len] = '\0';
os_normalize_path(ptr);
} }
/* Make sure that the specified suffix is at the end of the filepath /* Make sure that the specified suffix is at the end of the filepath
@ -1989,6 +1987,13 @@ fil_make_filepath(
return(full_name); return(full_name);
} }
char *fil_make_filepath(const char* path, const table_name_t name,
ib_extention suffix, bool strip_name)
{
return fil_make_filepath(path, {name.m_name, strlen(name.m_name)},
suffix, strip_name);
}
/** Test if a tablespace file can be renamed to a new filepath by checking /** Test if a tablespace file can be renamed to a new filepath by checking
if that the old filepath exists and the new filepath does not exist. if that the old filepath exists and the new filepath does not exist.
@param[in] old_path old filepath @param[in] old_path old filepath
@ -2055,8 +2060,7 @@ retry:
return(DB_SUCCESS); return(DB_SUCCESS);
} }
dberr_t fil_space_t::rename(const char* name, const char* path, bool log, dberr_t fil_space_t::rename(const char* path, bool log, bool replace)
bool replace)
{ {
ut_ad(UT_LIST_GET_LEN(chain) == 1); ut_ad(UT_LIST_GET_LEN(chain) == 1);
ut_ad(!is_system_tablespace(id)); ut_ad(!is_system_tablespace(id));
@ -2070,7 +2074,7 @@ dberr_t fil_space_t::rename(const char* name, const char* path, bool log,
fil_name_write_rename(id, chain.start->name, path); fil_name_write_rename(id, chain.start->name, path);
} }
return fil_rename_tablespace(id, chain.start->name, name, path) return fil_rename_tablespace(id, chain.start->name, path)
? DB_SUCCESS : DB_ERROR; ? DB_SUCCESS : DB_ERROR;
} }
@ -2078,8 +2082,6 @@ dberr_t fil_space_t::rename(const char* name, const char* path, bool log,
The tablespace must exist in the memory cache. The tablespace must exist in the memory cache.
@param[in] id tablespace identifier @param[in] id tablespace identifier
@param[in] old_path old file name @param[in] old_path old file name
@param[in] new_name new table name in the
databasename/tablename format
@param[in] new_path_in new file name, @param[in] new_path_in new file name,
or NULL if it is located in the normal data directory or NULL if it is located in the normal data directory
@return true if success */ @return true if success */
@ -2087,15 +2089,12 @@ static bool
fil_rename_tablespace( fil_rename_tablespace(
ulint id, ulint id,
const char* old_path, const char* old_path,
const char* new_name,
const char* new_path_in) const char* new_path_in)
{ {
fil_space_t* space; fil_space_t* space;
fil_node_t* node; fil_node_t* node;
ut_a(id != 0); ut_a(id != 0);
ut_ad(strchr(new_name, '/') != NULL);
mysql_mutex_lock(&fil_system.mutex); mysql_mutex_lock(&fil_system.mutex);
space = fil_space_get_by_id(id); space = fil_space_get_by_id(id);
@ -2117,15 +2116,11 @@ fil_rename_tablespace(
mysql_mutex_unlock(&fil_system.mutex); mysql_mutex_unlock(&fil_system.mutex);
char* new_file_name = new_path_in == NULL char* new_file_name = mem_strdup(new_path_in);
? fil_make_filepath(NULL, new_name, IBD, false)
: mem_strdup(new_path_in);
char* old_file_name = node->name; char* old_file_name = node->name;
char* new_space_name = mem_strdup(new_name);
char* old_space_name = space->name;
ut_ad(strchr(old_file_name, OS_PATH_SEPARATOR) != NULL); ut_ad(strchr(old_file_name, '/'));
ut_ad(strchr(new_file_name, OS_PATH_SEPARATOR) != NULL); ut_ad(strchr(new_file_name, '/'));
if (!recv_recovery_is_on()) { if (!recv_recovery_is_on()) {
mysql_mutex_lock(&log_sys.mutex); mysql_mutex_lock(&log_sys.mutex);
@ -2135,7 +2130,6 @@ fil_rename_tablespace(
mysql_mutex_assert_owner(&log_sys.mutex); mysql_mutex_assert_owner(&log_sys.mutex);
mysql_mutex_lock(&fil_system.mutex); mysql_mutex_lock(&fil_system.mutex);
space->release(); space->release();
ut_ad(space->name == old_space_name);
ut_ad(node->name == old_file_name); ut_ad(node->name == old_file_name);
bool success; bool success;
DBUG_EXECUTE_IF("fil_rename_tablespace_failure_2", DBUG_EXECUTE_IF("fil_rename_tablespace_failure_2",
@ -2151,26 +2145,17 @@ skip_second_rename:
if (success) { if (success) {
node->name = new_file_name; node->name = new_file_name;
} else {
old_file_name = new_file_name;
} }
if (!recv_recovery_is_on()) { if (!recv_recovery_is_on()) {
mysql_mutex_unlock(&log_sys.mutex); mysql_mutex_unlock(&log_sys.mutex);
} }
ut_ad(space->name == old_space_name);
if (success) {
space->name = new_space_name;
} else {
/* Because nothing was renamed, we must free the new
names, not the old ones. */
old_file_name = new_file_name;
old_space_name = new_space_name;
}
mysql_mutex_unlock(&fil_system.mutex); mysql_mutex_unlock(&fil_system.mutex);
ut_free(old_file_name); ut_free(old_file_name);
ut_free(old_space_name);
return(success); return(success);
} }
@ -2193,7 +2178,7 @@ must be >= FIL_IBD_FILE_INITIAL_SIZE
fil_space_t* fil_space_t*
fil_ibd_create( fil_ibd_create(
ulint space_id, ulint space_id,
const char* name, const table_name_t name,
const char* path, const char* path,
ulint flags, ulint flags,
uint32_t size, uint32_t size,
@ -2341,6 +2326,7 @@ err_exit:
} }
aligned_free(page); aligned_free(page);
fil_space_t::name_type space_name;
if (*err != DB_SUCCESS) { if (*err != DB_SUCCESS) {
ib::error() ib::error()
@ -2359,13 +2345,14 @@ err_exit:
if (has_data_dir) { if (has_data_dir) {
/* Make the ISL file if the IBD file is not /* Make the ISL file if the IBD file is not
in the default location. */ in the default location. */
*err = RemoteDatafile::create_link_file(name, path); space_name = {name.m_name, strlen(name.m_name)};
*err = RemoteDatafile::create_link_file(space_name, path);
if (*err != DB_SUCCESS) { if (*err != DB_SUCCESS) {
goto err_exit; goto err_exit;
} }
} }
if (fil_space_t* space = fil_space_t::create(name, space_id, flags, if (fil_space_t* space = fil_space_t::create(space_id, flags,
FIL_TYPE_TABLESPACE, FIL_TYPE_TABLESPACE,
crypt_data, mode)) { crypt_data, mode)) {
space->punch_hole = punch_hole; space->punch_hole = punch_hole;
@ -2380,8 +2367,8 @@ err_exit:
return space; return space;
} }
if (has_data_dir) { if (space_name.data()) {
RemoteDatafile::delete_link_file(name); RemoteDatafile::delete_link_file(space_name);
} }
*err = DB_ERROR; *err = DB_ERROR;
@ -2424,23 +2411,12 @@ fil_ibd_open(
fil_type_t purpose, fil_type_t purpose,
ulint id, ulint id,
ulint flags, ulint flags,
const table_name_t& tablename, const table_name_t tablename,
const char* path_in, const char* path_in,
dberr_t* err) dberr_t* err)
{ {
mysql_mutex_lock(&fil_system.mutex); mysql_mutex_lock(&fil_system.mutex);
if (fil_space_t* space = fil_space_get_by_id(id)) { if (fil_space_t* space = fil_space_get_by_id(id)) {
if (strcmp(space->name, tablename.m_name)) {
table_name_t space_name;
space_name.m_name = space->name;
ib::error()
<< "Trying to open table " << tablename
<< " with id " << id
<< ", conflicting with " << space_name;
space = NULL;
if (err) *err = DB_TABLESPACE_EXISTS;
} else if (err) *err = DB_SUCCESS;
mysql_mutex_unlock(&fil_system.mutex); mysql_mutex_unlock(&fil_system.mutex);
if (space && validate && !srv_read_only_mode) { if (space && validate && !srv_read_only_mode) {
@ -2466,27 +2442,32 @@ corrupted:
} }
ut_ad(fil_space_t::is_valid_flags(flags & ~FSP_FLAGS_MEM_MASK, id)); ut_ad(fil_space_t::is_valid_flags(flags & ~FSP_FLAGS_MEM_MASK, id));
df_default.init(tablename.m_name, flags); df_default.init(flags);
df_remote.init(tablename.m_name, flags); df_remote.init(flags);
/* Discover the correct file by looking in three possible locations /* Discover the correct file by looking in three possible locations
while avoiding unecessary effort. */ while avoiding unecessary effort. */
/* We will always look for an ibd in the default location. */ /* We will always look for an ibd in the default location. */
df_default.make_filepath(NULL, tablename.m_name, IBD); df_default.make_filepath(nullptr, {tablename.m_name,
strlen(tablename.m_name)}, IBD);
/* Look for a filepath embedded in an ISL where the default file /* Look for a filepath embedded in an ISL where the default file
would be. */ would be. */
if (df_remote.open_read_only(true) == DB_SUCCESS) { if (df_remote.open_link_file(tablename)) {
ut_ad(df_remote.is_open());
/* Always validate a file opened from an ISL pointer */
validate = true;
++tablespaces_found;
} else if (df_remote.filepath() != NULL) {
/* An ISL file was found but contained a bad filepath in it.
Better validate anything we do find. */
validate = true; validate = true;
if (df_remote.open_read_only(true) == DB_SUCCESS) {
ut_ad(df_remote.is_open());
++tablespaces_found;
} else {
/* The following call prints an error message */
os_file_get_last_error(true);
ib::error() << "A link file was found named '"
<< df_remote.link_filepath()
<< "' but the linked tablespace '"
<< df_remote.filepath()
<< "' could not be opened read-only.";
}
} }
/* Attempt to open the tablespace at the dictionary filepath. */ /* Attempt to open the tablespace at the dictionary filepath. */
@ -2619,7 +2600,7 @@ skip_validate:
: NULL; : NULL;
fil_space_t* space = fil_space_t::create( fil_space_t* space = fil_space_t::create(
tablename.m_name, id, flags, purpose, crypt_data); id, flags, purpose, crypt_data);
if (!space) { if (!space) {
goto error; goto error;
} }
@ -2647,89 +2628,6 @@ skip_validate:
return space; return space;
} }
/** Looks for a pre-existing fil_space_t with the given tablespace ID
and, if found, returns the name and filepath in newly allocated buffers
that the caller must free.
@param[in] space_id The tablespace ID to search for.
@param[out] name Name of the tablespace found.
@param[out] filepath The filepath of the first datafile for the
tablespace.
@return true if tablespace is found, false if not. */
bool
fil_space_read_name_and_filepath(
ulint space_id,
char** name,
char** filepath)
{
bool success = false;
*name = NULL;
*filepath = NULL;
mysql_mutex_lock(&fil_system.mutex);
fil_space_t* space = fil_space_get_by_id(space_id);
if (space != NULL) {
*name = mem_strdup(space->name);
fil_node_t* node = UT_LIST_GET_FIRST(space->chain);
*filepath = mem_strdup(node->name);
success = true;
}
mysql_mutex_unlock(&fil_system.mutex);
return(success);
}
/** Convert a file name to a tablespace name.
@param[in] filename directory/databasename/tablename.ibd
@return database/tablename string, to be freed with ut_free() */
char*
fil_path_to_space_name(
const char* filename)
{
/* Strip the file name prefix and suffix, leaving
only databasename/tablename. */
ulint filename_len = strlen(filename);
const char* end = filename + filename_len;
#ifdef HAVE_MEMRCHR
const char* tablename = 1 + static_cast<const char*>(
memrchr(filename, OS_PATH_SEPARATOR,
filename_len));
const char* dbname = 1 + static_cast<const char*>(
memrchr(filename, OS_PATH_SEPARATOR,
tablename - filename - 1));
#else /* HAVE_MEMRCHR */
const char* tablename = filename;
const char* dbname = NULL;
while (const char* t = static_cast<const char*>(
memchr(tablename, OS_PATH_SEPARATOR,
ulint(end - tablename)))) {
dbname = tablename;
tablename = t + 1;
}
#endif /* HAVE_MEMRCHR */
ut_ad(dbname != NULL);
ut_ad(tablename > dbname);
ut_ad(tablename < end);
ut_ad(end - tablename > 4);
ut_ad(memcmp(end - 4, DOT_IBD, 4) == 0);
char* name = mem_strdupl(dbname, ulint(end - dbname) - 4);
ut_ad(name[tablename - dbname - 1] == OS_PATH_SEPARATOR);
#if OS_PATH_SEPARATOR != '/'
/* space->name uses '/', not OS_PATH_SEPARATOR. */
name[tablename - dbname - 1] = '/';
#endif
return(name);
}
/** Discover the correct IBD file to open given a remote or missing /** Discover the correct IBD file to open given a remote or missing
filepath from the REDO log. Administrators can move a crashed filepath from the REDO log. Administrators can move a crashed
database to another location on the same machine and try to recover it. database to another location on the same machine and try to recover it.
@ -2760,14 +2658,18 @@ fil_ibd_discover(
ulint sep_found = 0; ulint sep_found = 0;
const char* db = basename; const char* db = basename;
for (; db > filename && sep_found < 2; db--) { for (; db > filename && sep_found < 2; db--) {
if (db[0] == OS_PATH_SEPARATOR) { switch (db[0]) {
#ifdef _WIN32
case '\\':
#endif
case '/':
sep_found++; sep_found++;
} }
} }
if (sep_found == 2) { if (sep_found == 2) {
db += 2; db += 2;
df_def_per.init(db, 0); df_def_per.init(0);
df_def_per.make_filepath(NULL, db, IBD); df_def_per.set_filepath(db);
if (df_def_per.open_read_only(false) == DB_SUCCESS if (df_def_per.open_read_only(false) == DB_SUCCESS
&& df_def_per.validate_for_recovery() == DB_SUCCESS && df_def_per.validate_for_recovery() == DB_SUCCESS
&& df_def_per.space_id() == space_id) { && df_def_per.space_id() == space_id) {
@ -2787,8 +2689,16 @@ fil_ibd_discover(
case SRV_OPERATION_RESTORE: case SRV_OPERATION_RESTORE:
break; break;
case SRV_OPERATION_NORMAL: case SRV_OPERATION_NORMAL:
df_rem_per.set_name(db); char* name = const_cast<char*>(db);
if (df_rem_per.open_link_file() != DB_SUCCESS) { size_t len= strlen(name);
if (len <= 4 || strcmp(name + len - 4, dot_ext[IBD])) {
break;
}
name[len - 4] = '\0';
df_rem_per.open_link_file(table_name_t{name});
name[len - 4] = *dot_ext[IBD];
if (!df_rem_per.filepath()) {
break; break;
} }
@ -2811,7 +2721,7 @@ fil_ibd_discover(
} }
/* Use this file if it has the space_id from the /* Use this file if it has the space_id from the
MLOG record. */ FILE_ record. */
if (df_rem_per.space_id() == space_id) { if (df_rem_per.space_id() == space_id) {
df.set_filepath(df_rem_per.filepath()); df.set_filepath(df_rem_per.filepath());
df.open_read_only(false); df.open_read_only(false);
@ -2883,9 +2793,20 @@ fil_ibd_load(
if (srv_operation == SRV_OPERATION_RESTORE) { if (srv_operation == SRV_OPERATION_RESTORE) {
/* Replace absolute DATA DIRECTORY file paths with /* Replace absolute DATA DIRECTORY file paths with
short names relative to the backup directory. */ short names relative to the backup directory. */
if (const char* name = strrchr(filename, OS_PATH_SEPARATOR)) { const char* name = strrchr(filename, '/');
#ifdef _WIN32
if (const char *last = strrchr(filename, '\\')) {
if (last > name) {
name = last;
}
}
#endif
if (name) {
while (--name > filename while (--name > filename
&& *name != OS_PATH_SEPARATOR); #ifdef _WIN32
&& *name != '\\'
#endif
&& *name != '/');
if (name > filename) { if (name > filename) {
filename = name + 1; filename = name + 1;
} }
@ -2971,7 +2892,7 @@ fil_ibd_load(
first_page) first_page)
: NULL; : NULL;
space = fil_space_t::create( space = fil_space_t::create(
file.name(), space_id, flags, FIL_TYPE_TABLESPACE, crypt_data); space_id, flags, FIL_TYPE_TABLESPACE, crypt_data);
if (space == NULL) { if (space == NULL) {
return(FIL_LOAD_INVALID); return(FIL_LOAD_INVALID);
@ -3075,15 +2996,10 @@ func_exit:
memory cache. Note that if we have not done a crash recovery at the database memory cache. Note that if we have not done a crash recovery at the database
startup, there may be many tablespaces which are not yet in the memory cache. startup, there may be many tablespaces which are not yet in the memory cache.
@param[in] id Tablespace ID @param[in] id Tablespace ID
@param[in] name Tablespace name used in fil_space_t::create().
@param[in] table_flags table flags @param[in] table_flags table flags
@return the tablespace @return the tablespace
@retval NULL if no matching tablespace exists in the memory cache */ @retval NULL if no matching tablespace exists in the memory cache */
fil_space_t* fil_space_t *fil_space_for_table_exists_in_mem(ulint id, ulint table_flags)
fil_space_for_table_exists_in_mem(
ulint id,
const char* name,
ulint table_flags)
{ {
const ulint expected_flags = dict_tf_to_fsp_flags(table_flags); const ulint expected_flags = dict_tf_to_fsp_flags(table_flags);
@ -3097,17 +3013,6 @@ fil_space_for_table_exists_in_mem(
goto func_exit; goto func_exit;
} }
if (strcmp(space->name, name)) {
ib::error() << "Table " << name
<< " in InnoDB data dictionary"
" has tablespace id " << id
<< ", but the tablespace"
" with that id has name " << space->name << "."
" Have you deleted or moved .ibd files?";
ib::info() << TROUBLESHOOT_DATADICT_MSG;
goto func_exit;
}
/* Adjust the flags that are in FSP_FLAGS_MEM_MASK. /* Adjust the flags that are in FSP_FLAGS_MEM_MASK.
FSP_SPACE_FLAGS will not be written back here. */ FSP_SPACE_FLAGS will not be written back here. */
space->flags = (space->flags & ~FSP_FLAGS_MEM_MASK) space->flags = (space->flags & ~FSP_FLAGS_MEM_MASK)
@ -3206,8 +3111,8 @@ fil_io_t fil_space_t::io(const IORequest &type, os_offset_t offset, size_t len,
release(); release();
return {DB_ERROR, nullptr}; return {DB_ERROR, nullptr};
} }
fil_report_invalid_page_access(name, offset, fil_report_invalid_page_access(node->name,
len, offset, len,
type.is_read()); type.is_read());
} }
} }
@ -3422,23 +3327,18 @@ fil_page_set_type(
Delete the tablespace file and any related files like .cfg. Delete the tablespace file and any related files like .cfg.
This should not be called for temporary tables. This should not be called for temporary tables.
@param[in] ibd_filepath File path of the IBD tablespace */ @param[in] ibd_filepath File path of the IBD tablespace */
void void fil_delete_file(const char *ibd_filepath)
fil_delete_file(
/*============*/
const char* ibd_filepath)
{ {
/* Force a delete of any stale .ibd files that are lying around. */ ib::info() << "Deleting " << ibd_filepath;
os_file_delete_if_exists(innodb_data_file_key, ibd_filepath, nullptr);
ib::info() << "Deleting " << ibd_filepath; if (char *cfg_filepath= fil_make_filepath(ibd_filepath,
os_file_delete_if_exists(innodb_data_file_key, ibd_filepath, NULL); fil_space_t::name_type{}, CFG,
false))
char* cfg_filepath = fil_make_filepath( {
ibd_filepath, NULL, CFG, false); os_file_delete_if_exists(innodb_data_file_key, cfg_filepath, nullptr);
if (cfg_filepath != NULL) { ut_free(cfg_filepath);
os_file_delete_if_exists( }
innodb_data_file_key, cfg_filepath, NULL);
ut_free(cfg_filepath);
}
} }
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
@ -3512,7 +3412,6 @@ void fil_names_dirty_and_write(fil_space_t* space)
DBUG_EXECUTE_IF("fil_names_write_bogus", DBUG_EXECUTE_IF("fil_names_write_bogus",
{ {
char bogus_name[] = "./test/bogus file.ibd"; char bogus_name[] = "./test/bogus file.ibd";
os_normalize_path(bogus_name);
fil_name_write( fil_name_write(
SRV_SPACE_ID_UPPER_BOUND, SRV_SPACE_ID_UPPER_BOUND,
bogus_name, &mtr); bogus_name, &mtr);
@ -3666,6 +3565,43 @@ fil_space_get_block_size(const fil_space_t* space, unsigned offset)
return block_size; return block_size;
} }
/** @return the tablespace name (databasename/tablename) */
fil_space_t::name_type fil_space_t::name() const
{
switch (id) {
case 0:
return name_type{"innodb_system", 13};
case SRV_TMP_SPACE_ID:
return name_type{"innodb_temporary", 16};
}
if (!UT_LIST_GET_FIRST(chain) || srv_is_undo_tablespace(id))
return name_type{};
ut_ad(purpose != FIL_TYPE_TEMPORARY);
ut_ad(UT_LIST_GET_LEN(chain) == 1);
const char *path= UT_LIST_GET_FIRST(chain)->name;
const char *sep= strchr(path, '/');
ut_ad(sep);
while (const char *next_sep= strchr(sep + 1, '/'))
path= sep + 1, sep= next_sep;
#ifdef _WIN32
if (const char *last_sep= strchr(path, '\\'))
if (last_sep < sep)
path= last_sep;
#endif
size_t len= strlen(path);
ut_ad(len > 4);
len-= 4;
ut_ad(!strcmp(&path[len], DOT_IBD));
return name_type{path, len};
}
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
fil_space_t *fil_space_t::next_in_space_list() fil_space_t *fil_space_t::next_in_space_list()

View File

@ -1,7 +1,7 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 2013, 2016, Oracle and/or its affiliates. All Rights Reserved. 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 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
@ -30,29 +30,12 @@ Created 2013-7-26 by Kevin Lewis
#include "page0page.h" #include "page0page.h"
#include "srv0start.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. */ /** Release the resources. */
void void
Datafile::shutdown() Datafile::shutdown()
{ {
close(); close();
ut_free(m_name);
m_name = NULL;
free_filepath(); free_filepath();
free_first_page(); 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 /** Open a data file in read-write mode during start-up so that
doublewrite pages can be restored and then it can be validated.* 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 */ @return DB_SUCCESS or error code */
dberr_t inline dberr_t Datafile::open_read_write()
Datafile::open_read_write(bool read_only_mode)
{ {
bool success = false; bool success = false;
ut_ad(m_handle == OS_FILE_CLOSED); 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 /* 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 */ 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); set_open_flags(OS_FILE_OPEN);
m_handle = os_file_create_simple_no_error_handling( m_handle = os_file_create_simple_no_error_handling(
innodb_data_file_key, m_filepath, m_open_flags, 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) { if (!success) {
m_last_os_error = os_file_get_last_error(true); 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. Prepend the dirpath to filename using the extension given.
If dirpath is NULL, prepend the default datadir to filepath. If dirpath is NULL, prepend the default datadir to filepath.
Store the result in m_filepath. Store the result in m_filepath.
@param[in] dirpath directory path @param dirpath directory path
@param[in] filename filename or filepath @param name tablespace (table) name
@param[in] ext filename extension */ @param ext filename extension */
void void Datafile::make_filepath(const char *dirpath, fil_space_t::name_type name,
Datafile::make_filepath( ib_extention ext)
const char* dirpath,
const char* filename,
ib_extention ext)
{ {
ut_ad(dirpath != NULL || filename != NULL); ut_ad(dirpath || name.size());
free_filepath();
free_filepath(); m_filepath= fil_make_filepath(dirpath, name, ext, false);
ut_ad(m_filepath);
m_filepath = fil_make_filepath(dirpath, filename, ext, false); set_filename();
ut_ad(m_filepath != NULL);
set_filename();
} }
/** Set the filepath by duplicating the filepath sent in. This is the /** Set the filepath by duplicating the filepath sent in. This is the
@ -258,23 +233,6 @@ Datafile::same_as(
#endif /* WIN32 */ #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 /** Reads a few significant fields from the first page of the first
datafile. The Datafile must already be open. datafile. The Datafile must already be open.
@param[in] read_only_mode If true, then readonly mode checks are enforced. @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 page 0 from doublewrite and read the space ID from a survey
of the first few pages. */ of the first few pages. */
close(); close();
err = open_read_write(srv_read_only_mode); err = open_read_write();
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
return(err); return(err);
} }
@ -476,10 +434,6 @@ Datafile::validate_for_recovery()
err = validate_first_page(0); err = validate_first_page(0);
} }
if (err == DB_SUCCESS) {
set_name(NULL);
}
return(err); 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_SUCCESS on if the datafile is valid
@retval DB_CORRUPTION if the datafile is not readable @retval DB_CORRUPTION if the datafile is not readable
@retval DB_TABLESPACE_EXISTS if there is a duplicate space_id */ @retval DB_TABLESPACE_EXISTS if there is a duplicate space_id */
dberr_t dberr_t Datafile::validate_first_page(lsn_t *flush_lsn)
Datafile::validate_first_page(lsn_t* flush_lsn)
{ {
char* prev_name;
char* prev_filepath;
const char* error_txt = NULL; const char* error_txt = NULL;
m_is_valid = true; m_is_valid = true;
@ -576,26 +527,30 @@ err_exit:
goto err_exit; goto err_exit;
} }
if (fil_space_read_name_and_filepath( mysql_mutex_lock(&fil_system.mutex);
m_space_id, &prev_name, &prev_filepath)) {
if (0 == strcmp(m_filepath, prev_filepath)) { fil_space_t* space = fil_space_get_by_id(m_space_id);
ut_free(prev_name);
ut_free(prev_filepath); if (space) {
return(DB_SUCCESS); 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. */ /* Make sure the space_id has not already been opened. */
ib::error() << "Attempted to open a previously opened" ib::error() << "Attempted to open a previously opened"
" tablespace. Previous tablespace " << prev_name " tablespace. Previous tablespace: "
<< " at filepath: " << prev_filepath << (node ? node->name : "(unknown)")
<< " uses space ID: " << m_space_id << " uses space ID: " << m_space_id
<< ". Cannot open filepath: " << m_filepath << ". Cannot open filepath: " << m_filepath
<< " which uses the same space ID."; << " which uses the same space ID.";
}
ut_free(prev_name); mysql_mutex_unlock(&fil_system.mutex);
ut_free(prev_filepath);
if (space) {
m_is_valid = false; m_is_valid = false;
free_first_page(); free_first_page();
@ -809,68 +764,61 @@ Datafile::restore_from_doublewrite()
!= DB_SUCCESS); != DB_SUCCESS);
} }
/** Create a link filename based on the contents of m_name, /** 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 (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;
}
/** Create a link filename,
open that file, and read the contents into m_filepath. open that file, and read the contents into m_filepath.
@retval DB_SUCCESS if remote linked tablespace file is opened and read. @param name table name
@retval DB_CANNOT_OPEN_FILE if the link file does not exist. */ @return filepath()
dberr_t @retval nullptr if the .isl file does not exist or cannot be read */
RemoteDatafile::open_link_file() const char *RemoteDatafile::open_link_file(const table_name_t &name)
{ {
if (m_link_filepath == NULL) { if (!m_link_filepath)
m_link_filepath = fil_make_filepath(NULL, name(), ISL, false); m_link_filepath= fil_make_filepath(nullptr, name, ISL, false);
} m_filepath= read_link_file(m_link_filepath);
return m_filepath;
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)
{
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);
}
/** 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)
{
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);
} }
/** Release the resources. */ /** Release the resources. */
@ -885,16 +833,12 @@ RemoteDatafile::shutdown()
} }
} }
/** Creates a new InnoDB Symbolic Link (ISL) file. It is always created /** Create InnoDB Symbolic Link (ISL) file.
under the 'datadir' of MySQL. The datadir is the directory of a @param name tablespace name
running mysqld program. We can refer to it by simply using the path ".". @param filepath full file name
@param[in] name tablespace name
@param[in] filepath remote filepath of tablespace datafile
@return DB_SUCCESS or error code */ @return DB_SUCCESS or error code */
dberr_t dberr_t RemoteDatafile::create_link_file(fil_space_t::name_type name,
RemoteDatafile::create_link_file( const char *filepath)
const char* name,
const char* filepath)
{ {
bool success; bool success;
dberr_t err = DB_SUCCESS; dberr_t err = DB_SUCCESS;
@ -902,7 +846,6 @@ RemoteDatafile::create_link_file(
char* prev_filepath = NULL; char* prev_filepath = NULL;
ut_ad(!srv_read_only_mode); 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); 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 /* Truncate (starting with MySQL 5.6, probably no
longer since MariaDB Server 10.2.19) used to call this longer since MariaDB Server 10.2.19) used to call this
with an existing link file which contains the same filepath. */ 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); ut_free(prev_filepath);
if (same) { if (same) {
ut_free(link_filepath); ut_free(link_filepath);
@ -963,9 +907,8 @@ RemoteDatafile::create_link_file(
return(err); return(err);
} }
ulint rbytes = fwrite(filepath, 1, strlen(filepath), file); const size_t len = strlen(filepath);
if (fwrite(filepath, 1, len, file) != len) {
if (rbytes != strlen(filepath)) {
error = os_file_get_last_error(true); error = os_file_get_last_error(true);
ib::error() << ib::error() <<
"Cannot write link file: " "Cannot write link file: "
@ -994,50 +937,12 @@ RemoteDatafile::delete_link_file(void)
} }
/** Delete an InnoDB Symbolic Link (ISL) file by name. /** Delete an InnoDB Symbolic Link (ISL) file by name.
@param[in] name tablespace name */ @param name tablespace name */
void void RemoteDatafile::delete_link_file(fil_space_t::name_type name)
RemoteDatafile::delete_link_file(
const char* name)
{ {
char* link_filepath = fil_make_filepath(NULL, name, ISL, false); if (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, nullptr);
os_file_delete_if_exists( ut_free(link_filepath);
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)
{
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);
} }

View File

@ -1142,10 +1142,11 @@ fsp_alloc_free_page(
ut_a(!is_system_tablespace(space_id)); ut_a(!is_system_tablespace(space_id));
if (page_no >= FSP_EXTENT_SIZE) { if (page_no >= FSP_EXTENT_SIZE) {
ib::error() << "Trying to extend a single-table" ib::error() << "Trying to extend "
" tablespace " << space->name << " , by single" << space->chain.start->name
" page(s) though the space size " << space_size << " by single page(s) though the size is "
<< ". Page no " << page_no << "."; << space_size
<< ". Page no " << page_no << ".";
return(NULL); return(NULL);
} }

View File

@ -1,7 +1,7 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 2013, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2013, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, MariaDB Corporation. Copyright (c) 2017, 2021, 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
@ -131,7 +131,7 @@ Tablespace::open_or_create(bool is_temp)
} }
space = fil_space_t::create( space = fil_space_t::create(
m_name, m_space_id, fsp_flags, m_space_id, fsp_flags,
is_temp is_temp
? FIL_TYPE_TEMPORARY : FIL_TYPE_TABLESPACE, ? FIL_TYPE_TEMPORARY : FIL_TYPE_TABLESPACE,
NULL); NULL);
@ -178,7 +178,7 @@ Tablespace::delete_files()
if (success && file_pre_exists) { if (success && file_pre_exists) {
ib::info() << "Removed temporary tablespace data" ib::info() << "Removed temporary tablespace data"
" file: \"" << it->m_name << "\""; " file: \"" << it->m_filepath << "\"";
} }
} }
} }
@ -191,18 +191,13 @@ must end with the extension .ibd and have a basename of at least 1 byte.
Set tablespace m_path member and add a Datafile with the filename. Set tablespace m_path member and add a Datafile with the filename.
@param[in] datafile_path full path of the tablespace file. */ @param[in] datafile_path full path of the tablespace file. */
dberr_t dberr_t Tablespace::add_datafile(const char *filepath)
Tablespace::add_datafile(
const char* datafile_added)
{ {
/* The path provided ends in ".ibd". This was assured by /* The path provided ends in ".ibd". This was assured by
validate_create_tablespace_info() */ validate_create_tablespace_info() */
ut_d(const char* dot = strrchr(datafile_added, '.')); ut_d(const char* dot = strrchr(filepath, '.'));
ut_ad(dot != NULL && 0 == strcmp(dot, DOT_IBD)); ut_ad(dot != NULL && 0 == strcmp(dot, DOT_IBD));
char* filepath = mem_strdup(datafile_added);
os_normalize_path(filepath);
/* If the path is an absolute path, separate it onto m_path and a /* If the path is an absolute path, separate it onto m_path and a
basename. For relative paths, make the whole thing a basename so that basename. For relative paths, make the whole thing a basename so that
it can be appended to the datadir. */ it can be appended to the datadir. */
@ -219,12 +214,9 @@ Tablespace::add_datafile(
/* Now add a new Datafile and set the filepath /* Now add a new Datafile and set the filepath
using the m_path created above. */ using the m_path created above. */
m_files.push_back(Datafile(m_name, m_flags, m_files.push_back(Datafile(m_flags, FIL_IBD_FILE_INITIAL_SIZE, 0));
FIL_IBD_FILE_INITIAL_SIZE, 0)); m_files.back().make_filepath(m_path, {basename, strlen(basename) - 4},
Datafile* datafile = &m_files.back(); IBD);
datafile->make_filepath(m_path, basename, IBD);
ut_free(filepath);
return(DB_SUCCESS); return(DB_SUCCESS);
} }

View File

@ -1,7 +1,7 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 2013, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2013, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2016, 2020, MariaDB Corporation. Copyright (c) 2016, 2021, 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
@ -275,10 +275,10 @@ SysTablespace::parse_params(
} }
} }
m_files.push_back(Datafile(filepath, flags(), uint32_t(size), m_files.push_back(Datafile(flags(), uint32_t(size), order));
order)); m_files.back().make_filepath(path(),
Datafile* datafile = &m_files.back(); {filepath, strlen(filepath)},
datafile->make_filepath(path(), filepath, NO_EXT); NO_EXT);
if (::strlen(str) >= 6 if (::strlen(str) >= 6
&& *str == 'n' && *str == 'n'
@ -361,13 +361,12 @@ SysTablespace::check_size(
if (file.m_size > rounded_size_pages if (file.m_size > rounded_size_pages
|| (m_last_file_size_max > 0 || (m_last_file_size_max > 0
&& m_last_file_size_max < rounded_size_pages)) { && m_last_file_size_max < rounded_size_pages)) {
ib::error() << "The Auto-extending " << name() ib::error() << "The Auto-extending data file '"
<< " data file '" << file.filepath() << "' is" << file.filepath()
" of a different size " << rounded_size_pages << "' is of a different size "
<< " pages than specified" << rounded_size_pages
" in the .cnf file: initial " << file.m_size << " pages than specified"
<< " pages, max " << m_last_file_size_max " by innodb_data_file_path";
<< " (relevant if non-zero) pages!";
return(DB_ERROR); return(DB_ERROR);
} }
@ -375,11 +374,11 @@ SysTablespace::check_size(
} }
if (rounded_size_pages != file.m_size) { if (rounded_size_pages != file.m_size) {
ib::error() << "The " << name() << " data file '" ib::error() << "The data file '"
<< file.filepath() << "' is of a different size " << file.filepath() << "' is of a different size "
<< rounded_size_pages << " pages" << rounded_size_pages << " pages"
" than the " << file.m_size << " pages specified in" " than the " << file.m_size << " pages specified by"
" the .cnf file!"; " innodb_data_file_path";
return(DB_ERROR); return(DB_ERROR);
} }
@ -584,7 +583,7 @@ SysTablespace::read_lsn_and_check_flags(lsn_t* flushed_lsn)
if (space_id() != it->m_space_id) { if (space_id() != it->m_space_id) {
ib::error() ib::error()
<< "The " << name() << " data file '" << it->name() << "The data file '" << it->filepath()
<< "' has the wrong space ID. It should be " << "' has the wrong space ID. It should be "
<< space_id() << ", but " << it->m_space_id << space_id() << ", but " << it->m_space_id
<< " was found"; << " was found";
@ -628,20 +627,16 @@ SysTablespace::check_file_status(
break; break;
case DB_SUCCESS: case DB_SUCCESS:
/* Note: stat.rw_perm is only valid for "regular" files */ /* Note: stat.rw_perm is only valid for "regular" files */
if (stat.type == OS_FILE_TYPE_FILE) { if (stat.type == OS_FILE_TYPE_FILE) {
if (!stat.rw_perm) { if (!stat.rw_perm) {
const char *p = (!srv_read_only_mode ib::error() << "The data file"
|| m_ignore_read_only) << " '" << file.filepath()
? "writable" << ((!srv_read_only_mode
: "readable"; || m_ignore_read_only)
? "' must be writable"
ib::error() << "The " << name() << " data file" : "' must be readable");
<< " '" << file.name() << "' must be "
<< p;
err = DB_ERROR; err = DB_ERROR;
reason = FILE_STATUS_READ_WRITE_ERROR; reason = FILE_STATUS_READ_WRITE_ERROR;
@ -649,9 +644,8 @@ SysTablespace::check_file_status(
} else { } else {
/* Not a regular file, bail out. */ /* Not a regular file, bail out. */
ib::error() << "The " << name() << " data file '" ib::error() << "The data file '" << file.filepath()
<< file.name() << "' is not a regular" << "' is not a regular file.";
" InnoDB data file.";
err = DB_ERROR; err = DB_ERROR;
reason = FILE_STATUS_NOT_REGULAR_FILE_ERROR; reason = FILE_STATUS_NOT_REGULAR_FILE_ERROR;
@ -692,14 +686,14 @@ SysTablespace::file_not_found(
*create_new_db = TRUE; *create_new_db = TRUE;
if (space_id() == TRX_SYS_SPACE) { if (space_id() == TRX_SYS_SPACE) {
ib::info() << "The first " << name() << " data file '" ib::info() << "The first data file '"
<< file.name() << "' did not exist." << file.filepath() << "' did not exist."
" A new tablespace will be created!"; " A new tablespace will be created!";
} }
} else { } else {
ib::info() << "Need to create a new " << name() ib::info() << "Need to create a new data file '"
<< " data file '" << file.name() << "'."; << file.filepath() << "'.";
} }
/* Set the file create mode. */ /* Set the file create mode. */
@ -758,8 +752,8 @@ SysTablespace::check_file_spec(
*create_new_db = FALSE; *create_new_db = FALSE;
if (m_files.size() >= 1000) { if (m_files.size() >= 1000) {
ib::error() << "There must be < 1000 data files in " ib::error() << "There must be < 1000 data files "
<< name() << " but " << m_files.size() << " have been" " but " << m_files.size() << " have been"
" defined."; " defined.";
return(DB_ERROR); return(DB_ERROR);
@ -798,22 +792,23 @@ SysTablespace::check_file_spec(
} else if (err != DB_SUCCESS) { } else if (err != DB_SUCCESS) {
if (reason_if_failed == FILE_STATUS_READ_WRITE_ERROR) { if (reason_if_failed == FILE_STATUS_READ_WRITE_ERROR) {
const char* p = (!srv_read_only_mode ib::error() << "The data file '"
|| m_ignore_read_only) << it->filepath()
? "writable" : "readable"; << ((!srv_read_only_mode
ib::error() << "The " << name() << " data file" || m_ignore_read_only)
<< " '" << it->name() << "' must be " ? "' must be writable"
<< p; : "' must be readable");
} }
ut_a(err != DB_FAIL); ut_a(err != DB_FAIL);
break; break;
} else if (*create_new_db) { } else if (*create_new_db) {
ib::error() << "The " << name() << " data file '" ib::error() << "The data file '"
<< begin->m_name << "' was not found but" << begin->filepath()
" one of the other data files '" << it->m_name << "' was not found but"
<< "' exists."; " one of the other data files '"
<< it->filepath() << "' exists.";
err = DB_ERROR; err = DB_ERROR;
break; break;
@ -907,7 +902,7 @@ SysTablespace::open_or_create(
} else if (is_temp) { } else if (is_temp) {
ut_ad(space_id() == SRV_TMP_SPACE_ID); ut_ad(space_id() == SRV_TMP_SPACE_ID);
space = fil_space_t::create( space = fil_space_t::create(
name(), SRV_TMP_SPACE_ID, flags(), SRV_TMP_SPACE_ID, flags(),
FIL_TYPE_TEMPORARY, NULL); FIL_TYPE_TEMPORARY, NULL);
ut_ad(space == fil_system.temp_space); ut_ad(space == fil_system.temp_space);
if (!space) { if (!space) {
@ -918,7 +913,7 @@ SysTablespace::open_or_create(
} else { } else {
ut_ad(space_id() == TRX_SYS_SPACE); ut_ad(space_id() == TRX_SYS_SPACE);
space = fil_space_t::create( space = fil_space_t::create(
name(), TRX_SYS_SPACE, it->flags(), TRX_SYS_SPACE, it->flags(),
FIL_TYPE_TABLESPACE, NULL); FIL_TYPE_TABLESPACE, NULL);
ut_ad(space == fil_system.sys_space); ut_ad(space == fil_system.sys_space);
if (!space) { if (!space) {
@ -965,8 +960,7 @@ uint32_t SysTablespace::get_increment() const
if (!is_valid_size()) if (!is_valid_size())
{ {
ib::error() << "The last data file in " << name() ib::error() << "The last data file has a size of " << last_file_size()
<< " has a size of " << last_file_size()
<< " but the max size allowed is " << " but the max size allowed is "
<< m_last_file_size_max; << m_last_file_size_max;
} }

View File

@ -1583,7 +1583,7 @@ fts_drop_common_tables(
if (drop_orphan && err == DB_FAIL) { if (drop_orphan && err == DB_FAIL) {
char* path = fil_make_filepath( char* path = fil_make_filepath(
NULL, table_name, IBD, false); NULL, table_name_t{table_name}, IBD, false);
if (path != NULL) { if (path != NULL) {
os_file_delete_if_exists( os_file_delete_if_exists(
innodb_data_file_key, path, NULL); innodb_data_file_key, path, NULL);
@ -5652,17 +5652,18 @@ bool fts_check_aux_table(const char *name,
ut_ad(len <= MAX_FULL_NAME_LEN); ut_ad(len <= MAX_FULL_NAME_LEN);
ptr= static_cast<const char*>(memchr(name, '/', len)); ptr= static_cast<const char*>(memchr(name, '/', len));
IF_WIN(if (!ptr) ptr= static_cast<const char*>(memchr(name, '\\', len)), );
if (ptr != NULL) if (!ptr)
{ return false;
/* We will start the match after the '/' */
++ptr; /* We will start the match after the '/' */
len = end - ptr; ++ptr;
} len= end - ptr;
/* All auxiliary tables are prefixed with "FTS_" and the name /* All auxiliary tables are prefixed with "FTS_" and the name
length will be at the very least greater than 20 bytes. */ length will be at the very least greater than 20 bytes. */
if (ptr && len > 20 && !memcmp(ptr, "FTS_", 4)) if (len > 24 && !memcmp(ptr, "FTS_", 4))
{ {
/* Skip the prefix. */ /* Skip the prefix. */
ptr+= 4; ptr+= 4;
@ -5706,6 +5707,11 @@ bool fts_check_aux_table(const char *name,
ut_a(end > ptr); ut_a(end > ptr);
len= end - ptr; len= end - ptr;
if (len <= 4)
return false;
len-= 4; /* .ibd suffix */
if (len > 7) if (len > 7)
return false; return false;
@ -5740,8 +5746,9 @@ static void fil_get_fts_spaces(fts_space_set_t& fts_space_set)
index_id_t index_id= 0; index_id_t index_id= 0;
table_id_t table_id= 0; table_id_t table_id= 0;
if (space.purpose == FIL_TYPE_TABLESPACE if (space.purpose == FIL_TYPE_TABLESPACE && space.id &&
&& fts_check_aux_table(space.name, &table_id, &index_id)) space.chain.start &&
fts_check_aux_table(space.chain.start->name, &table_id, &index_id))
fts_space_set.insert(std::make_pair(table_id, index_id)); fts_space_set.insert(std::make_pair(table_id, index_id));
} }
@ -5823,17 +5830,14 @@ static void fts_drop_all_aux_tables(trx_t *trx, fts_table_t *fts_table)
fts_get_table_name(fts_table, fts_table_name, true); fts_get_table_name(fts_table, fts_table_name, true);
/* Drop all fts aux and common table */ /* Drop all fts aux and common table */
dberr_t err= fts_drop_table(trx, fts_table_name); if (fts_drop_table(trx, fts_table_name) != DB_FAIL)
continue;
if (err == DB_FAIL) if (char *path= fil_make_filepath(nullptr, table_name_t{fts_table_name},
IBD, false))
{ {
char *path= fil_make_filepath(NULL, fts_table_name, IBD, false); os_file_delete_if_exists(innodb_data_file_key, path, nullptr);
ut_free(path);
if (path != NULL)
{
os_file_delete_if_exists(innodb_data_file_key, path , NULL);
ut_free(path);
}
} }
} }
} }

View File

@ -758,7 +758,6 @@ innodb_tmpdir_validate(
return(1); return(1);
} }
os_normalize_path(alter_tmp_dir);
my_realpath(tmp_abs_path, alter_tmp_dir, 0); my_realpath(tmp_abs_path, alter_tmp_dir, 0);
size_t tmp_abs_len = strlen(tmp_abs_path); size_t tmp_abs_len = strlen(tmp_abs_path);
@ -3292,8 +3291,6 @@ static int innodb_init_params()
{ {
DBUG_ENTER("innodb_init_params"); DBUG_ENTER("innodb_init_params");
static char current_dir[3];
char *default_path;
ulong num_pll_degree; ulong num_pll_degree;
/* Check that values don't overflow on 32-bit systems. */ /* Check that values don't overflow on 32-bit systems. */
@ -3385,19 +3382,11 @@ static int innodb_init_params()
Note that when using the embedded server, the datadirectory is not Note that when using the embedded server, the datadirectory is not
necessarily the current directory of this program. */ necessarily the current directory of this program. */
if (mysqld_embedded) { fil_path_to_mysql_datadir =
default_path = mysql_real_data_home; #ifndef HAVE_REPLICATION
} else { mysqld_embedded ? mysql_real_data_home :
/* It's better to use current lib, to keep paths short */ #endif
current_dir[0] = FN_CURLIB; "./";
current_dir[1] = FN_LIBCHAR;
current_dir[2] = 0;
default_path = current_dir;
}
ut_a(default_path);
fil_path_to_mysql_datadir = default_path;
/* Set InnoDB initialization parameters according to the values /* Set InnoDB initialization parameters according to the values
read from MySQL .cnf file */ read from MySQL .cnf file */
@ -3405,7 +3394,8 @@ static int innodb_init_params()
/* The default dir for data files is the datadir of MySQL */ /* The default dir for data files is the datadir of MySQL */
srv_data_home = innobase_data_home_dir srv_data_home = innobase_data_home_dir
? innobase_data_home_dir : default_path; ? innobase_data_home_dir
: const_cast<char*>(fil_path_to_mysql_datadir);
#ifdef WITH_WSREP #ifdef WITH_WSREP
/* If we use the wsrep API, then we need to tell the server /* If we use the wsrep API, then we need to tell the server
the path to the data files (for passing it to the SST scripts): */ the path to the data files (for passing it to the SST scripts): */
@ -3437,7 +3427,6 @@ static int innodb_init_params()
srv_sys_space.set_flags(FSP_FLAGS_PAGE_SSIZE()); srv_sys_space.set_flags(FSP_FLAGS_PAGE_SSIZE());
} }
srv_sys_space.set_name("innodb_system");
srv_sys_space.set_path(srv_data_home); srv_sys_space.set_path(srv_data_home);
/* Supports raw devices */ /* Supports raw devices */
@ -3447,7 +3436,6 @@ static int innodb_init_params()
DBUG_RETURN(HA_ERR_INITIALIZATION); DBUG_RETURN(HA_ERR_INITIALIZATION);
} }
srv_tmp_space.set_name("innodb_temporary");
srv_tmp_space.set_path(srv_data_home); srv_tmp_space.set_path(srv_data_home);
/* Temporary tablespace is in full crc32 format. */ /* Temporary tablespace is in full crc32 format. */
@ -3462,8 +3450,8 @@ static int innodb_init_params()
/* Perform all sanity check before we take action of deleting files*/ /* Perform all sanity check before we take action of deleting files*/
if (srv_sys_space.intersection(&srv_tmp_space)) { if (srv_sys_space.intersection(&srv_tmp_space)) {
sql_print_error("%s and %s file names seem to be the same.", sql_print_error("innodb_temporary and innodb_system"
srv_tmp_space.name(), srv_sys_space.name()); " file names seem to be the same.");
DBUG_RETURN(HA_ERR_INITIALIZATION); DBUG_RETURN(HA_ERR_INITIALIZATION);
} }
@ -3472,11 +3460,9 @@ static int innodb_init_params()
/* ------------ UNDO tablespaces files ---------------------*/ /* ------------ UNDO tablespaces files ---------------------*/
if (!srv_undo_dir) { if (!srv_undo_dir) {
srv_undo_dir = default_path; srv_undo_dir = const_cast<char*>(fil_path_to_mysql_datadir);
} }
os_normalize_path(srv_undo_dir);
if (strchr(srv_undo_dir, ';')) { if (strchr(srv_undo_dir, ';')) {
sql_print_error("syntax error in innodb_undo_directory"); sql_print_error("syntax error in innodb_undo_directory");
DBUG_RETURN(HA_ERR_INITIALIZATION); DBUG_RETURN(HA_ERR_INITIALIZATION);
@ -3487,11 +3473,10 @@ static int innodb_init_params()
/* The default dir for log files is the datadir of MySQL */ /* The default dir for log files is the datadir of MySQL */
if (!srv_log_group_home_dir) { if (!srv_log_group_home_dir) {
srv_log_group_home_dir = default_path; srv_log_group_home_dir
= const_cast<char*>(fil_path_to_mysql_datadir);
} }
os_normalize_path(srv_log_group_home_dir);
if (strchr(srv_log_group_home_dir, ';')) { if (strchr(srv_log_group_home_dir, ';')) {
sql_print_error("syntax error in innodb_log_group_home_dir"); sql_print_error("syntax error in innodb_log_group_home_dir");
DBUG_RETURN(HA_ERR_INITIALIZATION); DBUG_RETURN(HA_ERR_INITIALIZATION);

View File

@ -6495,7 +6495,19 @@ static int i_s_sys_tablespaces_fill(THD *thd, const fil_space_t &s, TABLE *t)
Field **fields= t->field; Field **fields= t->field;
OK(fields[SYS_TABLESPACES_SPACE]->store(s.id, true)); OK(fields[SYS_TABLESPACES_SPACE]->store(s.id, true));
OK(field_store_string(fields[SYS_TABLESPACES_NAME], s.name)); {
Field *f= fields[SYS_TABLESPACES_NAME];
const auto name= s.name();
if (name.data())
{
OK(f->store(name.data(), name.size(), system_charset_info));
f->set_notnull();
}
else
f->set_notnull();
}
fields[SYS_TABLESPACES_NAME]->set_null();
OK(fields[SYS_TABLESPACES_FLAGS]->store(s.flags, true)); OK(fields[SYS_TABLESPACES_FLAGS]->store(s.flags, true));
OK(field_store_string(fields[SYS_TABLESPACES_ROW_FORMAT], row_format)); OK(field_store_string(fields[SYS_TABLESPACES_ROW_FORMAT], row_format));
const char *filepath= s.chain.start->name; const char *filepath= s.chain.start->name;
@ -6711,8 +6723,17 @@ i_s_dict_fill_tablespaces_encryption(
OK(fields[TABLESPACES_ENCRYPTION_SPACE]->store(space->id, true)); OK(fields[TABLESPACES_ENCRYPTION_SPACE]->store(space->id, true));
OK(field_store_string(fields[TABLESPACES_ENCRYPTION_NAME], {
space->name)); const auto name = space->name();
if (name.data()) {
OK(fields[TABLESPACES_ENCRYPTION_NAME]->store(
name.data(), name.size(),
system_charset_info));
fields[TABLESPACES_ENCRYPTION_NAME]->set_notnull();
} else {
fields[TABLESPACES_ENCRYPTION_NAME]->set_null();
}
}
OK(fields[TABLESPACES_ENCRYPTION_ENCRYPTION_SCHEME]->store( OK(fields[TABLESPACES_ENCRYPTION_ENCRYPTION_SCHEME]->store(
status.scheme, true)); status.scheme, true));

View File

@ -39,6 +39,7 @@ Created 10/25/1995 Heikki Tuuri
#include "log0recv.h" #include "log0recv.h"
#include "dict0types.h" #include "dict0types.h"
#include "ilist.h" #include "ilist.h"
#include "span.h"
#include <set> #include <set>
#include <mutex> #include <mutex>
@ -353,7 +354,6 @@ struct fil_space_t final
} }
ulint id; /*!< space id */ ulint id; /*!< space id */
hash_node_t hash; /*!< hash chain node */ hash_node_t hash; /*!< hash chain node */
char* name; /*!< Tablespace name */
lsn_t max_lsn; lsn_t max_lsn;
/*!< LSN of the most recent /*!< LSN of the most recent
fil_names_write_if_was_clean(). fil_names_write_if_was_clean().
@ -490,15 +490,14 @@ public:
n_reserved_extents -= n_reserved; n_reserved_extents -= n_reserved;
} }
/** Rename a file. /** Rename a file.
@param[in] name table name after renaming @param[in] path tablespace file name after renaming
@param[in] path tablespace file name after renaming @param[in] log whether to write redo log
@param[in] log whether to write redo log @param[in] replace whether to ignore the existence of path
@param[in] replace whether to ignore the existence of path @return error code
@return error code @retval DB_SUCCESS on success */
@retval DB_SUCCESS on success */ dberr_t rename(const char *path, bool log, bool replace= false)
dberr_t rename(const char* name, const char* path, bool log, MY_ATTRIBUTE((nonnull));
bool replace = false);
/** Note that the tablespace has been imported. /** Note that the tablespace has been imported.
Initially, purpose=FIL_TYPE_IMPORT so that no redo log is Initially, purpose=FIL_TYPE_IMPORT so that no redo log is
@ -908,7 +907,6 @@ public:
#ifndef UNIV_INNOCHECKSUM #ifndef UNIV_INNOCHECKSUM
MY_ATTRIBUTE((warn_unused_result)) MY_ATTRIBUTE((warn_unused_result))
/** Create a tablespace in fil_system. /** Create a tablespace in fil_system.
@param name tablespace name
@param id tablespace identifier @param id tablespace identifier
@param flags tablespace flags @param flags tablespace flags
@param purpose tablespace purpose @param purpose tablespace purpose
@ -916,7 +914,7 @@ public:
@param mode encryption mode @param mode encryption mode
@return pointer to created tablespace, to be filled in with add() @return pointer to created tablespace, to be filled in with add()
@retval nullptr on failure (such as when the same tablespace exists) */ @retval nullptr on failure (such as when the same tablespace exists) */
static fil_space_t *create(const char *name, ulint id, ulint flags, static fil_space_t *create(ulint id, ulint flags,
fil_type_t purpose, fil_space_crypt_t *crypt_data, fil_type_t purpose, fil_space_crypt_t *crypt_data,
fil_encryption_t mode= FIL_ENCRYPTION_DEFAULT); fil_encryption_t mode= FIL_ENCRYPTION_DEFAULT);
@ -1036,6 +1034,11 @@ public:
latch.rd_unlock(); latch.rd_unlock();
} }
typedef span<const char> name_type;
/** @return the tablespace name (databasename/tablename) */
name_type name() const;
private: private:
/** @return whether the file is usable for io() */ /** @return whether the file is usable for io() */
ATTRIBUTE_COLD bool prepare(bool have_mutex= false); ATTRIBUTE_COLD bool prepare(bool have_mutex= false);
@ -1592,15 +1595,15 @@ void fil_close_tablespace(ulint id);
Allocates and builds a file name from a path, a table or tablespace name Allocates and builds a file name from a path, a table or tablespace name
and a suffix. The string must be freed by caller with ut_free(). and a suffix. The string must be freed by caller with ut_free().
@param[in] path NULL or the directory path or the full path and filename. @param[in] path NULL or the directory path or the full path and filename.
@param[in] name NULL if path is full, or Table/Tablespace name @param[in] name {} if path is full, or Table/Tablespace name
@param[in] suffix NULL or the file extention to use. @param[in] ext the file extension to use
@param[in] trim_name true if the last name on the path should be trimmed.
@return own: file name */ @return own: file name */
char* char* fil_make_filepath(const char *path, const fil_space_t::name_type &name,
fil_make_filepath( ib_extention ext, bool trim_name);
const char* path,
const char* name, char *fil_make_filepath(const char* path, const table_name_t name,
ib_extention suffix, ib_extention ext, bool trim_name);
bool strip_name);
/** Create a tablespace file. /** Create a tablespace file.
@param[in] space_id Tablespace ID @param[in] space_id Tablespace ID
@ -1617,14 +1620,14 @@ must be >= FIL_IBD_FILE_INITIAL_SIZE
fil_space_t* fil_space_t*
fil_ibd_create( fil_ibd_create(
ulint space_id, ulint space_id,
const char* name, const table_name_t name,
const char* path, const char* path,
ulint flags, ulint flags,
uint32_t size, uint32_t size,
fil_encryption_t mode, fil_encryption_t mode,
uint32_t key_id, uint32_t key_id,
dberr_t* err) dberr_t* err)
MY_ATTRIBUTE((nonnull(2,8), warn_unused_result)); MY_ATTRIBUTE((nonnull, warn_unused_result));
/** Try to adjust FSP_SPACE_FLAGS if they differ from the expectations. /** Try to adjust FSP_SPACE_FLAGS if they differ from the expectations.
(Typically when upgrading from MariaDB 10.1.0..10.1.20.) (Typically when upgrading from MariaDB 10.1.0..10.1.20.)
@ -1668,7 +1671,7 @@ fil_ibd_open(
fil_type_t purpose, fil_type_t purpose,
ulint id, ulint id,
ulint flags, ulint flags,
const table_name_t& tablename, const table_name_t tablename,
const char* path_in, const char* path_in,
dberr_t* err = NULL) dberr_t* err = NULL)
MY_ATTRIBUTE((warn_unused_result)); MY_ATTRIBUTE((warn_unused_result));
@ -1716,15 +1719,10 @@ fil_file_readdir_next_file(
memory cache. Note that if we have not done a crash recovery at the database memory cache. Note that if we have not done a crash recovery at the database
startup, there may be many tablespaces which are not yet in the memory cache. startup, there may be many tablespaces which are not yet in the memory cache.
@param[in] id Tablespace ID @param[in] id Tablespace ID
@param[in] name Tablespace name used in fil_space_t::create().
@param[in] table_flags table flags @param[in] table_flags table flags
@return the tablespace @return the tablespace
@retval NULL if no matching tablespace exists in the memory cache */ @retval NULL if no matching tablespace exists in the memory cache */
fil_space_t* fil_space_t *fil_space_for_table_exists_in_mem(ulint id, ulint table_flags);
fil_space_for_table_exists_in_mem(
ulint id,
const char* name,
ulint table_flags);
/** Try to extend a tablespace if it is smaller than the specified size. /** Try to extend a tablespace if it is smaller than the specified size.
@param[in,out] space tablespace @param[in,out] space tablespace
@ -1755,26 +1753,6 @@ fil_delete_file(
/*============*/ /*============*/
const char* path); /*!< in: filepath of the ibd tablespace */ const char* path); /*!< in: filepath of the ibd tablespace */
/********************************************************************//**
Looks for a pre-existing fil_space_t with the given tablespace ID
and, if found, returns the name and filepath in newly allocated buffers that the caller must free.
@param[in] space_id The tablespace ID to search for.
@param[out] name Name of the tablespace found.
@param[out] fileapth The filepath of the first datafile for thtablespace found.
@return true if tablespace is found, false if not. */
bool
fil_space_read_name_and_filepath(
ulint space_id,
char** name,
char** filepath);
/** Convert a file name to a tablespace name.
@param[in] filename directory/databasename/tablename.ibd
@return database/tablename string, to be freed with ut_free() */
char*
fil_path_to_space_name(
const char* filename);
/*******************************************************************//** /*******************************************************************//**
Returns the table space by a given id, NULL if not found. */ Returns the table space by a given id, NULL if not found. */
fil_space_t* fil_space_t*

View File

@ -129,7 +129,8 @@ fil_page_type_validate(
/* Dump out the page info */ /* Dump out the page info */
ib::fatal() << "Page " << space_id << ":" << offset ib::fatal() << "Page " << space_id << ":" << offset
<< " name " << (space ? space->name : "???") << " name " << (space && space->chain.start
? space->chain.start->name : "???")
<< " page_type " << page_type << " page_type " << page_type
<< " key_version " << key_version << " key_version " << key_version
<< " lsn " << mach_read_from_8(page + FIL_PAGE_LSN) << " lsn " << mach_read_from_8(page + FIL_PAGE_LSN)

View File

@ -1,7 +1,7 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 2013, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2013, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2018, 2020, MariaDB Corporation. Copyright (c) 2018, 2021, 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
@ -49,7 +49,6 @@ public:
Datafile() Datafile()
: :
m_name(),
m_filepath(), m_filepath(),
m_filename(), m_filename(),
m_handle(), m_handle(),
@ -68,9 +67,8 @@ public:
/* No op */ /* No op */
} }
Datafile(const char* name, ulint flags, uint32_t size, ulint order) Datafile(ulint flags, uint32_t size, ulint order)
: :
m_name(mem_strdup(name)),
m_filepath(), m_filepath(),
m_filename(), m_filename(),
m_handle(), m_handle(),
@ -86,8 +84,6 @@ public:
m_last_os_error(), m_last_os_error(),
m_file_info() m_file_info()
{ {
ut_ad(m_name != NULL);
/* No op */
} }
Datafile(const Datafile& file) Datafile(const Datafile& file)
@ -105,9 +101,6 @@ public:
m_last_os_error(), m_last_os_error(),
m_file_info() m_file_info()
{ {
m_name = mem_strdup(file.m_name);
ut_ad(m_name != NULL);
if (file.m_filepath != NULL) { if (file.m_filepath != NULL) {
m_filepath = mem_strdup(file.m_filepath); m_filepath = mem_strdup(file.m_filepath);
ut_a(m_filepath != NULL); ut_a(m_filepath != NULL);
@ -127,10 +120,6 @@ public:
{ {
ut_a(this != &file); ut_a(this != &file);
ut_ad(m_name == NULL);
m_name = mem_strdup(file.m_name);
ut_a(m_name != NULL);
m_size = file.m_size; m_size = file.m_size;
m_order = file.m_order; m_order = file.m_order;
m_type = file.m_type; m_type = file.m_type;
@ -164,10 +153,8 @@ public:
return(*this); return(*this);
} }
/** Initialize the name and flags of this datafile. /** Initialize the tablespace flags */
@param[in] name tablespace name, will be copied void init(ulint flags) { m_flags= flags; }
@param[in] flags tablespace flags */
void init(const char* name, ulint flags);
/** Release the resources. */ /** Release the resources. */
virtual void shutdown(); virtual void shutdown();
@ -176,14 +163,12 @@ public:
so that it can be validated. so that it can be validated.
@param[in] strict whether to issue error messages @param[in] strict whether to issue error messages
@return DB_SUCCESS or error code */ @return DB_SUCCESS or error code */
virtual dberr_t open_read_only(bool strict); dberr_t open_read_only(bool strict);
/** Open a data file in read-write mode during start-up so that /** Open a data file in read-write mode during start-up so that
doublewrite pages can be restored and then it can be validated. 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 */ @return DB_SUCCESS or error code */
virtual dberr_t open_read_write(bool read_only_mode) inline dberr_t open_read_write()
MY_ATTRIBUTE((warn_unused_result)); MY_ATTRIBUTE((warn_unused_result));
/** Initialize OS specific file info. */ /** Initialize OS specific file info. */
@ -197,24 +182,15 @@ public:
Prepend the dirpath to filename using the extension given. Prepend the dirpath to filename using the extension given.
If dirpath is NULL, prepend the default datadir to filepath. If dirpath is NULL, prepend the default datadir to filepath.
Store the result in m_filepath. Store the result in m_filepath.
@param[in] dirpath directory path @param dirpath directory path
@param[in] filename filename or filepath @param name tablespace (table) name
@param[in] ext filename extension */ @param ext filename extension */
void make_filepath( void make_filepath(const char* dirpath, fil_space_t::name_type name,
const char* dirpath, ib_extention ext);
const char* filename,
ib_extention ext);
/** Set the filepath by duplicating the filepath sent in */ /** Set the filepath by duplicating the filepath sent in */
void set_filepath(const char* filepath); void set_filepath(const char* filepath);
/** 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 set_name(const char* name);
/** Validates the datafile and checks that it conforms with /** Validates the datafile and checks that it conforms with
the expected space ID and flags. The file should exist and be the expected space ID and flags. The file should exist and be
successfully opened in order for this function to validate it. successfully opened in order for this function to validate it.
@ -247,13 +223,6 @@ public:
dberr_t validate_first_page(lsn_t* flush_lsn) dberr_t validate_first_page(lsn_t* flush_lsn)
MY_ATTRIBUTE((warn_unused_result)); MY_ATTRIBUTE((warn_unused_result));
/** Get Datafile::m_name.
@return m_name */
const char* name() const
{
return(m_name);
}
/** Get Datafile::m_filepath. /** Get Datafile::m_filepath.
@return m_filepath */ @return m_filepath */
const char* filepath() const const char* filepath() const
@ -363,13 +332,22 @@ private:
in the filepath. */ in the filepath. */
void set_filename() void set_filename()
{ {
if (m_filepath == NULL) { if (!m_filepath) {
return; return;
} }
char* last_slash = strrchr(m_filepath, OS_PATH_SEPARATOR); if (char *last_slash = strrchr(m_filepath, '/')) {
#if _WIN32
m_filename = last_slash ? last_slash + 1 : m_filepath; if (char *last = strrchr(m_filepath, '\\')) {
if (last > last_slash) {
last_slash = last;
}
}
#endif
m_filename = last_slash + 1;
} else {
m_filename = m_filepath;
}
} }
/** Create/open a data file. /** Create/open a data file.
@ -406,12 +384,6 @@ private:
/* DATA MEMBERS */ /* DATA MEMBERS */
/** Datafile name at the tablespace location.
This is either the basename of the file if an absolute path
was entered, or it is the relative path to the datadir or
Tablespace::m_path. */
char* m_name;
protected: protected:
/** Physical file path with base name and extension */ /** Physical file path with base name and extension */
char* m_filepath; char* m_filepath;
@ -520,57 +492,28 @@ public:
return(m_link_filepath); return(m_link_filepath);
} }
/** Create a link filename based on the contents of m_name, /** Attempt to read the contents of an .isl file into m_filepath.
open that file, and read the contents into m_filepath. @param name table name
@retval DB_SUCCESS if remote linked tablespace file is opened and read. @return filepath()
@retval DB_CANNOT_OPEN_FILE if the link file does not exist. */ @retval nullptr if the .isl file does not exist or cannot be read */
dberr_t open_link_file(); const char* open_link_file(const table_name_t& name);
/** Delete an InnoDB Symbolic Link (ISL) file. */ /** Delete an InnoDB Symbolic Link (ISL) file. */
void delete_link_file(void); void delete_link_file(void);
/** Open 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 or error code */
dberr_t open_read_only(bool strict) override;
/** 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 or error code */
dberr_t open_read_write(bool read_only_mode) override
MY_ATTRIBUTE((warn_unused_result));
/****************************************************************** /******************************************************************
Global Static Functions; Cannot refer to data members. Global Static Functions; Cannot refer to data members.
******************************************************************/ ******************************************************************/
/** Creates a new InnoDB Symbolic Link (ISL) file. It is always /** Create InnoDB Symbolic Link (ISL) file.
created under the 'datadir' of MySQL. The datadir is the directory @param name tablespace name
of a running mysqld program. We can refer to it by simply using @param filepath full file name
the path ".".
@param[in] name tablespace name
@param[in] filepath remote filepath of tablespace datafile
@return DB_SUCCESS or error code */ @return DB_SUCCESS or error code */
static dberr_t create_link_file( static dberr_t create_link_file(fil_space_t::name_type name,
const char* name, const char *filepath);
const char* filepath);
/** Delete an InnoDB Symbolic Link (ISL) file by name. /** Delete an InnoDB Symbolic Link (ISL) file by name.
@param[in] name tablespace name */ @param name tablespace name */
static void delete_link_file(const char* name); static void delete_link_file(fil_space_t::name_type name);
/** 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 */
static char* read_link_file(
const char* link_filepath);
}; };
#endif /* fsp0file_h */ #endif /* fsp0file_h */

View File

@ -1,7 +1,7 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 2013, 2016, Oracle and/or its affiliates. All Rights Reserved. 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 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
@ -50,7 +50,6 @@ public:
Tablespace() Tablespace()
: :
m_files(), m_files(),
m_name(),
m_space_id(ULINT_UNDEFINED), m_space_id(ULINT_UNDEFINED),
m_path(), m_path(),
m_flags(), m_flags(),
@ -79,9 +78,6 @@ public:
/** Data file iterator */ /** Data file iterator */
iterator end() { return m_files.end(); } iterator end() { return m_files.end(); }
void set_name(const char* name) { m_name = name; }
const char* name() const { return m_name; }
/** Set tablespace path and filename members. /** Set tablespace path and filename members.
@param[in] path where tablespace file(s) resides @param[in] path where tablespace file(s) resides
@param[in] len length of the file path */ @param[in] len length of the file path */
@ -90,8 +86,6 @@ public:
ut_ad(m_path == NULL); ut_ad(m_path == NULL);
m_path = mem_strdupl(path, len); m_path = mem_strdupl(path, len);
ut_ad(m_path != NULL); ut_ad(m_path != NULL);
os_normalize_path(m_path);
} }
/** Set tablespace path and filename members. /** Set tablespace path and filename members.
@ -218,9 +212,6 @@ private:
/* DATA MEMBERS */ /* DATA MEMBERS */
/** Name of the tablespace. */
const char* m_name;
/** Tablespace ID */ /** Tablespace ID */
ulint m_space_id; ulint m_space_id;

View File

@ -1240,31 +1240,34 @@ os_file_punch_hole(
os_offset_t len) os_offset_t len)
MY_ATTRIBUTE((warn_unused_result)); MY_ATTRIBUTE((warn_unused_result));
/** Normalizes a directory path for the current OS:
On Windows, we convert '/' to '\', else we convert '\' to '/'.
@param[in,out] str A null-terminated directory and file path */
void os_normalize_path(char* str);
/* Determine if a path is an absolute path or not. /* Determine if a path is an absolute path or not.
@param[in] OS directory or file path to evaluate @param[in] OS directory or file path to evaluate
@retval true if an absolute path @retval true if an absolute path
@retval false if a relative path */ @retval false if a relative path */
UNIV_INLINE inline bool is_absolute_path(const char *path)
bool
is_absolute_path(
const char* path)
{ {
if (path[0] == OS_PATH_SEPARATOR) { switch (path[0]) {
return(true); #ifdef _WIN32
} case '\0':
return false;
case '\\':
#endif
case '/':
return true;
}
#ifdef _WIN32 #ifdef _WIN32
if (path[1] == ':' && path[2] == OS_PATH_SEPARATOR) { if (path[1] == ':')
return(true); {
} switch (path[2]) {
case '/':
case '\\':
return true;
}
}
#endif /* _WIN32 */ #endif /* _WIN32 */
return(false); return false;
} }
#include "os0file.ic" #include "os0file.ic"

View File

@ -531,22 +531,6 @@ it is read or written. */
/* Compile-time constant of the given array's size. */ /* Compile-time constant of the given array's size. */
#define UT_ARR_SIZE(a) (sizeof(a) / sizeof((a)[0])) #define UT_ARR_SIZE(a) (sizeof(a) / sizeof((a)[0]))
/* The return type from a thread's start function differs between Unix and
Windows, so define a typedef for it and a macro to use at the end of such
functions. */
#ifdef _WIN32
typedef DWORD os_thread_ret_t;
# define OS_THREAD_DUMMY_RETURN return(0)
# define OS_PATH_SEPARATOR '\\'
# define OS_PATH_SEPARATOR_ALT '/'
#else
typedef void* os_thread_ret_t;
# define OS_THREAD_DUMMY_RETURN return(NULL)
# define OS_PATH_SEPARATOR '/'
# define OS_PATH_SEPARATOR_ALT '\\'
#endif
#include <stdio.h> #include <stdio.h>
#include "db0err.h" #include "db0err.h"
#include "ut0dbg.h" #include "ut0dbg.h"

View File

@ -135,7 +135,7 @@ InnoDB:
#include "mysql/psi/psi_memory.h" /* PSI_memory_key, PSI_memory_info */ #include "mysql/psi/psi_memory.h" /* PSI_memory_key, PSI_memory_info */
#include "ut0ut.h" /* ut_strcmp_functor, ut_basename_noext() */ #include "ut0ut.h" /* ut_strcmp_functor */
#define OUT_OF_MEMORY_MSG \ #define OUT_OF_MEMORY_MSG \
"Check if you should increase the swap file or ulimits of your" \ "Check if you should increase the swap file or ulimits of your" \

View File

@ -1,7 +1,7 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2019, 2020, MariaDB Corporation. Copyright (c) 2019, 2021, 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
@ -276,25 +276,6 @@ ut_strerr(
#endif /* !UNIV_INNOCHECKSUM */ #endif /* !UNIV_INNOCHECKSUM */
#ifdef UNIV_PFS_MEMORY
/** Extract the basename of a file without its extension.
For example, extract "foo0bar" out of "/path/to/foo0bar.cc".
@param[in] file file path, e.g. "/path/to/foo0bar.cc"
@param[out] base result, e.g. "foo0bar"
@param[in] base_size size of the output buffer 'base', if there
is not enough space, then the result will be truncated, but always
'\0'-terminated
@return number of characters that would have been printed if the size
were unlimited (not including the final \0) */
size_t
ut_basename_noext(
const char* file,
char* base,
size_t base_size);
#endif /* UNIV_PFS_MEMORY */
namespace ib { namespace ib {
/** This is a wrapper class, used to print any unsigned integer type /** This is a wrapper class, used to print any unsigned integer type

View File

@ -4581,7 +4581,7 @@ static void lock_rec_block_validate(const page_id_t page_id)
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
ib::error() << "Lock rec block validate failed for tablespace " ib::error() << "Lock rec block validate failed for tablespace "
<< space->name << space->chain.start->name
<< page_id << " err " << err; << page_id << " err " << err;
} }

View File

@ -1306,11 +1306,15 @@ std::string get_log_file_path(const char *filename)
path.reserve(size); path.reserve(size);
path.assign(srv_log_group_home_dir); path.assign(srv_log_group_home_dir);
std::replace(path.begin(), path.end(), OS_PATH_SEPARATOR_ALT, switch (path.back()) {
OS_PATH_SEPARATOR); #ifdef _WIN32
case '\\':
if (path.back() != OS_PATH_SEPARATOR) #endif
path.push_back(OS_PATH_SEPARATOR); case '/':
break;
default:
path.push_back('/');
}
path.append(filename); path.append(filename);
return path; return path;

View File

@ -807,7 +807,6 @@ fil_name_process(char* name, ulint len, ulint space_id, bool deleted)
further checks can ensure that a FILE_MODIFY record was further checks can ensure that a FILE_MODIFY record was
scanned before applying any page records for the space_id. */ scanned before applying any page records for the space_id. */
os_normalize_path(name);
const file_name_t fname(std::string(name, len), deleted); const file_name_t fname(std::string(name, len), deleted);
std::pair<recv_spaces_t::iterator,bool> p = recv_spaces.emplace( std::pair<recv_spaces_t::iterator,bool> p = recv_spaces.emplace(
space_id, fname); space_id, fname);
@ -2853,22 +2852,8 @@ next_page:
} }
else else
{ {
size_t base= r.second.rfind(OS_PATH_SEPARATOR);
ut_ad(base != std::string::npos);
size_t start= r.second.rfind(OS_PATH_SEPARATOR, base - 1);
if (start == std::string::npos)
start= 0;
else
++start;
/* Keep only databasename/tablename without .ibd suffix */
std::string space_name(r.second, start, r.second.size() - start - 4);
ut_ad(space_name[base - start] == OS_PATH_SEPARATOR);
#if OS_PATH_SEPARATOR != '/'
space_name[base - start]= '/';
#endif
mysql_mutex_lock(&log_sys.mutex); mysql_mutex_lock(&log_sys.mutex);
if (dberr_t err= space->rename(space_name.c_str(), r.second.c_str(), if (dberr_t err= space->rename(r.second.c_str(), false))
false))
{ {
ib::error() << "Cannot replay rename of tablespace " << id ib::error() << "Cannot replay rename of tablespace " << id
<< " to '" << r.second << "': " << err; << " to '" << r.second << "': " << err;

View File

@ -425,36 +425,32 @@ responsibility to free the return value after it is no longer needed.
@param[in] old_path Pathname @param[in] old_path Pathname
@param[in] tablename Contains new base name @param[in] tablename Contains new base name
@return own: new full pathname */ @return own: new full pathname */
char* char *os_file_make_new_pathname(const char *old_path, const char *tablename)
os_file_make_new_pathname(
const char* old_path,
const char* tablename)
{ {
ulint dir_len; /* Split the tablename into its database and table name components.
char* last_slash; They are separated by a '/'. */
char* base_name; const char *last_slash= strrchr(tablename, '/');
char* new_path; const char *base_name= last_slash ? last_slash + 1 : tablename;
ulint new_path_len;
/* Split the tablename into its database and table name components. /* Find the offset of the last slash. We will strip off the
They are separated by a '/'. */ old basename.ibd which starts after that slash. */
last_slash = strrchr((char*) tablename, '/'); last_slash = strrchr(old_path, '/');
base_name = last_slash ? last_slash + 1 : (char*) tablename; #ifdef _WIN32
if (const char *last= strrchr(old_path, '\\'))
if (last > last_slash)
last_slash= last;
#endif
/* Find the offset of the last slash. We will strip off the size_t dir_len= last_slash
old basename.ibd which starts after that slash. */ ? size_t(last_slash - old_path)
last_slash = strrchr((char*) old_path, OS_PATH_SEPARATOR); : strlen(old_path);
dir_len = last_slash ? ulint(last_slash - old_path) : strlen(old_path);
/* allocate a new path and move the old directory path to it. */ /* allocate a new path and move the old directory path to it. */
new_path_len = dir_len + strlen(base_name) + sizeof "/.ibd"; size_t new_path_len= dir_len + strlen(base_name) + sizeof "/.ibd";
new_path = static_cast<char*>(ut_malloc_nokey(new_path_len)); char *new_path= static_cast<char*>(ut_malloc_nokey(new_path_len));
memcpy(new_path, old_path, dir_len); memcpy(new_path, old_path, dir_len);
snprintf(new_path + dir_len, new_path_len - dir_len, "/%s.ibd", base_name);
snprintf(new_path + dir_len, new_path_len - dir_len, return new_path;
"%c%s.ibd", OS_PATH_SEPARATOR, base_name);
return(new_path);
} }
/** This function reduces a null-terminated full remote path name into /** This function reduces a null-terminated full remote path name into
@ -474,7 +470,7 @@ os_file_make_data_dir_path(
char* data_dir_path) char* data_dir_path)
{ {
/* Replace the period before the extension with a null byte. */ /* Replace the period before the extension with a null byte. */
char* ptr = strrchr((char*) data_dir_path, '.'); char* ptr = strrchr(data_dir_path, '.');
if (ptr == NULL) { if (ptr == NULL) {
return; return;
@ -483,7 +479,8 @@ os_file_make_data_dir_path(
ptr[0] = '\0'; ptr[0] = '\0';
/* The tablename starts after the last slash. */ /* The tablename starts after the last slash. */
ptr = strrchr((char*) data_dir_path, OS_PATH_SEPARATOR); ptr = strrchr(data_dir_path, '/');
if (ptr == NULL) { if (ptr == NULL) {
return; return;
@ -494,7 +491,14 @@ os_file_make_data_dir_path(
char* tablename = ptr + 1; char* tablename = ptr + 1;
/* The databasename starts after the next to last slash. */ /* The databasename starts after the next to last slash. */
ptr = strrchr((char*) data_dir_path, OS_PATH_SEPARATOR); ptr = strrchr(data_dir_path, '/');
#ifdef _WIN32
if (char *aptr = strrchr(data_dir_path, '\\')) {
if (aptr > ptr) {
ptr = aptr;
}
}
#endif
if (ptr == NULL) { if (ptr == NULL) {
return; return;
@ -541,10 +545,16 @@ char*
os_file_get_parent_dir( os_file_get_parent_dir(
const char* path) const char* path)
{ {
bool has_trailing_slash = false;
/* Find the offset of the last slash */ /* Find the offset of the last slash */
const char* last_slash = strrchr(path, OS_PATH_SEPARATOR); const char* last_slash = strrchr(path, '/');
#ifdef _WIN32
if (const char *last = strrchr(path, '\\')) {
if (last > last_slash) {
last_slash = last;
}
}
#endif
if (!last_slash) { if (!last_slash) {
/* No slash in the path, return NULL */ /* No slash in the path, return NULL */
@ -552,13 +562,11 @@ os_file_get_parent_dir(
} }
/* Ok, there is a slash. Is there anything after it? */ /* Ok, there is a slash. Is there anything after it? */
if (static_cast<size_t>(last_slash - path + 1) == strlen(path)) { const bool has_trailing_slash = last_slash[1] == '\0';
has_trailing_slash = true;
}
/* Reduce repetative slashes. */ /* Reduce repetitive slashes. */
while (last_slash > path while (last_slash > path
&& last_slash[-1] == OS_PATH_SEPARATOR) { && (IF_WIN(last_slash[-1] == '\\' ||,) last_slash[-1] == '/')) {
last_slash--; last_slash--;
} }
@ -573,13 +581,15 @@ os_file_get_parent_dir(
/* Back up to the previous slash. */ /* Back up to the previous slash. */
last_slash--; last_slash--;
while (last_slash > path while (last_slash > path
&& last_slash[0] != OS_PATH_SEPARATOR) { && (IF_WIN(last_slash[0] != '\\' &&,)
last_slash[0] != '/')) {
last_slash--; last_slash--;
} }
/* Reduce repetative slashes. */ /* Reduce repetitive slashes. */
while (last_slash > path while (last_slash > path
&& last_slash[-1] == OS_PATH_SEPARATOR) { && (IF_WIN(last_slash[-1] == '\\' ||,)
last_slash[-1] == '/')) {
last_slash--; last_slash--;
} }
} }
@ -611,11 +621,6 @@ test_os_file_get_parent_dir(
char* expected = expected_dir == NULL ? NULL char* expected = expected_dir == NULL ? NULL
: mem_strdup(expected_dir); : mem_strdup(expected_dir);
/* os_file_get_parent_dir() assumes that separators are
converted to OS_PATH_SEPARATOR. */
os_normalize_path(child);
os_normalize_path(expected);
char* parent = os_file_get_parent_dir(child); char* parent = os_file_get_parent_dir(child);
bool unexpected = (expected == NULL bool unexpected = (expected == NULL
@ -4583,23 +4588,4 @@ invalid:
space->free_len = free_len; space->free_len = free_len;
return true; return true;
} }
#else
#include "univ.i"
#endif /* !UNIV_INNOCHECKSUM */ #endif /* !UNIV_INNOCHECKSUM */
/** Normalizes a directory path for the current OS:
On Windows, we convert '/' to '\', else we convert '\' to '/'.
@param[in,out] str A null-terminated directory and file path */
void
os_normalize_path(
char* str)
{
if (str != NULL) {
for (; *str; str++) {
if (*str == OS_PATH_SEPARATOR_ALT) {
*str = OS_PATH_SEPARATOR;
}
}
}
}

View File

@ -3761,16 +3761,15 @@ fil_tablespace_iterate(
/* Make sure the data_dir_path is set. */ /* 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, false);
if (DICT_TF_HAS_DATA_DIR(table->flags)) { ut_ad(!DICT_TF_HAS_DATA_DIR(table->flags) || table->data_dir_path);
ut_a(table->data_dir_path);
filepath = fil_make_filepath( const char *data_dir_path = DICT_TF_HAS_DATA_DIR(table->flags)
table->data_dir_path, table->name.m_name, IBD, true); ? table->data_dir_path : nullptr;
} else {
filepath = fil_make_filepath(
NULL, table->name.m_name, IBD, false);
}
filepath = fil_make_filepath(data_dir_path,
{table->name.m_name,
strlen(table->name.m_name)},
IBD, data_dir_path != nullptr);
if (!filepath) { if (!filepath) {
return(DB_OUT_OF_MEMORY); return(DB_OUT_OF_MEMORY);
} else { } else {
@ -4095,16 +4094,10 @@ row_import_for_mysql(
dict_get_and_save_data_dir_path(table, true); dict_get_and_save_data_dir_path(table, true);
ut_ad(!DICT_TF_HAS_DATA_DIR(table->flags) || table->data_dir_path); 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)
if (DICT_TF_HAS_DATA_DIR(table->flags)) { ? table->data_dir_path : nullptr;
ut_a(table->data_dir_path); filepath = fil_make_filepath(data_dir_path, table->name, IBD,
data_dir_path != nullptr);
filepath = fil_make_filepath(
table->data_dir_path, table->name.m_name, IBD, true);
} else {
filepath = fil_make_filepath(
NULL, table->name.m_name, IBD, false);
}
DBUG_EXECUTE_IF( DBUG_EXECUTE_IF(
"ib_import_OOM_15", "ib_import_OOM_15",

View File

@ -3359,7 +3359,9 @@ row_drop_table_for_mysql(
if (table->space != fil_system.sys_space) { if (table->space != fil_system.sys_space) {
/* Delete the link file if used. */ /* Delete the link file if used. */
if (DICT_TF_HAS_DATA_DIR(table->flags)) { if (DICT_TF_HAS_DATA_DIR(table->flags)) {
RemoteDatafile::delete_link_file(name); RemoteDatafile::delete_link_file(
{table->name.m_name,
strlen(table->name.m_name)});
} }
} }
@ -3648,15 +3650,14 @@ do_drop:
if (DICT_TF_HAS_DATA_DIR(table->flags)) { if (DICT_TF_HAS_DATA_DIR(table->flags)) {
dict_get_and_save_data_dir_path(table, true); dict_get_and_save_data_dir_path(table, true);
ut_ad(table->data_dir_path || !space); ut_ad(table->data_dir_path || !space);
filepath = space ? NULL : fil_make_filepath(
table->data_dir_path,
table->name.m_name, IBD,
table->data_dir_path != NULL);
} else {
filepath = space ? NULL : fil_make_filepath(
NULL, table->name.m_name, IBD, false);
} }
filepath = space
? nullptr
: fil_make_filepath(table->data_dir_path, table->name,
IBD,
table->data_dir_path != nullptr);
/* Free the dict_table_t object. */ /* Free the dict_table_t object. */
err = row_drop_table_from_cache(tablename, table, trx); err = row_drop_table_from_cache(tablename, table, trx);
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {

View File

@ -479,15 +479,12 @@ static ulint trx_rseg_get_n_undo_tablespaces()
static ulint srv_undo_tablespace_open(bool create, const char* name, ulint i) static ulint srv_undo_tablespace_open(bool create, const char* name, ulint i)
{ {
bool success; bool success;
char undo_name[sizeof "innodb_undo000"];
ulint space_id= 0; ulint space_id= 0;
ulint fsp_flags= 0; ulint fsp_flags= 0;
if (create) if (create)
{ {
space_id= srv_undo_space_id_start + i; space_id= srv_undo_space_id_start + i;
snprintf(undo_name, sizeof(undo_name),
"innodb_undo%03u", static_cast<unsigned>(space_id));
switch (srv_checksum_algorithm) { switch (srv_checksum_algorithm) {
case SRV_CHECKSUM_ALGORITHM_FULL_CRC32: case SRV_CHECKSUM_ALGORITHM_FULL_CRC32:
case SRV_CHECKSUM_ALGORITHM_STRICT_FULL_CRC32: case SRV_CHECKSUM_ALGORITHM_STRICT_FULL_CRC32:
@ -542,7 +539,6 @@ err_exit:
} }
space_id= id; space_id= id;
snprintf(undo_name, sizeof undo_name, "innodb_undo%03u", id);
aligned_free(page); aligned_free(page);
} }
@ -554,7 +550,7 @@ err_exit:
fil_set_max_space_id_if_bigger(space_id); fil_set_max_space_id_if_bigger(space_id);
fil_space_t *space= fil_space_t::create(undo_name, space_id, fsp_flags, fil_space_t *space= fil_space_t::create(space_id, fsp_flags,
FIL_TYPE_TABLESPACE, NULL); FIL_TYPE_TABLESPACE, NULL);
ut_a(fil_validate()); ut_a(fil_validate());
ut_a(space); ut_a(space);
@ -594,11 +590,7 @@ srv_check_undo_redo_logs_exists()
/* Check if any undo tablespaces exist */ /* Check if any undo tablespaces exist */
for (ulint i = 1; i <= srv_undo_tablespaces; ++i) { for (ulint i = 1; i <= srv_undo_tablespaces; ++i) {
snprintf( snprintf(name, sizeof name, "%s/undo%03zu", srv_undo_dir, i);
name, sizeof(name),
"%s%cundo%03zu",
srv_undo_dir, OS_PATH_SEPARATOR,
i);
fh = os_file_create( fh = os_file_create(
innodb_data_file_key, name, innodb_data_file_key, name,
@ -656,8 +648,7 @@ static dberr_t srv_all_undo_tablespaces_open(bool create_new_db, ulint n_undo)
for (ulint i= 0; i < n_undo; ++i) for (ulint i= 0; i < n_undo; ++i)
{ {
char name[OS_FILE_MAX_PATH]; char name[OS_FILE_MAX_PATH];
snprintf(name, sizeof name, "%s%cundo%03zu", srv_undo_dir, snprintf(name, sizeof name, "%s/undo%03zu", srv_undo_dir, i + 1);
OS_PATH_SEPARATOR, i + 1);
ulint space_id= srv_undo_tablespace_open(create_new_db, name, i); ulint space_id= srv_undo_tablespace_open(create_new_db, name, i);
if (!space_id) if (!space_id)
{ {
@ -687,8 +678,7 @@ static dberr_t srv_all_undo_tablespaces_open(bool create_new_db, ulint n_undo)
++i) ++i)
{ {
char name[OS_FILE_MAX_PATH]; char name[OS_FILE_MAX_PATH];
snprintf(name, sizeof(name), snprintf(name, sizeof name, "%s/undo%03zu", srv_undo_dir, i);
"%s%cundo%03zu", srv_undo_dir, OS_PATH_SEPARATOR, i);
if (!srv_undo_tablespace_open(create_new_db, name, i)) if (!srv_undo_tablespace_open(create_new_db, name, i))
break; break;
++srv_undo_tablespaces_open; ++srv_undo_tablespaces_open;
@ -722,8 +712,7 @@ srv_undo_tablespaces_init(bool create_new_db)
for (ulint i= 0; i < srv_undo_tablespaces; ++i) for (ulint i= 0; i < srv_undo_tablespaces; ++i)
{ {
char name[OS_FILE_MAX_PATH]; char name[OS_FILE_MAX_PATH];
snprintf(name, sizeof name, "%s%cundo%03zu", snprintf(name, sizeof name, "%s/undo%03zu", srv_undo_dir, i + 1);
srv_undo_dir, OS_PATH_SEPARATOR, i + 1);
if (dberr_t err= srv_undo_tablespace_create(name)) if (dberr_t err= srv_undo_tablespace_create(name))
{ {
ib::error() << "Could not create undo tablespace '" << name << "'."; ib::error() << "Could not create undo tablespace '" << name << "'.";
@ -2106,15 +2095,12 @@ srv_get_meta_data_filename(
/* Make sure the data_dir_path is set. */ /* 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, false);
if (DICT_TF_HAS_DATA_DIR(table->flags)) { const char* data_dir_path = DICT_TF_HAS_DATA_DIR(table->flags)
ut_a(table->data_dir_path); ? table->data_dir_path : nullptr;
ut_ad(!DICT_TF_HAS_DATA_DIR(table->flags) || data_dir_path);
path = fil_make_filepath(
table->data_dir_path, table->name.m_name, CFG, true);
} else {
path = fil_make_filepath(NULL, table->name.m_name, CFG, false);
}
path = fil_make_filepath(data_dir_path, table->name, CFG,
data_dir_path != nullptr);
ut_a(path); ut_a(path);
len = strlen(path); len = strlen(path);
ut_a(max_len >= len); ut_a(max_len >= len);

View File

@ -482,57 +482,6 @@ ut_strerr(
return("Unknown error"); return("Unknown error");
} }
#ifdef UNIV_PFS_MEMORY
/** Extract the basename of a file without its extension.
For example, extract "foo0bar" out of "/path/to/foo0bar.cc".
@param[in] file file path, e.g. "/path/to/foo0bar.cc"
@param[out] base result, e.g. "foo0bar"
@param[in] base_size size of the output buffer 'base', if there
is not enough space, then the result will be truncated, but always
'\0'-terminated
@return number of characters that would have been printed if the size
were unlimited (not including the final \0) */
size_t
ut_basename_noext(
const char* file,
char* base,
size_t base_size)
{
/* Assuming 'file' contains something like the following,
extract the file name without the extenstion out of it by
setting 'beg' and 'len'.
...mysql-trunk/storage/innobase/dict/dict0dict.cc:302
^-- beg, len=9
*/
const char* beg = strrchr(file, OS_PATH_SEPARATOR);
if (beg == NULL) {
beg = file;
} else {
beg++;
}
size_t len = strlen(beg);
const char* end = strrchr(beg, '.');
if (end != NULL) {
len = end - beg;
}
const size_t copy_len = std::min(len, base_size - 1);
memcpy(base, beg, copy_len);
base[copy_len] = '\0';
return(len);
}
#endif /* UNIV_PFS_MEMORY */
namespace ib { namespace ib {
ATTRIBUTE_COLD logger& logger::operator<<(dberr_t err) ATTRIBUTE_COLD logger& logger::operator<<(dberr_t err)