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 zlob0index_h 27 #define zlob0index_h 28 29 #include "fil0fil.h" 30 #include "fut0lst.h" 31 #include "lob0impl.h" 32 33 namespace lob { 34 35 /** In-memory copy of the information from z_index_entry_t. */ 36 struct z_index_entry_mem_t { z_index_entry_mem_tz_index_entry_mem_t37 z_index_entry_mem_t() 38 : m_trx_id(0), m_z_page_no(FIL_NULL), m_z_frag_id(FRAG_ID_NULL) {} 39 40 /** The location of this index entry node. */ 41 fil_addr_t m_self; 42 43 fil_addr_t m_prev; 44 fil_addr_t m_next; 45 flst_bnode_t m_versions; 46 trx_id_t m_trx_id; 47 trx_id_t m_trx_id_modifier; 48 undo_no_t m_trx_undo_no; 49 undo_no_t m_trx_undo_no_modifier; 50 page_no_t m_z_page_no; 51 frag_id_t m_z_frag_id; 52 53 /** Uncompressed data length. */ 54 ulint m_data_len; 55 56 /** Compressed data length. */ 57 ulint m_z_data_len; 58 59 std::ostream &print(std::ostream &out) const; 60 61 /** Initialize all the members. */ resetz_index_entry_mem_t62 void reset() { 63 m_self = fil_addr_null; 64 m_prev = fil_addr_null; 65 m_next = fil_addr_null; 66 m_versions.reset(); 67 m_trx_id = 0; 68 m_trx_id_modifier = 0; 69 m_trx_undo_no = 0; 70 m_trx_undo_no_modifier = 0; 71 m_z_page_no = FIL_NULL; 72 m_z_frag_id = 0; 73 m_data_len = 0; 74 m_z_data_len = 0; 75 } 76 is_nullz_index_entry_mem_t77 bool is_null() { return (m_self.is_equal(fil_addr_null)); } 78 }; 79 80 inline std::ostream &operator<<(std::ostream &out, 81 const z_index_entry_mem_t &obj) { 82 return (obj.print(out)); 83 } 84 85 /** An index entry pointing to one zlib stream. */ 86 struct z_index_entry_t { 87 /** Offset with index entry pointing to the prev index entry. */ 88 static const ulint OFFSET_PREV = 0; 89 90 /** Offset with index entry pointing to the next index entry. */ 91 static const ulint OFFSET_NEXT = OFFSET_PREV + FIL_ADDR_SIZE; 92 93 /** Offset within index entry pointing to base node of list of 94 versions.*/ 95 static const ulint OFFSET_VERSIONS = OFFSET_NEXT + FIL_ADDR_SIZE; 96 97 /** Offset within index entry pointing to creator trxid.*/ 98 static const ulint OFFSET_TRXID = OFFSET_VERSIONS + FLST_BASE_NODE_SIZE; 99 100 /** The modifier trx id. */ 101 static const ulint OFFSET_TRXID_MODIFIER = OFFSET_TRXID + 6; 102 103 /** Offset within index entry pointing to trx undo no.*/ 104 static const ulint OFFSET_TRX_UNDO_NO = OFFSET_TRXID_MODIFIER + 6; 105 106 /** Offset within index entry pointing to modifier trx undo no.*/ 107 static const ulint OFFSET_TRX_UNDO_NO_MODIFIER = OFFSET_TRX_UNDO_NO + 4; 108 109 /** Offset within index entry pointing to page number where zlib 110 stream starts. This could be a data page or a fragment page. */ 111 static const ulint OFFSET_Z_PAGE_NO = OFFSET_TRX_UNDO_NO_MODIFIER + 4; 112 113 /** Offset within index entry pointing to location of zlib stream.*/ 114 static const ulint OFFSET_Z_FRAG_ID = OFFSET_Z_PAGE_NO + 4; 115 116 /** Offset within index entry pointing to uncompressed data 117 len (bytes).*/ 118 static const ulint OFFSET_DATA_LEN = OFFSET_Z_FRAG_ID + 2; 119 120 /** Offset within index entry pointing to compressed data len 121 (bytes).*/ 122 static const ulint OFFSET_ZDATA_LEN = OFFSET_DATA_LEN + 4; 123 124 /** LOB version */ 125 static const ulint OFFSET_LOB_VERSION = OFFSET_ZDATA_LEN + 4; 126 127 /** Total size of one index entry. */ 128 static const ulint SIZE = OFFSET_LOB_VERSION + 4; 129 130 /** Constructor. */ z_index_entry_tz_index_entry_t131 z_index_entry_t(flst_node_t *node, mtr_t *mtr) : m_node(node), m_mtr(mtr) {} 132 133 /** Constructor. */ z_index_entry_tz_index_entry_t134 z_index_entry_t(flst_node_t *node, mtr_t *mtr, dict_index_t *index) 135 : m_node(node), m_mtr(mtr), m_index(index) {} 136 137 /** Constructor 138 @param[in] mtr the mini transaction 139 @param[in] index the clustered index to which LOB belongs. */ z_index_entry_tz_index_entry_t140 z_index_entry_t(mtr_t *mtr, dict_index_t *index) 141 : m_node(nullptr), 142 m_mtr(mtr), 143 m_index(index), 144 m_block(nullptr), 145 m_page_no(FIL_NULL) {} 146 147 /** Constructor 148 @param[in] node the location where index entry starts. */ z_index_entry_tz_index_entry_t149 z_index_entry_t(flst_node_t *node) 150 : m_node(node), 151 m_mtr(nullptr), 152 m_index(nullptr), 153 m_block(nullptr), 154 m_page_no(FIL_NULL) {} 155 156 /** Default constructor */ z_index_entry_tz_index_entry_t157 z_index_entry_t() 158 : m_node(nullptr), 159 m_mtr(nullptr), 160 m_index(nullptr), 161 m_block(nullptr), 162 m_page_no(FIL_NULL) {} 163 set_indexz_index_entry_t164 void set_index(dict_index_t *index) { m_index = index; } 165 166 /** Point to another index entry. 167 @param[in] node point to this file list node. */ resetz_index_entry_t168 void reset(flst_node_t *node) { m_node = node; } 169 170 /** Point to another index entry. 171 @param[in] entry another index entry.*/ resetz_index_entry_t172 void reset(const z_index_entry_t &entry) { m_node = entry.m_node; } 173 174 /** Initialize an index entry to some sane value. */ initz_index_entry_t175 void init() { 176 ut_ad(m_mtr != nullptr); 177 178 set_prev_null(); 179 set_next_null(); 180 set_versions_null(); 181 set_trx_id(0); 182 set_trx_undo_no(0); 183 set_z_page_no(FIL_NULL); 184 set_z_frag_id(FRAG_ID_NULL); 185 set_data_len(0); 186 set_zdata_len(0); 187 } 188 189 /** Determine if the current index entry be rolled back. 190 @param[in] trxid the transaction that is being rolled 191 back. 192 @param[in] undo_no the savepoint undo number of trx, 193 upto which rollback happens. 194 @return true if this entry can be rolled back, false otherwise. */ can_rollbackz_index_entry_t195 bool can_rollback(trx_id_t trxid, undo_no_t undo_no) { 196 /* For rollback, make use of creator trx id. */ 197 return ((trxid == get_trx_id()) && (get_trx_undo_no() >= undo_no)); 198 } 199 200 /** Determine if the current index entry be purged. 201 @param[in] trxid the transaction that is being purged. 202 @param[in] undo_no the undo number of trx. 203 @return true if this entry can be purged, false otherwise. */ can_be_purgedz_index_entry_t204 bool can_be_purged(trx_id_t trxid, undo_no_t undo_no) { 205 return ((trxid == get_trx_id_modifier()) && 206 (get_trx_undo_no_modifier() == undo_no)); 207 } 208 209 /** Purge one index entry. 210 @param[in] index index to which LOB belongs. 211 @param[in] trxid purging data belonging to trxid. 212 @param[in] first first page of LOB. 213 @param[in,out] lst list from which this entry will be 214 removed. 215 @param[in,out] free_list list to which this entry will be 216 added.*/ 217 fil_addr_t purge_version(dict_index_t *index, trx_id_t trxid, 218 z_first_page_t &first, flst_base_node_t *lst, 219 flst_base_node_t *free_list); 220 221 /** Purge the current index entry. An index entry points to either a 222 FIRST page or DATA page. That LOB page will be freed if it is DATA 223 page. A FIRST page should not be freed. */ 224 void purge(dict_index_t *index, z_first_page_t &first); 225 226 /** Remove this node from the given list. 227 @param[in] bnode the base node of the list from which to remove 228 current node. */ removez_index_entry_t229 void remove(flst_base_node_t *bnode) { 230 ut_ad(m_mtr != nullptr); 231 232 flst_remove(bnode, m_node, m_mtr); 233 } 234 235 /** Insert the given index entry after the current index entry. 236 @param[in] base the base node of the file based list. 237 @param[in] entry the new node to be inserted.*/ insert_afterz_index_entry_t238 void insert_after(flst_base_node_t *base, z_index_entry_t &entry) { 239 ut_ad(m_mtr != nullptr); 240 241 flst_insert_after(base, m_node, entry.get_node(), m_mtr); 242 } 243 insert_beforez_index_entry_t244 void insert_before(flst_base_node_t *base, z_index_entry_t &entry) { 245 ut_ad(m_mtr != nullptr); 246 247 flst_insert_before(base, entry.get_node(), m_node, m_mtr); 248 } 249 250 /** Add this node as the last node in the given list. 251 @param[in] bnode the base node of the file list. */ push_backz_index_entry_t252 void push_back(flst_base_node_t *bnode) { 253 ut_ad(m_mtr != nullptr); 254 255 flst_add_last(bnode, m_node, m_mtr); 256 } 257 258 /** Add this node as the last node in the given list. 259 @param[in] bnode the base node of the file list. */ push_frontz_index_entry_t260 void push_front(flst_base_node_t *bnode) { 261 ut_ad(m_mtr != nullptr); 262 flst_add_first(bnode, m_node, m_mtr); 263 } 264 265 /** Set the previous index entry as null. */ set_prev_nullz_index_entry_t266 void set_prev_null() { 267 flst_write_addr(m_node + OFFSET_PREV, fil_addr_null, m_mtr); 268 } 269 270 /** Get the location of previous index entry. */ get_prevz_index_entry_t271 fil_addr_t get_prev() const { 272 return (flst_read_addr(m_node + OFFSET_PREV, m_mtr)); 273 } 274 275 /** Get the location of next index entry. 276 @return the file address of the next index entry. */ get_nextz_index_entry_t277 fil_addr_t get_next() const { 278 return (flst_read_addr(m_node + OFFSET_NEXT, m_mtr)); 279 } 280 281 /** Set the next index entry as null. */ set_next_nullz_index_entry_t282 void set_next_null() { 283 ut_ad(m_mtr != nullptr); 284 flst_write_addr(m_node + OFFSET_NEXT, fil_addr_null, m_mtr); 285 } 286 287 /** Set the versions list as null. */ set_versions_nullz_index_entry_t288 void set_versions_null() { 289 flst_base_node_t *bnode = get_versions_list(); 290 flst_init(bnode, m_mtr); 291 } 292 293 /** Get the base node of the list of versions. */ get_versions_listz_index_entry_t294 flst_base_node_t *get_versions_list() const { 295 return (m_node + OFFSET_VERSIONS); 296 } 297 298 /** Get the base node of the list of versions. */ get_versions_memz_index_entry_t299 flst_bnode_t get_versions_mem() const { 300 ut_ad(m_mtr != nullptr); 301 flst_base_node_t *node = get_versions_list(); 302 return (flst_bnode_t(node, m_mtr)); 303 } 304 get_trx_idz_index_entry_t305 trx_id_t get_trx_id() const { 306 return (mach_read_from_6(m_node + OFFSET_TRXID)); 307 } 308 get_trx_id_modifierz_index_entry_t309 trx_id_t get_trx_id_modifier() const { 310 return (mach_read_from_6(m_node + OFFSET_TRXID_MODIFIER)); 311 } 312 313 /** Get the undo number of the creator transaction. This is used 314 for rollback purposes. 315 @return the undo number of creator trx. */ get_trx_undo_noz_index_entry_t316 undo_no_t get_trx_undo_no() const { 317 byte *ptr = m_node + OFFSET_TRX_UNDO_NO; 318 return (mach_read_from_4(ptr)); 319 } 320 321 /** Get the undo number of the modifier transaction. This is used 322 for purging purposes. 323 @return the undo number of modifier trx. */ get_trx_undo_no_modifierz_index_entry_t324 undo_no_t get_trx_undo_no_modifier() const { 325 byte *ptr = m_node + OFFSET_TRX_UNDO_NO_MODIFIER; 326 return (mach_read_from_4(ptr)); 327 } 328 329 /** Set the trx identifier to given value, without generating redo 330 log records. 331 @param[in] id the given trx identifier.*/ set_trx_id_no_redoz_index_entry_t332 void set_trx_id_no_redo(trx_id_t id) { 333 byte *ptr = m_node + OFFSET_TRXID; 334 mach_write_to_6(ptr, id); 335 } 336 337 /** Set the trx identifier to given value. 338 @param[in] id the given trx identifier.*/ set_trx_idz_index_entry_t339 void set_trx_id(trx_id_t id) { 340 ut_ad(m_mtr != nullptr); 341 byte *ptr = m_node + OFFSET_TRXID; 342 mach_write_to_6(ptr, id); 343 mlog_log_string(ptr, 6, m_mtr); 344 } 345 346 /** Set the modifier trxid to the given value. 347 @param[in] id the modifier trxid.*/ set_trx_id_modifierz_index_entry_t348 void set_trx_id_modifier(trx_id_t id) { 349 ut_ad(m_mtr != nullptr); 350 351 byte *ptr = m_node + OFFSET_TRXID_MODIFIER; 352 mach_write_to_6(ptr, id); 353 mlog_log_string(ptr, 6, m_mtr); 354 } 355 356 /** Set the modifier trxid to the given value, without generating 357 redo log records. 358 @param[in] id the modifier trxid.*/ set_trx_id_modifier_no_redoz_index_entry_t359 void set_trx_id_modifier_no_redo(trx_id_t id) { 360 byte *ptr = m_node + OFFSET_TRXID_MODIFIER; 361 mach_write_to_6(ptr, id); 362 } 363 364 /** Set the undo number of the creator trx. 365 @param[in] undo_no the undo number value.*/ set_trx_undo_noz_index_entry_t366 void set_trx_undo_no(undo_no_t undo_no) { 367 ut_ad(m_mtr != nullptr); 368 byte *ptr = m_node + OFFSET_TRX_UNDO_NO; 369 mlog_write_ulint(ptr, undo_no, MLOG_4BYTES, m_mtr); 370 } 371 372 /** Set the undo number of the modifier trx. 373 @param[in] undo_no the undo number value.*/ set_trx_undo_no_modifierz_index_entry_t374 void set_trx_undo_no_modifier(undo_no_t undo_no) { 375 ut_ad(m_mtr != nullptr); 376 byte *ptr = m_node + OFFSET_TRX_UNDO_NO_MODIFIER; 377 mlog_write_ulint(ptr, undo_no, MLOG_4BYTES, m_mtr); 378 } 379 get_z_page_noz_index_entry_t380 page_no_t get_z_page_no() const { 381 return (mach_read_from_4(m_node + OFFSET_Z_PAGE_NO)); 382 } 383 384 /** Set the page number pointed to by this index entry to FIL_NULL. 385 @param[in] mtr The mini transaction used for this modification. */ set_z_page_no_nullz_index_entry_t386 void set_z_page_no_null(mtr_t *mtr) { 387 mlog_write_ulint(m_node + OFFSET_Z_PAGE_NO, FIL_NULL, MLOG_4BYTES, mtr); 388 } 389 390 /** Free the data pages pointed to by this index entry. 391 @param[in] mtr the mini transaction used to free the pages. 392 @return the number of pages freed. */ 393 size_t free_data_pages(mtr_t *mtr); 394 395 /** Set the page number pointed to by this index entry to given value. 396 @param[in] page_no Page number to be put in index entry. */ set_z_page_noz_index_entry_t397 void set_z_page_no(page_no_t page_no) { 398 ut_ad(m_mtr != nullptr); 399 mlog_write_ulint(m_node + OFFSET_Z_PAGE_NO, page_no, MLOG_4BYTES, m_mtr); 400 } 401 get_z_frag_idz_index_entry_t402 page_no_t get_z_frag_id() const { 403 return (mach_read_from_2(m_node + OFFSET_Z_FRAG_ID)); 404 } 405 set_z_frag_idz_index_entry_t406 void set_z_frag_id(frag_id_t id) { 407 ut_ad(m_mtr != nullptr); 408 mlog_write_ulint(m_node + OFFSET_Z_FRAG_ID, id, MLOG_2BYTES, m_mtr); 409 } 410 411 /** Get the uncompressed data length in bytes. */ get_data_lenz_index_entry_t412 ulint get_data_len() const { 413 return (mach_read_from_4(m_node + OFFSET_DATA_LEN)); 414 } 415 416 /** Set the uncompressed data length in bytes. 417 @param[in] len the uncompressed data length in bytes */ set_data_lenz_index_entry_t418 void set_data_len(ulint len) { 419 ut_ad(m_mtr != nullptr); 420 mlog_write_ulint(m_node + OFFSET_DATA_LEN, len, MLOG_4BYTES, m_mtr); 421 } 422 423 /** Get the compressed data length in bytes. */ get_zdata_lenz_index_entry_t424 ulint get_zdata_len() const { 425 return (mach_read_from_4(m_node + OFFSET_ZDATA_LEN)); 426 } 427 428 /** Set the compressed data length in bytes. 429 @param[in] len the compressed data length in bytes */ set_zdata_lenz_index_entry_t430 void set_zdata_len(ulint len) { 431 ut_ad(m_mtr != nullptr); 432 mlog_write_ulint(m_node + OFFSET_ZDATA_LEN, len, MLOG_4BYTES, m_mtr); 433 } 434 435 /** Get the LOB version. */ get_lob_versionz_index_entry_t436 uint32_t get_lob_version() const { 437 return (mach_read_from_4(m_node + OFFSET_LOB_VERSION)); 438 } 439 440 /** Set the LOB version . 441 @param[in] version the lob version. */ set_lob_versionz_index_entry_t442 void set_lob_version(ulint version) { 443 ut_ad(m_mtr != nullptr); 444 mlog_write_ulint(m_node + OFFSET_LOB_VERSION, version, MLOG_4BYTES, m_mtr); 445 } 446 447 /* The given entry becomes the old version of the current entry. 448 Move the version base node from old entry to current entry. 449 @param[in] entry the old entry */ 450 void set_old_version(z_index_entry_t &entry); 451 452 /** The current index entry points to a latest LOB page. It may or 453 may not have older versions. If older version is there, bring it 454 back to the index list from the versions list. Then remove the 455 current entry from the index list. Move the versions list from 456 current entry to older entry. 457 @param[in] index the index in which LOB exists. 458 @param[in] trxid The transaction identifier. 459 @param[in] first The first lob page containing index list 460 and free list. */ 461 fil_addr_t make_old_version_current(dict_index_t *index, trx_id_t trxid, 462 z_first_page_t &first); 463 get_nodez_index_entry_t464 flst_node_t *get_node() { return (m_node); } is_nullz_index_entry_t465 bool is_null() const { return (m_node == nullptr); } 466 467 std::ostream &print(std::ostream &out) const; 468 std::ostream &print_pages(std::ostream &out) const; 469 470 /** Load the page (in shared mode) whose number was cached. 471 @return the buffer block of the page loaded. */ load_sz_index_entry_t472 buf_block_t *load_s() { 473 ut_ad(m_page_no != FIL_NULL); 474 475 page_id_t page_id(dict_index_get_space(m_index), m_page_no); 476 page_size_t page_size(dict_table_page_size(m_index->table)); 477 m_block = buf_page_get(page_id, page_size, RW_S_LATCH, m_mtr); 478 return (m_block); 479 } 480 481 /** Load the given file address in s mode. 482 @param[in] addr the file address of the required node. */ load_sz_index_entry_t483 void load_s(fil_addr_t &addr) { 484 space_id_t space = dict_index_get_space(m_index); 485 const page_size_t page_size = dict_table_page_size(m_index->table); 486 m_node = fut_get_ptr(space, page_size, addr, RW_S_LATCH, m_mtr, &m_block); 487 m_page_no = m_block->get_page_no(); 488 } 489 490 /** Load the given file address in x mode. 491 @param[in] addr the file address of the required node. */ load_xz_index_entry_t492 void load_x(fil_addr_t &addr) { 493 space_id_t space = dict_index_get_space(m_index); 494 const page_size_t page_size = dict_table_page_size(m_index->table); 495 m_node = fut_get_ptr(space, page_size, addr, RW_X_LATCH, m_mtr, &m_block); 496 m_page_no = m_block->get_page_no(); 497 } 498 499 /** Read the given LOB index entry. 500 @param[in] entry_mem the LOB index entry. */ 501 void read(z_index_entry_mem_t &entry_mem) const; 502 503 /** Read the given LOB index entry and then commit the mtr. 504 @param[in] entry_mem the LOB index entry. */ read_and_commitz_index_entry_t505 void read_and_commit(z_index_entry_mem_t &entry_mem) { 506 read(entry_mem); 507 mtr_commit(m_mtr); 508 m_node = nullptr; 509 } 510 511 /** Get the location of the current index entry. */ 512 fil_addr_t get_self() const; 513 514 private: 515 /** Move the version base node from current entry to the given entry. 516 @param[in] entry The index entry to which the version base 517 node is moved to. */ 518 void move_version_base_node(z_index_entry_t &entry); 519 520 /** The file list node in a db page. This node is persisted. */ 521 flst_node_t *m_node; 522 523 /** A mini transaction. */ 524 mtr_t *m_mtr; 525 526 /** The index containing the LOB. */ 527 dict_index_t *m_index; 528 529 /** The buffer block in which this entry exists. While reading data 530 from m_node, appropriate latches must be held on this block. */ 531 buf_block_t *m_block; 532 533 /** The page number in which this entry is available. This 534 information will be cached and can be used to reload the page 535 conveniently. */ 536 page_no_t m_page_no; 537 }; 538 539 inline std::ostream &operator<<(std::ostream &out, const z_index_entry_t &obj) { 540 return (obj.print(out)); 541 } 542 543 } /* namespace lob */ 544 545 #endif /* zlob0index_h */ 546