mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 20:42:30 +01:00
368 lines
12 KiB
Text
368 lines
12 KiB
Text
/*****************************************************************************
|
|
|
|
Copyright (c) 1997, 2015, Oracle and/or its affiliates. All Rights Reserved.
|
|
|
|
This program is free software; you can redistribute it and/or modify it under
|
|
the terms of the GNU General Public License as published by the Free Software
|
|
Foundation; version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License along with
|
|
this program; if not, write to the Free Software Foundation, Inc.,
|
|
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
|
|
|
|
*****************************************************************************/
|
|
|
|
/**************************************************//**
|
|
@file include/ibuf0ibuf.ic
|
|
Insert buffer
|
|
|
|
Created 7/19/1997 Heikki Tuuri
|
|
*******************************************************/
|
|
|
|
#include "page0page.h"
|
|
#include "page0zip.h"
|
|
#ifndef UNIV_HOTBACKUP
|
|
#include "buf0lru.h"
|
|
|
|
/** An index page must contain at least UNIV_PAGE_SIZE /
|
|
IBUF_PAGE_SIZE_PER_FREE_SPACE bytes of free space for ibuf to try to
|
|
buffer inserts to this page. If there is this much of free space, the
|
|
corresponding bits are set in the ibuf bitmap. */
|
|
#define IBUF_PAGE_SIZE_PER_FREE_SPACE 32
|
|
|
|
/***************************************************************//**
|
|
Starts an insert buffer mini-transaction. */
|
|
UNIV_INLINE
|
|
void
|
|
ibuf_mtr_start(
|
|
/*===========*/
|
|
mtr_t* mtr) /*!< out: mini-transaction */
|
|
{
|
|
mtr_start(mtr);
|
|
mtr->inside_ibuf = TRUE;
|
|
}
|
|
/***************************************************************//**
|
|
Commits an insert buffer mini-transaction. */
|
|
UNIV_INLINE
|
|
void
|
|
ibuf_mtr_commit(
|
|
/*============*/
|
|
mtr_t* mtr) /*!< in/out: mini-transaction */
|
|
{
|
|
ut_ad(mtr->inside_ibuf);
|
|
ut_d(mtr->inside_ibuf = FALSE);
|
|
mtr_commit(mtr);
|
|
}
|
|
|
|
/** Insert buffer struct */
|
|
struct ibuf_t{
|
|
ulint size; /*!< current size of the ibuf index
|
|
tree, in pages */
|
|
ulint max_size; /*!< recommended maximum size of the
|
|
ibuf index tree, in pages */
|
|
ulint seg_size; /*!< allocated pages of the file
|
|
segment containing ibuf header and
|
|
tree */
|
|
bool empty; /*!< Protected by the page
|
|
latch of the root page of the
|
|
insert buffer tree
|
|
(FSP_IBUF_TREE_ROOT_PAGE_NO). true
|
|
if and only if the insert
|
|
buffer tree is empty. */
|
|
ulint free_list_len; /*!< length of the free list */
|
|
ulint height; /*!< tree height */
|
|
dict_index_t* index; /*!< insert buffer index */
|
|
|
|
ulint n_merges; /*!< number of pages merged */
|
|
ulint n_merged_ops[IBUF_OP_COUNT];
|
|
/*!< number of operations of each type
|
|
merged to index pages */
|
|
ulint n_discarded_ops[IBUF_OP_COUNT];
|
|
/*!< number of operations of each type
|
|
discarded without merging due to the
|
|
tablespace being deleted or the
|
|
index being dropped */
|
|
};
|
|
|
|
/************************************************************************//**
|
|
Sets the free bit of the page in the ibuf bitmap. This is done in a separate
|
|
mini-transaction, hence this operation does not restrict further work to only
|
|
ibuf bitmap operations, which would result if the latch to the bitmap page
|
|
were kept. */
|
|
UNIV_INTERN
|
|
void
|
|
ibuf_set_free_bits_func(
|
|
/*====================*/
|
|
buf_block_t* block, /*!< in: index page of a non-clustered index;
|
|
free bit is reset if page level is 0 */
|
|
#ifdef UNIV_IBUF_DEBUG
|
|
ulint max_val,/*!< in: ULINT_UNDEFINED or a maximum
|
|
value which the bits must have before
|
|
setting; this is for debugging */
|
|
#endif /* UNIV_IBUF_DEBUG */
|
|
ulint val); /*!< in: value to set: < 4 */
|
|
#ifdef UNIV_IBUF_DEBUG
|
|
# define ibuf_set_free_bits(b,v,max) ibuf_set_free_bits_func(b,max,v)
|
|
#else /* UNIV_IBUF_DEBUG */
|
|
# define ibuf_set_free_bits(b,v,max) ibuf_set_free_bits_func(b,v)
|
|
#endif /* UNIV_IBUF_DEBUG */
|
|
|
|
/**********************************************************************//**
|
|
A basic partial test if an insert to the insert buffer could be possible and
|
|
recommended. */
|
|
UNIV_INLINE
|
|
ibool
|
|
ibuf_should_try(
|
|
/*============*/
|
|
dict_index_t* index, /*!< in: index where to insert */
|
|
ulint ignore_sec_unique) /*!< in: if != 0, we should
|
|
ignore UNIQUE constraint on
|
|
a secondary index when we
|
|
decide */
|
|
{
|
|
return(ibuf_use != IBUF_USE_NONE
|
|
&& ibuf->max_size != 0
|
|
&& !dict_index_is_clust(index)
|
|
&& index->table->quiesce == QUIESCE_NONE
|
|
&& (ignore_sec_unique || !dict_index_is_unique(index))
|
|
&& srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE);
|
|
}
|
|
|
|
/******************************************************************//**
|
|
Returns TRUE if the current OS thread is performing an insert buffer
|
|
routine.
|
|
|
|
For instance, a read-ahead of non-ibuf pages is forbidden by threads
|
|
that are executing an insert buffer routine.
|
|
@return TRUE if inside an insert buffer routine */
|
|
UNIV_INLINE
|
|
ibool
|
|
ibuf_inside(
|
|
/*========*/
|
|
const mtr_t* mtr) /*!< in: mini-transaction */
|
|
{
|
|
return(mtr->inside_ibuf);
|
|
}
|
|
|
|
/***********************************************************************//**
|
|
Checks if a page address is an ibuf bitmap page address.
|
|
@return TRUE if a bitmap page */
|
|
UNIV_INLINE
|
|
ibool
|
|
ibuf_bitmap_page(
|
|
/*=============*/
|
|
ulint zip_size,/*!< in: compressed page size in bytes;
|
|
0 for uncompressed pages */
|
|
ulint page_no)/*!< in: page number */
|
|
{
|
|
ut_ad(ut_is_2pow(zip_size));
|
|
|
|
if (!zip_size) {
|
|
return((page_no & (UNIV_PAGE_SIZE - 1))
|
|
== FSP_IBUF_BITMAP_OFFSET);
|
|
}
|
|
|
|
return((page_no & (zip_size - 1)) == FSP_IBUF_BITMAP_OFFSET);
|
|
}
|
|
|
|
/*********************************************************************//**
|
|
Translates the free space on a page to a value in the ibuf bitmap.
|
|
@return value for ibuf bitmap bits */
|
|
UNIV_INLINE
|
|
ulint
|
|
ibuf_index_page_calc_free_bits(
|
|
/*===========================*/
|
|
ulint zip_size, /*!< in: compressed page size in bytes;
|
|
0 for uncompressed pages */
|
|
ulint max_ins_size) /*!< in: maximum insert size after reorganize
|
|
for the page */
|
|
{
|
|
ulint n;
|
|
ut_ad(ut_is_2pow(zip_size));
|
|
ut_ad(!zip_size || zip_size > IBUF_PAGE_SIZE_PER_FREE_SPACE);
|
|
ut_ad(zip_size <= UNIV_ZIP_SIZE_MAX);
|
|
|
|
if (zip_size) {
|
|
n = max_ins_size
|
|
/ (zip_size / IBUF_PAGE_SIZE_PER_FREE_SPACE);
|
|
} else {
|
|
n = max_ins_size
|
|
/ (UNIV_PAGE_SIZE / IBUF_PAGE_SIZE_PER_FREE_SPACE);
|
|
}
|
|
|
|
if (n == 3) {
|
|
n = 2;
|
|
}
|
|
|
|
if (n > 3) {
|
|
n = 3;
|
|
}
|
|
|
|
return(n);
|
|
}
|
|
|
|
/*********************************************************************//**
|
|
Translates the ibuf free bits to the free space on a page in bytes.
|
|
@return maximum insert size after reorganize for the page */
|
|
UNIV_INLINE
|
|
ulint
|
|
ibuf_index_page_calc_free_from_bits(
|
|
/*================================*/
|
|
ulint zip_size,/*!< in: compressed page size in bytes;
|
|
0 for uncompressed pages */
|
|
ulint bits) /*!< in: value for ibuf bitmap bits */
|
|
{
|
|
ut_ad(bits < 4);
|
|
ut_ad(ut_is_2pow(zip_size));
|
|
ut_ad(!zip_size || zip_size > IBUF_PAGE_SIZE_PER_FREE_SPACE);
|
|
ut_ad(zip_size <= UNIV_ZIP_SIZE_MAX);
|
|
|
|
if (zip_size) {
|
|
if (bits == 3) {
|
|
return(4 * zip_size / IBUF_PAGE_SIZE_PER_FREE_SPACE);
|
|
}
|
|
|
|
return(bits * zip_size / IBUF_PAGE_SIZE_PER_FREE_SPACE);
|
|
}
|
|
|
|
if (bits == 3) {
|
|
return(4 * UNIV_PAGE_SIZE / IBUF_PAGE_SIZE_PER_FREE_SPACE);
|
|
}
|
|
|
|
return(bits * (UNIV_PAGE_SIZE / IBUF_PAGE_SIZE_PER_FREE_SPACE));
|
|
}
|
|
|
|
/*********************************************************************//**
|
|
Translates the free space on a compressed page to a value in the ibuf bitmap.
|
|
@return value for ibuf bitmap bits */
|
|
UNIV_INLINE
|
|
ulint
|
|
ibuf_index_page_calc_free_zip(
|
|
/*==========================*/
|
|
ulint zip_size,
|
|
/*!< in: compressed page size in bytes */
|
|
const buf_block_t* block) /*!< in: buffer block */
|
|
{
|
|
ulint max_ins_size;
|
|
const page_zip_des_t* page_zip;
|
|
lint zip_max_ins;
|
|
|
|
ut_ad(zip_size == buf_block_get_zip_size(block));
|
|
ut_ad(zip_size);
|
|
|
|
/* Consider the maximum insert size on the uncompressed page
|
|
without reorganizing the page. We must not assume anything
|
|
about the compression ratio. If zip_max_ins > max_ins_size and
|
|
there is 1/4 garbage on the page, recompression after the
|
|
reorganize could fail, in theory. So, let us guarantee that
|
|
merging a buffered insert to a compressed page will always
|
|
succeed without reorganizing or recompressing the page, just
|
|
by using the page modification log. */
|
|
max_ins_size = page_get_max_insert_size(
|
|
buf_block_get_frame(block), 1);
|
|
|
|
page_zip = buf_block_get_page_zip(block);
|
|
zip_max_ins = page_zip_max_ins_size(page_zip,
|
|
FALSE/* not clustered */);
|
|
|
|
if (zip_max_ins < 0) {
|
|
return(0);
|
|
} else if (max_ins_size > (ulint) zip_max_ins) {
|
|
max_ins_size = (ulint) zip_max_ins;
|
|
}
|
|
|
|
return(ibuf_index_page_calc_free_bits(zip_size, max_ins_size));
|
|
}
|
|
|
|
/*********************************************************************//**
|
|
Translates the free space on a page to a value in the ibuf bitmap.
|
|
@return value for ibuf bitmap bits */
|
|
UNIV_INLINE
|
|
ulint
|
|
ibuf_index_page_calc_free(
|
|
/*======================*/
|
|
ulint zip_size,/*!< in: compressed page size in bytes;
|
|
0 for uncompressed pages */
|
|
const buf_block_t* block) /*!< in: buffer block */
|
|
{
|
|
ut_ad(zip_size == buf_block_get_zip_size(block));
|
|
|
|
if (!zip_size) {
|
|
ulint max_ins_size;
|
|
|
|
max_ins_size = page_get_max_insert_size_after_reorganize(
|
|
buf_block_get_frame(block), 1);
|
|
|
|
return(ibuf_index_page_calc_free_bits(0, max_ins_size));
|
|
} else {
|
|
return(ibuf_index_page_calc_free_zip(zip_size, block));
|
|
}
|
|
}
|
|
|
|
/************************************************************************//**
|
|
Updates the free bits of an uncompressed page in the ibuf bitmap if
|
|
there is not enough free on the page any more. This is done in a
|
|
separate mini-transaction, hence this operation does not restrict
|
|
further work to only ibuf bitmap operations, which would result if the
|
|
latch to the bitmap page were kept. NOTE: The free bits in the insert
|
|
buffer bitmap must never exceed the free space on a page. It is
|
|
unsafe to increment the bits in a separately committed
|
|
mini-transaction, because in crash recovery, the free bits could
|
|
momentarily be set too high. It is only safe to use this function for
|
|
decrementing the free bits. Should more free space become available,
|
|
we must not update the free bits here, because that would break crash
|
|
recovery. */
|
|
UNIV_INLINE
|
|
void
|
|
ibuf_update_free_bits_if_full(
|
|
/*==========================*/
|
|
buf_block_t* block, /*!< in: index page to which we have added new
|
|
records; the free bits are updated if the
|
|
index is non-clustered and non-unique and
|
|
the page level is 0, and the page becomes
|
|
fuller */
|
|
ulint max_ins_size,/*!< in: value of maximum insert size with
|
|
reorganize before the latest operation
|
|
performed to the page */
|
|
ulint increase)/*!< in: upper limit for the additional space
|
|
used in the latest operation, if known, or
|
|
ULINT_UNDEFINED */
|
|
{
|
|
ulint before;
|
|
ulint after;
|
|
|
|
ut_ad(!buf_block_get_page_zip(block));
|
|
|
|
before = ibuf_index_page_calc_free_bits(0, max_ins_size);
|
|
|
|
if (max_ins_size >= increase) {
|
|
#if ULINT32_UNDEFINED <= UNIV_PAGE_SIZE_MAX
|
|
# error "ULINT32_UNDEFINED <= UNIV_PAGE_SIZE_MAX"
|
|
#endif
|
|
after = ibuf_index_page_calc_free_bits(0, max_ins_size
|
|
- increase);
|
|
#ifdef UNIV_IBUF_DEBUG
|
|
ut_a(after <= ibuf_index_page_calc_free(0, block));
|
|
#endif
|
|
} else {
|
|
after = ibuf_index_page_calc_free(0, block);
|
|
}
|
|
|
|
if (after == 0) {
|
|
/* We move the page to the front of the buffer pool LRU list:
|
|
the purpose of this is to prevent those pages to which we
|
|
cannot make inserts using the insert buffer from slipping
|
|
out of the buffer pool */
|
|
|
|
buf_page_make_young(&block->page);
|
|
}
|
|
|
|
if (before > after) {
|
|
ibuf_set_free_bits(block, after, before);
|
|
}
|
|
}
|
|
#endif /* !UNIV_HOTBACKUP */
|