1/*****************************************************************************
2
3Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved.
4Copyright (c) 2017, 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, Suite 500, 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/**
30Pushes an object to an mtr memo stack. */
31void
32mtr_t::memo_push(void* object, mtr_memo_type_t type)
33{
34 ut_ad(is_active());
35 ut_ad(object != NULL);
36 ut_ad(type >= MTR_MEMO_PAGE_S_FIX);
37 ut_ad(type <= MTR_MEMO_SX_LOCK);
38 ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
39 ut_ad(ut_is_2pow(type));
40
41 /* If this mtr has x-fixed a clean page then we set
42 the made_dirty flag. This tells us if we need to
43 grab log_flush_order_mutex at mtr_commit so that we
44 can insert the dirtied page to the flush list. */
45
46 if ((type == MTR_MEMO_PAGE_X_FIX || type == MTR_MEMO_PAGE_SX_FIX)
47 && !m_impl.m_made_dirty) {
48
49 m_impl.m_made_dirty = is_block_dirtied(
50 reinterpret_cast<const buf_block_t*>(object));
51 }
52
53 mtr_memo_slot_t* slot;
54
55 slot = m_impl.m_memo.push<mtr_memo_slot_t*>(sizeof(*slot));
56
57 slot->type = type;
58 slot->object = object;
59}
60
61/**
62Releases the (index tree) s-latch stored in an mtr memo after a
63savepoint. */
64void
65mtr_t::release_s_latch_at_savepoint(
66 ulint savepoint,
67 rw_lock_t* lock)
68{
69 ut_ad(is_active());
70 ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
71
72 ut_ad(m_impl.m_memo.size() > savepoint);
73
74 mtr_memo_slot_t* slot = m_impl.m_memo.at<mtr_memo_slot_t*>(savepoint);
75
76 ut_ad(slot->object == lock);
77 ut_ad(slot->type == MTR_MEMO_S_LOCK);
78
79 rw_lock_s_unlock(lock);
80
81 slot->object = NULL;
82}
83
84/**
85SX-latches the not yet latched block after a savepoint. */
86
87void
88mtr_t::sx_latch_at_savepoint(
89 ulint savepoint,
90 buf_block_t* block)
91{
92 ut_ad(is_active());
93 ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
94 ut_ad(m_impl.m_memo.size() > savepoint);
95
96 ut_ad(!memo_contains_flagged(
97 block,
98 MTR_MEMO_PAGE_S_FIX
99 | MTR_MEMO_PAGE_X_FIX
100 | MTR_MEMO_PAGE_SX_FIX));
101
102 mtr_memo_slot_t* slot;
103
104 slot = m_impl.m_memo.at<mtr_memo_slot_t*>(savepoint);
105
106 ut_ad(slot->object == block);
107
108 /* == RW_NO_LATCH */
109 ut_a(slot->type == MTR_MEMO_BUF_FIX);
110
111 rw_lock_sx_lock(&block->lock);
112
113 if (!m_impl.m_made_dirty) {
114 m_impl.m_made_dirty = is_block_dirtied(block);
115 }
116
117 slot->type = MTR_MEMO_PAGE_SX_FIX;
118}
119
120/**
121X-latches the not yet latched block after a savepoint. */
122
123void
124mtr_t::x_latch_at_savepoint(
125 ulint savepoint,
126 buf_block_t* block)
127{
128 ut_ad(is_active());
129 ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
130 ut_ad(m_impl.m_memo.size() > savepoint);
131
132 ut_ad(!memo_contains_flagged(
133 block,
134 MTR_MEMO_PAGE_S_FIX
135 | MTR_MEMO_PAGE_X_FIX
136 | MTR_MEMO_PAGE_SX_FIX));
137
138 mtr_memo_slot_t* slot;
139
140 slot = m_impl.m_memo.at<mtr_memo_slot_t*>(savepoint);
141
142 ut_ad(slot->object == block);
143
144 /* == RW_NO_LATCH */
145 ut_a(slot->type == MTR_MEMO_BUF_FIX);
146
147 rw_lock_x_lock(&block->lock);
148
149 if (!m_impl.m_made_dirty) {
150 m_impl.m_made_dirty = is_block_dirtied(block);
151 }
152
153 slot->type = MTR_MEMO_PAGE_X_FIX;
154}
155
156/**
157Releases the block in an mtr memo after a savepoint. */
158
159void
160mtr_t::release_block_at_savepoint(
161 ulint savepoint,
162 buf_block_t* block)
163{
164 ut_ad(is_active());
165 ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
166
167 mtr_memo_slot_t* slot;
168
169 slot = m_impl.m_memo.at<mtr_memo_slot_t*>(savepoint);
170
171 ut_a(slot->object == block);
172
173 buf_block_unfix(reinterpret_cast<buf_block_t*>(block));
174
175 buf_page_release_latch(block, slot->type);
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_impl.m_log_mode >= MTR_LOG_ALL);
188 ut_ad(m_impl.m_log_mode <= MTR_LOG_SHORT_INSERTS);
189
190 return(m_impl.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_impl.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
223 || m_impl.m_n_log_recs == 0);
224 m_impl.m_log_mode = mode;
225 return(old_mode);
226 }
227
228 ut_ad(0);
229 return(old_mode);
230}
231
232/**
233Locks a lock in s-mode. */
234
235void
236mtr_t::s_lock(rw_lock_t* lock, const char* file, unsigned line)
237{
238 rw_lock_s_lock_inline(lock, 0, file, line);
239
240 memo_push(lock, MTR_MEMO_S_LOCK);
241}
242
243/**
244Locks a lock in x-mode. */
245
246void
247mtr_t::x_lock(rw_lock_t* lock, const char* file, unsigned line)
248{
249 rw_lock_x_lock_inline(lock, 0, file, line);
250
251 memo_push(lock, MTR_MEMO_X_LOCK);
252}
253
254/**
255Locks a lock in sx-mode. */
256
257void
258mtr_t::sx_lock(rw_lock_t* lock, const char* file, unsigned line)
259{
260 rw_lock_sx_lock_inline(lock, 0, file, line);
261
262 memo_push(lock, MTR_MEMO_SX_LOCK);
263}
264
265/**
266Reads 1 - 4 bytes from a file page buffered in the buffer pool.
267@return value read */
268
269ulint
270mtr_t::read_ulint(const byte* ptr, mlog_id_t type) const
271{
272 ut_ad(is_active());
273
274 ut_ad(memo_contains_page_flagged(
275 ptr,
276 MTR_MEMO_PAGE_S_FIX
277 | MTR_MEMO_PAGE_X_FIX
278 | MTR_MEMO_PAGE_SX_FIX));
279
280 return(mach_read_ulint(ptr, type));
281}
282