| 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 |  |