polardbxengine/storage/innobase/include/fil0fil.h

1867 lines
69 KiB
C++

/*****************************************************************************
Copyright (c) 1995, 2019, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License, version 2.0, as published by the
Free Software Foundation.
This program is also distributed with certain software (including but not
limited to OpenSSL) that is licensed under separate terms, as designated in a
particular file or component or in included license documentation. The authors
of MySQL hereby grant you an additional permission to link the program and
your derivative works with the separately licensed software that they have
included with MySQL.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
/** @file include/fil0fil.h
The low-level file system
Created 10/25/1995 Heikki Tuuri
*******************************************************/
#ifndef fil0fil_h
#define fil0fil_h
#include "univ.i"
#include "dict0types.h"
#include "fil0types.h"
#include "log0recv.h"
#include "page0size.h"
#ifndef UNIV_HOTBACKUP
#include "ibuf0types.h"
#endif /* !UNIV_HOTBACKUP */
#include "ut0new.h"
#include "sql/dd/object_id.h"
#include <list>
#include <vector>
/** This tablespace name is used internally during file discovery to open a
general tablespace before the data dictionary is recovered and available. */
static constexpr char general_space_name[] = "innodb_general";
/** This tablespace name is used as the prefix for implicit undo tablespaces
and during file discovery to open an undo tablespace before the DD is
recovered and available. */
static constexpr char undo_space_name[] = "innodb_undo";
extern volatile bool recv_recovery_on;
#ifdef UNIV_HOTBACKUP
#include <unordered_set>
using Dir_set = std::unordered_set<std::string>;
extern Dir_set rem_gen_ts_dirs;
extern bool replay_in_datadir;
#endif /* UNIV_HOTBACKUP */
// Forward declaration
struct trx_t;
class page_id_t;
using Filenames = std::vector<std::string, ut_allocator<std::string>>;
using Space_ids = std::vector<space_id_t, ut_allocator<space_id_t>>;
/** File types */
enum fil_type_t : uint8_t {
/** temporary tablespace (temporary undo log or tables) */
FIL_TYPE_TEMPORARY = 1,
/** a tablespace that is being imported (no logging until finished) */
FIL_TYPE_IMPORT = 2,
/** persistent tablespace (for system, undo log or tables) */
FIL_TYPE_TABLESPACE = 4,
/** redo log covering changes to files of FIL_TYPE_TABLESPACE */
FIL_TYPE_LOG = 8
};
/** Result of comparing a path. */
enum class Fil_state {
/** The path matches what was found during the scan. */
MATCHES,
/** No MLOG_FILE_DELETE record and the file could not be found. */
MISSING,
/** A MLOG_FILE_DELETE was found, file was deleted. */
DELETED,
/** Space ID matches but the paths don't match. */
MOVED,
/** Tablespace and/or filename was renamed. The DDL log will handle
this case. */
RENAMED
};
/** Check if fil_type is any of FIL_TYPE_TEMPORARY, FIL_TYPE_IMPORT
or FIL_TYPE_TABLESPACE.
@param[in] type variable of type fil_type_t
@return true if any of FIL_TYPE_TEMPORARY, FIL_TYPE_IMPORT
or FIL_TYPE_TABLESPACE */
inline bool fil_type_is_data(fil_type_t type) {
return (type == FIL_TYPE_TEMPORARY || type == FIL_TYPE_IMPORT ||
type == FIL_TYPE_TABLESPACE);
}
struct fil_space_t;
/** File node of a tablespace or the log data space */
struct fil_node_t {
using List_node = UT_LIST_NODE_T(fil_node_t);
/** tablespace containing this file */
fil_space_t *space;
/** file name; protected by Fil_shard::m_mutex and log_sys->mutex. */
char *name;
/** whether this file is open. Note: We set the is_open flag after
we increase the write the MLOG_FILE_OPEN record to redo log. Therefore
we increment the in_use reference count before setting the OPEN flag. */
bool is_open;
/** file handle (valid if is_open) */
pfs_os_file_t handle;
/** event that groups and serializes calls to fsync */
os_event_t sync_event;
/** whether the file actually is a raw device or disk partition */
bool is_raw_disk;
/** size of the file in database pages (0 if not known yet);
the possible last incomplete megabyte may be ignored
if space->id == 0 */
page_no_t size;
/** Size of the file when last flushed, used to force the flush when file
grows to keep the filesystem metadata synced when using O_DIRECT_NO_FSYNC */
page_no_t flush_size;
/** initial size of the file in database pages;
FIL_IBD_FILE_INITIAL_SIZE by default */
page_no_t init_size;
/** maximum size of the file in database pages */
page_no_t max_size;
/** count of pending i/o's; is_open must be true if nonzero */
size_t n_pending;
/** count of pending flushes; is_open must be true if nonzero */
size_t n_pending_flushes;
/** e.g., when a file is being extended or just opened. */
size_t in_use;
/** number of writes to the file since the system was started */
int64_t modification_counter;
/** the modification_counter of the latest flush to disk */
int64_t flush_counter;
/** link to the fil_system->LRU list (keeping track of open files) */
List_node LRU;
/** whether the file system of this file supports PUNCH HOLE */
bool punch_hole;
/** block size to use for punching holes */
size_t block_size;
/** whether atomic write is enabled for this file */
bool atomic_write;
/** FIL_NODE_MAGIC_N */
size_t magic_n;
};
/* Type of (un)encryption operation in progress for Tablespace. */
enum encryption_op_type { ENCRYPTION = 1, UNENCRYPTION = 2, NONE };
/** Tablespace or log data space */
struct fil_space_t {
using List_node = UT_LIST_NODE_T(fil_space_t);
using Files = std::vector<fil_node_t, ut_allocator<fil_node_t>>;
/** Tablespace name */
char *name;
/** Tablespace ID */
space_id_t id;
/** true if we want to rename the .ibd file of tablespace and
want to stop temporarily posting of new i/o requests on the file */
bool stop_ios;
/** We set this true when we start deleting a single-table
tablespace. When this is set following new ops are not allowed:
* read IO request
* ibuf merge
* file flush
Note that we can still possibly have new write operations because we
don't check this flag when doing flush batches. */
bool stop_new_ops;
#ifdef UNIV_DEBUG
/** Reference count for operations who want to skip redo log in
the file space in order to make fsp_space_modify_check pass. */
ulint redo_skipped_count;
#endif /* UNIV_DEBUG */
/** Purpose */
fil_type_t purpose;
/** Files attached to this tablespace. Note: Only the system tablespace
can have multiple files, this is a legacy issue. */
Files files;
/** Tablespace file size in pages; 0 if not known yet */
page_no_t size;
/** FSP_SIZE in the tablespace header; 0 if not known yet */
page_no_t size_in_header;
/** Length of the FSP_FREE list */
uint32_t free_len;
/** Contents of FSP_FREE_LIMIT */
page_no_t free_limit;
/** Tablespace flags; see fsp_flags_is_valid() and
page_size_t(ulint) (constructor).
This is protected by space->latch and tablespace MDL */
uint32_t flags;
/** Number of reserved free extents for ongoing operations like
B-tree page split */
uint32_t n_reserved_extents;
/** This is positive when flushing the tablespace to disk;
dropping of the tablespace is forbidden if this is positive */
uint32_t n_pending_flushes;
/** This is positive when we have pending operations against this
tablespace. The pending operations can be ibuf merges or lock
validation code trying to read a block. Dropping of the tablespace
is forbidden if this is positive. Protected by Fil_shard::m_mutex. */
uint32_t n_pending_ops;
#ifndef UNIV_HOTBACKUP
/** Latch protecting the file space storage allocation */
rw_lock_t latch;
#endif /* !UNIV_HOTBACKUP */
/** List of spaces with at least one unflushed file we have
written to */
List_node unflushed_spaces;
/** true if this space is currently in unflushed_spaces */
bool is_in_unflushed_spaces;
/** Compression algorithm */
Compression::Type compression_type;
/** Encryption algorithm */
Encryption::Type encryption_type;
/** Encrypt key */
byte encryption_key[ENCRYPTION_KEY_LEN];
/** Encrypt key length*/
ulint encryption_klen;
/** Encrypt initial vector */
byte encryption_iv[ENCRYPTION_KEY_LEN];
/** Encryption is in progress */
encryption_op_type encryption_op_in_progress;
/** Release the reserved free extents.
@param[in] n_reserved number of reserved extents */
void release_free_extents(ulint n_reserved);
/** FIL_SPACE_MAGIC_N */
ulint magic_n;
/** System tablespace */
static fil_space_t *s_sys_space;
/** Redo log tablespace */
static fil_space_t *s_redo_space;
/** Lizard tablespace */
static fil_space_t *s_lizard_space;
#ifdef UNIV_DEBUG
/** Print the extent descriptor pages of this tablespace into
the given output stream.
@param[in] out the output stream.
@return the output stream. */
std::ostream &print_xdes_pages(std::ostream &out) const;
/** Print the extent descriptor pages of this tablespace into
the given file.
@param[in] filename the output file name. */
void print_xdes_pages(const char *filename) const;
#endif /* UNIV_DEBUG */
};
/** Value of fil_space_t::magic_n */
constexpr size_t FIL_SPACE_MAGIC_N = 89472;
/** Value of fil_node_t::magic_n */
constexpr size_t FIL_NODE_MAGIC_N = 89389;
/** Common InnoDB file extentions */
enum ib_file_suffix { NO_EXT = 0, IBD = 1, CFG = 2, CFP = 3, IBT = 4, IBU = 5 };
extern const char *dot_ext[];
#define DOT_IBD dot_ext[IBD]
#define DOT_CFG dot_ext[CFG]
#define DOT_CFP dot_ext[CFP]
#define DOT_IBT dot_ext[IBT]
#define DOT_IBU dot_ext[IBU]
#ifdef _WIN32
/* Initialization of m_abs_path() produces warning C4351:
"new behavior: elements of array '...' will be default initialized."
See https://msdn.microsoft.com/en-us/library/1ywe7hcy.aspx */
#pragma warning(disable : 4351)
#endif /* _WIN32 */
/** Wrapper for a path to a directory that may or may not exist. */
class Fil_path {
public:
/** schema '/' table separator */
static constexpr auto DB_SEPARATOR = '/';
/** OS specific path separator. */
static constexpr auto OS_SEPARATOR = OS_PATH_SEPARATOR;
/** Directory separators that are supported. */
static constexpr auto SEPARATOR = "\\/";
#ifdef _WIN32
static constexpr auto DOT_SLASH = ".\\";
static constexpr auto DOT_DOT_SLASH = "..\\";
static constexpr auto SLASH_DOT_DOT_SLASH = "\\..\\";
#else
static constexpr auto DOT_SLASH = "./";
static constexpr auto DOT_DOT_SLASH = "../";
static constexpr auto SLASH_DOT_DOT_SLASH = "/../";
#endif /* _WIN32 */
/** Various types of file paths. */
enum path_type { absolute, relative, file_name_only, invalid };
/** Default constructor. Defaults to MySQL_datadir_path. */
Fil_path();
/** Constructor
@param[in] path Path, not necessarily NUL terminated
@param[in] len Length of path
@param[in] normalize_path If false, it's the callers responsibility to
ensure that the path is normalized. */
explicit Fil_path(const char *path, size_t len, bool normalize_path = false);
/** Constructor
@param[in] path Path, not necessarily NUL terminated
@param[in] normalize_path If false, it's the callers responsibility to
ensure that the path is normalized. */
explicit Fil_path(const char *path, bool normalize_path = false);
/** Constructor
@param[in] path pathname (may also include the file basename)
@param[in] normalize_path If false, it's the callers responsibility to
ensure that the path is normalized. */
explicit Fil_path(const std::string &path, bool normalize_path = false);
/** Implicit type conversion
@return pointer to m_path.c_str() */
operator const char *() const { return (m_path.c_str()); }
/** Explicit type conversion
@return pointer to m_path.c_str() */
const char *operator()() const { return (m_path.c_str()); }
/** @return the value of m_path */
const std::string &path() const MY_ATTRIBUTE((warn_unused_result)) {
return (m_path);
}
/** @return the length of m_path */
size_t len() const MY_ATTRIBUTE((warn_unused_result)) {
return (m_path.length());
}
/** @return the length of m_abs_path */
size_t abs_len() const MY_ATTRIBUTE((warn_unused_result)) {
return (m_abs_path.length());
}
/** Determine if this path is equal to the other path.
@param[in] lhs Path to compare to
@return true if the paths are the same */
bool operator==(const Fil_path &lhs) const {
return (m_path.compare(lhs.m_path));
}
/** Check if m_path is the same as path.
@param[in] path directory path to compare to
@return true if m_path is the same as path */
bool is_same_as(const std::string &path) const
MY_ATTRIBUTE((warn_unused_result)) {
if (m_path.empty() || path.empty()) {
return (false);
}
return (m_abs_path == get_real_path(path));
}
/** Check if m_path is the parent of name.
@param[in] name Path to compare to
@return true if m_path is an ancestor of name */
bool is_ancestor(const std::string &name) const
MY_ATTRIBUTE((warn_unused_result)) {
if (m_path.empty() || name.empty()) {
return (false);
}
return (is_ancestor(m_abs_path, get_real_path(name)));
}
/** Check if m_path is the parent of other.m_path.
@param[in] other Path to compare to
@return true if m_path is an ancestor of name */
bool is_ancestor(const Fil_path &other) const
MY_ATTRIBUTE((warn_unused_result)) {
if (m_path.empty() || other.m_path.empty()) {
return (false);
}
return (is_ancestor(m_abs_path, other.m_abs_path));
}
/** @return true if m_path exists and is a file. */
bool is_file_and_exists() const MY_ATTRIBUTE((warn_unused_result));
/** @return true if m_path exists and is a directory. */
bool is_directory_and_exists() const MY_ATTRIBUTE((warn_unused_result));
/** Return the absolute path */
const std::string &abs_path() const MY_ATTRIBUTE((warn_unused_result)) {
return (m_abs_path);
}
/** This validation is only for ':'.
@return true if the path is valid. */
bool is_valid() const MY_ATTRIBUTE((warn_unused_result));
/** Determine if m_path contains a circular section like "/anydir/../"
Fil_path::normalize() must be run before this.
@return true if a circular section if found, false if not */
bool is_circular() const MY_ATTRIBUTE((warn_unused_result));
/** Determine if the file or directory is considered HIDDEN.
Most file systems identify the HIDDEN attribute by a '.' preceeding the
basename. On Windows, a HIDDEN path is identified by a file attribute.
We will use the preceeding '.' to indicate a HIDDEN attribute on ALL
file systems so that InnoDB tablespaces and their directory structure
remain portable.
@param[in] path The full or relative path of a file or directory.
@return true if the directory or path is HIDDEN. */
static bool is_hidden(std::string path);
#ifdef _WIN32
/** Use the WIN32_FIND_DATA struncture to determine if the file or
directory is HIDDEN. Consider a SYSTEM attribute also as an indicator
that it is HIDDEN to InnoDB.
@param[in] dirent A directory entry obtained from a call to FindFirstFile()
or FindNextFile()
@return true if the directory or path is HIDDEN. */
static bool is_hidden(WIN32_FIND_DATA &dirent);
#endif /* WIN32 */
/** Remove quotes e.g., 'a;b' or "a;b" -> a;b.
Assumes matching quotes.
@return pathspec with the quotes stripped */
static std::string parse(const char *pathspec) {
std::string path(pathspec);
ut_ad(!path.empty());
if (path.size() >= 2 && (path.front() == '\'' || path.back() == '"')) {
path.erase(0, 1);
if (path.back() == '\'' || path.back() == '"') {
path.erase(path.size() - 1);
}
}
return (path);
}
/** Convert the paths into absolute paths and compare them. The
paths to compare must be valid paths, otherwise the result is
undefined.
@param[in] lhs Filename to compare
@param[in] rhs Filename to compare
@return true if they are the same */
static bool equal(const std::string &lhs, const std::string &rhs)
MY_ATTRIBUTE((warn_unused_result)) {
Fil_path path1(lhs);
Fil_path path2(rhs);
return (path1.abs_path().compare(path2.abs_path()) == 0);
}
/** @return true if the path is an absolute path. */
bool is_relative_path() const MY_ATTRIBUTE((warn_unused_result)) {
return (type_of_path(m_path) == relative);
}
/** @return true if the path is an absolute path. */
bool is_absolute_path() const MY_ATTRIBUTE((warn_unused_result)) {
return (type_of_path(m_path) == absolute);
}
/** Determine if a path is an absolute path or not.
@param[in] path OS directory or file path to evaluate
@retval true if an absolute path
@retval false if a relative path */
static bool is_absolute_path(const std::string &path) {
return (type_of_path(path) == absolute);
}
/** Determine if a path is an absolute path or not.
@param[in] path OS directory or file path to evaluate
@retval true if an absolute path
@retval false if a relative path */
static path_type type_of_path(const std::string &path)
MY_ATTRIBUTE((warn_unused_result)) {
if (path.empty()) {
return (invalid);
}
/* The most likely type is a file name only with no separators. */
if (path.find('\\', 0) == std::string::npos &&
path.find('/', 0) == std::string::npos) {
return (file_name_only);
}
/* Any string that starts with an OS_SEPARATOR is
an absolute path. This includes any OS and even
paths like "\\Host\share" on Windows. */
if (path.at(0) == '\\' || path.at(0) == '/') {
return (absolute);
}
#ifdef _WIN32
/* Windows may have an absolute path like 'A:\' */
if (path.length() >= 3 && isalpha(path.at(0)) && path.at(1) == ':' &&
(path.at(2) == '\\' || path.at(2) == '/')) {
return (absolute);
}
#endif /* _WIN32 */
/* Since it contains separators and is not an absolute path,
it must be a relative path. */
return (relative);
}
/* Check if the path is prefixed with pattern.
@return true if prefix matches */
static bool has_prefix(const std::string &path, const std::string prefix)
MY_ATTRIBUTE((warn_unused_result)) {
return (path.size() >= prefix.size() &&
std::equal(prefix.begin(), prefix.end(), path.begin()));
}
/** Normalize a directory path for the current OS:
On Windows, we convert '/' to '\', else we convert '\' to '/'.
@param[in,out] path Directory and file path */
static void normalize(std::string &path) {
for (auto &c : path) {
if (c == OS_PATH_SEPARATOR_ALT) {
c = OS_SEPARATOR;
}
}
}
/** Normalize a directory path for the current OS:
On Windows, we convert '/' to '\', else we convert '\' to '/'.
@param[in,out] path A NUL terminated path */
static void normalize(char *path) {
for (auto ptr = path; *ptr; ++ptr) {
if (*ptr == OS_PATH_SEPARATOR_ALT) {
*ptr = OS_SEPARATOR;
}
}
}
/** @return true if the path exists and is a file . */
static os_file_type_t get_file_type(const std::string &path)
MY_ATTRIBUTE((warn_unused_result));
/** Get the real path for a directory or a file name, useful for
comparing symlinked files.
@param[in] path Directory or filename
@return the absolute path of dir + filename, or "" on error. */
static std::string get_real_path(const std::string &path)
MY_ATTRIBUTE((warn_unused_result));
/** Check if lhs is the ancestor of rhs. If the two paths are the
same it will return false.
@param[in] lhs Parent path to check
@param[in] rhs Descendent path to check
@return true if lhs is an ancestor of rhs */
static bool is_ancestor(const std::string &lhs, const std::string &rhs)
MY_ATTRIBUTE((warn_unused_result)) {
if (lhs.empty() || rhs.empty() || rhs.length() <= lhs.length()) {
return (false);
}
return (std::equal(lhs.begin(), lhs.end(), rhs.begin()));
}
/** Check if the name is an undo tablespace name.
@param[in] name Tablespace name
@return true if it is an undo tablespace name */
static bool is_undo_tablespace_name(const std::string &name)
MY_ATTRIBUTE((warn_unused_result));
/** Check if the file has the the specified suffix
@param[in] sfx suffix to look for
@param[in] path Filename to check
@return true if it has the the ".ibd" suffix. */
static bool has_suffix(ib_file_suffix sfx, const std::string &path) {
const auto suffix = dot_ext[sfx];
size_t len = strlen(suffix);
return (path.size() >= len &&
path.compare(path.size() - len, len, suffix) == 0);
}
/** Check if a character is a path separator ('\' or '/')
@param[in] c Character to check
@return true if it is a separator */
static bool is_separator(char c) { return (c == '\\' || c == '/'); }
/** Allocate and build a file name from a path, a table or
tablespace name and a suffix.
@param[in] path_in nullptr or the direcory path or
the full path and filename
@param[in] name_in nullptr if path is full, or
Table/Tablespace name
@param[in] ext the file extension to use
@param[in] trim whether last name on the path should
be trimmed
@return own: file name; must be freed by ut_free() */
static char *make(const std::string &path_in, const std::string &name_in,
ib_file_suffix ext, bool trim = false)
MY_ATTRIBUTE((warn_unused_result));
/** Allocate and build a CFG file name from a path.
@param[in] path_in Full path to the filename
@return own: file name; must be freed by ut_free() */
static char *make_cfg(const std::string &path_in)
MY_ATTRIBUTE((warn_unused_result)) {
return (make(path_in, "", CFG));
}
/** Allocate and build a CFP file name from a path.
@param[in] path_in Full path to the filename
@return own: file name; must be freed by ut_free() */
static char *make_cfp(const std::string &path_in)
MY_ATTRIBUTE((warn_unused_result)) {
return (make(path_in, "", CFP));
}
/** Allocate and build a file name from a path, a table or
tablespace name and a suffix.
@param[in] path_in nullptr or the direcory path or
the full path and filename
@param[in] name_in nullptr if path is full, or
Table/Tablespace name
@return own: file name; must be freed by ut_free() */
static char *make_ibd(const std::string &path_in, const std::string &name_in)
MY_ATTRIBUTE((warn_unused_result)) {
return (make(path_in, name_in, IBD));
}
/** Allocate and build a file name from a path, a table or
tablespace name and a suffix.
@param[in] name_in Table/Tablespace name
@return own: file name; must be freed by ut_free() */
static char *make_ibd_from_table_name(const std::string &name_in)
MY_ATTRIBUTE((warn_unused_result)) {
return (make("", name_in, IBD));
}
/** Create an IBD path name after replacing the basename in an old path
with a new basename. The old_path is a full path name including the
extension. The tablename is in the normal form "schema/tablename".
@param[in] path_in Pathname
@param[in] name_in Contains new base name
@return new full pathname */
static std::string make_new_ibd(const std::string &path_in,
const std::string &name_in)
MY_ATTRIBUTE((warn_unused_result));
/** This function reduces a null-terminated full remote path name
into the path that is sent by MySQL for DATA DIRECTORY clause.
It replaces the 'databasename/tablename.ibd' found at the end of the
path with just 'tablename'.
Since the result is always smaller than the path sent in, no new
memory is allocated. The caller should allocate memory for the path
sent in. This function manipulates that path in place. If the path
format is not as expected, set data_dir_path to "" and return.
The result is used to inform a SHOW CREATE TABLE command.
@param[in,out] data_dir_path Full path/data_dir_path */
static void make_data_dir_path(char *data_dir_path);
/** @return the null path */
static const Fil_path &null() MY_ATTRIBUTE((warn_unused_result)) {
return (s_null_path);
}
#ifndef UNIV_HOTBACKUP
/** Check if the filepath provided is in a valid placement.
1) File-per-table must be in a dir named for the schema.
2) File-per-table must not be in the datadir.
3) General tablespace must no be under the datadir.
@param[in] space_name tablespace name
@param[in] path filepath to validate
@retval true if the filepath is a valid datafile location */
static bool is_valid_location(const char *space_name,
const std::string &path);
/** Convert filename to the file system charset format.
@param[in,out] name Filename to convert */
static void convert_to_filename_charset(std::string &name);
/** Convert to lower case using the file system charset.
@param[in,out] path Filepath to convert */
static void convert_to_lower_case(std::string &path);
#endif /* !UNIV_HOTBACKUP */
protected:
/** Path to a file or directory. */
std::string m_path;
/** A full absolute path to the same file. */
std::string m_abs_path;
/** Empty (null) path. */
static Fil_path s_null_path;
public:
/** Check if the name is an lizard tablespace name.
@param[in] name Tablespace name
@return true if it is an lizard tablespace name */
static bool is_lizard_tablespace_name(const std::string &name);
};
/** The MySQL server --datadir value */
extern Fil_path MySQL_datadir_path;
/** Initial size of a single-table tablespace in pages */
constexpr size_t FIL_IBD_FILE_INITIAL_SIZE = 7;
constexpr size_t FIL_IBT_FILE_INITIAL_SIZE = 5;
/** An empty tablespace (CREATE TABLESPACE) has minimum
of 4 pages and an empty CREATE TABLE (file_per_table) has 6 pages.
Minimum of these two is 4 */
constexpr size_t FIL_IBD_FILE_INITIAL_SIZE_5_7 = 4;
/** 'null' (undefined) page offset in the context of file spaces */
constexpr page_no_t FIL_NULL = std::numeric_limits<page_no_t>::max();
/** Maximum Page Number, one less than FIL_NULL */
constexpr page_no_t PAGE_NO_MAX = std::numeric_limits<page_no_t>::max() - 1;
/** Unknown space id */
constexpr space_id_t SPACE_UNKNOWN = std::numeric_limits<space_id_t>::max();
/* Space address data type; this is intended to be used when
addresses accurate to a byte are stored in file pages. If the page part
of the address is FIL_NULL, the address is considered undefined. */
/** 'type' definition in C: an address stored in a file page is a
string of bytes */
using fil_faddr_t = byte;
/** File space address */
struct fil_addr_t {
/* Default constructor */
fil_addr_t() : page(FIL_NULL), boffset(0) {}
/** Constructor
@param[in] p Logical page number
@param[in] boff Offset within the page */
fil_addr_t(page_no_t p, uint32_t boff) : page(p), boffset(boff) {}
/** Compare to instances
@param[in] rhs Instance to compare with
@return true if the page number and page offset are equal */
bool is_equal(const fil_addr_t &rhs) const {
return (page == rhs.page && boffset == rhs.boffset);
}
/** Check if the file address is null.
@return true if null */
bool is_null() const { return (page == FIL_NULL && boffset == 0); }
/** Print a string representation.
@param[in,out] out Stream to write to */
std::ostream &print(std::ostream &out) const {
out << "[fil_addr_t: page=" << page << ", boffset=" << boffset << "]";
return (out);
}
/** Page number within a space */
page_no_t page;
/** Byte offset within the page */
uint32_t boffset;
};
/* For printing fil_addr_t to a stream.
@param[in,out] out Stream to write to
@param[in] obj fil_addr_t instance to write */
inline std::ostream &operator<<(std::ostream &out, const fil_addr_t &obj) {
return (obj.print(out));
}
/** The null file address */
extern fil_addr_t fil_addr_null;
using page_type_t = uint16_t;
/** File page types (values of FIL_PAGE_TYPE) @{ */
/** B-tree node */
constexpr page_type_t FIL_PAGE_INDEX = 17855;
/** R-tree node */
constexpr page_type_t FIL_PAGE_RTREE = 17854;
/** Tablespace SDI Index page */
constexpr page_type_t FIL_PAGE_SDI = 17853;
/** Undo log page */
constexpr page_type_t FIL_PAGE_UNDO_LOG = 2;
/** Index node */
constexpr page_type_t FIL_PAGE_INODE = 3;
/** Insert buffer free list */
constexpr page_type_t FIL_PAGE_IBUF_FREE_LIST = 4;
/* File page types introduced in MySQL/InnoDB 5.1.7 */
/** Freshly allocated page */
constexpr page_type_t FIL_PAGE_TYPE_ALLOCATED = 0;
/** Insert buffer bitmap */
constexpr page_type_t FIL_PAGE_IBUF_BITMAP = 5;
/** System page */
constexpr page_type_t FIL_PAGE_TYPE_SYS = 6;
/** Transaction system data */
constexpr page_type_t FIL_PAGE_TYPE_TRX_SYS = 7;
/** File space header */
constexpr page_type_t FIL_PAGE_TYPE_FSP_HDR = 8;
/** Extent descriptor page */
constexpr page_type_t FIL_PAGE_TYPE_XDES = 9;
/** Uncompressed BLOB page */
constexpr page_type_t FIL_PAGE_TYPE_BLOB = 10;
/** First compressed BLOB page */
constexpr page_type_t FIL_PAGE_TYPE_ZBLOB = 11;
/** Subsequent compressed BLOB page */
constexpr page_type_t FIL_PAGE_TYPE_ZBLOB2 = 12;
/** In old tablespaces, garbage in FIL_PAGE_TYPE is replaced with
this value when flushing pages. */
constexpr page_type_t FIL_PAGE_TYPE_UNKNOWN = 13;
/** Compressed page */
constexpr page_type_t FIL_PAGE_COMPRESSED = 14;
/** Encrypted page */
constexpr page_type_t FIL_PAGE_ENCRYPTED = 15;
/** Compressed and Encrypted page */
constexpr page_type_t FIL_PAGE_COMPRESSED_AND_ENCRYPTED = 16;
/** Encrypted R-tree page */
constexpr page_type_t FIL_PAGE_ENCRYPTED_RTREE = 17;
/** Uncompressed SDI BLOB page */
constexpr page_type_t FIL_PAGE_SDI_BLOB = 18;
/** Commpressed SDI BLOB page */
constexpr page_type_t FIL_PAGE_SDI_ZBLOB = 19;
/** Available for future use */
constexpr page_type_t FIL_PAGE_TYPE_UNUSED = 20;
/** Rollback Segment Array page */
constexpr page_type_t FIL_PAGE_TYPE_RSEG_ARRAY = 21;
/** Index pages of uncompressed LOB */
constexpr page_type_t FIL_PAGE_TYPE_LOB_INDEX = 22;
/** Data pages of uncompressed LOB */
constexpr page_type_t FIL_PAGE_TYPE_LOB_DATA = 23;
/** The first page of an uncompressed LOB */
constexpr page_type_t FIL_PAGE_TYPE_LOB_FIRST = 24;
/** The first page of a compressed LOB */
constexpr page_type_t FIL_PAGE_TYPE_ZLOB_FIRST = 25;
/** Data pages of compressed LOB */
constexpr page_type_t FIL_PAGE_TYPE_ZLOB_DATA = 26;
/** Index pages of compressed LOB. This page contains an array of
z_index_entry_t objects.*/
constexpr page_type_t FIL_PAGE_TYPE_ZLOB_INDEX = 27;
/** Fragment pages of compressed LOB. */
constexpr page_type_t FIL_PAGE_TYPE_ZLOB_FRAG = 28;
/** Index pages of fragment pages (compressed LOB). */
constexpr page_type_t FIL_PAGE_TYPE_ZLOB_FRAG_ENTRY = 29;
/** Used by i_s.cc to index into the text description. */
constexpr page_type_t FIL_PAGE_TYPE_LAST = FIL_PAGE_TYPE_ZLOB_FRAG_ENTRY;
/** Check whether the page type is sys */
#define fil_page_type_is_sys(page_type) \
(page_type == FIL_PAGE_TYPE_SYS || page_type == FIL_PAGE_TYPE_TRX_SYS)
/** Check whether the page type is index (Btree or Rtree or SDI) type */
#define fil_page_type_is_index(page_type) \
(page_type == FIL_PAGE_INDEX || page_type == FIL_PAGE_SDI || \
page_type == FIL_PAGE_RTREE)
/** Check whether the page is index page (either regular Btree index or Rtree
index */
#define fil_page_index_page_check(page) \
fil_page_type_is_index(fil_page_get_type(page))
/** The number of fsyncs done to the log */
extern ulint fil_n_log_flushes;
/** Number of pending redo log flushes */
extern ulint fil_n_pending_log_flushes;
/** Number of pending tablespace flushes */
extern ulint fil_n_pending_tablespace_flushes;
/** Number of files currently open */
extern ulint fil_n_file_opened;
/** Look up a tablespace.
The caller should hold an InnoDB table lock or a MDL that prevents
the tablespace from being dropped during the operation,
or the caller should be in single-threaded crash recovery mode
(no user connections that could drop tablespaces).
If this is not the case, fil_space_acquire() and fil_space_release()
should be used instead.
@param[in] space_id Tablespace ID
@return tablespace, or nullptr if not found */
fil_space_t *fil_space_get(space_id_t space_id)
MY_ATTRIBUTE((warn_unused_result));
#ifndef UNIV_HOTBACKUP
/** Returns the latch of a file space.
@param[in] space_id Tablespace ID
@return latch protecting storage allocation */
rw_lock_t *fil_space_get_latch(space_id_t space_id)
MY_ATTRIBUTE((warn_unused_result));
#ifdef UNIV_DEBUG
/** Gets the type of a file space.
@param[in] space_id Tablespace ID
@return file type */
fil_type_t fil_space_get_type(space_id_t space_id)
MY_ATTRIBUTE((warn_unused_result));
#endif /* UNIV_DEBUG */
/** Note that a tablespace has been imported.
It is initially marked as FIL_TYPE_IMPORT so that no logging is
done during the import process when the space ID is stamped to each page.
Now we change it to FIL_SPACE_TABLESPACE to start redo and undo logging.
NOTE: temporary tablespaces are never imported.
@param[in] space_id Tablespace ID */
void fil_space_set_imported(space_id_t space_id);
#endif /* !UNIV_HOTBACKUP */
/** 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 enabled
@param[in] max_pages maximum number of pages in file
@return pointer to the file name
@retval nullptr if error */
char *fil_node_create(const char *name, page_no_t size, fil_space_t *space,
bool is_raw, bool atomic_write,
page_no_t max_pages = PAGE_NO_MAX)
MY_ATTRIBUTE((warn_unused_result));
/** Create a space memory object and put it to the fil_system hash table.
The tablespace name is independent from the tablespace file-name.
Error messages are issued to the server log.
@param[in] name Tablespace name
@param[in] space_id Tablespace ID
@param[in] flags tablespace flags
@param[in] purpose tablespace purpose
@return pointer to created tablespace, to be filled in with fil_node_create()
@retval nullptr on failure (such as when the same tablespace exists) */
fil_space_t *fil_space_create(const char *name, space_id_t space_id,
uint32_t flags, fil_type_t purpose)
MY_ATTRIBUTE((warn_unused_result));
/** Assigns a new space id for a new single-table tablespace.
This works simply by incrementing the global counter. If 4 billion id's
is not enough, we may need to recycle id's.
@param[in,out] space_id New space ID
@return true if assigned, false if not */
bool fil_assign_new_space_id(space_id_t *space_id)
MY_ATTRIBUTE((warn_unused_result));
/** Returns the path from the first fil_node_t found with this space ID.
The caller is responsible for freeing the memory allocated here for the
value returned.
@param[in] space_id Tablespace ID
@return own: A copy of fil_node_t::path, nullptr if space ID is zero
or not found. */
char *fil_space_get_first_path(space_id_t space_id)
MY_ATTRIBUTE((warn_unused_result));
/** Returns the size of the space in pages. The tablespace must be cached
in the memory cache.
@param[in] space_id Tablespace ID
@return space size, 0 if space not found */
page_no_t fil_space_get_size(space_id_t space_id)
MY_ATTRIBUTE((warn_unused_result));
/** Returns the flags of the space. The tablespace must be cached
in the memory cache.
@param[in] space_id Tablespace ID for which to get the flags
@return flags, ULINT_UNDEFINED if space not found */
uint32_t fil_space_get_flags(space_id_t space_id)
MY_ATTRIBUTE((warn_unused_result));
/** Sets the flags of the tablespace. The tablespace must be locked
in MDL_EXCLUSIVE MODE.
@param[in] space tablespace in-memory struct
@param[in] flags tablespace flags */
void fil_space_set_flags(fil_space_t *space, uint32_t flags);
/** Open each file of a tablespace if not already open.
@param[in] space_id Tablespace ID
@retval true if all file nodes were opened
@retval false on failure */
bool fil_space_open(space_id_t space_id) MY_ATTRIBUTE((warn_unused_result));
/** Close each file of a tablespace if open.
@param[in] space_id Tablespace ID */
void fil_space_close(space_id_t space_id);
/** Returns the page size of the space and whether it is compressed or not.
The tablespace must be cached in the memory cache.
@param[in] space_id Tablespace ID
@param[out] found true if tablespace was found
@return page size */
const page_size_t fil_space_get_page_size(space_id_t space_id, bool *found)
MY_ATTRIBUTE((warn_unused_result));
/** Initializes the tablespace memory cache.
@param[in] max_n_open Max number of open files. */
void fil_init(ulint max_n_open);
/** Initializes the tablespace memory cache. */
void fil_close();
/** Opens all log files and system tablespace data files.
They stay open until the database server shutdown. This should be called
at a server startup after the space objects for the log and the system
tablespace have been created. The purpose of this operation is to make
sure we never run out of file descriptors if we need to read from the
insert buffer or to write to the log. */
void fil_open_log_and_system_tablespace_files();
/** Closes all open files. There must not be any pending i/o's or not flushed
modifications in the files. */
void fil_close_all_files();
/** Closes the redo log files. There must not be any pending i/o's or not
flushed modifications in the files.
@param[in] free_all Whether to free the instances. */
void fil_close_log_files(bool free_all);
/** Iterate over the files in all the tablespaces. */
class Fil_iterator {
public:
using Function = std::function<dberr_t(fil_node_t *)>;
/** For each data file, exclude redo log files.
@param[in] include_log include files, if true
@param[in] f Callback */
template <typename F>
static dberr_t for_each_file(bool include_log, F &&f) {
return (iterate(include_log, [=](fil_node_t *file) { return (f(file)); }));
}
/** Iterate over the spaces and file lists.
@param[in] include_log if true then fetch log files too
@param[in,out] f Callback */
static dberr_t iterate(bool include_log, Function &&f);
};
/** Sets the max tablespace id counter if the given number is bigger than the
previous value.
@param[in] max_id Maximum known tablespace ID */
void fil_set_max_space_id_if_bigger(space_id_t max_id);
#ifndef UNIV_HOTBACKUP
/** Write the flushed LSN to the page header of the first page in the
system tablespace.
@param[in] lsn Flushed LSN
@return DB_SUCCESS or error number */
dberr_t fil_write_flushed_lsn(lsn_t lsn) MY_ATTRIBUTE((warn_unused_result));
#else /* !UNIV_HOTBACKUP */
/** Frees a space object from the tablespace memory cache.
Closes a tablespaces' files but does not delete them.
There must not be any pending i/o's or flushes on the files.
@param[in] space_id Tablespace ID
@return true if success */
bool meb_fil_space_free(space_id_t space_id);
/** Extends all tablespaces to the size stored in the space header. During the
mysqlbackup --apply-log phase we extended the spaces on-demand so that log
records could be applied, but that may have left spaces still too small
compared to the size stored in the space header. */
void meb_extend_tablespaces_to_stored_len();
/** Process a file name passed as an input
@param[in] name absolute path of tablespace file
@param[in] space_id the tablespace ID */
void meb_fil_name_process(const char *name, space_id_t space_id);
#endif /* !UNIV_HOTBACKUP */
/** Acquire a tablespace when it could be dropped concurrently.
Used by background threads that do not necessarily hold proper locks
for concurrency control.
@param[in] space_id Tablespace ID
@return the tablespace, or nullptr if missing or being deleted */
fil_space_t *fil_space_acquire(space_id_t space_id)
MY_ATTRIBUTE((warn_unused_result));
/** Acquire a tablespace that may not exist.
Used by background threads that do not necessarily hold proper locks
for concurrency control.
@param[in] space_id Tablespace ID
@return the tablespace, or nullptr if missing or being deleted */
fil_space_t *fil_space_acquire_silent(space_id_t space_id)
MY_ATTRIBUTE((warn_unused_result));
/** Release a tablespace acquired with fil_space_acquire().
@param[in,out] space Tablespace to release */
void fil_space_release(fil_space_t *space);
/** Fetch the file name opened for a space_id during recovery
from the file map.
@param[in] space_id Undo tablespace ID
@return file name that was opened, empty string if space ID not found. */
std::string fil_system_open_fetch(space_id_t space_id)
MY_ATTRIBUTE((warn_unused_result));
/** Truncate the tablespace to needed size.
@param[in] space_id Id of tablespace to truncate
@param[in] size_in_pages Truncate size.
@return true if truncate was successful. */
bool fil_truncate_tablespace(space_id_t space_id, page_no_t size_in_pages)
MY_ATTRIBUTE((warn_unused_result));
/** Truncate the tablespace to needed size with a new space_id.
@param[in] old_space_id Tablespace ID to truncate
@param[in] new_space_id Tablespace ID to for the new file
@param[in] size_in_pages Truncate size.
@return true if truncate was successful. */
bool fil_replace_tablespace(space_id_t old_space_id, space_id_t new_space_id,
page_no_t size_in_pages)
MY_ATTRIBUTE((warn_unused_result));
/** Closes a single-table tablespace. The tablespace must be cached in the
memory cache. Free all pages used by the tablespace.
@param[in,out] trx Transaction covering the close
@param[in] space_id Tablespace ID
@return DB_SUCCESS or error */
dberr_t fil_close_tablespace(trx_t *trx, space_id_t space_id)
MY_ATTRIBUTE((warn_unused_result));
/** Discards a single-table tablespace. The tablespace must be cached in the
memory cache. Discarding is like deleting a tablespace, but
1. We do not drop the table from the data dictionary;
2. We remove all insert buffer entries for the tablespace immediately;
in DROP TABLE they are only removed gradually in the background;
3. When the user does IMPORT TABLESPACE, the tablespace will have the
same id as it originally had.
4. Free all the pages in use by the tablespace if rename=true.
@param[in] space_id Tablespace ID
@return DB_SUCCESS or error */
dberr_t fil_discard_tablespace(space_id_t space_id)
MY_ATTRIBUTE((warn_unused_result));
/** 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.
@param[in] space_id Tablespace ID
@param[in] old_path Old filepath
@param[in] new_path New filepath
@param[in] is_discarded Whether the tablespace is discarded
@return innodb error code */
dberr_t fil_rename_tablespace_check(space_id_t space_id, const char *old_path,
const char *new_path, bool is_discarded)
MY_ATTRIBUTE((warn_unused_result));
/** Rename a single-table tablespace.
The tablespace must exist in the memory cache.
@param[in] space_id Tablespace ID
@param[in] old_path Old file name
@param[in] new_name New tablespace name in the schema/name format
@param[in] new_path_in New file name, or nullptr if it is located in
The normal data directory
@return InnoDB error code */
dberr_t fil_rename_tablespace(space_id_t space_id, const char *old_path,
const char *new_name, const char *new_path_in)
MY_ATTRIBUTE((warn_unused_result));
/** Create a tablespace file.
@param[in] space_id Tablespace ID
@param[in] name Tablespace name in dbname/tablename format.
For general tablespaces, the 'dbname/' part
may be missing.
@param[in] path Path and filename of the datafile to create.
@param[in] flags Tablespace flags
@param[in] size Initial size of the tablespace file in pages,
must be >= FIL_IBD_FILE_INITIAL_SIZE
@return DB_SUCCESS or error code */
dberr_t fil_ibd_create(space_id_t space_id, const char *name, const char *path,
uint32_t flags, page_no_t size)
MY_ATTRIBUTE((warn_unused_result));
/** Create a session temporary tablespace (IBT) file.
@param[in] space_id Tablespace ID
@param[in] name Tablespace name
@param[in] path Path and filename of the datafile to create.
@param[in] flags Tablespace flags
@param[in] size Initial size of the tablespace file in pages,
must be >= FIL_IBT_FILE_INITIAL_SIZE
@return DB_SUCCESS or error code */
dberr_t fil_ibt_create(space_id_t space_id, const char *name, const char *path,
uint32_t flags, page_no_t size)
MY_ATTRIBUTE((warn_unused_result));
/** Deletes an IBD tablespace, either general or single-table.
The tablespace must be cached in the memory cache. This will delete the
datafile, fil_space_t & fil_node_t entries from the file_system_t cache.
@param[in] space_id Tablespace ID
@param[in] buf_remove Specify the action to take on the pages
for this table in the buffer pool.
@param[in] new_filepath Rename the original datafile to new_filepath.
@return DB_SUCCESS, DB_TABLESPCE_NOT_FOUND or DB_IO_ERROR */
dberr_t fil_delete_tablespace(space_id_t space_id, buf_remove_t buf_remove,
const char *new_filepath)
MY_ATTRIBUTE((warn_unused_result));
/** Open a single-table tablespace and optionally check the space id is
right in it. If not successful, print an error message to the error log. This
function is used to open a tablespace when we start up mysqld, and also in
IMPORT TABLESPACE.
NOTE that we assume this operation is used either at the database startup
or under the protection of the dictionary mutex, so that two users cannot
race here.
The fil_node_t::handle will not be left open.
@param[in] validate whether we should validate the tablespace
(read the first page of the file and
check that the space id in it matches id)
@param[in] purpose FIL_TYPE_TABLESPACE or FIL_TYPE_TEMPORARY
@param[in] space_id Tablespace ID
@param[in] flags tablespace flags
@param[in] space_name tablespace name of the datafile
If file-per-table, it is the table name in the
databasename/tablename format
@param[in] table_name table name in case need to build filename
from it
@param[in] path_in expected filepath, usually read from dictionary
@param[in] strict whether to report error when open ibd failed
@param[in] old_space whether it is a 5.7 tablespace opening
by upgrade
@return DB_SUCCESS or error code */
dberr_t fil_ibd_open(bool validate, fil_type_t purpose, space_id_t space_id,
uint32_t flags, const char *space_name,
const char *table_name, const char *path_in, bool strict,
bool old_space) MY_ATTRIBUTE((warn_unused_result));
/** Returns true if a matching tablespace exists in the InnoDB tablespace
memory cache.
@param[in] space_id Tablespace ID
@param[in] name Tablespace name used in
fil_space_create().
@param[in] print_err detailed error information to the
error log if a matching tablespace is
not found from memory.
@param[in] adjust_space Whether to adjust spaceid on mismatch
@param[in] heap Heap memory
@param[in] table_id table id
@return true if a matching tablespace exists in the memory cache */
bool fil_space_exists_in_mem(space_id_t space_id, const char *name,
bool print_err, bool adjust_space,
mem_heap_t *heap, table_id_t table_id)
MY_ATTRIBUTE((warn_unused_result));
/** Extends all tablespaces to the size stored in the space header. During the
mysqlbackup --apply-log phase we extended the spaces on-demand so that log
records could be appllied, but that may have left spaces still too small
compared to the size stored in the space header. */
void fil_extend_tablespaces_to_stored_len();
/** Try to extend a tablespace if it is smaller than the specified size.
@param[in,out] space Tablespace ID
@param[in] size desired size in pages
@return whether the tablespace is at least as big as requested */
bool fil_space_extend(fil_space_t *space, page_no_t size)
MY_ATTRIBUTE((warn_unused_result));
/** Tries to reserve free extents in a file space.
@param[in] space_id Tablespace ID
@param[in] n_free_now Number of free extents now
@param[in] n_to_reserve How many one wants to reserve
@return true if succeed */
bool fil_space_reserve_free_extents(space_id_t space_id, ulint n_free_now,
ulint n_to_reserve)
MY_ATTRIBUTE((warn_unused_result));
/** Releases free extents in a file space.
@param[in] space_id Tablespace ID
@param[in] n_reserved How many were reserved */
void fil_space_release_free_extents(space_id_t space_id, ulint n_reserved);
/** Gets the number of reserved extents. If the database is silent, this
number should be zero.
@param[in] space_id Tablespace ID
@return the number of reserved extents */
ulint fil_space_get_n_reserved_extents(space_id_t space_id)
MY_ATTRIBUTE((warn_unused_result));
/** Read or write redo log data (synchronous buffered IO).
@param[in] type IO context
@param[in] page_id where to read or write
@param[in] page_size page size
@param[in] byte_offset remainder of offset in bytes
@param[in] len this must not cross a file boundary;
@param[in,out] buf buffer where to store read data or from where
to write
@retval DB_SUCCESS if all OK */
dberr_t fil_redo_io(const IORequest &type, const page_id_t &page_id,
const page_size_t &page_size, ulint byte_offset, ulint len,
void *buf) MY_ATTRIBUTE((warn_unused_result));
/** Read or write data.
@param[in] type IO context
@param[in] sync If true then do synchronous IO
@param[in] page_id page id
@param[in] page_size page size
@param[in] byte_offset remainder of offset in bytes; in aio this
must be divisible by the OS block size
@param[in] len how many bytes to read or write; this must
not cross a file boundary; in aio this must
be a block size multiple
@param[in,out] buf buffer where to store read data or from where
to write; in aio this must be appropriately
aligned
@param[in] message message for aio handler if !sync, else ignored
@return error code
@retval DB_SUCCESS on success
@retval DB_TABLESPACE_DELETED if the tablespace does not exist */
dberr_t fil_io(const IORequest &type, bool sync, const page_id_t &page_id,
const page_size_t &page_size, ulint byte_offset, ulint len,
void *buf, void *message) MY_ATTRIBUTE((warn_unused_result));
/** Waits for an aio operation to complete. This function is used to write the
handler for completed requests. The aio array of pending requests is divided
into segments (see os0file.cc for more info). The thread specifies which
segment it wants to wait for.
@param[in] segment The number of the segment in the AIO array
to wait for */
void fil_aio_wait(ulint segment);
/** Flushes to disk possible writes cached by the OS. If the space does
not exist or is being dropped, does not do anything.
@param[in] space_id Tablespace ID (this can be a group of log files
or a tablespace of the database) */
void fil_flush(space_id_t space_id);
/** Flush to disk the writes in file spaces of the given type
possibly cached by the OS. */
void fil_flush_file_redo();
/** Flush to disk the writes in file spaces of the given type
possibly cached by the OS.
@param[in] purpose FIL_TYPE_TABLESPACE or FIL_TYPE_LOG, can
be ORred. */
void fil_flush_file_spaces(uint8_t purpose);
#ifdef UNIV_DEBUG
/** Checks the consistency of the tablespace cache.
@return true if ok */
bool fil_validate();
#endif /* UNIV_DEBUG */
/** Returns true if file address is undefined.
@param[in] addr File address to check
@return true if undefined */
bool fil_addr_is_null(const fil_addr_t &addr)
MY_ATTRIBUTE((warn_unused_result));
/** Get the predecessor of a file page.
@param[in] page File page
@return FIL_PAGE_PREV */
page_no_t fil_page_get_prev(const byte *page)
MY_ATTRIBUTE((warn_unused_result));
/** Get the successor of a file page.
@param[in] page File page
@return FIL_PAGE_NEXT */
page_no_t fil_page_get_next(const byte *page)
MY_ATTRIBUTE((warn_unused_result));
/** Sets the file page type.
@param[in,out] page File page
@param[in] type File page type to set */
void fil_page_set_type(byte *page, ulint type);
/** Reset the page type.
Data files created before MySQL 5.1 may contain garbage in FIL_PAGE_TYPE.
In MySQL 3.23.53, only undo log pages and index pages were tagged.
Any other pages were written with uninitialized bytes in FIL_PAGE_TYPE.
@param[in] page_id page number
@param[in,out] page page with invalid FIL_PAGE_TYPE
@param[in] type expected page type
@param[in,out] mtr mini-transaction */
void fil_page_reset_type(const page_id_t &page_id, byte *page, ulint type,
mtr_t *mtr);
/** Get the file page type.
@param[in] page File page
@return page type */
inline page_type_t fil_page_get_type(const byte *page) {
return (static_cast<page_type_t>(mach_read_from_2(page + FIL_PAGE_TYPE)));
}
/** Check (and if needed, reset) the page type.
Data files created before MySQL 5.1 may contain
garbage in the FIL_PAGE_TYPE field.
In MySQL 3.23.53, only undo log pages and index pages were tagged.
Any other pages were written with uninitialized bytes in FIL_PAGE_TYPE.
@param[in] page_id page number
@param[in,out] page page with possibly invalid FIL_PAGE_TYPE
@param[in] type expected page type
@param[in,out] mtr mini-transaction */
inline void fil_page_check_type(const page_id_t &page_id, byte *page,
ulint type, mtr_t *mtr) {
ulint page_type = fil_page_get_type(page);
if (page_type != type) {
fil_page_reset_type(page_id, page, type, mtr);
}
}
/** Check (and if needed, reset) the page type.
Data files created before MySQL 5.1 may contain
garbage in the FIL_PAGE_TYPE field.
In MySQL 3.23.53, only undo log pages and index pages were tagged.
Any other pages were written with uninitialized bytes in FIL_PAGE_TYPE.
@param[in,out] block block with possibly invalid FIL_PAGE_TYPE
@param[in] type expected page type
@param[in,out] mtr mini-transaction */
#define fil_block_check_type(block, type, mtr) \
fil_page_check_type(block->page.id, block->frame, type, mtr)
#ifdef UNIV_DEBUG
/** Increase redo skipped of a tablespace.
@param[in] space_id Tablespace ID */
void fil_space_inc_redo_skipped_count(space_id_t space_id);
/** Decrease redo skipped of a tablespace.
@param[in] space_id Tablespace ID */
void fil_space_dec_redo_skipped_count(space_id_t space_id);
/** Check whether a single-table tablespace is redo skipped.
@param[in] space_id Tablespace ID
@return true if redo skipped */
bool fil_space_is_redo_skipped(space_id_t space_id)
MY_ATTRIBUTE((warn_unused_result));
#endif /* UNIV_DEBUG */
/** Delete the tablespace file and any related files like .cfg.
This should not be called for temporary tables.
@param[in] path File path of the tablespace
@return true on success */
bool fil_delete_file(const char *path) MY_ATTRIBUTE((warn_unused_result));
/** Callback functor. */
struct PageCallback {
/** Default constructor */
PageCallback() : m_page_size(0, 0, false), m_filepath() UNIV_NOTHROW {}
virtual ~PageCallback() UNIV_NOTHROW {}
/** Called for page 0 in the tablespace file at the start.
@param file_size size of the file in bytes
@param block contents of the first page in the tablespace file
@retval DB_SUCCESS or error code. */
virtual dberr_t init(os_offset_t file_size, const buf_block_t *block)
MY_ATTRIBUTE((warn_unused_result)) UNIV_NOTHROW = 0;
/** Called for every page in the tablespace. If the page was not
updated then its state must be set to BUF_PAGE_NOT_USED. For
compressed tables the page descriptor memory will be at offset:
block->frame + UNIV_PAGE_SIZE;
@param offset physical offset within the file
@param block block read from file, note it is not from the buffer pool
@retval DB_SUCCESS or error code. */
virtual dberr_t operator()(os_offset_t offset, buf_block_t *block)
MY_ATTRIBUTE((warn_unused_result)) UNIV_NOTHROW = 0;
/** Set the name of the physical file and the file handle that is used
to open it for the file that is being iterated over.
@param filename then physical name of the tablespace file.
@param file OS file handle */
void set_file(const char *filename, pfs_os_file_t file) UNIV_NOTHROW {
m_file = file;
m_filepath = filename;
}
/** @return the space id of the tablespace */
virtual space_id_t get_space_id() const
MY_ATTRIBUTE((warn_unused_result)) UNIV_NOTHROW = 0;
/**
@retval the space flags of the tablespace being iterated over */
virtual ulint get_space_flags() const
MY_ATTRIBUTE((warn_unused_result)) UNIV_NOTHROW = 0;
/** Set the tablespace table size.
@param[in] page a page belonging to the tablespace */
void set_page_size(const buf_frame_t *page) UNIV_NOTHROW;
/** The compressed page size
@return the compressed page size */
const page_size_t &get_page_size() const MY_ATTRIBUTE((warn_unused_result)) {
return (m_page_size);
}
/** The tablespace page size. */
page_size_t m_page_size;
/** File handle to the tablespace */
pfs_os_file_t m_file;
/** Physical file path. */
const char *m_filepath;
// Disable copying
PageCallback(PageCallback &&) = delete;
PageCallback(const PageCallback &) = delete;
PageCallback &operator=(const PageCallback &) = delete;
};
/** Iterate over all the pages in the tablespace.
@param table the table definiton in the server
@param n_io_buffers number of blocks to read and write together
@param callback functor that will do the page updates
@return DB_SUCCESS or error code */
dberr_t fil_tablespace_iterate(dict_table_t *table, ulint n_io_buffers,
PageCallback &callback)
MY_ATTRIBUTE((warn_unused_result));
/** 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 thtablespace found.
@return true if tablespace is found, false if not. */
bool fil_space_read_name_and_filepath(space_id_t space_id, char **name,
char **filepath)
MY_ATTRIBUTE((warn_unused_result));
/** 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)
MY_ATTRIBUTE((warn_unused_result));
/** Returns the space ID based on the tablespace name.
The tablespace must be found in the tablespace memory cache.
This call is made from external to this module, so the mutex is not owned.
@param[in] name Tablespace name
@return space ID if tablespace found, SPACE_UNKNOWN if space not. */
space_id_t fil_space_get_id_by_name(const char *name)
MY_ATTRIBUTE((warn_unused_result));
/** Check if swapping two .ibd files can be done without failure
@param[in] old_table old table
@param[in] new_table new table
@param[in] tmp_name temporary table name
@return innodb error code */
dberr_t fil_rename_precheck(const dict_table_t *old_table,
const dict_table_t *new_table, const char *tmp_name)
MY_ATTRIBUTE((warn_unused_result));
/** Set the compression type for the tablespace of a table
@param[in] table Table that should be compressesed
@param[in] algorithm Text representation of the algorithm
@return DB_SUCCESS or error code */
dberr_t fil_set_compression(dict_table_t *table, const char *algorithm)
MY_ATTRIBUTE((warn_unused_result));
/** Get the compression type for the tablespace
@param[in] space_id Space ID to check
@return the compression algorithm */
Compression::Type fil_get_compression(space_id_t space_id)
MY_ATTRIBUTE((warn_unused_result));
/** Set encryption.
@param[in,out] req_type IO request
@param[in] page_id Page address for IO
@param[in,out] space Tablespace instance */
void fil_io_set_encryption(IORequest &req_type, const page_id_t &page_id,
fil_space_t *space);
/** Set the encryption type for the tablespace
@param[in] space_id Space ID of tablespace for which to set
@param[in] algorithm Encryption algorithm
@param[in] key Encryption key
@param[in] iv Encryption iv
@return DB_SUCCESS or error code */
dberr_t fil_set_encryption(space_id_t space_id, Encryption::Type algorithm,
byte *key, byte *iv)
MY_ATTRIBUTE((warn_unused_result));
/** Reset the encryption type for the tablespace
@param[in] space_id Space ID of tablespace for which to set
@return DB_SUCCESS or error code */
dberr_t fil_reset_encryption(space_id_t space_id)
MY_ATTRIBUTE((warn_unused_result));
/** @return true if the re-encrypt success */
bool fil_encryption_rotate() MY_ATTRIBUTE((warn_unused_result));
/** During crash recovery, open a tablespace if it had not been opened
yet, to get valid size and flags.
@param[in,out] space Tablespace instance */
inline void fil_space_open_if_needed(fil_space_t *space) {
if (space->size == 0) {
/* Initially, size and flags will be set to 0,
until the files are opened for the first time.
fil_space_get_size() will open the file
and adjust the size and flags. */
page_no_t size = fil_space_get_size(space->id);
ut_a(size == space->size);
}
}
#if !defined(NO_FALLOCATE) && defined(UNIV_LINUX)
/**
Try and enable FusionIO atomic writes.
@param[in] file OS file handle
@return true if successful */
bool fil_fusionio_enable_atomic_write(pfs_os_file_t file)
MY_ATTRIBUTE((warn_unused_result));
#endif /* !NO_FALLOCATE && UNIV_LINUX */
/** Note that the file system where the file resides doesn't support PUNCH HOLE
@param[in,out] file File node to set */
void fil_no_punch_hole(fil_node_t *file);
#ifdef UNIV_ENABLE_UNIT_TEST_MAKE_FILEPATH
void test_make_filepath();
#endif /* UNIV_ENABLE_UNIT_TEST_MAKE_FILEPATH */
/** @return the system tablespace instance */
#define fil_space_get_sys_space() (fil_space_t::s_sys_space)
/** Redo a tablespace create
@param[in] ptr redo log record
@param[in] end end of the redo log buffer
@param[in] page_id Tablespace Id and first page in file
@param[in] parsed_bytes Number of bytes parsed so far
@param[in] parse_only Don't apply the log if true
@return pointer to next redo log record
@retval nullptr if this log record was truncated */
byte *fil_tablespace_redo_create(byte *ptr, const byte *end,
const page_id_t &page_id, ulint parsed_bytes,
bool parse_only)
MY_ATTRIBUTE((warn_unused_result));
/** Redo a tablespace drop
@param[in] ptr redo log record
@param[in] end end of the redo log buffer
@param[in] page_id Tablespace Id and first page in file
@param[in] parsed_bytes Number of bytes parsed so far
@param[in] parse_only Don't apply the log if true
@return pointer to next redo log record
@retval nullptr if this log record was truncated */
byte *fil_tablespace_redo_delete(byte *ptr, const byte *end,
const page_id_t &page_id, ulint parsed_bytes,
bool parse_only)
MY_ATTRIBUTE((warn_unused_result));
/** Redo a tablespace rename
@param[in] ptr redo log record
@param[in] end end of the redo log buffer
@param[in] page_id Tablespace Id and first page in file
@param[in] parsed_bytes Number of bytes parsed so far
@param[in] parse_only Don't apply the log if true
@return pointer to next redo log record
@retval nullptr if this log record was truncated */
byte *fil_tablespace_redo_rename(byte *ptr, const byte *end,
const page_id_t &page_id, ulint parsed_bytes,
bool parse_only)
MY_ATTRIBUTE((warn_unused_result));
/** Parse and process an encryption redo record.
@param[in] ptr redo log record
@param[in] end end of the redo log buffer
@param[in] space_id the tablespace ID
@return log record end, nullptr if not a complete record */
byte *fil_tablespace_redo_encryption(byte *ptr, const byte *end,
space_id_t space_id)
MY_ATTRIBUTE((warn_unused_result));
/** Read the tablespace id to path mapping from the file
@param[in] recovery true if called from crash recovery */
void fil_tablespace_open_init_for_recovery(bool recovery);
/** Lookup the space ID.
@param[in] space_id Tablespace ID to lookup
@return true if space ID is known and open */
bool fil_tablespace_lookup_for_recovery(space_id_t space_id)
MY_ATTRIBUTE((warn_unused_result));
/** Lookup the tablespace ID and return the path to the file. The filename
is ignored when testing for equality. Only the path up to the file name is
considered for matching: e.g. ./test/a.ibd == ./test/b.ibd.
@param[in] dd_object_id Server DD tablespace ID
@param[in] space_id Tablespace ID to lookup
@param[in] space_name Tablespace name
@param[in] old_path Path in the data dictionary
@param[out] new_path New path if scanned path not equal to path
@return status of the match. */
Fil_state fil_tablespace_path_equals(dd::Object_id dd_object_id,
space_id_t space_id,
const char *space_name,
std::string old_path,
std::string *new_path)
MY_ATTRIBUTE((warn_unused_result));
/** This function should be called after recovery has completed.
Check for tablespace files for which we did not see any MLOG_FILE_DELETE
or MLOG_FILE_RENAME record. These could not be recovered
@return true if there were some filenames missing for which we had to
ignore redo log records during the apply phase */
bool fil_check_missing_tablespaces() MY_ATTRIBUTE((warn_unused_result));
/** Discover tablespaces by reading the header from .ibd files.
@param[in] directories Directories to scan
@return DB_SUCCESS if all goes well */
dberr_t fil_scan_for_tablespaces(const std::string &directories);
/** Open the tabelspace and also get the tablespace filenames, space_id must
already be known.
@param[in] space_id Tablespace ID to lookup
@return true if open was successful */
bool fil_tablespace_open_for_recovery(space_id_t space_id)
MY_ATTRIBUTE((warn_unused_result));
/** Replay a file rename operation for ddl replay.
@param[in] page_id Space ID and first page number in the file
@param[in] old_name old file name
@param[in] new_name new file name
@return whether the operation was successfully applied
(the name did not exist, or new_name did not exist and
name was successfully renamed to new_name) */
bool fil_op_replay_rename_for_ddl(const page_id_t &page_id,
const char *old_name, const char *new_name);
/** Free the Tablespace_files instance.
@param[in] read_only_mode true if InnoDB is started in read only mode.
@return DB_SUCCESS if all OK */
dberr_t fil_open_for_business(bool read_only_mode)
MY_ATTRIBUTE((warn_unused_result));
/** Check if a path is known to InnoDB.
@param[in] path Path to check
@return true if path is known to InnoDB */
bool fil_check_path(const std::string &path) MY_ATTRIBUTE((warn_unused_result));
/** Get the list of directories that datafiles can reside in.
@return the list of directories 'dir1;dir2;....;dirN' */
std::string fil_get_dirs() MY_ATTRIBUTE((warn_unused_result));
/** Rename a tablespace. Use the space_id to find the shard.
@param[in] space_id tablespace ID
@param[in] old_name old tablespace name
@param[in] new_name new tablespace name
@return DB_SUCCESS on success */
dberr_t fil_rename_tablespace_by_id(space_id_t space_id, const char *old_name,
const char *new_name)
MY_ATTRIBUTE((warn_unused_result));
/** Free the data structures required for recovery. */
void fil_free_scanned_files();
/** Update the tablespace name. Incase, the new name
and old name are same, no update done.
@param[in,out] space tablespace object on which name
will be updated
@param[in] name new name for tablespace */
void fil_space_update_name(fil_space_t *space, const char *name);
#endif /* fil0fil_h */