MDEV-17849 Undo tablespace truncation recovery fails to shrink file

fil_space_t::add(): Replaces fil_node_create(), fil_node_create_low().
Let the caller pass fil_node_t::handle, to avoid having to close and
re-open files.

fil_node_t::read_page0(): Refactored from fil_node_open_file().
Read the first page of a data file.

fil_node_open_file(): Open the file only once.

srv_undo_tablespace_open(): Set the file handle for the opened
undo tablespace. This should ensure that ut_ad(file->is_open())
no longer fails in recv_add_trim().

xtrabackup_backup_func(): Remove some dead code.

xb_fil_cur_open(): Open files only if needed. Undo tablespaces
should already have been opened.
This commit is contained in:
Marko Mäkelä 2018-11-27 14:49:20 +02:00
parent eb6364619f
commit e82e216e37
7 changed files with 253 additions and 387 deletions

View file

@ -159,8 +159,11 @@ xb_fil_cur_open(
/* In the backup mode we should already have a tablespace handle created
by fil_ibd_load() unless it is a system
tablespace. Otherwise we open the file here. */
if (cursor->is_system() || srv_operation == SRV_OPERATION_RESTORE_DELTA
|| xb_close_files) {
if (!node->is_open()) {
ut_ad(cursor->is_system()
|| srv_operation == SRV_OPERATION_RESTORE_DELTA
|| xb_close_files);
node->handle = os_file_create_simple_no_error_handling(
0, node->name,
OS_FILE_OPEN,

View file

@ -3101,11 +3101,8 @@ xb_load_single_table_tablespace(
ut_a(space != NULL);
if (!fil_node_create(file->filepath(), ulint(n_pages), space,
false, false)) {
ut_error;
}
space->add(file->filepath(), OS_FILE_CLOSED, ulint(n_pages),
false, false);
/* by opening the tablespace we forcing node and space objects
in the cache to be populated with fields from space header */
fil_space_open(space->name);
@ -3781,22 +3778,17 @@ xb_filters_free()
}
/*********************************************************************//**
Creates or opens the log files and closes them.
@return DB_SUCCESS or error code */
Create log file metadata. */
static
ulint
void
open_or_create_log_file(
/*====================*/
fil_space_t* space,
ibool* log_file_created, /*!< out: TRUE if new log file
created */
ulint i) /*!< in: log file number in group */
{
char name[10000];
ulint dirnamelen;
*log_file_created = FALSE;
os_normalize_path(srv_log_group_home_dir);
dirnamelen = strlen(srv_log_group_home_dir);
@ -3808,14 +3800,13 @@ open_or_create_log_file(
name[dirnamelen++] = OS_PATH_SEPARATOR;
}
sprintf(name + dirnamelen, "%s%lu", "ib_logfile", (ulong) i);
sprintf(name + dirnamelen, "%s%zu", "ib_logfile", i);
ut_a(fil_validate());
ut_a(fil_node_create(name, ulint(srv_log_file_size >> srv_page_size_shift),
space, false, false));
return(DB_SUCCESS);
space->add(name, OS_FILE_CLOSED,
ulint(srv_log_file_size >> srv_page_size_shift),
false, false);
}
/*********************************************************************//**
@ -4124,13 +4115,6 @@ fail:
xb_filters_init();
{
ibool log_file_created;
ibool log_created = FALSE;
ibool log_opened = FALSE;
ulint err;
ulint i;
xb_fil_io_init();
srv_n_file_io_threads = srv_n_read_io_threads;
@ -4145,36 +4129,8 @@ fail:
lock_sys_create(srv_lock_table_size);
for (i = 0; i < srv_n_log_files; i++) {
err = open_or_create_log_file(space, &log_file_created, i);
if (err != DB_SUCCESS) {
goto fail;
}
if (log_file_created) {
log_created = TRUE;
} else {
log_opened = TRUE;
}
if ((log_opened && log_created)) {
msg(
"mariabackup: Error: all log files must be created at the same time.\n"
"mariabackup: All log files must be created also in database creation.\n"
"mariabackup: If you want bigger or smaller log files, shut down the\n"
"mariabackup: database and make sure there were no errors in shutdown.\n"
"mariabackup: Then delete the existing log files. Edit the .cnf file\n"
"mariabackup: and start the database again.\n");
goto fail;
}
}
/* log_file_created must not be TRUE, if online */
if (log_file_created) {
msg("mariabackup: Something wrong with source files...\n");
goto fail;
}
for (ulint i = 0; i < srv_n_log_files; i++) {
open_or_create_log_file(space, i);
}
/* create extra LSN dir if it does not exist. */

View file

@ -465,36 +465,25 @@ fil_space_is_flushed(
/** Append a file to the chain of files of a space.
@param[in] name file name of a file that is not open
@param[in] size file size in entire database blocks
@param[in,out] space tablespace from fil_space_create()
@param[in] is_raw whether this is a raw device or partition
@param[in] atomic_write true if the file could use atomic write
@param[in] handle file handle, or OS_FILE_CLOSED
@param[in] size file size in entire database pages
@param[in] is_raw whether this is a raw device
@param[in] atomic_write true if atomic write could be enabled
@param[in] max_pages maximum number of pages in file,
ULINT_MAX means the file size is unlimited.
@return pointer to the file name
@retval NULL if error */
static
fil_node_t*
fil_node_create_low(
const char* name,
ulint size,
fil_space_t* space,
bool is_raw,
bool atomic_write,
ulint max_pages = ULINT_MAX)
or ULINT_MAX for unlimited
@return file object */
fil_node_t* fil_space_t::add(const char* name, pfs_os_file_t handle,
ulint size, bool is_raw, bool atomic_write,
ulint max_pages)
{
fil_node_t* node;
ut_ad(name != NULL);
ut_ad(fil_system != NULL);
if (space == NULL) {
return(NULL);
}
node = reinterpret_cast<fil_node_t*>(ut_zalloc_nokey(sizeof(*node)));
node->handle = OS_FILE_CLOSED;
node->handle = handle;
node->name = mem_strdup(name);
@ -511,56 +500,116 @@ fil_node_create_low(
node->init_size = size;
node->max_size = max_pages;
mutex_enter(&fil_system->mutex);
space->size += size;
node->space = space;
node->space = this;
node->atomic_write = atomic_write;
UT_LIST_ADD_LAST(space->chain, node);
mutex_enter(&fil_system->mutex);
this->size += size;
UT_LIST_ADD_LAST(chain, node);
if (node->is_open()) {
fil_system->n_open++;
}
mutex_exit(&fil_system->mutex);
return(node);
return node;
}
/** Appends a new file to the chain of files of a space. File must be closed.
@param[in] name file name (file must be closed)
@param[in] size file size in database blocks, rounded downwards to
an integer
@param[in,out] space space where to append
@param[in] is_raw true if a raw device or a raw disk partition
@param[in] atomic_write true if the file could use atomic write
@param[in] max_pages maximum number of pages in file,
ULINT_MAX means the file size is unlimited.
@return pointer to the file name
@retval NULL if error */
char*
fil_node_create(
const char* name,
ulint size,
fil_space_t* space,
bool is_raw,
bool atomic_write,
ulint max_pages)
/** Read the first page of a data file.
@param[in] first whether this is the very first read
@return whether the page was found valid */
bool fil_node_t::read_page0(bool first)
{
fil_node_t* node;
ut_ad(mutex_own(&fil_system->mutex));
ut_a(space->purpose != FIL_TYPE_LOG);
const page_size_t page_size(space->flags);
const ulint psize = page_size.physical();
node = fil_node_create_low(
name, size, space, is_raw, atomic_write, max_pages);
os_offset_t size_bytes = os_file_get_size(handle);
ut_a(size_bytes != (os_offset_t) -1);
const ulint min_size = FIL_IBD_FILE_INITIAL_SIZE * psize;
return(node == NULL ? NULL : node->name);
if (size_bytes < min_size) {
ib::error() << "The size of the file " << name
<< " is only " << size_bytes
<< " bytes, should be at least " << min_size;
return false;
}
byte* buf2 = static_cast<byte*>(ut_malloc_nokey(2 * psize));
/* Align the memory for file i/o if we might have O_DIRECT set */
byte* page = static_cast<byte*>(ut_align(buf2, psize));
IORequest request(IORequest::READ);
if (!os_file_read(request, handle, page, 0, psize)) {
ib::error() << "Unable to read first page of file " << name;
ut_free(buf2);
return false;
}
srv_stats.page0_read.add(1);
const ulint space_id = fsp_header_get_space_id(page);
ulint flags = fsp_header_get_flags(page);
const ulint size = fsp_header_get_field(page, FSP_SIZE);
const ulint free_limit = fsp_header_get_field(page, FSP_FREE_LIMIT);
const ulint free_len = flst_get_len(FSP_HEADER_OFFSET + FSP_FREE
+ page);
/* Try to read crypt_data from page 0 if it is not yet read. */
if (!space->crypt_data) {
space->crypt_data = fil_space_read_crypt_data(page_size, page);
}
ut_free(buf2);
if (!fsp_flags_is_valid(flags, space->id)) {
ulint cflags = fsp_flags_convert_from_101(flags);
if (cflags == ULINT_UNDEFINED
|| (cflags ^ space->flags) & ~FSP_FLAGS_MEM_MASK) {
ib::error()
<< "Expected tablespace flags "
<< ib::hex(space->flags)
<< " but found " << ib::hex(flags)
<< " in the file " << name;
return false;
}
flags = cflags;
}
if (UNIV_UNLIKELY(space_id != space->id)) {
ib::error() << "Expected tablespace id " << space->id
<< " but found " << space_id
<< " in the file " << name;
return false;
}
ut_ad(space->free_limit == 0 || space->free_limit == free_limit);
ut_ad(space->free_len == 0 || space->free_len == free_len);
space->size_in_header = size;
space->free_limit = free_limit;
space->free_len = free_len;
if (first) {
/* Truncate the size to a multiple of extent size. */
ulint mask = psize * FSP_EXTENT_SIZE - 1;
if (size_bytes <= mask) {
/* .ibd files start smaller than an
extent size. Do not truncate valid data. */
} else {
size_bytes &= ~os_offset_t(mask);
}
this->size = ulint(size_bytes / psize);
space->size += this->size;
}
return true;
}
/** Open a file node of a tablespace.
The caller must own the fil_system mutex.
@param[in,out] node File node
@return false if the file can't be opened, otherwise true */
static
bool
fil_node_open_file(
fil_node_t* node)
static bool fil_node_open_file(fil_node_t* node)
{
bool success;
bool read_only_mode;
@ -588,9 +637,12 @@ fil_node_open_file(
from a file opened for async I/O! */
retry:
node->handle = os_file_create_simple_no_error_handling(
innodb_data_file_key, node->name, OS_FILE_OPEN,
OS_FILE_READ_ONLY, read_only_mode, &success);
node->handle = os_file_create(
innodb_data_file_key, node->name,
node->is_raw_disk
? OS_FILE_OPEN_RAW | OS_FILE_ON_ERROR_NO_EXIT
: OS_FILE_OPEN | OS_FILE_ON_ERROR_NO_EXIT,
OS_FILE_AIO, OS_DATA_FILE, read_only_mode, &success);
if (!success) {
/* The following call prints an error message */
@ -606,150 +658,47 @@ retry:
return(false);
}
os_offset_t size_bytes = os_file_get_size(node->handle);
ut_a(size_bytes != (os_offset_t) -1);
ut_a(space->purpose != FIL_TYPE_LOG);
const page_size_t page_size(space->flags);
const ulint psize = page_size.physical();
const ulint min_size = FIL_IBD_FILE_INITIAL_SIZE
* psize;
if (size_bytes < min_size) {
ib::error() << "The size of the file " << node->name
<< " is only " << size_bytes
<< " bytes, should be at least " << min_size;
if (!node->read_page0(first_time_open)) {
os_file_close(node->handle);
node->handle = OS_FILE_CLOSED;
return(false);
return false;
}
/* Read the first page of the tablespace */
byte* buf2 = static_cast<byte*>(ut_malloc_nokey(2 * psize));
/* Align the memory for file i/o if we might have O_DIRECT
set */
byte* page = static_cast<byte*>(ut_align(buf2, psize));
IORequest request(IORequest::READ);
success = os_file_read(
request,
node->handle, page, 0, psize);
srv_stats.page0_read.add(1);
const ulint space_id
= fsp_header_get_space_id(page);
ulint flags = fsp_header_get_flags(page);
const ulint size = fsp_header_get_field(
page, FSP_SIZE);
const ulint free_limit = fsp_header_get_field(
page, FSP_FREE_LIMIT);
const ulint free_len = flst_get_len(
FSP_HEADER_OFFSET + FSP_FREE + page);
/* Try to read crypt_data from page 0 if it is not yet
read. */
if (!space->crypt_data) {
space->crypt_data = fil_space_read_crypt_data(
page_size_t(space->flags), page);
}
ut_free(buf2);
os_file_close(node->handle);
node->handle = OS_FILE_CLOSED;
if (!fsp_flags_is_valid(flags, space->id)) {
ulint cflags = fsp_flags_convert_from_101(flags);
if (cflags == ULINT_UNDEFINED
|| (cflags ^ space->flags) & ~FSP_FLAGS_MEM_MASK) {
ib::error()
<< "Expected tablespace flags "
<< ib::hex(space->flags)
<< " but found " << ib::hex(flags)
<< " in the file " << node->name;
return(false);
}
flags = cflags;
}
if (UNIV_UNLIKELY(space_id != space->id)) {
ib::error()
<< "Expected tablespace id " << space->id
<< " but found " << space_id
<< " in the file" << node->name;
return(false);
}
ut_ad(space->free_limit == 0
|| space->free_limit == free_limit);
ut_ad(space->free_len == 0
|| space->free_len == free_len);
space->size_in_header = size;
space->free_limit = free_limit;
space->free_len = free_len;
if (first_time_open) {
/* Truncate the size to a multiple of extent size. */
ulint mask = psize * FSP_EXTENT_SIZE - 1;
if (size_bytes <= mask) {
/* .ibd files start smaller than an
extent size. Do not truncate valid data. */
} else {
size_bytes &= ~os_offset_t(mask);
}
node->size = ulint(size_bytes / psize);
space->size += node->size;
}
}
/* printf("Opening file %s\n", node->name); */
/* Open the file for reading and writing, in Windows normally in the
unbuffered async I/O mode, though global variables may make
os_file_create() to fall back to the normal file I/O mode. */
if (space->purpose == FIL_TYPE_LOG) {
} else if (space->purpose == FIL_TYPE_LOG) {
node->handle = os_file_create(
innodb_log_file_key, node->name, OS_FILE_OPEN,
OS_FILE_AIO, OS_LOG_FILE, read_only_mode, &success);
} else if (node->is_raw_disk) {
node->handle = os_file_create(
innodb_data_file_key, node->name, OS_FILE_OPEN_RAW,
OS_FILE_AIO, OS_DATA_FILE, read_only_mode, &success);
} else {
node->handle = os_file_create(
innodb_data_file_key, node->name, OS_FILE_OPEN,
innodb_data_file_key, node->name,
node->is_raw_disk
? OS_FILE_OPEN_RAW | OS_FILE_ON_ERROR_NO_EXIT
: OS_FILE_OPEN | OS_FILE_ON_ERROR_NO_EXIT,
OS_FILE_AIO, OS_DATA_FILE, read_only_mode, &success);
}
if (first_time_open) {
/*
For the temporary tablespace and during the
non-redo-logged adjustments in
IMPORT TABLESPACE, we do not care about
the atomicity of writes.
if (space->purpose != FIL_TYPE_LOG) {
/*
For the temporary tablespace and during the
non-redo-logged adjustments in
IMPORT TABLESPACE, we do not care about
the atomicity of writes.
Atomic writes is supported if the file can be used
with atomic_writes (not log file), O_DIRECT is
used (tested in ha_innodb.cc) and the file is
device and file system that supports atomic writes
for the given block size
*/
space->atomic_write_supported
= space->purpose == FIL_TYPE_TEMPORARY
|| space->purpose == FIL_TYPE_IMPORT
|| (node->atomic_write
&& srv_use_atomic_writes
&& my_test_if_atomic_write(
node->handle,
int(page_size_t(space->flags)
.physical())));
}
}
Atomic writes is supported if the file can be used
with atomic_writes (not log file), O_DIRECT is
used (tested in ha_innodb.cc) and the file is
device and file system that supports atomic writes
for the given block size
*/
space->atomic_write_supported
= space->purpose == FIL_TYPE_TEMPORARY
|| space->purpose == FIL_TYPE_IMPORT
|| (node->atomic_write
&& srv_use_atomic_writes
&& my_test_if_atomic_write(
node->handle,
int(page_size_t(space->flags)
.physical())));
}
ut_a(success);
ut_a(node->is_open());
@ -1430,7 +1379,7 @@ Error messages are issued to the server log.
@param[in] purpose tablespace purpose
@param[in,out] crypt_data encryption information
@param[in] mode encryption mode
@return pointer to created tablespace, to be filled in with fil_node_create()
@return pointer to created tablespace, to be filled in with fil_space_t::add()
@retval NULL on failure (such as when the same tablespace exists) */
fil_space_t*
fil_space_create(
@ -1519,7 +1468,7 @@ fil_space_create(
if (space->purpose == FIL_TYPE_TEMPORARY) {
ut_d(space->latch.set_temp_fsp());
/* SysTablespace::open_or_create() would pass
size!=0 to fil_node_create(), so first_time_open
size!=0 to fil_space_t::add(), so first_time_open
would not hold in fil_node_open_file(), and we
must assign this manually. We do not care about
the durability or atomicity of writes to the
@ -3819,22 +3768,16 @@ fil_ibd_create(
space = fil_space_create(name, space_id, flags, FIL_TYPE_TABLESPACE,
crypt_data, mode);
fil_node_t* node = NULL;
if (space) {
node = fil_node_create_low(path, size, space, false, true);
}
if (!space || !node) {
if (!space) {
if (crypt_data) {
free(crypt_data);
}
err = DB_ERROR;
} else {
mtr_t mtr;
const fil_node_t* file = UT_LIST_GET_FIRST(space->chain);
mtr_t mtr;
fil_node_t* file = space->add(path, OS_FILE_CLOSED, size,
false, true);
mtr.start();
fil_op_write_log(
@ -3843,7 +3786,7 @@ fil_ibd_create(
fil_name_write(space, 0, file, &mtr);
mtr.commit();
node->block_size = block_size;
file->block_size = block_size;
space->punch_hole = punch_hole;
err = DB_SUCCESS;
@ -4072,6 +4015,7 @@ fil_ibd_open(
|| df_remote.is_open() != df_remote.is_valid()) {
return(DB_CORRUPTION);
}
error:
return(DB_ERROR);
}
@ -4180,17 +4124,17 @@ skip_validate:
fil_space_t* space = fil_space_create(
space_name, id, flags, purpose, crypt_data);
if (!space) {
goto error;
}
/* We do not measure the size of the file, that is why
we pass the 0 below */
if (fil_node_create_low(
df_remote.is_open() ? df_remote.filepath() :
df_dict.is_open() ? df_dict.filepath() :
df_default.filepath(), 0, space, false,
true) == NULL) {
err = DB_ERROR;
}
space->add(
df_remote.is_open() ? df_remote.filepath() :
df_dict.is_open() ? df_dict.filepath() :
df_default.filepath(), OS_FILE_CLOSED, 0, false, true);
if (err == DB_SUCCESS && validate
&& purpose != FIL_TYPE_IMPORT && !srv_read_only_mode) {
@ -4539,9 +4483,7 @@ fil_ibd_load(
the rounding formula for extents and pages is somewhat complex; we
let fil_node_open() do that task. */
if (!fil_node_create_low(file.filepath(), 0, space, false, false)) {
ut_error;
}
space->add(file.filepath(), OS_FILE_CLOSED, 0, false, false);
return(FIL_LOAD_OK);
}

View file

@ -123,18 +123,15 @@ Tablespace::open_or_create(bool is_temp)
is_temp
? FIL_TYPE_TEMPORARY : FIL_TYPE_TABLESPACE,
NULL);
if (!space) {
return DB_ERROR;
}
}
ut_a(fil_validate());
/* Create the tablespace node entry for this data file. */
if (!fil_node_create(
it->m_filepath, it->m_size, space, false,
TRUE)) {
err = DB_ERROR;
break;
}
space->add(it->m_filepath, OS_FILE_CLOSED, it->m_size,
false, true);
}
return(err);

View file

@ -918,6 +918,9 @@ SysTablespace::open_or_create(
name(), space_id(), flags(), is_temp
? FIL_TYPE_TEMPORARY : FIL_TYPE_TABLESPACE,
NULL);
if (!space) {
return DB_ERROR;
}
}
ut_a(fil_validate());
@ -928,15 +931,8 @@ SysTablespace::open_or_create(
: m_last_file_size_max)
: it->m_size);
/* Add the datafile to the fil_system cache. */
if (!fil_node_create(
it->m_filepath, it->m_size,
space, it->m_type != SRV_NOT_RAW,
TRUE, max_size)) {
err = DB_ERROR;
break;
}
space->add(it->m_filepath, OS_FILE_CLOSED, it->m_size,
it->m_type != SRV_NOT_RAW, true, max_size);
}
return(err);

View file

@ -195,6 +195,19 @@ struct fil_space_t {
return !atomic_write_supported
&& srv_use_doublewrite_buf && buf_dblwr;
}
/** Append a file to the chain of files of a space.
@param[in] name file name of a file that is not open
@param[in] handle file handle, or OS_FILE_CLOSED
@param[in] size file size in entire database pages
@param[in] is_raw whether this is a raw device
@param[in] atomic_write true if atomic write could be enabled
@param[in] max_pages maximum number of pages in file,
or ULINT_MAX for unlimited
@return file object */
fil_node_t* add(const char* name, pfs_os_file_t handle,
ulint size, bool is_raw, bool atomic_write,
ulint max_pages = ULINT_MAX);
};
/** Value of fil_space_t::magic_n */
@ -252,6 +265,11 @@ struct fil_node_t {
{
return(handle != OS_FILE_CLOSED);
}
/** Read the first page of a data file.
@param[in] first whether this is the very first read
@return whether the page was found valid */
bool read_page0(bool first);
};
/** Value of fil_node_t::magic_n */
@ -547,26 +565,6 @@ void
fil_space_set_imported(
ulint id);
/** Append a file to the chain of files of a space.
@param[in] name file name of a file that is not open
@param[in] size file size in entire database blocks
@param[in,out] space tablespace from fil_space_create()
@param[in] is_raw whether this is a raw device or partition
@param[in] atomic_write true if atomic write could be enabled
@param[in] max_pages maximum number of pages in file,
ULINT_MAX means the file size is unlimited.
@return pointer to the file name
@retval NULL if error */
char*
fil_node_create(
const char* name,
ulint size,
fil_space_t* space,
bool is_raw,
bool atomic_write,
ulint max_pages = ULINT_MAX)
MY_ATTRIBUTE((warn_unused_result));
/** Create a space memory object and put it to the fil_system hash table.
Error messages are issued to the server log.
@param[in] name tablespace name
@ -575,7 +573,7 @@ Error messages are issued to the server log.
@param[in] purpose tablespace purpose
@param[in,out] crypt_data encryption information
@param[in] mode encryption mode
@return pointer to created tablespace, to be filled in with fil_node_create()
@return pointer to created tablespace, to be filled in with fil_space_t::add()
@retval NULL on failure (such as when the same tablespace exists) */
fil_space_t*
fil_space_create(

View file

@ -470,23 +470,16 @@ create_log_files(
const ulint size = ulint(srv_log_file_size >> srv_page_size_shift);
logfile0 = fil_node_create(
logfilename, size, log_space, false, false);
logfile0 = log_space->add(logfilename, OS_FILE_CLOSED, size,
false, false)->name;
ut_a(logfile0);
for (unsigned i = 1; i < srv_n_log_files; i++) {
sprintf(logfilename + dirnamelen, "ib_logfile%u", i);
if (!fil_node_create(logfilename, size,
log_space, false, false)) {
ib::error()
<< "Cannot create file node for log file "
<< logfilename;
return(DB_ERROR);
}
log_space->add(logfilename, OS_FILE_CLOSED, size,
false, false);
}
log_init(srv_n_log_files);
@ -634,83 +627,68 @@ srv_undo_tablespace_create(
return(err);
}
/*********************************************************************//**
Open an undo tablespace.
@return DB_SUCCESS or error code */
static
dberr_t
srv_undo_tablespace_open(
/*=====================*/
const char* name, /*!< in: tablespace file name */
ulint space_id) /*!< in: tablespace id */
/** Open an undo tablespace.
@param[in] name tablespace file name
@param[in] space_id tablespace ID
@param[in] create_new_db whether undo tablespaces are being created
@return whether the tablespace was opened */
static bool srv_undo_tablespace_open(const char* name, ulint space_id,
bool create_new_db)
{
pfs_os_file_t fh;
bool ret;
dberr_t err = DB_ERROR;
bool success;
char undo_name[sizeof "innodb_undo000"];
snprintf(undo_name, sizeof(undo_name),
"innodb_undo%03u", static_cast<unsigned>(space_id));
if (!srv_file_check_mode(name)) {
ib::error() << "UNDO tablespaces must be " <<
(srv_read_only_mode ? "writable" : "readable") << "!";
return(DB_ERROR);
fh = os_file_create(
innodb_data_file_key, name, OS_FILE_OPEN
| OS_FILE_ON_ERROR_NO_EXIT | OS_FILE_ON_ERROR_SILENT,
OS_FILE_AIO, OS_DATA_FILE, srv_read_only_mode, &success);
if (!success) {
return false;
}
fh = os_file_create(
innodb_data_file_key, name,
OS_FILE_OPEN_RETRY
| OS_FILE_ON_ERROR_NO_EXIT
| OS_FILE_ON_ERROR_SILENT,
OS_FILE_NORMAL,
OS_DATA_FILE,
srv_read_only_mode,
&ret);
os_offset_t size = os_file_get_size(fh);
ut_a(size != os_offset_t(-1));
/* If the file open was successful then load the tablespace. */
/* Load the tablespace into InnoDB's internal data structures. */
if (ret) {
os_offset_t size;
fil_space_t* space;
/* We set the biggest space id to the undo tablespace
because InnoDB hasn't opened any other tablespace apart
from the system tablespace. */
size = os_file_get_size(fh);
ut_a(size != (os_offset_t) -1);
fil_set_max_space_id_if_bigger(space_id);
ret = os_file_close(fh);
ut_a(ret);
fil_space_t* space = fil_space_create(
undo_name, space_id, FSP_FLAGS_PAGE_SSIZE(),
FIL_TYPE_TABLESPACE, NULL);
/* Load the tablespace into InnoDB's internal
data structures. */
ut_a(fil_validate());
ut_a(space);
/* We set the biggest space id to the undo tablespace
because InnoDB hasn't opened any other tablespace apart
from the system tablespace. */
fil_node_t* file = space->add(name, fh, 0, false, true);
fil_set_max_space_id_if_bigger(space_id);
mutex_enter(&fil_system->mutex);
space = fil_space_create(
undo_name, space_id, FSP_FLAGS_PAGE_SSIZE(),
FIL_TYPE_TABLESPACE, NULL);
ut_a(fil_validate());
ut_a(space);
os_offset_t n_pages = size / UNIV_PAGE_SIZE;
/* On 32-bit platforms, ulint is 32 bits and os_offset_t
is 64 bits. It is OK to cast the n_pages to ulint because
the unit has been scaled to pages and page number is always
32 bits. */
if (fil_node_create(
name, (ulint) n_pages, space, false, TRUE)) {
err = DB_SUCCESS;
if (create_new_db) {
space->size = file->size = ulint(size >> srv_page_size_shift);
space->size_in_header = SRV_UNDO_TABLESPACE_SIZE_IN_PAGES;
} else {
success = file->read_page0(true);
if (!success) {
os_file_close(file->handle);
file->handle = OS_FILE_CLOSED;
ut_a(fil_system->n_open > 0);
fil_system->n_open--;
}
}
return(err);
mutex_exit(&fil_system->mutex);
return success;
}
/** Check if undo tablespaces and redo log files exist before creating a
@ -936,12 +914,11 @@ srv_undo_tablespaces_init(bool create_new_db)
ut_a(undo_tablespace_ids[i] != 0);
ut_a(undo_tablespace_ids[i] != ULINT_UNDEFINED);
err = srv_undo_tablespace_open(name, undo_tablespace_ids[i]);
if (err != DB_SUCCESS) {
if (!srv_undo_tablespace_open(name, undo_tablespace_ids[i],
create_new_db)) {
ib::error() << "Unable to open undo tablespace '"
<< name << "'.";
return(err);
return DB_ERROR;
}
prev_space_id = undo_tablespace_ids[i];
@ -966,9 +943,8 @@ srv_undo_tablespaces_init(bool create_new_db)
name, sizeof(name),
"%s%cundo%03zu", srv_undo_dir, OS_PATH_SEPARATOR, i);
err = srv_undo_tablespace_open(name, i);
if (err != DB_SUCCESS) {
if (!srv_undo_tablespace_open(name, i, create_new_db)) {
err = DB_ERROR;
break;
}
@ -2078,10 +2054,8 @@ innobase_start_or_create_for_mysql()
for (unsigned j = 0; j < srv_n_log_files_found; j++) {
sprintf(logfilename + dirnamelen, "ib_logfile%u", j);
if (!fil_node_create(logfilename, size,
log_space, false, false)) {
return(srv_init_abort(DB_ERROR));
}
log_space->add(logfilename, OS_FILE_CLOSED, size,
false, false);
}
log_init(srv_n_log_files_found);