summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2020-02-26 09:57:00 +0200
committerMarko Mäkelä <marko.makela@mariadb.com>2020-02-27 16:47:00 +0200
commite15ae1cfe1ca954182ab071fc948d6800ef42971 (patch)
tree7a7b318e0d5ed4bcb40574d23c263998c160b31b
parent4431144ae554ffe45a52d330a55eae171271911c (diff)
downloadmariadb-git-e15ae1cfe1ca954182ab071fc948d6800ef42971.tar.gz
MDEV-12353: Improve page_cur_delete_rec() recovery
This is a follow-up to commit 572d20757be38157fa2309c35efdec19e68087f1 where we introduced the EXTENDED log record subtypes DELETE_ROW_FORMAT_REDUNDANT and DELETE_ROW_FORMAT_DYNAMIC. log_phys_t::apply(): If corruption was noticed, stop applying the log unless innodb_force_recovery is set.
-rw-r--r--storage/innobase/include/page0cur.h10
-rw-r--r--storage/innobase/log/log0recv.cc11
-rw-r--r--storage/innobase/page/page0cur.cc16
3 files changed, 24 insertions, 13 deletions
diff --git a/storage/innobase/include/page0cur.h b/storage/innobase/include/page0cur.h
index 8387a409cde..4ed76d5d183 100644
--- a/storage/innobase/include/page0cur.h
+++ b/storage/innobase/include/page0cur.h
@@ -204,16 +204,18 @@ page_cur_delete_rec(
/** Apply a DELETE_ROW_FORMAT_REDUNDANT record that was written by
page_cur_delete_rec() for a ROW_FORMAT=REDUNDANT page.
@param block B-tree or R-tree page in ROW_FORMAT=REDUNDANT
-@param prev byte offset of the predecessor, relative to PAGE_OLD_INFIMUM */
-void page_apply_delete_redundant(const buf_block_t &block, ulint prev);
+@param prev byte offset of the predecessor, relative to PAGE_OLD_INFIMUM
+@return whether the operation failed (inconcistency was noticed) */
+bool page_apply_delete_redundant(const buf_block_t &block, ulint prev);
/** Apply a DELETE_ROW_FORMAT_DYNAMIC record that was written by
page_cur_delete_rec() for a ROW_FORMAT=COMPACT or DYNAMIC page.
@param block B-tree or R-tree page in ROW_FORMAT=COMPACT or DYNAMIC
@param prev byte offset of the predecessor, relative to PAGE_NEW_INFIMUM
@param hdr_size record header size, excluding REC_N_NEW_EXTRA_BYTES
-@param data_size data payload size, in bytes */
-void page_apply_delete_dynamic(const buf_block_t &block, ulint prev,
+@param data_size data payload size, in bytes
+@return whether the operation failed (inconcistency was noticed) */
+bool page_apply_delete_dynamic(const buf_block_t &block, ulint prev,
size_t hdr_size, size_t data_size);
/** Search the right position for a page cursor.
diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc
index 6c882600d42..a9bd2c118be 100644
--- a/storage/innobase/log/log0recv.cc
+++ b/storage/innobase/log/log0recv.cc
@@ -311,6 +311,7 @@ public:
goto record_corrupted;
if (undo_append(block, ++l, --rlen) && !srv_force_recovery)
{
+page_corrupted:
ib::error() << "Set innodb_force_recovery=1 to ignore corruption.";
recv_sys.found_corrupt_log= true;
return applied;
@@ -323,7 +324,9 @@ public:
ll= mlog_decode_varint_length(*++l);
if (UNIV_UNLIKELY(ll != rlen))
goto record_corrupted;
- page_apply_delete_redundant(block, mlog_decode_varint(l));
+ if (page_apply_delete_redundant(block, mlog_decode_varint(l)) &&
+ !srv_force_recovery)
+ goto page_corrupted;
break;
case DELETE_ROW_FORMAT_DYNAMIC:
if (UNIV_UNLIKELY(rlen < 2))
@@ -346,8 +349,10 @@ public:
ll= mlog_decode_varint_length(*l);
if (UNIV_UNLIKELY(ll > 3 || ll != rlen))
goto record_corrupted;
- page_apply_delete_dynamic(block, prev_rec, hdr_size,
- mlog_decode_varint(l));
+ if (page_apply_delete_dynamic(block, prev_rec, hdr_size,
+ mlog_decode_varint(l)) &&
+ !srv_force_recovery)
+ goto page_corrupted;
break;
}
last_offset= FIL_PAGE_TYPE;
diff --git a/storage/innobase/page/page0cur.cc b/storage/innobase/page/page0cur.cc
index dd20f4bca0f..dce4d5e2f5c 100644
--- a/storage/innobase/page/page0cur.cc
+++ b/storage/innobase/page/page0cur.cc
@@ -2060,8 +2060,9 @@ page_cur_delete_rec(
/** Apply a DELETE_ROW_FORMAT_REDUNDANT record that was written by
page_cur_delete_rec() for a ROW_FORMAT=REDUNDANT page.
@param block B-tree or R-tree page in ROW_FORMAT=REDUNDANT
-@param prev byte offset of the predecessor, relative to PAGE_OLD_INFIMUM */
-void page_apply_delete_redundant(const buf_block_t &block, ulint prev)
+@param prev byte offset of the predecessor, relative to PAGE_OLD_INFIMUM
+@return whether the operation failed (inconcistency was noticed) */
+bool page_apply_delete_redundant(const buf_block_t &block, ulint prev)
{
const uint16_t n_slots= page_dir_get_n_slots(block.frame);
ulint n_recs= page_get_n_recs(block.frame);
@@ -2077,7 +2078,7 @@ void page_apply_delete_redundant(const buf_block_t &block, ulint prev)
corrupted:
ib::error() << "Not applying DELETE_ROW_FORMAT_REDUNDANT"
" due to corruption on " << block.page.id;
- return;
+ return true;
}
byte *slot= page_dir_get_nth_slot(block.frame, n_slots - 1);
@@ -2145,6 +2146,7 @@ corrupted:
page_dir_balance_slot(block, (first_slot - slot) / 2);
ut_ad(page_simple_validate_old(block.frame));
+ return false;
}
/** Apply a DELETE_ROW_FORMAT_DYNAMIC record that was written by
@@ -2152,8 +2154,9 @@ page_cur_delete_rec() for a ROW_FORMAT=COMPACT or DYNAMIC page.
@param block B-tree or R-tree page in ROW_FORMAT=COMPACT or DYNAMIC
@param prev byte offset of the predecessor, relative to PAGE_NEW_INFIMUM
@param hdr_size record header size, excluding REC_N_NEW_EXTRA_BYTES
-@param data_size data payload size, in bytes */
-void page_apply_delete_dynamic(const buf_block_t &block, ulint prev,
+@param data_size data payload size, in bytes
+@return whether the operation failed (inconcistency was noticed) */
+bool page_apply_delete_dynamic(const buf_block_t &block, ulint prev,
size_t hdr_size, size_t data_size)
{
const uint16_t n_slots= page_dir_get_n_slots(block.frame);
@@ -2170,7 +2173,7 @@ void page_apply_delete_dynamic(const buf_block_t &block, ulint prev,
corrupted:
ib::error() << "Not applying DELETE_ROW_FORMAT_DYNAMIC"
" due to corruption on " << block.page.id;
- return;
+ return true;
}
byte *slot= page_dir_get_nth_slot(block.frame, n_slots - 1);
@@ -2237,6 +2240,7 @@ corrupted:
page_dir_balance_slot(block, (first_slot - slot) / 2);
ut_ad(page_simple_validate_new(block.frame));
+ return false;
}
#ifdef UNIV_COMPILE_TEST_FUNCS