/***************************************************************************** Copyright (c) 1995, 2012, 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 *******************************************************/ #ifndef UNIV_HOTBACKUP # include "sync0sync.h" # include "sync0rw.h" #endif /* !UNIV_HOTBACKUP */ #include "mach0data.h" /***************************************************//** Checks if a mini-transaction is dirtying a clean page. @return TRUE if the mtr is dirtying a clean page. */ UNIV_INTERN ibool mtr_block_dirtied( /*==============*/ const buf_block_t* block) /*!< in: block being x-fixed */ __attribute__((nonnull,warn_unused_result)); /***************************************************************//** Starts a mini-transaction. */ UNIV_INLINE void mtr_start( /*======*/ mtr_t* mtr) /*!< out: mini-transaction */ { UNIV_MEM_INVALID(mtr, sizeof *mtr); dyn_array_create(&(mtr->memo)); dyn_array_create(&(mtr->log)); mtr->log_mode = MTR_LOG_ALL; mtr->modifications = FALSE; mtr->inside_ibuf = FALSE; mtr->n_log_recs = 0; mtr->n_freed_pages = 0; mtr->made_dirty = FALSE; ut_d(mtr->state = MTR_ACTIVE); ut_d(mtr->magic_n = MTR_MAGIC_N); } /***************************************************//** Pushes an object to an mtr memo stack. */ UNIV_INLINE void mtr_memo_push( /*==========*/ mtr_t* mtr, /*!< in: mtr */ void* object, /*!< in: object */ ulint type) /*!< in: object type: MTR_MEMO_S_LOCK, ... */ { dyn_array_t* memo; mtr_memo_slot_t* slot; /* 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 && !mtr->made_dirty) { mtr->made_dirty = mtr_block_dirtied((const buf_block_t *)object); } ut_ad(object); ut_ad(type >= MTR_MEMO_PAGE_S_FIX); ut_ad(type <= MTR_MEMO_X_LOCK); ut_ad(mtr); ut_ad(mtr->magic_n == MTR_MAGIC_N); ut_ad(mtr->state == MTR_ACTIVE); memo = &(mtr->memo); slot = (mtr_memo_slot_t*) dyn_array_push(memo, sizeof *slot); slot->object = object; slot->type = type; } /**********************************************************//** Sets and returns a savepoint in mtr. @return savepoint */ UNIV_INLINE ulint mtr_set_savepoint( /*==============*/ mtr_t* mtr) /*!< in: mtr */ { dyn_array_t* memo; ut_ad(mtr); ut_ad(mtr->magic_n == MTR_MAGIC_N); ut_ad(mtr->state == MTR_ACTIVE); memo = &(mtr->memo); return(dyn_array_get_data_size(memo)); } #ifndef UNIV_HOTBACKUP /**********************************************************//** Releases the (index tree) s-latch stored in an mtr memo after a savepoint. */ UNIV_INLINE void mtr_release_s_latch_at_savepoint( /*=============================*/ mtr_t* mtr, /*!< in: mtr */ ulint savepoint, /*!< in: savepoint */ rw_lock_t* lock) /*!< in: latch to release */ { mtr_memo_slot_t* slot; dyn_array_t* memo; ut_ad(mtr); ut_ad(mtr->magic_n == MTR_MAGIC_N); ut_ad(mtr->state == MTR_ACTIVE); memo = &(mtr->memo); ut_ad(dyn_array_get_data_size(memo) > savepoint); slot = (mtr_memo_slot_t*) dyn_array_get_element(memo, savepoint); ut_ad(slot->object == lock); ut_ad(slot->type == MTR_MEMO_S_LOCK); rw_lock_s_unlock(lock); slot->object = NULL; } # ifdef UNIV_DEBUG /**********************************************************//** Checks if memo contains the given item. @return TRUE if contains */ UNIV_INLINE ibool mtr_memo_contains( /*==============*/ mtr_t* mtr, /*!< in: mtr */ const void* object, /*!< in: object to search */ ulint type) /*!< in: type of object */ { mtr_memo_slot_t* slot; dyn_array_t* memo; ulint offset; ut_ad(mtr->magic_n == MTR_MAGIC_N); ut_ad(mtr->state == MTR_ACTIVE || mtr->state == MTR_COMMITTING); memo = &(mtr->memo); offset = dyn_array_get_data_size(memo); while (offset > 0) { offset -= sizeof(mtr_memo_slot_t); slot = (mtr_memo_slot_t*) dyn_array_get_element(memo, offset); if ((object == slot->object) && (type == slot->type)) { return(TRUE); } } return(FALSE); } # endif /* UNIV_DEBUG */ #endif /* !UNIV_HOTBACKUP */ /***************************************************************//** Returns the log object of a mini-transaction buffer. @return log */ UNIV_INLINE dyn_array_t* mtr_get_log( /*========*/ mtr_t* mtr) /*!< in: mini-transaction */ { ut_ad(mtr); ut_ad(mtr->magic_n == MTR_MAGIC_N); return(&(mtr->log)); } /***************************************************************//** Gets the logging mode of a mini-transaction. @return logging mode: MTR_LOG_NONE, ... */ UNIV_INLINE ulint mtr_get_log_mode( /*=============*/ mtr_t* mtr) /*!< in: mtr */ { ut_ad(mtr); ut_ad(mtr->log_mode >= MTR_LOG_ALL); ut_ad(mtr->log_mode <= MTR_LOG_SHORT_INSERTS); return(mtr->log_mode); } /***************************************************************//** Changes the logging mode of a mini-transaction. @return old mode */ UNIV_INLINE ulint mtr_set_log_mode( /*=============*/ mtr_t* mtr, /*!< in: mtr */ ulint mode) /*!< in: logging mode: MTR_LOG_NONE, ... */ { ulint old_mode; ut_ad(mtr); ut_ad(mode >= MTR_LOG_ALL); ut_ad(mode <= MTR_LOG_SHORT_INSERTS); old_mode = mtr->log_mode; if ((mode == MTR_LOG_SHORT_INSERTS) && (old_mode == MTR_LOG_NONE)) { /* Do nothing */ } else { mtr->log_mode = mode; } ut_ad(old_mode >= MTR_LOG_ALL); ut_ad(old_mode <= MTR_LOG_SHORT_INSERTS); return(old_mode); } #ifndef UNIV_HOTBACKUP /*********************************************************************//** Locks a lock in s-mode. */ UNIV_INLINE void mtr_s_lock_func( /*============*/ rw_lock_t* lock, /*!< in: rw-lock */ const char* file, /*!< in: file name */ ulint line, /*!< in: line number */ mtr_t* mtr) /*!< in: mtr */ { ut_ad(mtr); ut_ad(lock); rw_lock_s_lock_inline(lock, 0, file, line); mtr_memo_push(mtr, lock, MTR_MEMO_S_LOCK); } /*********************************************************************//** Locks a lock in x-mode. */ UNIV_INLINE void mtr_x_lock_func( /*============*/ rw_lock_t* lock, /*!< in: rw-lock */ const char* file, /*!< in: file name */ ulint line, /*!< in: line number */ mtr_t* mtr) /*!< in: mtr */ { ut_ad(mtr); ut_ad(lock); rw_lock_x_lock_inline(lock, 0, file, line); mtr_memo_push(mtr, lock, MTR_MEMO_X_LOCK); } #endif /* !UNIV_HOTBACKUP */