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