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