1/*****************************************************************************
2
3Copyright (c) 1994, 2016, 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/btr0btr.ic
29The B-tree
30
31Created 6/2/1994 Heikki Tuuri
32*******************************************************/
33
34#include "mach0data.h"
35#ifndef UNIV_HOTBACKUP
36#include "mtr0mtr.h"
37#include "mtr0log.h"
38#include "page0zip.h"
39#include "srv0srv.h"
40#define BTR_MAX_NODE_LEVEL	50	/*!< Maximum B-tree page level
41					(not really a hard limit).
42					Used in debug assertions
43					in btr_page_set_level and
44					btr_page_get_level_low */
45
46/**************************************************************//**
47Gets a buffer page and declares its latching order level. */
48UNIV_INLINE
49buf_block_t*
50btr_block_get_func(
51/*===============*/
52	ulint		space,		/*!< in: space id */
53	ulint		zip_size,	/*!< in: compressed page size in bytes
54					or 0 for uncompressed pages */
55	ulint		page_no,	/*!< in: page number */
56	ulint		mode,		/*!< in: latch mode */
57	const char*	file,		/*!< in: file name */
58	ulint		line,		/*!< in: line where called */
59#ifdef UNIV_SYNC_DEBUG
60	const dict_index_t*	index,	/*!< in: index tree, may be NULL
61					if it is not an insert buffer tree */
62#endif /* UNIV_SYNC_DEBUG */
63	mtr_t*		mtr)		/*!< in/out: mtr */
64{
65	buf_block_t*	block;
66
67	block = buf_page_get_gen(space, zip_size, page_no, mode,
68				 NULL, BUF_GET, file, line, mtr);
69
70	SRV_CORRUPT_TABLE_CHECK(block, ; /* do nothing */);
71
72	if (block && mode != RW_NO_LATCH) {
73
74		buf_block_dbg_add_level(
75			block, index != NULL && dict_index_is_ibuf(index)
76			? SYNC_IBUF_TREE_NODE : SYNC_TREE_NODE);
77	}
78
79	return(block);
80}
81
82/**************************************************************//**
83Sets the index id field of a page. */
84UNIV_INLINE
85void
86btr_page_set_index_id(
87/*==================*/
88	page_t*		page,	/*!< in: page to be created */
89	page_zip_des_t*	page_zip,/*!< in: compressed page whose uncompressed
90				part will be updated, or NULL */
91	index_id_t	id,	/*!< in: index id */
92	mtr_t*		mtr)	/*!< in: mtr */
93{
94	if (page_zip) {
95		mach_write_to_8(page + (PAGE_HEADER + PAGE_INDEX_ID), id);
96		page_zip_write_header(page_zip,
97				      page + (PAGE_HEADER + PAGE_INDEX_ID),
98				      8, mtr);
99	} else {
100		mlog_write_ull(page + (PAGE_HEADER + PAGE_INDEX_ID), id, mtr);
101	}
102}
103#endif /* !UNIV_HOTBACKUP */
104
105/**************************************************************//**
106Gets the index id field of a page.
107@return	index id */
108UNIV_INLINE
109index_id_t
110btr_page_get_index_id(
111/*==================*/
112	const page_t*	page)	/*!< in: index page */
113{
114	return(mach_read_from_8(page + PAGE_HEADER + PAGE_INDEX_ID));
115}
116
117#ifndef UNIV_HOTBACKUP
118/********************************************************//**
119Gets the node level field in an index page.
120@return	level, leaf level == 0 */
121UNIV_INLINE
122ulint
123btr_page_get_level_low(
124/*===================*/
125	const page_t*	page)	/*!< in: index page */
126{
127	ulint	level;
128
129	ut_ad(page);
130
131	level = mach_read_from_2(page + PAGE_HEADER + PAGE_LEVEL);
132
133	ut_ad(level <= BTR_MAX_NODE_LEVEL);
134
135	return(level);
136}
137
138/********************************************************//**
139Sets the node level field in an index page. */
140UNIV_INLINE
141void
142btr_page_set_level(
143/*===============*/
144	page_t*		page,	/*!< in: index page */
145	page_zip_des_t*	page_zip,/*!< in: compressed page whose uncompressed
146				part will be updated, or NULL */
147	ulint		level,	/*!< in: level, leaf level == 0 */
148	mtr_t*		mtr)	/*!< in: mini-transaction handle */
149{
150	ut_ad(page && mtr);
151	ut_ad(level <= BTR_MAX_NODE_LEVEL);
152
153	if (page_zip) {
154		mach_write_to_2(page + (PAGE_HEADER + PAGE_LEVEL), level);
155		page_zip_write_header(page_zip,
156				      page + (PAGE_HEADER + PAGE_LEVEL),
157				      2, mtr);
158	} else {
159		mlog_write_ulint(page + (PAGE_HEADER + PAGE_LEVEL), level,
160				 MLOG_2BYTES, mtr);
161	}
162}
163
164/********************************************************//**
165Gets the next index page number.
166@return	next page number */
167UNIV_INLINE
168ulint
169btr_page_get_next(
170/*==============*/
171	const page_t*	page,	/*!< in: index page */
172	mtr_t*		mtr MY_ATTRIBUTE((unused)))
173				/*!< in: mini-transaction handle */
174{
175	ut_ad(page != NULL);
176	ut_ad(mtr != NULL);
177	ut_ad(mtr_memo_contains_page(mtr, page, MTR_MEMO_PAGE_X_FIX)
178	      || mtr_memo_contains_page(mtr, page, MTR_MEMO_PAGE_S_FIX));
179
180	return(mach_read_from_4(page + FIL_PAGE_NEXT));
181}
182
183/********************************************************//**
184Sets the next index page field. */
185UNIV_INLINE
186void
187btr_page_set_next(
188/*==============*/
189	page_t*		page,	/*!< in: index page */
190	page_zip_des_t*	page_zip,/*!< in: compressed page whose uncompressed
191				part will be updated, or NULL */
192	ulint		next,	/*!< in: next page number */
193	mtr_t*		mtr)	/*!< in: mini-transaction handle */
194{
195	ut_ad(page != NULL);
196	ut_ad(mtr != NULL);
197
198	if (page_zip) {
199		mach_write_to_4(page + FIL_PAGE_NEXT, next);
200		page_zip_write_header(page_zip, page + FIL_PAGE_NEXT, 4, mtr);
201	} else {
202		mlog_write_ulint(page + FIL_PAGE_NEXT, next, MLOG_4BYTES, mtr);
203	}
204}
205
206/********************************************************//**
207Gets the previous index page number.
208@return	prev page number */
209UNIV_INLINE
210ulint
211btr_page_get_prev(
212/*==============*/
213	const page_t*	page,	/*!< in: index page */
214	mtr_t*	mtr MY_ATTRIBUTE((unused))) /*!< in: mini-transaction handle */
215{
216	ut_ad(page != NULL);
217	ut_ad(mtr != NULL);
218
219	return(mach_read_from_4(page + FIL_PAGE_PREV));
220}
221
222/********************************************************//**
223Sets the previous index page field. */
224UNIV_INLINE
225void
226btr_page_set_prev(
227/*==============*/
228	page_t*		page,	/*!< in: index page */
229	page_zip_des_t*	page_zip,/*!< in: compressed page whose uncompressed
230				part will be updated, or NULL */
231	ulint		prev,	/*!< in: previous page number */
232	mtr_t*		mtr)	/*!< in: mini-transaction handle */
233{
234	ut_ad(page != NULL);
235	ut_ad(mtr != NULL);
236
237	if (page_zip) {
238		mach_write_to_4(page + FIL_PAGE_PREV, prev);
239		page_zip_write_header(page_zip, page + FIL_PAGE_PREV, 4, mtr);
240	} else {
241		mlog_write_ulint(page + FIL_PAGE_PREV, prev, MLOG_4BYTES, mtr);
242	}
243}
244
245/**************************************************************//**
246Gets the child node file address in a node pointer.
247NOTE: the offsets array must contain all offsets for the record since
248we read the last field according to offsets and assume that it contains
249the child page number. In other words offsets must have been retrieved
250with rec_get_offsets(n_fields=ULINT_UNDEFINED).
251@return	child node address */
252UNIV_INLINE
253ulint
254btr_node_ptr_get_child_page_no(
255/*===========================*/
256	const rec_t*	rec,	/*!< in: node pointer record */
257	const ulint*	offsets)/*!< in: array returned by rec_get_offsets() */
258{
259	const byte*	field;
260	ulint		len;
261	ulint		page_no;
262
263	ut_ad(!rec_offs_comp(offsets) || rec_get_node_ptr_flag(rec));
264
265	/* The child address is in the last field */
266	field = rec_get_nth_field(rec, offsets,
267				  rec_offs_n_fields(offsets) - 1, &len);
268
269	ut_ad(len == 4);
270
271	page_no = mach_read_from_4(field);
272
273	if (page_no == 0) {
274		fprintf(stderr,
275			"InnoDB: a nonsensical page number 0"
276			" in a node ptr record at offset %lu\n",
277			(ulong) page_offset(rec));
278		buf_page_print(page_align(rec), 0, 0);
279		ut_ad(0);
280	}
281
282	return(page_no);
283}
284
285/**************************************************************//**
286Releases the latches on a leaf page and bufferunfixes it. */
287UNIV_INLINE
288void
289btr_leaf_page_release(
290/*==================*/
291	buf_block_t*	block,		/*!< in: buffer block */
292	ulint		latch_mode,	/*!< in: BTR_SEARCH_LEAF or
293					BTR_MODIFY_LEAF */
294	mtr_t*		mtr)		/*!< in: mtr */
295{
296	ut_ad(latch_mode == BTR_SEARCH_LEAF || latch_mode == BTR_MODIFY_LEAF);
297	ut_ad(!mtr_memo_contains(mtr, block, MTR_MEMO_MODIFY));
298
299	mtr_memo_release(mtr, block,
300			 latch_mode == BTR_SEARCH_LEAF
301			 ? MTR_MEMO_PAGE_S_FIX
302			 : MTR_MEMO_PAGE_X_FIX);
303}
304#endif /* !UNIV_HOTBACKUP */
305