diff options
Diffstat (limited to 'storage/innobase/include/mtr0mtr.h')
-rw-r--r-- | storage/innobase/include/mtr0mtr.h | 228 |
1 files changed, 95 insertions, 133 deletions
diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h index abc1f65e692..299f658e98a 100644 --- a/storage/innobase/include/mtr0mtr.h +++ b/storage/innobase/include/mtr0mtr.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2013, 2022, MariaDB Corporation. +Copyright (c) 2013, 2023, 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 @@ -29,7 +29,7 @@ Created 11/26/1995 Heikki Tuuri #include "fil0fil.h" #include "dyn0buf.h" #include "buf0buf.h" -#include <vector> +#include "small_vector.h" /** Start a mini-transaction. */ #define mtr_start(m) (m)->start() @@ -37,15 +37,6 @@ Created 11/26/1995 Heikki Tuuri /** Commit a mini-transaction. */ #define mtr_commit(m) (m)->commit() -/** Set and return a savepoint in mtr. -@return savepoint */ -#define mtr_set_savepoint(m) (m)->get_savepoint() - -/** Release the (index tree) s-latch stored in an mtr memo after a -savepoint. */ -#define mtr_release_s_latch_at_savepoint(m, s, l) \ - (m)->release_s_latch_at_savepoint((s), (l)) - /** Change the logging mode of a mini-transaction. @return old mode */ #define mtr_set_log_mode(m, d) (m)->set_log_mode((d)) @@ -60,13 +51,10 @@ savepoint. */ # define mtr_sx_lock_index(i,m) (m)->u_lock(&(i)->lock) #endif -#define mtr_release_block_at_savepoint(m, s, b) \ - (m)->release_block_at_savepoint((s), (b)) - /** Mini-transaction memo stack slot. */ struct mtr_memo_slot_t { - /** pointer to the object, or nullptr if released */ + /** pointer to the object */ void *object; /** type of the stored object */ mtr_memo_type_t type; @@ -77,6 +65,9 @@ struct mtr_memo_slot_t /** Mini-transaction handle and buffer */ struct mtr_t { + mtr_t(); + ~mtr_t(); + /** Start a mini-transaction. */ void start(); @@ -91,11 +82,11 @@ struct mtr_t { /** Release latches of unmodified buffer pages. @param begin first slot to release */ void rollback_to_savepoint(ulint begin) - { rollback_to_savepoint(begin, m_memo->size()); } + { rollback_to_savepoint(begin, m_memo.size()); } /** Release the last acquired buffer page latch. */ void release_last_page() - { auto s= m_memo->size(); rollback_to_savepoint(s - 1, s); } + { auto s= m_memo.size(); rollback_to_savepoint(s - 1, s); } /** Commit a mini-transaction that is shrinking a tablespace. @param space tablespace that is being shrunk */ @@ -120,86 +111,39 @@ struct mtr_t { ulint get_savepoint() const { ut_ad(is_active()); - return m_memo ? m_memo->size() : 0; + return m_memo.size(); } - /** Release the (index tree) s-latch stored in an mtr memo after a savepoint. - @param savepoint value returned by get_savepoint() - @param lock index latch to release */ - void release_s_latch_at_savepoint(ulint savepoint, index_lock *lock) + /** Get the block at a savepoint */ + buf_block_t *at_savepoint(ulint savepoint) const { ut_ad(is_active()); - mtr_memo_slot_t &slot= m_memo->at(savepoint); - ut_ad(slot.object == lock); - ut_ad(slot.type == MTR_MEMO_S_LOCK); - slot.object= nullptr; - lock->s_unlock(); - } - /** Release the block in an mtr memo after a savepoint. */ - void release_block_at_savepoint(ulint savepoint, buf_block_t *block) - { - ut_ad(is_active()); - mtr_memo_slot_t &slot= m_memo->at(savepoint); - ut_ad(slot.object == block); - ut_ad(!(slot.type & MTR_MEMO_MODIFY)); - slot.object= nullptr; - block->page.unfix(); - - switch (slot.type) { - case MTR_MEMO_PAGE_S_FIX: - block->page.lock.s_unlock(); - break; - case MTR_MEMO_PAGE_SX_FIX: - case MTR_MEMO_PAGE_X_FIX: - block->page.lock.u_or_x_unlock(slot.type == MTR_MEMO_PAGE_SX_FIX); - break; - default: - break; - } - } - - /** @return if we are about to make a clean buffer block dirty */ - static bool is_block_dirtied(const buf_page_t &b) - { - ut_ad(b.in_file()); - ut_ad(b.frame); - ut_ad(b.buf_fix_count()); - return b.oldest_modification() <= 1 && b.id().space() < SRV_TMP_SPACE_ID; + const mtr_memo_slot_t &slot= m_memo[savepoint]; + ut_ad(slot.type < MTR_MEMO_S_LOCK); + ut_ad(slot.object); + return static_cast<buf_block_t*>(slot.object); } - /** X-latch a not yet latched block after a savepoint. */ - void x_latch_at_savepoint(ulint savepoint, buf_block_t *block) + /** Try to get a block at a savepoint. + @param savepoint the savepoint right before the block was acquired + @return the block at the savepoint + @retval nullptr if no buffer block was registered at that savepoint */ + buf_block_t *block_at_savepoint(ulint savepoint) const { ut_ad(is_active()); - ut_ad(!memo_contains_flagged(block, MTR_MEMO_PAGE_S_FIX | - MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX)); - mtr_memo_slot_t &slot= m_memo->at(savepoint); - ut_ad(slot.object == block); - ut_ad(slot.type == MTR_MEMO_BUF_FIX); - slot.type= MTR_MEMO_PAGE_X_FIX; - block->page.lock.x_lock(); - ut_ad(!block->page.is_io_fixed()); - - if (!m_made_dirty) - m_made_dirty= is_block_dirtied(block->page); + const mtr_memo_slot_t &slot= m_memo[savepoint]; + return slot.type < MTR_MEMO_S_LOCK + ? static_cast<buf_block_t*>(slot.object) + : nullptr; } - /** U-latch a not yet latched block after a savepoint. */ - void sx_latch_at_savepoint(ulint savepoint, buf_block_t *block) - { - ut_ad(is_active()); - ut_ad(!memo_contains_flagged(block, MTR_MEMO_PAGE_S_FIX | - MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX)); - mtr_memo_slot_t &slot= m_memo->at(savepoint); - ut_ad(slot.object == block); - ut_ad(slot.type == MTR_MEMO_BUF_FIX); - slot.type= MTR_MEMO_PAGE_SX_FIX; - block->page.lock.u_lock(); - ut_ad(!block->page.is_io_fixed()); - - if (!m_made_dirty) - m_made_dirty= is_block_dirtied(block->page); - } + /** Retrieve a page that has already been latched. + @param id page identifier + @param type page latch type + @return block + @retval nullptr if the block had not been latched yet */ + buf_block_t *get_already_latched(const page_id_t id, mtr_memo_type_t type) + const; /** @return the logging mode */ mtr_log_t get_log_mode() const @@ -358,23 +302,17 @@ struct mtr_t { void release(const index_lock &lock) { release(&lock); } /** Release a latch to an unmodified page. */ void release(const buf_block_t &block) { release(&block); } - - /** Note that the mini-transaction will modify data. */ - void flag_modified() { m_modifications = true; } private: /** Release an unmodified object. */ void release(const void *object); +public: /** Mark the given latched page as modified. @param block page that will be modified */ - void modify(const buf_block_t& block); -public: - /** Note that the mini-transaction will modify a block. */ - void set_modified(const buf_block_t &block) - { flag_modified(); if (m_log_mode != MTR_LOG_NONE) modify(block); } + void set_modified(const buf_block_t &block); /** Set the state to not-modified. This will not log the changes. This is only used during redo log apply, to avoid logging the changes. */ - void discard_modifications() { m_modifications = false; } + void discard_modifications() { m_modifications= false; } /** Get the LSN of commit(). @return the commit LSN @@ -403,28 +341,17 @@ public: @param rw_latch latch to acquire */ void upgrade_buffer_fix(ulint savepoint, rw_lock_type_t rw_latch); - /** Register a page latch on a buffer-fixed block was buffer-fixed. - @param latch latch type */ - void u_lock_register(ulint savepoint) + /** Register a change to the page latch state. */ + void lock_register(ulint savepoint, mtr_memo_type_t type) { - mtr_memo_slot_t &slot= m_memo->at(savepoint); - ut_ad(slot.type == MTR_MEMO_BUF_FIX); - slot.type= MTR_MEMO_PAGE_SX_FIX; - } - - /** Register a page latch on a buffer-fixed block was buffer-fixed. - @param latch latch type */ - void s_lock_register(ulint savepoint) - { - mtr_memo_slot_t &slot= m_memo->at(savepoint); - ut_ad(slot.type == MTR_MEMO_BUF_FIX); - slot.type= MTR_MEMO_PAGE_S_FIX; + mtr_memo_slot_t &slot= m_memo[savepoint]; + ut_ad(slot.type <= MTR_MEMO_BUF_FIX); + ut_ad(type <= MTR_MEMO_BUF_FIX); + slot.type= type; } /** Upgrade U locks on a block to X */ void page_lock_upgrade(const buf_block_t &block); - /** Upgrade U lock to X */ - void lock_upgrade(const index_lock &lock); /** Check if we are holding tablespace latch @param space tablespace to search for @@ -454,31 +381,66 @@ public: @retval nullptr if not found */ buf_block_t *memo_contains_page_flagged(const byte *ptr, ulint flags) const; - /** @return true if mini-transaction contains modifications. */ + /** @return whether this mini-transaction modifies persistent data */ bool has_modifications() const { return m_modifications; } #endif /* UNIV_DEBUG */ - /** Push an object to an mtr memo stack. - @param object object + /** Push a buffer page to an the memo. + @param block buffer block @param type object type: MTR_MEMO_S_LOCK, ... */ - void memo_push(void *object, mtr_memo_type_t type) __attribute__((nonnull)) + void memo_push(buf_block_t *block, mtr_memo_type_t type) + __attribute__((nonnull)) { ut_ad(is_active()); - /* If this mtr has U or X latched a clean page then we set - the m_made_dirty flag. This tells us if we need to - grab log_sys.flush_order_mutex at mtr_t::commit() so that we - can insert the dirtied page into the buf_pool.flush_list. - - FIXME: Do this only when the MTR_MEMO_MODIFY flag is set! */ - if (!m_made_dirty && - (type & (MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX))) - m_made_dirty= - is_block_dirtied(*static_cast<const buf_page_t*>(object)); - - if (!m_memo) - m_memo= new std::vector<mtr_memo_slot_t>(1, {object, type}); + ut_ad(type <= MTR_MEMO_PAGE_SX_MODIFY); + ut_ad(block->page.buf_fix_count()); + ut_ad(block->page.in_file()); +#ifdef UNIV_DEBUG + switch (type) { + case MTR_MEMO_PAGE_S_FIX: + ut_ad(block->page.lock.have_s()); + break; + case MTR_MEMO_PAGE_X_FIX: case MTR_MEMO_PAGE_X_MODIFY: + ut_ad(block->page.lock.have_x()); + break; + case MTR_MEMO_PAGE_SX_FIX: case MTR_MEMO_PAGE_SX_MODIFY: + ut_ad(block->page.lock.have_u_or_x()); + break; + case MTR_MEMO_BUF_FIX: + break; + case MTR_MEMO_MODIFY: + case MTR_MEMO_S_LOCK: case MTR_MEMO_X_LOCK: case MTR_MEMO_SX_LOCK: + case MTR_MEMO_SPACE_X_LOCK: case MTR_MEMO_SPACE_S_LOCK: + ut_ad("invalid type" == 0); + } +#endif + if (!(type & MTR_MEMO_MODIFY)); + else if (block->page.id().space() >= SRV_TMP_SPACE_ID) + { + block->page.set_temp_modified(); + type= mtr_memo_type_t(type & ~MTR_MEMO_MODIFY); + } else - m_memo->emplace_back(mtr_memo_slot_t{object, type}); + { + m_modifications= true; + if (!m_made_dirty) + /* If we are going to modify a previously clean persistent page, + we must set m_made_dirty, so that commit() will acquire + log_sys.flush_order_mutex and insert the block into + buf_pool.flush_list. */ + m_made_dirty= block->page.oldest_modification() <= 1; + } + m_memo.emplace_back(mtr_memo_slot_t{block, type}); + } + + /** Push an index lock or tablespace latch to the memo. + @param object index lock or tablespace latch + @param type object type: MTR_MEMO_S_LOCK, ... */ + void memo_push(void *object, mtr_memo_type_t type) __attribute__((nonnull)) + { + ut_ad(is_active()); + ut_ad(type >= MTR_MEMO_S_LOCK); + m_memo.emplace_back(mtr_memo_slot_t{object, type}); } /** @return the size of the log is empty */ @@ -783,7 +745,7 @@ private: /** specifies which operations should be logged; default MTR_LOG_ALL */ uint16_t m_log_mode:2; - /** whether at least one buffer pool page was written to */ + /** whether at least one persistent page was written to */ uint16_t m_modifications:1; /** whether at least one previously clean buffer pool page was written to */ @@ -809,7 +771,7 @@ private: #endif /* UNIV_DEBUG */ /** acquired dict_index_t::lock, fil_space_t::latch, buf_block_t */ - std::vector<mtr_memo_slot_t> *m_memo= nullptr; + small_vector<mtr_memo_slot_t, 16> m_memo; /** mini-transaction log */ mtr_buf_t m_log; |