1 /***************************************************************************** 2 3 Copyright (c) 1994, 2021, Oracle and/or its affiliates. 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License, version 2.0, 7 as published by the Free Software Foundation. 8 9 This program is also distributed with certain software (including 10 but not limited to OpenSSL) that is licensed under separate terms, 11 as designated in a particular file or component or in included license 12 documentation. The authors of MySQL hereby grant you an additional 13 permission to link the program and your derivative works with the 14 separately licensed software that they have included with MySQL. 15 16 This program is distributed in the hope that it will be useful, 17 but WITHOUT ANY WARRANTY; without even the implied warranty of 18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 GNU General Public License, version 2.0, for more details. 20 21 You should have received a copy of the GNU General Public License along with 22 this program; if not, write to the Free Software Foundation, Inc., 23 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA 24 25 *****************************************************************************/ 26 27 /**************************************************//** 28 @file include/page0page.h 29 Index page routines 30 31 Created 2/2/1994 Heikki Tuuri 32 *******************************************************/ 33 34 #ifndef page0page_h 35 #define page0page_h 36 37 #include "univ.i" 38 39 #include "page0types.h" 40 #ifndef UNIV_INNOCHECKSUM 41 #include "fil0fil.h" 42 #include "buf0buf.h" 43 #include "data0data.h" 44 #include "dict0dict.h" 45 #include "rem0rec.h" 46 #endif /* !UNIV_INNOCHECKSUM*/ 47 #include "fsp0fsp.h" 48 #ifndef UNIV_INNOCHECKSUM 49 #include "mtr0mtr.h" 50 51 #ifdef UNIV_MATERIALIZE 52 #undef UNIV_INLINE 53 #define UNIV_INLINE 54 #endif 55 56 /* PAGE HEADER 57 =========== 58 59 Index page header starts at the first offset left free by the FIL-module */ 60 61 typedef byte page_header_t; 62 #endif /* !UNIV_INNOCHECKSUM */ 63 64 #define PAGE_HEADER FSEG_PAGE_DATA /* index page header starts at this 65 offset */ 66 /*-----------------------------*/ 67 #define PAGE_N_DIR_SLOTS 0 /* number of slots in page directory */ 68 #define PAGE_HEAP_TOP 2 /* pointer to record heap top */ 69 #define PAGE_N_HEAP 4 /* number of records in the heap, 70 bit 15=flag: new-style compact page format */ 71 #define PAGE_FREE 6 /* pointer to start of page free record list */ 72 #define PAGE_GARBAGE 8 /* number of bytes in deleted records */ 73 #define PAGE_LAST_INSERT 10 /* pointer to the last inserted record, or 74 NULL if this info has been reset by a delete, 75 for example */ 76 #define PAGE_DIRECTION 12 /* last insert direction: PAGE_LEFT, ... */ 77 #define PAGE_N_DIRECTION 14 /* number of consecutive inserts to the same 78 direction */ 79 #define PAGE_N_RECS 16 /* number of user records on the page */ 80 #define PAGE_MAX_TRX_ID 18 /* highest id of a trx which may have modified 81 a record on the page; trx_id_t; defined only 82 in secondary indexes and in the insert buffer 83 tree */ 84 #define PAGE_HEADER_PRIV_END 26 /* end of private data structure of the page 85 header which are set in a page create */ 86 /*----*/ 87 #define PAGE_LEVEL 26 /* level of the node in an index tree; the 88 leaf level is the level 0. This field should 89 not be written to after page creation. */ 90 #define PAGE_INDEX_ID 28 /* index id where the page belongs. 91 This field should not be written to after 92 page creation. */ 93 94 #ifndef UNIV_INNOCHECKSUM 95 96 #define PAGE_BTR_SEG_LEAF 36 /* file segment header for the leaf pages in 97 a B-tree: defined only on the root page of a 98 B-tree, but not in the root of an ibuf tree */ 99 #define PAGE_BTR_IBUF_FREE_LIST PAGE_BTR_SEG_LEAF 100 #define PAGE_BTR_IBUF_FREE_LIST_NODE PAGE_BTR_SEG_LEAF 101 /* in the place of PAGE_BTR_SEG_LEAF and _TOP 102 there is a free list base node if the page is 103 the root page of an ibuf tree, and at the same 104 place is the free list node if the page is in 105 a free list */ 106 #define PAGE_BTR_SEG_TOP (36 + FSEG_HEADER_SIZE) 107 /* file segment header for the non-leaf pages 108 in a B-tree: defined only on the root page of 109 a B-tree, but not in the root of an ibuf 110 tree */ 111 /*----*/ 112 #define PAGE_DATA (PAGE_HEADER + 36 + 2 * FSEG_HEADER_SIZE) 113 /* start of data on the page */ 114 115 #define PAGE_OLD_INFIMUM (PAGE_DATA + 1 + REC_N_OLD_EXTRA_BYTES) 116 /* offset of the page infimum record on an 117 old-style page */ 118 #define PAGE_OLD_SUPREMUM (PAGE_DATA + 2 + 2 * REC_N_OLD_EXTRA_BYTES + 8) 119 /* offset of the page supremum record on an 120 old-style page */ 121 #define PAGE_OLD_SUPREMUM_END (PAGE_OLD_SUPREMUM + 9) 122 /* offset of the page supremum record end on 123 an old-style page */ 124 #define PAGE_NEW_INFIMUM (PAGE_DATA + REC_N_NEW_EXTRA_BYTES) 125 /* offset of the page infimum record on a 126 new-style compact page */ 127 #define PAGE_NEW_SUPREMUM (PAGE_DATA + 2 * REC_N_NEW_EXTRA_BYTES + 8) 128 /* offset of the page supremum record on a 129 new-style compact page */ 130 #define PAGE_NEW_SUPREMUM_END (PAGE_NEW_SUPREMUM + 8) 131 /* offset of the page supremum record end on 132 a new-style compact page */ 133 /*-----------------------------*/ 134 135 /* Heap numbers */ 136 #define PAGE_HEAP_NO_INFIMUM 0 /* page infimum */ 137 #define PAGE_HEAP_NO_SUPREMUM 1 /* page supremum */ 138 #define PAGE_HEAP_NO_USER_LOW 2 /* first user record in 139 creation (insertion) order, 140 not necessarily collation order; 141 this record may have been deleted */ 142 143 /* Directions of cursor movement */ 144 #define PAGE_LEFT 1 145 #define PAGE_RIGHT 2 146 #define PAGE_SAME_REC 3 147 #define PAGE_SAME_PAGE 4 148 #define PAGE_NO_DIRECTION 5 149 150 /* PAGE DIRECTORY 151 ============== 152 */ 153 154 typedef byte page_dir_slot_t; 155 typedef page_dir_slot_t page_dir_t; 156 157 /* Offset of the directory start down from the page end. We call the 158 slot with the highest file address directory start, as it points to 159 the first record in the list of records. */ 160 #define PAGE_DIR FIL_PAGE_DATA_END 161 162 /* We define a slot in the page directory as two bytes */ 163 #define PAGE_DIR_SLOT_SIZE 2 164 165 /* The offset of the physically lower end of the directory, counted from 166 page end, when the page is empty */ 167 #define PAGE_EMPTY_DIR_START (PAGE_DIR + 2 * PAGE_DIR_SLOT_SIZE) 168 169 /* The maximum and minimum number of records owned by a directory slot. The 170 number may drop below the minimum in the first and the last slot in the 171 directory. */ 172 #define PAGE_DIR_SLOT_MAX_N_OWNED 8 173 #define PAGE_DIR_SLOT_MIN_N_OWNED 4 174 175 /************************************************************//** 176 Gets the start of a page. 177 @return start of the page */ 178 UNIV_INLINE 179 page_t* 180 page_align( 181 /*=======*/ 182 const void* ptr) /*!< in: pointer to page frame */ 183 MY_ATTRIBUTE((const)); 184 /************************************************************//** 185 Gets the offset within a page. 186 @return offset from the start of the page */ 187 UNIV_INLINE 188 ulint 189 page_offset( 190 /*========*/ 191 const void* ptr) /*!< in: pointer to page frame */ 192 MY_ATTRIBUTE((const)); 193 /*************************************************************//** 194 Returns the max trx id field value. */ 195 UNIV_INLINE 196 trx_id_t 197 page_get_max_trx_id( 198 /*================*/ 199 const page_t* page); /*!< in: page */ 200 /*************************************************************//** 201 Sets the max trx id field value. */ 202 void 203 page_set_max_trx_id( 204 /*================*/ 205 buf_block_t* block, /*!< in/out: page */ 206 page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */ 207 trx_id_t trx_id, /*!< in: transaction id */ 208 mtr_t* mtr); /*!< in/out: mini-transaction, or NULL */ 209 /*************************************************************//** 210 Sets the max trx id field value if trx_id is bigger than the previous 211 value. */ 212 UNIV_INLINE 213 void 214 page_update_max_trx_id( 215 /*===================*/ 216 buf_block_t* block, /*!< in/out: page */ 217 page_zip_des_t* page_zip,/*!< in/out: compressed page whose 218 uncompressed part will be updated, or NULL */ 219 trx_id_t trx_id, /*!< in: transaction id */ 220 mtr_t* mtr); /*!< in/out: mini-transaction */ 221 /*************************************************************//** 222 Returns the RTREE SPLIT SEQUENCE NUMBER (FIL_RTREE_SPLIT_SEQ_NUM). 223 @return SPLIT SEQUENCE NUMBER */ 224 UNIV_INLINE 225 node_seq_t 226 page_get_ssn_id( 227 /*============*/ 228 const page_t* page); /*!< in: page */ 229 /*************************************************************//** 230 Sets the RTREE SPLIT SEQUENCE NUMBER field value */ 231 UNIV_INLINE 232 void 233 page_set_ssn_id( 234 /*============*/ 235 buf_block_t* block, /*!< in/out: page */ 236 page_zip_des_t* page_zip,/*!< in/out: compressed page whose 237 uncompressed part will be updated, or NULL */ 238 node_seq_t ssn_id, /*!< in: split sequence id */ 239 mtr_t* mtr); /*!< in/out: mini-transaction */ 240 241 #endif /* !UNIV_INNOCHECKSUM */ 242 /*************************************************************//** 243 Reads the given header field. */ 244 UNIV_INLINE 245 ulint 246 page_header_get_field( 247 /*==================*/ 248 const page_t* page, /*!< in: page */ 249 ulint field); /*!< in: PAGE_N_DIR_SLOTS, ... */ 250 251 #ifndef UNIV_INNOCHECKSUM 252 /*************************************************************//** 253 Sets the given header field. */ 254 UNIV_INLINE 255 void 256 page_header_set_field( 257 /*==================*/ 258 page_t* page, /*!< in/out: page */ 259 page_zip_des_t* page_zip,/*!< in/out: compressed page whose 260 uncompressed part will be updated, or NULL */ 261 ulint field, /*!< in: PAGE_N_DIR_SLOTS, ... */ 262 ulint val); /*!< in: value */ 263 /*************************************************************//** 264 Returns the offset stored in the given header field. 265 @return offset from the start of the page, or 0 */ 266 UNIV_INLINE 267 ulint 268 page_header_get_offs( 269 /*=================*/ 270 const page_t* page, /*!< in: page */ 271 ulint field) /*!< in: PAGE_FREE, ... */ 272 MY_ATTRIBUTE((warn_unused_result)); 273 274 /*************************************************************//** 275 Returns the pointer stored in the given header field, or NULL. */ 276 #define page_header_get_ptr(page, field) \ 277 (page_header_get_offs(page, field) \ 278 ? page + page_header_get_offs(page, field) : NULL) 279 /*************************************************************//** 280 Sets the pointer stored in the given header field. */ 281 UNIV_INLINE 282 void 283 page_header_set_ptr( 284 /*================*/ 285 page_t* page, /*!< in/out: page */ 286 page_zip_des_t* page_zip,/*!< in/out: compressed page whose 287 uncompressed part will be updated, or NULL */ 288 ulint field, /*!< in/out: PAGE_FREE, ... */ 289 const byte* ptr); /*!< in: pointer or NULL*/ 290 #ifndef UNIV_HOTBACKUP 291 /*************************************************************//** 292 Resets the last insert info field in the page header. Writes to mlog 293 about this operation. */ 294 UNIV_INLINE 295 void 296 page_header_reset_last_insert( 297 /*==========================*/ 298 page_t* page, /*!< in: page */ 299 page_zip_des_t* page_zip,/*!< in/out: compressed page whose 300 uncompressed part will be updated, or NULL */ 301 mtr_t* mtr); /*!< in: mtr */ 302 #endif /* !UNIV_HOTBACKUP */ 303 /************************************************************//** 304 Gets the offset of the first record on the page. 305 @return offset of the first record in record list, relative from page */ 306 UNIV_INLINE 307 ulint 308 page_get_infimum_offset( 309 /*====================*/ 310 const page_t* page); /*!< in: page which must have record(s) */ 311 /************************************************************//** 312 Gets the offset of the last record on the page. 313 @return offset of the last record in record list, relative from page */ 314 UNIV_INLINE 315 ulint 316 page_get_supremum_offset( 317 /*=====================*/ 318 const page_t* page); /*!< in: page which must have record(s) */ 319 #define page_get_infimum_rec(page) ((page) + page_get_infimum_offset(page)) 320 #define page_get_supremum_rec(page) ((page) + page_get_supremum_offset(page)) 321 322 /************************************************************//** 323 Returns the nth record of the record list. 324 This is the inverse function of page_rec_get_n_recs_before(). 325 @return nth record */ 326 const rec_t* 327 page_rec_get_nth_const( 328 /*===================*/ 329 const page_t* page, /*!< in: page */ 330 ulint nth) /*!< in: nth record */ 331 MY_ATTRIBUTE((warn_unused_result)); 332 /************************************************************//** 333 Returns the nth record of the record list. 334 This is the inverse function of page_rec_get_n_recs_before(). 335 @return nth record */ 336 UNIV_INLINE 337 rec_t* 338 page_rec_get_nth( 339 /*=============*/ 340 page_t* page, /*< in: page */ 341 ulint nth) /*!< in: nth record */ 342 MY_ATTRIBUTE((warn_unused_result)); 343 344 #ifndef UNIV_HOTBACKUP 345 /************************************************************//** 346 Returns the middle record of the records on the page. If there is an 347 even number of records in the list, returns the first record of the 348 upper half-list. 349 @return middle record */ 350 UNIV_INLINE 351 rec_t* 352 page_get_middle_rec( 353 /*================*/ 354 page_t* page) /*!< in: page */ 355 MY_ATTRIBUTE((warn_unused_result)); 356 #endif /* !UNIV_HOTBACKUP */ 357 /*************************************************************//** 358 Gets the page number. 359 @return page number */ 360 UNIV_INLINE 361 ulint 362 page_get_page_no( 363 /*=============*/ 364 const page_t* page); /*!< in: page */ 365 /*************************************************************//** 366 Gets the tablespace identifier. 367 @return space id */ 368 UNIV_INLINE 369 ulint 370 page_get_space_id( 371 /*==============*/ 372 const page_t* page); /*!< in: page */ 373 /*************************************************************//** 374 Gets the number of user records on page (the infimum and supremum records 375 are not user records). 376 @return number of user records */ 377 UNIV_INLINE 378 ulint 379 page_get_n_recs( 380 /*============*/ 381 const page_t* page); /*!< in: index page */ 382 /***************************************************************//** 383 Returns the number of records before the given record in chain. 384 The number includes infimum and supremum records. 385 This is the inverse function of page_rec_get_nth(). 386 @return number of records */ 387 ulint 388 page_rec_get_n_recs_before( 389 /*=======================*/ 390 const rec_t* rec); /*!< in: the physical record */ 391 /*************************************************************//** 392 Gets the number of records in the heap. 393 @return number of user records */ 394 UNIV_INLINE 395 ulint 396 page_dir_get_n_heap( 397 /*================*/ 398 const page_t* page); /*!< in: index page */ 399 /*************************************************************//** 400 Sets the number of records in the heap. */ 401 UNIV_INLINE 402 void 403 page_dir_set_n_heap( 404 /*================*/ 405 page_t* page, /*!< in/out: index page */ 406 page_zip_des_t* page_zip,/*!< in/out: compressed page whose 407 uncompressed part will be updated, or NULL. 408 Note that the size of the dense page directory 409 in the compressed page trailer is 410 n_heap * PAGE_ZIP_DIR_SLOT_SIZE. */ 411 ulint n_heap);/*!< in: number of records */ 412 /*************************************************************//** 413 Gets the number of dir slots in directory. 414 @return number of slots */ 415 UNIV_INLINE 416 ulint 417 page_dir_get_n_slots( 418 /*=================*/ 419 const page_t* page); /*!< in: index page */ 420 /*************************************************************//** 421 Sets the number of dir slots in directory. */ 422 UNIV_INLINE 423 void 424 page_dir_set_n_slots( 425 /*=================*/ 426 page_t* page, /*!< in/out: page */ 427 page_zip_des_t* page_zip,/*!< in/out: compressed page whose 428 uncompressed part will be updated, or NULL */ 429 ulint n_slots);/*!< in: number of slots */ 430 #ifdef UNIV_DEBUG 431 /*************************************************************//** 432 Gets pointer to nth directory slot. 433 @return pointer to dir slot */ 434 UNIV_INLINE 435 page_dir_slot_t* 436 page_dir_get_nth_slot( 437 /*==================*/ 438 const page_t* page, /*!< in: index page */ 439 ulint n); /*!< in: position */ 440 #else /* UNIV_DEBUG */ 441 # define page_dir_get_nth_slot(page, n) \ 442 ((page) + (UNIV_PAGE_SIZE - PAGE_DIR \ 443 - (n + 1) * PAGE_DIR_SLOT_SIZE)) 444 #endif /* UNIV_DEBUG */ 445 /**************************************************************//** 446 Used to check the consistency of a record on a page. 447 @return TRUE if succeed */ 448 UNIV_INLINE 449 ibool 450 page_rec_check( 451 /*===========*/ 452 const rec_t* rec); /*!< in: record */ 453 /***************************************************************//** 454 Gets the record pointed to by a directory slot. 455 @return pointer to record */ 456 UNIV_INLINE 457 const rec_t* 458 page_dir_slot_get_rec( 459 /*==================*/ 460 const page_dir_slot_t* slot); /*!< in: directory slot */ 461 /***************************************************************//** 462 This is used to set the record offset in a directory slot. */ 463 UNIV_INLINE 464 void 465 page_dir_slot_set_rec( 466 /*==================*/ 467 page_dir_slot_t* slot, /*!< in: directory slot */ 468 rec_t* rec); /*!< in: record on the page */ 469 /***************************************************************//** 470 Gets the number of records owned by a directory slot. 471 @return number of records */ 472 UNIV_INLINE 473 ulint 474 page_dir_slot_get_n_owned( 475 /*======================*/ 476 const page_dir_slot_t* slot); /*!< in: page directory slot */ 477 /***************************************************************//** 478 This is used to set the owned records field of a directory slot. */ 479 UNIV_INLINE 480 void 481 page_dir_slot_set_n_owned( 482 /*======================*/ 483 page_dir_slot_t*slot, /*!< in/out: directory slot */ 484 page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */ 485 ulint n); /*!< in: number of records owned by the slot */ 486 /************************************************************//** 487 Calculates the space reserved for directory slots of a given 488 number of records. The exact value is a fraction number 489 n * PAGE_DIR_SLOT_SIZE / PAGE_DIR_SLOT_MIN_N_OWNED, and it is 490 rounded upwards to an integer. */ 491 UNIV_INLINE 492 ulint 493 page_dir_calc_reserved_space( 494 /*=========================*/ 495 ulint n_recs); /*!< in: number of records */ 496 /***************************************************************//** 497 Looks for the directory slot which owns the given record. 498 @return the directory slot number */ 499 ulint 500 page_dir_find_owner_slot( 501 /*=====================*/ 502 const rec_t* rec); /*!< in: the physical record */ 503 /************************************************************//** 504 Determine whether the page is in new-style compact format. 505 @return nonzero if the page is in compact format, zero if it is in 506 old-style format */ 507 UNIV_INLINE 508 ulint 509 page_is_comp( 510 /*=========*/ 511 const page_t* page); /*!< in: index page */ 512 /************************************************************//** 513 TRUE if the record is on a page in compact format. 514 @return nonzero if in compact format */ 515 UNIV_INLINE 516 ulint 517 page_rec_is_comp( 518 /*=============*/ 519 const rec_t* rec); /*!< in: record */ 520 /***************************************************************//** 521 Returns the heap number of a record. 522 @return heap number */ 523 UNIV_INLINE 524 ulint 525 page_rec_get_heap_no( 526 /*=================*/ 527 const rec_t* rec); /*!< in: the physical record */ 528 /************************************************************//** 529 Determine whether the page is a B-tree leaf. 530 @return true if the page is a B-tree leaf (PAGE_LEVEL = 0) */ 531 UNIV_INLINE 532 bool 533 page_is_leaf( 534 /*=========*/ 535 const page_t* page) /*!< in: page */ 536 MY_ATTRIBUTE((warn_unused_result)); 537 /************************************************************//** 538 Determine whether the page is empty. 539 @return true if the page is empty (PAGE_N_RECS = 0) */ 540 UNIV_INLINE 541 bool 542 page_is_empty( 543 /*==========*/ 544 const page_t* page) /*!< in: page */ 545 MY_ATTRIBUTE((warn_unused_result)); 546 /** Determine whether a page is an index root page. 547 @param[in] page page frame 548 @return true if the page is a root page of an index */ 549 UNIV_INLINE 550 bool 551 page_is_root( 552 const page_t* page) 553 MY_ATTRIBUTE((warn_unused_result)); 554 /************************************************************//** 555 Determine whether the page contains garbage. 556 @return true if the page contains garbage (PAGE_GARBAGE is not 0) */ 557 UNIV_INLINE 558 bool 559 page_has_garbage( 560 /*=============*/ 561 const page_t* page) /*!< in: page */ 562 MY_ATTRIBUTE((warn_unused_result)); 563 /************************************************************//** 564 Gets the pointer to the next record on the page. 565 @return pointer to next record */ 566 UNIV_INLINE 567 const rec_t* 568 page_rec_get_next_low( 569 /*==================*/ 570 const rec_t* rec, /*!< in: pointer to record */ 571 ulint comp); /*!< in: nonzero=compact page layout */ 572 /************************************************************//** 573 Gets the pointer to the next record on the page. 574 @return pointer to next record */ 575 UNIV_INLINE 576 rec_t* 577 page_rec_get_next( 578 /*==============*/ 579 rec_t* rec); /*!< in: pointer to record */ 580 /************************************************************//** 581 Gets the pointer to the next record on the page. 582 @return pointer to next record */ 583 UNIV_INLINE 584 const rec_t* 585 page_rec_get_next_const( 586 /*====================*/ 587 const rec_t* rec); /*!< in: pointer to record */ 588 /************************************************************//** 589 Gets the pointer to the next non delete-marked record on the page. 590 If all subsequent records are delete-marked, then this function 591 will return the supremum record. 592 @return pointer to next non delete-marked record or pointer to supremum */ 593 UNIV_INLINE 594 const rec_t* 595 page_rec_get_next_non_del_marked( 596 /*=============================*/ 597 const rec_t* rec); /*!< in: pointer to record */ 598 /************************************************************//** 599 Sets the pointer to the next record on the page. */ 600 UNIV_INLINE 601 void 602 page_rec_set_next( 603 /*==============*/ 604 rec_t* rec, /*!< in: pointer to record, 605 must not be page supremum */ 606 const rec_t* next); /*!< in: pointer to next record, 607 must not be page infimum */ 608 /************************************************************//** 609 Gets the pointer to the previous record. 610 @return pointer to previous record */ 611 UNIV_INLINE 612 const rec_t* 613 page_rec_get_prev_const( 614 /*====================*/ 615 const rec_t* rec); /*!< in: pointer to record, must not be page 616 infimum */ 617 /************************************************************//** 618 Gets the pointer to the previous record. 619 @return pointer to previous record */ 620 UNIV_INLINE 621 rec_t* 622 page_rec_get_prev( 623 /*==============*/ 624 rec_t* rec); /*!< in: pointer to record, 625 must not be page infimum */ 626 /************************************************************//** 627 TRUE if the record is a user record on the page. 628 @return TRUE if a user record */ 629 UNIV_INLINE 630 ibool 631 page_rec_is_user_rec_low( 632 /*=====================*/ 633 ulint offset) /*!< in: record offset on page */ 634 MY_ATTRIBUTE((const)); 635 /************************************************************//** 636 TRUE if the record is the supremum record on a page. 637 @return TRUE if the supremum record */ 638 UNIV_INLINE 639 ibool 640 page_rec_is_supremum_low( 641 /*=====================*/ 642 ulint offset) /*!< in: record offset on page */ 643 MY_ATTRIBUTE((const)); 644 /************************************************************//** 645 TRUE if the record is the infimum record on a page. 646 @return TRUE if the infimum record */ 647 UNIV_INLINE 648 ibool 649 page_rec_is_infimum_low( 650 /*====================*/ 651 ulint offset) /*!< in: record offset on page */ 652 MY_ATTRIBUTE((const)); 653 654 /************************************************************//** 655 TRUE if the record is a user record on the page. 656 @return TRUE if a user record */ 657 UNIV_INLINE 658 ibool 659 page_rec_is_user_rec( 660 /*=================*/ 661 const rec_t* rec) /*!< in: record */ 662 MY_ATTRIBUTE((warn_unused_result)); 663 /************************************************************//** 664 TRUE if the record is the supremum record on a page. 665 @return TRUE if the supremum record */ 666 UNIV_INLINE 667 ibool 668 page_rec_is_supremum( 669 /*=================*/ 670 const rec_t* rec) /*!< in: record */ 671 MY_ATTRIBUTE((warn_unused_result)); 672 673 /************************************************************//** 674 TRUE if the record is the infimum record on a page. 675 @return TRUE if the infimum record */ 676 UNIV_INLINE 677 ibool 678 page_rec_is_infimum( 679 /*================*/ 680 const rec_t* rec) /*!< in: record */ 681 MY_ATTRIBUTE((warn_unused_result)); 682 683 /************************************************************//** 684 true if the record is the first user record on a page. 685 @return true if the first user record */ 686 UNIV_INLINE 687 bool 688 page_rec_is_first( 689 /*==============*/ 690 const rec_t* rec, /*!< in: record */ 691 const page_t* page) /*!< in: page */ 692 MY_ATTRIBUTE((warn_unused_result)); 693 694 /************************************************************//** 695 true if the record is the second user record on a page. 696 @return true if the second user record */ 697 UNIV_INLINE 698 bool 699 page_rec_is_second( 700 /*===============*/ 701 const rec_t* rec, /*!< in: record */ 702 const page_t* page) /*!< in: page */ 703 MY_ATTRIBUTE((warn_unused_result)); 704 705 /************************************************************//** 706 true if the record is the last user record on a page. 707 @return true if the last user record */ 708 UNIV_INLINE 709 bool 710 page_rec_is_last( 711 /*=============*/ 712 const rec_t* rec, /*!< in: record */ 713 const page_t* page) /*!< in: page */ 714 MY_ATTRIBUTE((warn_unused_result)); 715 716 /************************************************************//** 717 true if distance between the records (measured in number of times we have to 718 move to the next record) is at most the specified value 719 @param[in] left_rec lefter record 720 @param[in] right_rec righter record 721 @param[in] val specified value to compare 722 @return true if the distance is smaller than the value */ 723 UNIV_INLINE 724 bool 725 page_rec_distance_is_at_most( 726 /*=========================*/ 727 const rec_t* left_rec, 728 const rec_t* right_rec, 729 ulint val) 730 MY_ATTRIBUTE((warn_unused_result)); 731 732 /************************************************************//** 733 true if the record is the second last user record on a page. 734 @return true if the second last user record */ 735 UNIV_INLINE 736 bool 737 page_rec_is_second_last( 738 /*====================*/ 739 const rec_t* rec, /*!< in: record */ 740 const page_t* page) /*!< in: page */ 741 MY_ATTRIBUTE((warn_unused_result)); 742 743 /***************************************************************//** 744 Looks for the record which owns the given record. 745 @return the owner record */ 746 UNIV_INLINE 747 rec_t* 748 page_rec_find_owner_rec( 749 /*====================*/ 750 rec_t* rec); /*!< in: the physical record */ 751 #ifndef UNIV_HOTBACKUP 752 /***********************************************************************//** 753 Write a 32-bit field in a data dictionary record. */ 754 UNIV_INLINE 755 void 756 page_rec_write_field( 757 /*=================*/ 758 rec_t* rec, /*!< in/out: record to update */ 759 ulint i, /*!< in: index of the field to update */ 760 ulint val, /*!< in: value to write */ 761 mtr_t* mtr); /*!< in/out: mini-transaction */ 762 #endif /* !UNIV_HOTBACKUP */ 763 /************************************************************//** 764 Returns the maximum combined size of records which can be inserted on top 765 of record heap. 766 @return maximum combined size for inserted records */ 767 UNIV_INLINE 768 ulint 769 page_get_max_insert_size( 770 /*=====================*/ 771 const page_t* page, /*!< in: index page */ 772 ulint n_recs);/*!< in: number of records */ 773 /************************************************************//** 774 Returns the maximum combined size of records which can be inserted on top 775 of record heap if page is first reorganized. 776 @return maximum combined size for inserted records */ 777 UNIV_INLINE 778 ulint 779 page_get_max_insert_size_after_reorganize( 780 /*======================================*/ 781 const page_t* page, /*!< in: index page */ 782 ulint n_recs);/*!< in: number of records */ 783 /*************************************************************//** 784 Calculates free space if a page is emptied. 785 @return free space */ 786 UNIV_INLINE 787 ulint 788 page_get_free_space_of_empty( 789 /*=========================*/ 790 ulint comp) /*!< in: nonzero=compact page format */ 791 MY_ATTRIBUTE((const)); 792 /**********************************************************//** 793 Returns the base extra size of a physical record. This is the 794 size of the fixed header, independent of the record size. 795 @return REC_N_NEW_EXTRA_BYTES or REC_N_OLD_EXTRA_BYTES */ 796 UNIV_INLINE 797 ulint 798 page_rec_get_base_extra_size( 799 /*=========================*/ 800 const rec_t* rec); /*!< in: physical record */ 801 /************************************************************//** 802 Returns the sum of the sizes of the records in the record list 803 excluding the infimum and supremum records. 804 @return data in bytes */ 805 UNIV_INLINE 806 ulint 807 page_get_data_size( 808 /*===============*/ 809 const page_t* page); /*!< in: index page */ 810 /************************************************************//** 811 Allocates a block of memory from the head of the free list 812 of an index page. */ 813 UNIV_INLINE 814 void 815 page_mem_alloc_free( 816 /*================*/ 817 page_t* page, /*!< in/out: index page */ 818 page_zip_des_t* page_zip,/*!< in/out: compressed page with enough 819 space available for inserting the record, 820 or NULL */ 821 rec_t* next_rec,/*!< in: pointer to the new head of the 822 free record list */ 823 ulint need); /*!< in: number of bytes allocated */ 824 /************************************************************//** 825 Allocates a block of memory from the heap of an index page. 826 @return pointer to start of allocated buffer, or NULL if allocation fails */ 827 byte* 828 page_mem_alloc_heap( 829 /*================*/ 830 page_t* page, /*!< in/out: index page */ 831 page_zip_des_t* page_zip,/*!< in/out: compressed page with enough 832 space available for inserting the record, 833 or NULL */ 834 ulint need, /*!< in: total number of bytes needed */ 835 ulint* heap_no);/*!< out: this contains the heap number 836 of the allocated record 837 if allocation succeeds */ 838 /************************************************************//** 839 Puts a record to free list. */ 840 UNIV_INLINE 841 void 842 page_mem_free( 843 /*==========*/ 844 page_t* page, /*!< in/out: index page */ 845 page_zip_des_t* page_zip,/*!< in/out: compressed page, 846 or NULL */ 847 rec_t* rec, /*!< in: pointer to the (origin of) 848 record */ 849 const dict_index_t* index, /*!< in: index of rec */ 850 const ulint* offsets);/*!< in: array returned by 851 rec_get_offsets() */ 852 /**********************************************************//** 853 Create an uncompressed B-tree index page. 854 @return pointer to the page */ 855 page_t* 856 page_create( 857 /*========*/ 858 buf_block_t* block, /*!< in: a buffer block where the 859 page is created */ 860 mtr_t* mtr, /*!< in: mini-transaction handle */ 861 ulint comp, /*!< in: nonzero=compact page format */ 862 bool is_rtree); /*!< in: if creating R-tree page */ 863 /**********************************************************//** 864 Create a compressed B-tree index page. 865 @return pointer to the page */ 866 page_t* 867 page_create_zip( 868 /*============*/ 869 buf_block_t* block, /*!< in/out: a buffer frame 870 where the page is created */ 871 dict_index_t* index, /*!< in: the index of the 872 page, or NULL when applying 873 TRUNCATE log 874 record during recovery */ 875 ulint level, /*!< in: the B-tree level of 876 the page */ 877 trx_id_t max_trx_id, /*!< in: PAGE_MAX_TRX_ID */ 878 const redo_page_compress_t* page_comp_info, 879 /*!< in: used for applying 880 TRUNCATE log 881 record during recovery */ 882 mtr_t* mtr); /*!< in/out: mini-transaction 883 handle */ 884 /**********************************************************//** 885 Empty a previously created B-tree index page. */ 886 void 887 page_create_empty( 888 /*==============*/ 889 buf_block_t* block, /*!< in/out: B-tree block */ 890 dict_index_t* index, /*!< in: the index of the page */ 891 mtr_t* mtr); /*!< in/out: mini-transaction */ 892 /*************************************************************//** 893 Differs from page_copy_rec_list_end, because this function does not 894 touch the lock table and max trx id on page or compress the page. 895 896 IMPORTANT: The caller will have to update IBUF_BITMAP_FREE 897 if new_block is a compressed leaf page in a secondary index. 898 This has to be done either within the same mini-transaction, 899 or by invoking ibuf_reset_free_bits() before mtr_commit(). */ 900 void 901 page_copy_rec_list_end_no_locks( 902 /*============================*/ 903 buf_block_t* new_block, /*!< in: index page to copy to */ 904 buf_block_t* block, /*!< in: index page of rec */ 905 rec_t* rec, /*!< in: record on page */ 906 dict_index_t* index, /*!< in: record descriptor */ 907 mtr_t* mtr); /*!< in: mtr */ 908 /*************************************************************//** 909 Copies records from page to new_page, from the given record onward, 910 including that record. Infimum and supremum records are not copied. 911 The records are copied to the start of the record list on new_page. 912 913 IMPORTANT: The caller will have to update IBUF_BITMAP_FREE 914 if new_block is a compressed leaf page in a secondary index. 915 This has to be done either within the same mini-transaction, 916 or by invoking ibuf_reset_free_bits() before mtr_commit(). 917 918 @return pointer to the original successor of the infimum record on 919 new_page, or NULL on zip overflow (new_block will be decompressed) */ 920 rec_t* 921 page_copy_rec_list_end( 922 /*===================*/ 923 buf_block_t* new_block, /*!< in/out: index page to copy to */ 924 buf_block_t* block, /*!< in: index page containing rec */ 925 rec_t* rec, /*!< in: record on page */ 926 dict_index_t* index, /*!< in: record descriptor */ 927 mtr_t* mtr); /*!< in: mtr */ 928 /*************************************************************//** 929 Copies records from page to new_page, up to the given record, NOT 930 including that record. Infimum and supremum records are not copied. 931 The records are copied to the end of the record list on new_page. 932 933 IMPORTANT: The caller will have to update IBUF_BITMAP_FREE 934 if new_block is a compressed leaf page in a secondary index. 935 This has to be done either within the same mini-transaction, 936 or by invoking ibuf_reset_free_bits() before mtr_commit(). 937 938 @return pointer to the original predecessor of the supremum record on 939 new_page, or NULL on zip overflow (new_block will be decompressed) */ 940 rec_t* 941 page_copy_rec_list_start( 942 /*=====================*/ 943 buf_block_t* new_block, /*!< in/out: index page to copy to */ 944 buf_block_t* block, /*!< in: index page containing rec */ 945 rec_t* rec, /*!< in: record on page */ 946 dict_index_t* index, /*!< in: record descriptor */ 947 mtr_t* mtr); /*!< in: mtr */ 948 /*************************************************************//** 949 Deletes records from a page from a given record onward, including that record. 950 The infimum and supremum records are not deleted. */ 951 void 952 page_delete_rec_list_end( 953 /*=====================*/ 954 rec_t* rec, /*!< in: pointer to record on page */ 955 buf_block_t* block, /*!< in: buffer block of the page */ 956 dict_index_t* index, /*!< in: record descriptor */ 957 ulint n_recs, /*!< in: number of records to delete, 958 or ULINT_UNDEFINED if not known */ 959 ulint size, /*!< in: the sum of the sizes of the 960 records in the end of the chain to 961 delete, or ULINT_UNDEFINED if not known */ 962 mtr_t* mtr); /*!< in: mtr */ 963 /*************************************************************//** 964 Deletes records from page, up to the given record, NOT including 965 that record. Infimum and supremum records are not deleted. */ 966 void 967 page_delete_rec_list_start( 968 /*=======================*/ 969 rec_t* rec, /*!< in: record on page */ 970 buf_block_t* block, /*!< in: buffer block of the page */ 971 dict_index_t* index, /*!< in: record descriptor */ 972 mtr_t* mtr); /*!< in: mtr */ 973 /*************************************************************//** 974 Moves record list end to another page. Moved records include 975 split_rec. 976 977 IMPORTANT: The caller will have to update IBUF_BITMAP_FREE 978 if new_block is a compressed leaf page in a secondary index. 979 This has to be done either within the same mini-transaction, 980 or by invoking ibuf_reset_free_bits() before mtr_commit(). 981 982 @return TRUE on success; FALSE on compression failure (new_block will 983 be decompressed) */ 984 ibool 985 page_move_rec_list_end( 986 /*===================*/ 987 buf_block_t* new_block, /*!< in/out: index page where to move */ 988 buf_block_t* block, /*!< in: index page from where to move */ 989 rec_t* split_rec, /*!< in: first record to move */ 990 dict_index_t* index, /*!< in: record descriptor */ 991 mtr_t* mtr); /*!< in: mtr */ 992 /*************************************************************//** 993 Moves record list start to another page. Moved records do not include 994 split_rec. 995 996 IMPORTANT: The caller will have to update IBUF_BITMAP_FREE 997 if new_block is a compressed leaf page in a secondary index. 998 This has to be done either within the same mini-transaction, 999 or by invoking ibuf_reset_free_bits() before mtr_commit(). 1000 1001 @return TRUE on success; FALSE on compression failure */ 1002 ibool 1003 page_move_rec_list_start( 1004 /*=====================*/ 1005 buf_block_t* new_block, /*!< in/out: index page where to move */ 1006 buf_block_t* block, /*!< in/out: page containing split_rec */ 1007 rec_t* split_rec, /*!< in: first record not to move */ 1008 dict_index_t* index, /*!< in: record descriptor */ 1009 mtr_t* mtr); /*!< in: mtr */ 1010 /****************************************************************//** 1011 Splits a directory slot which owns too many records. */ 1012 void 1013 page_dir_split_slot( 1014 /*================*/ 1015 page_t* page, /*!< in: index page */ 1016 page_zip_des_t* page_zip,/*!< in/out: compressed page whose 1017 uncompressed part will be written, or NULL */ 1018 ulint slot_no);/*!< in: the directory slot */ 1019 /*************************************************************//** 1020 Tries to balance the given directory slot with too few records 1021 with the upper neighbor, so that there are at least the minimum number 1022 of records owned by the slot; this may result in the merging of 1023 two slots. */ 1024 void 1025 page_dir_balance_slot( 1026 /*==================*/ 1027 page_t* page, /*!< in/out: index page */ 1028 page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */ 1029 ulint slot_no);/*!< in: the directory slot */ 1030 /**********************************************************//** 1031 Parses a log record of a record list end or start deletion. 1032 @return end of log record or NULL */ 1033 byte* 1034 page_parse_delete_rec_list( 1035 /*=======================*/ 1036 mlog_id_t type, /*!< in: MLOG_LIST_END_DELETE, 1037 MLOG_LIST_START_DELETE, 1038 MLOG_COMP_LIST_END_DELETE or 1039 MLOG_COMP_LIST_START_DELETE */ 1040 byte* ptr, /*!< in: buffer */ 1041 byte* end_ptr,/*!< in: buffer end */ 1042 buf_block_t* block, /*!< in/out: buffer block or NULL */ 1043 dict_index_t* index, /*!< in: record descriptor */ 1044 mtr_t* mtr); /*!< in: mtr or NULL */ 1045 /** Parses a redo log record of creating a page. 1046 @param[in,out] block buffer block, or NULL 1047 @param[in] comp nonzero=compact page format 1048 @param[in] is_rtree whether it is rtree page */ 1049 void 1050 page_parse_create( 1051 buf_block_t* block, 1052 ulint comp, 1053 bool is_rtree); 1054 #ifndef UNIV_HOTBACKUP 1055 /************************************************************//** 1056 Prints record contents including the data relevant only in 1057 the index page context. */ 1058 void 1059 page_rec_print( 1060 /*===========*/ 1061 const rec_t* rec, /*!< in: physical record */ 1062 const ulint* offsets);/*!< in: record descriptor */ 1063 # ifdef UNIV_BTR_PRINT 1064 /***************************************************************//** 1065 This is used to print the contents of the directory for 1066 debugging purposes. */ 1067 void 1068 page_dir_print( 1069 /*===========*/ 1070 page_t* page, /*!< in: index page */ 1071 ulint pr_n); /*!< in: print n first and n last entries */ 1072 /***************************************************************//** 1073 This is used to print the contents of the page record list for 1074 debugging purposes. */ 1075 void 1076 page_print_list( 1077 /*============*/ 1078 buf_block_t* block, /*!< in: index page */ 1079 dict_index_t* index, /*!< in: dictionary index of the page */ 1080 ulint pr_n); /*!< in: print n first and n last entries */ 1081 /***************************************************************//** 1082 Prints the info in a page header. */ 1083 void 1084 page_header_print( 1085 /*==============*/ 1086 const page_t* page); /*!< in: index page */ 1087 /***************************************************************//** 1088 This is used to print the contents of the page for 1089 debugging purposes. */ 1090 void 1091 page_print( 1092 /*=======*/ 1093 buf_block_t* block, /*!< in: index page */ 1094 dict_index_t* index, /*!< in: dictionary index of the page */ 1095 ulint dn, /*!< in: print dn first and last entries 1096 in directory */ 1097 ulint rn); /*!< in: print rn first and last records 1098 in directory */ 1099 # endif /* UNIV_BTR_PRINT */ 1100 #endif /* !UNIV_HOTBACKUP */ 1101 /***************************************************************//** 1102 The following is used to validate a record on a page. This function 1103 differs from rec_validate as it can also check the n_owned field and 1104 the heap_no field. 1105 @return TRUE if ok */ 1106 ibool 1107 page_rec_validate( 1108 /*==============*/ 1109 const rec_t* rec, /*!< in: physical record */ 1110 const ulint* offsets);/*!< in: array returned by rec_get_offsets() */ 1111 #ifdef UNIV_DEBUG 1112 /***************************************************************//** 1113 Checks that the first directory slot points to the infimum record and 1114 the last to the supremum. This function is intended to track if the 1115 bug fixed in 4.0.14 has caused corruption to users' databases. */ 1116 void 1117 page_check_dir( 1118 /*===========*/ 1119 const page_t* page); /*!< in: index page */ 1120 #endif /* UNIV_DEBUG */ 1121 /***************************************************************//** 1122 This function checks the consistency of an index page when we do not 1123 know the index. This is also resilient so that this should never crash 1124 even if the page is total garbage. 1125 @return TRUE if ok */ 1126 ibool 1127 page_simple_validate_old( 1128 /*=====================*/ 1129 const page_t* page); /*!< in: index page in ROW_FORMAT=REDUNDANT */ 1130 /***************************************************************//** 1131 This function checks the consistency of an index page when we do not 1132 know the index. This is also resilient so that this should never crash 1133 even if the page is total garbage. 1134 @return TRUE if ok */ 1135 ibool 1136 page_simple_validate_new( 1137 /*=====================*/ 1138 const page_t* page); /*!< in: index page in ROW_FORMAT!=REDUNDANT */ 1139 /***************************************************************//** 1140 This function checks the consistency of an index page. 1141 @return TRUE if ok */ 1142 ibool 1143 page_validate( 1144 /*==========*/ 1145 const page_t* page, /*!< in: index page */ 1146 dict_index_t* index); /*!< in: data dictionary index containing 1147 the page record type definition */ 1148 /***************************************************************//** 1149 Looks in the page record list for a record with the given heap number. 1150 @return record, NULL if not found */ 1151 const rec_t* 1152 page_find_rec_with_heap_no( 1153 /*=======================*/ 1154 const page_t* page, /*!< in: index page */ 1155 ulint heap_no);/*!< in: heap number */ 1156 /** Get the last non-delete-marked record on a page. 1157 @param[in] page index tree leaf page 1158 @return the last record, not delete-marked 1159 @retval infimum record if all records are delete-marked */ 1160 const rec_t* 1161 page_find_rec_max_not_deleted( 1162 const page_t* page); 1163 1164 /** Issue a warning when the checksum that is stored in the page is valid, 1165 but different than the global setting innodb_checksum_algorithm. 1166 @param[in] current_algo current checksum algorithm 1167 @param[in] page_checksum page valid checksum 1168 @param[in] page_id page identifier */ 1169 void 1170 page_warn_strict_checksum( 1171 srv_checksum_algorithm_t curr_algo, 1172 srv_checksum_algorithm_t page_checksum, 1173 const page_id_t& page_id); 1174 1175 /** This function checks if the page in which record is present is a 1176 non-leaf node of a spatial index. 1177 param[in] rec Btree record 1178 param[in] index index 1179 @return TRUE if ok */ 1180 bool page_is_spatial_non_leaf( 1181 /*==========================*/ 1182 const rec_t* rec,/*!< in: Btree record */ 1183 dict_index_t* index);/*!< in: index */ 1184 1185 #ifdef UNIV_MATERIALIZE 1186 #undef UNIV_INLINE 1187 #define UNIV_INLINE UNIV_INLINE_ORIGINAL 1188 #endif 1189 1190 #endif /* !UNIV_INNOCHECKSUM */ 1191 #ifndef UNIV_NONINL 1192 #include "page0page.ic" 1193 #endif 1194 1195 #endif 1196