1/*****************************************************************************
2
3Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved.
4Copyright (c) 2017, 2018, 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/trx0undo.ic
22Transaction undo log
23
24Created 3/26/1996 Heikki Tuuri
25*******************************************************/
26
27#include "data0type.h"
28#include "page0page.h"
29
30/***********************************************************************//**
31Builds a roll pointer.
32@return roll pointer */
33UNIV_INLINE
34roll_ptr_t
35trx_undo_build_roll_ptr(
36/*====================*/
37	ibool	is_insert,	/*!< in: TRUE if insert undo log */
38	ulint	rseg_id,	/*!< in: rollback segment id */
39	ulint	page_no,	/*!< in: page number */
40	ulint	offset)		/*!< in: offset of the undo entry within page */
41{
42	roll_ptr_t	roll_ptr;
43	compile_time_assert(DATA_ROLL_PTR_LEN == 7);
44	ut_ad(is_insert == 0 || is_insert == 1);
45	ut_ad(rseg_id < TRX_SYS_N_RSEGS);
46	ut_ad(offset < 65536);
47
48	roll_ptr = (roll_ptr_t) is_insert << ROLL_PTR_INSERT_FLAG_POS
49		| (roll_ptr_t) rseg_id << ROLL_PTR_RSEG_ID_POS
50		| (roll_ptr_t) page_no << ROLL_PTR_PAGE_POS
51		| offset;
52	return(roll_ptr);
53}
54
55/***********************************************************************//**
56Decodes a roll pointer. */
57UNIV_INLINE
58void
59trx_undo_decode_roll_ptr(
60/*=====================*/
61	roll_ptr_t	roll_ptr,	/*!< in: roll pointer */
62	ibool*		is_insert,	/*!< out: TRUE if insert undo log */
63	ulint*		rseg_id,	/*!< out: rollback segment id */
64	ulint*		page_no,	/*!< out: page number */
65	ulint*		offset)		/*!< out: offset of the undo
66					entry within page */
67{
68	compile_time_assert(DATA_ROLL_PTR_LEN == 7);
69	ut_ad(roll_ptr < (1ULL << 56));
70	*offset = (ulint) roll_ptr & 0xFFFF;
71	roll_ptr >>= 16;
72	*page_no = (ulint) roll_ptr & 0xFFFFFFFF;
73	roll_ptr >>= 32;
74	*rseg_id = (ulint) roll_ptr & 0x7F;
75	roll_ptr >>= 7;
76	*is_insert = (ibool) roll_ptr; /* TRUE==1 */
77}
78
79/***********************************************************************//**
80Returns TRUE if the roll pointer is of the insert type.
81@return TRUE if insert undo log */
82UNIV_INLINE
83ibool
84trx_undo_roll_ptr_is_insert(
85/*========================*/
86	roll_ptr_t	roll_ptr)	/*!< in: roll pointer */
87{
88	compile_time_assert(DATA_ROLL_PTR_LEN == 7);
89	ut_ad(roll_ptr < (1ULL << (ROLL_PTR_INSERT_FLAG_POS + 1)));
90	return((ibool) (roll_ptr >> ROLL_PTR_INSERT_FLAG_POS));
91}
92
93/***********************************************************************//**
94Returns true if the record is of the insert type.
95@return true if the record was freshly inserted (not updated). */
96UNIV_INLINE
97bool
98trx_undo_trx_id_is_insert(
99/*======================*/
100	const byte*	trx_id)	/*!< in: DB_TRX_ID, followed by DB_ROLL_PTR */
101{
102	compile_time_assert(DATA_TRX_ID + 1 == DATA_ROLL_PTR);
103	return bool(trx_id[DATA_TRX_ID_LEN] >> 7);
104}
105
106/*****************************************************************//**
107Writes a roll ptr to an index page. In case that the size changes in
108some future version, this function should be used instead of
109mach_write_... */
110UNIV_INLINE
111void
112trx_write_roll_ptr(
113/*===============*/
114	byte*		ptr,		/*!< in: pointer to memory where
115					written */
116	roll_ptr_t	roll_ptr)	/*!< in: roll ptr */
117{
118	compile_time_assert(DATA_ROLL_PTR_LEN == 7);
119	mach_write_to_7(ptr, roll_ptr);
120}
121
122/*****************************************************************//**
123Reads a roll ptr from an index page. In case that the roll ptr size
124changes in some future version, this function should be used instead of
125mach_read_...
126@return roll ptr */
127UNIV_INLINE
128roll_ptr_t
129trx_read_roll_ptr(
130/*==============*/
131	const byte*	ptr)	/*!< in: pointer to memory from where to read */
132{
133	compile_time_assert(DATA_ROLL_PTR_LEN == 7);
134	return(mach_read_from_7(ptr));
135}
136
137/** Gets an undo log page and x-latches it.
138@param[in]	page_id		page id
139@param[in,out]	mtr		mini-transaction
140@return pointer to page x-latched */
141UNIV_INLINE
142page_t*
143trx_undo_page_get(const page_id_t page_id, mtr_t* mtr)
144{
145	buf_block_t*	block = buf_page_get(page_id, univ_page_size,
146					     RW_X_LATCH, mtr);
147
148	buf_block_dbg_add_level(block, SYNC_TRX_UNDO_PAGE);
149
150	return(buf_block_get_frame(block));
151}
152
153/** Gets an undo log page and s-latches it.
154@param[in]	page_id		page id
155@param[in,out]	mtr		mini-transaction
156@return pointer to page s-latched */
157UNIV_INLINE
158page_t*
159trx_undo_page_get_s_latched(const page_id_t page_id, mtr_t* mtr)
160{
161	buf_block_t*	block = buf_page_get(page_id, univ_page_size,
162					     RW_S_LATCH, mtr);
163
164	buf_block_dbg_add_level(block, SYNC_TRX_UNDO_PAGE);
165
166	return(buf_block_get_frame(block));
167}
168
169/** Determine the end offset of undo log records of an undo log page.
170@param[in]	undo_page	undo log page
171@param[in]	page_no		undo log header page number
172@param[in]	offset		undo log header offset
173@return end offset */
174inline
175uint16_t
176trx_undo_page_get_end(const page_t* undo_page, ulint page_no, ulint offset)
177{
178	if (page_no == page_get_page_no(undo_page)) {
179		if (uint16_t end = mach_read_from_2(TRX_UNDO_NEXT_LOG
180						    + offset + undo_page)) {
181			return end;
182		}
183	}
184
185	return mach_read_from_2(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE
186				+ undo_page);
187}
188
189/******************************************************************//**
190Returns the next undo log record on the page in the specified log, or
191NULL if none exists.
192@return pointer to record, NULL if none */
193UNIV_INLINE
194trx_undo_rec_t*
195trx_undo_page_get_next_rec(
196/*=======================*/
197	trx_undo_rec_t*	rec,	/*!< in: undo log record */
198	ulint		page_no,/*!< in: undo log header page number */
199	ulint		offset)	/*!< in: undo log header offset on page */
200{
201	page_t*	undo_page;
202	ulint	end;
203	ulint	next;
204
205	undo_page = (page_t*) ut_align_down(rec, srv_page_size);
206
207	end = trx_undo_page_get_end(undo_page, page_no, offset);
208
209	next = mach_read_from_2(rec);
210
211	if (next == end) {
212
213		return(NULL);
214	}
215
216	return(undo_page + next);
217}
218