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 lob0index_h 27 #define lob0index_h 28 29 #include "fut0lst.h" 30 #include "lob0util.h" 31 #include "trx0trx.h" 32 #include "univ.i" 33 34 namespace lob { 35 36 typedef std::map<page_no_t, buf_block_t *> BlockCache; 37 struct first_page_t; 38 39 /** An in-memory copy of an index_entry_t data */ 40 struct index_entry_mem_t { 41 fil_addr_t m_self; 42 fil_addr_t m_prev; 43 fil_addr_t m_next; 44 flst_bnode_t m_versions; 45 trx_id_t m_trx_id; 46 trx_id_t m_trx_id_modifier; 47 undo_no_t m_undo_no; 48 undo_no_t m_undo_no_modifier; 49 page_no_t m_page_no; 50 ulint m_data_len; 51 index_entry_mem_tindex_entry_mem_t52 index_entry_mem_t() { reset(); } 53 54 void reset(); 55 is_nullindex_entry_mem_t56 bool is_null() { return (m_self.is_equal(fil_addr_null)); } 57 get_page_noindex_entry_mem_t58 page_no_t get_page_no() const { return (m_page_no); } 59 60 /** Print this object into the given output stream. 61 @param[in] out the output stream. 62 @return the output stream. */ 63 std::ostream &print(std::ostream &out) const; 64 }; 65 66 /** List of index entry memory (iem) objects. */ 67 using List_iem_t = std::list<index_entry_mem_t>; 68 69 /** Overloading the global output operator to print the index_entry_mem_t 70 object. 71 @param[in,out] out the output stream. 72 @param[in] obj an object of type index_entry_mem_t 73 @return the output stream. */ 74 inline std::ostream &operator<<(std::ostream &out, 75 const index_entry_mem_t &obj) { 76 return (obj.print(out)); 77 } 78 79 /** An index entry pointing to an LOB page. */ 80 struct index_entry_t { 81 /** Index entry offsets within node. */ 82 static const ulint OFFSET_PREV = 0; 83 static const ulint OFFSET_NEXT = OFFSET_PREV + FIL_ADDR_SIZE; 84 85 /** Points to base node of the list of versions. The size of base node is 86 16 bytes. */ 87 static const ulint OFFSET_VERSIONS = OFFSET_NEXT + FIL_ADDR_SIZE; 88 89 /** The creator trx id. */ 90 static const ulint OFFSET_TRXID = OFFSET_VERSIONS + FLST_BASE_NODE_SIZE; 91 92 /** The modifier trx id. */ 93 static const ulint OFFSET_TRXID_MODIFIER = OFFSET_TRXID + 6; 94 static const ulint OFFSET_TRX_UNDO_NO = OFFSET_TRXID_MODIFIER + 6; 95 96 /** The undo number of the modifier trx. */ 97 static const ulint OFFSET_TRX_UNDO_NO_MODIFIER = OFFSET_TRX_UNDO_NO + 4; 98 static const ulint OFFSET_PAGE_NO = OFFSET_TRX_UNDO_NO_MODIFIER + 4; 99 static const ulint OFFSET_DATA_LEN = OFFSET_PAGE_NO + 4; 100 101 /** The LOB version number. */ 102 static const ulint OFFSET_LOB_VERSION = OFFSET_DATA_LEN + 4; 103 104 /** Total length of an index node. */ 105 static const ulint SIZE = OFFSET_LOB_VERSION + 4; 106 107 /** Constructor. 108 @param[in] node the pointer where index entry is located. */ index_entry_tindex_entry_t109 index_entry_t(flst_node_t *node) 110 : m_node(node), m_mtr(nullptr), m_index(nullptr), m_block(nullptr) {} 111 index_entry_tindex_entry_t112 index_entry_t(flst_node_t *node, mtr_t *mtr) 113 : m_node(node), m_mtr(mtr), m_index(nullptr), m_block(nullptr) {} 114 index_entry_tindex_entry_t115 index_entry_t(flst_node_t *node, mtr_t *mtr, dict_index_t *index) 116 : m_node(node), m_mtr(mtr), m_index(index), m_block(nullptr) {} 117 index_entry_tindex_entry_t118 index_entry_t(mtr_t *mtr, const dict_index_t *index) 119 : m_node(nullptr), m_mtr(mtr), m_index(index), m_block(nullptr) {} 120 121 /* Move the node pointer to a different place within the same page. 122 @param[in] addr new location of node pointer. */ resetindex_entry_t123 void reset(fil_addr_t &addr) { 124 ut_ad(m_block->page.id.page_no() == addr.page); 125 126 m_node = buf_block_get_frame(m_block) + addr.boffset; 127 } 128 129 /* Get the buffer block of the current index entry. 130 @return the buffer block of the current index entry.*/ get_blockindex_entry_t131 buf_block_t *get_block() const { return (m_block); } 132 133 /* Reset the current object to point to a different node. 134 @param[in] node the new file list node. */ resetindex_entry_t135 void reset(flst_node_t *node) { m_node = node; } 136 is_nullindex_entry_t137 bool is_null() const { 138 const byte zero[SIZE] = {0x00}; 139 return (m_node == nullptr || memcmp(m_node, zero, SIZE) == 0); 140 } 141 142 /** Initialize the object fully. */ initindex_entry_t143 void init() { 144 set_prev_null(); 145 set_next_null(); 146 set_versions_null(); 147 set_trx_id(0); 148 set_trx_undo_no(0); 149 set_page_no(FIL_NULL); 150 set_data_len(0); 151 } 152 153 /** Get the location of the current index entry. */ 154 fil_addr_t get_self() const; 155 156 /** The versions base node is set to NULL. */ set_versions_nullindex_entry_t157 void set_versions_null() { 158 ut_ad(m_mtr != nullptr); 159 160 byte *base_node = get_versions_ptr(); 161 flst_init(base_node, m_mtr); 162 } 163 164 /** Determine if the current index entry be rolled back. 165 @param[in] trxid the transaction that is being purged. 166 @param[in] undo_no the undo number of trx. 167 @return true if this entry can be rolled back, false otherwise. */ can_rollbackindex_entry_t168 bool can_rollback(trx_id_t trxid, undo_no_t undo_no) { 169 /* For rollback, make use of creator trx id. */ 170 return ((trxid == get_trx_id()) && (get_trx_undo_no() >= undo_no)); 171 } 172 173 /** Determine if the current index entry be purged. 174 @param[in] trxid the transaction that is being purged. 175 @param[in] undo_no the undo number of trx. 176 @return true if this entry can be purged, false otherwise. */ can_be_purgedindex_entry_t177 bool can_be_purged(trx_id_t trxid, undo_no_t undo_no) { 178 return ((trxid == get_trx_id_modifier()) && 179 (get_trx_undo_no_modifier() == undo_no)); 180 } 181 182 /* The given entry becomes the old version of the current entry. 183 Move the version base node from old entry to current entry. 184 @param[in] entry the old entry */ set_old_versionindex_entry_t185 void set_old_version(index_entry_t &entry) { 186 flst_node_t *node = entry.get_node_ptr(); 187 flst_base_node_t *version_list = get_versions_ptr(); 188 ut_ad(flst_get_len(version_list) == 0); 189 190 entry.move_version_base_node(*this); 191 flst_add_first(version_list, node, m_mtr); 192 } 193 194 /** The current index entry points to a latest LOB page. It may or 195 may not have older versions. If older version is there, bring it 196 back to the index list from the versions list. Then remove the 197 current entry from the index list. Move the versions list from 198 current entry to older entry. 199 @param[in] index the clustered index containing the LOB. 200 @param[in] trxid The transaction identifier. 201 @param[in] first_page The first lob page containing index 202 list and free list. 203 @return the location of next entry. */ 204 fil_addr_t make_old_version_current(dict_index_t *index, trx_id_t trxid, 205 first_page_t &first_page); 206 207 /** Purge the current entry. 208 @param[in] index the clustered index containing the LOB. 209 @param[in] trxid The transaction identifier. 210 @param[in] lst the base node of index list. 211 @param[in] free_list the base node of free list. 212 @return the location of the next entry. */ 213 fil_addr_t purge_version(dict_index_t *index, trx_id_t trxid, 214 flst_base_node_t *lst, flst_base_node_t *free_list); 215 add_versionindex_entry_t216 void add_version(index_entry_t &entry) const { 217 flst_node_t *node = entry.get_node_ptr(); 218 flst_base_node_t *version_list = get_versions_ptr(); 219 flst_add_first(version_list, node, m_mtr); 220 } 221 get_versions_listindex_entry_t222 flst_base_node_t *get_versions_list() const { return (get_versions_ptr()); } 223 224 /** Add this node as the last node in the given list. 225 @param[in] bnode the base node of the file list. */ push_backindex_entry_t226 void push_back(flst_base_node_t *bnode) { 227 flst_add_last(bnode, m_node, m_mtr); 228 } 229 230 /** Get the base node of the list of versions. */ get_versions_memindex_entry_t231 flst_bnode_t get_versions_mem() const { 232 flst_base_node_t *node = get_versions_list(); 233 return (flst_bnode_t(node, m_mtr)); 234 } 235 get_trx_idindex_entry_t236 trx_id_t get_trx_id() const { 237 byte *ptr = get_trxid_ptr(); 238 return (mach_read_from_6(ptr)); 239 } 240 get_trx_id_modifierindex_entry_t241 trx_id_t get_trx_id_modifier() const { 242 byte *ptr = get_trxid_modifier_ptr(); 243 return (mach_read_from_6(ptr)); 244 } 245 get_trx_undo_noindex_entry_t246 undo_no_t get_trx_undo_no() const { 247 byte *ptr = get_trx_undo_no_ptr(); 248 return (mach_read_from_4(ptr)); 249 } 250 get_lob_versionindex_entry_t251 uint32_t get_lob_version() const { 252 byte *ptr = get_lob_version_ptr(); 253 return (mach_read_from_4(ptr)); 254 } 255 256 /** Get the undo number of the modifier trx. 257 @return the undo number of the modifier trx. */ get_trx_undo_no_modifierindex_entry_t258 undo_no_t get_trx_undo_no_modifier() const { 259 byte *ptr = get_trx_undo_no_modifier_ptr(); 260 return (mach_read_from_4(ptr)); 261 } 262 get_nextindex_entry_t263 fil_addr_t get_next() const { 264 ut_ad(m_node != nullptr); 265 266 return (flst_read_addr(m_node + OFFSET_NEXT, m_mtr)); 267 } 268 269 /** Make the current index entry object to point to the next index 270 entry object. 271 @return the buffer block in which the next index entry is available.*/ nextindex_entry_t272 buf_block_t *next() { 273 fil_addr_t node_loc = get_next(); 274 275 if (node_loc.is_null()) { 276 return (nullptr); 277 } 278 279 if (m_block == nullptr || m_block->page.id.page_no() != node_loc.page) { 280 load_x(node_loc); 281 } else { 282 /* Next entry in the same page. */ 283 reset(node_loc); 284 } 285 286 return (m_block); 287 } 288 289 /** Get the previous index entry. 290 @return The file address of previous index entry. */ get_previndex_entry_t291 fil_addr_t get_prev() const { 292 return (flst_read_addr(m_node + OFFSET_PREV, m_mtr)); 293 } 294 295 /** Write the trx identifier to the index entry. No redo log 296 is generated for this modification. This is meant to be used 297 during tablespace import. 298 @param[in] id the trx identifier.*/ set_trx_id_no_redoindex_entry_t299 void set_trx_id_no_redo(trx_id_t id) { 300 byte *ptr = get_trxid_ptr(); 301 mach_write_to_6(ptr, id); 302 } 303 304 /** Write the modifier trx identifier to the index entry. No redo log 305 is generated for this modification. This is meant to be used 306 during tablespace import. 307 @param[in] id the trx identifier.*/ set_trx_id_modifier_no_redoindex_entry_t308 void set_trx_id_modifier_no_redo(trx_id_t id) { 309 byte *ptr = get_trxid_modifier_ptr(); 310 mach_write_to_6(ptr, id); 311 } 312 set_trx_idindex_entry_t313 void set_trx_id(trx_id_t id) { 314 byte *ptr = get_trxid_ptr(); 315 mach_write_to_6(ptr, id); 316 mlog_log_string(ptr, 6, m_mtr); 317 } 318 set_trx_id_modifierindex_entry_t319 void set_trx_id_modifier(trx_id_t id) { 320 ut_ad(m_mtr != nullptr); 321 322 byte *ptr = get_trxid_modifier_ptr(); 323 mach_write_to_6(ptr, id); 324 mlog_log_string(ptr, 6, m_mtr); 325 } 326 set_trx_undo_noindex_entry_t327 void set_trx_undo_no(undo_no_t undo_no) { 328 byte *ptr = get_trx_undo_no_ptr(); 329 mlog_write_ulint(ptr, undo_no, MLOG_4BYTES, m_mtr); 330 } 331 332 /** Set the LOB version of this entry. 333 @param[in] version the LOB version number. */ set_lob_versionindex_entry_t334 void set_lob_version(uint32_t version) { 335 byte *ptr = get_lob_version_ptr(); 336 mlog_write_ulint(ptr, version, MLOG_4BYTES, m_mtr); 337 } 338 set_trx_undo_no_modifierindex_entry_t339 void set_trx_undo_no_modifier(undo_no_t undo_no) { 340 ut_ad(m_mtr != nullptr); 341 342 byte *ptr = get_trx_undo_no_modifier_ptr(); 343 mlog_write_ulint(ptr, undo_no, MLOG_4BYTES, m_mtr); 344 } 345 set_page_noindex_entry_t346 void set_page_no(page_no_t num) { 347 ut_ad(num > 0); 348 byte *ptr = get_pageno_ptr(); 349 return (mlog_write_ulint(ptr, num, MLOG_4BYTES, m_mtr)); 350 } 351 set_prev_nullindex_entry_t352 void set_prev_null() { 353 flst_write_addr(m_node + OFFSET_PREV, fil_addr_null, m_mtr); 354 } 355 set_next_nullindex_entry_t356 void set_next_null() { 357 flst_write_addr(m_node + OFFSET_NEXT, fil_addr_null, m_mtr); 358 } 359 get_page_noindex_entry_t360 page_no_t get_page_no() const { 361 byte *ptr = get_pageno_ptr(); 362 return (mach_read_from_4(ptr)); 363 } 364 set_data_lenindex_entry_t365 void set_data_len(ulint len) { 366 byte *ptr = get_datalen_ptr(); 367 return (mlog_write_ulint(ptr, len, MLOG_2BYTES, m_mtr)); 368 } 369 get_data_lenindex_entry_t370 ulint get_data_len() const { 371 byte *ptr = get_datalen_ptr(); 372 return (mach_read_from_2(ptr)); 373 } 374 375 std::ostream &print(std::ostream &out) const; 376 is_sameindex_entry_t377 bool is_same(const index_entry_t &that) { return (m_node == that.m_node); } 378 379 void read(index_entry_mem_t &entry_mem) const; 380 381 /** Load the index entry available in the given file address. 382 Take x-latch on the index page. 383 @param[in] addr the file address of the index entry. 384 @return the buffer block containing the index entry. */ 385 buf_block_t *load_x(const fil_addr_t &addr); 386 387 /** Load the index entry available in the given file address. 388 Take s-latch on the index page. 389 @param[in] addr the file location of index entry. 390 @return the buffer block. */ 391 buf_block_t *load_s(const fil_addr_t &addr); 392 insert_afterindex_entry_t393 void insert_after(flst_base_node_t *base, index_entry_t &entry) { 394 flst_insert_after(base, m_node, entry.get_node(), m_mtr); 395 } 396 insert_beforeindex_entry_t397 void insert_before(flst_base_node_t *base, index_entry_t &entry) { 398 flst_insert_before(base, entry.get_node(), m_node, m_mtr); 399 } 400 removeindex_entry_t401 void remove(flst_base_node_t *bnode) { flst_remove(bnode, m_node, m_mtr); } 402 403 private: 404 /** Move the version base node from current entry to the given entry. 405 @param[in] to_entry The index entry to which the version 406 base node is moved to.*/ 407 void move_version_base_node(index_entry_t &to_entry); 408 409 /** Purge the current index entry. An index entry points to either a 410 FIRST page or DATA page. That LOB page will be freed if it is DATA 411 page. A FIRST page should not be freed. */ 412 void purge(dict_index_t *index); 413 get_versions_ptrindex_entry_t414 byte *get_versions_ptr() const { return (m_node + OFFSET_VERSIONS); } 415 get_trxid_ptrindex_entry_t416 byte *get_trxid_ptr() const { return (m_node + OFFSET_TRXID); } 417 get_trxid_modifier_ptrindex_entry_t418 byte *get_trxid_modifier_ptr() const { 419 return (m_node + OFFSET_TRXID_MODIFIER); 420 } 421 get_trx_undo_no_ptrindex_entry_t422 byte *get_trx_undo_no_ptr() const { return (m_node + OFFSET_TRX_UNDO_NO); } 423 get_lob_version_ptrindex_entry_t424 byte *get_lob_version_ptr() const { return (m_node + OFFSET_LOB_VERSION); } 425 get_trx_undo_no_modifier_ptrindex_entry_t426 byte *get_trx_undo_no_modifier_ptr() const { 427 return (m_node + OFFSET_TRX_UNDO_NO_MODIFIER); 428 } 429 get_pageno_ptrindex_entry_t430 byte *get_pageno_ptr() const { return (m_node + OFFSET_PAGE_NO); } 431 get_datalen_ptrindex_entry_t432 byte *get_datalen_ptr() const { return (m_node + OFFSET_DATA_LEN); } 433 get_node_ptrindex_entry_t434 byte *get_node_ptr() const { return (m_node); } 435 get_nodeindex_entry_t436 byte *get_node() const { return (m_node); } 437 438 private: 439 byte *m_node; 440 mtr_t *m_mtr; 441 const dict_index_t *m_index; 442 buf_block_t *m_block; 443 }; 444 445 /** Overloading the global output operator to easily print an index entry. 446 @param[in] out the output stream. 447 @param[in] obj the index entry. 448 @return the output stream. */ 449 inline std::ostream &operator<<(std::ostream &out, const index_entry_t &obj) { 450 return (obj.print(out)); 451 } 452 453 } /* namespace lob */ 454 455 #endif /* lob0index_h */ 456