1/***************************************************************************** 2 3Copyright (c) 1997, 2015, Oracle and/or its affiliates. All Rights Reserved. 4 5This program is free software; you can redistribute it and/or modify 6it under the terms of the GNU General Public License, version 2.0, 7as published by the Free Software Foundation. 8 9This program is also distributed with certain software (including 10but not limited to OpenSSL) that is licensed under separate terms, 11as designated in a particular file or component or in included license 12documentation. The authors of MySQL hereby grant you an additional 13permission to link the program and your derivative works with the 14separately licensed software that they have included with MySQL. 15 16This program is distributed in the hope that it will be useful, 17but WITHOUT ANY WARRANTY; without even the implied warranty of 18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19GNU General Public License, version 2.0, for more details. 20 21You should have received a copy of the GNU General Public License along with 22this program; if not, write to the Free Software Foundation, Inc., 2351 Franklin Street, Suite 500, Boston, MA 02110-1335 USA 24 25*****************************************************************************/ 26 27/**************************************************//** 28@file include/ibuf0ibuf.ic 29Insert buffer 30 31Created 7/19/1997 Heikki Tuuri 32*******************************************************/ 33 34#include "page0page.h" 35#include "page0zip.h" 36#ifndef UNIV_HOTBACKUP 37#include "buf0lru.h" 38 39/** An index page must contain at least UNIV_PAGE_SIZE / 40IBUF_PAGE_SIZE_PER_FREE_SPACE bytes of free space for ibuf to try to 41buffer inserts to this page. If there is this much of free space, the 42corresponding bits are set in the ibuf bitmap. */ 43#define IBUF_PAGE_SIZE_PER_FREE_SPACE 32 44 45/***************************************************************//** 46Starts an insert buffer mini-transaction. */ 47UNIV_INLINE 48void 49ibuf_mtr_start( 50/*===========*/ 51 mtr_t* mtr) /*!< out: mini-transaction */ 52{ 53 mtr_start(mtr); 54 mtr->inside_ibuf = TRUE; 55} 56/***************************************************************//** 57Commits an insert buffer mini-transaction. */ 58UNIV_INLINE 59void 60ibuf_mtr_commit( 61/*============*/ 62 mtr_t* mtr) /*!< in/out: mini-transaction */ 63{ 64 ut_ad(mtr->inside_ibuf); 65 ut_d(mtr->inside_ibuf = FALSE); 66 mtr_commit(mtr); 67} 68 69/** Insert buffer struct */ 70struct ibuf_t{ 71 ulint size; /*!< current size of the ibuf index 72 tree, in pages */ 73 ulint max_size; /*!< recommended maximum size of the 74 ibuf index tree, in pages */ 75 ulint seg_size; /*!< allocated pages of the file 76 segment containing ibuf header and 77 tree */ 78 bool empty; /*!< Protected by the page 79 latch of the root page of the 80 insert buffer tree 81 (FSP_IBUF_TREE_ROOT_PAGE_NO). true 82 if and only if the insert 83 buffer tree is empty. */ 84 ulint free_list_len; /*!< length of the free list */ 85 ulint height; /*!< tree height */ 86 dict_index_t* index; /*!< insert buffer index */ 87 88 ulint n_merges; /*!< number of pages merged */ 89 ulint n_merged_ops[IBUF_OP_COUNT]; 90 /*!< number of operations of each type 91 merged to index pages */ 92 ulint n_discarded_ops[IBUF_OP_COUNT]; 93 /*!< number of operations of each type 94 discarded without merging due to the 95 tablespace being deleted or the 96 index being dropped */ 97}; 98 99/************************************************************************//** 100Sets the free bit of the page in the ibuf bitmap. This is done in a separate 101mini-transaction, hence this operation does not restrict further work to only 102ibuf bitmap operations, which would result if the latch to the bitmap page 103were kept. */ 104UNIV_INTERN 105void 106ibuf_set_free_bits_func( 107/*====================*/ 108 buf_block_t* block, /*!< in: index page of a non-clustered index; 109 free bit is reset if page level is 0 */ 110#ifdef UNIV_IBUF_DEBUG 111 ulint max_val,/*!< in: ULINT_UNDEFINED or a maximum 112 value which the bits must have before 113 setting; this is for debugging */ 114#endif /* UNIV_IBUF_DEBUG */ 115 ulint val); /*!< in: value to set: < 4 */ 116#ifdef UNIV_IBUF_DEBUG 117# define ibuf_set_free_bits(b,v,max) ibuf_set_free_bits_func(b,max,v) 118#else /* UNIV_IBUF_DEBUG */ 119# define ibuf_set_free_bits(b,v,max) ibuf_set_free_bits_func(b,v) 120#endif /* UNIV_IBUF_DEBUG */ 121 122/**********************************************************************//** 123A basic partial test if an insert to the insert buffer could be possible and 124recommended. */ 125UNIV_INLINE 126ibool 127ibuf_should_try( 128/*============*/ 129 dict_index_t* index, /*!< in: index where to insert */ 130 ulint ignore_sec_unique) /*!< in: if != 0, we should 131 ignore UNIQUE constraint on 132 a secondary index when we 133 decide */ 134{ 135 return(ibuf_use != IBUF_USE_NONE 136 && ibuf->max_size != 0 137 && !dict_index_is_clust(index) 138 && index->table->quiesce == QUIESCE_NONE 139 && (ignore_sec_unique || !dict_index_is_unique(index)) 140 && srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE); 141} 142 143/******************************************************************//** 144Returns TRUE if the current OS thread is performing an insert buffer 145routine. 146 147For instance, a read-ahead of non-ibuf pages is forbidden by threads 148that are executing an insert buffer routine. 149@return TRUE if inside an insert buffer routine */ 150UNIV_INLINE 151ibool 152ibuf_inside( 153/*========*/ 154 const mtr_t* mtr) /*!< in: mini-transaction */ 155{ 156 return(mtr->inside_ibuf); 157} 158 159/***********************************************************************//** 160Checks if a page address is an ibuf bitmap page address. 161@return TRUE if a bitmap page */ 162UNIV_INLINE 163ibool 164ibuf_bitmap_page( 165/*=============*/ 166 ulint zip_size,/*!< in: compressed page size in bytes; 167 0 for uncompressed pages */ 168 ulint page_no)/*!< in: page number */ 169{ 170 ut_ad(ut_is_2pow(zip_size)); 171 172 if (!zip_size) { 173 return((page_no & (UNIV_PAGE_SIZE - 1)) 174 == FSP_IBUF_BITMAP_OFFSET); 175 } 176 177 return((page_no & (zip_size - 1)) == FSP_IBUF_BITMAP_OFFSET); 178} 179 180/*********************************************************************//** 181Translates the free space on a page to a value in the ibuf bitmap. 182@return value for ibuf bitmap bits */ 183UNIV_INLINE 184ulint 185ibuf_index_page_calc_free_bits( 186/*===========================*/ 187 ulint zip_size, /*!< in: compressed page size in bytes; 188 0 for uncompressed pages */ 189 ulint max_ins_size) /*!< in: maximum insert size after reorganize 190 for the page */ 191{ 192 ulint n; 193 ut_ad(ut_is_2pow(zip_size)); 194 ut_ad(!zip_size || zip_size > IBUF_PAGE_SIZE_PER_FREE_SPACE); 195 ut_ad(zip_size <= UNIV_ZIP_SIZE_MAX); 196 197 if (zip_size) { 198 n = max_ins_size 199 / (zip_size / IBUF_PAGE_SIZE_PER_FREE_SPACE); 200 } else { 201 n = max_ins_size 202 / (UNIV_PAGE_SIZE / IBUF_PAGE_SIZE_PER_FREE_SPACE); 203 } 204 205 if (n == 3) { 206 n = 2; 207 } 208 209 if (n > 3) { 210 n = 3; 211 } 212 213 return(n); 214} 215 216/*********************************************************************//** 217Translates the ibuf free bits to the free space on a page in bytes. 218@return maximum insert size after reorganize for the page */ 219UNIV_INLINE 220ulint 221ibuf_index_page_calc_free_from_bits( 222/*================================*/ 223 ulint zip_size,/*!< in: compressed page size in bytes; 224 0 for uncompressed pages */ 225 ulint bits) /*!< in: value for ibuf bitmap bits */ 226{ 227 ut_ad(bits < 4); 228 ut_ad(ut_is_2pow(zip_size)); 229 ut_ad(!zip_size || zip_size > IBUF_PAGE_SIZE_PER_FREE_SPACE); 230 ut_ad(zip_size <= UNIV_ZIP_SIZE_MAX); 231 232 if (zip_size) { 233 if (bits == 3) { 234 return(4 * zip_size / IBUF_PAGE_SIZE_PER_FREE_SPACE); 235 } 236 237 return(bits * zip_size / IBUF_PAGE_SIZE_PER_FREE_SPACE); 238 } 239 240 if (bits == 3) { 241 return(4 * UNIV_PAGE_SIZE / IBUF_PAGE_SIZE_PER_FREE_SPACE); 242 } 243 244 return(bits * (UNIV_PAGE_SIZE / IBUF_PAGE_SIZE_PER_FREE_SPACE)); 245} 246 247/*********************************************************************//** 248Translates the free space on a compressed page to a value in the ibuf bitmap. 249@return value for ibuf bitmap bits */ 250UNIV_INLINE 251ulint 252ibuf_index_page_calc_free_zip( 253/*==========================*/ 254 ulint zip_size, 255 /*!< in: compressed page size in bytes */ 256 const buf_block_t* block) /*!< in: buffer block */ 257{ 258 ulint max_ins_size; 259 const page_zip_des_t* page_zip; 260 lint zip_max_ins; 261 262 ut_ad(zip_size == buf_block_get_zip_size(block)); 263 ut_ad(zip_size); 264 265 /* Consider the maximum insert size on the uncompressed page 266 without reorganizing the page. We must not assume anything 267 about the compression ratio. If zip_max_ins > max_ins_size and 268 there is 1/4 garbage on the page, recompression after the 269 reorganize could fail, in theory. So, let us guarantee that 270 merging a buffered insert to a compressed page will always 271 succeed without reorganizing or recompressing the page, just 272 by using the page modification log. */ 273 max_ins_size = page_get_max_insert_size( 274 buf_block_get_frame(block), 1); 275 276 page_zip = buf_block_get_page_zip(block); 277 zip_max_ins = page_zip_max_ins_size(page_zip, 278 FALSE/* not clustered */); 279 280 if (zip_max_ins < 0) { 281 return(0); 282 } else if (max_ins_size > (ulint) zip_max_ins) { 283 max_ins_size = (ulint) zip_max_ins; 284 } 285 286 return(ibuf_index_page_calc_free_bits(zip_size, max_ins_size)); 287} 288 289/*********************************************************************//** 290Translates the free space on a page to a value in the ibuf bitmap. 291@return value for ibuf bitmap bits */ 292UNIV_INLINE 293ulint 294ibuf_index_page_calc_free( 295/*======================*/ 296 ulint zip_size,/*!< in: compressed page size in bytes; 297 0 for uncompressed pages */ 298 const buf_block_t* block) /*!< in: buffer block */ 299{ 300 ut_ad(zip_size == buf_block_get_zip_size(block)); 301 302 if (!zip_size) { 303 ulint max_ins_size; 304 305 max_ins_size = page_get_max_insert_size_after_reorganize( 306 buf_block_get_frame(block), 1); 307 308 return(ibuf_index_page_calc_free_bits(0, max_ins_size)); 309 } else { 310 return(ibuf_index_page_calc_free_zip(zip_size, block)); 311 } 312} 313 314/************************************************************************//** 315Updates the free bits of an uncompressed page in the ibuf bitmap if 316there is not enough free on the page any more. This is done in a 317separate mini-transaction, hence this operation does not restrict 318further work to only ibuf bitmap operations, which would result if the 319latch to the bitmap page were kept. NOTE: The free bits in the insert 320buffer bitmap must never exceed the free space on a page. It is 321unsafe to increment the bits in a separately committed 322mini-transaction, because in crash recovery, the free bits could 323momentarily be set too high. It is only safe to use this function for 324decrementing the free bits. Should more free space become available, 325we must not update the free bits here, because that would break crash 326recovery. */ 327UNIV_INLINE 328void 329ibuf_update_free_bits_if_full( 330/*==========================*/ 331 buf_block_t* block, /*!< in: index page to which we have added new 332 records; the free bits are updated if the 333 index is non-clustered and non-unique and 334 the page level is 0, and the page becomes 335 fuller */ 336 ulint max_ins_size,/*!< in: value of maximum insert size with 337 reorganize before the latest operation 338 performed to the page */ 339 ulint increase)/*!< in: upper limit for the additional space 340 used in the latest operation, if known, or 341 ULINT_UNDEFINED */ 342{ 343 ulint before; 344 ulint after; 345 346 ut_ad(!buf_block_get_page_zip(block)); 347 348 before = ibuf_index_page_calc_free_bits(0, max_ins_size); 349 350 if (max_ins_size >= increase) { 351#if ULINT32_UNDEFINED <= UNIV_PAGE_SIZE_MAX 352# error "ULINT32_UNDEFINED <= UNIV_PAGE_SIZE_MAX" 353#endif 354 after = ibuf_index_page_calc_free_bits(0, max_ins_size 355 - increase); 356#ifdef UNIV_IBUF_DEBUG 357 ut_a(after <= ibuf_index_page_calc_free(0, block)); 358#endif 359 } else { 360 after = ibuf_index_page_calc_free(0, block); 361 } 362 363 if (after == 0) { 364 /* We move the page to the front of the buffer pool LRU list: 365 the purpose of this is to prevent those pages to which we 366 cannot make inserts using the insert buffer from slipping 367 out of the buffer pool */ 368 369 buf_page_make_young(&block->page); 370 } 371 372 if (before > after) { 373 ibuf_set_free_bits(block, after, before); 374 } 375} 376#endif /* !UNIV_HOTBACKUP */ 377