1/*****************************************************************************
2
3Copyright (c) 1996, 2009, Oracle and/or its affiliates. All Rights Reserved.
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/trx0undo.ic
29Transaction undo log
30
31Created 3/26/1996 Heikki Tuuri
32*******************************************************/
33
34#include "data0type.h"
35#include "page0page.h"
36
37#ifndef UNIV_HOTBACKUP
38/***********************************************************************//**
39Builds a roll pointer.
40@return	roll pointer */
41UNIV_INLINE
42roll_ptr_t
43trx_undo_build_roll_ptr(
44/*====================*/
45	ibool	is_insert,	/*!< in: TRUE if insert undo log */
46	ulint	rseg_id,	/*!< in: rollback segment id */
47	ulint	page_no,	/*!< in: page number */
48	ulint	offset)		/*!< in: offset of the undo entry within page */
49{
50	roll_ptr_t	roll_ptr;
51#if DATA_ROLL_PTR_LEN != 7
52# error "DATA_ROLL_PTR_LEN != 7"
53#endif
54	ut_ad(is_insert == 0 || is_insert == 1);
55	ut_ad(rseg_id < TRX_SYS_N_RSEGS);
56	ut_ad(offset < 65536);
57
58	roll_ptr = (roll_ptr_t) is_insert << 55
59		| (roll_ptr_t) rseg_id << 48
60		| (roll_ptr_t) page_no << 16
61		| offset;
62	return(roll_ptr);
63}
64
65/***********************************************************************//**
66Decodes a roll pointer. */
67UNIV_INLINE
68void
69trx_undo_decode_roll_ptr(
70/*=====================*/
71	roll_ptr_t	roll_ptr,	/*!< in: roll pointer */
72	ibool*		is_insert,	/*!< out: TRUE if insert undo log */
73	ulint*		rseg_id,	/*!< out: rollback segment id */
74	ulint*		page_no,	/*!< out: page number */
75	ulint*		offset)		/*!< out: offset of the undo
76					entry within page */
77{
78#if DATA_ROLL_PTR_LEN != 7
79# error "DATA_ROLL_PTR_LEN != 7"
80#endif
81#if TRUE != 1
82# error "TRUE != 1"
83#endif
84	ut_ad(roll_ptr < (1ULL << 56));
85	*offset = (ulint) roll_ptr & 0xFFFF;
86	roll_ptr >>= 16;
87	*page_no = (ulint) roll_ptr & 0xFFFFFFFF;
88	roll_ptr >>= 32;
89	*rseg_id = (ulint) roll_ptr & 0x7F;
90	roll_ptr >>= 7;
91	*is_insert = (ibool) roll_ptr; /* TRUE==1 */
92}
93
94/***********************************************************************//**
95Returns TRUE if the roll pointer is of the insert type.
96@return	TRUE if insert undo log */
97UNIV_INLINE
98ibool
99trx_undo_roll_ptr_is_insert(
100/*========================*/
101	roll_ptr_t	roll_ptr)	/*!< in: roll pointer */
102{
103#if DATA_ROLL_PTR_LEN != 7
104# error "DATA_ROLL_PTR_LEN != 7"
105#endif
106#if TRUE != 1
107# error "TRUE != 1"
108#endif
109	ut_ad(roll_ptr < (1ULL << 56));
110	return((ibool) (roll_ptr >> 55));
111}
112
113/***********************************************************************//**
114Returns true if the record is of the insert type.
115@return	true if the record was freshly inserted (not updated). */
116UNIV_INLINE
117bool
118trx_undo_trx_id_is_insert(
119/*======================*/
120	const byte*	trx_id)	/*!< in: DB_TRX_ID, followed by DB_ROLL_PTR */
121{
122#if DATA_TRX_ID + 1 != DATA_ROLL_PTR
123# error
124#endif
125	return(static_cast<bool>(trx_id[DATA_TRX_ID_LEN] >> 7));
126}
127#endif /* !UNIV_HOTBACKUP */
128
129/*****************************************************************//**
130Writes a roll ptr to an index page. In case that the size changes in
131some future version, this function should be used instead of
132mach_write_... */
133UNIV_INLINE
134void
135trx_write_roll_ptr(
136/*===============*/
137	byte*		ptr,		/*!< in: pointer to memory where
138					written */
139	roll_ptr_t	roll_ptr)	/*!< in: roll ptr */
140{
141#if DATA_ROLL_PTR_LEN != 7
142# error "DATA_ROLL_PTR_LEN != 7"
143#endif
144	mach_write_to_7(ptr, roll_ptr);
145}
146
147/*****************************************************************//**
148Reads a roll ptr from an index page. In case that the roll ptr size
149changes in some future version, this function should be used instead of
150mach_read_...
151@return	roll ptr */
152UNIV_INLINE
153roll_ptr_t
154trx_read_roll_ptr(
155/*==============*/
156	const byte*	ptr)	/*!< in: pointer to memory from where to read */
157{
158#if DATA_ROLL_PTR_LEN != 7
159# error "DATA_ROLL_PTR_LEN != 7"
160#endif
161	return(mach_read_from_7(ptr));
162}
163
164#ifndef UNIV_HOTBACKUP
165/******************************************************************//**
166Gets an undo log page and x-latches it.
167@return	pointer to page x-latched */
168UNIV_INLINE
169page_t*
170trx_undo_page_get(
171/*==============*/
172	ulint	space,		/*!< in: space where placed */
173	ulint	zip_size,	/*!< in: compressed page size in bytes
174				or 0 for uncompressed pages */
175	ulint	page_no,	/*!< in: page number */
176	mtr_t*	mtr)		/*!< in: mtr */
177{
178	buf_block_t*	block = buf_page_get(space, zip_size, page_no,
179					     RW_X_LATCH, mtr);
180	buf_block_dbg_add_level(block, SYNC_TRX_UNDO_PAGE);
181
182	return(buf_block_get_frame(block));
183}
184
185/******************************************************************//**
186Gets an undo log page and s-latches it.
187@return	pointer to page s-latched */
188UNIV_INLINE
189page_t*
190trx_undo_page_get_s_latched(
191/*========================*/
192	ulint	space,		/*!< in: space where placed */
193	ulint	zip_size,	/*!< in: compressed page size in bytes
194				or 0 for uncompressed pages */
195	ulint	page_no,	/*!< in: page number */
196	mtr_t*	mtr)		/*!< in: mtr */
197{
198	buf_block_t*	block = buf_page_get(space, zip_size, page_no,
199					     RW_S_LATCH, mtr);
200	buf_block_dbg_add_level(block, SYNC_TRX_UNDO_PAGE);
201
202	return(buf_block_get_frame(block));
203}
204
205/******************************************************************//**
206Returns the start offset of the undo log records of the specified undo
207log on the page.
208@return	start offset */
209UNIV_INLINE
210ulint
211trx_undo_page_get_start(
212/*====================*/
213	page_t*	undo_page,/*!< in: undo log page */
214	ulint	page_no,/*!< in: undo log header page number */
215	ulint	offset)	/*!< in: undo log header offset on page */
216{
217	ulint	start;
218
219	if (page_no == page_get_page_no(undo_page)) {
220
221		start = mach_read_from_2(offset + undo_page
222					 + TRX_UNDO_LOG_START);
223	} else {
224		start = TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE;
225	}
226
227	return(start);
228}
229
230/******************************************************************//**
231Returns the end offset of the undo log records of the specified undo
232log on the page.
233@return	end offset */
234UNIV_INLINE
235ulint
236trx_undo_page_get_end(
237/*==================*/
238	page_t*	undo_page,/*!< in: undo log page */
239	ulint	page_no,/*!< in: undo log header page number */
240	ulint	offset)	/*!< in: undo log header offset on page */
241{
242	trx_ulogf_t*	log_hdr;
243	ulint		end;
244
245	if (page_no == page_get_page_no(undo_page)) {
246
247		log_hdr = undo_page + offset;
248
249		end = mach_read_from_2(log_hdr + TRX_UNDO_NEXT_LOG);
250
251		if (end == 0) {
252			end = mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
253					       + TRX_UNDO_PAGE_FREE);
254		}
255	} else {
256		end = mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
257				       + TRX_UNDO_PAGE_FREE);
258	}
259
260	return(end);
261}
262
263/******************************************************************//**
264Returns the previous undo record on the page in the specified log, or
265NULL if none exists.
266@return	pointer to record, NULL if none */
267UNIV_INLINE
268trx_undo_rec_t*
269trx_undo_page_get_prev_rec(
270/*=======================*/
271	trx_undo_rec_t*	rec,	/*!< in: undo log record */
272	ulint		page_no,/*!< in: undo log header page number */
273	ulint		offset)	/*!< in: undo log header offset on page */
274{
275	page_t*	undo_page;
276	ulint	start;
277
278	undo_page = (page_t*) ut_align_down(rec, UNIV_PAGE_SIZE);
279
280	start = trx_undo_page_get_start(undo_page, page_no, offset);
281
282	if (start + undo_page == rec) {
283
284		return(NULL);
285	}
286
287	return(undo_page + mach_read_from_2(rec - 2));
288}
289
290/******************************************************************//**
291Returns the next undo log record on the page in the specified log, or
292NULL if none exists.
293@return	pointer to record, NULL if none */
294UNIV_INLINE
295trx_undo_rec_t*
296trx_undo_page_get_next_rec(
297/*=======================*/
298	trx_undo_rec_t*	rec,	/*!< in: undo log record */
299	ulint		page_no,/*!< in: undo log header page number */
300	ulint		offset)	/*!< in: undo log header offset on page */
301{
302	page_t*	undo_page;
303	ulint	end;
304	ulint	next;
305
306	undo_page = (page_t*) ut_align_down(rec, UNIV_PAGE_SIZE);
307
308	end = trx_undo_page_get_end(undo_page, page_no, offset);
309
310	next = mach_read_from_2(rec);
311
312	if (next == end) {
313
314		return(NULL);
315	}
316
317	return(undo_page + next);
318}
319
320/******************************************************************//**
321Returns the last undo record on the page in the specified undo log, or
322NULL if none exists.
323@return	pointer to record, NULL if none */
324UNIV_INLINE
325trx_undo_rec_t*
326trx_undo_page_get_last_rec(
327/*=======================*/
328	page_t*	undo_page,/*!< in: undo log page */
329	ulint	page_no,/*!< in: undo log header page number */
330	ulint	offset)	/*!< in: undo log header offset on page */
331{
332	ulint	start;
333	ulint	end;
334
335	start = trx_undo_page_get_start(undo_page, page_no, offset);
336	end = trx_undo_page_get_end(undo_page, page_no, offset);
337
338	if (start == end) {
339
340		return(NULL);
341	}
342
343	return(undo_page + mach_read_from_2(undo_page + end - 2));
344}
345
346/******************************************************************//**
347Returns the first undo record on the page in the specified undo log, or
348NULL if none exists.
349@return	pointer to record, NULL if none */
350UNIV_INLINE
351trx_undo_rec_t*
352trx_undo_page_get_first_rec(
353/*========================*/
354	page_t*	undo_page,/*!< in: undo log page */
355	ulint	page_no,/*!< in: undo log header page number */
356	ulint	offset)	/*!< in: undo log header offset on page */
357{
358	ulint	start;
359	ulint	end;
360
361	start = trx_undo_page_get_start(undo_page, page_no, offset);
362	end = trx_undo_page_get_end(undo_page, page_no, offset);
363
364	if (start == end) {
365
366		return(NULL);
367	}
368
369	return(undo_page + start);
370}
371#endif /* !UNIV_HOTBACKUP */
372