/***************************************************************************** Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved. 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 Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA *****************************************************************************/ /**************************************************//** @file include/mtr0mtr.ic Mini-transaction buffer Created 11/26/1995 Heikki Tuuri *******************************************************/ #include "buf0buf.h" /** Pushes an object to an mtr memo stack. */ void mtr_t::memo_push(void* object, mtr_memo_type_t type) { ut_ad(is_active()); ut_ad(object != NULL); ut_ad(type >= MTR_MEMO_PAGE_S_FIX); ut_ad(type <= MTR_MEMO_SX_LOCK); ut_ad(m_impl.m_magic_n == MTR_MAGIC_N); ut_ad(ut_is_2pow(type)); /* If this mtr has x-fixed a clean page then we set the made_dirty flag. This tells us if we need to grab log_flush_order_mutex at mtr_commit so that we can insert the dirtied page to the flush list. */ if ((type == MTR_MEMO_PAGE_X_FIX || type == MTR_MEMO_PAGE_SX_FIX) && !m_impl.m_made_dirty) { m_impl.m_made_dirty = is_block_dirtied( reinterpret_cast(object)); } mtr_memo_slot_t* slot; slot = m_impl.m_memo.push(sizeof(*slot)); slot->type = type; slot->object = object; } /** Releases the (index tree) s-latch stored in an mtr memo after a savepoint. */ void mtr_t::release_s_latch_at_savepoint( ulint savepoint, rw_lock_t* lock) { ut_ad(is_active()); ut_ad(m_impl.m_magic_n == MTR_MAGIC_N); ut_ad(m_impl.m_memo.size() > savepoint); mtr_memo_slot_t* slot = m_impl.m_memo.at(savepoint); ut_ad(slot->object == lock); ut_ad(slot->type == MTR_MEMO_S_LOCK); rw_lock_s_unlock(lock); slot->object = NULL; } /** SX-latches the not yet latched block after a savepoint. */ void mtr_t::sx_latch_at_savepoint( ulint savepoint, buf_block_t* block) { ut_ad(is_active()); ut_ad(m_impl.m_magic_n == MTR_MAGIC_N); ut_ad(m_impl.m_memo.size() > savepoint); 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; slot = m_impl.m_memo.at(savepoint); ut_ad(slot->object == block); /* == RW_NO_LATCH */ ut_a(slot->type == MTR_MEMO_BUF_FIX); rw_lock_sx_lock(&block->lock); if (!m_impl.m_made_dirty) { m_impl.m_made_dirty = is_block_dirtied(block); } slot->type = MTR_MEMO_PAGE_SX_FIX; } /** X-latches the not yet latched block after a savepoint. */ void mtr_t::x_latch_at_savepoint( ulint savepoint, buf_block_t* block) { ut_ad(is_active()); ut_ad(m_impl.m_magic_n == MTR_MAGIC_N); ut_ad(m_impl.m_memo.size() > savepoint); 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; slot = m_impl.m_memo.at(savepoint); ut_ad(slot->object == block); /* == RW_NO_LATCH */ ut_a(slot->type == MTR_MEMO_BUF_FIX); rw_lock_x_lock(&block->lock); if (!m_impl.m_made_dirty) { m_impl.m_made_dirty = is_block_dirtied(block); } slot->type = MTR_MEMO_PAGE_X_FIX; } /** Releases the block in an mtr memo after a savepoint. */ void mtr_t::release_block_at_savepoint( ulint savepoint, buf_block_t* block) { ut_ad(is_active()); ut_ad(m_impl.m_magic_n == MTR_MAGIC_N); mtr_memo_slot_t* slot; slot = m_impl.m_memo.at(savepoint); ut_a(slot->object == block); buf_block_unfix(reinterpret_cast(block)); buf_page_release_latch(block, slot->type); slot->object = NULL; } /** Gets the logging mode of a mini-transaction. @return logging mode: MTR_LOG_NONE, ... */ mtr_log_t mtr_t::get_log_mode() const { ut_ad(m_impl.m_log_mode >= MTR_LOG_ALL); ut_ad(m_impl.m_log_mode <= MTR_LOG_SHORT_INSERTS); return(m_impl.m_log_mode); } /** Changes the logging mode of a mini-transaction. @return old mode */ mtr_log_t mtr_t::set_log_mode(mtr_log_t mode) { ut_ad(mode >= MTR_LOG_ALL); ut_ad(mode <= MTR_LOG_SHORT_INSERTS); const mtr_log_t old_mode = m_impl.m_log_mode; switch (old_mode) { case MTR_LOG_NO_REDO: /* Once this mode is set, it must not be changed. */ ut_ad(mode == MTR_LOG_NO_REDO || mode == MTR_LOG_NONE); return(old_mode); case MTR_LOG_NONE: if (mode == old_mode || mode == MTR_LOG_SHORT_INSERTS) { /* Keep MTR_LOG_NONE. */ return(old_mode); } /* fall through */ case MTR_LOG_SHORT_INSERTS: ut_ad(mode == MTR_LOG_ALL); /* fall through */ case MTR_LOG_ALL: /* MTR_LOG_NO_REDO can only be set before generating any redo log records. */ ut_ad(mode != MTR_LOG_NO_REDO || m_impl.m_n_log_recs == 0); m_impl.m_log_mode = mode; return(old_mode); } ut_ad(0); return(old_mode); } /** Locks a lock in s-mode. */ void mtr_t::s_lock(rw_lock_t* lock, const char* file, ulint line) { rw_lock_s_lock_inline(lock, 0, file, line); memo_push(lock, MTR_MEMO_S_LOCK); } /** Locks a lock in x-mode. */ void mtr_t::x_lock(rw_lock_t* lock, const char* file, ulint line) { rw_lock_x_lock_inline(lock, 0, file, line); memo_push(lock, MTR_MEMO_X_LOCK); } /** Locks a lock in sx-mode. */ void mtr_t::sx_lock(rw_lock_t* lock, const char* file, ulint line) { rw_lock_sx_lock_inline(lock, 0, file, line); memo_push(lock, MTR_MEMO_SX_LOCK); } /** Reads 1 - 4 bytes from a file page buffered in the buffer pool. @return value read */ ulint mtr_t::read_ulint(const byte* ptr, mlog_id_t type) const { ut_ad(is_active()); ut_ad(memo_contains_page_flagged( ptr, MTR_MEMO_PAGE_S_FIX | MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX)); return(mach_read_ulint(ptr, type)); }