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