1/*****************************************************************************
2
3Copyright (c) 1995, 2021, Oracle and/or its affiliates.
4
5This program is free software; you can redistribute it and/or modify
6it under the terms of the GNU General Public License, version 2.0,
7as published by the Free Software Foundation.
8
9This program is also distributed with certain software (including
10but not limited to OpenSSL) that is licensed under separate terms,
11as designated in a particular file or component or in included license
12documentation.  The authors of MySQL hereby grant you an additional
13permission to link the program and your derivative works with the
14separately licensed software that they have included with MySQL.
15
16This program is distributed in the hope that it will be useful,
17but WITHOUT ANY WARRANTY; without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19GNU General Public License, version 2.0, for more details.
20
21You should have received a copy of the GNU General Public License along with
22this program; if not, write to the Free Software Foundation, Inc.,
2351 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
24
25*****************************************************************************/
26
27/**************************************************//**
28@file include/mtr0mtr.ic
29Mini-transaction buffer
30
31Created 11/26/1995 Heikki Tuuri
32*******************************************************/
33
34#include "buf0buf.h"
35
36/**
37Pushes an object to an mtr memo stack. */
38void
39mtr_t::memo_push(void* object, mtr_memo_type_t type)
40{
41	ut_ad(is_active());
42	ut_ad(object != NULL);
43	ut_ad(type >= MTR_MEMO_PAGE_S_FIX);
44	ut_ad(type <= MTR_MEMO_SX_LOCK);
45	ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
46	ut_ad(ut_is_2pow(type));
47
48	/* If this mtr has x-fixed a clean page then we set
49	the made_dirty flag. This tells us if we need to
50	grab log_flush_order_mutex at mtr_commit so that we
51	can insert the dirtied page to the flush list. */
52
53	if ((type == MTR_MEMO_PAGE_X_FIX || type == MTR_MEMO_PAGE_SX_FIX)
54	    && !m_impl.m_made_dirty) {
55
56		m_impl.m_made_dirty = is_block_dirtied(
57			reinterpret_cast<const buf_block_t*>(object));
58	} else if (type == MTR_MEMO_BUF_FIX && !m_impl.m_made_dirty) {
59
60		if (reinterpret_cast<const buf_block_t*>(
61			object)->made_dirty_with_no_latch) {
62
63			m_impl.m_made_dirty = true;
64		}
65	}
66
67	mtr_memo_slot_t*	slot;
68
69	slot = m_impl.m_memo.push<mtr_memo_slot_t*>(sizeof(*slot));
70
71	slot->type = type;
72	slot->object = object;
73}
74
75/**
76Releases the (index tree) s-latch stored in an mtr memo after a
77savepoint. */
78void
79mtr_t::release_s_latch_at_savepoint(
80	ulint		savepoint,
81	rw_lock_t*	lock)
82{
83	ut_ad(is_active());
84	ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
85
86	ut_ad(m_impl.m_memo.size() > savepoint);
87
88	mtr_memo_slot_t* slot = m_impl.m_memo.at<mtr_memo_slot_t*>(savepoint);
89
90	ut_ad(slot->object == lock);
91	ut_ad(slot->type == MTR_MEMO_S_LOCK);
92
93	rw_lock_s_unlock(lock);
94
95	slot->object = NULL;
96}
97
98/**
99SX-latches the not yet latched block after a savepoint. */
100
101void
102mtr_t::sx_latch_at_savepoint(
103	ulint		savepoint,
104	buf_block_t*	block)
105{
106	ut_ad(is_active());
107	ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
108	ut_ad(m_impl.m_memo.size() > savepoint);
109
110	ut_ad(!memo_contains_flagged(
111			block,
112			MTR_MEMO_PAGE_S_FIX
113			| MTR_MEMO_PAGE_X_FIX
114			| MTR_MEMO_PAGE_SX_FIX));
115
116	mtr_memo_slot_t*	slot;
117
118	slot = m_impl.m_memo.at<mtr_memo_slot_t*>(savepoint);
119
120	ut_ad(slot->object == block);
121
122	/* == RW_NO_LATCH */
123	ut_a(slot->type == MTR_MEMO_BUF_FIX);
124
125	rw_lock_sx_lock(&block->lock);
126
127	if (!m_impl.m_made_dirty) {
128		m_impl.m_made_dirty = is_block_dirtied(block);
129	}
130
131	slot->type = MTR_MEMO_PAGE_SX_FIX;
132}
133
134/**
135X-latches the not yet latched block after a savepoint. */
136
137void
138mtr_t::x_latch_at_savepoint(
139	ulint		savepoint,
140	buf_block_t*	block)
141{
142	ut_ad(is_active());
143	ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
144	ut_ad(m_impl.m_memo.size() > savepoint);
145
146	ut_ad(!memo_contains_flagged(
147			block,
148			MTR_MEMO_PAGE_S_FIX
149			| MTR_MEMO_PAGE_X_FIX
150			| MTR_MEMO_PAGE_SX_FIX));
151
152	mtr_memo_slot_t*	slot;
153
154	slot = m_impl.m_memo.at<mtr_memo_slot_t*>(savepoint);
155
156	ut_ad(slot->object == block);
157
158	/* == RW_NO_LATCH */
159	ut_a(slot->type == MTR_MEMO_BUF_FIX);
160
161	rw_lock_x_lock(&block->lock);
162
163	if (!m_impl.m_made_dirty) {
164		m_impl.m_made_dirty = is_block_dirtied(block);
165	}
166
167	slot->type = MTR_MEMO_PAGE_X_FIX;
168}
169
170/**
171Releases the block in an mtr memo after a savepoint. */
172
173void
174mtr_t::release_block_at_savepoint(
175	ulint		savepoint,
176	buf_block_t*	block)
177{
178	ut_ad(is_active());
179	ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
180
181	mtr_memo_slot_t*	slot;
182
183	slot = m_impl.m_memo.at<mtr_memo_slot_t*>(savepoint);
184
185	ut_a(slot->object == block);
186
187	buf_page_release_latch(block, slot->type);
188	buf_block_unfix(block);
189
190	slot->object = NULL;
191}
192
193/**
194Gets the logging mode of a mini-transaction.
195@return	logging mode: MTR_LOG_NONE, ... */
196
197mtr_log_t
198mtr_t::get_log_mode() const
199{
200	ut_ad(m_impl.m_log_mode >= MTR_LOG_ALL);
201	ut_ad(m_impl.m_log_mode <= MTR_LOG_SHORT_INSERTS);
202
203	return(m_impl.m_log_mode);
204}
205
206/**
207Changes the logging mode of a mini-transaction.
208@return	old mode */
209
210mtr_log_t
211mtr_t::set_log_mode(mtr_log_t mode)
212{
213	ut_ad(mode >= MTR_LOG_ALL);
214	ut_ad(mode <= MTR_LOG_SHORT_INSERTS);
215
216	const mtr_log_t	old_mode = m_impl.m_log_mode;
217
218	switch (old_mode) {
219	case MTR_LOG_NO_REDO:
220		/* Once this mode is set, it must not be changed. */
221		ut_ad(mode == MTR_LOG_NO_REDO || mode == MTR_LOG_NONE);
222		return(old_mode);
223	case MTR_LOG_NONE:
224		if (mode == old_mode || mode == MTR_LOG_SHORT_INSERTS) {
225			/* Keep MTR_LOG_NONE. */
226			return(old_mode);
227		}
228		/* fall through */
229	case MTR_LOG_SHORT_INSERTS:
230		ut_ad(mode == MTR_LOG_ALL);
231		/* fall through */
232	case MTR_LOG_ALL:
233		/* MTR_LOG_NO_REDO can only be set before generating
234		any redo log records. */
235		ut_ad(mode != MTR_LOG_NO_REDO
236		      || m_impl.m_n_log_recs == 0);
237		m_impl.m_log_mode = mode;
238		return(old_mode);
239	}
240
241	ut_ad(0);
242	return(old_mode);
243}
244
245/**
246Locks a lock in s-mode. */
247
248void
249mtr_t::s_lock(rw_lock_t* lock, const char* file, ulint line)
250{
251	rw_lock_s_lock_inline(lock, 0, file, line);
252
253	memo_push(lock, MTR_MEMO_S_LOCK);
254}
255
256/**
257Locks a lock in x-mode. */
258
259void
260mtr_t::x_lock(rw_lock_t* lock, const char* file, ulint line)
261{
262	rw_lock_x_lock_inline(lock, 0, file, line);
263
264	memo_push(lock, MTR_MEMO_X_LOCK);
265}
266
267/**
268Locks a lock in sx-mode. */
269
270void
271mtr_t::sx_lock(rw_lock_t* lock, const char* file, ulint line)
272{
273	rw_lock_sx_lock_inline(lock, 0, file, line);
274
275	memo_push(lock, MTR_MEMO_SX_LOCK);
276}
277
278/**
279Reads 1 - 4 bytes from a file page buffered in the buffer pool.
280@return	value read */
281
282ulint
283mtr_t::read_ulint(const byte* ptr, mlog_id_t type) const
284{
285	ut_ad(is_active());
286
287	ut_ad(memo_contains_page_flagged(
288			ptr,
289			MTR_MEMO_PAGE_S_FIX
290			| MTR_MEMO_PAGE_X_FIX
291			| MTR_MEMO_PAGE_SX_FIX));
292
293	return(mach_read_ulint(ptr, type));
294}
295