Commit 0871a00a authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-12545 Reduce the amount of fil_space_t lookups

buf_flush_write_block_low(): Acquire the tablespace reference once,
and pass it to lower-level functions. This is only a start; further
calls may be removed.

fil_decompress_page(): Remove unsafe use of fil_space_get_by_id().
parent b66e15ec
......@@ -7373,72 +7373,55 @@ buf_pool_reserve_tmp_slot(
return (free_slot);
}
/********************************************************************//**
Encrypts a buffer page right before it's flushed to disk
@param[in,out] bpage Page control block
@param[in,out] src_frame Source page
@param[in] space_id Tablespace id
@return either unencrypted source page or decrypted page.
*/
/** Encryption and page_compression hook that is called just before
a page is written to disk.
@param[in,out] space tablespace
@param[in,out] bpage buffer page
@param[in] src_frame physical page frame that is being encrypted
@return page frame to be written to file
(may be src_frame or an encrypted/compressed copy of it) */
UNIV_INTERN
byte*
buf_page_encrypt_before_write(
fil_space_t* space,
buf_page_t* bpage,
byte* src_frame,
ulint space_id)
byte* src_frame)
{
ut_ad(space->id == bpage->id.space());
bpage->real_size = UNIV_PAGE_SIZE;
fil_page_type_validate(src_frame);
if (bpage->id.page_no() == 0) {
switch (bpage->id.page_no()) {
case 0:
/* Page 0 of a tablespace is not encrypted/compressed */
ut_ad(bpage->key_version == 0);
return src_frame;
}
if (space_id == TRX_SYS_SPACE && bpage->id.page_no() == TRX_SYS_PAGE_NO) {
/* don't encrypt/compress page as it contains address to dblwr buffer */
bpage->key_version = 0;
return src_frame;
}
fil_space_t* space = fil_space_acquire_silent(space_id);
/* Tablespace must exist during write operation */
if (!space) {
/* This could be true on discard if we have injected a error
case e.g. in innodb.innodb-wl5522-debug-zip so that space
is already marked as stop_new_ops = true. */
return src_frame;
case TRX_SYS_PAGE_NO:
if (bpage->id.space() == 0) {
/* don't encrypt/compress page as it contains
address to dblwr buffer */
bpage->key_version = 0;
return src_frame;
}
}
const page_size_t page_size(space->flags);
fil_space_crypt_t* crypt_data = space->crypt_data;
bool encrypted = true;
if (space->crypt_data != NULL && space->crypt_data->not_encrypted()) {
/* Encryption is disabled */
encrypted = false;
}
if (!srv_encrypt_tables && (crypt_data == NULL || crypt_data->is_default_encryption())) {
/* Encryption is disabled */
encrypted = false;
}
const bool encrypted = crypt_data
&& !crypt_data->not_encrypted()
&& crypt_data->type != CRYPT_SCHEME_UNENCRYPTED
&& (!crypt_data->is_default_encryption()
|| srv_encrypt_tables);
/* Is encryption needed? */
if (crypt_data == NULL || crypt_data->type == CRYPT_SCHEME_UNENCRYPTED) {
/* An unencrypted table */
if (!encrypted) {
bpage->key_version = 0;
encrypted = false;
}
bool page_compressed = fil_space_is_page_compressed(bpage->id.space());
bool page_compressed = FSP_FLAGS_HAS_PAGE_COMPRESSION(space->flags);
if (!encrypted && !page_compressed) {
/* No need to encrypt or page compress the page */
fil_space_release(space);
return src_frame;
}
......@@ -7465,25 +7448,21 @@ buf_page_encrypt_before_write(
bpage->real_size = page_size.physical();
slot->out_buf = dst_frame = tmp;
#ifdef UNIV_DEBUG
fil_page_type_validate(tmp);
#endif
ut_d(fil_page_type_validate(tmp));
} else {
/* First we compress the page content */
ulint out_len = 0;
ulint block_size = fil_space_get_block_size(space_id, bpage->id.page_no(), page_size.logical());
byte *tmp = fil_compress_page(space_id,
(byte *)src_frame,
slot->comp_buf,
page_size.logical(),
fil_space_get_page_compression_level(space_id),
block_size,
encrypted,
&out_len,
IF_LZO(slot->lzo_mem, NULL)
);
byte *tmp = fil_compress_page(
space,
(byte *)src_frame,
slot->comp_buf,
page_size.logical(),
fsp_flags_get_page_compression_level(space->flags),
fil_space_get_block_size(space, bpage->id.page_no()),
encrypted,
&out_len,
IF_LZO(slot->lzo_mem, NULL));
bpage->real_size = out_len;
......@@ -7506,7 +7485,6 @@ buf_page_encrypt_before_write(
ut_d(fil_page_type_validate(dst_frame));
fil_space_release(space);
// return dst_frame which will be written
return dst_frame;
}
......
......@@ -1006,11 +1006,16 @@ buf_flush_write_block_low(
buf_flush_t flush_type, /*!< in: type of flush */
bool sync) /*!< in: true if sync IO request */
{
fil_space_t* space = fil_space_acquire(bpage->id.space(), true);
if (!space) {
return;
}
ut_ad(space->purpose == FIL_TYPE_TEMPORARY
|| space->purpose == FIL_TYPE_IMPORT
|| space->purpose == FIL_TYPE_TABLESPACE);
const bool is_temp = space->purpose == FIL_TYPE_TEMPORARY;
ut_ad(is_temp == fsp_is_system_temporary(space->id));
page_t* frame = NULL;
ulint space_id = bpage->id.space();
const bool is_temp = fsp_is_system_temporary(space_id);
bool atomic_writes = is_temp || fil_space_get_atomic_writes(space_id);
#ifdef UNIV_DEBUG
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
ut_ad(!buf_pool_mutex_own(buf_pool));
......@@ -1076,28 +1081,27 @@ buf_flush_write_block_low(
break;
}
frame = buf_page_encrypt_before_write(bpage, frame, space_id);
frame = buf_page_encrypt_before_write(space, bpage, frame);
/* Disable use of double-write buffer for temporary tablespace.
Given the nature and load of temporary tablespace doublewrite buffer
adds an overhead during flushing. */
if (!srv_use_doublewrite_buf
|| buf_dblwr == NULL
|| srv_read_only_mode
|| atomic_writes) {
ut_ad(!srv_read_only_mode
|| fsp_is_system_temporary(bpage->id.space()));
if (is_temp || space->atomic_write_supported
|| !srv_use_doublewrite_buf
|| buf_dblwr == NULL) {
ulint type = IORequest::WRITE | IORequest::DO_NOT_WAKE;
IORequest request(type, bpage);
/* TODO: pass the tablespace to fil_io() */
fil_io(request,
sync, bpage->id, bpage->size, 0, bpage->size.physical(),
frame, bpage);
frame, bpage);
} else {
ut_ad(!srv_read_only_mode);
if (flush_type == BUF_FLUSH_SINGLE_PAGE) {
buf_dblwr_write_single_page(bpage, sync);
} else {
......@@ -1111,13 +1115,17 @@ buf_flush_write_block_low(
are working on. */
if (sync) {
ut_ad(flush_type == BUF_FLUSH_SINGLE_PAGE);
fil_flush(bpage->id.space());
if (!is_temp) {
fil_flush(space);
}
/* true means we want to evict this page from the
LRU list as well. */
buf_page_io_complete(bpage, true);
}
fil_space_release(space);
/* Increment the counter of I/O operations used
for selecting LRU policy. */
buf_LRU_stat_inc_io();
......
......@@ -5487,6 +5487,24 @@ fil_flush(
mutex_exit(&fil_system->mutex);
}
/** Flush a tablespace.
@param[in,out] space tablespace to flush */
void
fil_flush(fil_space_t* space)
{
ut_ad(space->n_pending_ops > 0);
ut_ad(space->purpose == FIL_TYPE_TABLESPACE
|| space->purpose == FIL_TYPE_IMPORT);
if (!space->is_stopping()) {
mutex_enter(&fil_system->mutex);
if (!space->is_stopping()) {
fil_flush_low(space);
}
mutex_exit(&fil_system->mutex);
}
}
/** Flush to disk the writes in file spaces of the given type
possibly cached by the OS.
@param[in] purpose FIL_TYPE_TABLESPACE or FIL_TYPE_LOG */
......@@ -5955,12 +5973,13 @@ fil_iterate(
if (page_compressed) {
ulint len = 0;
byte * res = fil_compress_page(space_id,
byte * res = fil_compress_page(
NULL,
src,
NULL,
size,
dict_table_page_compression_level(iter.table),
fil_space_get_block_size(space_id, offset, size),
512,/* FIXME: use proper block size */
encrypted,
&len,
NULL);
......@@ -5975,6 +5994,8 @@ fil_iterate(
/* 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(
......@@ -6822,73 +6843,24 @@ fil_space_keyrotate_next(
return(space);
}
/********************************************************************//**
Find correct node from file space
@return node */
static
fil_node_t*
fil_space_get_node(
fil_space_t* space, /*!< in: file spage */
ulint space_id, /*!< in: space id */
os_offset_t* block_offset, /*!< in/out: offset in number of blocks */
ulint byte_offset, /*!< in: remainder of offset in bytes; in
aio this must be divisible by the OS block
size */
ulint len) /*!< in: how many bytes to read or write; this
must not cross a file boundary; in aio this
must be a block size multiple */
{
fil_node_t* node;
ut_ad(mutex_own(&fil_system->mutex));
node = UT_LIST_GET_FIRST(space->chain);
for (;;) {
if (node == NULL) {
return(NULL);
} else if (fil_is_user_tablespace_id(space->id)
&& node->size == 0) {
/* We do not know the size of a single-table tablespace
before we open the file */
break;
} else if (node->size > *block_offset) {
/* Found! */
break;
} else {
*block_offset -= node->size;
node = UT_LIST_GET_NEXT(chain, node);
}
}
return (node);
}
/********************************************************************//**
Return block size of node in file space
@param[in] space_id space id
@param[in] block_offset page offset
@param[in] len page len
@return file block size */
/** Determine the block size of the data file.
@param[in] space tablespace
@param[in] offset page number
@return block size */
UNIV_INTERN
ulint
fil_space_get_block_size(
ulint space_id,
os_offset_t block_offset,
ulint len)
fil_space_get_block_size(const fil_space_t* space, unsigned offset)
{
ulint block_size = 512;
ut_ad(!mutex_own(&fil_system->mutex));
mutex_enter(&fil_system->mutex);
fil_space_t* space = fil_space_get_space(space_id);
if (space) {
fil_node_t* node = fil_space_get_node(space, space_id, &block_offset, 0, len);
if (node) {
block_size = node->block_size;
for (fil_node_t* node = UT_LIST_GET_FIRST(space->chain);
node != NULL;
node = UT_LIST_GET_NEXT(chain, node)) {
block_size = node->block_size;
if (node->size > offset) {
break;
}
offset -= node->size;
}
/* Currently supporting block size up to 4K,
......@@ -6897,8 +6869,6 @@ fil_space_get_block_size(
block_size = 512;
}
mutex_exit(&fil_system->mutex);
return block_size;
}
......
......@@ -85,8 +85,7 @@ UNIV_INTERN
byte*
fil_compress_page(
/*==============*/
ulint space_id, /*!< in: tablespace id of the
table. */
fil_space_t* space, /*!< in,out: tablespace (NULL during IMPORT) */
byte* buf, /*!< in: buffer from which to write; in aio
this must be appropriately aligned */
byte* out_buf, /*!< out: compressed buffer */
......@@ -104,9 +103,12 @@ fil_compress_page(
ulint write_size=0;
/* Cache to avoid change during function execution */
ulint comp_method = innodb_compression_algorithm;
ulint orig_page_type;
bool allocated=false;
/* page_compression does not apply to tables or tablespaces
that use ROW_FORMAT=COMPRESSED */
ut_ad(!space || !page_size_t(space->flags).is_compressed());
if (encrypted) {
header_len += FIL_PAGE_COMPRESSION_METHOD_SIZE;
}
......@@ -127,19 +129,13 @@ fil_compress_page(
ut_ad(len);
ut_ad(out_len);
/* read original page type */
orig_page_type = mach_read_from_2(buf + FIL_PAGE_TYPE);
fil_system_enter();
fil_space_t* space = fil_space_get_by_id(space_id);
fil_system_exit();
/* Let's not compress file space header or
extent descriptor */
if (orig_page_type == 0 ||
orig_page_type == FIL_PAGE_TYPE_FSP_HDR ||
orig_page_type == FIL_PAGE_TYPE_XDES ||
orig_page_type == FIL_PAGE_PAGE_COMPRESSED) {
switch (fil_page_get_type(buf)) {
case 0:
case FIL_PAGE_TYPE_FSP_HDR:
case FIL_PAGE_TYPE_XDES:
case FIL_PAGE_PAGE_COMPRESSED:
*out_len = len;
goto err_exit;
......@@ -151,12 +147,9 @@ fil_compress_page(
comp_level = page_zip_level;
}
#ifdef UNIV_PAGECOMPRESS_DEBUG
ib_logf(IB_LOG_LEVEL_INFO,
"Preparing for compress for space " ULINTPF
" name %s len " ULINTPF ".",
space_id, fil_space_name(space), len);
#endif /* UNIV_PAGECOMPRESS_DEBUG */
DBUG_LOG("compress", "Preparing for space "
<< (space ? space->id : 0) << " '"
<< (space ? space->name : "(import)") << "' len " << len);
write_size = UNIV_PAGE_SIZE - header_len;
......@@ -306,13 +299,12 @@ fil_compress_page(
comp_page = static_cast<byte *>(ut_malloc_nokey(UNIV_PAGE_SIZE));
uncomp_page = static_cast<byte *>(ut_malloc_nokey(UNIV_PAGE_SIZE));
memcpy(comp_page, out_buf, UNIV_PAGE_SIZE);
bool tsfound;
const page_size_t page_size = fil_space_get_page_size(space_id, &tsfound);
fil_decompress_page(uncomp_page, comp_page, ulong(len), NULL);
if (buf_page_is_corrupted(false, uncomp_page, page_size, space)) {
buf_page_print(uncomp_page, page_size, 0);
if (buf_page_is_corrupted(false, uncomp_page, univ_page_size,
space)) {
buf_page_print(uncomp_page, univ_page_size, 0);
}
ut_free(comp_page);
......@@ -341,12 +333,10 @@ fil_compress_page(
#endif
}
#ifdef UNIV_PAGECOMPRESS_DEBUG
ib_logf(IB_LOG_LEVEL_INFO,
"Compression succeeded for space " ULINTPF
" name %s len " ULINTPF " out_len " ULINTPF ".",
space_id, fil_space_name(space), len, write_size);
#endif /* UNIV_PAGECOMPRESS_DEBUG */
DBUG_LOG("compress", "Succeeded for space "
<< (space ? space->id : 0) << " '"
<< (space ? space->name : "(import)")
<< "' len " << len << " out_len " << write_size);
srv_stats.page_compression_saved.add((len - write_size));
srv_stats.pages_page_compressed.inc();
......@@ -372,11 +362,11 @@ fil_compress_page(
/* If error we leave the actual page as it was */
#ifndef UNIV_PAGECOMPRESS_DEBUG
if (space && space->printed_compression_failure == false) {
if (!space->printed_compression_failure) {
#endif
ib::warn() << "Compression failed for space: "
<< space_id << " name: "
<< fil_space_name(space) << " len: "
<< space->id << " name: "
<< space->name << " len: "
<< len << " err: " << err << " write_size: "
<< write_size
<< " compression method: "
......@@ -643,21 +633,16 @@ fil_decompress_page(
/* Note that as we have found the page is corrupted, so
all this could be incorrect. */
ulint space_id = mach_read_from_4(buf+FIL_PAGE_SPACE_ID);
fil_system_enter();
fil_space_t* space = fil_space_get_by_id(space_id);
fil_system_exit();
bool tsfound;
const page_size_t page_size = fil_space_get_page_size(space_id, &tsfound);
const FilSpace space(space_id, true);
ib::error() << "Corruption: Page is marked as compressed"
<< " space: " << space_id << " name: "
<< (space ? fil_space_name(space) : "NULL")
<< (space() ? space()->name : "NULL")
<< " but uncompress failed with error: " << err
<< " size: " << actual_size
<< " len: " << len
<< " compression method: "
<< fil_get_compression_alg_name(compression_alg) << ".";
buf_page_print(buf, page_size, 0);
buf_page_print(buf, univ_page_size, 0);
}
......@@ -1544,17 +1544,19 @@ buf_flush_update_zip_checksum(
ulint size,
lsn_t lsn);
/********************************************************************//**
The hook that is called just before a page is written to disk.
The function encrypts the content of the page and returns a pointer
to a frame that will be written instead of the real frame. */
/** Encryption and page_compression hook that is called just before
a page is written to disk.
@param[in,out] space tablespace
@param[in,out] bpage buffer page
@param[in] src_frame physical page frame that is being encrypted
@return page frame to be written to file
(may be src_frame or an encrypted/compressed copy of it) */
UNIV_INTERN
byte*
buf_page_encrypt_before_write(
/*==========================*/
buf_page_t* page, /*!< in/out: buffer page to be flushed */
byte* frame, /*!< in: src frame */
ulint space_id); /*!< in: space id */
fil_space_t* space,
buf_page_t* bpage,
byte* src_frame);
/** @brief The temporary memory structure.
......
......@@ -1216,6 +1216,11 @@ fil_flush(
/*======*/
ulint space_id); /*!< in: file space id (this can be a group of
log files or a tablespace of the database) */
/** Flush a tablespace.
@param[in,out] space tablespace to flush */
void
fil_flush(fil_space_t* space);
/** Flush to disk the writes in file spaces of the given type
possibly cached by the OS.
@param[in] purpose FIL_TYPE_TABLESPACE or FIL_TYPE_LOG */
......@@ -1582,18 +1587,13 @@ void test_make_filepath();
#endif /* UNIV_ENABLE_UNIT_TEST_MAKE_FILEPATH */
/*******************************************************************//**
Returns the block size of the file space
@param[in] space_id space id
@param[in] offset page offset
@param[in] len page len
/** Determine the block size of the data file.
@param[in] space tablespace
@param[in] offset page number
@return block size */
UNIV_INTERN
ulint
fil_space_get_block_size(
ulint id,
os_offset_t offset,
ulint len);
fil_space_get_block_size(const fil_space_t* space, unsigned offset);
/*******************************************************************//**
Increments the count of pending operation, if space is not being deleted.
@return TRUE if being deleted, and operation should be skipped */
......
......@@ -26,28 +26,6 @@ Created 31/03/2015 Jan Lindström
#ifndef fil0fil_ic
#define fil0fil_ic
/*******************************************************************//**
Return space name */
UNIV_INLINE
char*
fil_space_name(
/*===========*/
fil_space_t* space) /*!< in: space */
{
return (space->name);
}
/*******************************************************************//**
Return space flags */
UNIV_INLINE
ulint
fil_space_flags(
/*===========*/
fil_space_t* space) /*!< in: space */
{
return (space->flags);
}
/*******************************************************************//**
Return page type name */
UNIV_INLINE
......
......@@ -30,34 +30,6 @@ atomic writes information to table space.
Created 11/12/2013 Jan Lindström jan.lindstrom@skysql.com
***********************************************************************/
/*******************************************************************//**
Returns the page compression level flag of the space, or 0 if the space
is not compressed. The tablespace must be cached in the memory cache.
@return page compression level if page compressed, ULINT_UNDEFINED if space not found */
UNIV_INLINE
ulint
fil_space_get_page_compression_level(
/*=================================*/
ulint id); /*!< in: space id */
/*******************************************************************//**
Returns the page compression flag of the space, or false if the space
is not compressed. The tablespace must be cached in the memory cache.
@return true if page compressed, false if not or space not found */
UNIV_INLINE
bool
fil_space_is_page_compressed(
/*=========================*/
ulint id); /*!< in: space id */
/*******************************************************************//**
Returns the atomic writes flag of the space, or false if the space
is not using atomic writes. The tablespace must be cached in the memory cache.
@return atomic write table option value */
UNIV_INLINE
bool
fil_space_get_atomic_writes(
/*=========================*/
ulint id); /*!< in: space id */
/****************************************************************//**
For page compressed pages compress the page before actual write
operation.
......@@ -66,8 +38,7 @@ UNIV_INTERN
byte*
fil_compress_page(
/*==============*/
ulint space_id, /*!< in: tablespace id of the
table. */
fil_space_t* space, /*!< in,out: tablespace (NULL during IMPORT) */
byte* buf, /*!< in: buffer from which to write; in aio
this must be appropriately aligned */
byte* out_buf, /*!< out: compressed buffer */
......
......@@ -74,47 +74,6 @@ fil_page_is_compressed_encrypted(
return(mach_read_from_2(buf+FIL_PAGE_TYPE) == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED);
}
#ifndef UNIV_INNOCHECKSUM
/*******************************************************************//**
Returns the page compression level of the space, or 0 if the space
is not compressed. The tablespace must be cached in the memory cache.
@return page compression level, 0 if space not found */
UNIV_INLINE
ulint
fil_space_get_page_compression_level(
/*=================================*/
ulint id) /*!< in: space id */
{
ulint flags;
flags = fil_space_get_flags(id);
if (flags && flags != ULINT_UNDEFINED) {
return(fsp_flags_get_page_compression_level(flags));
}
return(0);
}
/*******************************************************************//**
Extract the page compression from space.
@return true if space is page compressed, false if space is not found
or space is not page compressed. */
UNIV_INLINE
bool
fil_space_is_page_compressed(
/*=========================*/
ulint id) /*!< in: space id */
{
ulint flags = fil_space_get_flags(id);
return(flags != ULINT_UNDEFINED
&& FSP_FLAGS_HAS_PAGE_COMPRESSION(flags));
}
#endif /* UNIV_INNOCHECKSUM */
/****************************************************************//**
Get the name of the compression algorithm used for page
compression.
......@@ -154,31 +113,6 @@ fil_get_compression_alg_name(
}
#ifndef UNIV_INNOCHECKSUM
/*******************************************************************//**
Returns the atomic writes flag of the space, or false if the space
is not using atomic writes. The tablespace must be cached in the memory cache.
@return 1 if atomic writes can be used for the file */
UNIV_INLINE
bool
fil_space_get_atomic_writes(
/*========================*/
ulint id) /*!< in: space id */
{
struct fil_space_t* space;
bool ret= 0;
ut_ad(fil_system);
mutex_enter(&fil_system->mutex);
if ((space = fil_space_get_by_id(id)))
ret= space->atomic_write_supported;
mutex_exit(&fil_system->mutex);
return(ret);
}
/*******************************************************************//**
Find out wheather the page is page compressed with lzo method
@return true if page is page compressed with lzo method, false if not */
......
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