polardbxengine/storage/innobase/include/os0file.h

2034 lines
79 KiB
C++

/***********************************************************************
Copyright (c) 1995, 2019, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2009, Percona Inc.
Portions of this file contain modifications contributed and copyrighted
by Percona Inc.. Those modifications are
gratefully acknowledged and are described briefly in the InnoDB
documentation. The contributions by Percona Inc. are incorporated with
their permission, and subject to the conditions contained in the file
COPYING.Percona.
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/os0file.h
The interface to the operating system file io
Created 10/21/1995 Heikki Tuuri
*******************************************************/
#ifndef os0file_h
#define os0file_h
#include "my_dbug.h"
#include "my_io.h"
#include "os/file.h"
#include "univ.i"
#ifndef _WIN32
#include <dirent.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <time.h>
#else
#include <Strsafe.h>
#include <locale>
#include <string>
#endif /* !_WIN32 */
#include <functional>
#include <stack>
/** Prefix all files and directory created under data directory with special
string so that it never conflicts with MySQL schema directory. */
#define OS_FILE_PREFIX "#"
/** File node of a tablespace or the log data space */
struct fil_node_t;
extern bool os_has_said_disk_full;
/** Number of pending read operations */
extern ulint os_n_pending_reads;
/** Number of pending write operations */
extern ulint os_n_pending_writes;
/* Flush after each os_fsync_threshold bytes */
extern unsigned long long os_fsync_threshold;
/** File offset in bytes */
typedef ib_uint64_t os_offset_t;
#ifdef _WIN32
typedef HANDLE os_file_dir_t; /*!< directory stream */
/** We define always WIN_ASYNC_IO, and check at run-time whether
the OS actually supports it: Win 95 does not, NT does. */
#define WIN_ASYNC_IO
/** Use unbuffered I/O */
#define UNIV_NON_BUFFERED_IO
/** File handle */
#define os_file_t HANDLE
/** Convert a C file descriptor to a native file handle
@param fd file descriptor
@return native file handle */
#define OS_FILE_FROM_FD(fd) (HANDLE) _get_osfhandle(fd)
/** Associates a C file descriptor with an existing native file handle
@param[in] file native file handle
@return C file descriptor */
#define OS_FD_FROM_FILE(file) _open_osfhandle((intptr_t)file, _O_RDONLY)
/** Closes the file associated with C file descriptor fd
@param[in] fd C file descriptor
@return 0 if success */
#define OS_FILE_CLOSE_FD(fd) _close(fd)
#else /* _WIN32 */
/** File handle */
typedef int os_file_t;
/** Convert a C file descriptor to a native file handle
@param fd file descriptor
@return native file handle */
#define OS_FILE_FROM_FD(fd) fd
/** C file descriptor from an existing native file handle
@param[in] file native file handle
@return C file descriptor */
#define OS_FD_FROM_FILE(file) file
/** Closes the file associated with C file descriptor fd
@param[in] fd C file descriptor
@return 0 if success */
#define OS_FILE_CLOSE_FD(fd) (os_file_close(fd) ? 0 : -1)
#endif /* _WIN32 */
/** Common file descriptor for file IO instrumentation with PFS
on windows and other platforms */
struct pfs_os_file_t {
#ifdef UNIV_PFS_IO
struct PSI_file *m_psi;
#else /* UNIV_PFS_IO */
pfs_os_file_t &operator=(os_file_t file) {
m_file = file;
return (*this);
}
#endif /* UNIV_PFS_IO */
os_file_t m_file;
};
static const os_file_t OS_FILE_CLOSED = os_file_t(~0);
/** The next value should be smaller or equal to the smallest sector size used
on any disk. A log block is required to be a portion of disk which is written
so that if the start and the end of a block get written to disk, then the
whole block gets written. This should be true even in most cases of a crash:
if this fails for a log block, then it is equivalent to a media failure in the
log. */
#define OS_FILE_LOG_BLOCK_SIZE 512
/** Options for os_file_create_func @{ */
enum os_file_create_t {
OS_FILE_OPEN = 51, /*!< to open an existing file (if
doesn't exist, error) */
OS_FILE_CREATE, /*!< to create new file (if
exists, error) */
OS_FILE_OPEN_RAW, /*!< to open a raw device or disk
partition */
OS_FILE_CREATE_PATH, /*!< to create the directories */
OS_FILE_OPEN_RETRY, /*!< open with retry */
/** Flags that can be combined with the above values. Please ensure
that the above values stay below 128. */
OS_FILE_ON_ERROR_NO_EXIT = 128, /*!< do not exit on unknown errors */
OS_FILE_ON_ERROR_SILENT = 256 /*!< don't print diagnostic messages to
the log unless it is a fatal error,
this flag is only used if
ON_ERROR_NO_EXIT is set */
};
static const ulint OS_FILE_READ_ONLY = 333;
static const ulint OS_FILE_READ_WRITE = 444;
/** Used by MySQLBackup */
static const ulint OS_FILE_READ_ALLOW_DELETE = 555;
/* Options for file_create */
static const ulint OS_FILE_AIO = 61;
static const ulint OS_FILE_NORMAL = 62;
/* @} */
/** Types for file create @{ */
static const ulint OS_DATA_FILE = 100;
static const ulint OS_LOG_FILE = 101;
/* Don't use this for Data files, Log files. Use it for smaller files
or if number of bytes to write are not multiple of sector size.
With this flag, writes to file will be always buffered and ignores the value
of innodb_flush_method. */
static const ulint OS_BUFFERED_FILE = 102;
static const ulint OS_CLONE_DATA_FILE = 103;
static const ulint OS_CLONE_LOG_FILE = 104;
static const ulint OS_REDO_LOG_ARCHIVE_FILE = 105;
/* @} */
/** Error codes from os_file_get_last_error @{ */
static const ulint OS_FILE_NOT_FOUND = 71;
static const ulint OS_FILE_DISK_FULL = 72;
static const ulint OS_FILE_ALREADY_EXISTS = 73;
static const ulint OS_FILE_PATH_ERROR = 74;
/** wait for OS aio resources to become available again */
static const ulint OS_FILE_AIO_RESOURCES_RESERVED = 75;
static const ulint OS_FILE_SHARING_VIOLATION = 76;
static const ulint OS_FILE_ERROR_NOT_SPECIFIED = 77;
static const ulint OS_FILE_INSUFFICIENT_RESOURCE = 78;
static const ulint OS_FILE_AIO_INTERRUPTED = 79;
static const ulint OS_FILE_OPERATION_ABORTED = 80;
static const ulint OS_FILE_ACCESS_VIOLATION = 81;
static const ulint OS_FILE_NAME_TOO_LONG = 82;
static const ulint OS_FILE_ERROR_MAX = 100;
/* @} */
/** Encryption key length */
static const ulint ENCRYPTION_KEY_LEN = 32;
/** Encryption magic bytes size */
static const ulint ENCRYPTION_MAGIC_SIZE = 3;
/** Encryption magic bytes for 5.7.11, it's for checking the encryption
information version. */
static const char ENCRYPTION_KEY_MAGIC_V1[] = "lCA";
/** Encryption magic bytes for 5.7.12+, it's for checking the encryption
information version. */
static const char ENCRYPTION_KEY_MAGIC_V2[] = "lCB";
/** Encryption magic bytes for 8.0.5+, it's for checking the encryption
information version. */
static const char ENCRYPTION_KEY_MAGIC_V3[] = "lCC";
/** Encryption master key prifix */
static const char ENCRYPTION_MASTER_KEY_PRIFIX[] = "INNODBKey";
/** Encryption master key prifix size */
static const ulint ENCRYPTION_MASTER_KEY_PRIFIX_LEN = 9;
/** Encryption master key prifix size */
static const ulint ENCRYPTION_MASTER_KEY_NAME_MAX_LEN = 100;
/** UUID of server instance, it's needed for composing master key name */
static const ulint ENCRYPTION_SERVER_UUID_LEN = 36;
/** Encryption information total size: magic number + master_key_id +
key + iv + server_uuid + checksum */
static const ulint ENCRYPTION_INFO_SIZE =
(ENCRYPTION_MAGIC_SIZE + sizeof(uint32) + (ENCRYPTION_KEY_LEN * 2) +
ENCRYPTION_SERVER_UUID_LEN + sizeof(uint32));
/** Maximum size of Encryption information considering all formats v1, v2 & v3.
*/
static const ulint ENCRYPTION_INFO_MAX_SIZE =
(ENCRYPTION_INFO_SIZE + sizeof(uint32));
/** Default master key for bootstrap */
static const char ENCRYPTION_DEFAULT_MASTER_KEY[] = "DefaultMasterKey";
/** Default master key id for bootstrap */
static const ulint ENCRYPTION_DEFAULT_MASTER_KEY_ID = 0;
/** (Un)Encryption Operation information size */
static const uint ENCRYPTION_OPERATION_INFO_SIZE = 1;
/** Encryption Progress information size */
static const uint ENCRYPTION_PROGRESS_INFO_SIZE = sizeof(uint);
/** Flag bit to indicate if Encryption/Decryption is in progress */
#define ENCRYPTION_IN_PROGRESS (1 << 0)
#define UNENCRYPTION_IN_PROGRESS (1 << 1)
class IORequest;
/** Encryption algorithm. */
struct Encryption {
/** Algorithm types supported */
enum Type {
/** No encryption */
NONE = 0,
/** Use AES */
AES = 1,
};
/** Encryption information format version */
enum Version {
/** Version in 5.7.11 */
ENCRYPTION_VERSION_1 = 0,
/** Version in > 5.7.11 */
ENCRYPTION_VERSION_2 = 1,
/** Version in > 8.0.4 */
ENCRYPTION_VERSION_3 = 2,
};
/** Default constructor */
Encryption() : m_type(NONE) {}
/** Specific constructor
@param[in] type Algorithm type */
explicit Encryption(Type type) : m_type(type) {
#ifdef UNIV_DEBUG
switch (m_type) {
case NONE:
case AES:
default:
ut_error;
}
#endif /* UNIV_DEBUG */
}
/** Copy constructor */
Encryption(const Encryption &other)
: m_type(other.m_type),
m_key(other.m_key),
m_klen(other.m_klen),
m_iv(other.m_iv) {}
Encryption &operator=(const Encryption &) = default;
/** Check if page is encrypted page or not
@param[in] page page which need to check
@return true if it is an encrypted page */
static bool is_encrypted_page(const byte *page)
MY_ATTRIBUTE((warn_unused_result));
/** Check if a log block is encrypted or not
@param[in] block block which need to check
@return true if it is an encrypted block */
static bool is_encrypted_log(const byte *block)
MY_ATTRIBUTE((warn_unused_result));
/** Check the encryption option and set it
@param[in] option encryption option
@param[in,out] encryption The encryption type
@return DB_SUCCESS or DB_UNSUPPORTED */
dberr_t set_algorithm(const char *option, Encryption *type)
MY_ATTRIBUTE((warn_unused_result));
/** Validate the algorithm string.
@param[in] option Encryption option
@return DB_SUCCESS or error code */
static dberr_t validate(const char *option)
MY_ATTRIBUTE((warn_unused_result));
/** Convert to a "string".
@param[in] type The encryption type
@return the string representation */
static const char *to_string(Type type) MY_ATTRIBUTE((warn_unused_result));
/** Check if the string is "empty" or "none".
@param[in] algorithm Encryption algorithm to check
@return true if no algorithm requested */
static bool is_none(const char *algorithm) MY_ATTRIBUTE((warn_unused_result));
/** Generate random encryption value for key and iv.
@param[in,out] value Encryption value */
static void random_value(byte *value);
/** Create new master key for key rotation.
@param[in,out] master_key master key */
static void create_master_key(byte **master_key);
/** Get master key by key id.
@param[in] master_key_id master key id
@param[in] srv_uuid uuid of server instance
@param[in,out] master_key master key */
static void get_master_key(ulint master_key_id, char *srv_uuid,
byte **master_key);
/** Get current master key and key id.
@param[in,out] master_key_id master key id
@param[in,out] master_key master key */
static void get_master_key(ulint *master_key_id, byte **master_key);
/** Fill the encryption information.
@param[in] key encryption key
@param[in] iv encryption iv
@param[in,out] encrypt_info encryption information
@param[in] is_boot if it's for bootstrap
@param[in] encrypt_key encrypt with master key
@return true if success. */
static bool fill_encryption_info(byte *key, byte *iv, byte *encrypt_info,
bool is_boot, bool encrypt_key);
/** Get master key from encryption information
@param[in] encrypt_info encryption information
@param[in] version version of encryption information
@param[in,out] m_key_id master key id
@param[in,out] srv_uuid server uuid
@param[in,out] master_key master key
@return position after master key id or uuid, or the old position
if can't get the master key. */
static byte *get_master_key_from_info(byte *encrypt_info, Version version,
uint32_t *m_key_id, char *srv_uuid,
byte **master_key);
/** Decoding the encryption info from the first page of a tablespace.
@param[in,out] key key
@param[in,out] iv iv
@param[in] encryption_info encryption info
@param[in] decrypt_key decrypt key using master key
@return true if success */
static bool decode_encryption_info(byte *key, byte *iv, byte *encryption_info,
bool decrypt_key);
/** Encrypt the redo log block.
@param[in] type IORequest
@param[in,out] src_ptr log block which need to encrypt
@param[in,out] dst_ptr destination area
@return true if success. */
bool encrypt_log_block(const IORequest &type, byte *src_ptr, byte *dst_ptr);
/** Encrypt the redo log data contents.
@param[in] type IORequest
@param[in,out] src page data which need to encrypt
@param[in] src_len size of the source in bytes
@param[in,out] dst destination area
@param[in,out] dst_len size of the destination in bytes
@return buffer data, dst_len will have the length of the data */
byte *encrypt_log(const IORequest &type, byte *src, ulint src_len, byte *dst,
ulint *dst_len);
/** Encrypt the page data contents. Page type can't be
FIL_PAGE_ENCRYPTED, FIL_PAGE_COMPRESSED_AND_ENCRYPTED,
FIL_PAGE_ENCRYPTED_RTREE.
@param[in] type IORequest
@param[in,out] src page data which need to encrypt
@param[in] src_len size of the source in bytes
@param[in,out] dst destination area
@param[in,out] dst_len size of the destination in bytes
@return buffer data, dst_len will have the length of the data */
byte *encrypt(const IORequest &type, byte *src, ulint src_len, byte *dst,
ulint *dst_len) MY_ATTRIBUTE((warn_unused_result));
/** Decrypt the log block.
@param[in] type IORequest
@param[in,out] src data read from disk, decrypted data
will be copied to this page
@param[in,out] dst scratch area to use for decryption
@return DB_SUCCESS or error code */
dberr_t decrypt_log_block(const IORequest &type, byte *src, byte *dst);
/** Decrypt the log data contents.
@param[in] type IORequest
@param[in,out] src data read from disk, decrypted data
will be copied to this page
@param[in] src_len source data length
@param[in,out] dst scratch area to use for decryption
@param[in] dst_len size of the scratch area in bytes
@return DB_SUCCESS or error code */
dberr_t decrypt_log(const IORequest &type, byte *src, ulint src_len,
byte *dst, ulint dst_len);
/** Decrypt the page data contents. Page type must be
FIL_PAGE_ENCRYPTED, FIL_PAGE_COMPRESSED_AND_ENCRYPTED,
FIL_PAGE_ENCRYPTED_RTREE, if not then the source contents are
left unchanged and DB_SUCCESS is returned.
@param[in] type IORequest
@param[in,out] src data read from disk, decrypt
data will be copied to this page
@param[in] src_len source data length
@param[in,out] dst scratch area to use for decrypt
@param[in] dst_len size of the scratch area in bytes
@return DB_SUCCESS or error code */
dberr_t decrypt(const IORequest &type, byte *src, ulint src_len, byte *dst,
ulint dst_len) MY_ATTRIBUTE((warn_unused_result));
/** Check if keyring plugin loaded. */
static bool check_keyring();
/** Encrypt type */
Type m_type;
/** Encrypt key */
byte *m_key;
/** Encrypt key length*/
ulint m_klen;
/** Encrypt initial vector */
byte *m_iv;
/** Current master key id */
static ulint s_master_key_id;
/** Current uuid of server instance */
static char s_uuid[ENCRYPTION_SERVER_UUID_LEN + 1];
};
/** Types for AIO operations @{ */
/** No transformations during read/write, write as is. */
#define IORequestRead IORequest(IORequest::READ)
#define IORequestWrite IORequest(IORequest::WRITE)
#define IORequestLogRead IORequest(IORequest::LOG | IORequest::READ)
#define IORequestLogWrite IORequest(IORequest::LOG | IORequest::WRITE)
/**
The IO Context that is passed down to the low level IO code */
class IORequest {
public:
/** Flags passed in the request, they can be ORred together. */
enum {
UNSET = 0,
READ = 1,
WRITE = 2,
/** Double write buffer recovery. */
DBLWR_RECOVER = 4,
/** Enumerations below can be ORed to READ/WRITE above*/
/** Data file */
DATA_FILE = 8,
/** Log file request*/
LOG = 16,
/** Disable partial read warnings */
DISABLE_PARTIAL_IO_WARNINGS = 32,
/** Do not to wake i/o-handler threads, but the caller will do
the waking explicitly later, in this way the caller can post
several requests in a batch; NOTE that the batch must not be
so big that it exhausts the slots in AIO arrays! NOTE that
a simulated batch may introduce hidden chances of deadlocks,
because I/Os are not actually handled until all
have been posted: use with great caution! */
DO_NOT_WAKE = 64,
/** Ignore failed reads of non-existent pages */
IGNORE_MISSING = 128,
/** Use punch hole if available, only makes sense if
compression algorithm != NONE. Ignored if not set */
PUNCH_HOLE = 256,
/** Force raw read, do not try to compress/decompress.
This can be used to force a read and write without any
compression e.g., for redo log, merge sort temporary files
and the truncate redo log. */
NO_COMPRESSION = 512
};
/** Default constructor */
IORequest()
: m_block_size(UNIV_SECTOR_SIZE),
m_type(READ),
m_compression(),
m_encryption() {
/* No op */
}
/**
@param[in] type Request type, can be a value that is
ORed from the above enum */
explicit IORequest(ulint type)
: m_block_size(UNIV_SECTOR_SIZE),
m_type(static_cast<uint16_t>(type)),
m_compression(),
m_encryption() {
if (is_log()) {
disable_compression();
}
if (!is_punch_hole_supported()) {
clear_punch_hole();
}
}
/** @return true if ignore missing flag is set */
static bool ignore_missing(ulint type) MY_ATTRIBUTE((warn_unused_result)) {
return ((type & IGNORE_MISSING) == IGNORE_MISSING);
}
/** @return true if it is a read request */
bool is_read() const MY_ATTRIBUTE((warn_unused_result)) {
return ((m_type & READ) == READ);
}
/** @return true if it is a write request */
bool is_write() const MY_ATTRIBUTE((warn_unused_result)) {
return ((m_type & WRITE) == WRITE);
}
/** @return true if it is a redo log write */
bool is_log() const MY_ATTRIBUTE((warn_unused_result)) {
return ((m_type & LOG) == LOG);
}
/** @return true if the simulated AIO thread should be woken up */
bool is_wake() const MY_ATTRIBUTE((warn_unused_result)) {
return ((m_type & DO_NOT_WAKE) == 0);
}
/** @return true if partial read warning disabled */
bool is_partial_io_warning_disabled() const
MY_ATTRIBUTE((warn_unused_result)) {
return ((m_type & DISABLE_PARTIAL_IO_WARNINGS) ==
DISABLE_PARTIAL_IO_WARNINGS);
}
/** Disable partial read warnings */
void disable_partial_io_warnings() { m_type |= DISABLE_PARTIAL_IO_WARNINGS; }
/** @return true if missing files should be ignored */
bool ignore_missing() const MY_ATTRIBUTE((warn_unused_result)) {
return (ignore_missing(m_type));
}
/** @return true if punch hole should be used */
bool punch_hole() const MY_ATTRIBUTE((warn_unused_result)) {
return ((m_type & PUNCH_HOLE) == PUNCH_HOLE);
}
/** @return true if the read should be validated */
bool validate() const MY_ATTRIBUTE((warn_unused_result)) {
ut_a(is_read() ^ is_write());
return (!is_read() || !punch_hole());
}
/** Set the punch hole flag */
void set_punch_hole() {
if (is_punch_hole_supported()) {
m_type |= PUNCH_HOLE;
}
}
/** Clear the do not wake flag */
void clear_do_not_wake() { m_type &= ~DO_NOT_WAKE; }
/** Clear the punch hole flag */
void clear_punch_hole() { m_type &= ~PUNCH_HOLE; }
/** @return the block size to use for IO */
ulint block_size() const MY_ATTRIBUTE((warn_unused_result)) {
return (m_block_size);
}
/** Set the block size for IO
@param[in] block_size Block size to set */
void block_size(ulint block_size) {
m_block_size = static_cast<uint32_t>(block_size);
}
/** Clear all compression related flags */
void clear_compressed() {
clear_punch_hole();
m_compression.m_type = Compression::NONE;
}
/** Compare two requests
@return true if the are equal */
bool operator==(const IORequest &rhs) const { return (m_type == rhs.m_type); }
/** Set compression algorithm
@param[in] type The compression algorithm to use */
void compression_algorithm(Compression::Type type) {
if (type == Compression::NONE) {
return;
}
set_punch_hole();
m_compression.m_type = type;
}
/** Get the compression algorithm.
@return the compression algorithm */
Compression compression_algorithm() const MY_ATTRIBUTE((warn_unused_result)) {
return (m_compression);
}
/** @return true if the page should be compressed */
bool is_compressed() const MY_ATTRIBUTE((warn_unused_result)) {
return (compression_algorithm().m_type != Compression::NONE);
}
/** @return true if the page read should not be transformed. */
bool is_compression_enabled() const MY_ATTRIBUTE((warn_unused_result)) {
return ((m_type & NO_COMPRESSION) == 0);
}
/** Disable transformations. */
void disable_compression() { m_type |= NO_COMPRESSION; }
/** Set encryption algorithm
@param[in] type The encryption algorithm to use */
void encryption_algorithm(Encryption::Type type) {
if (type == Encryption::NONE) {
return;
}
m_encryption.m_type = type;
}
/** Set encryption key and iv
@param[in] key The encryption key to use
@param[in] key_len length of the encryption key
@param[in] iv The encryption iv to use */
void encryption_key(byte *key, ulint key_len, byte *iv) {
m_encryption.m_key = key;
m_encryption.m_klen = key_len;
m_encryption.m_iv = iv;
}
/** Get the encryption algorithm.
@return the encryption algorithm */
Encryption encryption_algorithm() const MY_ATTRIBUTE((warn_unused_result)) {
return (m_encryption);
}
/** @return true if the page should be encrypted. */
bool is_encrypted() const MY_ATTRIBUTE((warn_unused_result)) {
return (m_encryption.m_type != Encryption::NONE);
}
/** Clear all encryption related flags */
void clear_encrypted() {
m_encryption.m_key = NULL;
m_encryption.m_klen = 0;
m_encryption.m_iv = NULL;
m_encryption.m_type = Encryption::NONE;
}
/** Note that the IO is for double write recovery. */
void dblwr_recover() { m_type |= DBLWR_RECOVER; }
/** @return true if the request is from the dblwr recovery */
bool is_dblwr_recover() const MY_ATTRIBUTE((warn_unused_result)) {
return ((m_type & DBLWR_RECOVER) == DBLWR_RECOVER);
}
/** @return true if punch hole is supported */
static bool is_punch_hole_supported() {
/* In this debugging mode, we act as if punch hole is supported,
and then skip any calls to actually punch a hole here.
In this way, Transparent Page Compression is still being tested. */
DBUG_EXECUTE_IF("ignore_punch_hole", return (true););
#if defined(HAVE_FALLOC_PUNCH_HOLE_AND_KEEP_SIZE) || defined(_WIN32)
return (true);
#else
return (false);
#endif /* HAVE_FALLOC_PUNCH_HOLE_AND_KEEP_SIZE || _WIN32 */
}
private:
/* File system best block size */
uint32_t m_block_size;
/** Request type bit flags */
uint16_t m_type;
/** Compression algorithm */
Compression m_compression;
/** Encryption algorithm */
Encryption m_encryption;
};
/* @} */
/** Sparse file size information. */
struct os_file_size_t {
/** Total size of file in bytes */
os_offset_t m_total_size;
/** If it is a sparse file then this is the number of bytes
actually allocated for the file. */
os_offset_t m_alloc_size;
};
/** Win NT does not allow more than 64 */
static const ulint OS_AIO_N_PENDING_IOS_PER_THREAD = 32;
/** Modes for aio operations @{ */
enum class AIO_mode : size_t {
/** Normal asynchronous i/o not for ibuf pages or ibuf bitmap pages */
NORMAL = 21,
/** Asynchronous i/o for ibuf pages or ibuf bitmap pages */
IBUF = 22,
/** Asynchronous i/o for the log */
LOG = 23,
/** Asynchronous i/o where the calling thread will itself wait for
the i/o to complete, doing also the job of the i/o-handler thread;
can be used for any pages, ibuf or non-ibuf. This is used to save
CPU time, as we can do with fewer thread switches. Plain synchronous
I/O is not as good, because it must serialize the file seek and read
or write, causing a bottleneck for parallelism. */
SYNC = 24
};
/* @} */
extern ulint os_n_file_reads;
extern ulint os_n_file_writes;
extern ulint os_n_fsyncs;
/* File types for directory entry data type */
enum os_file_type_t {
/** Get status failed. */
OS_FILE_TYPE_FAILED,
/** stat() failed, with ENAMETOOLONG */
OS_FILE_TYPE_NAME_TOO_LONG,
/** stat() failed with EACCESS */
OS_FILE_PERMISSION_ERROR,
/** File doesn't exist. */
OS_FILE_TYPE_MISSING,
/** File exists but type is unknown. */
OS_FILE_TYPE_UNKNOWN,
/** Ordinary file. */
OS_FILE_TYPE_FILE,
/** Directory. */
OS_FILE_TYPE_DIR,
/** Symbolic link. */
OS_FILE_TYPE_LINK,
/** Block device. */
OS_FILE_TYPE_BLOCK
};
/* Maximum path string length in bytes when referring to tables with in the
'./databasename/tablename.ibd' path format; we can allocate at least 2 buffers
of this size from the thread stack; that is why this should not be made much
bigger than 4000 bytes. The maximum path length used by any storage engine
in the server must be at least this big. */
#define OS_FILE_MAX_PATH 4000
#if (FN_REFLEN_SE < OS_FILE_MAX_PATH)
#error "(FN_REFLEN_SE < OS_FILE_MAX_PATH)"
#endif
/** Struct used in fetching information of a file in a directory */
struct os_file_stat_t {
char name[OS_FILE_MAX_PATH]; /*!< path to a file */
os_file_type_t type; /*!< file type */
os_offset_t size; /*!< file size in bytes */
os_offset_t alloc_size; /*!< Allocated size for
sparse files in bytes */
uint32_t block_size; /*!< Block size to use for IO
in bytes*/
time_t ctime; /*!< creation time */
time_t mtime; /*!< modification time */
time_t atime; /*!< access time */
bool rw_perm; /*!< true if can be opened
in read-write mode. Only valid
if type == OS_FILE_TYPE_FILE */
};
#ifndef UNIV_HOTBACKUP
/** Create a temporary file. This function is like tmpfile(3), but
the temporary file is created in the given parameter path. If the path
is null then it will create the file in the mysql server configuration
parameter (--tmpdir).
@param[in] path location for creating temporary file
@return temporary file handle, or NULL on error */
FILE *os_file_create_tmpfile(const char *path);
#endif /* !UNIV_HOTBACKUP */
/**
This function attempts to create a directory named pathname. The new directory
gets default permissions. On Unix, the permissions are (0770 & ~umask). If the
directory exists already, nothing is done and the call succeeds, unless the
fail_if_exists arguments is true.
@param[in] pathname directory name as null-terminated string
@param[in] fail_if_exists if true, pre-existing directory is treated
as an error.
@return true if call succeeds, false on error */
bool os_file_create_directory(const char *pathname, bool fail_if_exists);
/** Callback function type to be implemented by caller. It is called for each
entry in directory.
@param[in] path path to the file
@param[in] name name of the file */
typedef void (*os_dir_cbk_t)(const char *path, const char *name);
/** This function scans the contents of a directory and invokes the callback
for each entry.
@param[in] path directory name as null-terminated string
@param[in] scan_cbk use callback to be called for each entry
@param[in] is_drop attempt to drop the directory after scan
@return true if call succeeds, false on error */
bool os_file_scan_directory(const char *path, os_dir_cbk_t scan_cbk,
bool is_delete);
/** NOTE! Use the corresponding macro os_file_create_simple(), not directly
this function!
A simple function to open or create a file.
@param[in] name name of the file or path as a null-terminated
string
@param[in] create_mode create mode
@param[in] access_type OS_FILE_READ_ONLY or OS_FILE_READ_WRITE
@param[in] read_only if true read only mode checks are enforced
@param[out] success true if succeed, false if error
@return own: handle to the file, not defined if error, error number
can be retrieved with os_file_get_last_error */
os_file_t os_file_create_simple_func(const char *name, ulint create_mode,
ulint access_type, bool read_only,
bool *success);
/** NOTE! Use the corresponding macro
os_file_create_simple_no_error_handling(), not directly this function!
A simple function to open or create a file.
@param[in] name name of the file or path as a
null-terminated string
@param[in] create_mode create mode
@param[in] access_type OS_FILE_READ_ONLY, OS_FILE_READ_WRITE, or
OS_FILE_READ_ALLOW_DELETE; the last option
is used by a backup program reading the file
@param[in] read_only if true read only mode checks are enforced
@param[out] success true if succeeded
@return own: handle to the file, not defined if error, error number
can be retrieved with os_file_get_last_error */
pfs_os_file_t os_file_create_simple_no_error_handling_func(
const char *name, ulint create_mode, ulint access_type, bool read_only,
bool *success) MY_ATTRIBUTE((warn_unused_result));
/** Tries to disable OS caching on an opened file descriptor.
@param[in] fd file descriptor to alter
@param[in] file_name file name, used in the diagnostic message
@param[in] operation_name "open" or "create"; used in the diagnostic
message */
void os_file_set_nocache(int fd, const char *file_name,
const char *operation_name);
/** NOTE! Use the corresponding macro os_file_create(), not directly
this function!
Opens an existing file or creates a new.
@param[in] name name of the file or path as a null-terminated
string
@param[in] create_mode create mode
@param[in] purpose OS_FILE_AIO, if asynchronous, non-buffered I/O
is desired, OS_FILE_NORMAL, if any normal file;
NOTE that it also depends on type, os_aio_..
and srv_.. variables whether we really use
async I/O or unbuffered I/O: look in the
function source code for the exact rules
@param[in] type OS_DATA_FILE or OS_LOG_FILE
@param[in] read_only if true read only mode checks are enforced
@param[in] success true if succeeded
@return own: handle to the file, not defined if error, error number
can be retrieved with os_file_get_last_error */
pfs_os_file_t os_file_create_func(const char *name, ulint create_mode,
ulint purpose, ulint type, bool read_only,
bool *success)
MY_ATTRIBUTE((warn_unused_result));
/** Deletes a file. The file has to be closed before calling this.
@param[in] name file path as a null-terminated string
@return true if success */
bool os_file_delete_func(const char *name);
/** Deletes a file if it exists. The file has to be closed before calling this.
@param[in] name file path as a null-terminated string
@param[out] exist indicate if file pre-exist
@return true if success */
bool os_file_delete_if_exists_func(const char *name, bool *exist);
/** NOTE! Use the corresponding macro os_file_rename(), not directly
this function!
Renames a file (can also move it to another directory). It is safest that the
file is closed before calling this function.
@param[in] oldpath old file path as a null-terminated string
@param[in] newpath new file path
@return true if success */
bool os_file_rename_func(const char *oldpath, const char *newpath);
/** NOTE! Use the corresponding macro os_file_close(), not directly this
function!
Closes a file handle. In case of error, error number can be retrieved with
os_file_get_last_error.
@param[in] file own: handle to a file
@return true if success */
bool os_file_close_func(os_file_t file);
#ifdef UNIV_PFS_IO
/* Keys to register InnoDB I/O with performance schema */
extern mysql_pfs_key_t innodb_log_file_key;
extern mysql_pfs_key_t innodb_temp_file_key;
extern mysql_pfs_key_t innodb_arch_file_key;
extern mysql_pfs_key_t innodb_clone_file_key;
extern mysql_pfs_key_t innodb_data_file_key;
extern mysql_pfs_key_t innodb_tablespace_open_file_key;
/* Following four macros are instumentations to register
various file I/O operations with performance schema.
1) register_pfs_file_open_begin() and register_pfs_file_open_end() are
used to register file creation, opening and closing.
2) register_pfs_file_rename_begin() and register_pfs_file_rename_end()
are used to register file renaming.
3) register_pfs_file_io_begin() and register_pfs_file_io_end() are
used to register actual file read, write and flush
4) register_pfs_file_close_begin() and register_pfs_file_close_end()
are used to register file deletion operations*/
#define register_pfs_file_open_begin(state, locker, key, op, name, src_file, \
src_line) \
do { \
locker = PSI_FILE_CALL(get_thread_file_name_locker)(state, key.m_value, \
op, name, &locker); \
if (locker != NULL) { \
PSI_FILE_CALL(start_file_open_wait) \
(locker, src_file, static_cast<uint>(src_line)); \
} \
} while (0)
#define register_pfs_file_open_end(locker, file, result) \
do { \
if (locker != NULL) { \
file.m_psi = PSI_FILE_CALL(end_file_open_wait)(locker, result); \
} \
} while (0)
#define register_pfs_file_rename_begin(state, locker, key, op, name, src_file, \
src_line) \
register_pfs_file_open_begin(state, locker, key, op, name, src_file, \
static_cast<uint>(src_line))
#define register_pfs_file_rename_end(locker, from, to, result) \
do { \
if (locker != NULL) { \
PSI_FILE_CALL(end_file_rename_wait)(locker, from, to, result); \
} \
} while (0)
#define register_pfs_file_close_begin(state, locker, key, op, name, src_file, \
src_line) \
do { \
locker = PSI_FILE_CALL(get_thread_file_name_locker)(state, key.m_value, \
op, name, &locker); \
if (locker != NULL) { \
PSI_FILE_CALL(start_file_close_wait) \
(locker, src_file, static_cast<uint>(src_line)); \
} \
} while (0)
#define register_pfs_file_close_end(locker, result) \
do { \
if (locker != NULL) { \
PSI_FILE_CALL(end_file_close_wait)(locker, result); \
} \
} while (0)
#define register_pfs_file_io_begin(state, locker, file, count, op, src_file, \
src_line) \
do { \
locker = \
PSI_FILE_CALL(get_thread_file_stream_locker)(state, file.m_psi, op); \
if (locker != NULL) { \
PSI_FILE_CALL(start_file_wait) \
(locker, count, src_file, static_cast<uint>(src_line)); \
} \
} while (0)
#define register_pfs_file_io_end(locker, count) \
do { \
if (locker != NULL) { \
PSI_FILE_CALL(end_file_wait)(locker, count); \
} \
} while (0)
/* Following macros/functions are file I/O APIs that would be performance
schema instrumented if "UNIV_PFS_IO" is defined. They would point to
wrapper functions with performance schema instrumentation in such case.
os_file_create
os_file_create_simple
os_file_create_simple_no_error_handling
os_file_close
os_file_rename
os_aio
os_file_read
os_file_read_no_error_handling
os_file_read_no_error_handling_int_fd
os_file_write
The wrapper functions have the prefix of "innodb_". */
#define os_file_create(key, name, create, purpose, type, read_only, success) \
pfs_os_file_create_func(key, name, create, purpose, type, read_only, \
success, __FILE__, __LINE__)
#define os_file_create_simple(key, name, create, access, read_only, success) \
pfs_os_file_create_simple_func(key, name, create, access, read_only, \
success, __FILE__, __LINE__)
#define os_file_create_simple_no_error_handling(key, name, create_mode, \
access, read_only, success) \
pfs_os_file_create_simple_no_error_handling_func( \
key, name, create_mode, access, read_only, success, __FILE__, __LINE__)
#define os_file_close_pfs(file) pfs_os_file_close_func(file, __FILE__, __LINE__)
#define os_aio(type, mode, name, file, buf, offset, n, read_only, message1, \
message2) \
pfs_os_aio_func(type, mode, name, file, buf, offset, n, read_only, message1, \
message2, __FILE__, __LINE__)
#define os_file_read_pfs(type, file_name, file, buf, offset, n) \
pfs_os_file_read_func(type, file_name, file, buf, offset, n, __FILE__, \
__LINE__)
#define os_file_read_first_page_pfs(type, file_name, file, buf, n) \
pfs_os_file_read_first_page_func(type, file_name, file, buf, n, __FILE__, \
__LINE__)
#define os_file_copy_pfs(src, src_offset, dest, dest_offset, size) \
pfs_os_file_copy_func(src, src_offset, dest, dest_offset, size, __FILE__, \
__LINE__)
#define os_file_read_no_error_handling_pfs(type, file_name, file, buf, offset, \
n, o) \
pfs_os_file_read_no_error_handling_func(type, file_name, file, buf, offset, \
n, o, __FILE__, __LINE__)
#define os_file_read_no_error_handling_int_fd(type, file_name, file, buf, \
offset, n, o) \
pfs_os_file_read_no_error_handling_int_fd_func( \
type, file_name, file, buf, offset, n, o, __FILE__, __LINE__)
#define os_file_write_pfs(type, name, file, buf, offset, n) \
pfs_os_file_write_func(type, name, file, buf, offset, n, __FILE__, __LINE__)
#define os_file_write_int_fd(type, name, file, buf, offset, n) \
pfs_os_file_write_int_fd_func(type, name, file, buf, offset, n, __FILE__, \
__LINE__)
#define os_file_flush_pfs(file) pfs_os_file_flush_func(file, __FILE__, __LINE__)
#define os_file_rename(key, oldpath, newpath) \
pfs_os_file_rename_func(key, oldpath, newpath, __FILE__, __LINE__)
#define os_file_delete(key, name) \
pfs_os_file_delete_func(key, name, __FILE__, __LINE__)
#define os_file_delete_if_exists(key, name, exist) \
pfs_os_file_delete_if_exists_func(key, name, exist, __FILE__, __LINE__)
/** NOTE! Please use the corresponding macro os_file_create_simple(),
not directly this function!
A performance schema instrumented wrapper function for
os_file_create_simple() which opens or creates a file.
@param[in] key Performance Schema Key
@param[in] name name of the file or path as a null-terminated
string
@param[in] create_mode create mode
@param[in] access_type OS_FILE_READ_ONLY or OS_FILE_READ_WRITE
@param[in] read_only if true read only mode checks are enforced
@param[out] success true if succeeded
@param[in] src_file file name where func invoked
@param[in] src_line line where the func invoked
@return own: handle to the file, not defined if error, error number
can be retrieved with os_file_get_last_error */
UNIV_INLINE
pfs_os_file_t pfs_os_file_create_simple_func(
mysql_pfs_key_t key, const char *name, ulint create_mode, ulint access_type,
bool read_only, bool *success, const char *src_file, uint src_line)
MY_ATTRIBUTE((warn_unused_result));
/** NOTE! Please use the corresponding macro
os_file_create_simple_no_error_handling(), not directly this function!
A performance schema instrumented wrapper function for
os_file_create_simple_no_error_handling(). Add instrumentation to
monitor file creation/open.
@param[in] key Performance Schema Key
@param[in] name name of the file or path as a null-terminated
string
@param[in] create_mode create mode
@param[in] access_type OS_FILE_READ_ONLY, OS_FILE_READ_WRITE, or
OS_FILE_READ_ALLOW_DELETE; the last option is
used by a backup program reading the file
@param[in] read_only if true read only mode checks are enforced
@param[out] success true if succeeded
@param[in] src_file file name where func invoked
@param[in] src_line line where the func invoked
@return own: handle to the file, not defined if error, error number
can be retrieved with os_file_get_last_error */
UNIV_INLINE
pfs_os_file_t pfs_os_file_create_simple_no_error_handling_func(
mysql_pfs_key_t key, const char *name, ulint create_mode, ulint access_type,
bool read_only, bool *success, const char *src_file, uint src_line)
MY_ATTRIBUTE((warn_unused_result));
/** NOTE! Please use the corresponding macro os_file_create(), not directly
this function!
A performance schema wrapper function for os_file_create().
Add instrumentation to monitor file creation/open.
@param[in] key Performance Schema Key
@param[in] name name of the file or path as a null-terminated
string
@param[in] create_mode create mode
@param[in] purpose OS_FILE_AIO, if asynchronous, non-buffered I/O
is desired, OS_FILE_NORMAL, if any normal file;
NOTE that it also depends on type, os_aio_..
and srv_.. variables whether we really use
async I/O or unbuffered I/O: look in the
function source code for the exact rules
@param[in] type OS_DATA_FILE or OS_LOG_FILE
@param[in] read_only if true read only mode checks are enforced
@param[out] success true if succeeded
@param[in] src_file file name where func invoked
@param[in] src_line line where the func invoked
@return own: handle to the file, not defined if error, error number
can be retrieved with os_file_get_last_error */
UNIV_INLINE
pfs_os_file_t pfs_os_file_create_func(mysql_pfs_key_t key, const char *name,
ulint create_mode, ulint purpose,
ulint type, bool read_only, bool *success,
const char *src_file, uint src_line)
MY_ATTRIBUTE((warn_unused_result));
/** NOTE! Please use the corresponding macro os_file_close(), not directly
this function!
A performance schema instrumented wrapper function for os_file_close().
@param[in] file handle to a file
@param[in] src_file file name where func invoked
@param[in] src_line line where the func invoked
@return true if success */
UNIV_INLINE
bool pfs_os_file_close_func(pfs_os_file_t file, const char *src_file,
uint src_line);
/** NOTE! Please use the corresponding macro os_file_read(), not directly
this function!
This is the performance schema instrumented wrapper function for
os_file_read() which requests a synchronous read operation.
@param[in, out] type IO request context
@param[in] file_name file name
@param[in] file Open file handle
@param[out] buf buffer where to read
@param[in] offset file offset where to read
@param[in] n number of bytes to read
@param[in] src_file file name where func invoked
@param[in] src_line line where the func invoked
@return DB_SUCCESS if request was successful */
UNIV_INLINE
dberr_t pfs_os_file_read_func(IORequest &type, const char *file_name,
pfs_os_file_t file, void *buf, os_offset_t offset,
ulint n, const char *src_file, uint src_line);
/** NOTE! Please use the corresponding macro os_file_read_first_page(),
not directly this function!
This is the performance schema instrumented wrapper function for
os_file_read_first_page() which requests a synchronous read operation
of page 0 of IBD file
@param[in, out] type IO request context
@param[in] file_name file name
@param[in] file Open file handle
@param[out] buf buffer where to read
@param[in] n number of bytes to read
@param[in] src_file file name where func invoked
@param[in] src_line line where the func invoked
@return DB_SUCCESS if request was successful */
UNIV_INLINE
dberr_t pfs_os_file_read_first_page_func(IORequest &type, const char *file_name,
pfs_os_file_t file, void *buf, ulint n,
const char *src_file, uint src_line);
/** copy data from one file to another file. Data is read/written
at current file offset.
@param[in] src file handle to copy from
@param[in] src_offset offset to copy from
@param[in] dest file handle to copy to
@param[in] dest_offset offset to copy to
@param[in] size number of bytes to copy
@param[in] src_file file name where func invoked
@param[in] src_line line where the func invoked
@return DB_SUCCESS if successful */
UNIV_INLINE
dberr_t pfs_os_file_copy_func(pfs_os_file_t src, os_offset_t src_offset,
pfs_os_file_t dest, os_offset_t dest_offset,
uint size, const char *src_file, uint src_line);
/** NOTE! Please use the corresponding macro os_file_read_no_error_handling(),
not directly this function!
This is the performance schema instrumented wrapper function for
os_file_read_no_error_handling_func() which requests a synchronous
read operation.
@param[in, out] type IO request context
@param[in] file_name file name
@param[in] file Open file handle
@param[out] buf buffer where to read
@param[in] offset file offset where to read
@param[in] n number of bytes to read
@param[out] o number of bytes actually read
@param[in] src_file file name where func invoked
@param[in] src_line line where the func invoked
@return DB_SUCCESS if request was successful */
UNIV_INLINE
dberr_t pfs_os_file_read_no_error_handling_func(
IORequest &type, const char *file_name, pfs_os_file_t file, void *buf,
os_offset_t offset, ulint n, ulint *o, const char *src_file, uint src_line);
/** NOTE! Please use the corresponding macro
os_file_read_no_error_handling_int_fd(), not directly this function!
This is the performance schema instrumented wrapper function for
os_file_read_no_error_handling_int_fd_func() which requests a
synchronous read operation on files with int type descriptors.
@param[in, out] type IO request context
@param[in] file_name file name
@param[in] file Open file handle
@param[out] buf buffer where to read
@param[in] offset file offset where to read
@param[in] n number of bytes to read
@param[out] o number of bytes actually read
@param[in] src_file file name where func invoked
@param[in] src_line line where the func invoked
@return DB_SUCCESS if request was successful */
UNIV_INLINE
dberr_t pfs_os_file_read_no_error_handling_int_fd_func(
IORequest &type, const char *file_name, int file, void *buf,
os_offset_t offset, ulint n, ulint *o, const char *src_file,
ulint src_line);
/** NOTE! Please use the corresponding macro os_aio(), not directly this
function!
Performance schema wrapper function of os_aio() which requests
an asynchronous I/O operation.
@param[in] type IO request context
@param[in] mode IO mode
@param[in] name Name of the file or path as NUL terminated
string
@param[in] file Open file handle
@param[out] buf buffer where to read
@param[in] offset file offset where to read
@param[in] n number of bytes to read
@param[in] read_only if true read only mode checks are enforced
@param[in,out] m1 Message for the AIO handler, (can be used to
identify a completed AIO operation); ignored
if mode is OS_AIO_SYNC
@param[in,out] m2 message for the AIO handler (can be used to
identify a completed AIO operation); ignored
if mode is OS_AIO_SYNC
@param[in] src_file file name where func invoked
@param[in] src_line line where the func invoked
@return DB_SUCCESS if request was queued successfully, false if fail */
UNIV_INLINE
dberr_t pfs_os_aio_func(IORequest &type, AIO_mode mode, const char *name,
pfs_os_file_t file, void *buf, os_offset_t offset,
ulint n, bool read_only, fil_node_t *m1, void *m2,
const char *src_file, uint src_line);
/** NOTE! Please use the corresponding macro os_file_write(), not directly
this function!
This is the performance schema instrumented wrapper function for
os_file_write() which requests a synchronous write operation.
@param[in, out] type IO request context
@param[in] name Name of the file or path as NUL terminated
string
@param[in] file Open file handle
@param[out] buf buffer where to read
@param[in] offset file offset where to read
@param[in] n number of bytes to read
@param[in] src_file file name where func invoked
@param[in] src_line line where the func invoked
@return DB_SUCCESS if request was successful */
UNIV_INLINE
dberr_t pfs_os_file_write_func(IORequest &type, const char *name,
pfs_os_file_t file, const void *buf,
os_offset_t offset, ulint n,
const char *src_file, uint src_line);
/** NOTE! Please use the corresponding macro os_file_write(), not
directly this function!
This is the performance schema instrumented wrapper function for
os_file_write() which requests a synchronous write operation
on files with int type descriptors.
@param[in, out] type IO request context
@param[in] name Name of the file or path as NUL terminated
string
@param[in] file Open file handle
@param[out] buf buffer where to read
@param[in] offset file offset where to read
@param[in] n number of bytes to read
@param[in] src_file file name where func invoked
@param[in] src_line line where the func invoked
@return DB_SUCCESS if request was successful */
UNIV_INLINE
dberr_t pfs_os_file_write_int_fd_func(IORequest &type, const char *name,
int file, const void *buf,
os_offset_t offset, ulint n,
const char *src_file, ulint src_line);
/** NOTE! Please use the corresponding macro os_file_flush(), not directly
this function!
This is the performance schema instrumented wrapper function for
os_file_flush() which flushes the write buffers of a given file to the disk.
Flushes the write buffers of a given file to the disk.
@param[in] file Open file handle
@param[in] src_file file name where func invoked
@param[in] src_line line where the func invoked
@return true if success */
UNIV_INLINE
bool pfs_os_file_flush_func(pfs_os_file_t file, const char *src_file,
uint src_line);
/** NOTE! Please use the corresponding macro os_file_rename(), not directly
this function!
This is the performance schema instrumented wrapper function for
os_file_rename()
@param[in] key Performance Schema Key
@param[in] oldpath old file path as a null-terminated string
@param[in] newpath new file path
@param[in] src_file file name where func invoked
@param[in] src_line line where the func invoked
@return true if success */
UNIV_INLINE
bool pfs_os_file_rename_func(mysql_pfs_key_t key, const char *oldpath,
const char *newpath, const char *src_file,
uint src_line);
/**
NOTE! Please use the corresponding macro os_file_delete(), not directly
this function!
This is the performance schema instrumented wrapper function for
os_file_delete()
@param[in] key Performance Schema Key
@param[in] name old file path as a null-terminated string
@param[in] src_file file name where func invoked
@param[in] src_line line where the func invoked
@return true if success */
UNIV_INLINE
bool pfs_os_file_delete_func(mysql_pfs_key_t key, const char *name,
const char *src_file, uint src_line);
/**
NOTE! Please use the corresponding macro os_file_delete_if_exists(), not
directly this function!
This is the performance schema instrumented wrapper function for
os_file_delete_if_exists()
@param[in] key Performance Schema Key
@param[in] name old file path as a null-terminated string
@param[in] exist indicate if file pre-exist
@param[in] src_file file name where func invoked
@param[in] src_line line where the func invoked
@return true if success */
UNIV_INLINE
bool pfs_os_file_delete_if_exists_func(mysql_pfs_key_t key, const char *name,
bool *exist, const char *src_file,
uint src_line);
#else /* UNIV_PFS_IO */
/* If UNIV_PFS_IO is not defined, these I/O APIs point
to original un-instrumented file I/O APIs */
#define os_file_create(key, name, create, purpose, type, read_only, success) \
os_file_create_func(name, create, purpose, type, read_only, success)
#define os_file_create_simple(key, name, create_mode, access, read_only, \
success) \
os_file_create_simple_func(name, create_mode, access, read_only, success)
#define os_file_create_simple_no_error_handling(key, name, create_mode, \
access, read_only, success) \
os_file_create_simple_no_error_handling_func(name, create_mode, access, \
read_only, success)
#define os_file_close_pfs(file) os_file_close_func(file)
#define os_aio(type, mode, name, file, buf, offset, n, read_only, message1, \
message2) \
os_aio_func(type, mode, name, file, buf, offset, n, read_only, message1, \
message2)
#define os_file_read_pfs(type, file_name, file, buf, offset, n) \
os_file_read_func(type, file_name, file, buf, offset, n)
#define os_file_read_first_page_pfs(type, file_name, file, buf, n) \
os_file_read_first_page_func(type, file_name, file, buf, n)
#define os_file_copy_pfs(src, src_offset, dest, dest_offset, size) \
os_file_copy_func(src, src_offset, dest, dest_offset, size)
#define os_file_read_no_error_handling_pfs(type, file_name, file, buf, offset, \
n, o) \
os_file_read_no_error_handling_func(type, file_name, file, buf, offset, n, o)
#define os_file_read_no_error_handling_int_fd(type, file_name, file, buf, \
offset, n, o) \
os_file_read_no_error_handling_func(type, file_name, file, buf, offset, n, o)
#define os_file_write_pfs(type, name, file, buf, offset, n) \
os_file_write_func(type, name, file, buf, offset, n)
#define os_file_write_int_fd(type, name, file, buf, offset, n) \
os_file_write_func(type, name, file, buf, offset, n)
#define os_file_flush_pfs(file) os_file_flush_func(file)
#define os_file_rename(key, oldpath, newpath) \
os_file_rename_func(oldpath, newpath)
#define os_file_delete(key, name) os_file_delete_func(name)
#define os_file_delete_if_exists(key, name, exist) \
os_file_delete_if_exists_func(name, exist)
#endif /* UNIV_PFS_IO */
#ifdef UNIV_PFS_IO
#define os_file_close(file) os_file_close_pfs(file)
#else
#define os_file_close(file) os_file_close_pfs((file).m_file)
#endif
#ifdef UNIV_PFS_IO
#define os_file_read(type, file_name, file, buf, offset, n) \
os_file_read_pfs(type, file_name, file, buf, offset, n)
#else
#define os_file_read(type, file_name, file, buf, offset, n) \
os_file_read_pfs(type, file_name, file.m_file, buf, offset, n)
#endif
#ifdef UNIV_PFS_IO
#define os_file_read_first_page(type, file_name, file, buf, n) \
os_file_read_first_page_pfs(type, file_name, file, buf, n)
#else
#define os_file_read_first_page(type, file_name, file, buf, n) \
os_file_read_first_page_pfs(type, file_name, file.m_file, buf, n)
#endif
#ifdef UNIV_PFS_IO
#define os_file_flush(file) os_file_flush_pfs(file)
#else
#define os_file_flush(file) os_file_flush_pfs(file.m_file)
#endif
#ifdef UNIV_PFS_IO
#define os_file_write(type, name, file, buf, offset, n) \
os_file_write_pfs(type, name, file, buf, offset, n)
#else
#define os_file_write(type, name, file, buf, offset, n) \
os_file_write_pfs(type, name, file.m_file, buf, offset, n)
#endif
#ifdef UNIV_PFS_IO
#define os_file_copy(src, src_offset, dest, dest_offset, size) \
os_file_copy_pfs(src, src_offset, dest, dest_offset, size)
#else
#define os_file_copy(src, src_offset, dest, dest_offset, size) \
os_file_copy_pfs(src.m_file, src_offset, dest.m_file, dest_offset, size)
#endif
#ifdef UNIV_PFS_IO
#define os_file_read_no_error_handling(type, file_name, file, buf, offset, n, \
o) \
os_file_read_no_error_handling_pfs(type, file_name, file, buf, offset, n, o)
#else
#define os_file_read_no_error_handling(type, file_name, file, buf, offset, n, \
o) \
os_file_read_no_error_handling_pfs(type, file_name, file.m_file, buf, \
offset, n, o)
#endif
#ifdef UNIV_HOTBACKUP
/** Closes a file handle.
@param[in] file handle to a file
@return true if success */
bool os_file_close_no_error_handling(os_file_t file);
#endif /* UNIV_HOTBACKUP */
/** Gets a file size.
@param[in] filename handle to a file
@return file size if OK, else set m_total_size to ~0 and m_alloc_size
to errno */
os_file_size_t os_file_get_size(const char *filename)
MY_ATTRIBUTE((warn_unused_result));
/** Gets a file size.
@param[in] file handle to a file
@return file size, or (os_offset_t) -1 on failure */
os_offset_t os_file_get_size(pfs_os_file_t file)
MY_ATTRIBUTE((warn_unused_result));
/** Write the specified number of zeros to a file from specific offset.
@param[in] name name of the file or path as a null-terminated
string
@param[in] file handle to a file
@param[in] offset file offset
@param[in] size file size
@param[in] read_only Enable read-only checks if true
@param[in] flush Flush file content to disk
@return true if success */
bool os_file_set_size(const char *name, pfs_os_file_t file, os_offset_t offset,
os_offset_t size, bool read_only, bool flush)
MY_ATTRIBUTE((warn_unused_result));
/** Truncates a file at its current position.
@param[in,out] file file to be truncated
@return true if success */
bool os_file_set_eof(FILE *file); /*!< in: file to be truncated */
/** Truncates a file to a specified size in bytes. Do nothing if the size
preserved is smaller or equal than current size of file.
@param[in] pathname file path
@param[in] file file to be truncated
@param[in] size size preserved in bytes
@return true if success */
bool os_file_truncate(const char *pathname, pfs_os_file_t file,
os_offset_t size);
/** Set read/write position of a file handle to specific offset.
@param[in] pathname file path
@param[in] file file handle
@param[in] offset read/write offset
@return true if success */
bool os_file_seek(const char *pathname, os_file_t file, os_offset_t offset);
/** NOTE! Use the corresponding macro os_file_flush(), not directly this
function!
Flushes the write buffers of a given file to the disk.
@param[in] file handle to a file
@return true if success */
bool os_file_flush_func(os_file_t file);
/** Retrieves the last error number if an error occurs in a file io function.
The number should be retrieved before any other OS calls (because they may
overwrite the error number). If the number is not known to this program,
the OS error number + 100 is returned.
@param[in] report_all_errors true if we want an error message printed
for all errors
@return error number, or OS error number + 100 */
ulint os_file_get_last_error(bool report_all_errors);
/** NOTE! Use the corresponding macro os_file_read(), not directly this
function!
Requests a synchronous read operation.
@param[in] type IO request context
@param[in] file_name file name
@param[in] file Open file handle
@param[out] buf buffer where to read
@param[in] offset file offset where to read
@param[in] n number of bytes to read
@return DB_SUCCESS if request was successful */
dberr_t os_file_read_func(IORequest &type, const char *file_name,
os_file_t file, void *buf, os_offset_t offset,
ulint n) MY_ATTRIBUTE((warn_unused_result));
/** NOTE! Use the corresponding macro os_file_read_first_page(),
not directly this function!
Requests a synchronous read operation of page 0 of IBD file
@param[in] type IO request context
@param[in] file_name file name
@param[in] file Open file handle
@param[out] buf buffer where to read
@param[in] n number of bytes to read
@return DB_SUCCESS if request was successful */
dberr_t os_file_read_first_page_func(IORequest &type, const char *file_name,
os_file_t file, void *buf, ulint n)
MY_ATTRIBUTE((warn_unused_result));
/** copy data from one file to another file. Data is read/written
at current file offset.
@param[in] src_file file handle to copy from
@param[in] src_offset offset to copy from
@param[in] dest_file file handle to copy to
@param[in] dest_offset offset to copy to
@param[in] size number of bytes to copy
@return DB_SUCCESS if successful */
dberr_t os_file_copy_func(os_file_t src_file, os_offset_t src_offset,
os_file_t dest_file, os_offset_t dest_offset,
uint size) MY_ATTRIBUTE((warn_unused_result));
/** Rewind file to its start, read at most size - 1 bytes from it to str, and
NUL-terminate str. All errors are silently ignored. This function is
mostly meant to be used with temporary files.
@param[in,out] file file to read from
@param[in,out] str buffer where to read
@param[in] size size of buffer */
void os_file_read_string(FILE *file, char *str, ulint size);
/** NOTE! Use the corresponding macro os_file_read_no_error_handling(),
not directly this function!
Requests a synchronous positioned read operation. This function does not do
any error handling. In case of error it returns FALSE.
@param[in] type IO request context
@param[in] file_name file name
@param[in] file Open file handle
@param[out] buf buffer where to read
@param[in] offset file offset where to read
@param[in] n number of bytes to read
@param[out] o number of bytes actually read
@return DB_SUCCESS or error code */
dberr_t os_file_read_no_error_handling_func(
IORequest &type, const char *file_name, os_file_t file, void *buf,
os_offset_t offset, ulint n, ulint *o) MY_ATTRIBUTE((warn_unused_result));
/** NOTE! Use the corresponding macro os_file_write(), not directly this
function!
Requests a synchronous write operation.
@param[in,out] type IO request context
@param[in] name name of the file or path as a null-terminated
string
@param[in] file Open file handle
@param[out] buf buffer where to read
@param[in] offset file offset where to read
@param[in] n number of bytes to read
@return DB_SUCCESS if request was successful */
dberr_t os_file_write_func(IORequest &type, const char *name, os_file_t file,
const void *buf, os_offset_t offset, ulint n)
MY_ATTRIBUTE((warn_unused_result));
/** Check the existence and type of the given file.
@param[in] path pathname of the file
@param[out] exists true if file exists
@param[out] type type of the file (if it exists)
@return true if call succeeded */
bool os_file_status(const char *path, bool *exists, os_file_type_t *type);
/** Create all missing subdirectories along the given path.
@return DB_SUCCESS if OK, otherwise error code. */
dberr_t os_file_create_subdirs_if_needed(const char *path);
#ifdef UNIV_ENABLE_UNIT_TEST_GET_PARENT_DIR
/* Test the function os_file_get_parent_dir. */
void unit_test_os_file_get_parent_dir();
#endif /* UNIV_ENABLE_UNIT_TEST_GET_PARENT_DIR */
#ifdef UNIV_HOTBACKUP
/** Deallocates the "Blocks" in block_cache */
void meb_free_block_cache();
#endif /* UNIV_HOTBACKUP */
/** Creates and initializes block_cache. Creates array of MAX_BLOCKS
and allocates the memory in each block to hold BUFFER_BLOCK_SIZE
of data.
This function is called by InnoDB during srv_start().
It is also called by MEB while applying the redo logs on TDE tablespaces,
the "Blocks" allocated in this block_cache are used to hold the decrypted
page data. */
void os_create_block_cache();
/** Initializes the asynchronous io system. Creates one array each for ibuf
and log i/o. Also creates one array each for read and write where each
array is divided logically into n_read_segs and n_write_segs
respectively. The caller must create an i/o handler thread for each
segment in these arrays. This function also creates the sync array.
No i/o handler thread needs to be created for that
@param[in] n_readers number of reader threads
@param[in] n_writers number of writer threads
@param[in] n_slots_sync number of slots in the sync aio array */
bool os_aio_init(ulint n_readers, ulint n_writers, ulint n_slots_sync);
/**
Frees the asynchronous io system. */
void os_aio_free();
/**
NOTE! Use the corresponding macro os_aio(), not directly this function!
Requests an asynchronous i/o operation.
@param[in] type IO request context
@param[in] aio_mode IO mode
@param[in] name Name of the file or path as NUL terminated
string
@param[in] file Open file handle
@param[out] buf buffer where to read
@param[in] offset file offset where to read
@param[in] n number of bytes to read
@param[in] read_only if true read only mode checks are enforced
@param[in,out] m1 Message for the AIO handler, (can be used to
identify a completed AIO operation); ignored
if mode is OS_AIO_SYNC
@param[in,out] m2 message for the AIO handler (can be used to
identify a completed AIO operation); ignored
if mode is OS_AIO_SYNC
@return DB_SUCCESS or error code */
dberr_t os_aio_func(IORequest &type, AIO_mode aio_mode, const char *name,
pfs_os_file_t file, void *buf, os_offset_t offset, ulint n,
bool read_only, fil_node_t *m1, void *m2);
/** Wakes up all async i/o threads so that they know to exit themselves in
shutdown. */
void os_aio_wake_all_threads_at_shutdown();
/** Waits until there are no pending writes in os_aio_write_array. There can
be other, synchronous, pending writes. */
void os_aio_wait_until_no_pending_writes();
/** Wakes up simulated aio i/o-handler threads if they have something to do. */
void os_aio_simulated_wake_handler_threads();
/** This function can be called if one wants to post a batch of reads and
prefers an i/o-handler thread to handle them all at once later. You must
call os_aio_simulated_wake_handler_threads later to ensure the threads
are not left sleeping! */
void os_aio_simulated_put_read_threads_to_sleep();
/** This is the generic AIO handler interface function.
Waits for an aio operation to complete. This function is used to wait the
for completed requests. The AIO array of pending requests is divided
into segments. The thread specifies which segment or slot it wants to wait
for. NOTE: this function will also take care of freeing the aio slot,
therefore no other thread is allowed to do the freeing!
@param[in] segment the number of the segment in the aio arrays to
wait for; segment 0 is the ibuf I/O thread,
segment 1 the log I/O thread, then follow the
non-ibuf read threads, and as the last are the
non-ibuf write threads; if this is
ULINT_UNDEFINED, then it means that sync AIO
is used, and this parameter is ignored
@param[out] m1 the messages passed with the AIO request;
note that also in the case where the AIO
operation failed, these output parameters
are valid and can be used to restart the
operation, for example
@param[out] m2 callback message
@param[out] request OS_FILE_WRITE or ..._READ
@return DB_SUCCESS or error code */
dberr_t os_aio_handler(ulint segment, fil_node_t **m1, void **m2,
IORequest *request);
/** Prints info of the aio arrays.
@param[in,out] file file where to print */
void os_aio_print(FILE *file);
/** Refreshes the statistics used to print per-second averages. */
void os_aio_refresh_stats();
/** Checks that all slots in the system have been freed, that is, there are
no pending io operations. */
bool os_aio_all_slots_free();
#ifdef UNIV_DEBUG
/** Prints all pending IO
@param[in] file file where to print */
void os_aio_print_pending_io(FILE *file);
#endif /* UNIV_DEBUG */
/** Get available free space on disk
@param[in] path pathname of a directory or file in disk
@param[out] free_space free space available in bytes
@return DB_SUCCESS if all OK */
dberr_t os_get_free_space(const char *path, uint64_t &free_space);
/** This function returns information about the specified file
@param[in] path pathname of the file
@param[in] stat_info information of a file in a directory
@param[in] check_rw_perm for testing whether the file can be opened
in RW mode
@param[in] read_only if true read only mode checks are enforced
@return DB_SUCCESS if all OK */
dberr_t os_file_get_status(const char *path, os_file_stat_t *stat_info,
bool check_rw_perm, bool read_only);
#ifndef UNIV_HOTBACKUP
/** return any of the tmpdir path */
char *innobase_mysql_tmpdir();
/** Creates a temporary file in the location specified by the parameter
path. If the path is NULL then it will be created on --tmpdir location.
This function is defined in ha_innodb.cc.
@param[in] path location for creating temporary file
@return temporary file descriptor, or < 0 on error */
int innobase_mysql_tmpfile(const char *path);
#endif /* !UNIV_HOTBACKUP */
/** If it is a compressed page return the compressed page data + footer size
@param[in] buf Buffer to check, must include header + 10 bytes
@return ULINT_UNDEFINED if the page is not a compressed page or length
of the compressed data (including footer) if it is a compressed page */
ulint os_file_compressed_page_size(const byte *buf);
/** If it is a compressed page return the original page data + footer size
@param[in] buf Buffer to check, must include header + 10 bytes
@return ULINT_UNDEFINED if the page is not a compressed page or length
of the original data + footer if it is a compressed page */
ulint os_file_original_page_size(const byte *buf);
/** Set the file create umask
@param[in] umask The umask to use for file creation. */
void os_file_set_umask(ulint umask);
/** Get the file create umask
@return the umask to use for file creation. */
ulint os_file_get_umask();
/** Free storage space associated with a section of the file.
@param[in] fh Open file handle
@param[in] off Starting offset (SEEK_SET)
@param[in] len Size of the hole
@return DB_SUCCESS or error code */
dberr_t os_file_punch_hole(os_file_t fh, os_offset_t off, os_offset_t len)
MY_ATTRIBUTE((warn_unused_result));
/** Check if the file system supports sparse files.
Warning: On POSIX systems we try and punch a hole from offset 0 to
the system configured page size. This should only be called on an empty
file.
Note: On Windows we use the name and on Unices we use the file handle.
@param[in] path File name
@param[in] fh File handle for the file - if opened
@return true if the file system supports sparse files */
bool os_is_sparse_file_supported(const char *path, pfs_os_file_t fh)
MY_ATTRIBUTE((warn_unused_result));
/** Decompress the page data contents. Page type must be FIL_PAGE_COMPRESSED, if
not then the source contents are left unchanged and DB_SUCCESS is returned.
@param[in] dblwr_recover true of double write recovery in progress
@param[in,out] src Data read from disk, decompressed data will be
copied to this page
@param[in,out] dst Scratch area to use for decompression
@param[in] dst_len Size of the scratch area in bytes
@return DB_SUCCESS or error code */
dberr_t os_file_decompress_page(bool dblwr_recover, byte *src, byte *dst,
ulint dst_len)
MY_ATTRIBUTE((warn_unused_result));
/** Compress a data page
@param[in] compression Compression algorithm
@param[in] block_size File system block size
@param[in] src Source contents to compress
@param[in] src_len Length in bytes of the source
@param[out] dst Compressed page contents
@param[out] dst_len Length in bytes of dst contents
@return buffer data, dst_len will have the length of the data */
byte *os_file_compress_page(Compression compression, ulint block_size,
byte *src, ulint src_len, byte *dst,
ulint *dst_len);
/** Determine if O_DIRECT is supported.
@retval true if O_DIRECT is supported.
@retval false if O_DIRECT is not supported. */
bool os_is_o_direct_supported() MY_ATTRIBUTE((warn_unused_result));
/** Class to scan the directory heirarchy using a depth first scan. */
class Dir_Walker {
public:
using Path = std::string;
/** Check if the path is a directory. The file/directory must exist.
@param[in] path The path to check
@return true if it is a directory */
static bool is_directory(const Path &path);
/** Depth first traversal of the directory starting from basedir
@param[in] basedir Start scanning from this directory
@param[in] recursive `true` if scan should be recursive
@param[in] f Function to call for each entry */
template <typename F>
static void walk(const Path &basedir, bool recursive, F &&f) {
#ifdef _WIN32
walk_win32(basedir, recursive,
[&](const Path &path, size_t depth) { f(path); });
#else
walk_posix(basedir, recursive,
[&](const Path &path, size_t depth) { f(path); });
#endif /* _WIN32 */
}
private:
/** Directory names for the depth first directory scan. */
struct Entry {
/** Constructor
@param[in] path Directory to traverse
@param[in] depth Relative depth to the base
directory in walk() */
Entry(const Path &path, size_t depth) : m_path(path), m_depth(depth) {}
/** Path to the directory */
Path m_path;
/** Relative depth of m_path */
size_t m_depth;
};
using Function = std::function<void(const Path &, size_t)>;
/** Depth first traversal of the directory starting from basedir
@param[in] basedir Start scanning from this directory
@param[in] recursive `true` if scan should be recursive
@param[in] f Callback for each entry found */
#ifdef _WIN32
static void walk_win32(const Path &basedir, bool recursive, Function &&f);
#else
static void walk_posix(const Path &basedir, bool recursive, Function &&f);
#endif /* _WIN32 */
};
#include "os0file.ic"
/**
Convert the InnoDB Engine IO request to PPI defined IO type.
*/
inline PPI_IO_TYPE ppi_io_request_conversion(IORequest &type) {
if (type.is_read()) {
if (type.is_log()) return PPI_IO_NONE; // Didn't record log read.
return PPI_IO_DATAFILE_READ;
} else if (type.is_write()) {
if (type.is_log()) return PPI_IO_LOG_WRITE;
return PPI_IO_DATAFILE_WRITE;
}
return PPI_IO_NONE;
}
#endif /* os0file_h */