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