summaryrefslogtreecommitdiff
path: root/storage/innobase/buf
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/buf')
-rw-r--r--storage/innobase/buf/buf0buf.cc446
-rw-r--r--storage/innobase/buf/buf0checksum.cc46
-rw-r--r--storage/innobase/buf/buf0flu.cc9
-rw-r--r--storage/innobase/buf/buf0lru.cc2
-rw-r--r--storage/innobase/buf/buf0rea.cc155
5 files changed, 307 insertions, 351 deletions
diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc
index 754b2cd1c25..e63c234b2f6 100644
--- a/storage/innobase/buf/buf0buf.cc
+++ b/storage/innobase/buf/buf0buf.cc
@@ -412,16 +412,6 @@ bool
buf_page_decrypt_after_read(buf_page_t* bpage, fil_space_t* space)
MY_ATTRIBUTE((nonnull));
-/** Check if page is maybe compressed, encrypted or both when we encounter
-corrupted page. Note that we can't be 100% sure if page is corrupted
-or decrypt/decompress just failed.
-@param[in,out] bpage Page
-@return true if page corrupted, false if not */
-static
-bool
-buf_page_check_corrupt(buf_page_t* bpage)
- MY_ATTRIBUTE((nonnull, warn_unused_result));
-
/* prototypes for new functions added to ha_innodb.cc */
trx_t* innobase_get_trx();
@@ -782,20 +772,18 @@ buf_page_is_checksum_valid_none(
&& checksum_field1 == BUF_NO_CHECKSUM_MAGIC);
}
-/** Checks if a page is corrupt.
-@param[in] check_lsn true if we need to check and complain about
-the LSN
+/** Check if a page is corrupt.
+@param[in] check_lsn whether the LSN should be checked
@param[in] read_buf database page
@param[in] page_size page size
@param[in] space tablespace
-@return TRUE if corrupted */
+@return whether the page is corrupted */
bool
buf_page_is_corrupted(
bool check_lsn,
const byte* read_buf,
const page_size_t& page_size,
- const fil_space_t* space
-)
+ const fil_space_t* space)
{
ulint checksum_field1;
ulint checksum_field2;
@@ -970,25 +958,23 @@ buf_page_is_corrupted(
SRV_CHECKSUM_ALGORITHM_NONE,
page_id);
}
-#endif /* !UNIV_INNOCHECKSUM */
-
-#ifdef UNIV_INNOCHECKSUM
+#else /* !UNIV_INNOCHECKSUM */
if (log_file) {
-
fprintf(log_file, "page::%lu;"
- " old style: calculated = " ULINTPF ";"
- " recorded = " ULINTPF "\n", cur_page_num,
+ " old style: calculated = %u;"
+ " recorded = " ULINTPF "\n",
+ cur_page_num,
buf_calc_page_old_checksum(read_buf),
checksum_field2);
fprintf(log_file, "page::%lu;"
- " new style: calculated = " ULINTPF ";"
+ " new style: calculated = %u;"
" crc32 = %u; recorded = " ULINTPF "\n",
cur_page_num,
buf_calc_page_new_checksum(read_buf),
buf_calc_page_crc32(read_buf),
checksum_field1);
}
-#endif /* UNIV_INNOCHECKSUM */
+#endif /* !UNIV_INNOCHECKSUM */
return(false);
}
@@ -1055,24 +1041,22 @@ buf_page_is_corrupted(
SRV_CHECKSUM_ALGORITHM_NONE,
page_id);
}
-#endif /* !UNIV_INNOCHECKSUM */
-
-#ifdef UNIV_INNOCHECKSUM
+#else /* !UNIV_INNOCHECKSUM */
if (log_file) {
fprintf(log_file, "page::%lu;"
- " old style: calculated = %lu;"
+ " old style: calculated = %u;"
" recorded = %lu\n", cur_page_num,
buf_calc_page_old_checksum(read_buf),
checksum_field2);
fprintf(log_file, "page::%lu;"
- " new style: calculated = %lu;"
+ " new style: calculated = %u;"
" crc32 = %u; recorded = %lu\n",
cur_page_num,
buf_calc_page_new_checksum(read_buf),
buf_calc_page_crc32(read_buf),
checksum_field1);
}
-#endif /* UNIV_INNOCHECKSUM */
+#endif /* !UNIV_INNOCHECKSUM */
return(false);
}
@@ -1423,7 +1407,6 @@ buf_block_init(
block->page.buf_fix_count = 0;
block->page.io_fix = BUF_IO_NONE;
block->page.flush_observer = NULL;
- block->page.key_version = 0;
block->page.encrypted = false;
block->page.real_size = 0;
block->page.write_size = 0;
@@ -3709,7 +3692,6 @@ buf_page_get_zip(
ibool discard_attempted = FALSE;
ibool must_read;
buf_pool_t* buf_pool = buf_pool_get(page_id);
- buf_page_t* rpage = NULL;
buf_pool->stat.n_page_gets++;
@@ -3728,7 +3710,14 @@ lookup:
/* Page not in buf_pool: needs to be read from file */
ut_ad(!hash_lock);
- buf_read_page(page_id, page_size, &rpage);
+ dberr_t err = buf_read_page(page_id, page_size);
+
+ if (err != DB_SUCCESS) {
+ ib::error() << "Reading compressed page " << page_id
+ << " failed with error: " << ut_strerr(err);
+
+ goto err_exit;
+ }
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
ut_a(++buf_dbg_counter % 5771 || buf_validate());
@@ -4205,7 +4194,6 @@ loop:
}
if (block == NULL) {
- buf_page_t* bpage=NULL;
/* Page not in buf_pool: needs to be read from file */
@@ -4263,7 +4251,20 @@ loop:
return(NULL);
}
- if (buf_read_page(page_id, page_size, &bpage)) {
+ /* The call path is buf_read_page() ->
+ buf_read_page_low() (fil_io()) ->
+ buf_page_io_complete() ->
+ buf_decrypt_after_read(). Here fil_space_t* is used
+ and we decrypt -> buf_page_check_corrupt() where page
+ checksums are compared. Decryption, decompression as
+ well as error handling takes place at a lower level.
+ Here we only need to know whether the page really is
+ corrupted, or if an encrypted page with a valid
+ checksum cannot be decypted. */
+
+ dberr_t local_err = buf_read_page(page_id, page_size);
+
+ if (local_err == DB_SUCCESS) {
buf_read_ahead_random(page_id, page_size,
ibuf_inside(mtr));
@@ -4271,82 +4272,44 @@ loop:
} else if (retries < BUF_PAGE_READ_MAX_RETRIES) {
++retries;
- bool corrupted = false;
-
- if (bpage) {
- corrupted = buf_page_check_corrupt(bpage);
- }
-
- /* Do not try again for encrypted pages */
- if (corrupted && bpage->encrypted) {
- BPageMutex* pmutex = buf_page_get_mutex(bpage);
-
- buf_pool = buf_pool_from_bpage(bpage);
- buf_pool_mutex_enter(buf_pool);
- mutex_enter(pmutex);
-
- ut_ad(buf_pool->n_pend_reads > 0);
- my_atomic_addlint(&buf_pool->n_pend_reads, -1);
- buf_page_set_io_fix(bpage, BUF_IO_NONE);
- mutex_exit(pmutex);
- buf_LRU_free_page(bpage, true);
- buf_pool_mutex_exit(buf_pool);
- rw_lock_x_unlock_gen(&((buf_block_t*) bpage)->lock,
- BUF_IO_READ);
-
- if (err) {
- *err = DB_DECRYPTION_FAILED;
- }
-
- return (NULL);
- }
-
DBUG_EXECUTE_IF(
"innodb_page_corruption_retries",
retries = BUF_PAGE_READ_MAX_RETRIES;
);
} else {
- bool corrupted = false;
-
- if (bpage) {
- corrupted = buf_page_check_corrupt(bpage);
+ if (err) {
+ *err = local_err;
}
- if (corrupted && !bpage->encrypted) {
- ib::fatal() << "Unable to read page " << page_id
- << " into the buffer pool after "
- << BUF_PAGE_READ_MAX_RETRIES << " attempts."
- " The most probable cause of this error may"
- " be that the table has been corrupted. Or,"
- " the table was compressed with with an"
- " algorithm that is not supported by this"
- " instance. If it is not a decompress failure,"
- " you can try to fix this problem by using"
- " innodb_force_recovery."
- " Please see " REFMAN " for more"
- " details. Aborting...";
- } else {
- BPageMutex* pmutex = buf_page_get_mutex(bpage);
-
- buf_pool = buf_pool_from_bpage(bpage);
- buf_pool_mutex_enter(buf_pool);
- mutex_enter(pmutex);
-
- ut_ad(buf_pool->n_pend_reads > 0);
- my_atomic_addlint(&buf_pool->n_pend_reads, -1);
- buf_page_set_io_fix(bpage, BUF_IO_NONE);
- mutex_exit(pmutex);
- buf_LRU_free_page(bpage, true);
- buf_pool_mutex_exit(buf_pool);
- rw_lock_x_unlock_gen(&((buf_block_t*) bpage)->lock,
- BUF_IO_READ);
-
- if (err) {
- *err = DB_DECRYPTION_FAILED;
- }
+ /* Pages whose encryption key is unavailable or used
+ key, encryption algorithm or encryption method is
+ incorrect are marked as encrypted in
+ buf_page_check_corrupt(). Unencrypted page could be
+ corrupted in a way where the key_id field is
+ nonzero. There is no checksum on field
+ FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION. */
+ if (local_err == DB_DECRYPTION_FAILED) {
+ return (NULL);
+ }
+ /* Try to set table as corrupted instead of
+ asserting. */
+ if (page_id.space() != TRX_SYS_SPACE &&
+ dict_set_corrupted_by_space(page_id.space())) {
return (NULL);
}
+
+ ib::fatal() << "Unable to read page " << page_id
+ << " into the buffer pool after "
+ << BUF_PAGE_READ_MAX_RETRIES
+ << ". The most probable cause"
+ " of this error may be that the"
+ " table has been corrupted."
+ " You can try to fix this"
+ " problem by using"
+ " innodb_force_recovery."
+ " Please see " REFMAN " for more"
+ " details. Aborting...";
}
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
@@ -5113,7 +5076,6 @@ buf_page_init_low(
bpage->newest_modification = 0;
bpage->oldest_modification = 0;
bpage->write_size = 0;
- bpage->key_version = 0;
bpage->encrypted = false;
bpage->real_size = 0;
bpage->slot = NULL;
@@ -5210,7 +5172,7 @@ buf_page_init(
}
}
-/** Inits a page for read to the buffer buf_pool. If the page is
+/** Initialize a page for read to the buffer buf_pool. If the page is
(1) already in buf_pool, or
(2) if we specify to read only ibuf pages and the page is not an ibuf page, or
(3) if the space is deleted or being deleted,
@@ -5221,15 +5183,17 @@ and the lock released later.
@param[out] err DB_SUCCESS or DB_TABLESPACE_DELETED
@param[in] mode BUF_READ_IBUF_PAGES_ONLY, ...
@param[in] page_id page id
-@param[in] unzip TRUE=request uncompressed page
-@return pointer to the block or NULL */
+@param[in] unzip whether the uncompressed page is
+ requested (for ROW_FORMAT=COMPRESSED)
+@return pointer to the block
+@retval NULL in case of an error */
buf_page_t*
buf_page_init_for_read(
dberr_t* err,
ulint mode,
const page_id_t& page_id,
const page_size_t& page_size,
- ibool unzip)
+ bool unzip)
{
buf_block_t* block;
buf_page_t* bpage = NULL;
@@ -5708,72 +5672,74 @@ buf_page_monitor(
/********************************************************************//**
Mark a table with the specified space pointed by bpage->id.space() corrupted.
Also remove the bpage from LRU list.
-@return TRUE if successful */
+@param[in,out] bpage Block */
static
-ibool
-buf_mark_space_corrupt(
-/*===================*/
- buf_page_t* bpage) /*!< in: pointer to the block in question */
+void
+buf_mark_space_corrupt(buf_page_t* bpage)
{
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
const ibool uncompressed = (buf_page_get_state(bpage)
== BUF_BLOCK_FILE_PAGE);
- ib_uint32_t space = bpage->id.space();
- ibool ret = TRUE;
+ uint32_t space = bpage->id.space();
- if (!bpage->encrypted) {
- /* First unfix and release lock on the bpage */
- buf_pool_mutex_enter(buf_pool);
- mutex_enter(buf_page_get_mutex(bpage));
- ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_READ);
- ut_ad(bpage->buf_fix_count == 0);
-
- /* Set BUF_IO_NONE before we remove the block from LRU list */
- buf_page_set_io_fix(bpage, BUF_IO_NONE);
+ /* First unfix and release lock on the bpage */
+ buf_pool_mutex_enter(buf_pool);
+ mutex_enter(buf_page_get_mutex(bpage));
+ ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_READ);
+ ut_ad(bpage->buf_fix_count == 0);
- if (uncompressed) {
- rw_lock_x_unlock_gen(
- &((buf_block_t*) bpage)->lock,
- BUF_IO_READ);
- }
+ /* Set BUF_IO_NONE before we remove the block from LRU list */
+ buf_page_set_io_fix(bpage, BUF_IO_NONE);
- mutex_exit(buf_page_get_mutex(bpage));
+ if (uncompressed) {
+ rw_lock_x_unlock_gen(
+ &((buf_block_t*) bpage)->lock,
+ BUF_IO_READ);
}
- /* Find the table with specified space id, and mark it corrupted */
- if (dict_set_corrupted_by_space(space)) {
- if (!bpage->encrypted) {
- buf_LRU_free_one_page(bpage);
- }
+ mutex_exit(buf_page_get_mutex(bpage));
+
+ /* If block is not encrypted find the table with specified
+ space id, and mark it corrupted. Encrypted tables
+ are marked unusable later e.g. in ::open(). */
+ if (!bpage->encrypted) {
+ dict_set_corrupted_by_space(space);
} else {
- ret = FALSE;
+ dict_set_encrypted_by_space(space);
}
- if (!bpage->encrypted) {
- ut_ad(buf_pool->n_pend_reads > 0);
- buf_pool->n_pend_reads--;
+ /* After this point bpage can't be referenced. */
+ buf_LRU_free_one_page(bpage);
- buf_pool_mutex_exit(buf_pool);
- }
+ ut_ad(buf_pool->n_pend_reads > 0);
+ buf_pool->n_pend_reads--;
- return(ret);
+ buf_pool_mutex_exit(buf_pool);
}
/** Check if page is maybe compressed, encrypted or both when we encounter
corrupted page. Note that we can't be 100% sure if page is corrupted
or decrypt/decompress just failed.
-@param[in,out] bpage Page
-@return true if page corrupted, false if not */
+@param[in,out] bpage page
+@param[in,out] space tablespace from fil_space_acquire_for_io()
+@return whether the operation succeeded
+@retval DB_SUCCESS if page has been read and is not corrupted
+@retval DB_PAGE_CORRUPTED if page based on checksum check is corrupted
+@retval DB_DECRYPTION_FAILED if page post encryption checksum matches but
+after decryption normal page checksum does not match.
+@retval DB_TABLESPACE_DELETED if accessed tablespace is not found */
static
-bool
-buf_page_check_corrupt(buf_page_t* bpage)
+dberr_t
+buf_page_check_corrupt(buf_page_t* bpage, fil_space_t* space)
{
+ ut_ad(space->n_pending_ios > 0);
+
byte* dst_frame = (bpage->zip.data) ? bpage->zip.data :
((buf_block_t*) bpage)->frame;
- fil_space_t* space = fil_space_acquire_silent(bpage->id.space());
bool still_encrypted = false;
+ dberr_t err = DB_SUCCESS;
bool corrupted = false;
- fil_space_crypt_t* crypt_data = space ? space->crypt_data : NULL;
+ fil_space_crypt_t* crypt_data = space->crypt_data;
/* In buf_decrypt_after_read we have either decrypted the page if
page post encryption checksum matches and used key_id is found
@@ -5784,9 +5750,9 @@ buf_page_check_corrupt(buf_page_t* bpage)
still_encrypted = crypt_data
&& crypt_data->type != CRYPT_SCHEME_UNENCRYPTED
&& !bpage->encrypted
- && fil_space_verify_crypt_checksum(dst_frame, bpage->size,
- bpage->id.space(),
- bpage->id.page_no());
+ && fil_space_verify_crypt_checksum(
+ dst_frame, bpage->size,
+ bpage->id.space(), bpage->id.page_no());
if (!still_encrypted) {
/* If traditional checksums match, we assume that page is
@@ -5796,6 +5762,8 @@ buf_page_check_corrupt(buf_page_t* bpage)
if (!corrupted) {
bpage->encrypted = false;
+ } else {
+ err = DB_PAGE_CORRUPTED;
}
}
@@ -5806,16 +5774,18 @@ buf_page_check_corrupt(buf_page_t* bpage)
buf_page_io_complete(). */
} else if (still_encrypted || (bpage->encrypted && corrupted)) {
bpage->encrypted = true;
- corrupted = true;
+ err = DB_DECRYPTION_FAILED;
ib::error()
- << "The page " << bpage->id << " in file "
- << (space && space->name ? space->name : "NULL")
- << " cannot be decrypted.";
+ << "The page " << bpage->id << " in file '"
+ << space->chain.start->name
+ << "' cannot be decrypted.";
ib::info()
<< "However key management plugin or used key_version "
- << bpage->key_version << " is not found or"
+ << mach_read_from_4(dst_frame
+ + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION)
+ << " is not found or"
" used encryption algorithm or method does not match.";
if (bpage->id.space() != TRX_SYS_SPACE) {
@@ -5827,32 +5797,28 @@ buf_page_check_corrupt(buf_page_t* bpage)
}
}
- if (space) {
- fil_space_release(space);
- }
-
- return corrupted;
+ return (err);
}
-/********************************************************************//**
-Completes an asynchronous read or write request of a file page to or from
-the buffer pool.
-@return true if successful */
-bool
-buf_page_io_complete(
-/*=================*/
- buf_page_t* bpage, /*!< in: pointer to the block in question */
- bool evict) /*!< in: whether or not to evict the page
- from LRU list. */
-
+/** Complete a read or write request of a file page to or from the buffer pool.
+@param[in,out] bpage Page to complete
+@param[in] evict whether or not to evict the page
+ from LRU list.
+@return whether the operation succeeded
+@retval DB_SUCCESS always when writing, or if a read page was OK
+@retval DB_TABLESPACE_DELETED if the tablespace does not exist
+@retval DB_PAGE_CORRUPTED if the checksum fails on a page read
+@retval DB_DECRYPTION_FAILED if page post encryption checksum matches but
+ after decryption normal page checksum does
+ not match */
+UNIV_INTERN
+dberr_t
+buf_page_io_complete(buf_page_t* bpage, bool evict)
{
enum buf_io_fix io_type;
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
- const ibool uncompressed = (buf_page_get_state(bpage)
+ const bool uncompressed = (buf_page_get_state(bpage)
== BUF_BLOCK_FILE_PAGE);
- byte* frame = NULL;
- bool corrupted = false;
-
ut_a(buf_page_in_file(bpage));
/* We do not need protect io_fix here by mutex to read
@@ -5863,46 +5829,42 @@ buf_page_io_complete(
io_type = buf_page_get_io_fix(bpage);
ut_ad(io_type == BUF_IO_READ || io_type == BUF_IO_WRITE);
+ ut_ad(bpage->size.is_compressed() == (bpage->zip.data != NULL));
+ ut_ad(uncompressed || bpage->zip.data);
if (io_type == BUF_IO_READ) {
- ulint read_page_no;
- ulint read_space_id;
+ ulint read_page_no = 0;
+ ulint read_space_id = 0;
+ uint key_version = 0;
ut_ad(bpage->zip.data != NULL || ((buf_block_t*)bpage)->frame != NULL);
fil_space_t* space = fil_space_acquire_for_io(
bpage->id.space());
if (!space) {
- return false;
+ return DB_TABLESPACE_DELETED;
}
buf_page_decrypt_after_read(bpage, space);
- if (bpage->size.is_compressed()) {
- frame = bpage->zip.data;
- } else {
- frame = ((buf_block_t*) bpage)->frame;
- }
-
- if (bpage->size.is_compressed()) {
- frame = bpage->zip.data;
- buf_pool->n_pend_unzip++;
-
- if (uncompressed
- && !buf_zip_decompress((buf_block_t*) bpage,
- FALSE)) {
+ byte* frame = bpage->zip.data
+ ? bpage->zip.data
+ : reinterpret_cast<buf_block_t*>(bpage)->frame;
+ dberr_t err;
- buf_pool->n_pend_unzip--;
+ if (bpage->zip.data && uncompressed) {
+ my_atomic_addlint(&buf_pool->n_pend_unzip, 1);
+ ibool ok = buf_zip_decompress((buf_block_t*) bpage,
+ FALSE);
+ my_atomic_addlint(&buf_pool->n_pend_unzip, -1);
+ if (!ok) {
ib::info() << "Page "
<< bpage->id
<< " zip_decompress failure.";
+ err = DB_PAGE_CORRUPTED;
goto database_corrupted;
}
- buf_pool->n_pend_unzip--;
- } else {
- ut_a(uncompressed);
- frame = ((buf_block_t*) bpage)->frame;
}
/* If this page is not uninitialized and not in the
@@ -5911,6 +5873,8 @@ buf_page_io_complete(
read_page_no = mach_read_from_4(frame + FIL_PAGE_OFFSET);
read_space_id = mach_read_from_4(
frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
+ key_version = mach_read_from_4(
+ frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
if (bpage->id.space() == TRX_SYS_SPACE
&& buf_dblwr_page_inside(bpage->id.page_no())) {
@@ -5934,28 +5898,29 @@ buf_page_io_complete(
<< ", should be " << bpage->id;
}
- corrupted = buf_page_check_corrupt(bpage);
+ err = buf_page_check_corrupt(bpage, space);
database_corrupted:
- if (corrupted) {
+ if (err != DB_SUCCESS) {
/* Not a real corruption if it was triggered by
error injection */
DBUG_EXECUTE_IF(
"buf_page_import_corrupt_failure",
if (bpage->id.space()
> srv_undo_tablespaces_open
- && bpage->id.space() != SRV_TMP_SPACE_ID
- && buf_mark_space_corrupt(bpage)) {
+ && bpage->id.space() != SRV_TMP_SPACE_ID) {
+ buf_mark_space_corrupt(bpage);
ib::info() << "Simulated IMPORT "
"corruption";
fil_space_release_for_io(space);
- return(true);
+ return(err);
}
+ err = DB_SUCCESS;
goto page_not_corrupt;
);
- if (!bpage->encrypted) {
+ if (err == DB_PAGE_CORRUPTED) {
ib::error()
<< "Database page corruption on disk"
" or a failed file read of tablespace "
@@ -5985,38 +5950,14 @@ database_corrupted:
/* If page space id is larger than TRX_SYS_SPACE
(0), we will attempt to mark the corresponding
table as corrupted instead of crashing server */
-
- if (bpage->id.space() > TRX_SYS_SPACE
- && buf_mark_space_corrupt(bpage)) {
- fil_space_release_for_io(space);
- return(false);
- } else {
- if (!bpage->encrypted) {
- ib::fatal()
- << "Aborting because of a"
- " corrupt database page in"
- " the system tablespace. Or, "
- " there was a failure in"
- " tagging the tablespace "
- " as corrupt.";
- }
-
- ib_push_warning(innobase_get_trx(), DB_DECRYPTION_FAILED,
- "Table in tablespace %u encrypted."
- "However key management plugin or used key_id %lu is not found or"
- " used encryption algorithm or method does not match."
- " Can't continue opening the table.",
- bpage->id.space(), bpage->key_version);
-
- if (bpage->encrypted && bpage->id.space() > TRX_SYS_SPACE) {
- buf_mark_space_corrupt(bpage);
- } else {
- ut_error;
- }
-
- fil_space_release_for_io(space);
- return(false);
+ if (bpage->id.space() == TRX_SYS_SPACE) {
+ ib::fatal() << "Aborting because of"
+ " a corrupt database page.";
}
+
+ buf_mark_space_corrupt(bpage);
+ fil_space_release_for_io(space);
+ return(err);
}
}
@@ -6046,7 +5987,7 @@ database_corrupted:
<< bpage->id.space()
<< " encrypted. However key "
"management plugin or used "
- << "key_version " << bpage->key_version
+ << "key_version " << key_version
<< "is not found or"
" used encryption algorithm or method does not match."
" Can't continue opening the table.";
@@ -6150,7 +6091,7 @@ database_corrupted:
buf_pool_mutex_exit(buf_pool);
- return(true);
+ return DB_SUCCESS;
}
/*********************************************************************//**
@@ -6173,9 +6114,7 @@ buf_all_freed_instance(
for (i = buf_pool->n_chunks; i--; chunk++) {
- const buf_block_t* block = buf_chunk_not_freed(chunk);
-
- if (UNIV_LIKELY_NULL(block) && block->page.key_version == 0) {
+ if (const buf_block_t* block = buf_chunk_not_freed(chunk)) {
ib::fatal() << "Page " << block->page.id
<< " still fixed or dirty";
}
@@ -7324,33 +7263,29 @@ buf_page_encrypt_before_write(
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;
case TRX_SYS_PAGE_NO:
if (bpage->id.space() == TRX_SYS_SPACE) {
/* 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;
+
const bool encrypted = crypt_data
&& !crypt_data->not_encrypted()
&& crypt_data->type != CRYPT_SCHEME_UNENCRYPTED
&& (!crypt_data->is_default_encryption()
|| srv_encrypt_tables);
- if (!encrypted) {
- bpage->key_version = 0;
- }
-
bool page_compressed = FSP_FLAGS_HAS_PAGE_COMPRESSION(space->flags);
if (!encrypted && !page_compressed) {
- /* No need to encrypt or page compress the page */
+ /* No need to encrypt or page compress the page.
+ Clear key-version & crypt-checksum. */
+ memset(src_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, 0, 8);
return src_frame;
}
@@ -7370,11 +7305,6 @@ buf_page_encrypt_before_write(
src_frame,
dst_frame);
- uint32_t key_version = mach_read_from_4(
- dst_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
- ut_ad(key_version == 0 || key_version >= bpage->key_version);
- bpage->key_version = key_version;
- bpage->real_size = page_size.physical();
slot->out_buf = dst_frame = tmp;
ut_d(fil_page_type_validate(tmp));
@@ -7386,7 +7316,7 @@ buf_page_encrypt_before_write(
space,
(byte *)src_frame,
slot->comp_buf,
- page_size.logical(),
+ srv_page_size,
fsp_flags_get_page_compression_level(space->flags),
fil_space_get_block_size(space, bpage->id.page_no()),
encrypted,
@@ -7440,8 +7370,6 @@ buf_page_decrypt_after_read(buf_page_t* bpage, fil_space_t* space)
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
bool success = true;
- bpage->key_version = key_version;
-
if (bpage->id.page_no() == 0) {
/* File header pages are not encrypted/compressed */
return (true);
@@ -7481,6 +7409,10 @@ buf_page_decrypt_after_read(buf_page_t* bpage, fil_space_t* space)
if (!fil_space_verify_crypt_checksum(
dst_frame, size,
bpage->id.space(), bpage->id.page_no())) {
+ if (space->crypt_data->type
+ != CRYPT_SCHEME_UNENCRYPTED) {
+ bpage->encrypted = true;
+ }
return (false);
}
@@ -7490,12 +7422,8 @@ buf_page_decrypt_after_read(buf_page_t* bpage, fil_space_t* space)
ut_d(fil_page_type_validate(dst_frame));
/* decrypt using crypt_buf to dst_frame */
- byte* res = fil_space_decrypt(space,
- slot->crypt_buf,
- dst_frame,
- &bpage->encrypted);
-
- if (!res) {
+ if (!fil_space_decrypt(space, slot->crypt_buf,
+ dst_frame, &bpage->encrypted)) {
success = false;
}
diff --git a/storage/innobase/buf/buf0checksum.cc b/storage/innobase/buf/buf0checksum.cc
index 94eafec0584..4b56cc81e98 100644
--- a/storage/innobase/buf/buf0checksum.cc
+++ b/storage/innobase/buf/buf0checksum.cc
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2017, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -80,15 +81,13 @@ buf_calc_page_crc32(
return(c1 ^ c2);
}
-/********************************************************************//**
-Calculates a page checksum which is stored to the page when it is written
+/** Calculate a checksum which is stored to the page when it is written
to a file. Note that we must be careful to calculate the same value on
32-bit and 64-bit architectures.
+@param[in] page file page (srv_page_size bytes)
@return checksum */
-ulint
-buf_calc_page_new_checksum(
-/*=======================*/
- const byte* page) /*!< in: buffer page */
+uint32_t
+buf_calc_page_new_checksum(const byte* page)
{
ulint checksum;
@@ -106,40 +105,29 @@ buf_calc_page_new_checksum(
+ ut_fold_binary(page + FIL_PAGE_DATA,
UNIV_PAGE_SIZE - FIL_PAGE_DATA
- FIL_PAGE_END_LSN_OLD_CHKSUM);
- checksum = checksum & 0xFFFFFFFFUL;
-
- return(checksum);
+ return(static_cast<uint32_t>(checksum));
}
-/********************************************************************//**
-In versions < 4.0.14 and < 4.1.1 there was a bug that the checksum only
-looked at the first few bytes of the page. This calculates that old
-checksum.
+/** In MySQL before 4.0.14 or 4.1.1 there was an InnoDB bug that
+the checksum only looked at the first few bytes of the page.
+This calculates that old checksum.
NOTE: we must first store the new formula checksum to
FIL_PAGE_SPACE_OR_CHKSUM before calculating and storing this old checksum
because this takes that field as an input!
+@param[in] page file page (srv_page_size bytes)
@return checksum */
-ulint
-buf_calc_page_old_checksum(
-/*=======================*/
- const byte* page) /*!< in: buffer page */
+uint32_t
+buf_calc_page_old_checksum(const byte* page)
{
- ulint checksum;
-
- checksum = ut_fold_binary(page, FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
-
- checksum = checksum & 0xFFFFFFFFUL;
-
- return(checksum);
+ return(static_cast<uint32_t>
+ (ut_fold_binary(page, FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION)));
}
-/********************************************************************//**
-Return a printable string describing the checksum algorithm.
+/** Return a printable string describing the checksum algorithm.
+@param[in] algo algorithm
@return algorithm name */
const char*
-buf_checksum_algorithm_name(
-/*========================*/
- srv_checksum_algorithm_t algo) /*!< in: algorithm */
+buf_checksum_algorithm_name(srv_checksum_algorithm_t algo)
{
switch (algo) {
case SRV_CHECKSUM_ALGORITHM_CRC32:
diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc
index 7b0597f27ea..2a9acc8c298 100644
--- a/storage/innobase/buf/buf0flu.cc
+++ b/storage/innobase/buf/buf0flu.cc
@@ -1119,15 +1119,20 @@ buf_flush_write_block_low(
fil_flush(space);
}
- /* true means we want to evict this page from the
- LRU list as well. */
/* The tablespace could already have been dropped,
because fil_io(request, sync) would already have
decremented the node->n_pending. However,
buf_page_io_complete() only needs to look up the
tablespace during read requests, not during writes. */
ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_WRITE);
+#ifdef UNIV_DEBUG
+ dberr_t err =
+#endif
+ /* true means we want to evict this page from the
+ LRU list as well. */
buf_page_io_complete(bpage, true);
+
+ ut_ad(err == DB_SUCCESS);
}
fil_space_release_for_io(space);
diff --git a/storage/innobase/buf/buf0lru.cc b/storage/innobase/buf/buf0lru.cc
index 10a8561d38d..1e7b7065b12 100644
--- a/storage/innobase/buf/buf0lru.cc
+++ b/storage/innobase/buf/buf0lru.cc
@@ -1420,7 +1420,7 @@ loop:
++flush_failures;
}
- srv_stats.buf_pool_wait_free.add(n_iterations, 1);
+ srv_stats.buf_pool_wait_free.inc();
n_iterations++;
diff --git a/storage/innobase/buf/buf0rea.cc b/storage/innobase/buf/buf0rea.cc
index f5bd088ce5c..12775c74daf 100644
--- a/storage/innobase/buf/buf0rea.cc
+++ b/storage/innobase/buf/buf0rea.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2015, 2016 MariaDB Corporation.
+Copyright (c) 2015, 2017, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -118,8 +118,7 @@ buf_read_page_low(
ulint mode,
const page_id_t& page_id,
const page_size_t& page_size,
- bool unzip,
- buf_page_t** rbpage) /*!< out: page */
+ bool unzip)
{
buf_page_t* bpage;
@@ -155,12 +154,9 @@ buf_read_page_low(
return(0);
}
- DBUG_PRINT("ib_buf", ("read page %u:%u size=%u unzip=%u,%s",
- (unsigned) page_id.space(),
- (unsigned) page_id.page_no(),
- (unsigned) page_size.physical(),
- (unsigned) unzip,
- sync ? "sync" : "async"));
+ DBUG_LOG("ib_buf",
+ "read page " << page_id << " size=" << page_size.physical()
+ << " unzip=" << unzip << ',' << (sync ? "sync" : "async"));
ut_ad(buf_page_in_file(bpage));
@@ -213,19 +209,13 @@ buf_read_page_low(
if (sync) {
/* The i/o is already completed when we arrive from
fil_read */
+ *err = buf_page_io_complete(bpage);
- if (!buf_page_io_complete(bpage)) {
- if (rbpage) {
- *rbpage = bpage;
- }
+ if (*err != DB_SUCCESS) {
return(0);
}
}
- if (rbpage) {
- *rbpage = bpage;
- }
-
return(1);
}
@@ -256,7 +246,7 @@ buf_read_ahead_random(
ulint ibuf_mode;
ulint count;
ulint low, high;
- dberr_t err;
+ dberr_t err = DB_SUCCESS;
ulint i;
const ulint buf_read_ahead_random_area
= BUF_READ_AHEAD_AREA(buf_pool);
@@ -369,19 +359,25 @@ read_ahead:
const page_id_t cur_page_id(page_id.space(), i);
if (!ibuf_bitmap_page(cur_page_id, page_size)) {
- buf_page_t* rpage = NULL;
count += buf_read_page_low(
&err, false,
IORequest::DO_NOT_WAKE,
ibuf_mode,
- cur_page_id, page_size, false, &rpage);
+ cur_page_id, page_size, false);
- if (err == DB_TABLESPACE_DELETED) {
- ib::warn() << "Random readahead trying to"
+ switch (err) {
+ case DB_SUCCESS:
+ case DB_TABLESPACE_TRUNCATED:
+ case DB_ERROR:
+ break;
+ case DB_TABLESPACE_DELETED:
+ ib::info() << "Random readahead trying to"
" access page " << cur_page_id
<< " in nonexisting or"
" being-dropped tablespace";
break;
+ default:
+ ut_error;
}
}
}
@@ -414,15 +410,18 @@ an exclusive lock on the buffer frame. The flag is cleared and the x-lock
released by the i/o-handler thread.
@param[in] page_id page id
@param[in] page_size page size
-@return TRUE if page has been read in, FALSE in case of failure */
-ibool
+@retval DB_SUCCESS if the page was read and is not corrupted,
+@retval DB_PAGE_CORRUPTED if page based on checksum check is corrupted,
+@retval DB_DECRYPTION_FAILED if page post encryption checksum matches but
+after decryption normal page checksum does not match.
+@retval DB_TABLESPACE_DELETED if tablespace .ibd file is missing */
+dberr_t
buf_read_page(
const page_id_t& page_id,
- const page_size_t& page_size,
- buf_page_t** bpage) /*!< out: page */
+ const page_size_t& page_size)
{
ulint count;
- dberr_t err;
+ dberr_t err = DB_SUCCESS;
/* We do synchronous IO because our AIO completion code
is sub-optimal. See buf_page_io_complete(), we have to
@@ -432,19 +431,19 @@ buf_read_page(
count = buf_read_page_low(
&err, true,
- 0, BUF_READ_ANY_PAGE, page_id, page_size, false, bpage);
+ 0, BUF_READ_ANY_PAGE, page_id, page_size, false);
srv_stats.buf_pool_reads.add(count);
if (err == DB_TABLESPACE_DELETED) {
- ib::error() << "trying to read page " << page_id
+ ib::info() << "trying to read page " << page_id
<< " in nonexisting or being-dropped tablespace";
}
/* Increment number of I/O operations used for LRU policy. */
buf_LRU_stat_inc_io();
- return(count > 0);
+ return(err);
}
/** High-level function which reads a page asynchronously from a file to the
@@ -453,9 +452,8 @@ an exclusive lock on the buffer frame. The flag is cleared and the x-lock
released by the i/o-handler thread.
@param[in] page_id page id
@param[in] page_size page size
-@param[in] sync true if synchronous aio is desired
-@return TRUE if page has been read in, FALSE in case of failure */
-ibool
+@param[in] sync true if synchronous aio is desired */
+void
buf_read_page_background(
const page_id_t& page_id,
const page_size_t& page_size,
@@ -463,13 +461,31 @@ buf_read_page_background(
{
ulint count;
dberr_t err;
- buf_page_t* rbpage = NULL;
count = buf_read_page_low(
&err, sync,
IORequest::DO_NOT_WAKE | IORequest::IGNORE_MISSING,
BUF_READ_ANY_PAGE,
- page_id, page_size, false, &rbpage);
+ page_id, page_size, false);
+
+ switch (err) {
+ case DB_SUCCESS:
+ case DB_TABLESPACE_TRUNCATED:
+ case DB_ERROR:
+ break;
+ case DB_TABLESPACE_DELETED:
+ ib::info() << "trying to read page " << page_id
+ << " in the background"
+ " in a non-existing or being-dropped tablespace";
+ break;
+ case DB_DECRYPTION_FAILED:
+ ib::error()
+ << "Background Page read failed to decrypt page "
+ << page_id;
+ break;
+ default:
+ ut_error;
+ }
srv_stats.buf_pool_reads.add(count);
@@ -479,8 +495,6 @@ buf_read_page_background(
buffer pool. Since this function is called from buffer pool load
these IOs are deliberate and are not part of normal workload we can
ignore these in our heuristics. */
-
- return(count > 0);
}
/** Applies linear read-ahead if in the buf_pool the page is a border page of
@@ -525,7 +539,7 @@ buf_read_ahead_linear(
ulint new_offset;
ulint fail_count;
ulint low, high;
- dberr_t err;
+ dberr_t err = DB_SUCCESS;
ulint i;
const ulint buf_read_ahead_linear_area
= BUF_READ_AHEAD_AREA(buf_pool);
@@ -730,19 +744,29 @@ buf_read_ahead_linear(
const page_id_t cur_page_id(page_id.space(), i);
if (!ibuf_bitmap_page(cur_page_id, page_size)) {
- buf_page_t* rpage = NULL;
-
count += buf_read_page_low(
&err, false,
IORequest::DO_NOT_WAKE,
- ibuf_mode, cur_page_id, page_size, false, &rpage);
+ ibuf_mode, cur_page_id, page_size, false);
- if (err == DB_TABLESPACE_DELETED) {
- ib::warn() << "linear readahead trying to"
+ switch (err) {
+ case DB_SUCCESS:
+ case DB_TABLESPACE_TRUNCATED:
+ case DB_ERROR:
+ break;
+ case DB_TABLESPACE_DELETED:
+ ib::info() << "linear readahead trying to"
" access page "
<< page_id_t(page_id.space(), i)
<< " in nonexisting or being-dropped"
" tablespace";
+ case DB_DECRYPTION_FAILED:
+ ib::error() << "linear readahead failed to"
+ " decrypt page "
+ << page_id_t(page_id.space(), i);
+ break;
+ default:
+ ut_error;
}
}
}
@@ -797,13 +821,13 @@ buf_read_ibuf_merge_pages(
const page_id_t page_id(space_ids[i], page_nos[i]);
buf_pool_t* buf_pool = buf_pool_get(page_id);
- buf_page_t* rpage = NULL;
bool found;
const page_size_t page_size(fil_space_get_page_size(
space_ids[i], &found));
if (!found) {
+tablespace_deleted:
/* The tablespace was not found, remove the
entries for that page */
ibuf_merge_or_delete_for_page(NULL, page_id,
@@ -822,13 +846,21 @@ buf_read_ibuf_merge_pages(
sync && (i + 1 == n_stored),
0,
BUF_READ_ANY_PAGE, page_id, page_size,
- true, &rpage);
-
- if (err == DB_TABLESPACE_DELETED) {
- /* We have deleted or are deleting the single-table
- tablespace: remove the entries for that page */
- ibuf_merge_or_delete_for_page(NULL, page_id,
- &page_size, FALSE);
+ true);
+
+ switch(err) {
+ case DB_SUCCESS:
+ case DB_TABLESPACE_TRUNCATED:
+ case DB_ERROR:
+ break;
+ case DB_TABLESPACE_DELETED:
+ goto tablespace_deleted;
+ case DB_DECRYPTION_FAILED:
+ ib::error() << "Failed to decrypt page " << page_id
+ << " for change buffer merge";
+ break;
+ default:
+ ut_error;
}
}
@@ -855,9 +887,6 @@ buf_read_recv_pages(
const ulint* page_nos,
ulint n_stored)
{
- ulint count;
- dberr_t err;
- ulint i;
fil_space_t* space = fil_space_get(space_id);
if (space == NULL) {
@@ -869,12 +898,11 @@ buf_read_recv_pages(
const page_size_t page_size(space->flags);
- for (i = 0; i < n_stored; i++) {
+ for (ulint i = 0; i < n_stored; i++) {
buf_pool_t* buf_pool;
const page_id_t cur_page_id(space_id, page_nos[i]);
- buf_page_t* rpage = NULL;
- count = 0;
+ ulint count = 0;
buf_pool = buf_pool_get(cur_page_id);
while (buf_pool->n_pend_reads >= recv_n_pool_free_frames / 2) {
@@ -894,18 +922,25 @@ buf_read_recv_pages(
}
}
- if ((i + 1 == n_stored) && sync) {
+ dberr_t err;
+
+ if (sync && i + 1 == n_stored) {
buf_read_page_low(
&err, true,
0,
BUF_READ_ANY_PAGE,
- cur_page_id, page_size, true, &rpage);
+ cur_page_id, page_size, true);
} else {
buf_read_page_low(
&err, false,
IORequest::DO_NOT_WAKE,
BUF_READ_ANY_PAGE,
- cur_page_id, page_size, true, &rpage);
+ cur_page_id, page_size, true);
+ }
+
+ if (err == DB_DECRYPTION_FAILED) {
+ ib::error() << "Recovery failed to decrypt page "
+ << cur_page_id;
}
}