1 /***************************************************************************** 2 3 Copyright (c) 2016, 2019, Oracle and/or its affiliates. All Rights Reserved. 4 5 This program is free software; you can redistribute it and/or modify it under 6 the terms of the GNU General Public License, version 2.0, as published by the 7 Free Software Foundation. 8 9 This program is also distributed with certain software (including but not 10 limited to OpenSSL) that is licensed under separate terms, as designated in a 11 particular file or component or in included license documentation. The authors 12 of MySQL hereby grant you an additional permission to link the program and 13 your derivative works with the separately licensed software that they have 14 included with MySQL. 15 16 This program is distributed in the hope that it will be useful, but WITHOUT 17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, 19 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 St, Fifth Floor, Boston, MA 02110-1301 USA 24 25 *****************************************************************************/ 26 #ifndef zlob0first_h 27 #define zlob0first_h 28 29 #include "fil0types.h" 30 #include "fut0lst.h" 31 #include "lob0impl.h" 32 #include "univ.i" 33 34 namespace lob { 35 36 /** The first page of an zlob. */ 37 struct z_first_page_t { 38 /** Version information. One byte. */ 39 static const ulint OFFSET_VERSION = FIL_PAGE_DATA; 40 41 /** One byte of flag bits. Currently only one bit (the least 42 significant bit) is used, other 7 bits are available for future use.*/ 43 static const ulint OFFSET_FLAGS = FIL_PAGE_DATA + 1; 44 45 /** LOB version. 4 bytes.*/ 46 static const uint32_t OFFSET_LOB_VERSION = OFFSET_FLAGS + 1; 47 48 /** The last transaction that modified this LOB. */ 49 static const ulint OFFSET_LAST_TRX_ID = OFFSET_LOB_VERSION + 4; 50 51 /** The last transaction that modified this LOB. */ 52 static const ulint OFFSET_LAST_UNDO_NO = OFFSET_LAST_TRX_ID + 6; 53 54 /** The length of compressed data stored in this page. */ 55 static const ulint OFFSET_DATA_LEN = OFFSET_LAST_UNDO_NO + 4; 56 57 /** The transaction that created data in the data portion. */ 58 static const ulint OFFSET_TRX_ID = OFFSET_DATA_LEN + 4; 59 60 /** The next index page. */ 61 static const ulint OFFSET_INDEX_PAGE_NO = OFFSET_TRX_ID + 6; 62 63 /** The next frag nodes page. */ 64 static const ulint OFFSET_FRAG_NODES_PAGE_NO = OFFSET_INDEX_PAGE_NO + 4; 65 66 /** List of free index entries. */ 67 static const ulint OFFSET_FREE_LIST = OFFSET_FRAG_NODES_PAGE_NO + 4; 68 69 /** List of index entries. */ 70 static const ulint OFFSET_INDEX_LIST = OFFSET_FREE_LIST + FLST_BASE_NODE_SIZE; 71 72 /** List of free frag entries. */ 73 static const ulint OFFSET_FREE_FRAG_LIST = 74 OFFSET_INDEX_LIST + FLST_BASE_NODE_SIZE; 75 76 /** List of frag entries. */ 77 static const ulint OFFSET_FRAG_LIST = 78 OFFSET_FREE_FRAG_LIST + FLST_BASE_NODE_SIZE; 79 80 /** Begin of index entries. */ 81 static const ulint OFFSET_INDEX_BEGIN = 82 OFFSET_FRAG_LIST + FLST_BASE_NODE_SIZE; 83 84 /** Given the page size, what is the number of index entries the 85 first page can contain. */ 86 ulint get_n_index_entries() const; 87 88 /** Given the page size, what is the number of frag entries the 89 first page can contain. */ 90 ulint get_n_frag_entries() const; 91 92 ulint size_of_index_entries() const; 93 size_of_frag_entriesz_first_page_t94 ulint size_of_frag_entries() const { 95 return (z_frag_entry_t::SIZE * get_n_frag_entries()); 96 } 97 begin_frag_entriesz_first_page_t98 ulint begin_frag_entries() const { 99 return (OFFSET_INDEX_BEGIN + size_of_index_entries()); 100 } 101 begin_dataz_first_page_t102 ulint begin_data() const { 103 return (begin_frag_entries() + size_of_frag_entries()); 104 } 105 is_emptyz_first_page_t106 bool is_empty() const { 107 flst_base_node_t *flst = index_list(); 108 return (flst_get_len(flst) == 0); 109 } 110 111 /** Get the length of the index list. 112 @return length of the index list. */ get_index_list_lengthz_first_page_t113 ulint get_index_list_length() const { 114 flst_base_node_t *flst = index_list(); 115 return (flst_get_len(flst)); 116 } 117 set_version_0z_first_page_t118 void set_version_0() { 119 mlog_write_ulint(frame() + OFFSET_VERSION, 0, MLOG_1BYTE, m_mtr); 120 } 121 begin_data_ptrz_first_page_t122 byte *begin_data_ptr() const { return (frame() + begin_data()); } 123 124 /** Amount of zlob data that can be stored in first page (in bytes). */ payloadz_first_page_t125 ulint payload() { 126 page_size_t page_size(dict_table_page_size(m_index->table)); 127 ut_ad(begin_data() + FIL_PAGE_DATA_END < page_size.physical()); 128 return (page_size.physical() - begin_data() - FIL_PAGE_DATA_END); 129 } 130 z_first_page_tz_first_page_t131 z_first_page_t() : m_block(nullptr), m_mtr(nullptr), m_index(nullptr) {} 132 z_first_page_tz_first_page_t133 z_first_page_t(mtr_t *mtr, dict_index_t *index) 134 : m_block(nullptr), m_mtr(mtr), m_index(index) {} 135 z_first_page_tz_first_page_t136 z_first_page_t(buf_block_t *block) : m_block(block) {} 137 z_first_page_tz_first_page_t138 z_first_page_t(buf_block_t *block, mtr_t *mtr, dict_index_t *index) 139 : m_block(block), m_mtr(mtr), m_index(index) {} 140 141 buf_block_t *alloc(bool bulk); 142 143 void import(trx_id_t trx_id); 144 get_page_typez_first_page_t145 page_type_t get_page_type() const { 146 return (mach_read_from_2(frame() + FIL_PAGE_TYPE)); 147 } 148 149 /** Load the given page number as the first page in x-latch mode. 150 @param[in] page_no the first page number. 151 @return the buffer block of the given page number. */ load_xz_first_page_t152 buf_block_t *load_x(page_no_t page_no) { 153 page_id_t page_id(dict_index_get_space(m_index), page_no); 154 page_size_t page_size(dict_table_page_size(m_index->table)); 155 m_block = buf_page_get(page_id, page_size, RW_X_LATCH, m_mtr); 156 return (m_block); 157 } 158 159 /** Load the first page using given mini transaction. The first page must 160 already be x-latched by the m_mtr. 161 @param[in] mtr the mini transaction in which first page is to be loaded. 162 @return the buffer block of first page. */ load_xz_first_page_t163 buf_block_t *load_x(mtr_t *mtr) const { 164 ut_ad(mtr_memo_contains(m_mtr, m_block, MTR_MEMO_PAGE_X_FIX)); 165 buf_block_t *tmp = buf_page_get(m_block->page.id, m_index->get_page_size(), 166 RW_X_LATCH, mtr); 167 ut_ad(tmp == m_block); 168 return (tmp); 169 } 170 171 /** Load the first page of the compressed LOB with x-latch. 172 @param[in] page_id the page identifier of first page 173 @param[in] page_size the page size information of table. 174 @return buffer block of the first page. */ 175 buf_block_t *load_x(const page_id_t &page_id, const page_size_t &page_size); 176 177 /** Load the given page number as the first page in s-latch mode. 178 @param[in] page_no the first page number. 179 @return the buffer block of the given page number. */ load_sz_first_page_t180 buf_block_t *load_s(page_no_t page_no) { 181 ut_ad(m_block == nullptr); 182 183 page_id_t page_id(dict_index_get_space(m_index), page_no); 184 page_size_t page_size(dict_table_page_size(m_index->table)); 185 m_block = buf_page_get(page_id, page_size, RW_S_LATCH, m_mtr); 186 return (m_block); 187 } 188 189 /** Deallocate the first page of a compressed LOB. */ 190 void dealloc(); 191 192 /** Set the FIL_PAGE_NEXT to FIL_NULL. */ set_next_page_nullz_first_page_t193 void set_next_page_null() { set_next_page_no(FIL_NULL, m_mtr); } 194 195 /** Set the FIL_PAGE_PREV to FIL_NULL. */ set_prev_page_nullz_first_page_t196 void set_prev_page_null() { set_prev_page_no(FIL_NULL, m_mtr); } 197 198 /** Set the FIL_PAGE_NEXT to the given value. 199 @param[in] page_no the page number to set in FIL_PAGE_NEXT. 200 @param[in] mtr mini trx to be used for this modification. */ set_next_page_noz_first_page_t201 void set_next_page_no(page_no_t page_no, mtr_t *mtr) { 202 ut_ad(mtr != nullptr); 203 mlog_write_ulint(frame() + FIL_PAGE_NEXT, page_no, MLOG_4BYTES, mtr); 204 } 205 206 /** Set the FIL_PAGE_PREV to the given value. 207 @param[in] page_no the page number to set in FIL_PAGE_PREV. 208 @param[in] mtr mini trx to be used for this modification. */ set_prev_page_noz_first_page_t209 void set_prev_page_no(page_no_t page_no, mtr_t *mtr) { 210 ut_ad(mtr != nullptr); 211 mlog_write_ulint(frame() + FIL_PAGE_PREV, page_no, MLOG_4BYTES, mtr); 212 } 213 214 /** Write the space identifier to the page header, without generating 215 redo log records. 216 @param[in] space_id the space identifier. */ set_space_id_no_redoz_first_page_t217 void set_space_id_no_redo(space_id_t space_id) { 218 mlog_write_ulint(frame() + FIL_PAGE_SPACE_ID, space_id, MLOG_4BYTES, 219 nullptr); 220 } 221 initz_first_page_t222 void init() { 223 ut_ad(m_mtr != nullptr); 224 225 set_page_type(); 226 set_version_0(); 227 set_data_len(0); 228 set_next_page_null(); 229 set_prev_page_null(); 230 set_trx_id(0); 231 flst_base_node_t *flst = free_list(); 232 flst_init(flst, m_mtr); 233 flst_base_node_t *ilst = index_list(); 234 flst_init(ilst, m_mtr); 235 flst_base_node_t *free_frag_lst = free_frag_list(); 236 flst_init(free_frag_lst, m_mtr); 237 flst_base_node_t *frag_lst = frag_list(); 238 flst_init(frag_lst, m_mtr); 239 init_index_entries(); 240 init_frag_entries(); 241 set_frag_node_page_no(FIL_NULL); 242 set_index_page_no(FIL_NULL); 243 } 244 245 /** Get the amount of zlob data stored in this page. */ get_data_lenz_first_page_t246 ulint get_data_len() const { 247 return (mach_read_from_4(frame() + OFFSET_DATA_LEN)); 248 } 249 250 /** Get the page number. */ get_page_noz_first_page_t251 page_no_t get_page_no() const { return (m_block->page.id.page_no()); } 252 253 /** Get the page id of the first page of compressed LOB. 254 @return page id of the first page of compressed LOB. */ get_page_idz_first_page_t255 page_id_t get_page_id() const { 256 ut_ad(m_block != nullptr); 257 258 return (m_block->page.id); 259 } 260 get_self_addrz_first_page_t261 fil_addr_t get_self_addr() const { 262 page_no_t page_no = get_page_no(); 263 uint32_t offset = static_cast<uint32_t>(begin_data()); 264 return (fil_addr_t(page_no, offset)); 265 } 266 267 /** All the index pages are singled linked with each other, and 268 the first page contains the link to one index page. 269 @param[in] page_no the page number of an index page. */ set_index_page_noz_first_page_t270 void set_index_page_no(page_no_t page_no) { 271 ut_ad(m_mtr != nullptr); 272 mlog_write_ulint(frame() + OFFSET_INDEX_PAGE_NO, page_no, MLOG_4BYTES, 273 m_mtr); 274 } 275 276 /** All the index pages are singled linked with each other, and 277 the first page contains the link to one index page. Get that index 278 page number. 279 @return the index page number. */ get_index_page_noz_first_page_t280 page_no_t get_index_page_no() const { 281 return (mach_read_from_4(frame() + OFFSET_INDEX_PAGE_NO)); 282 } 283 284 /** All the fragment pages are doubly linked with each other, and 285 the first page contains the link to one fragment page in FIL_PAGE_PREV. Get 286 that frag page number. 287 @return the frag page number. */ get_frag_page_noz_first_page_t288 page_no_t get_frag_page_no() const { return (m_block->get_prev_page_no()); } 289 290 /** All the fragment pages are doubly linked with each other, and 291 the first page contains the link to one fragment page in FIL_PAGE_PREV. Get 292 that frag page number. 293 @param[in] mtr mini transaction to use for this read operation. 294 @return the frag page number. */ get_frag_page_noz_first_page_t295 page_no_t get_frag_page_no(mtr_t *mtr) const { 296 return (mtr_read_ulint(frame() + FIL_PAGE_PREV, MLOG_4BYTES, mtr)); 297 } 298 299 #ifdef UNIV_DEBUG 300 /** Verify that the page number pointed to by FIL_PAGE_PREV of the first page 301 of LOB is indeed a fragment page. It uses its own mtr internally. 302 @return true if it is a fragment page, false otherwise. */ 303 bool verify_frag_page_no(); 304 #endif /* UNIV_DEBUG */ 305 306 /** All the fragment pages are doubly linked with each other, and 307 the first page contains the link to one fragment page in FIL_PAGE_PREV. 308 @param[in] mtr mini transaction for this modification. 309 @param[in] page_no the page number of a fragment page. */ set_frag_page_noz_first_page_t310 void set_frag_page_no(mtr_t *mtr, page_no_t page_no) { 311 ut_ad(verify_frag_page_no()); 312 set_prev_page_no(page_no, mtr); 313 } 314 315 /** All the fragment pages are doubly linked with each other, and 316 the first page contains the link to one fragment page in FIL_PAGE_PREV. 317 @param[in] page_no the page number of a fragment page. */ set_frag_page_noz_first_page_t318 void set_frag_page_no(page_no_t page_no) { 319 ut_ad(verify_frag_page_no()); 320 set_prev_page_no(page_no, m_mtr); 321 } 322 323 /** All the frag node pages are singled linked with each other, and 324 the first page contains the link to one frag node page. 325 @param[in] page_no the page number of an frag node page. */ set_frag_node_page_noz_first_page_t326 void set_frag_node_page_no(page_no_t page_no) { 327 ut_ad(m_mtr != nullptr); 328 mlog_write_ulint(frame() + OFFSET_FRAG_NODES_PAGE_NO, page_no, MLOG_4BYTES, 329 m_mtr); 330 } 331 332 /** Free all the z_frag_page_t pages. All the z_frag_page_t pages are 333 singly linked to each other. The head of the list is maintained in the 334 first page. 335 @return the number of pages freed. */ 336 size_t free_all_frag_node_pages(); 337 338 /** Free all the index pages. 339 @return the number of pages freed. */ 340 size_t free_all_index_pages(); 341 342 /** Free all the fragment pages. 343 @return the number of pages freed. */ 344 size_t free_all_frag_pages(); 345 346 private: 347 /** Free all the fragment pages when the next page of the first LOB page IS 348 * NOT USED to link the fragment pages. 349 @return the number of pages freed. */ 350 size_t free_all_frag_pages_old(); 351 352 /** Free all the fragment pages when the next page of the first LOB page IS 353 * USED to link the fragment pages. 354 @return the number of pages freed. */ 355 size_t free_all_frag_pages_new(); 356 357 public: 358 /** Free all the data pages. 359 @return the number of pages freed. */ 360 size_t free_all_data_pages(); 361 362 /** All the frag node pages are singled linked with each other, and the 363 first page contains the link to one frag node page. Get that frag node 364 page number. 365 @return the index page number. */ get_frag_node_page_noz_first_page_t366 page_no_t get_frag_node_page_no() { 367 return (mach_read_from_4(frame() + OFFSET_FRAG_NODES_PAGE_NO)); 368 } 369 370 /** Set the page type to FIL_PAGE_TYPE_UNKNOWN. This is done while 371 deallocating this page. */ set_page_type_unknownz_first_page_t372 void set_page_type_unknown() { 373 ut_ad(m_mtr != nullptr); 374 mlog_write_ulint(frame() + FIL_PAGE_TYPE, FIL_PAGE_TYPE_UNKNOWN, 375 MLOG_2BYTES, m_mtr); 376 } 377 set_page_typez_first_page_t378 void set_page_type() { 379 ut_ad(m_mtr != nullptr); 380 mlog_write_ulint(frame() + FIL_PAGE_TYPE, FIL_PAGE_TYPE_ZLOB_FIRST, 381 MLOG_2BYTES, m_mtr); 382 } 383 set_data_lenz_first_page_t384 void set_data_len(ulint len) { 385 ut_ad(m_mtr != nullptr); 386 mlog_write_ulint(frame() + OFFSET_DATA_LEN, len, MLOG_4BYTES, m_mtr); 387 } 388 389 /** Update the trx id in the header. 390 @param[in] tid the given transaction identifier. */ set_trx_idz_first_page_t391 void set_trx_id(trx_id_t tid) { 392 byte *ptr = frame() + OFFSET_TRX_ID; 393 mach_write_to_6(ptr, tid); 394 mlog_log_string(ptr, 6, m_mtr); 395 } 396 397 /** Update the trx id in the header, without generating redo 398 log records. 399 @param[in] tid the given transaction identifier. */ set_trx_id_no_redoz_first_page_t400 void set_trx_id_no_redo(trx_id_t tid) { 401 byte *ptr = frame() + OFFSET_TRX_ID; 402 mach_write_to_6(ptr, tid); 403 } 404 405 /** Initialize the LOB version to 1. */ init_lob_versionz_first_page_t406 void init_lob_version() { 407 ut_ad(m_mtr != nullptr); 408 409 mlog_write_ulint(frame() + OFFSET_LOB_VERSION, 1, MLOG_4BYTES, m_mtr); 410 } 411 412 /** Get the LOB version 413 @return the LOB version. */ get_lob_versionz_first_page_t414 uint32_t get_lob_version() { 415 return (mach_read_from_4(frame() + OFFSET_LOB_VERSION)); 416 } 417 418 /** Increment LOB version by 1. */ 419 uint32_t incr_lob_version(); 420 421 /** Get one byte of flags 422 @return one byte of flags. */ get_flagsz_first_page_t423 uint8_t get_flags() { return (mach_read_from_1(frame() + OFFSET_FLAGS)); } 424 425 /** When the bit is set, the LOB is not partially updatable anymore. 426 @return true, if partially updatable. 427 @return false, if partially NOT updatable. */ can_be_partially_updatedz_first_page_t428 bool can_be_partially_updated() { 429 uint8_t flags = get_flags(); 430 return (!(flags & 0x01)); 431 } 432 433 /** When the bit is set, the LOB is not partially updatable anymore. 434 Enable the bit. 435 @param[in] trx the current transaction.*/ 436 void mark_cannot_be_partially_updated(trx_t *trx); 437 set_last_trx_idz_first_page_t438 void set_last_trx_id(trx_id_t tid) { 439 byte *ptr = frame() + OFFSET_LAST_TRX_ID; 440 mach_write_to_6(ptr, tid); 441 mlog_log_string(ptr, 6, m_mtr); 442 } 443 444 /** Update the last transaction identifier in the header, without 445 generating redo logs. 446 @param[in] tid given transaction identifier.*/ set_last_trx_id_no_redoz_first_page_t447 void set_last_trx_id_no_redo(trx_id_t tid) { 448 byte *ptr = frame() + OFFSET_LAST_TRX_ID; 449 mach_write_to_6(ptr, tid); 450 } 451 set_last_trx_undo_noz_first_page_t452 void set_last_trx_undo_no(undo_no_t undo_no) { 453 ut_ad(m_mtr != nullptr); 454 455 byte *ptr = frame() + OFFSET_LAST_UNDO_NO; 456 mlog_write_ulint(ptr, undo_no, MLOG_4BYTES, m_mtr); 457 } 458 get_last_trx_idz_first_page_t459 trx_id_t get_last_trx_id() const { 460 byte *ptr = frame() + OFFSET_LAST_TRX_ID; 461 return (mach_read_from_6(ptr)); 462 } 463 get_last_trx_undo_noz_first_page_t464 undo_no_t get_last_trx_undo_no() const { 465 byte *ptr = frame() + OFFSET_LAST_UNDO_NO; 466 return (mach_read_from_4(ptr)); 467 } 468 free_listz_first_page_t469 flst_base_node_t *free_list() const { return (frame() + OFFSET_FREE_LIST); } 470 index_listz_first_page_t471 flst_base_node_t *index_list() const { return (frame() + OFFSET_INDEX_LIST); } 472 free_frag_listz_first_page_t473 flst_base_node_t *free_frag_list() const { 474 return (frame() + OFFSET_FREE_FRAG_LIST); 475 } 476 frag_listz_first_page_t477 flst_base_node_t *frag_list() const { return (frame() + OFFSET_FRAG_LIST); } 478 init_frag_entriesz_first_page_t479 void init_frag_entries() { 480 flst_base_node_t *free_frag_lst = free_frag_list(); 481 ulint n = get_n_frag_entries(); 482 for (ulint i = 0; i < n; ++i) { 483 flst_node_t *ptr = frame() + begin_frag_entries(); 484 ptr += (i * z_frag_entry_t::SIZE); 485 z_frag_entry_t frag_entry(ptr, m_mtr); 486 frag_entry.init(); 487 frag_entry.push_back(free_frag_lst); 488 } 489 } 490 491 void init_index_entries(); 492 493 /** Allocate a fragment of the given size. This involves finding a 494 fragment page, that has space to store len bytes of data. If necessary, 495 allocate a new fragment page. 496 @param[in] bulk true if it is bulk operation 497 (OPCODE_INSERT_BULK), false otherwise. 498 @param[in] len length of data to be stored in 499 fragment page. 500 @param[out] frag_page the fragment page with the needed 501 free space. 502 @param[out] entry fragment page entry representing frag_page. 503 @return fragment identifier within the fragment page. 504 @return FRAG_ID_NULL if fragment could not be allocated. */ 505 frag_id_t alloc_fragment(bool bulk, ulint len, z_frag_page_t &frag_page, 506 z_frag_entry_t &entry); 507 508 /** Allocate one index entry. If there is no free index entry, 509 allocate an index page (a page full of z_index_entry_t objects) 510 and service the request. 511 @return the allocated index entry. */ 512 z_index_entry_t alloc_index_entry(bool bulk); 513 514 /** Allocate one frag page entry. If there is no free frag 515 entry, allocate an frag node page (a page full of z_frag_entry_t 516 objects) and service the request. 517 @return the allocated frag entry. */ 518 z_frag_entry_t alloc_frag_entry(bool bulk); 519 520 /** Print the index entries. */ 521 std::ostream &print_index_entries(std::ostream &out) const; 522 523 /** Print the index entries. */ 524 std::ostream &print_frag_entries(std::ostream &out) const; 525 526 /** Print the page. */ 527 std::ostream &print(std::ostream &out) const; 528 framez_first_page_t529 byte *frame() const { return (buf_block_get_frame(m_block)); } 530 531 /** Load the page, in x-latch mode, containing the given file address. 532 @param[in] addr given file address 533 @return the file list node pointer. */ addr2ptr_xz_first_page_t534 flst_node_t *addr2ptr_x(fil_addr_t &addr) const { 535 return (addr2ptr_x(addr, m_mtr)); 536 } 537 538 /** Load the page, in x-latch mode, containing the given file address. 539 @param[in] addr given file address 540 @param[in] mtr the mini transaction context to be used. 541 @return the file list node pointer. */ addr2ptr_xz_first_page_t542 flst_node_t *addr2ptr_x(fil_addr_t &addr, mtr_t *mtr) const { 543 space_id_t space = dict_index_get_space(m_index); 544 const page_size_t page_size = dict_table_page_size(m_index->table); 545 return (fut_get_ptr(space, page_size, addr, RW_X_LATCH, mtr)); 546 } 547 548 /** Load the page, in s-latch mode, containing the given file address. 549 @param[in] addr given file address 550 @return the file list node pointer. */ addr2ptr_sz_first_page_t551 flst_node_t *addr2ptr_s(fil_addr_t &addr) { 552 space_id_t space = dict_index_get_space(m_index); 553 const page_size_t page_size = dict_table_page_size(m_index->table); 554 return (fut_get_ptr(space, page_size, addr, RW_S_LATCH, m_mtr)); 555 } 556 557 /** Load the entry available in the given file address. 558 @param[in] addr file address 559 @param[out] entry the entry to be loaded.*/ 560 void load_entry_s(fil_addr_t &addr, z_index_entry_t &entry); 561 562 /** Load the entry available in the given file address. 563 @param[in] addr file address 564 @param[out] entry the entry to be loaded.*/ 565 void load_entry_x(fil_addr_t &addr, z_index_entry_t &entry); 566 567 /** Free all the pages of the zlob. 568 @return the total number of pages freed. */ 569 size_t destroy(); 570 571 #ifdef UNIV_DEBUG 572 private: 573 /** Validate the LOB. This is a costly function. We need to avoid using 574 this directly, instead call z_first_page_t::validate(). 575 @return true if valid, false otherwise. */ 576 bool validate_low(); 577 578 public: 579 /** Validate the LOB. 580 @return true if valid, false otherwise. */ validatez_first_page_t581 bool validate() { 582 static const uint32_t FREQ = 50; 583 static std::atomic<uint32_t> n{0}; 584 585 bool valid = true; 586 if (++n % FREQ == 0) { 587 valid = validate_low(); 588 } 589 return (valid); 590 } 591 #endif /* UNIV_DEBUG */ 592 593 /** Get the buffer block of the first page of LOB. 594 @return the buffer block of the first page of LOB. */ get_blockz_first_page_t595 buf_block_t *get_block() const { return (m_block); } 596 597 public: set_mtrz_first_page_t598 void set_mtr(mtr_t *mtr) { m_mtr = mtr; } 599 600 /** Restart the given mtr. The first page must already be x-latched by the 601 m_mtr. 602 @param[in] mtr the mini transaction context which is to be restarted. */ restart_mtrz_first_page_t603 void restart_mtr(mtr_t *mtr) { 604 ut_ad(mtr != m_mtr); 605 606 mtr_commit(mtr); 607 mtr_start(mtr); 608 mtr->set_log_mode(m_mtr->get_log_mode()); 609 load_x(mtr); 610 } 611 612 private: 613 /** The buffer block of the first page. */ 614 buf_block_t *m_block; 615 616 /** The mini-transaction context. */ 617 mtr_t *m_mtr; 618 619 /** The index dictionary object. */ 620 dict_index_t *m_index; 621 622 }; // struct z_first_page_t 623 624 /** Overloading the global output parameter to print object of type 625 z_first_page_t into the given output stream. 626 @param[in,out] out output stream. 627 @param[in] obj object to be printed. 628 @return the output stream. */ 629 inline std::ostream &operator<<(std::ostream &out, const z_first_page_t &obj) { 630 return (obj.print(out)); 631 } 632 633 } /* namespace lob */ 634 635 #endif /* zlob0first_h */ 636