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