/** Try to close a file to adhere to the innodb_open_files limit. @paramignore_spaceIgnorethetablespacewhichisacquiredbycaller @paramprint_infowhethertodiagnosewhyafilecannotbeclosed
@return whether a file was closed */ bool fil_space_t::try_to_close(fil_space_t *ignore_space, bool print_info)
noexcept
{
mysql_mutex_assert_owner(&fil_system.mutex); for (fil_space_t &space : fil_system.space_list)
{ if (&space == ignore_space || space.is_being_imported() ||
space.id == TRX_SYS_SPACE || space.id == SRV_TMP_SPACE_ID ||
srv_is_undo_tablespace(space.id)) continue;
ut_ad(!space.is_temporary());
/* We are using an approximation of LRU replacement policy. In fil_node_open_file_low(),newlyopenedfilesaremovedtotheend offil_system.space_list,sothattheywouldbelesslikelytobe
closed here. */
fil_node_t *node= UT_LIST_GET_FIRST(space.chain); if (!node) /* fil_ibd_create() did not invoke fil_space_t::add() yet */ continue;
ut_ad(!UT_LIST_GET_NEXT(chain, node));
if (!node->is_open()) continue;
constauto n= space.set_closing(); if (n & STOPPING) /* Let fil_space_t::drop() in another thread handle this. */ continue; if (n & (PENDING | NEEDS_FSYNC))
{ if (!print_info) continue;
print_info= false; const time_t now= time(nullptr); if (now - fil_system.n_open_exceeded_time < 5) continue; /* We display messages at most once in 5 seconds. */
fil_system.n_open_exceeded_time= now;
if (n & PENDING)
sql_print_information("InnoDB: Cannot close file %s because of "
UINT32PF " pending operations%s", node->name,
n & PENDING,
(n & NEEDS_FSYNC) ? " and pending fsync" : ""); elseif (n & NEEDS_FSYNC)
sql_print_information("InnoDB: Cannot close file %s because of " "pending fsync", node->name); continue;
}
/** Reference to the server data directory. Usually it is the currentworkingdirectory".",butintheMariaDBEmbeddedServerLibrary
it is an absolute path. */ constchar* fil_path_to_mysql_datadir;
/** Number of pending tablespace flushes */
Atomic_counter<ulint> fil_n_pending_tablespace_flushes;
/** The tablespace memory cache. This variable is NULL before the module is
initialized. */
fil_system_t fil_system;
/** At this age or older a space/page will be rotated */ extern uint srv_fil_crypt_rotate_key_age;
#ifdef UNIV_DEBUG /** Try fil_validate() every this many times */ # define FIL_VALIDATE_SKIP 17
/******************************************************************//**
Checks the consistency of the tablespace cache some of the time.
@returntrueif ok or the check was skipped */ staticbool fil_validate_skip() noexcept
{ /** The fil_validate() call skip counter. */ static Atomic_counter<uint32_t> fil_validate_count;
/* We want to reduce the call frequency of the costly fil_validate()
check in debug builds. */ return (fil_validate_count++ % FIL_VALIDATE_SKIP) || fil_validate();
} #endif/* UNIV_DEBUG */
/** Look up a tablespace. ThecallershouldholdanInnoDBtablelockoraMDLthatprevents thetablespacefrombeingdroppedduringtheoperation, orthecallershouldbeinsingle-threadedcrashrecoverymode (nouserconnectionsthatcoulddroptablespaces). Normally,fil_space_t::get()shouldbeusedinstead. @param[in]idtablespaceID
@return tablespace, or NULL if not found */
fil_space_t *fil_space_get(uint32_t id) noexcept
{
mysql_mutex_lock(&fil_system.mutex);
fil_space_t *space= fil_space_get_by_id(id);
mysql_mutex_unlock(&fil_system.mutex); return space;
}
/** Check if the compression algorithm is loaded @param[in]comp_algoulintcompressionalgorithm
@return whether the compression algorithm is loaded */ bool fil_comp_algo_loaded(ulint comp_algo) noexcept
{ switch (comp_algo) { case PAGE_UNCOMPRESSED: case PAGE_ZLIB_ALGORITHM: returntrue;
case PAGE_LZ4_ALGORITHM: return provider_service_lz4->is_loaded;
case PAGE_LZO_ALGORITHM: return provider_service_lzo->is_loaded;
case PAGE_LZMA_ALGORITHM: return provider_service_lzma->is_loaded;
case PAGE_BZIP2_ALGORITHM: return provider_service_bzip2->is_loaded;
case PAGE_SNAPPY_ALGORITHM: return provider_service_snappy->is_loaded;
}
returnfalse;
}
/** Append a file to the chain of files of a space. @param[in]namefilenameofafilethatisnotopen @param[in]handlefilehandle,orOS_FILE_CLOSED @param[in]sizefilesizeinentiredatabasepages @param[in]is_rawwhetherthisisarawdevice @param[in]atomic_writetrueifatomicwritecouldbeenabled @param[in]max_pagesmaximumnumberofpagesinfile, orUINT32_MAXforunlimited
@return file object */
fil_node_t* fil_space_t::add(constchar* name, pfs_os_file_t handle,
uint32_t size, bool is_raw, bool atomic_write,
uint32_t max_pages) noexcept
{
mysql_mutex_assert_owner(&fil_system.mutex);
/* The following call prints an error message */ if (os_file_get_last_error(true) == EMFILE + 100 &&
fil_space_t::try_to_close(nullptr, true)) continue;
if (node->size); elseif (!node->read_page0(page, no_lsn) || // validate compression algorithm for full crc32 format
(node->space->full_crc32() &&
(comp_algo_invalid = !fil_comp_algo_loaded(comp_algo))))
{ if (comp_algo_invalid)
{ if (comp_algo <= PAGE_ALGORITHM_LAST)
ib::warn() << "'" << node->name << "' is compressed with "
<< page_compression_algorithms[comp_algo]
<< ", which is not currently loaded"; else
ib::warn() << "'" << node->name << "' is compressed with "
<< "invalid algorithm: " << comp_algo;
}
for (ulint count= 0; fil_system.n_open >= srv_max_n_open_files; count++)
{ if (fil_space_t::try_to_close(nullptr, count > 1))
count= 0; elseif (count >= 2)
{ if (old_time != fil_system.n_open_exceeded_time)
sql_print_warning("InnoDB: innodb_open_files=" ULINTPF " is exceeded (" ULINTPF " files stay open)",
srv_max_n_open_files, fil_system.n_open); break;
} else
{
mysql_mutex_unlock(&fil_system.mutex);
std::this_thread::sleep_for(std::chrono::milliseconds(20)); /* Flush tablespaces so that we can close modified files. */
fil_flush_file_spaces();
mysql_mutex_lock(&fil_system.mutex); if (node->is_open()) returntrue;
}
}
/* The node can be opened between releasing and acquiring fil_system.mutex
in the above code */ return node->is_open() || fil_node_open_file_low(node, page, no_lsn);
}
/** Close the file handle. */ void fil_node_t::close() noexcept
{
prepare_to_close_or_detach();
/** Try to extend a tablespace. @param[in,out]spacetablespacetobeextended @param[in,out]nodelastfileofthetablespace @param[in]sizedesiredsizeinnumberofpages @param[out]successwhethertheoperationsucceeded
@return whether the operation should be retried */ static ATTRIBUTE_COLD __attribute__((warn_unused_result, nonnull)) bool
fil_space_extend_must_retry(
fil_space_t* space,
fil_node_t* node,
uint32_t size, bool* success) noexcept
{
mysql_mutex_assert_owner(&fil_system.mutex);
ut_ad(UT_LIST_GET_LAST(space->chain) == node);
ut_ad(size >= FIL_IBD_FILE_INITIAL_SIZE);
ut_ad(node->space == space);
ut_ad(space->referenced());
*success = space->size >= size;
if (*success) { /* Space already big enough */ return(false);
}
if (node->being_extended) { /* Another thread is currently extending the file. Wait forittofinish. It'dhavebeenbettertouseeventdrivenmechanismbut
the entire module is peppered with polling stuff. */
mysql_mutex_unlock(&fil_system.mutex);
std::this_thread::sleep_for(std::chrono::milliseconds(100)); return(true);
}
node->being_extended = true;
/* At this point it is safe to release fil_system.mutex. No otherthreadcanrename,delete,closeorextendthefilebecause
we have set the node->being_extended flag. */
mysql_mutex_unlock(&fil_system.mutex);
os_has_said_disk_full = !*success; if (*success) {
os_file_flush(node->handle);
last_page_no = size;
} else { /* Let us measure the size of the file todeterminehowmuchwewereableto
extend it */
os_offset_t fsize = os_file_get_size(node->handle);
ut_a(fsize != os_offset_t(-1));
/** Try to extend a tablespace if it is smaller than the specified size. @param[in,out]spacetablespace @param[in]sizedesiredsizeinpages
@return whether the tablespace is at least as big as requested */ bool fil_space_extend(fil_space_t *space, uint32_t size) noexcept
{
ut_ad(!srv_read_only_mode || space->is_temporary()); bool success= false; constbool acquired= space->acquire();
mysql_mutex_lock(&fil_system.mutex); if (acquired) while (fil_space_extend_must_retry(space, UT_LIST_GET_LAST(space->chain),
size, &success))
mysql_mutex_lock(&fil_system.mutex);
mysql_mutex_unlock(&fil_system.mutex); if (acquired)
space->release(); return success;
}
/** Prepare to free a file from fil_system. */ inline pfs_os_file_t fil_node_t::close_to_free(bool detach_handle) noexcept
{
mysql_mutex_assert_owner(&fil_system.mutex);
ut_a(!being_extended);
if (is_open() &&
(space->n_pending.fetch_or(fil_space_t::CLOSING,
std::memory_order_acquire) &
fil_space_t::PENDING))
{
mysql_mutex_unlock(&fil_system.mutex); while (space->referenced())
std::this_thread::sleep_for(std::chrono::microseconds(100));
mysql_mutex_lock(&fil_system.mutex);
}
while (is_open())
{ if (space->is_in_unflushed_spaces)
{
space->is_in_unflushed_spaces= false;
fil_system.unflushed_spaces.remove(*space);
}
ut_a(!being_extended); if (detach_handle)
{ auto result= handle;
handle= OS_FILE_CLOSED; return result;
} bool ret= os_file_close(handle);
ut_a(ret);
handle= OS_FILE_CLOSED; break;
}
return OS_FILE_CLOSED;
}
/** Detach a tablespace from the cache and close the files. @paramspacetablespace @paramdetach_handlewhethertodetachthehandle,insteadofclosing @returndetachedhandle
@retval OS_FILE_CLOSED if no handle was detached */
pfs_os_file_t fil_system_t::detach(fil_space_t *space, bool detach_handle)
noexcept
{
mysql_mutex_assert_owner(&fil_system.mutex);
spaces.cell_get(space->id)->remove(*space, &fil_space_t::hash);
if (space->is_in_unflushed_spaces)
{
space->is_in_unflushed_spaces= false;
unflushed_spaces.remove(*space);
}
if (space->is_in_default_encrypt)
{
space->is_in_default_encrypt= false;
default_encrypt_tables.remove(*space);
}
for (fil_node_t* node= UT_LIST_GET_FIRST(space->chain); node;
node= UT_LIST_GET_NEXT(chain, node))
handle= node->close_to_free(detach_handle);
ut_ad(!space->referenced()); return handle;
}
/** Free a tablespace object on which fil_system_t::detach() was invoked. Theremustnotbeanypendingi/o'sorflushesonthefiles.
@param[in,out] space tablespace */ staticvoid fil_space_free_low(fil_space_t *space) noexcept
{ /* The tablespace must not be in fil_system.named_spaces. */
ut_ad(srv_fast_shutdown == 2 || !srv_was_started
|| space->max_lsn == 0);
ut_ad(!space->referenced());
if (srv_n_fil_crypt_threads_started)
{
mysql_mutex_unlock(&fil_system.mutex);
fil_crypt_threads_signal();
mysql_mutex_lock(&fil_system.mutex);
}
}
return space;
}
/*******************************************************************//**
Assigns a new space id for a new single-table tablespace. This works simply by
incrementing the global counter. If4 billion id's is not enough, we may need
to recycle id's.
@returntrueif assigned, falseifnot */ bool fil_assign_new_space_id(uint32_t *space_id) noexcept
{
uint32_t id = *space_id; bool success;
mysql_mutex_lock(&fil_system.mutex);
if (id < fil_system.max_assigned_id) {
id = fil_system.max_assigned_id;
}
id++;
if (id > (SRV_SPACE_ID_UPPER_BOUND / 2) && (id % 1000000UL == 0)) {
ib::warn() << "You are running out of new single-table" " tablespace id's. Current counter is " << id
<< " and it must not exceed" <<SRV_SPACE_ID_UPPER_BOUND
<< "! To reset the counter to zero you have to dump" " all your tables and recreate the whole InnoDB" " installation.";
}
success = (id < SRV_SPACE_ID_UPPER_BOUND);
if (success) {
*space_id = fil_system.max_assigned_id = id;
} else {
ib::warn() << "You have run out of single-table tablespace" " id's! Current counter is " << id
<< ". To reset the counter to zero" " you have to dump all your tables and" " recreate the whole InnoDB installation.";
*space_id = UINT32_MAX;
}
mysql_mutex_unlock(&fil_system.mutex);
return(success);
}
/** Read the first page of a data file. @paramdpagecopyofafirstpage,fromthedoublewritebuffer,ornullptr @paramno_lsnwhethertoskiptheFIL_PAGE_LSNcheck
@return whether the page was found valid */ bool fil_space_t::read_page0(const byte *dpage, bool no_lsn) noexcept
{
ut_ad(fil_system.is_initialised());
mysql_mutex_assert_owner(&fil_system.mutex); if (size) returntrue;
fil_node_t *node= UT_LIST_GET_FIRST(chain); if (!node) returnfalse;
ut_ad(!UT_LIST_GET_NEXT(chain, node));
if (UNIV_UNLIKELY(acquire_low() & STOPPING))
{
ut_ad("this should not happen" == 0); returnfalse;
} constbool ok= node->is_open() || fil_node_open_file(node, dpage, no_lsn);
release(); return ok;
}
void fil_space_set_recv_size_and_flags(uint32_t id, uint32_t size,
uint32_t flags) noexcept
{
ut_ad(id < SRV_SPACE_ID_UPPER_BOUND);
mysql_mutex_assert_owner(&recv_sys.mutex);
mysql_mutex_lock(&fil_system.mutex); if (fil_space_t *space= fil_space_get_by_id(id)) if (space->read_page0(recv_sys.dblwr.find_page(page_id_t(id, 0), LSN_MAX), true))
{ if (size)
space->recv_size= size; if (flags != FSP_FLAGS_FCRC32_MASK_MARKER)
space->flags= flags;
}
mysql_mutex_unlock(&fil_system.mutex);
}
/** Open each file. Never invoked on .ibd files. @paramcreate_new_dbwhethertoskipthecalltofil_node_t::read_page0()
@return whether all files were opened */ bool fil_space_t::open(bool create_new_db)
{
ut_ad(fil_system.is_initialised());
ut_ad(!id || create_new_db);
/** Extend all open data files to the recovered size */
ATTRIBUTE_COLD void fil_system_t::extend_to_recv_size() noexcept
{
ut_ad(is_initialised());
mysql_mutex_lock(&mutex); for (fil_space_t &space : fil_system.space_list)
{ const uint32_t size= space.recv_size;
if (size > space.size)
{ if (space.is_closing()) continue;
space.reacquire(); bool success; while (fil_space_extend_must_retry(&space, UT_LIST_GET_LAST(space.chain),
size, &success))
mysql_mutex_lock(&mutex); /* Crash recovery requires the file extension to succeed. */
ut_a(success);
space.release();
}
}
mysql_mutex_unlock(&mutex);
}
if (buffered != is_buffered())
{ this->buffered= buffered;
fil_space_t::reopen_all();
}
mysql_mutex_unlock(&mutex);
}
/** Close all tablespace files at shutdown */ void fil_space_t::close_all() noexcept
{ if (!fil_system.is_initialised()) return;
/* At shutdown, we should not have any files in this list. */
ut_ad(srv_fast_shutdown == 2 || !srv_was_started ||
fil_system.named_spaces.empty());
fil_flush_file_spaces();
mysql_mutex_lock(&fil_system.mutex);
while (!fil_system.space_list.empty())
{
fil_space_t &space= fil_system.space_list.front();
for (fil_node_t *node= UT_LIST_GET_FIRST(space.chain); node != NULL;
node= UT_LIST_GET_NEXT(chain, node))
{ if (!node->is_open())
next: continue;
for (ulint count= 10000; count--;)
{ constauto n= space.set_closing(); if (n & STOPPING) goto next; if (!(n & (PENDING | NEEDS_FSYNC)))
{
node->close(); goto next;
}
mysql_mutex_unlock(&fil_system.mutex);
std::this_thread::sleep_for(std::chrono::microseconds(100));
mysql_mutex_lock(&fil_system.mutex); if (!node->is_open()) goto next;
}
/*******************************************************************//**
Sets the max tablespace id counter if the given number is bigger than the
previous value. */ void fil_set_max_space_id_if_bigger(uint32_t max_id) noexcept
{
ut_a(max_id < SRV_SPACE_ID_UPPER_BOUND);
mysql_mutex_lock(&fil_system.mutex);
if (fil_system.max_assigned_id < max_id) {
fil_system.max_assigned_id = max_id;
}
mysql_mutex_unlock(&fil_system.mutex);
}
/** Acquire a tablespace reference. @paramidtablespaceidentifier @returntablespace
@retval nullptr if the tablespace is missing or inaccessible */
fil_space_t *fil_space_t::get(uint32_t id) noexcept
{
mysql_mutex_lock(&fil_system.mutex);
fil_space_t *space= fil_space_get_by_id(id); const uint32_t n= space ? space->acquire_low() : 0;
/** Write a log record about a file operation. @paramtypefileoperation @paramfirst_page_nofirstpagenumberinthefile @parampathfilepath @paramnew_pathnewfilepathfortype=FILE_RENAME
@return number of bytes written */ inline size_t mtr_t::log_file_op(mfile_type_t type, uint32_t space_id, constchar *path, constchar *new_path)
noexcept
{
ut_ad((new_path != nullptr) == (type == FILE_RENAME));
ut_ad(!(byte(type) & 15));
ut_ad(!is_predefined_tablespace(space_id));
/* fil_name_parse() requires that there be at least one path
separator and that the file path end with ".ibd" or "ibb". */
ut_ad(strchr(path, '/'));
ut_ad(!strcmp(&path[strlen(path) - strlen(DOT_IBD)], DOT_IBD) ||
!strcmp(&path[strlen(path) - strlen(DOT_IBB)], DOT_IBB));
m_modifications= true; if (!is_logged()) return0;
m_last= nullptr;
if (!space)
{
mysql_mutex_unlock(&fil_system.mutex); return nullptr;
}
if (space->pending() & STOPPING)
{ /* A thread executing DDL and another thread executing purge may beexecutingfil_delete_tablespace()concurrentlyforthesame
tablespace. Wait for the other thread to complete the operation. */ for (ulint count= 0;; count++)
{
space= fil_space_get_by_id(id);
ut_ad(!space || space->is_stopping());
mysql_mutex_unlock(&fil_system.mutex); if (!space) return nullptr; /* Issue a warning every 10.24 seconds, starting after 2.56 seconds */ if ((count & 511) == 128)
sql_print_warning("InnoDB: Waiting for tablespace " UINT32PF " to be deleted", id);
std::this_thread::sleep_for(std::chrono::milliseconds(20));
mysql_mutex_lock(&fil_system.mutex);
}
}
/* We must be the first one to set either STOPPING flag on the .ibd file, becausetheflagsareonlybeingsethere,withinacriticalsectionof
fil_system.mutex. */ unsigned pending;
ut_d(pending=)
space->n_pending.fetch_add(STOPPING_READS + 1, std::memory_order_relaxed);
ut_ad(!(pending & STOPPING));
mysql_mutex_unlock(&fil_system.mutex);
if (space->crypt_data)
fil_space_crypt_close_tablespace(space);
if (!space->is_being_imported())
{ if (id >= srv_undo_space_id_start &&
id < srv_undo_space_id_start + srv_undo_tablespaces_open)
{
os_file_delete(innodb_data_file_key, space->chain.start->name); goto deleted;
}
/* Before deleting the file, persistently write a log record. */
mtr_t mtr{nullptr};
mtr.start();
mtr.log_file_op(FILE_DELETE, id, space->chain.start->name);
mtr.commit_file(*space, nullptr);
if (FSP_FLAGS_HAS_DATA_DIR(space->flags))
RemoteDatafile::delete_link_file(space->name());
deleted:
mysql_mutex_lock(&fil_system.mutex);
ut_ad(space == fil_space_get_by_id(id));
pending=
space->n_pending.fetch_add(STOPPING_WRITES - 1, std::memory_order_relaxed);
ut_ad((pending & STOPPING) == STOPPING_READS);
ut_ad(pending & PENDING);
pending&= PENDING; if (--pending)
{ for (ulint count= 0;; count++)
{
ut_ad(space == fil_space_get_by_id(id));
pending= space->n_pending.load(std::memory_order_relaxed) & PENDING; if (!pending) break;
mysql_mutex_unlock(&fil_system.mutex); /* Issue a warning every 10.24 seconds, starting after 2.56 seconds */ if ((count & 511) == 128)
sql_print_warning("InnoDB: Trying to delete tablespace '%s' " "but there are %u pending operations",
space->chain.start->name, pending);
std::this_thread::sleep_for(std::chrono::milliseconds(20));
mysql_mutex_lock(&fil_system.mutex);
}
}
pfs_os_file_t handle= fil_system.detach(space, true);
mysql_mutex_unlock(&fil_system.mutex); /* The above mtr.commit_file(*space, nullptr) should remove the space from fil_system.named_spaces.BeforewesettheSTOPPING_WRITESflag,another concurrentoperationcouldhavemarkedthetablespacedirtyagain.
This clean-up corresponds to fil_space_free(). */
log_sys.latch.wr_lock();
ut_ad((space->pending() & ~NEEDS_FSYNC) == (STOPPING | CLOSING)); if (space->max_lsn != 0)
{
space->max_lsn= 0;
fil_system.named_spaces.remove(*space);
}
log_sys.latch.wr_unlock();
if (detached_handle)
*detached_handle = handle; else
os_file_close(handle);
return space;
}
/** Close a single-table tablespace on failed IMPORT TABLESPACE. Thetablespacemustbecachedinthememorycache.
Free all pages used by the tablespace. */ void fil_close_tablespace(uint32_t id) noexcept
{
ut_ad(!is_system_tablespace(id));
fil_space_t* space = fil_space_t::drop(id, nullptr); if (!space) { return;
}
space->x_lock();
ut_ad(space->is_stopping());
/* Invalidate in the buffer pool all pages belonging to the tablespace.Sincespace->is_stopping()holds,readahead cannolongerreadmorepagesofthistablespacetobuf_pool. Thuswecancleanthetablespaceoutofbuf_pool
completely and permanently. */ while (buf_flush_list_space(space));
space->x_unlock();
fil_space_free_low(space);
}
/** Delete a tablespace and associated .ibd file. @paramidtablespaceidentifier @returndetachedfilehandle(tobeclosedbythecaller)
@return OS_FILE_CLOSED if no file existed */
pfs_os_file_t fil_delete_tablespace(uint32_t id) noexcept
{
ut_ad(!is_system_tablespace(id));
pfs_os_file_t handle= OS_FILE_CLOSED; if (fil_space_t *space= fil_space_t::drop(id, &handle))
fil_space_free_low(space); return handle;
}
char* fil_make_filepath_low(constchar *path, const fil_space_t::name_type &name,
ib_extention extension, bool trim_name) noexcept
{ /* The path may contain the basename of the file, if so we do not needthename.IfthepathisNULL,wecanusethedefaultpath,
but there needs to be a name. */
ut_ad(path || name.data());
if (path == NULL) {
path = fil_path_to_mysql_datadir;
}
/* If the name is a relative or absolute path, do not prepend "./". */ if (path[0] == '.'
&& (path[1] == '\0' || path[1] == '/' IF_WIN(|| path[1] == '\\',))
&& name.size() && (name.data()[0] == '.'
|| is_absolute_path(name.data()))) {
path = NULL;
path_len = 0;
}
if (path != NULL) {
memcpy(full_name, path, path_len);
len = path_len;
}
full_name[len] = '\0';
if (trim_name) { /* Find the offset of the last DIR separator and set it to
null in order to strip off the old basename from this path. */ 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) {
last_dir_sep[0] = '\0';
len = strlen(full_name);
}
}
if (name.size()) { if (len && full_name[len - 1] != '/') { /* Add a DIR separator */
full_name[len] = '/';
full_name[++len] = '\0';
}
/* Make sure that the specified suffix is at the end of the filepath stringprovided.Thisassumesthatthesuffixstartswith'.'. Ifthefirstcharofthesuffixisfoundinthefilepathatthesame lengthasthesuffixfromtheend,thenwewillassumethatthereis
a previous suffix that needs to be replaced. */ if (suffix != NULL) { /* Need room for the trailing null byte. */
ut_ad(len < full_len);
if ((len > suffix_len)
&& (full_name[len - suffix_len] == suffix[0])) { /* Another suffix exists, make it the one requested. */
memcpy(&full_name[len - suffix_len], suffix, suffix_len);
if (!log)
{ if (!os_file_rename(innodb_data_file_key, old_path, path)) return DB_ERROR;
mysql_mutex_lock(&fil_system.mutex);
ut_free(chain.start->name);
chain.start->name= mem_strdup(path);
mysql_mutex_unlock(&fil_system.mutex); return DB_SUCCESS;
}
bool exists= false;
os_file_type_t ftype;
/* Check upfront if the rename operation might succeed, because we mustdurablywriteredologbeforeactuallyattemptingtoexecute
the rename in the file system. */ if (os_file_status(old_path, &exists, &ftype) && !exists)
{
sql_print_error("InnoDB: Cannot rename '%s' to '%s'" " because the source file does not exist.",
old_path, path); return DB_TABLESPACE_NOT_FOUND;
}
if (!replace)
{ char *schema_path= fil_make_dirpath(path); if (!schema_path) return DB_ERROR;
/* Create the subdirectories in the path, if they are
not there already. */
*err = os_file_create_subdirs_if_needed(path); if (*err != DB_SUCCESS) { return NULL;
}
static_assert(((UNIV_ZIP_SIZE_MIN >> 1) << 3) == 4096, "compatibility"); #ifdefined _WIN32 || defined O_DIRECT
ulint type; switch (FSP_FLAGS_GET_ZIP_SSIZE(flags)) { case1: case2:
type = OS_DATA_FILE_NO_O_DIRECT; break; default:
type = OS_DATA_FILE;
} #else
constexpr auto type = OS_DATA_FILE; #endif constbool is_compressed = fil_space_t::is_compressed(flags);
/* Create crypt data if the tablespace is either encrypted or user has
requested it to remain unencrypted. */
fil_space_crypt_t* crypt_data = (mode != FIL_ENCRYPTION_DEFAULT
|| srv_encrypt_tables)
? fil_space_create_crypt_data(mode, key_id)
: nullptr;
buf_block_t *header[2];
{
mtr_t mtr{nullptr};
mtr.start();
mtr.log_file_op(FILE_CREATE, space_id, path);
mtr.set_named_space(space);
log_free_check();
ut_a(fsp_header_init(space, size, &mtr) == DB_SUCCESS);
ut_ad(mtr.get_savepoint() == 3);
header[0] = mtr.at_savepoint(1);
header[1] = mtr.at_savepoint(2);
ut_ad(header[0]->page.id() == page_id_t(space_id, 0));
ut_ad(header[1]->page.id() == page_id_t(space_id, 1)); /* Block any page writes before the file has been created. */
header[0]->page.lock.x_lock();
header[1]->page.lock.x_lock();
mtr.commit(); /* Durably write the FILE_CREATE record (as well as records for
the fsp_header_init() above before creating the file. */
log_write_up_to(mtr.commit_lsn(), true);
}
if (!success) {
*err = DB_ERROR; /* The following call will print an error message */ switch (os_file_get_last_error(true)) { case OS_FILE_ALREADY_EXISTS:
sql_print_error("InnoDB: The file '%s'" " already exists though the" " corresponding table did not exist" " in the InnoDB data dictionary." " You can resolve the problem" " by removing" " the file.", path);
*err = DB_TABLESPACE_EXISTS; break; case OS_FILE_DISK_FULL:
*err = DB_OUT_OF_FILE_SPACE; /* fall through */ default:
sql_print_error("InnoDB: Cannot create file '%s'",
path);
} goto err_exit_after_cleanup;
err_exit:
os_file_delete(innodb_data_file_key, path);
os_file_close(file);
err_exit_after_cleanup:
space->release();
fil_space_free(space_id, false);
space = nullptr;
func_exit:
header[0]->page.lock.x_unlock();
header[1]->page.lock.x_unlock();
DBUG_EXECUTE_IF("checkpoint_after_file_create",
log_make_checkpoint();); return space;
}
if (FSP_FLAGS_HAS_DATA_DIR(flags)) { /* Make the ISL file if the IBD file is not
in the default location. */
fil_space_t::name_type space_name{name.m_name,
strlen(name.m_name)};
*err = RemoteDatafile::create_link_file(space_name, path); if (*err != DB_SUCCESS) { goto err_exit;
}
}
/* Table flags can be ULINT_UNDEFINED if
dict_tf_to_fsp_flags_failure is set. */ if (flags == UINT32_MAX) {
corrupted:
local_err = DB_CORRUPTION;
func_exit: if (err) *err = local_err; return space;
}
/* Discover the correct file by looking in three possible locations
while avoiding unnecessary effort. */
/* We will always look for an ibd in the default location. */
df_default.make_filepath(nullptr, name, IBD);
/* Look for a filepath embedded in an ISL where the default file
would be. */ bool must_validate = df_remote.open_link_file(name);
if (must_validate) { 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.";
}
} elseif (path_in && !df_default.same_filepath_as(path_in)) { /* Dict path is not the default path. Always validate
remote files. If default is opened, it was moved. */
must_validate = true;
} elseif (validate >= fil_space_t::VALIDATE_SPACE_ID) {
must_validate = true;
}
/* Always look for a file at the default location. But don't log
an error if the tablespace is already open in remote or dict. */
ut_a(df_default.filepath());
/* Mariabackup will not copy files whose names start with #sql-.Wewillsuppressmessagesaboutsuchfilesmissingon thefirstserverstartup.Thetablesoughttobedroppedby
drop_garbage_tables_after_restore() a little later. */
if (df_default.open_read_only(strict) == DB_SUCCESS) {
ut_ad(df_default.is_open());
++tablespaces_found;
}
/* Check if multiple locations point to the same file. */ if (tablespaces_found > 1 && df_default.same_as(df_remote)) { /* A link file was found with the default path in it.
Use the default path and delete the link file. */
--tablespaces_found;
df_remote.delete_link_file();
df_remote.close();
}
/* We have now checked all possible tablespace locations and haveacountofhowmanyuniquefileswefound.Ifthingsare
normal, we only found 1. */ /* For encrypted tablespace, we need to check the
encryption in header of first page. */ if (!must_validate && tablespaces_found == 1) { goto skip_validate;
}
/* Read and validate the first page of these three tablespace
locations, if found. */
valid_tablespaces_found +=
(df_remote.validate_to_dd(id, flags) == DB_SUCCESS);
/* Make sense of these three possible locations.
First, bail out if no tablespace files were found. */ if (valid_tablespaces_found == 0) { if (!strict
&& IF_WIN(GetLastError() == ERROR_FILE_NOT_FOUND
|| GetLastError() == ERROR_PATH_NOT_FOUND,
errno == ENOENT)) { /* Suppress a message about a missing file. */ goto corrupted;
}
if (!operation_not_for_export) { goto corrupted;
}
sql_print_error("InnoDB: Could not find a valid tablespace" " file for %.*s. %s", static_cast<int>(name.size()), name.data(),
TROUBLESHOOT_DATADICT_MSG); goto corrupted;
} if (!must_validate) { goto skip_validate;
}
/* Do not open any tablespaces if more than one tablespace with
the correct space ID and flags were found. */ if (df_default.is_open() && df_remote.is_open()) {
ib::error()
<< "A tablespace has been found in multiple places: "
<< df_default.filepath()
<< "(Space ID=" << df_default.space_id()
<< ", Flags=" << df_default.flags()
<< ") and "
<< df_remote.filepath()
<< "(Space ID=" << df_remote.space_id()
<< ", Flags=" << df_remote.flags()
<< (valid_tablespaces_found > 1 || srv_force_recovery
? "); will not open"
: ")");
/* Force-recovery will allow some tablespaces to be skippedbyREDOiftherewasmorethanonefilefound. UnlikeduringtheREDOphaseofrecovery,wenowknow ifthetablespaceisvalidaccordingtothedictionary, whichwasnotavailablethen.Soifwedidnotforce recoveryandthereisonlyonegoodtablespace,ignore
any bad tablespaces. */ if (valid_tablespaces_found > 1 || srv_force_recovery > 0) { /* If the file is not open it cannot be valid. */
ut_ad(df_default.is_open() || !df_default.is_valid());
ut_ad(df_remote.is_open() || !df_remote.is_valid());
/* Having established that, this is an easy way to
look for corrupted data files. */ if (df_default.is_open() != df_default.is_valid()
|| df_remote.is_open() != df_remote.is_valid()) { goto corrupted;
} #ifndef DBUG_OFF
error: #endif
local_err = DB_ERROR; goto func_exit;
}
/* There is only one valid tablespace found and we did notusesrv_force_recoveryduringREDO.Usethisone
tablespace and clean up invalid tablespace pointers */ if (df_default.is_open() && !df_default.is_valid()) {
df_default.close();
tablespaces_found--;
}
if (df_remote.is_open() && !df_remote.is_valid()) {
df_remote.close();
tablespaces_found--;
}
}
/* At this point, there should be only one filepath. */
ut_a(tablespaces_found == 1);
ut_a(valid_tablespaces_found == 1);
mysql_mutex_lock(&fil_system.mutex);
space = fil_space_t::create(id, flags,
validate == fil_space_t::VALIDATE_IMPORT,
crypt_data); /* We do not measure the size of the file, that is why
we pass the 0 below */
if (must_validate && !srv_read_only_mode) {
df_remote.close();
df_default.close(); if (space->acquire()) { if (validate < fil_space_t::VALIDATE_IMPORT) {
fsp_flags_try_adjust(space, flags
& ~FSP_FLAGS_MEM_MASK);
}
space->release();
}
}
goto func_exit;
}
/** Discover the correct IBD file to open given a remote or missing filepathfromtheREDOlog.Administratorscanmoveacrashed databasetoanotherlocationonthesamemachineandtrytorecoverit. RemoteIBDfilesmightbemovedaswelltothenewlocation. TheproblemwiththisisthattheREDOlogcontainstheoldlocation whichmaybestillaccessible.Duringrecovery,iffilesarefoundin bothlocations,wecanchoseonbasedonthesepriorities; 1.Defaultlocation 2.ISLlocation 3.REDOlocation @param[in]space_idtablespaceID @param[in]dfDatafileobjectwithpathfromredo
@return true if a valid datafile was found, false if not */ static bool
fil_ibd_discover(
ulint space_id,
Datafile& df)
{
Datafile df_def_per; /* default file-per-table datafile */
RemoteDatafile df_rem_per; /* remote file-per-table datafile */
/* Look for the datafile in the default location. */ constchar* filename = df.filepath(); constchar* basename = base_name(filename);
/* If this datafile is file-per-table it will have a schema dir. */
ulint sep_found = 0; constchar* db = basename; for (; db > filename && sep_found < 2; db--) { switch (db[0]) { #ifdef _WIN32 case'\\': #endif case'/':
sep_found++;
}
} if (sep_found == 2) {
db += 2;
df_def_per.init(0);
df_def_per.set_filepath(db); if (df_def_per.open_read_only(false) == DB_SUCCESS
&& df_def_per.validate_for_recovery() == DB_SUCCESS
&& df_def_per.space_id() == space_id) {
df.set_filepath(df_def_per.filepath());
df.open_read_only(false); return(true);
}
/* Look for a remote file-per-table tablespace. */
switch (srv_operation) { case SRV_OPERATION_BACKUP: case SRV_OPERATION_RESTORE_DELTA: case SRV_OPERATION_BACKUP_NO_DEFER:
ut_ad(0); break; case SRV_OPERATION_RESTORE_EXPORT: case SRV_OPERATION_RESTORE: break; case SRV_OPERATION_NORMAL: case SRV_OPERATION_EXPORT_RESTORED:
size_t len= strlen(db); if (len <= 4 || strcmp(db + len - 4, dot_ext[IBD])) { break;
}
df_rem_per.open_link_file({db, len - 4});
if (!df_rem_per.filepath()) { break;
}
/* An ISL file was found with contents. */ if (df_rem_per.open_read_only(false) != DB_SUCCESS
|| df_rem_per.validate_for_recovery()
!= DB_SUCCESS) {
/* Assume that this ISL file is intended to beused.Donotcontinuelookingforanother ifthisfilecannotbeopenedorisnot
a valid IBD file. */
ib::error() << "ISL file '"
<< df_rem_per.link_filepath()
<< "' was found but the linked file '"
<< df_rem_per.filepath()
<< "' could not be opened or is" " not correct."; return(false);
}
/* Use this file if it has the space_id from the
FILE_ record. */ if (df_rem_per.space_id() == space_id) {
df.set_filepath(df_rem_per.filepath());
df.open_read_only(false); return(true);
}
/* Since old MLOG records can use the same basename inmultipleCREATE/DROPTABLEsequences,thisISL filecouldbepointingtoalaterversionofthis basename.ibdfilewhichhasadifferentspace_id.
Keep looking. */
}
}
/* No ISL files were found in the default location. Use the location
given in the redo log. */ if (df.open_read_only(false) == DB_SUCCESS
&& df.validate_for_recovery() == DB_SUCCESS
&& df.space_id() == space_id) { return(true);
}
/* A datafile was not discovered for the filename given. */ return(false);
}
bool fil_crypt_check(fil_space_crypt_t *crypt_data, constchar *f_name)
noexcept
{ if (crypt_data->is_key_found()) returntrue;
sql_print_error("InnoDB: Encryption key is not found for %s", f_name);
crypt_data->~fil_space_crypt_t();
ut_free(crypt_data); returnfalse;
}
/** Open an ibd tablespace and add it to the InnoDB data structures. Thisissimilartofil_ibd_open()exceptthatitisusedwhileprocessing theREDOlog,sothedatadictionaryisnotavailableandverylittle validationisdone.Thetablespacenameisextractedfromthe dbname/tablename.ibdportionofthefilename,whichassumesthatthefile isafile-per-tabletablespace.Anynamewilldofornow.General tablespacenameswillbereadfromthedictionaryafterithasbeen recovered.Thetablespaceflagsarereadatthistimefromthefirstpage ofthefileinvalidate_for_recovery(). @param[in]space_idtablespaceID @param[in]filenamepath/to/databasename/tablename.ibd @param[out]spacethetablespace,orNULLonerror
@return status of the operation */ enum fil_load_status
fil_ibd_load(uint32_t space_id, constchar *filename, fil_space_t *&space) noexcept
{ /* If the a space is already in the file system cache with this
space ID, then there is nothing to do. */
mysql_mutex_lock(&fil_system.mutex);
space = fil_space_get_by_id(space_id);
mysql_mutex_unlock(&fil_system.mutex);
if (space) {
sql_print_information("InnoDB: Ignoring data file '%s'" " with space ID %" PRIu32 ". Another data file called %s" " exists" " with the same space ID.",
filename, space->id,
UT_LIST_GET_FIRST(space->chain)->name);
space = NULL; return FIL_LOAD_ID_CHANGED;
}
if (srv_operation == SRV_OPERATION_RESTORE) { /* Replace absolute DATA DIRECTORY file paths with
short names relative to the backup directory. */ constchar* name = strrchr(filename, '/'); #ifdef _WIN32 if (constchar *last = strrchr(filename, '\\')) { if (last > name) {
name = last;
}
} #endif if (name) { while (--name > filename #ifdef _WIN32
&& *name != '\\' #endif
&& *name != '/'); if (name > filename) {
filename = name + 1;
}
}
}
if (!file.is_open()) { /* The file has been moved or it is a remote datafile. */ if (!fil_ibd_discover(space_id, file)
|| !file.is_open()) { return(FIL_LOAD_NOT_FOUND);
}
}
os_offset_t size; bool deferred_space = false;
/* Read and validate the first page of the tablespace.
Assign a tablespace name based on the tablespace type. */ switch (file.validate_for_recovery()) {
os_offset_t minimum_size; case DB_SUCCESS:
deferred_space = file.m_defer;
if (deferred_space) { goto tablespace_check;
}
if (file.space_id() != space_id) { return(FIL_LOAD_ID_CHANGED);
}
tablespace_check: /* Get and test the file size. */
size = os_file_get_size(file.handle());
/* Every .ibd file is created >= 4 pages in size.
Smaller files cannot be OK. */
minimum_size = os_offset_t(FIL_IBD_FILE_INITIAL_SIZE)
<< srv_page_size_shift;
if (size == static_cast<os_offset_t>(-1)) { /* The following call prints an error message */
os_file_get_last_error(true);
ib::error() << "Could not measure the size of" " single-table tablespace file '"
<< file.filepath() << "'";
} elseif (deferred_space) { return FIL_LOAD_DEFER;
} elseif (size < minimum_size) {
ib::error() << "The size of tablespace file '"
<< file.filepath() << "' is only " << size
<< ", should be at least " << minimum_size
<< "!";
} else { /* Everything is fine so far. */ break;
}
/* fall through */
case DB_TABLESPACE_EXISTS: return(FIL_LOAD_INVALID);
default: return(FIL_LOAD_NOT_FOUND);
}
ut_ad(space == NULL);
/* Adjust the memory-based flags that would normally be set by
dict_tf_to_fsp_flags(). In recovery, we have no data dictionary. */
uint32_t flags = file.flags(); if (fil_space_t::is_compressed(flags)) {
flags |= page_zip_level
<< FSP_FLAGS_MEM_COMPRESSION_LEVEL;
}
/* We do not use the size information we have about the file, because theroundingformulaforextentsandpagesissomewhatcomplex;we
let fil_node_open() do that task. */
/** Try to adjust FSP_SPACE_FLAGS if they differ from the expectations. (TypicallywhenupgradingfromMariaDB10.1.0..10.1.20.) @param[in,out]spacetablespace
@param[in] flags desired tablespace flags */ void fsp_flags_try_adjust(fil_space_t *space, uint32_t flags)
{
ut_ad(!srv_read_only_mode);
ut_ad(fil_space_t::is_valid_flags(flags, space->id));
ut_ad(!space->is_being_imported());
ut_ad(!space->is_temporary()); if (space->full_crc32() || fil_space_t::full_crc32(flags)) { return;
} if (!space->size || !space->get_size()) { return;
}
mtr_t mtr{nullptr};
mtr.start(); if (buf_block_t* b = buf_page_get(
page_id_t(space->id, 0), space->zip_size(),
RW_X_LATCH, &mtr)) {
uint32_t f = fsp_header_get_flags(b->page.frame); if (fil_space_t::full_crc32(f)) { goto func_exit;
} if (fil_space_t::is_flags_equal(f, flags)) { goto func_exit;
} /* Suppress the message if only the DATA_DIR flag to differs. */ if ((f ^ flags) & ~(1U << FSP_FLAGS_POS_RESERVED)) {
ib::warn()
<< "adjusting FSP_SPACE_FLAGS of file '"
<< UT_LIST_GET_FIRST(space->chain)->name
<< "' from " << ib::hex(f)
<< " to " << ib::hex(flags);
}
mtr.set_named_space(space);
mtr.write<4,mtr_t::FORCED>(*b,
FSP_HEADER_OFFSET + FSP_SPACE_FLAGS
+ b->page.frame, flags);
}
func_exit:
mtr.commit();
}
/** Determine if a matching tablespace exists in the InnoDB tablespace memorycache.Notethatifwehavenotdoneacrashrecoveryatthedatabase startup,theremaybemanytablespaceswhicharenotyetinthememorycache. @param[in]idTablespaceID @param[in]table_flagstableflags @returnthetablespace
@retval NULL if no matching tablespace exists in the memory cache */
fil_space_t *fil_space_for_table_exists_in_mem(uint32_t id,
uint32_t table_flags) noexcept
{ const uint32_t expected_flags = dict_tf_to_fsp_flags(table_flags);
mysql_mutex_lock(&fil_system.mutex); if (fil_space_t* space = fil_space_get_by_id(id)) {
uint32_t tf = expected_flags & ~FSP_FLAGS_MEM_MASK;
uint32_t sf = space->flags & ~FSP_FLAGS_MEM_MASK;
if (!fil_space_t::is_flags_equal(tf, sf)
&& !fil_space_t::is_flags_equal(sf, tf)) { goto func_exit;
}
/* Adjust the flags that are in FSP_FLAGS_MEM_MASK.
FSP_SPACE_FLAGS will not be written back here. */
space->flags = (space->flags & ~FSP_FLAGS_MEM_MASK)
| (expected_flags & FSP_FLAGS_MEM_MASK);
mysql_mutex_unlock(&fil_system.mutex); if (!srv_read_only_mode) {
fsp_flags_try_adjust(space, expected_flags
& ~FSP_FLAGS_MEM_MASK);
} return space;
}
/** Flush to disk the writes in file spaces of the given type
possibly cached by the OS. */ void fil_flush_file_spaces() noexcept
{
rescan:
mysql_mutex_lock(&fil_system.mutex);
for (fil_space_t &space : fil_system.unflushed_spaces)
{ if (space.needs_flush_not_stopping())
{
space.reacquire();
mysql_mutex_unlock(&fil_system.mutex);
space.flush_low();
space.release(); goto rescan;
}
}
mysql_mutex_unlock(&fil_system.mutex);
}
/** Functor to validate the file node list of a tablespace. */ struct Check { /** Total size of file nodes visited so far */
ulint size; /** Total number of open files visited so far */
ulint n_open;
/******************************************************************//**
Checks the consistency of the tablespace cache.
@returntrueif ok */ bool fil_validate() noexcept
{
ulint n_open = 0;
mysql_mutex_lock(&fil_system.mutex);
for (fil_space_t &space : fil_system.space_list) {
n_open += Check::validate(&space);
}
ut_a(fil_system.n_open == n_open);
mysql_mutex_unlock(&fil_system.mutex);
return(true);
}
/********************************************************************//** Delete the tablespace file and any related files like .cfg. This should not be called for temporary tables.
@param[in] ibd_filepath File path of the IBD tablespace */ void fil_delete_file(constchar *ibd_filepath) noexcept
{
ib::info() << "Deleting " << ibd_filepath;
os_file_delete_if_exists(innodb_data_file_key, ibd_filepath, nullptr);
#ifdef UNIV_DEBUG /** Check that a tablespace is valid for mtr_commit().
@param[in] space persistent tablespace that has been changed */ static void fil_space_validate_for_mtr_commit(const fil_space_t *space) noexcept
{
mysql_mutex_assert_not_owner(&fil_system.mutex);
ut_ad(space != NULL);
ut_ad(!is_predefined_tablespace(space->id));
ut_ad(!space->is_being_imported());
/* We are serving mtr_commit(). While there is an active mini-transaction,weshouldhave!space->is_stopping().Thisis
guaranteed by meta-data locks or transactional locks. */
ut_ad(!space->is_stopping() || space->referenced());
} #endif/* UNIV_DEBUG */
/** Note that a non-predefined persistent tablespace has been modified byredolog.
@param[in,out] space tablespace */ void fil_names_dirty(fil_space_t *space) noexcept
{
ut_ad(log_sys.latch_have_wr());
ut_ad(recv_recovery_is_on());
ut_ad(!srv_read_only_mode);
ut_ad(log_sys.get_lsn() != 0);
ut_ad(space->max_lsn == 0);
ut_d(fil_space_validate_for_mtr_commit(space));
if (UNIV_UNLIKELY(recv_sys.rpo != 0)) { /* The log is read-only; do not write to it */ return;
}
/** Write a FILE_MODIFY record when a non-predefined persistent
tablespace was modified for the first time since fil_names_clear(). */
ATTRIBUTE_NOINLINE ATTRIBUTE_COLD void mtr_t::name_write() noexcept
{
ut_ad(log_sys.latch_have_wr());
ut_d(fil_space_validate_for_mtr_commit(m_user_space));
ut_ad(!m_user_space->max_lsn);
m_user_space->max_lsn= log_sys.get_lsn();
ut_ad(it->max_lsn > 0); if (it->max_lsn <= lsn) { /* The tablespace was last dirtied before the checkpointLSN.Removeitfromthelist,so thatifthetablespaceisnotgoingtobe modifiedanymore,subsequentcheckpointswill
avoid calling fil_names_clear() on it. */
it->max_lsn = 0;
fil_system.named_spaces.erase(it);
}
/* max_lsn is the last LSN where fil_names_dirty_and_write() wascalled.Ifwekepttrackof"min_lsn"(thefirstLSN wheremax_lsnturnednonzero),wecouldavoidthe
fil_names_clear() call if min_lsn > lsn. */
ut_ad(UT_LIST_GET_LEN((*it).chain) == 1);
size_t s = mtr.log_file_op(FILE_MODIFY, (*it).id, name);
ut_ad(s <= budget_left);
budget_left -= s;
it = next;
}
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.70Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-10-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.