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