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