diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2020-02-26 09:58:31 +0200 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2020-02-27 16:47:00 +0200 |
commit | 4431144ae554ffe45a52d330a55eae171271911c (patch) | |
tree | b64151660fd903f7906bdda8089e9a4ac3d7dd47 | |
parent | a346ff353e4909f96b6cdf1c997cd168b59b004f (diff) | |
download | mariadb-git-4431144ae554ffe45a52d330a55eae171271911c.tar.gz |
MDEV-12353: Make UNDO_APPEND more robust
This is a follow-up to commit 84e3f9ce84c3e7fce70142cff4bea1c8b916810b
that introduced the EXTENDED log record of UNDO_APPEND subtype.
mtr_t::undo_append(): Accurately enforce the mtr_buf_t::MAX_DATA_SIZE
limit. Also, replace mtr_buf_t::push() with simpler code, to append 1 byte
to the log.
log_phys_t::undo_append(): Return whether the page was found to
be in an inconsistent state.
log_phys_t::apply(): If corruption was noticed, stop applying log
unless innodb_force_recovery is set.
-rw-r--r-- | storage/innobase/include/mtr0log.h | 9 | ||||
-rw-r--r-- | storage/innobase/include/mtr0mtr.h | 2 | ||||
-rw-r--r-- | storage/innobase/log/log0recv.cc | 23 |
3 files changed, 23 insertions, 11 deletions
diff --git a/storage/innobase/include/mtr0log.h b/storage/innobase/include/mtr0log.h index fe80068fa0e..14a58c7575e 100644 --- a/storage/innobase/include/mtr0log.h +++ b/storage/innobase/include/mtr0log.h @@ -523,7 +523,7 @@ inline void mtr_t::free(const page_id_t id) /** Write an EXTENDED log record. @param block buffer pool page -@param type extended record subtype; @see mrec_ext_t */ +@param type extended record subtype; @see mrec_ext_t */ inline void mtr_t::log_write_extended(const buf_block_t &block, byte type) { set_modified(); @@ -615,7 +615,7 @@ inline void mtr_t::undo_append(const buf_block_t &block, set_modified(); if (m_log_mode != MTR_LOG_ALL) return; - const bool small= len < mtr_buf_t::MAX_DATA_SIZE - (3 + 3 + 5 + 5); + const bool small= len + 1 < mtr_buf_t::MAX_DATA_SIZE - (1 + 3 + 3 + 5 + 5); byte *end= log_write<EXTENDED>(block.page.id, &block.page, len + 1, small); if (UNIV_LIKELY(small)) { @@ -626,8 +626,9 @@ inline void mtr_t::undo_append(const buf_block_t &block, else { m_log.close(end); - byte type= UNDO_APPEND; - m_log.push(&type, 1); + end= m_log.open(1); + *end++= UNDO_APPEND; + m_log.close(end); m_log.push(static_cast<const byte*>(data), static_cast<uint32_t>(len)); } m_last_offset= FIL_PAGE_TYPE; diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h index 9461765abf4..5a0b4fd77b9 100644 --- a/storage/innobase/include/mtr0mtr.h +++ b/storage/innobase/include/mtr0mtr.h @@ -551,7 +551,7 @@ private: /** Write an EXTENDED log record. @param block buffer pool page - @param type extended record subtype; @see mrec_ext_t */ + @param type extended record subtype; @see mrec_ext_t */ inline void log_write_extended(const buf_block_t &block, byte type); /** Prepare to write the mini-transaction log to the redo log buffer. diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index 176b8c1d5d1..6c882600d42 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -157,8 +157,9 @@ public: @see mtr_t::undo_append() @param block undo log page @param data undo log record - @param len length of the undo log record */ - static void undo_append(const buf_block_t &block, const byte *data, + @param len length of the undo log record + @return whether the operation failed (inconcistency was noticed) */ + static bool undo_append(const buf_block_t &block, const byte *data, size_t len) { ut_ad(len > 2); @@ -170,7 +171,7 @@ public: { ib::error() << "Not applying UNDO_APPEND due to corruption on " << block.page.id; - return; + return true; } byte *p= block.frame + free; @@ -180,6 +181,7 @@ public: memcpy(p, data, len); p+= len; mach_write_to_2(p, free); + return false; } /** The status of apply() */ @@ -307,12 +309,17 @@ public: case UNDO_APPEND: if (UNIV_UNLIKELY(rlen <= 3)) goto record_corrupted; - undo_append(block, ++l, --rlen); + if (undo_append(block, ++l, --rlen) && !srv_force_recovery) + { + ib::error() << "Set innodb_force_recovery=1 to ignore corruption."; + recv_sys.found_corrupt_log= true; + return applied; + } break; case DELETE_ROW_FORMAT_REDUNDANT: if (UNIV_UNLIKELY(rlen < 2 || rlen > 4)) goto record_corrupted; - rlen--; + rlen--; ll= mlog_decode_varint_length(*++l); if (UNIV_UNLIKELY(ll != rlen)) goto record_corrupted; @@ -321,7 +328,7 @@ public: case DELETE_ROW_FORMAT_DYNAMIC: if (UNIV_UNLIKELY(rlen < 2)) goto record_corrupted; - rlen--; + rlen--; ll= mlog_decode_varint_length(*++l); if (UNIV_UNLIKELY(ll > 3 || ll >= rlen)) goto record_corrupted; @@ -2274,6 +2281,10 @@ static void recv_recover_page(buf_block_t* block, mtr_t& mtr, } set_start_lsn: + if (recv_sys.found_corrupt_log && !srv_force_recovery) { + break; + } + if (!start_lsn) { start_lsn = l->start_lsn; } |