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