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