1/***************************************************************************** 2 3Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved. 4Copyright (c) 2017, 2021, MariaDB Corporation. 5 6This program is free software; you can redistribute it and/or modify it under 7the terms of the GNU General Public License as published by the Free Software 8Foundation; version 2 of the License. 9 10This program is distributed in the hope that it will be useful, but WITHOUT 11ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 13 14You should have received a copy of the GNU General Public License along with 15this program; if not, write to the Free Software Foundation, Inc., 1651 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA 17 18*****************************************************************************/ 19 20/**************************************************//** 21@file include/mtr0mtr.ic 22Mini-transaction buffer 23 24Created 11/26/1995 Heikki Tuuri 25*******************************************************/ 26 27#include "buf0buf.h" 28 29/** Check if a mini-transaction is dirtying a clean page. 30@return true if the mtr is dirtying a clean page. */ 31bool 32mtr_t::is_block_dirtied(const buf_block_t* block) 33{ 34 ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); 35 ut_ad(block->page.buf_fix_count > 0); 36 37 /* It is OK to read oldest_modification because no 38 other thread can be performing a write of it and it 39 is only during write that the value is reset to 0. */ 40 return(block->page.oldest_modification == 0); 41} 42 43/** 44Pushes an object to an mtr memo stack. */ 45void 46mtr_t::memo_push(void* object, mtr_memo_type_t type) 47{ 48 ut_ad(is_active()); 49 ut_ad(object != NULL); 50 ut_ad(type >= MTR_MEMO_PAGE_S_FIX); 51 ut_ad(type <= MTR_MEMO_SPACE_X_LOCK); 52 ut_ad(ut_is_2pow(type)); 53 54 /* If this mtr has x-fixed a clean page then we set 55 the made_dirty flag. This tells us if we need to 56 grab log_sys.flush_order_mutex at mtr_t::commit() so that we 57 can insert the dirtied page into the flush list. */ 58 59 if ((type == MTR_MEMO_PAGE_X_FIX || type == MTR_MEMO_PAGE_SX_FIX) 60 && !m_made_dirty) { 61 62 m_made_dirty = is_block_dirtied( 63 reinterpret_cast<const buf_block_t*>(object)); 64 } 65 66 mtr_memo_slot_t* slot = m_memo.push<mtr_memo_slot_t*>(sizeof(*slot)); 67 68 slot->type = type; 69 slot->object = object; 70} 71 72/** 73Releases the (index tree) s-latch stored in an mtr memo after a 74savepoint. */ 75void 76mtr_t::release_s_latch_at_savepoint( 77 ulint savepoint, 78 rw_lock_t* lock) 79{ 80 ut_ad(is_active()); 81 ut_ad(m_memo.size() > savepoint); 82 83 mtr_memo_slot_t* slot = m_memo.at<mtr_memo_slot_t*>(savepoint); 84 85 ut_ad(slot->object == lock); 86 ut_ad(slot->type == MTR_MEMO_S_LOCK); 87 88 rw_lock_s_unlock(lock); 89 90 slot->object = NULL; 91} 92 93/** 94SX-latches the not yet latched block after a savepoint. */ 95 96void 97mtr_t::sx_latch_at_savepoint( 98 ulint savepoint, 99 buf_block_t* block) 100{ 101 ut_ad(is_active()); 102 ut_ad(m_memo.size() > savepoint); 103 104 ut_ad(!memo_contains_flagged( 105 block, 106 MTR_MEMO_PAGE_S_FIX 107 | MTR_MEMO_PAGE_X_FIX 108 | MTR_MEMO_PAGE_SX_FIX)); 109 110 mtr_memo_slot_t* slot = m_memo.at<mtr_memo_slot_t*>(savepoint); 111 112 ut_ad(slot->object == block); 113 114 /* == RW_NO_LATCH */ 115 ut_a(slot->type == MTR_MEMO_BUF_FIX); 116 117 rw_lock_sx_lock(&block->lock); 118 119 if (!m_made_dirty) { 120 m_made_dirty = is_block_dirtied(block); 121 } 122 123 slot->type = MTR_MEMO_PAGE_SX_FIX; 124} 125 126/** 127X-latches the not yet latched block after a savepoint. */ 128 129void 130mtr_t::x_latch_at_savepoint( 131 ulint savepoint, 132 buf_block_t* block) 133{ 134 ut_ad(is_active()); 135 ut_ad(m_memo.size() > savepoint); 136 137 ut_ad(!memo_contains_flagged( 138 block, 139 MTR_MEMO_PAGE_S_FIX 140 | MTR_MEMO_PAGE_X_FIX 141 | MTR_MEMO_PAGE_SX_FIX)); 142 143 mtr_memo_slot_t* slot = m_memo.at<mtr_memo_slot_t*>(savepoint); 144 145 ut_ad(slot->object == block); 146 147 /* == RW_NO_LATCH */ 148 ut_a(slot->type == MTR_MEMO_BUF_FIX); 149 150 rw_lock_x_lock(&block->lock); 151 152 if (!m_made_dirty) { 153 m_made_dirty = is_block_dirtied(block); 154 } 155 156 slot->type = MTR_MEMO_PAGE_X_FIX; 157} 158 159/** 160Releases the block in an mtr memo after a savepoint. */ 161 162void 163mtr_t::release_block_at_savepoint( 164 ulint savepoint, 165 buf_block_t* block) 166{ 167 ut_ad(is_active()); 168 169 mtr_memo_slot_t* slot = m_memo.at<mtr_memo_slot_t*>(savepoint); 170 171 ut_a(slot->object == block); 172 173 buf_page_release_latch(block, slot->type); 174 175 reinterpret_cast<buf_block_t*>(block)->unfix(); 176 177 slot->object = NULL; 178} 179 180/** 181Gets the logging mode of a mini-transaction. 182@return logging mode: MTR_LOG_NONE, ... */ 183 184mtr_log_t 185mtr_t::get_log_mode() const 186{ 187 ut_ad(m_log_mode >= MTR_LOG_ALL); 188 ut_ad(m_log_mode <= MTR_LOG_SHORT_INSERTS); 189 190 return m_log_mode; 191} 192 193/** 194Changes the logging mode of a mini-transaction. 195@return old mode */ 196 197mtr_log_t 198mtr_t::set_log_mode(mtr_log_t mode) 199{ 200 ut_ad(mode >= MTR_LOG_ALL); 201 ut_ad(mode <= MTR_LOG_SHORT_INSERTS); 202 203 const mtr_log_t old_mode = m_log_mode; 204 205 switch (old_mode) { 206 case MTR_LOG_NO_REDO: 207 /* Once this mode is set, it must not be changed. */ 208 ut_ad(mode == MTR_LOG_NO_REDO || mode == MTR_LOG_NONE); 209 return(old_mode); 210 case MTR_LOG_NONE: 211 if (mode == old_mode || mode == MTR_LOG_SHORT_INSERTS) { 212 /* Keep MTR_LOG_NONE. */ 213 return(old_mode); 214 } 215 /* fall through */ 216 case MTR_LOG_SHORT_INSERTS: 217 ut_ad(mode == MTR_LOG_ALL); 218 /* fall through */ 219 case MTR_LOG_ALL: 220 /* MTR_LOG_NO_REDO can only be set before generating 221 any redo log records. */ 222 ut_ad(mode != MTR_LOG_NO_REDO || m_n_log_recs == 0); 223 m_log_mode = mode; 224 return(old_mode); 225 } 226 227 ut_ad(0); 228 return(old_mode); 229} 230