mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-04 12:56:14 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			282 lines
		
	
	
	
		
			8.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			282 lines
		
	
	
	
		
			8.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*****************************************************************************
 | 
						|
 | 
						|
Copyright (c) 1997, 2015, Oracle and/or its affiliates. All Rights Reserved.
 | 
						|
Copyright (c) 2021, MariaDB Corporation.
 | 
						|
 | 
						|
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, Fifth Floor, Boston, MA 02110-1335 USA
 | 
						|
 | 
						|
*****************************************************************************/
 | 
						|
 | 
						|
/**************************************************//**
 | 
						|
@file include/ibuf0ibuf.ic
 | 
						|
Insert buffer
 | 
						|
 | 
						|
Created 7/19/1997 Heikki Tuuri
 | 
						|
*******************************************************/
 | 
						|
 | 
						|
#include "page0page.h"
 | 
						|
#include "page0zip.h"
 | 
						|
#include "fsp0types.h"
 | 
						|
#include "buf0lru.h"
 | 
						|
 | 
						|
/** An index page must contain at least srv_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->enter_ibuf();
 | 
						|
 | 
						|
	if (high_level_read_only || srv_read_only_mode) {
 | 
						|
		mtr_set_log_mode(mtr, MTR_LOG_NO_REDO);
 | 
						|
	}
 | 
						|
 | 
						|
}
 | 
						|
/***************************************************************//**
 | 
						|
Commits an insert buffer mini-transaction. */
 | 
						|
UNIV_INLINE
 | 
						|
void
 | 
						|
ibuf_mtr_commit(
 | 
						|
/*============*/
 | 
						|
	mtr_t*	mtr)	/*!< in/out: mini-transaction */
 | 
						|
{
 | 
						|
	ut_ad(mtr->is_inside_ibuf());
 | 
						|
	ut_d(mtr->exit_ibuf());
 | 
						|
 | 
						|
	mtr_commit(mtr);
 | 
						|
}
 | 
						|
 | 
						|
/************************************************************************//**
 | 
						|
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. */
 | 
						|
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 */
 | 
						|
{
 | 
						|
  if (index->type & (DICT_CLUSTERED | DICT_IBUF | DICT_SPATIAL) ||
 | 
						|
      !innodb_change_buffering || !ibuf.max_size)
 | 
						|
    return false;
 | 
						|
  if (!ignore_sec_unique && index->is_unique())
 | 
						|
    return false;
 | 
						|
  if (index->table->quiesce != QUIESCE_NONE)
 | 
						|
    return false;
 | 
						|
  for (unsigned i= 0; i < index->n_fields; i++)
 | 
						|
    if (index->fields[i].descending)
 | 
						|
      return false;
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
/******************************************************************//**
 | 
						|
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->is_inside_ibuf());
 | 
						|
}
 | 
						|
 | 
						|
/** Translates the free space on a page to a value in the ibuf bitmap.
 | 
						|
@param[in]	page_size	page size in bytes
 | 
						|
@param[in]	max_ins_size	maximum insert size after reorganize for
 | 
						|
the page
 | 
						|
@return value for ibuf bitmap bits */
 | 
						|
UNIV_INLINE
 | 
						|
ulint
 | 
						|
ibuf_index_page_calc_free_bits(
 | 
						|
	ulint	page_size,
 | 
						|
	ulint	max_ins_size)
 | 
						|
{
 | 
						|
	ulint	n;
 | 
						|
	ut_ad(ut_is_2pow(page_size));
 | 
						|
	ut_ad(page_size > IBUF_PAGE_SIZE_PER_FREE_SPACE);
 | 
						|
 | 
						|
	n = max_ins_size / (page_size / IBUF_PAGE_SIZE_PER_FREE_SPACE);
 | 
						|
 | 
						|
	if (n == 3) {
 | 
						|
		n = 2;
 | 
						|
	}
 | 
						|
 | 
						|
	if (n > 3) {
 | 
						|
		n = 3;
 | 
						|
	}
 | 
						|
 | 
						|
	return(n);
 | 
						|
}
 | 
						|
 | 
						|
/*********************************************************************//**
 | 
						|
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(
 | 
						|
/*==========================*/
 | 
						|
	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(block->page.zip.data);
 | 
						|
 | 
						|
	/* 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(block->physical_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(
 | 
						|
/*======================*/
 | 
						|
	const buf_block_t*	block)	/*!< in: buffer block */
 | 
						|
{
 | 
						|
	if (!block->page.zip.data) {
 | 
						|
		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(
 | 
						|
				block->physical_size(), max_ins_size));
 | 
						|
	} else {
 | 
						|
		return(ibuf_index_page_calc_free_zip(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) == NULL);
 | 
						|
 | 
						|
	before = ibuf_index_page_calc_free_bits(
 | 
						|
		srv_page_size, max_ins_size);
 | 
						|
 | 
						|
	if (max_ins_size >= increase) {
 | 
						|
		compile_time_assert(ULINT32_UNDEFINED > UNIV_PAGE_SIZE_MAX);
 | 
						|
		after = ibuf_index_page_calc_free_bits(
 | 
						|
			srv_page_size, max_ins_size - increase);
 | 
						|
#ifdef UNIV_IBUF_DEBUG
 | 
						|
		ut_a(after <= ibuf_index_page_calc_free(block));
 | 
						|
#endif
 | 
						|
	} else {
 | 
						|
		after = ibuf_index_page_calc_free(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);
 | 
						|
	}
 | 
						|
}
 |