| 1 | /***************************************************************************** |
| 2 | |
| 3 | Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved. |
| 4 | Copyright (c) 2016, 2018, MariaDB Corporation. |
| 5 | |
| 6 | This program is free software; you can redistribute it and/or modify it under |
| 7 | the terms of the GNU General Public License as published by the Free Software |
| 8 | Foundation; version 2 of the License. |
| 9 | |
| 10 | This program is distributed in the hope that it will be useful, but WITHOUT |
| 11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 12 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
| 13 | |
| 14 | You should have received a copy of the GNU General Public License along with |
| 15 | this program; if not, write to the Free Software Foundation, Inc., |
| 16 | 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA |
| 17 | |
| 18 | *****************************************************************************/ |
| 19 | |
| 20 | /**************************************************//** |
| 21 | @file include/ibuf0ibuf.h |
| 22 | Insert buffer |
| 23 | |
| 24 | Created 7/19/1997 Heikki Tuuri |
| 25 | *******************************************************/ |
| 26 | |
| 27 | #ifndef ibuf0ibuf_h |
| 28 | #define ibuf0ibuf_h |
| 29 | |
| 30 | #include "univ.i" |
| 31 | |
| 32 | #include "mtr0mtr.h" |
| 33 | #include "dict0mem.h" |
| 34 | #include "fsp0fsp.h" |
| 35 | #include "ibuf0types.h" |
| 36 | |
| 37 | /** Default value for maximum on-disk size of change buffer in terms |
| 38 | of percentage of the buffer pool. */ |
| 39 | #define CHANGE_BUFFER_DEFAULT_SIZE (25) |
| 40 | |
| 41 | /* Possible operations buffered in the insert/whatever buffer. See |
| 42 | ibuf_insert(). DO NOT CHANGE THE VALUES OF THESE, THEY ARE STORED ON DISK. */ |
| 43 | typedef enum { |
| 44 | IBUF_OP_INSERT = 0, |
| 45 | IBUF_OP_DELETE_MARK = 1, |
| 46 | IBUF_OP_DELETE = 2, |
| 47 | |
| 48 | /* Number of different operation types. */ |
| 49 | IBUF_OP_COUNT = 3 |
| 50 | } ibuf_op_t; |
| 51 | |
| 52 | /** Combinations of operations that can be buffered. |
| 53 | @see innodb_change_buffering_names */ |
| 54 | enum ibuf_use_t { |
| 55 | IBUF_USE_NONE = 0, |
| 56 | IBUF_USE_INSERT, /* insert */ |
| 57 | IBUF_USE_DELETE_MARK, /* delete */ |
| 58 | IBUF_USE_INSERT_DELETE_MARK, /* insert+delete */ |
| 59 | IBUF_USE_DELETE, /* delete+purge */ |
| 60 | IBUF_USE_ALL /* insert+delete+purge */ |
| 61 | }; |
| 62 | |
| 63 | /** Operations that can currently be buffered. */ |
| 64 | extern ibuf_use_t ibuf_use; |
| 65 | |
| 66 | /** The insert buffer control structure */ |
| 67 | extern ibuf_t* ibuf; |
| 68 | |
| 69 | /* The purpose of the insert buffer is to reduce random disk access. |
| 70 | When we wish to insert a record into a non-unique secondary index and |
| 71 | the B-tree leaf page where the record belongs to is not in the buffer |
| 72 | pool, we insert the record into the insert buffer B-tree, indexed by |
| 73 | (space_id, page_no). When the page is eventually read into the buffer |
| 74 | pool, we look up the insert buffer B-tree for any modifications to the |
| 75 | page, and apply these upon the completion of the read operation. This |
| 76 | is called the insert buffer merge. */ |
| 77 | |
| 78 | /* The insert buffer merge must always succeed. To guarantee this, |
| 79 | the insert buffer subsystem keeps track of the free space in pages for |
| 80 | which it can buffer operations. Two bits per page in the insert |
| 81 | buffer bitmap indicate the available space in coarse increments. The |
| 82 | free bits in the insert buffer bitmap must never exceed the free space |
| 83 | on a page. It is safe to decrement or reset the bits in the bitmap in |
| 84 | a mini-transaction that is committed before the mini-transaction that |
| 85 | affects the free space. It is unsafe to increment the bits in a |
| 86 | separately committed mini-transaction, because in crash recovery, the |
| 87 | free bits could momentarily be set too high. */ |
| 88 | |
| 89 | /******************************************************************//** |
| 90 | Creates the insert buffer data structure at a database startup. |
| 91 | @return DB_SUCCESS or failure */ |
| 92 | dberr_t |
| 93 | ibuf_init_at_db_start(void); |
| 94 | /*=======================*/ |
| 95 | /*********************************************************************//** |
| 96 | Updates the max_size value for ibuf. */ |
| 97 | void |
| 98 | ibuf_max_size_update( |
| 99 | /*=================*/ |
| 100 | ulint new_val); /*!< in: new value in terms of |
| 101 | percentage of the buffer pool size */ |
| 102 | /*********************************************************************//** |
| 103 | Reads the biggest tablespace id from the high end of the insert buffer |
| 104 | tree and updates the counter in fil_system. */ |
| 105 | void |
| 106 | ibuf_update_max_tablespace_id(void); |
| 107 | /*===============================*/ |
| 108 | /***************************************************************//** |
| 109 | Starts an insert buffer mini-transaction. */ |
| 110 | UNIV_INLINE |
| 111 | void |
| 112 | ibuf_mtr_start( |
| 113 | /*===========*/ |
| 114 | mtr_t* mtr) /*!< out: mini-transaction */ |
| 115 | MY_ATTRIBUTE((nonnull)); |
| 116 | /***************************************************************//** |
| 117 | Commits an insert buffer mini-transaction. */ |
| 118 | UNIV_INLINE |
| 119 | void |
| 120 | ibuf_mtr_commit( |
| 121 | /*============*/ |
| 122 | mtr_t* mtr) /*!< in/out: mini-transaction */ |
| 123 | MY_ATTRIBUTE((nonnull)); |
| 124 | /*********************************************************************//** |
| 125 | Initializes an ibuf bitmap page. */ |
| 126 | void |
| 127 | ibuf_bitmap_page_init( |
| 128 | /*==================*/ |
| 129 | buf_block_t* block, /*!< in: bitmap page */ |
| 130 | mtr_t* mtr); /*!< in: mtr */ |
| 131 | /************************************************************************//** |
| 132 | Resets the free bits of the page in the ibuf bitmap. This is done in a |
| 133 | separate mini-transaction, hence this operation does not restrict |
| 134 | further work to only ibuf bitmap operations, which would result if the |
| 135 | latch to the bitmap page were kept. NOTE: The free bits in the insert |
| 136 | buffer bitmap must never exceed the free space on a page. It is safe |
| 137 | to decrement or reset the bits in the bitmap in a mini-transaction |
| 138 | that is committed before the mini-transaction that affects the free |
| 139 | space. */ |
| 140 | void |
| 141 | ibuf_reset_free_bits( |
| 142 | /*=================*/ |
| 143 | buf_block_t* block); /*!< in: index page; free bits are set to 0 |
| 144 | if the index is a non-clustered |
| 145 | non-unique, and page level is 0 */ |
| 146 | /************************************************************************//** |
| 147 | Updates the free bits of an uncompressed page in the ibuf bitmap if |
| 148 | there is not enough free on the page any more. This is done in a |
| 149 | separate mini-transaction, hence this operation does not restrict |
| 150 | further work to only ibuf bitmap operations, which would result if the |
| 151 | latch to the bitmap page were kept. NOTE: The free bits in the insert |
| 152 | buffer bitmap must never exceed the free space on a page. It is |
| 153 | unsafe to increment the bits in a separately committed |
| 154 | mini-transaction, because in crash recovery, the free bits could |
| 155 | momentarily be set too high. It is only safe to use this function for |
| 156 | decrementing the free bits. Should more free space become available, |
| 157 | we must not update the free bits here, because that would break crash |
| 158 | recovery. */ |
| 159 | UNIV_INLINE |
| 160 | void |
| 161 | ibuf_update_free_bits_if_full( |
| 162 | /*==========================*/ |
| 163 | buf_block_t* block, /*!< in: index page to which we have added new |
| 164 | records; the free bits are updated if the |
| 165 | index is non-clustered and non-unique and |
| 166 | the page level is 0, and the page becomes |
| 167 | fuller */ |
| 168 | ulint max_ins_size,/*!< in: value of maximum insert size with |
| 169 | reorganize before the latest operation |
| 170 | performed to the page */ |
| 171 | ulint increase);/*!< in: upper limit for the additional space |
| 172 | used in the latest operation, if known, or |
| 173 | ULINT_UNDEFINED */ |
| 174 | /**********************************************************************//** |
| 175 | Updates the free bits for an uncompressed page to reflect the present |
| 176 | state. Does this in the mtr given, which means that the latching |
| 177 | order rules virtually prevent any further operations for this OS |
| 178 | thread until mtr is committed. NOTE: The free bits in the insert |
| 179 | buffer bitmap must never exceed the free space on a page. It is safe |
| 180 | to set the free bits in the same mini-transaction that updated the |
| 181 | page. */ |
| 182 | void |
| 183 | ibuf_update_free_bits_low( |
| 184 | /*======================*/ |
| 185 | const buf_block_t* block, /*!< in: index page */ |
| 186 | ulint max_ins_size, /*!< in: value of |
| 187 | maximum insert size |
| 188 | with reorganize before |
| 189 | the latest operation |
| 190 | performed to the page */ |
| 191 | mtr_t* mtr); /*!< in/out: mtr */ |
| 192 | /**********************************************************************//** |
| 193 | Updates the free bits for a compressed page to reflect the present |
| 194 | state. Does this in the mtr given, which means that the latching |
| 195 | order rules virtually prevent any further operations for this OS |
| 196 | thread until mtr is committed. NOTE: The free bits in the insert |
| 197 | buffer bitmap must never exceed the free space on a page. It is safe |
| 198 | to set the free bits in the same mini-transaction that updated the |
| 199 | page. */ |
| 200 | void |
| 201 | ibuf_update_free_bits_zip( |
| 202 | /*======================*/ |
| 203 | buf_block_t* block, /*!< in/out: index page */ |
| 204 | mtr_t* mtr); /*!< in/out: mtr */ |
| 205 | /**********************************************************************//** |
| 206 | Updates the free bits for the two pages to reflect the present state. |
| 207 | Does this in the mtr given, which means that the latching order rules |
| 208 | virtually prevent any further operations until mtr is committed. |
| 209 | NOTE: The free bits in the insert buffer bitmap must never exceed the |
| 210 | free space on a page. It is safe to set the free bits in the same |
| 211 | mini-transaction that updated the pages. */ |
| 212 | void |
| 213 | ibuf_update_free_bits_for_two_pages_low( |
| 214 | /*====================================*/ |
| 215 | buf_block_t* block1, /*!< in: index page */ |
| 216 | buf_block_t* block2, /*!< in: index page */ |
| 217 | mtr_t* mtr); /*!< in: mtr */ |
| 218 | /**********************************************************************//** |
| 219 | A basic partial test if an insert to the insert buffer could be possible and |
| 220 | recommended. */ |
| 221 | UNIV_INLINE |
| 222 | ibool |
| 223 | ibuf_should_try( |
| 224 | /*============*/ |
| 225 | dict_index_t* index, /*!< in: index where to insert */ |
| 226 | ulint ignore_sec_unique); /*!< in: if != 0, we should |
| 227 | ignore UNIQUE constraint on |
| 228 | a secondary index when we |
| 229 | decide */ |
| 230 | /******************************************************************//** |
| 231 | Returns TRUE if the current OS thread is performing an insert buffer |
| 232 | routine. |
| 233 | |
| 234 | For instance, a read-ahead of non-ibuf pages is forbidden by threads |
| 235 | that are executing an insert buffer routine. |
| 236 | @return TRUE if inside an insert buffer routine */ |
| 237 | UNIV_INLINE |
| 238 | ibool |
| 239 | ibuf_inside( |
| 240 | /*========*/ |
| 241 | const mtr_t* mtr) /*!< in: mini-transaction */ |
| 242 | MY_ATTRIBUTE((warn_unused_result)); |
| 243 | |
| 244 | /** Checks if a page address is an ibuf bitmap page (level 3 page) address. |
| 245 | @param[in] page_id page id |
| 246 | @param[in] page_size page size |
| 247 | @return TRUE if a bitmap page */ |
| 248 | UNIV_INLINE |
| 249 | ibool |
| 250 | ( |
| 251 | const page_id_t& page_id, |
| 252 | const page_size_t& page_size); |
| 253 | |
| 254 | /** Checks if a page is a level 2 or 3 page in the ibuf hierarchy of pages. |
| 255 | Must not be called when recv_no_ibuf_operations==true. |
| 256 | @param[in] page_id page id |
| 257 | @param[in] page_size page size |
| 258 | @param[in] x_latch FALSE if relaxed check (avoid latching the |
| 259 | bitmap page) |
| 260 | @param[in] file file name |
| 261 | @param[in] line line where called |
| 262 | @param[in,out] mtr mtr which will contain an x-latch to the |
| 263 | bitmap page if the page is not one of the fixed address ibuf pages, or NULL, |
| 264 | in which case a new transaction is created. |
| 265 | @return TRUE if level 2 or level 3 page */ |
| 266 | ibool |
| 267 | ibuf_page_low( |
| 268 | const page_id_t& page_id, |
| 269 | const page_size_t& page_size, |
| 270 | #ifdef UNIV_DEBUG |
| 271 | ibool x_latch, |
| 272 | #endif /* UNIV_DEBUG */ |
| 273 | const char* file, |
| 274 | unsigned line, |
| 275 | mtr_t* mtr) |
| 276 | MY_ATTRIBUTE((warn_unused_result)); |
| 277 | |
| 278 | #ifdef UNIV_DEBUG |
| 279 | |
| 280 | /** Checks if a page is a level 2 or 3 page in the ibuf hierarchy of pages. |
| 281 | Must not be called when recv_no_ibuf_operations==true. |
| 282 | @param[in] page_id tablespace/page identifier |
| 283 | @param[in] page_size page size |
| 284 | @param[in,out] mtr mini-transaction or NULL |
| 285 | @return TRUE if level 2 or level 3 page */ |
| 286 | # define ibuf_page(page_id, page_size, mtr) \ |
| 287 | ibuf_page_low(page_id, page_size, TRUE, __FILE__, __LINE__, mtr) |
| 288 | |
| 289 | #else /* UVIV_DEBUG */ |
| 290 | |
| 291 | /** Checks if a page is a level 2 or 3 page in the ibuf hierarchy of pages. |
| 292 | Must not be called when recv_no_ibuf_operations==true. |
| 293 | @param[in] page_id tablespace/page identifier |
| 294 | @param[in] page_size page size |
| 295 | @param[in,out] mtr mini-transaction or NULL |
| 296 | @return TRUE if level 2 or level 3 page */ |
| 297 | # define ibuf_page(page_id, page_size, mtr) \ |
| 298 | ibuf_page_low(page_id, page_size, __FILE__, __LINE__, mtr) |
| 299 | |
| 300 | #endif /* UVIV_DEBUG */ |
| 301 | /***********************************************************************//** |
| 302 | Frees excess pages from the ibuf free list. This function is called when an OS |
| 303 | thread calls fsp services to allocate a new file segment, or a new page to a |
| 304 | file segment, and the thread did not own the fsp latch before this call. */ |
| 305 | void |
| 306 | ibuf_free_excess_pages(void); |
| 307 | /*========================*/ |
| 308 | |
| 309 | /** Buffer an operation in the insert/delete buffer, instead of doing it |
| 310 | directly to the disk page, if this is possible. Does not do it if the index |
| 311 | is clustered or unique. |
| 312 | @param[in] op operation type |
| 313 | @param[in] entry index entry to insert |
| 314 | @param[in,out] index index where to insert |
| 315 | @param[in] page_id page id where to insert |
| 316 | @param[in] page_size page size |
| 317 | @param[in,out] thr query thread |
| 318 | @return TRUE if success */ |
| 319 | ibool |
| 320 | ibuf_insert( |
| 321 | ibuf_op_t op, |
| 322 | const dtuple_t* entry, |
| 323 | dict_index_t* index, |
| 324 | const page_id_t& page_id, |
| 325 | const page_size_t& page_size, |
| 326 | que_thr_t* thr); |
| 327 | |
| 328 | /** When an index page is read from a disk to the buffer pool, this function |
| 329 | applies any buffered operations to the page and deletes the entries from the |
| 330 | insert buffer. If the page is not read, but created in the buffer pool, this |
| 331 | function deletes its buffered entries from the insert buffer; there can |
| 332 | exist entries for such a page if the page belonged to an index which |
| 333 | subsequently was dropped. |
| 334 | @param[in,out] block if page has been read from disk, |
| 335 | pointer to the page x-latched, else NULL |
| 336 | @param[in] page_id page id of the index page |
| 337 | @param[in] update_ibuf_bitmap normally this is set to TRUE, but |
| 338 | if we have deleted or are deleting the tablespace, then we naturally do not |
| 339 | want to update a non-existent bitmap page */ |
| 340 | void |
| 341 | ibuf_merge_or_delete_for_page( |
| 342 | buf_block_t* block, |
| 343 | const page_id_t& page_id, |
| 344 | const page_size_t* page_size, |
| 345 | ibool update_ibuf_bitmap); |
| 346 | |
| 347 | /*********************************************************************//** |
| 348 | Deletes all entries in the insert buffer for a given space id. This is used |
| 349 | in DISCARD TABLESPACE and IMPORT TABLESPACE. |
| 350 | NOTE: this does not update the page free bitmaps in the space. The space will |
| 351 | become CORRUPT when you call this function! */ |
| 352 | void |
| 353 | ibuf_delete_for_discarded_space( |
| 354 | /*============================*/ |
| 355 | ulint space); /*!< in: space id */ |
| 356 | /** Contract the change buffer by reading pages to the buffer pool. |
| 357 | @param[in] full If true, do a full contraction based |
| 358 | on PCT_IO(100). If false, the size of contract batch is determined |
| 359 | based on the current size of the change buffer. |
| 360 | @return a lower limit for the combined size in bytes of entries which |
| 361 | will be merged from ibuf trees to the pages read, 0 if ibuf is |
| 362 | empty */ |
| 363 | ulint |
| 364 | ibuf_merge_in_background( |
| 365 | bool full); |
| 366 | |
| 367 | /** Contracts insert buffer trees by reading pages referring to space_id |
| 368 | to the buffer pool. |
| 369 | @returns number of pages merged.*/ |
| 370 | ulint |
| 371 | ibuf_merge_space( |
| 372 | /*=============*/ |
| 373 | ulint space); /*!< in: space id */ |
| 374 | |
| 375 | /*********************************************************************//** |
| 376 | Parses a redo log record of an ibuf bitmap page init. |
| 377 | @return end of log record or NULL */ |
| 378 | byte* |
| 379 | ibuf_parse_bitmap_init( |
| 380 | /*===================*/ |
| 381 | byte* ptr, /*!< in: buffer */ |
| 382 | byte* end_ptr,/*!< in: buffer end */ |
| 383 | buf_block_t* block, /*!< in: block or NULL */ |
| 384 | mtr_t* mtr); /*!< in: mtr or NULL */ |
| 385 | |
| 386 | #ifdef UNIV_IBUF_COUNT_DEBUG |
| 387 | /** Gets the ibuf count for a given page. |
| 388 | @param[in] page_id page id |
| 389 | @return number of entries in the insert buffer currently buffered for |
| 390 | this page */ |
| 391 | ulint |
| 392 | ibuf_count_get( |
| 393 | const page_id_t& page_id); |
| 394 | #endif |
| 395 | /******************************************************************//** |
| 396 | Looks if the insert buffer is empty. |
| 397 | @return true if empty */ |
| 398 | bool |
| 399 | ibuf_is_empty(void); |
| 400 | /*===============*/ |
| 401 | /******************************************************************//** |
| 402 | Prints info of ibuf. */ |
| 403 | void |
| 404 | ibuf_print( |
| 405 | /*=======*/ |
| 406 | FILE* file); /*!< in: file where to print */ |
| 407 | /******************************************************************** |
| 408 | Read the first two bytes from a record's fourth field (counter field in new |
| 409 | records; something else in older records). |
| 410 | @return "counter" field, or ULINT_UNDEFINED if for some reason it can't be read */ |
| 411 | ulint |
| 412 | ibuf_rec_get_counter( |
| 413 | /*=================*/ |
| 414 | const rec_t* rec); /*!< in: ibuf record */ |
| 415 | /******************************************************************//** |
| 416 | Closes insert buffer and frees the data structures. */ |
| 417 | void |
| 418 | ibuf_close(void); |
| 419 | /*============*/ |
| 420 | |
| 421 | /** Check the insert buffer bitmaps on IMPORT TABLESPACE. |
| 422 | @param[in] trx transaction |
| 423 | @param[in,out] space tablespace being imported |
| 424 | @return DB_SUCCESS or error code */ |
| 425 | dberr_t ibuf_check_bitmap_on_import(const trx_t* trx, fil_space_t* space) |
| 426 | MY_ATTRIBUTE((nonnull, warn_unused_result)); |
| 427 | |
| 428 | /** Updates free bits and buffered bits for bulk loaded page. |
| 429 | @param[in] block index page |
| 430 | @param]in] reset flag if reset free val */ |
| 431 | void |
| 432 | ibuf_set_bitmap_for_bulk_load( |
| 433 | buf_block_t* block, |
| 434 | bool reset); |
| 435 | |
| 436 | #define FSP_IBUF_HEADER_PAGE_NO |
| 437 | #define IBUF_TREE_ROOT_PAGE_NO FSP_IBUF_TREE_ROOT_PAGE_NO |
| 438 | |
| 439 | /* The ibuf header page currently contains only the file segment header |
| 440 | for the file segment from which the pages for the ibuf tree are allocated */ |
| 441 | #define PAGE_DATA |
| 442 | #define 0 /* fseg header for ibuf tree */ |
| 443 | |
| 444 | /* The insert buffer tree itself is always located in space 0. */ |
| 445 | #define IBUF_SPACE_ID static_cast<ulint>(0) |
| 446 | |
| 447 | #include "ibuf0ibuf.ic" |
| 448 | |
| 449 | #endif |
| 450 | |