Commit 6247c64c authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-12396 IMPORT TABLESPACE cleanup

Reduce unnecessary inter-module calls for IMPORT TABLESPACE.
Move some IMPORT-related code from fil0fil.cc to row0import.cc.

PageCallback: Remove. Make AbstractCallback the base class.

PageConverter: Define some member functions inline.
parent eee73ddf
......@@ -25,8 +25,6 @@ Created 10/25/1995 Heikki Tuuri
*******************************************************/
#include "fil0fil.h"
#include "fil0pagecompress.h"
#include "fsp0pagecompress.h"
#include "fil0crypt.h"
#include <debug_sync.h>
......@@ -49,12 +47,10 @@ Created 10/25/1995 Heikki Tuuri
#include "page0zip.h"
#include "trx0sys.h"
#include "row0mysql.h"
#include "os0file.h"
#ifndef UNIV_HOTBACKUP
# include "buf0lru.h"
# include "ibuf0ibuf.h"
# include "sync0sync.h"
# include "os0sync.h"
#else /* !UNIV_HOTBACKUP */
# include "srv0srv.h"
static ulint srv_data_read, srv_data_written;
......@@ -696,7 +692,7 @@ fil_node_open_file(
space->size += node->size;
}
ulint atomic_writes = fsp_flags_get_atomic_writes(space->flags);
ulint atomic_writes = FSP_FLAGS_GET_ATOMIC_WRITES(space->flags);
/* printf("Opening file %s\n", node->name); */
......@@ -3921,7 +3917,6 @@ fil_open_single_table_tablespace(
fsp_open_info remote;
ulint tablespaces_found = 0;
ulint valid_tablespaces_found = 0;
ulint atomic_writes = 0;
fil_space_crypt_t* crypt_data = NULL;
#ifdef UNIV_SYNC_DEBUG
......@@ -3936,7 +3931,7 @@ fil_open_single_table_tablespace(
}
ut_ad(fsp_flags_is_valid(flags & ~FSP_FLAGS_MEM_MASK, id));
atomic_writes = fsp_flags_get_atomic_writes(flags);
const ulint atomic_writes = FSP_FLAGS_GET_ATOMIC_WRITES(flags);
memset(&def, 0, sizeof(def));
memset(&dict, 0, sizeof(dict));
......@@ -5841,7 +5836,8 @@ fil_io(
} else if (type == OS_FILE_WRITE) {
ut_ad(!srv_read_only_mode);
srv_stats.data_written.add(len);
if (fil_page_is_index_page((byte *)buf)) {
if (mach_read_from_2(static_cast<const byte*>(buf)
+ FIL_PAGE_TYPE) == FIL_PAGE_INDEX) {
srv_stats.index_pages_written.inc();
} else {
srv_stats.non_index_pages_written.inc();
......@@ -6338,479 +6334,6 @@ fil_close(void)
fil_system = NULL;
}
/********************************************************************//**
Initializes a buffer control block when the buf_pool is created. */
static
void
fil_buf_block_init(
/*===============*/
buf_block_t* block, /*!< in: pointer to control block */
byte* frame) /*!< in: pointer to buffer frame */
{
UNIV_MEM_DESC(frame, UNIV_PAGE_SIZE);
block->frame = frame;
block->page.io_fix = BUF_IO_NONE;
/* There are assertions that check for this. */
block->page.buf_fix_count = 1;
block->page.state = BUF_BLOCK_READY_FOR_USE;
page_zip_des_init(&block->page.zip);
}
struct fil_iterator_t {
pfs_os_file_t file; /*!< File handle */
const char* filepath; /*!< File path name */
os_offset_t start; /*!< From where to start */
os_offset_t end; /*!< Where to stop */
os_offset_t file_size; /*!< File size in bytes */
ulint page_size; /*!< Page size */
ulint n_io_buffers; /*!< Number of pages to use
for IO */
byte* io_buffer; /*!< Buffer to use for IO */
fil_space_crypt_t *crypt_data; /*!< Crypt data (if encrypted) */
byte* crypt_io_buffer; /*!< IO buffer when encrypted */
};
/********************************************************************//**
TODO: This can be made parallel trivially by chunking up the file and creating
a callback per thread. . Main benefit will be to use multiple CPUs for
checksums and compressed tables. We have to do compressed tables block by
block right now. Secondly we need to decompress/compress and copy too much
of data. These are CPU intensive.
Iterate over all the pages in the tablespace.
@param iter - Tablespace iterator
@param block - block to use for IO
@param callback - Callback to inspect and update page contents
@retval DB_SUCCESS or error code */
static
dberr_t
fil_iterate(
/*========*/
const fil_iterator_t& iter,
buf_block_t* block,
PageCallback& callback)
{
os_offset_t offset;
ulint page_no = 0;
ulint space_id = callback.get_space_id();
ulint n_bytes = iter.n_io_buffers * iter.page_size;
ut_ad(!srv_read_only_mode);
/* TODO: For compressed tables we do a lot of useless
copying for non-index pages. Unfortunately, it is
required by buf_zip_decompress() */
const bool row_compressed = callback.get_zip_size() > 0;
for (offset = iter.start; offset < iter.end; offset += n_bytes) {
byte* io_buffer = iter.io_buffer;
block->frame = io_buffer;
if (row_compressed) {
page_zip_des_init(&block->page.zip);
page_zip_set_size(&block->page.zip, iter.page_size);
block->page.zip.data = block->frame + UNIV_PAGE_SIZE;
ut_d(block->page.zip.m_external = true);
ut_ad(iter.page_size == callback.get_zip_size());
/* Zip IO is done in the compressed page buffer. */
io_buffer = block->page.zip.data;
}
/* We have to read the exact number of bytes. Otherwise the
InnoDB IO functions croak on failed reads. */
n_bytes = static_cast<ulint>(
ut_min(static_cast<os_offset_t>(n_bytes),
iter.end - offset));
ut_ad(n_bytes > 0);
ut_ad(!(n_bytes % iter.page_size));
const bool encrypted = iter.crypt_data != NULL
&& iter.crypt_data->should_encrypt();
/* Use additional crypt io buffer if tablespace is encrypted */
byte* const readptr = encrypted
? iter.crypt_io_buffer : io_buffer;
byte* const writeptr = readptr;
if (!os_file_read(iter.file, readptr, offset, (ulint) n_bytes)) {
ib_logf(IB_LOG_LEVEL_ERROR, "os_file_read() failed");
return(DB_IO_ERROR);
}
bool updated = false;
os_offset_t page_off = offset;
ulint n_pages_read = (ulint) n_bytes / iter.page_size;
bool decrypted = false;
for (ulint i = 0; i < n_pages_read; ++i) {
ulint size = iter.page_size;
dberr_t err = DB_SUCCESS;
byte* src = readptr + (i * size);
byte* dst = io_buffer + (i * size);
bool frame_changed = false;
ulint page_type = mach_read_from_2(src+FIL_PAGE_TYPE);
const bool page_compressed
= page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED
|| page_type == FIL_PAGE_PAGE_COMPRESSED;
/* If tablespace is encrypted, we need to decrypt
the page. Note that tablespaces are not in
fil_system during import. */
if (encrypted) {
decrypted = fil_space_decrypt(
iter.crypt_data,
dst, //dst
iter.page_size,
src, // src
&err); // src
if (err != DB_SUCCESS) {
return(err);
}
if (decrypted) {
updated = true;
} else {
if (!page_compressed && !row_compressed) {
block->frame = src;
frame_changed = true;
} else {
memcpy(dst, src, size);
}
}
}
/* If the original page is page_compressed, we need
to decompress page before we can update it. */
if (page_compressed) {
fil_decompress_page(NULL, dst, ulong(size),
NULL);
updated = true;
}
buf_block_set_file_page(block, space_id, page_no++);
if ((err = callback(page_off, block)) != DB_SUCCESS) {
return(err);
} else if (!updated) {
updated = buf_block_get_state(block)
== BUF_BLOCK_FILE_PAGE;
}
buf_block_set_state(block, BUF_BLOCK_NOT_USED);
buf_block_set_state(block, BUF_BLOCK_READY_FOR_USE);
/* If tablespace is encrypted we use additional
temporary scratch area where pages are read
for decrypting readptr == crypt_io_buffer != io_buffer.
Destination for decryption is a buffer pool block
block->frame == dst == io_buffer that is updated.
Pages that did not require decryption even when
tablespace is marked as encrypted are not copied
instead block->frame is set to src == readptr.
For encryption we again use temporary scratch area
writeptr != io_buffer == dst
that is then written to the tablespace
(1) For normal tables io_buffer == dst == writeptr
(2) For only page compressed tables
io_buffer == dst == writeptr
(3) For encrypted (and page compressed)
readptr != io_buffer == dst != writeptr
*/
ut_ad(!encrypted && !page_compressed ?
src == dst && dst == writeptr + (i * size):1);
ut_ad(page_compressed && !encrypted ?
src == dst && dst == writeptr + (i * size):1);
ut_ad(encrypted ?
src != dst && dst != writeptr + (i * size):1);
if (encrypted) {
memcpy(writeptr + (i * size),
row_compressed ? block->page.zip.data :
block->frame, size);
}
if (frame_changed) {
block->frame = dst;
}
src = io_buffer + (i * size);
if (page_compressed) {
ulint len = 0;
fil_compress_page(
NULL,
src,
NULL,
size,
0,/* FIXME: compression level */
512,/* FIXME: use proper block size */
encrypted,
&len);
updated = true;
}
/* If tablespace is encrypted, encrypt page before we
write it back. Note that we should not encrypt the
buffer that is in buffer pool. */
/* NOTE: At this stage of IMPORT the
buffer pool is not being used at all! */
if (decrypted && encrypted) {
byte *dest = writeptr + (i * size);
ulint space = mach_read_from_4(
src + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
ulint offset = mach_read_from_4(src + FIL_PAGE_OFFSET);
ib_uint64_t lsn = mach_read_from_8(src + FIL_PAGE_LSN);
byte* tmp = fil_encrypt_buf(
iter.crypt_data,
space,
offset,
lsn,
src,
iter.page_size == UNIV_PAGE_SIZE ? 0 : iter.page_size,
dest);
if (tmp == src) {
/* TODO: remove unnecessary memcpy's */
memcpy(dest, src, size);
}
updated = true;
}
page_off += iter.page_size;
block->frame += iter.page_size;
}
/* A page was updated in the set, write back to disk. */
if (updated
&& !os_file_write(
iter.filepath, iter.file, writeptr,
offset, (ulint) n_bytes)) {
ib_logf(IB_LOG_LEVEL_ERROR, "os_file_write() failed");
return(DB_IO_ERROR);
}
}
return(DB_SUCCESS);
}
/********************************************************************//**
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 */
UNIV_INTERN
dberr_t
fil_tablespace_iterate(
/*===================*/
dict_table_t* table,
ulint n_io_buffers,
PageCallback& callback)
{
dberr_t err;
pfs_os_file_t file;
char* filepath;
ut_a(n_io_buffers > 0);
ut_ad(!srv_read_only_mode);
DBUG_EXECUTE_IF("ib_import_trigger_corruption_1",
return(DB_CORRUPTION););
if (DICT_TF_HAS_DATA_DIR(table->flags)) {
dict_get_and_save_data_dir_path(table, false);
ut_a(table->data_dir_path);
filepath = os_file_make_remote_pathname(
table->data_dir_path, table->name, "ibd");
} else {
filepath = fil_make_ibd_name(table->name, false);
}
{
ibool success;
file = os_file_create_simple_no_error_handling(
innodb_file_data_key, filepath,
OS_FILE_OPEN, OS_FILE_READ_WRITE, &success, FALSE);
DBUG_EXECUTE_IF("fil_tablespace_iterate_failure",
{
static bool once;
if (!once || ut_rnd_interval(0, 10) == 5) {
once = true;
success = FALSE;
os_file_close(file);
}
});
if (!success) {
/* The following call prints an error message */
os_file_get_last_error(true);
ib_logf(IB_LOG_LEVEL_ERROR,
"Trying to import a tablespace, but could not "
"open the tablespace file %s", filepath);
mem_free(filepath);
return(DB_TABLESPACE_NOT_FOUND);
} else {
err = DB_SUCCESS;
}
}
callback.set_file(filepath, file);
os_offset_t file_size = os_file_get_size(file);
ut_a(file_size != (os_offset_t) -1);
/* The block we will use for every physical page */
buf_block_t block;
memset(&block, 0x0, sizeof(block));
/* Allocate a page to read in the tablespace header, so that we
can determine the page size and zip_size (if it is compressed).
We allocate an extra page in case it is a compressed table. One
page is to ensure alignement. */
void* page_ptr = mem_alloc(3 * UNIV_PAGE_SIZE);
byte* page = static_cast<byte*>(ut_align(page_ptr, UNIV_PAGE_SIZE));
fil_buf_block_init(&block, page);
/* Read the first page and determine the page and zip size. */
if (!os_file_read(file, page, 0, UNIV_PAGE_SIZE)) {
err = DB_IO_ERROR;
} else if ((err = callback.init(file_size, &block)) == DB_SUCCESS) {
fil_iterator_t iter;
iter.file = file;
iter.start = 0;
iter.end = file_size;
iter.filepath = filepath;
iter.file_size = file_size;
iter.n_io_buffers = n_io_buffers;
iter.page_size = callback.get_page_size();
/* In MariaDB/MySQL 5.6 tablespace does not exist
during import, therefore we can't use space directly
here. */
ulint crypt_data_offset = fsp_header_get_crypt_offset(
callback.get_zip_size());
/* read (optional) crypt data */
iter.crypt_data = fil_space_read_crypt_data(
0, page, crypt_data_offset);
/* Compressed pages can't be optimised for block IO for now.
We do the IMPORT page by page. */
if (callback.get_zip_size() > 0) {
iter.n_io_buffers = 1;
ut_a(iter.page_size == callback.get_zip_size());
}
/** If tablespace is encrypted, it needs extra buffers */
if (iter.crypt_data != NULL) {
/* decrease io buffers so that memory
* consumption doesnt double
* note: the +1 is to avoid n_io_buffers getting down to 0 */
iter.n_io_buffers = (iter.n_io_buffers + 1) / 2;
}
/** Add an extra page for compressed page scratch area. */
void* io_buffer = mem_alloc(
(2 + iter.n_io_buffers) * UNIV_PAGE_SIZE);
iter.io_buffer = static_cast<byte*>(
ut_align(io_buffer, UNIV_PAGE_SIZE));
void* crypt_io_buffer = NULL;
if (iter.crypt_data != NULL) {
crypt_io_buffer = mem_alloc(
(2 + iter.n_io_buffers) * UNIV_PAGE_SIZE);
iter.crypt_io_buffer = static_cast<byte*>(
ut_align(crypt_io_buffer, UNIV_PAGE_SIZE));
}
err = fil_iterate(iter, &block, callback);
mem_free(io_buffer);
if (crypt_io_buffer != NULL) {
mem_free(crypt_io_buffer);
iter.crypt_io_buffer = NULL;
fil_space_destroy_crypt_data(&iter.crypt_data);
}
}
if (err == DB_SUCCESS) {
ib_logf(IB_LOG_LEVEL_INFO, "Sync to disk");
if (!os_file_flush(file)) {
ib_logf(IB_LOG_LEVEL_INFO, "os_file_flush() failed!");
err = DB_IO_ERROR;
} else {
ib_logf(IB_LOG_LEVEL_INFO, "Sync to disk - done!");
}
}
os_file_close(file);
mem_free(page_ptr);
mem_free(filepath);
return(err);
}
/**
Set the tablespace compressed table size.
@return DB_SUCCESS if it is valie or DB_CORRUPTION if not */
dberr_t
PageCallback::set_zip_size(const buf_frame_t* page) UNIV_NOTHROW
{
m_zip_size = fsp_header_get_zip_size(page);
if (!ut_is_2pow(m_zip_size) || m_zip_size > UNIV_ZIP_SIZE_MAX) {
return(DB_CORRUPTION);
}
return(DB_SUCCESS);
}
/********************************************************************//**
Delete the tablespace file and any related files like .cfg.
This should not be called for temporary tables. */
......
......@@ -1292,107 +1292,6 @@ fil_delete_file(
/*============*/
const char* path); /*!< in: filepath of the ibd tablespace */
/** Callback functor. */
struct PageCallback {
/**
Default constructor */
PageCallback()
:
m_zip_size(),
m_page_size(),
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) 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) 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 ulint get_space_id() const UNIV_NOTHROW = 0;
/** The compressed page size
@return the compressed page size */
ulint get_zip_size() const
{
return(m_zip_size);
}
/**
Set the tablespace compressed table size.
@return DB_SUCCESS if it is valie or DB_CORRUPTION if not */
dberr_t set_zip_size(const buf_frame_t* page) UNIV_NOTHROW;
/** The compressed page size
@return the compressed page size */
ulint get_page_size() const
{
return(m_page_size);
}
/** Compressed table page size */
ulint m_zip_size;
/** The tablespace page size. */
ulint m_page_size;
/** File handle to the tablespace */
pfs_os_file_t m_file;
/** Physical file path. */
const char* m_filepath;
protected:
// Disable copying
PageCallback(const PageCallback&);
PageCallback& operator=(const PageCallback&);
};
/********************************************************************//**
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 */
UNIV_INTERN
dberr_t
fil_tablespace_iterate(
/*===================*/
dict_table_t* table,
ulint n_io_buffers,
PageCallback& callback)
MY_ATTRIBUTE((nonnull, warn_unused_result));
/*******************************************************************//**
Checks if a single-table tablespace for a given table name exists in the
tablespace memory cache.
......
......@@ -40,6 +40,7 @@ Created 2012-02-08 by Sunny Bains.
#include "row0mysql.h"
#include "srv0start.h"
#include "row0quiesce.h"
#include "fil0pagecompress.h"
#include <vector>
......@@ -361,7 +362,8 @@ class IndexPurge {
/** Functor that is called for each physical page that is read from the
tablespace file. */
class AbstractCallback : public PageCallback {
class AbstractCallback
{
public:
/** Constructor
@param trx - covering transaction */
......@@ -394,6 +396,47 @@ class AbstractCallback : public PageCallback {
return(get_zip_size() > 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;
}
/** The compressed page size
@return the compressed page size */
ulint get_zip_size() const
{
return(m_zip_size);
}
/** The compressed page size
@return the compressed page size */
ulint get_page_size() const
{
return(m_page_size);
}
/**
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) UNIV_NOTHROW = 0;
/**
@return the space id of the tablespace */
virtual ulint get_space_id() const UNIV_NOTHROW = 0;
protected:
/**
Get the data page depending on the table type, compressed or not.
......@@ -509,6 +552,18 @@ class AbstractCallback : public PageCallback {
}
protected:
/** Compressed table page size */
ulint m_zip_size;
/** The tablespace page size. */
ulint m_page_size;
/** File handle to the tablespace */
pfs_os_file_t m_file;
/** Physical file path. */
const char* m_filepath;
/** Covering transaction. */
trx_t* m_trx;
......@@ -565,9 +620,9 @@ AbstractCallback::init(
/* Since we don't know whether it is a compressed table
or not, the data is always read into the block->frame. */
dberr_t err = set_zip_size(block->frame);
m_zip_size = fsp_header_get_zip_size(page);
if (err != DB_SUCCESS) {
if (!ut_is_2pow(m_zip_size) || m_zip_size > UNIV_ZIP_SIZE_MAX) {
return(DB_CORRUPTION);
}
......@@ -604,11 +659,7 @@ AbstractCallback::init(
m_free_limit = mach_read_from_4(page + FSP_FREE_LIMIT);
m_space = mach_read_from_4(page + FSP_HEADER_OFFSET + FSP_SPACE_ID);
if ((err = set_current_xdes(0, page)) != DB_SUCCESS) {
return(err);
}
return(DB_SUCCESS);
return set_current_xdes(0, page);
}
/**
......@@ -1596,6 +1647,7 @@ IndexPurge::purge() UNIV_NOTHROW
Constructor
* @param cfg - config of table being imported.
* @param trx - transaction covering the import */
inline
PageConverter::PageConverter(
row_import* cfg,
trx_t* trx)
......@@ -1620,6 +1672,7 @@ Adjust the BLOB reference for a single column that is externally stored
@param offsets - column offsets for the record
@param i - column ordinal value
@return DB_SUCCESS or error code */
inline
dberr_t
PageConverter::adjust_cluster_index_blob_column(
rec_t* rec,
......@@ -1672,6 +1725,7 @@ stored columns.
@param rec - record to update
@param offsets - column offsets for the record
@return DB_SUCCESS or error code */
inline
dberr_t
PageConverter::adjust_cluster_index_blob_columns(
rec_t* rec,
......@@ -1705,6 +1759,7 @@ BLOB reference, write the new space id.
@param rec - record to update
@param offsets - column offsets for the record
@return DB_SUCCESS or error code */
inline
dberr_t
PageConverter::adjust_cluster_index_blob_ref(
rec_t* rec,
......@@ -1728,6 +1783,7 @@ Purge delete-marked records, only if it is possible to do so without
re-organising the B+tree.
@param offsets - current row offsets.
@return true if purge succeeded */
inline
bool
PageConverter::purge(const ulint* offsets) UNIV_NOTHROW
{
......@@ -1752,6 +1808,7 @@ Adjust the BLOB references and sys fields for the current record.
@param offsets - column offsets for the record
@param deleted - true if row is delete marked
@return DB_SUCCESS or error code. */
inline
dberr_t
PageConverter::adjust_cluster_record(
const dict_index_t* index,
......@@ -1780,6 +1837,7 @@ Update the BLOB refrences and write UNDO log entries for
rows that can't be purged optimistically.
@param block - block to update
@retval DB_SUCCESS or error code */
inline
dberr_t
PageConverter::update_records(
buf_block_t* block) UNIV_NOTHROW
......@@ -1845,6 +1903,7 @@ PageConverter::update_records(
/**
Update the space, index id, trx id.
@return DB_SUCCESS or error code */
inline
dberr_t
PageConverter::update_index_page(
buf_block_t* block) UNIV_NOTHROW
......@@ -1914,6 +1973,7 @@ PageConverter::update_index_page(
Validate the space flags and update tablespace header page.
@param block - block read from file, not from the buffer pool.
@retval DB_SUCCESS or error code */
inline
dberr_t
PageConverter::update_header(
buf_block_t* block) UNIV_NOTHROW
......@@ -1953,6 +2013,7 @@ PageConverter::update_header(
Update the page, set the space id, max trx id and index id.
@param block - block read from file
@retval DB_SUCCESS or error code */
inline
dberr_t
PageConverter::update_page(
buf_block_t* block,
......@@ -3423,6 +3484,436 @@ row_import_update_discarded_flag(
return(err);
}
struct fil_iterator_t {
pfs_os_file_t file; /*!< File handle */
const char* filepath; /*!< File path name */
os_offset_t start; /*!< From where to start */
os_offset_t end; /*!< Where to stop */
os_offset_t file_size; /*!< File size in bytes */
ulint page_size; /*!< Page size */
ulint n_io_buffers; /*!< Number of pages to use
for IO */
byte* io_buffer; /*!< Buffer to use for IO */
fil_space_crypt_t *crypt_data; /*!< Crypt data (if encrypted) */
byte* crypt_io_buffer; /*!< IO buffer when encrypted */
};
/********************************************************************//**
TODO: This can be made parallel trivially by chunking up the file and creating
a callback per thread. . Main benefit will be to use multiple CPUs for
checksums and compressed tables. We have to do compressed tables block by
block right now. Secondly we need to decompress/compress and copy too much
of data. These are CPU intensive.
Iterate over all the pages in the tablespace.
@param iter - Tablespace iterator
@param block - block to use for IO
@param callback - Callback to inspect and update page contents
@retval DB_SUCCESS or error code */
static
dberr_t
fil_iterate(
/*========*/
const fil_iterator_t& iter,
buf_block_t* block,
AbstractCallback& callback)
{
os_offset_t offset;
ulint page_no = 0;
ulint space_id = callback.get_space_id();
ulint n_bytes = iter.n_io_buffers * iter.page_size;
ut_ad(!srv_read_only_mode);
/* TODO: For compressed tables we do a lot of useless
copying for non-index pages. Unfortunately, it is
required by buf_zip_decompress() */
const bool row_compressed = callback.get_zip_size() > 0;
for (offset = iter.start; offset < iter.end; offset += n_bytes) {
byte* io_buffer = iter.io_buffer;
block->frame = io_buffer;
if (row_compressed) {
page_zip_des_init(&block->page.zip);
page_zip_set_size(&block->page.zip, iter.page_size);
block->page.zip.data = block->frame + UNIV_PAGE_SIZE;
ut_d(block->page.zip.m_external = true);
ut_ad(iter.page_size == callback.get_zip_size());
/* Zip IO is done in the compressed page buffer. */
io_buffer = block->page.zip.data;
}
/* We have to read the exact number of bytes. Otherwise the
InnoDB IO functions croak on failed reads. */
n_bytes = ulint(ut_min(os_offset_t(n_bytes),
iter.end - offset));
ut_ad(n_bytes > 0);
ut_ad(!(n_bytes % iter.page_size));
const bool encrypted = iter.crypt_data != NULL
&& iter.crypt_data->should_encrypt();
/* Use additional crypt io buffer if tablespace is encrypted */
byte* const readptr = encrypted
? iter.crypt_io_buffer : io_buffer;
byte* const writeptr = readptr;
if (!os_file_read(iter.file, readptr, offset, n_bytes)) {
ib_logf(IB_LOG_LEVEL_ERROR, "os_file_read() failed");
return DB_IO_ERROR;
}
bool updated = false;
os_offset_t page_off = offset;
ulint n_pages_read = (ulint) n_bytes / iter.page_size;
bool decrypted = false;
for (ulint i = 0; i < n_pages_read; ++i) {
ulint size = iter.page_size;
dberr_t err = DB_SUCCESS;
byte* src = readptr + (i * size);
byte* dst = io_buffer + (i * size);
bool frame_changed = false;
ulint page_type = mach_read_from_2(src+FIL_PAGE_TYPE);
const bool page_compressed
= page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED
|| page_type == FIL_PAGE_PAGE_COMPRESSED;
/* If tablespace is encrypted, we need to decrypt
the page. Note that tablespaces are not in
fil_system during import. */
if (encrypted) {
decrypted = fil_space_decrypt(
iter.crypt_data,
dst, //dst
iter.page_size,
src, // src
&err);
if (err != DB_SUCCESS) {
return err;
}
if (decrypted) {
updated = true;
} else {
if (!page_compressed && !row_compressed) {
block->frame = src;
frame_changed = true;
} else {
memcpy(dst, src, size);
}
}
}
/* If the original page is page_compressed, we need
to decompress it before adjusting further. */
if (page_compressed) {
fil_decompress_page(NULL, dst, ulong(size),
NULL);
updated = true;
}
buf_block_set_file_page(block, space_id, page_no++);
if ((err = callback(page_off, block)) != DB_SUCCESS) {
return err;
} else if (!updated) {
updated = buf_block_get_state(block)
== BUF_BLOCK_FILE_PAGE;
}
/* If tablespace is encrypted we use additional
temporary scratch area where pages are read
for decrypting readptr == crypt_io_buffer != io_buffer.
Destination for decryption is a buffer pool block
block->frame == dst == io_buffer that is updated.
Pages that did not require decryption even when
tablespace is marked as encrypted are not copied
instead block->frame is set to src == readptr.
For encryption we again use temporary scratch area
writeptr != io_buffer == dst
that is then written to the tablespace
(1) For normal tables io_buffer == dst == writeptr
(2) For only page compressed tables
io_buffer == dst == writeptr
(3) For encrypted (and page compressed)
readptr != io_buffer == dst != writeptr
*/
ut_ad(!encrypted && !page_compressed ?
src == dst && dst == writeptr + (i * size):1);
ut_ad(page_compressed && !encrypted ?
src == dst && dst == writeptr + (i * size):1);
ut_ad(encrypted ?
src != dst && dst != writeptr + (i * size):1);
if (encrypted) {
memcpy(writeptr + (i * size),
row_compressed ? block->page.zip.data :
block->frame, size);
}
if (frame_changed) {
block->frame = dst;
}
src = io_buffer + (i * size);
if (page_compressed) {
ulint len = 0;
fil_compress_page(
NULL,
src,
NULL,
size,
0,/* FIXME: compression level */
512,/* FIXME: use proper block size */
encrypted,
&len);
updated = true;
}
/* If tablespace is encrypted, encrypt page before we
write it back. Note that we should not encrypt the
buffer that is in buffer pool. */
/* NOTE: At this stage of IMPORT the
buffer pool is not being used at all! */
if (decrypted && encrypted) {
byte *dest = writeptr + (i * size);
ulint space = mach_read_from_4(
src + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
ulint offset = mach_read_from_4(src + FIL_PAGE_OFFSET);
ib_uint64_t lsn = mach_read_from_8(src + FIL_PAGE_LSN);
byte* tmp = fil_encrypt_buf(
iter.crypt_data,
space,
offset,
lsn,
src,
iter.page_size == UNIV_PAGE_SIZE ? 0 : iter.page_size,
dest);
if (tmp == src) {
/* TODO: remove unnecessary memcpy's */
memcpy(dest, src, size);
}
updated = true;
}
page_off += iter.page_size;
block->frame += iter.page_size;
}
/* A page was updated in the set, write back to disk. */
if (updated
&& !os_file_write(
iter.filepath, iter.file, writeptr,
offset, (ulint) n_bytes)) {
ib_logf(IB_LOG_LEVEL_ERROR, "os_file_write() failed");
return DB_IO_ERROR;
}
}
return DB_SUCCESS;
}
/********************************************************************//**
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 */
static
dberr_t
fil_tablespace_iterate(
/*===================*/
dict_table_t* table,
ulint n_io_buffers,
AbstractCallback& callback)
{
dberr_t err;
pfs_os_file_t file;
char* filepath;
ut_a(n_io_buffers > 0);
ut_ad(!srv_read_only_mode);
DBUG_EXECUTE_IF("ib_import_trigger_corruption_1",
return(DB_CORRUPTION););
if (DICT_TF_HAS_DATA_DIR(table->flags)) {
dict_get_and_save_data_dir_path(table, false);
ut_a(table->data_dir_path);
filepath = os_file_make_remote_pathname(
table->data_dir_path, table->name, "ibd");
} else {
filepath = fil_make_ibd_name(table->name, false);
}
{
ibool success;
file = os_file_create_simple_no_error_handling(
innodb_file_data_key, filepath,
OS_FILE_OPEN, OS_FILE_READ_WRITE, &success, FALSE);
DBUG_EXECUTE_IF("fil_tablespace_iterate_failure",
{
static bool once;
if (!once || ut_rnd_interval(0, 10) == 5) {
once = true;
success = FALSE;
os_file_close(file);
}
});
if (!success) {
/* The following call prints an error message */
os_file_get_last_error(true);
ib_logf(IB_LOG_LEVEL_ERROR,
"Trying to import a tablespace, but could not "
"open the tablespace file %s", filepath);
mem_free(filepath);
return(DB_TABLESPACE_NOT_FOUND);
} else {
err = DB_SUCCESS;
}
}
callback.set_file(filepath, file);
os_offset_t file_size = os_file_get_size(file);
ut_a(file_size != (os_offset_t) -1);
/* Allocate a page to read in the tablespace header, so that we
can determine the page size and zip_size (if it is compressed).
We allocate an extra page in case it is a compressed table. One
page is to ensure alignement. */
void* page_ptr = mem_alloc(3 * UNIV_PAGE_SIZE);
byte* page = static_cast<byte*>(ut_align(page_ptr, UNIV_PAGE_SIZE));
/* The block we will use for every physical page */
buf_block_t block;
memset(&block, 0, sizeof block);
block.frame = page;
block.page.io_fix = BUF_IO_NONE;
block.page.buf_fix_count = 1;
block.page.state = BUF_BLOCK_FILE_PAGE;
/* Read the first page and determine the page and zip size. */
if (!os_file_read(file, page, 0, UNIV_PAGE_SIZE)) {
err = DB_IO_ERROR;
} else if ((err = callback.init(file_size, &block)) == DB_SUCCESS) {
fil_iterator_t iter;
iter.file = file;
iter.start = 0;
iter.end = file_size;
iter.filepath = filepath;
iter.file_size = file_size;
iter.n_io_buffers = n_io_buffers;
iter.page_size = callback.get_page_size();
/* In MariaDB/MySQL 5.6 tablespace does not exist
during import, therefore we can't use space directly
here. */
ulint crypt_data_offset = fsp_header_get_crypt_offset(
callback.get_zip_size());
/* read (optional) crypt data */
iter.crypt_data = fil_space_read_crypt_data(
0, page, crypt_data_offset);
/* Compressed pages can't be optimised for block IO for now.
We do the IMPORT page by page. */
if (callback.get_zip_size() > 0) {
iter.n_io_buffers = 1;
ut_a(iter.page_size == callback.get_zip_size());
}
/** If tablespace is encrypted, it needs extra buffers */
if (iter.crypt_data != NULL) {
/* decrease io buffers so that memory
* consumption doesnt double
* note: the +1 is to avoid n_io_buffers getting down to 0 */
iter.n_io_buffers = (iter.n_io_buffers + 1) / 2;
}
/** Add an extra page for compressed page scratch area. */
void* io_buffer = mem_alloc(
(2 + iter.n_io_buffers) * UNIV_PAGE_SIZE);
iter.io_buffer = static_cast<byte*>(
ut_align(io_buffer, UNIV_PAGE_SIZE));
void* crypt_io_buffer = NULL;
if (iter.crypt_data != NULL) {
crypt_io_buffer = mem_alloc(
(2 + iter.n_io_buffers) * UNIV_PAGE_SIZE);
iter.crypt_io_buffer = static_cast<byte*>(
ut_align(crypt_io_buffer, UNIV_PAGE_SIZE));
}
err = fil_iterate(iter, &block, callback);
mem_free(io_buffer);
if (crypt_io_buffer != NULL) {
mem_free(crypt_io_buffer);
iter.crypt_io_buffer = NULL;
fil_space_destroy_crypt_data(&iter.crypt_data);
}
}
if (err == DB_SUCCESS) {
ib_logf(IB_LOG_LEVEL_INFO, "Sync to disk");
if (!os_file_flush(file)) {
ib_logf(IB_LOG_LEVEL_INFO, "os_file_flush() failed!");
err = DB_IO_ERROR;
} else {
ib_logf(IB_LOG_LEVEL_INFO, "Sync to disk - done!");
}
}
os_file_close(file);
mem_free(page_ptr);
mem_free(filepath);
return(err);
}
/*****************************************************************//**
Imports a tablespace. The space id in the .ibd file must match the space id
of the table in the data dictionary.
......
......@@ -25,8 +25,6 @@ Created 10/25/1995 Heikki Tuuri
*******************************************************/
#include "fil0fil.h"
#include "fil0pagecompress.h"
#include "fsp0pagecompress.h"
#include "fil0crypt.h"
#include <debug_sync.h>
......@@ -49,12 +47,10 @@ Created 10/25/1995 Heikki Tuuri
#include "page0zip.h"
#include "trx0sys.h"
#include "row0mysql.h"
#include "os0file.h"
#ifndef UNIV_HOTBACKUP
# include "buf0lru.h"
# include "ibuf0ibuf.h"
# include "sync0sync.h"
# include "os0sync.h"
#else /* !UNIV_HOTBACKUP */
# include "srv0srv.h"
static ulint srv_data_read, srv_data_written;
......@@ -704,7 +700,7 @@ fil_node_open_file(
space->size += node->size;
}
ulint atomic_writes = fsp_flags_get_atomic_writes(space->flags);
ulint atomic_writes = FSP_FLAGS_GET_ATOMIC_WRITES(space->flags);
/* printf("Opening file %s\n", node->name); */
......@@ -4110,7 +4106,6 @@ fil_open_single_table_tablespace(
fsp_open_info remote;
ulint tablespaces_found = 0;
ulint valid_tablespaces_found = 0;
ulint atomic_writes = 0;
fil_space_crypt_t* crypt_data = NULL;
#ifdef UNIV_SYNC_DEBUG
......@@ -4125,7 +4120,7 @@ fil_open_single_table_tablespace(
}
ut_ad(fsp_flags_is_valid(flags & ~FSP_FLAGS_MEM_MASK, id));
atomic_writes = fsp_flags_get_atomic_writes(flags);
const ulint atomic_writes = FSP_FLAGS_GET_ATOMIC_WRITES(flags);
memset(&def, 0, sizeof(def));
memset(&dict, 0, sizeof(dict));
......@@ -6151,7 +6146,8 @@ fil_io(
} else if (type == OS_FILE_WRITE) {
ut_ad(!srv_read_only_mode);
srv_stats.data_written.add(len);
if (fil_page_is_index_page((byte *)buf)) {
if (mach_read_from_2(static_cast<const byte*>(buf)
+ FIL_PAGE_TYPE) == FIL_PAGE_INDEX) {
srv_stats.index_pages_written.inc();
} else {
srv_stats.non_index_pages_written.inc();
......@@ -6683,479 +6679,6 @@ fil_close(void)
fil_system = NULL;
}
/********************************************************************//**
Initializes a buffer control block when the buf_pool is created. */
static
void
fil_buf_block_init(
/*===============*/
buf_block_t* block, /*!< in: pointer to control block */
byte* frame) /*!< in: pointer to buffer frame */
{
UNIV_MEM_DESC(frame, UNIV_PAGE_SIZE);
block->frame = frame;
block->page.io_fix = BUF_IO_NONE;
/* There are assertions that check for this. */
block->page.buf_fix_count = 1;
block->page.state = BUF_BLOCK_READY_FOR_USE;
page_zip_des_init(&block->page.zip);
}
struct fil_iterator_t {
pfs_os_file_t file; /*!< File handle */
const char* filepath; /*!< File path name */
os_offset_t start; /*!< From where to start */
os_offset_t end; /*!< Where to stop */
os_offset_t file_size; /*!< File size in bytes */
ulint page_size; /*!< Page size */
ulint n_io_buffers; /*!< Number of pages to use
for IO */
byte* io_buffer; /*!< Buffer to use for IO */
fil_space_crypt_t *crypt_data; /*!< Crypt data (if encrypted) */
byte* crypt_io_buffer; /*!< IO buffer when encrypted */
};
/********************************************************************//**
TODO: This can be made parallel trivially by chunking up the file and creating
a callback per thread. . Main benefit will be to use multiple CPUs for
checksums and compressed tables. We have to do compressed tables block by
block right now. Secondly we need to decompress/compress and copy too much
of data. These are CPU intensive.
Iterate over all the pages in the tablespace.
@param iter - Tablespace iterator
@param block - block to use for IO
@param callback - Callback to inspect and update page contents
@retval DB_SUCCESS or error code */
static
dberr_t
fil_iterate(
/*========*/
const fil_iterator_t& iter,
buf_block_t* block,
PageCallback& callback)
{
os_offset_t offset;
ulint page_no = 0;
ulint space_id = callback.get_space_id();
ulint n_bytes = iter.n_io_buffers * iter.page_size;
ut_ad(!srv_read_only_mode);
/* TODO: For compressed tables we do a lot of useless
copying for non-index pages. Unfortunately, it is
required by buf_zip_decompress() */
const bool row_compressed = callback.get_zip_size() > 0;
for (offset = iter.start; offset < iter.end; offset += n_bytes) {
byte* io_buffer = iter.io_buffer;
block->frame = io_buffer;
if (row_compressed) {
page_zip_des_init(&block->page.zip);
page_zip_set_size(&block->page.zip, iter.page_size);
block->page.zip.data = block->frame + UNIV_PAGE_SIZE;
ut_d(block->page.zip.m_external = true);
ut_ad(iter.page_size == callback.get_zip_size());
/* Zip IO is done in the compressed page buffer. */
io_buffer = block->page.zip.data;
}
/* We have to read the exact number of bytes. Otherwise the
InnoDB IO functions croak on failed reads. */
n_bytes = static_cast<ulint>(
ut_min(static_cast<os_offset_t>(n_bytes),
iter.end - offset));
ut_ad(n_bytes > 0);
ut_ad(!(n_bytes % iter.page_size));
const bool encrypted = iter.crypt_data != NULL
&& iter.crypt_data->should_encrypt();
/* Use additional crypt io buffer if tablespace is encrypted */
byte* const readptr = encrypted
? iter.crypt_io_buffer : io_buffer;
byte* const writeptr = readptr;
if (!os_file_read(iter.file, readptr, offset, (ulint) n_bytes)) {
ib_logf(IB_LOG_LEVEL_ERROR, "os_file_read() failed");
return(DB_IO_ERROR);
}
bool updated = false;
os_offset_t page_off = offset;
ulint n_pages_read = (ulint) n_bytes / iter.page_size;
bool decrypted = false;
for (ulint i = 0; i < n_pages_read; ++i) {
ulint size = iter.page_size;
dberr_t err = DB_SUCCESS;
byte* src = readptr + (i * size);
byte* dst = io_buffer + (i * size);
bool frame_changed = false;
ulint page_type = mach_read_from_2(src+FIL_PAGE_TYPE);
const bool page_compressed
= page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED
|| page_type == FIL_PAGE_PAGE_COMPRESSED;
/* If tablespace is encrypted, we need to decrypt
the page. Note that tablespaces are not in
fil_system during import. */
if (encrypted) {
decrypted = fil_space_decrypt(
iter.crypt_data,
dst, //dst
iter.page_size,
src, // src
&err); // src
if (err != DB_SUCCESS) {
return(err);
}
if (decrypted) {
updated = true;
} else {
if (!page_compressed && !row_compressed) {
block->frame = src;
frame_changed = true;
} else {
memcpy(dst, src, size);
}
}
}
/* If the original page is page_compressed, we need
to decompress page before we can update it. */
if (page_compressed) {
fil_decompress_page(NULL, dst, ulong(size),
NULL);
updated = true;
}
buf_block_set_file_page(block, space_id, page_no++);
if ((err = callback(page_off, block)) != DB_SUCCESS) {
return(err);
} else if (!updated) {
updated = buf_block_get_state(block)
== BUF_BLOCK_FILE_PAGE;
}
buf_block_set_state(block, BUF_BLOCK_NOT_USED);
buf_block_set_state(block, BUF_BLOCK_READY_FOR_USE);
/* If tablespace is encrypted we use additional
temporary scratch area where pages are read
for decrypting readptr == crypt_io_buffer != io_buffer.
Destination for decryption is a buffer pool block
block->frame == dst == io_buffer that is updated.
Pages that did not require decryption even when
tablespace is marked as encrypted are not copied
instead block->frame is set to src == readptr.
For encryption we again use temporary scratch area
writeptr != io_buffer == dst
that is then written to the tablespace
(1) For normal tables io_buffer == dst == writeptr
(2) For only page compressed tables
io_buffer == dst == writeptr
(3) For encrypted (and page compressed)
readptr != io_buffer == dst != writeptr
*/
ut_ad(!encrypted && !page_compressed ?
src == dst && dst == writeptr + (i * size):1);
ut_ad(page_compressed && !encrypted ?
src == dst && dst == writeptr + (i * size):1);
ut_ad(encrypted ?
src != dst && dst != writeptr + (i * size):1);
if (encrypted) {
memcpy(writeptr + (i * size),
row_compressed ? block->page.zip.data :
block->frame, size);
}
if (frame_changed) {
block->frame = dst;
}
src = io_buffer + (i * size);
if (page_compressed) {
ulint len = 0;
fil_compress_page(
NULL,
src,
NULL,
size,
0,/* FIXME: compression level */
512,/* FIXME: use proper block size */
encrypted,
&len);
updated = true;
}
/* If tablespace is encrypted, encrypt page before we
write it back. Note that we should not encrypt the
buffer that is in buffer pool. */
/* NOTE: At this stage of IMPORT the
buffer pool is not being used at all! */
if (decrypted && encrypted) {
byte *dest = writeptr + (i * size);
ulint space = mach_read_from_4(
src + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
ulint offset = mach_read_from_4(src + FIL_PAGE_OFFSET);
ib_uint64_t lsn = mach_read_from_8(src + FIL_PAGE_LSN);
byte* tmp = fil_encrypt_buf(
iter.crypt_data,
space,
offset,
lsn,
src,
iter.page_size == UNIV_PAGE_SIZE ? 0 : iter.page_size,
dest);
if (tmp == src) {
/* TODO: remove unnecessary memcpy's */
memcpy(dest, src, size);
}
updated = true;
}
page_off += iter.page_size;
block->frame += iter.page_size;
}
/* A page was updated in the set, write back to disk. */
if (updated
&& !os_file_write(
iter.filepath, iter.file, writeptr,
offset, (ulint) n_bytes)) {
ib_logf(IB_LOG_LEVEL_ERROR, "os_file_write() failed");
return(DB_IO_ERROR);
}
}
return(DB_SUCCESS);
}
/********************************************************************//**
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 */
UNIV_INTERN
dberr_t
fil_tablespace_iterate(
/*===================*/
dict_table_t* table,
ulint n_io_buffers,
PageCallback& callback)
{
dberr_t err;
pfs_os_file_t file;
char* filepath;
ut_a(n_io_buffers > 0);
ut_ad(!srv_read_only_mode);
DBUG_EXECUTE_IF("ib_import_trigger_corruption_1",
return(DB_CORRUPTION););
if (DICT_TF_HAS_DATA_DIR(table->flags)) {
dict_get_and_save_data_dir_path(table, false);
ut_a(table->data_dir_path);
filepath = os_file_make_remote_pathname(
table->data_dir_path, table->name, "ibd");
} else {
filepath = fil_make_ibd_name(table->name, false);
}
{
ibool success;
file = os_file_create_simple_no_error_handling(
innodb_file_data_key, filepath,
OS_FILE_OPEN, OS_FILE_READ_WRITE, &success, FALSE);
DBUG_EXECUTE_IF("fil_tablespace_iterate_failure",
{
static bool once;
if (!once || ut_rnd_interval(0, 10) == 5) {
once = true;
success = FALSE;
os_file_close(file);
}
});
if (!success) {
/* The following call prints an error message */
os_file_get_last_error(true);
ib_logf(IB_LOG_LEVEL_ERROR,
"Trying to import a tablespace, but could not "
"open the tablespace file %s", filepath);
mem_free(filepath);
return(DB_TABLESPACE_NOT_FOUND);
} else {
err = DB_SUCCESS;
}
}
callback.set_file(filepath, file);
os_offset_t file_size = os_file_get_size(file);
ut_a(file_size != (os_offset_t) -1);
/* The block we will use for every physical page */
buf_block_t block;
memset(&block, 0x0, sizeof(block));
/* Allocate a page to read in the tablespace header, so that we
can determine the page size and zip_size (if it is compressed).
We allocate an extra page in case it is a compressed table. One
page is to ensure alignement. */
void* page_ptr = mem_alloc(3 * UNIV_PAGE_SIZE);
byte* page = static_cast<byte*>(ut_align(page_ptr, UNIV_PAGE_SIZE));
fil_buf_block_init(&block, page);
/* Read the first page and determine the page and zip size. */
if (!os_file_read(file, page, 0, UNIV_PAGE_SIZE)) {
err = DB_IO_ERROR;
} else if ((err = callback.init(file_size, &block)) == DB_SUCCESS) {
fil_iterator_t iter;
iter.file = file;
iter.start = 0;
iter.end = file_size;
iter.filepath = filepath;
iter.file_size = file_size;
iter.n_io_buffers = n_io_buffers;
iter.page_size = callback.get_page_size();
/* In MariaDB/MySQL 5.6 tablespace does not exist
during import, therefore we can't use space directly
here. */
ulint crypt_data_offset = fsp_header_get_crypt_offset(
callback.get_zip_size());
/* read (optional) crypt data */
iter.crypt_data = fil_space_read_crypt_data(
0, page, crypt_data_offset);
/* Compressed pages can't be optimised for block IO for now.
We do the IMPORT page by page. */
if (callback.get_zip_size() > 0) {
iter.n_io_buffers = 1;
ut_a(iter.page_size == callback.get_zip_size());
}
/** If tablespace is encrypted, it needs extra buffers */
if (iter.crypt_data != NULL) {
/* decrease io buffers so that memory
* consumption doesnt double
* note: the +1 is to avoid n_io_buffers getting down to 0 */
iter.n_io_buffers = (iter.n_io_buffers + 1) / 2;
}
/** Add an extra page for compressed page scratch area. */
void* io_buffer = mem_alloc(
(2 + iter.n_io_buffers) * UNIV_PAGE_SIZE);
iter.io_buffer = static_cast<byte*>(
ut_align(io_buffer, UNIV_PAGE_SIZE));
void* crypt_io_buffer = NULL;
if (iter.crypt_data != NULL) {
crypt_io_buffer = mem_alloc(
(2 + iter.n_io_buffers) * UNIV_PAGE_SIZE);
iter.crypt_io_buffer = static_cast<byte*>(
ut_align(crypt_io_buffer, UNIV_PAGE_SIZE));
}
err = fil_iterate(iter, &block, callback);
mem_free(io_buffer);
if (crypt_io_buffer != NULL) {
mem_free(crypt_io_buffer);
iter.crypt_io_buffer = NULL;
fil_space_destroy_crypt_data(&iter.crypt_data);
}
}
if (err == DB_SUCCESS) {
ib_logf(IB_LOG_LEVEL_INFO, "Sync to disk");
if (!os_file_flush(file)) {
ib_logf(IB_LOG_LEVEL_INFO, "os_file_flush() failed!");
err = DB_IO_ERROR;
} else {
ib_logf(IB_LOG_LEVEL_INFO, "Sync to disk - done!");
}
}
os_file_close(file);
mem_free(page_ptr);
mem_free(filepath);
return(err);
}
/**
Set the tablespace compressed table size.
@return DB_SUCCESS if it is valie or DB_CORRUPTION if not */
dberr_t
PageCallback::set_zip_size(const buf_frame_t* page) UNIV_NOTHROW
{
m_zip_size = fsp_header_get_zip_size(page);
if (!ut_is_2pow(m_zip_size) || m_zip_size > UNIV_ZIP_SIZE_MAX) {
return(DB_CORRUPTION);
}
return(DB_SUCCESS);
}
/********************************************************************//**
Delete the tablespace file and any related files like .cfg.
This should not be called for temporary tables. */
......
......@@ -1309,107 +1309,6 @@ fil_delete_file(
/*============*/
const char* path); /*!< in: filepath of the ibd tablespace */
/** Callback functor. */
struct PageCallback {
/**
Default constructor */
PageCallback()
:
m_zip_size(),
m_page_size(),
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) 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) 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 ulint get_space_id() const UNIV_NOTHROW = 0;
/** The compressed page size
@return the compressed page size */
ulint get_zip_size() const
{
return(m_zip_size);
}
/**
Set the tablespace compressed table size.
@return DB_SUCCESS if it is valie or DB_CORRUPTION if not */
dberr_t set_zip_size(const buf_frame_t* page) UNIV_NOTHROW;
/** The compressed page size
@return the compressed page size */
ulint get_page_size() const
{
return(m_page_size);
}
/** Compressed table page size */
ulint m_zip_size;
/** The tablespace page size. */
ulint m_page_size;
/** File handle to the tablespace */
pfs_os_file_t m_file;
/** Physical file path. */
const char* m_filepath;
protected:
// Disable copying
PageCallback(const PageCallback&);
PageCallback& operator=(const PageCallback&);
};
/********************************************************************//**
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 */
UNIV_INTERN
dberr_t
fil_tablespace_iterate(
/*===================*/
dict_table_t* table,
ulint n_io_buffers,
PageCallback& callback)
MY_ATTRIBUTE((nonnull, warn_unused_result));
/*******************************************************************//**
Checks if a single-table tablespace for a given table name exists in the
tablespace memory cache.
......
......@@ -40,7 +40,7 @@ Created 2012-02-08 by Sunny Bains.
#include "row0mysql.h"
#include "srv0start.h"
#include "row0quiesce.h"
#include "buf0buf.h"
#include "fil0pagecompress.h"
#include <vector>
......@@ -362,7 +362,8 @@ class IndexPurge {
/** Functor that is called for each physical page that is read from the
tablespace file. */
class AbstractCallback : public PageCallback {
class AbstractCallback
{
public:
/** Constructor
@param trx - covering transaction */
......@@ -395,6 +396,47 @@ class AbstractCallback : public PageCallback {
return(get_zip_size() > 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;
}
/** The compressed page size
@return the compressed page size */
ulint get_zip_size() const
{
return(m_zip_size);
}
/** The compressed page size
@return the compressed page size */
ulint get_page_size() const
{
return(m_page_size);
}
/**
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) UNIV_NOTHROW = 0;
/**
@return the space id of the tablespace */
virtual ulint get_space_id() const UNIV_NOTHROW = 0;
protected:
/**
Get the data page depending on the table type, compressed or not.
......@@ -510,6 +552,18 @@ class AbstractCallback : public PageCallback {
}
protected:
/** Compressed table page size */
ulint m_zip_size;
/** The tablespace page size. */
ulint m_page_size;
/** File handle to the tablespace */
pfs_os_file_t m_file;
/** Physical file path. */
const char* m_filepath;
/** Covering transaction. */
trx_t* m_trx;
......@@ -566,9 +620,9 @@ AbstractCallback::init(
/* Since we don't know whether it is a compressed table
or not, the data is always read into the block->frame. */
dberr_t err = set_zip_size(block->frame);
m_zip_size = fsp_header_get_zip_size(page);
if (err != DB_SUCCESS) {
if (!ut_is_2pow(m_zip_size) || m_zip_size > UNIV_ZIP_SIZE_MAX) {
return(DB_CORRUPTION);
}
......@@ -605,11 +659,7 @@ AbstractCallback::init(
m_free_limit = mach_read_from_4(page + FSP_FREE_LIMIT);
m_space = mach_read_from_4(page + FSP_HEADER_OFFSET + FSP_SPACE_ID);
if ((err = set_current_xdes(0, page)) != DB_SUCCESS) {
return(err);
}
return(DB_SUCCESS);
return set_current_xdes(0, page);
}
/**
......@@ -1316,8 +1366,8 @@ row_import::match_schema(
return(DB_ERROR);
} else if (m_table->n_cols != m_n_cols) {
ib_errf(thd, IB_LOG_LEVEL_ERROR, ER_TABLE_SCHEMA_MISMATCH,
"Number of columns don't match, table has %u "
"columns but the tablespace meta-data file has "
"Number of columns don't match, table has %u"
" columns but the tablespace meta-data file has "
ULINTPF " columns",
m_table->n_cols, m_n_cols);
......@@ -1597,6 +1647,7 @@ IndexPurge::purge() UNIV_NOTHROW
Constructor
* @param cfg - config of table being imported.
* @param trx - transaction covering the import */
inline
PageConverter::PageConverter(
row_import* cfg,
trx_t* trx)
......@@ -1621,6 +1672,7 @@ Adjust the BLOB reference for a single column that is externally stored
@param offsets - column offsets for the record
@param i - column ordinal value
@return DB_SUCCESS or error code */
inline
dberr_t
PageConverter::adjust_cluster_index_blob_column(
rec_t* rec,
......@@ -1673,6 +1725,7 @@ stored columns.
@param rec - record to update
@param offsets - column offsets for the record
@return DB_SUCCESS or error code */
inline
dberr_t
PageConverter::adjust_cluster_index_blob_columns(
rec_t* rec,
......@@ -1706,6 +1759,7 @@ BLOB reference, write the new space id.
@param rec - record to update
@param offsets - column offsets for the record
@return DB_SUCCESS or error code */
inline
dberr_t
PageConverter::adjust_cluster_index_blob_ref(
rec_t* rec,
......@@ -1729,6 +1783,7 @@ Purge delete-marked records, only if it is possible to do so without
re-organising the B+tree.
@param offsets - current row offsets.
@return true if purge succeeded */
inline
bool
PageConverter::purge(const ulint* offsets) UNIV_NOTHROW
{
......@@ -1753,6 +1808,7 @@ Adjust the BLOB references and sys fields for the current record.
@param offsets - column offsets for the record
@param deleted - true if row is delete marked
@return DB_SUCCESS or error code. */
inline
dberr_t
PageConverter::adjust_cluster_record(
const dict_index_t* index,
......@@ -1781,6 +1837,7 @@ Update the BLOB refrences and write UNDO log entries for
rows that can't be purged optimistically.
@param block - block to update
@retval DB_SUCCESS or error code */
inline
dberr_t
PageConverter::update_records(
buf_block_t* block) UNIV_NOTHROW
......@@ -1846,6 +1903,7 @@ PageConverter::update_records(
/**
Update the space, index id, trx id.
@return DB_SUCCESS or error code */
inline
dberr_t
PageConverter::update_index_page(
buf_block_t* block) UNIV_NOTHROW
......@@ -1915,6 +1973,7 @@ PageConverter::update_index_page(
Validate the space flags and update tablespace header page.
@param block - block read from file, not from the buffer pool.
@retval DB_SUCCESS or error code */
inline
dberr_t
PageConverter::update_header(
buf_block_t* block) UNIV_NOTHROW
......@@ -1954,6 +2013,7 @@ PageConverter::update_header(
Update the page, set the space id, max trx id and index id.
@param block - block read from file
@retval DB_SUCCESS or error code */
inline
dberr_t
PageConverter::update_page(
buf_block_t* block,
......@@ -3424,6 +3484,436 @@ row_import_update_discarded_flag(
return(err);
}
struct fil_iterator_t {
pfs_os_file_t file; /*!< File handle */
const char* filepath; /*!< File path name */
os_offset_t start; /*!< From where to start */
os_offset_t end; /*!< Where to stop */
os_offset_t file_size; /*!< File size in bytes */
ulint page_size; /*!< Page size */
ulint n_io_buffers; /*!< Number of pages to use
for IO */
byte* io_buffer; /*!< Buffer to use for IO */
fil_space_crypt_t *crypt_data; /*!< Crypt data (if encrypted) */
byte* crypt_io_buffer; /*!< IO buffer when encrypted */
};
/********************************************************************//**
TODO: This can be made parallel trivially by chunking up the file and creating
a callback per thread. . Main benefit will be to use multiple CPUs for
checksums and compressed tables. We have to do compressed tables block by
block right now. Secondly we need to decompress/compress and copy too much
of data. These are CPU intensive.
Iterate over all the pages in the tablespace.
@param iter - Tablespace iterator
@param block - block to use for IO
@param callback - Callback to inspect and update page contents
@retval DB_SUCCESS or error code */
static
dberr_t
fil_iterate(
/*========*/
const fil_iterator_t& iter,
buf_block_t* block,
AbstractCallback& callback)
{
os_offset_t offset;
ulint page_no = 0;
ulint space_id = callback.get_space_id();
ulint n_bytes = iter.n_io_buffers * iter.page_size;
ut_ad(!srv_read_only_mode);
/* TODO: For compressed tables we do a lot of useless
copying for non-index pages. Unfortunately, it is
required by buf_zip_decompress() */
const bool row_compressed = callback.get_zip_size() > 0;
for (offset = iter.start; offset < iter.end; offset += n_bytes) {
byte* io_buffer = iter.io_buffer;
block->frame = io_buffer;
if (row_compressed) {
page_zip_des_init(&block->page.zip);
page_zip_set_size(&block->page.zip, iter.page_size);
block->page.zip.data = block->frame + UNIV_PAGE_SIZE;
ut_d(block->page.zip.m_external = true);
ut_ad(iter.page_size == callback.get_zip_size());
/* Zip IO is done in the compressed page buffer. */
io_buffer = block->page.zip.data;
}
/* We have to read the exact number of bytes. Otherwise the
InnoDB IO functions croak on failed reads. */
n_bytes = ulint(ut_min(os_offset_t(n_bytes),
iter.end - offset));
ut_ad(n_bytes > 0);
ut_ad(!(n_bytes % iter.page_size));
const bool encrypted = iter.crypt_data != NULL
&& iter.crypt_data->should_encrypt();
/* Use additional crypt io buffer if tablespace is encrypted */
byte* const readptr = encrypted
? iter.crypt_io_buffer : io_buffer;
byte* const writeptr = readptr;
if (!os_file_read(iter.file, readptr, offset, n_bytes)) {
ib_logf(IB_LOG_LEVEL_ERROR, "os_file_read() failed");
return DB_IO_ERROR;
}
bool updated = false;
os_offset_t page_off = offset;
ulint n_pages_read = (ulint) n_bytes / iter.page_size;
bool decrypted = false;
for (ulint i = 0; i < n_pages_read; ++i) {
ulint size = iter.page_size;
dberr_t err = DB_SUCCESS;
byte* src = readptr + (i * size);
byte* dst = io_buffer + (i * size);
bool frame_changed = false;
ulint page_type = mach_read_from_2(src+FIL_PAGE_TYPE);
const bool page_compressed
= page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED
|| page_type == FIL_PAGE_PAGE_COMPRESSED;
/* If tablespace is encrypted, we need to decrypt
the page. Note that tablespaces are not in
fil_system during import. */
if (encrypted) {
decrypted = fil_space_decrypt(
iter.crypt_data,
dst, //dst
iter.page_size,
src, // src
&err);
if (err != DB_SUCCESS) {
return err;
}
if (decrypted) {
updated = true;
} else {
if (!page_compressed && !row_compressed) {
block->frame = src;
frame_changed = true;
} else {
memcpy(dst, src, size);
}
}
}
/* If the original page is page_compressed, we need
to decompress it before adjusting further. */
if (page_compressed) {
fil_decompress_page(NULL, dst, ulong(size),
NULL);
updated = true;
}
buf_block_set_file_page(block, space_id, page_no++);
if ((err = callback(page_off, block)) != DB_SUCCESS) {
return err;
} else if (!updated) {
updated = buf_block_get_state(block)
== BUF_BLOCK_FILE_PAGE;
}
/* If tablespace is encrypted we use additional
temporary scratch area where pages are read
for decrypting readptr == crypt_io_buffer != io_buffer.
Destination for decryption is a buffer pool block
block->frame == dst == io_buffer that is updated.
Pages that did not require decryption even when
tablespace is marked as encrypted are not copied
instead block->frame is set to src == readptr.
For encryption we again use temporary scratch area
writeptr != io_buffer == dst
that is then written to the tablespace
(1) For normal tables io_buffer == dst == writeptr
(2) For only page compressed tables
io_buffer == dst == writeptr
(3) For encrypted (and page compressed)
readptr != io_buffer == dst != writeptr
*/
ut_ad(!encrypted && !page_compressed ?
src == dst && dst == writeptr + (i * size):1);
ut_ad(page_compressed && !encrypted ?
src == dst && dst == writeptr + (i * size):1);
ut_ad(encrypted ?
src != dst && dst != writeptr + (i * size):1);
if (encrypted) {
memcpy(writeptr + (i * size),
row_compressed ? block->page.zip.data :
block->frame, size);
}
if (frame_changed) {
block->frame = dst;
}
src = io_buffer + (i * size);
if (page_compressed) {
ulint len = 0;
fil_compress_page(
NULL,
src,
NULL,
size,
0,/* FIXME: compression level */
512,/* FIXME: use proper block size */
encrypted,
&len);
updated = true;
}
/* If tablespace is encrypted, encrypt page before we
write it back. Note that we should not encrypt the
buffer that is in buffer pool. */
/* NOTE: At this stage of IMPORT the
buffer pool is not being used at all! */
if (decrypted && encrypted) {
byte *dest = writeptr + (i * size);
ulint space = mach_read_from_4(
src + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
ulint offset = mach_read_from_4(src + FIL_PAGE_OFFSET);
ib_uint64_t lsn = mach_read_from_8(src + FIL_PAGE_LSN);
byte* tmp = fil_encrypt_buf(
iter.crypt_data,
space,
offset,
lsn,
src,
iter.page_size == UNIV_PAGE_SIZE ? 0 : iter.page_size,
dest);
if (tmp == src) {
/* TODO: remove unnecessary memcpy's */
memcpy(dest, src, size);
}
updated = true;
}
page_off += iter.page_size;
block->frame += iter.page_size;
}
/* A page was updated in the set, write back to disk. */
if (updated
&& !os_file_write(
iter.filepath, iter.file, writeptr,
offset, (ulint) n_bytes)) {
ib_logf(IB_LOG_LEVEL_ERROR, "os_file_write() failed");
return DB_IO_ERROR;
}
}
return DB_SUCCESS;
}
/********************************************************************//**
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 */
static
dberr_t
fil_tablespace_iterate(
/*===================*/
dict_table_t* table,
ulint n_io_buffers,
AbstractCallback& callback)
{
dberr_t err;
pfs_os_file_t file;
char* filepath;
ut_a(n_io_buffers > 0);
ut_ad(!srv_read_only_mode);
DBUG_EXECUTE_IF("ib_import_trigger_corruption_1",
return(DB_CORRUPTION););
if (DICT_TF_HAS_DATA_DIR(table->flags)) {
dict_get_and_save_data_dir_path(table, false);
ut_a(table->data_dir_path);
filepath = os_file_make_remote_pathname(
table->data_dir_path, table->name, "ibd");
} else {
filepath = fil_make_ibd_name(table->name, false);
}
{
ibool success;
file = os_file_create_simple_no_error_handling(
innodb_file_data_key, filepath,
OS_FILE_OPEN, OS_FILE_READ_WRITE, &success, FALSE);
DBUG_EXECUTE_IF("fil_tablespace_iterate_failure",
{
static bool once;
if (!once || ut_rnd_interval(0, 10) == 5) {
once = true;
success = FALSE;
os_file_close(file);
}
});
if (!success) {
/* The following call prints an error message */
os_file_get_last_error(true);
ib_logf(IB_LOG_LEVEL_ERROR,
"Trying to import a tablespace, but could not "
"open the tablespace file %s", filepath);
mem_free(filepath);
return(DB_TABLESPACE_NOT_FOUND);
} else {
err = DB_SUCCESS;
}
}
callback.set_file(filepath, file);
os_offset_t file_size = os_file_get_size(file);
ut_a(file_size != (os_offset_t) -1);
/* Allocate a page to read in the tablespace header, so that we
can determine the page size and zip_size (if it is compressed).
We allocate an extra page in case it is a compressed table. One
page is to ensure alignement. */
void* page_ptr = mem_alloc(3 * UNIV_PAGE_SIZE);
byte* page = static_cast<byte*>(ut_align(page_ptr, UNIV_PAGE_SIZE));
/* The block we will use for every physical page */
buf_block_t block;
memset(&block, 0, sizeof block);
block.frame = page;
block.page.io_fix = BUF_IO_NONE;
block.page.buf_fix_count = 1;
block.page.state = BUF_BLOCK_FILE_PAGE;
/* Read the first page and determine the page and zip size. */
if (!os_file_read(file, page, 0, UNIV_PAGE_SIZE)) {
err = DB_IO_ERROR;
} else if ((err = callback.init(file_size, &block)) == DB_SUCCESS) {
fil_iterator_t iter;
iter.file = file;
iter.start = 0;
iter.end = file_size;
iter.filepath = filepath;
iter.file_size = file_size;
iter.n_io_buffers = n_io_buffers;
iter.page_size = callback.get_page_size();
/* In MariaDB/MySQL 5.6 tablespace does not exist
during import, therefore we can't use space directly
here. */
ulint crypt_data_offset = fsp_header_get_crypt_offset(
callback.get_zip_size());
/* read (optional) crypt data */
iter.crypt_data = fil_space_read_crypt_data(
0, page, crypt_data_offset);
/* Compressed pages can't be optimised for block IO for now.
We do the IMPORT page by page. */
if (callback.get_zip_size() > 0) {
iter.n_io_buffers = 1;
ut_a(iter.page_size == callback.get_zip_size());
}
/** If tablespace is encrypted, it needs extra buffers */
if (iter.crypt_data != NULL) {
/* decrease io buffers so that memory
* consumption doesnt double
* note: the +1 is to avoid n_io_buffers getting down to 0 */
iter.n_io_buffers = (iter.n_io_buffers + 1) / 2;
}
/** Add an extra page for compressed page scratch area. */
void* io_buffer = mem_alloc(
(2 + iter.n_io_buffers) * UNIV_PAGE_SIZE);
iter.io_buffer = static_cast<byte*>(
ut_align(io_buffer, UNIV_PAGE_SIZE));
void* crypt_io_buffer = NULL;
if (iter.crypt_data != NULL) {
crypt_io_buffer = mem_alloc(
(2 + iter.n_io_buffers) * UNIV_PAGE_SIZE);
iter.crypt_io_buffer = static_cast<byte*>(
ut_align(crypt_io_buffer, UNIV_PAGE_SIZE));
}
err = fil_iterate(iter, &block, callback);
mem_free(io_buffer);
if (crypt_io_buffer != NULL) {
mem_free(crypt_io_buffer);
iter.crypt_io_buffer = NULL;
fil_space_destroy_crypt_data(&iter.crypt_data);
}
}
if (err == DB_SUCCESS) {
ib_logf(IB_LOG_LEVEL_INFO, "Sync to disk");
if (!os_file_flush(file)) {
ib_logf(IB_LOG_LEVEL_INFO, "os_file_flush() failed!");
err = DB_IO_ERROR;
} else {
ib_logf(IB_LOG_LEVEL_INFO, "Sync to disk - done!");
}
}
os_file_close(file);
mem_free(page_ptr);
mem_free(filepath);
return(err);
}
/*****************************************************************//**
Imports a tablespace. The space id in the .ibd file must match the space id
of the table in the data dictionary.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment