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