mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 20:42:30 +01:00
9016198aa2
Apply innodb-5.0-* snapshots: ss1489 and ss1547. Fixes: Bug#9709: InnoDB inconsistensy causes "Operating System Error 32/33" Bug#22819: SHOW INNODB STATUS crashes the server with an assertion failure under high load Bug#25645: Assertion failure in file srv0srv.c Bug#27294: insert into ... select ... causes crash with innodb_locks_unsafe_for_binlog=1 Bug#28138: indexing column prefixes produces corruption in InnoDB innobase/btr/btr0btr.c: Apply innodb-5.0-* snapshots: ss1489 and ss1547. Revision r1547: branches/5.0: Merge r1546 from trunk: When buffering an insert to a prefix index of a variable-length column, do not incorrectly mark the column as fixed-length. (Bug #28138) ibuf_entry_build(): Instead of prefix_len, pass fixed_len to dtype_new_store_for_order_and_null_size(). Add debug assertions. btr_index_rec_validate(): Correct a comment about prefix indexes. rec_get_converted_size_new(), rec_convert_dtuple_to_rec_new(): Add debug assertions and comments. dict_col_type_assert_equal(): New debug function. innobase/buf/buf0buf.c: Apply innodb-5.0-* snapshots: ss1489 and ss1547. Revision r1502: branches/5.0: Add debug code for Bug 26081. This change has some debug assertions that have been promoted to normal assertions. These will need to be undone once we've nailed this bug. innobase/buf/buf0lru.c: Apply innodb-5.0-* snapshots: ss1489 and ss1547. Revision r1502: branches/5.0: Add debug code for Bug 26081. This change has some debug assertions that have been promoted to normal assertions. These will need to be undone once we've nailed this bug. innobase/ibuf/ibuf0ibuf.c: Apply innodb-5.0-* snapshots: ss1489 and ss1547. Revision r1547: branches/5.0: Merge r1546 from trunk: When buffering an insert to a prefix index of a variable-length column, do not incorrectly mark the column as fixed-length. (Bug #28138) ibuf_entry_build(): Instead of prefix_len, pass fixed_len to dtype_new_store_for_order_and_null_size(). Add debug assertions. btr_index_rec_validate(): Correct a comment about prefix indexes. rec_get_converted_size_new(), rec_convert_dtuple_to_rec_new(): Add debug assertions and comments. dict_col_type_assert_equal(): New debug function. innobase/include/buf0buf.ic: Apply innodb-5.0-* snapshots: ss1489 and ss1547. Revision r1502: branches/5.0: Add debug code for Bug 26081. This change has some debug assertions that have been promoted to normal assertions. These will need to be undone once we've nailed this bug. innobase/include/buf0lru.h: Apply innodb-5.0-* snapshots: ss1489 and ss1547. Revision r1502: branches/5.0: Add debug code for Bug 26081. This change has some debug assertions that have been promoted to normal assertions. These will need to be undone once we've nailed this bug. innobase/include/dict0dict.h: Apply innodb-5.0-* snapshots: ss1489 and ss1547. Revision r1547: branches/5.0: Merge r1546 from trunk: When buffering an insert to a prefix index of a variable-length column, do not incorrectly mark the column as fixed-length. (Bug #28138) ibuf_entry_build(): Instead of prefix_len, pass fixed_len to dtype_new_store_for_order_and_null_size(). Add debug assertions. btr_index_rec_validate(): Correct a comment about prefix indexes. rec_get_converted_size_new(), rec_convert_dtuple_to_rec_new(): Add debug assertions and comments. dict_col_type_assert_equal(): New debug function. innobase/include/dict0dict.ic: Apply innodb-5.0-* snapshots: ss1489 and ss1547. Revision r1547: branches/5.0: Merge r1546 from trunk: When buffering an insert to a prefix index of a variable-length column, do not incorrectly mark the column as fixed-length. (Bug #28138) ibuf_entry_build(): Instead of prefix_len, pass fixed_len to dtype_new_store_for_order_and_null_size(). Add debug assertions. btr_index_rec_validate(): Correct a comment about prefix indexes. rec_get_converted_size_new(), rec_convert_dtuple_to_rec_new(): Add debug assertions and comments. dict_col_type_assert_equal(): New debug function. innobase/include/dict0mem.h: Apply innodb-5.0-* snapshots: ss1489 and ss1547. Revision r1537: branches/5.0: merge r1536 and partially r1535 Change the comment to a more appropriate one. Discussed with Heikki on IM. Document that DICT_MAX_INDEX_COL_LEN should not be changed. innobase/include/os0file.h: Apply innodb-5.0-* snapshots: ss1489 and ss1547. Revision r1417: branches/5.0: Fix Bug#9709 by retrying (forever) if ERROR_SHARING_VIOLATION or ERROR_LOCK_VIOLATION is encountered during file operation. This is caused by backup software, so InnoDB should retry while the backup software is done with the file. Approved by: Heikki innobase/include/trx0trx.h: Apply innodb-5.0-* snapshots: ss1489 and ss1547. Revision r1463: branches/5.0: merge r1462 from trunk: Fix typo in comment. innobase/lock/lock0lock.c: Apply innodb-5.0-* snapshots: ss1489 and ss1547. Revision r1458: branches/5.0: Fix Bug#22819, remove assertion. (http://bugs.mysql.com/bug.php?id=22819) innobase/log/log0log.c: Apply innodb-5.0-* snapshots: ss1489 and ss1547. Revision r1520: Patch to allow monitor threads to stop before proceeding with normal shutdown. Also have a separate time counter for tablespace monitor. reviewed by: Heikki Revision r1525: backport of r1524 Log: Undo bad space formatting introduced in earlier commit r1521 spotted by: Marko innobase/mtr/mtr0mtr.c: Apply innodb-5.0-* snapshots: ss1489 and ss1547. Revision r1502: branches/5.0: Add debug code for Bug 26081. This change has some debug assertions that have been promoted to normal assertions. These will need to be undone once we've nailed this bug. innobase/os/os0file.c: Apply innodb-5.0-* snapshots: ss1489 and ss1547. Revision r1417: branches/5.0: Fix Bug#9709 by retrying (forever) if ERROR_SHARING_VIOLATION or ERROR_LOCK_VIOLATION is encountered during file operation. This is caused by backup software, so InnoDB should retry while the backup software is done with the file. Approved by: Heikki innobase/rem/rem0rec.c: Apply innodb-5.0-* snapshots: ss1489 and ss1547. Revision r1547: branches/5.0: Merge r1546 from trunk: When buffering an insert to a prefix index of a variable-length column, do not incorrectly mark the column as fixed-length. (Bug #28138) ibuf_entry_build(): Instead of prefix_len, pass fixed_len to dtype_new_store_for_order_and_null_size(). Add debug assertions. btr_index_rec_validate(): Correct a comment about prefix indexes. rec_get_converted_size_new(), rec_convert_dtuple_to_rec_new(): Add debug assertions and comments. dict_col_type_assert_equal(): New debug function. innobase/row/row0sel.c: Apply innodb-5.0-* snapshots: ss1489 and ss1547. Revision r1456: branches/5.0: merge r1452 from trunk: Fix phantom reads (http://bugs.mysql.com/27197) following Heikki's patch in the bug followup. innobase/srv/srv0srv.c: Apply innodb-5.0-* snapshots: ss1489 and ss1547. Revision r1460: branches/5.0: Merge r1459 from trunk: Fix typo in the comment. Revision r1520: Patch to allow monitor threads to stop before proceeding with normal shutdown. Also have a separate time counter for tablespace monitor. reviewed by: Heikki sql/ha_innodb.cc: Apply innodb-5.0-* snapshots: ss1489 and ss1547. Revision r1436: branches/5.0: Fix Bug#27294 by using trx returned by check_trx_exists() instead of prebuilt->trx. This has been fixed in 5.1 in r782. Approved by: Heikki Revision r1443: branches/5.0: merge r1442 from trunk: Potential fix for Bug#25645: "Move innobase_release_stat_resources(trx) outside the 'if' in ha_innobase::external_lock(). That would add more safety that whatever MySQL does at a query end, there would be no risk of a hang on the btr search latch." Also call innobase_release_temporary_latches() in the beginning of ha_innobase::close(). Approved by: Heikki Revision r1454: branches/5.0: merge r1453 from trunk: Bugfix: only call innobase_release_temporary_latches() in case of current_thd is not NULL, otherwise we get NULL pointer dereferencing. Revision r1504: branches/5.0: Apply patch for Bug 27650 from MySQL. Revision r1539: Backport of r1538 from 5.1 Do not return error in ha_innobase::info if srv_force_recovery >= 4. This is to allow for normal processing of the query by MySQL instead of generating an error. Reviewed by: Heikki
679 lines
18 KiB
Text
679 lines
18 KiB
Text
/******************************************************
|
|
The database buffer buf_pool
|
|
|
|
(c) 1995 Innobase Oy
|
|
|
|
Created 11/5/1995 Heikki Tuuri
|
|
*******************************************************/
|
|
|
|
#include "buf0flu.h"
|
|
#include "buf0lru.h"
|
|
#include "buf0rea.h"
|
|
#include "mtr0mtr.h"
|
|
|
|
/*************************************************************************
|
|
Print the mtr and block fields. */
|
|
|
|
void
|
|
buf_print_diagnostic(
|
|
/*=================*/
|
|
mtr_t* mtr, /* in: mtr to print */
|
|
const buf_block_t* block); /* in: block to print */
|
|
|
|
#ifdef UNIV_DEBUG
|
|
extern ulint buf_dbg_counter; /* This is used to insert validation
|
|
operations in execution in the
|
|
debug version */
|
|
#endif /* UNIV_DEBUG */
|
|
/************************************************************************
|
|
Recommends a move of a block to the start of the LRU list if there is danger
|
|
of dropping from the buffer pool. NOTE: does not reserve the buffer pool
|
|
mutex. */
|
|
UNIV_INLINE
|
|
ibool
|
|
buf_block_peek_if_too_old(
|
|
/*======================*/
|
|
/* out: TRUE if should be made younger */
|
|
buf_block_t* block) /* in: block to make younger */
|
|
{
|
|
return(buf_pool->freed_page_clock >= block->freed_page_clock
|
|
+ 1 + (buf_pool->curr_size / 1024));
|
|
}
|
|
|
|
/*************************************************************************
|
|
Gets the current size of buffer buf_pool in bytes. In the case of AWE, the
|
|
size of AWE window (= the frames). */
|
|
UNIV_INLINE
|
|
ulint
|
|
buf_pool_get_curr_size(void)
|
|
/*========================*/
|
|
/* out: size in bytes */
|
|
{
|
|
return((buf_pool->n_frames) * UNIV_PAGE_SIZE);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Gets the maximum size of buffer buf_pool in bytes. In the case of AWE, the
|
|
size of AWE window (= the frames). */
|
|
UNIV_INLINE
|
|
ulint
|
|
buf_pool_get_max_size(void)
|
|
/*=======================*/
|
|
/* out: size in bytes */
|
|
{
|
|
return((buf_pool->n_frames) * UNIV_PAGE_SIZE);
|
|
}
|
|
|
|
/***********************************************************************
|
|
Accessor function for block array. */
|
|
UNIV_INLINE
|
|
buf_block_t*
|
|
buf_pool_get_nth_block(
|
|
/*===================*/
|
|
/* out: pointer to block */
|
|
buf_pool_t* buf_pool,/* in: buf_pool */
|
|
ulint i) /* in: index of the block */
|
|
{
|
|
ut_ad(buf_pool);
|
|
ut_ad(i < buf_pool->max_size);
|
|
|
|
return(i + buf_pool->blocks);
|
|
}
|
|
|
|
/***********************************************************************
|
|
Checks if a pointer points to the block array of the buffer pool (blocks, not
|
|
the frames). */
|
|
UNIV_INLINE
|
|
ibool
|
|
buf_pool_is_block(
|
|
/*==============*/
|
|
/* out: TRUE if pointer to block */
|
|
void* ptr) /* in: pointer to memory */
|
|
{
|
|
if ((buf_pool->blocks <= (buf_block_t*)ptr)
|
|
&& ((buf_block_t*)ptr < buf_pool->blocks + buf_pool->max_size)) {
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
/************************************************************************
|
|
Gets the smallest oldest_modification lsn for any page in the pool. Returns
|
|
ut_dulint_zero if all modified pages have been flushed to disk. */
|
|
UNIV_INLINE
|
|
dulint
|
|
buf_pool_get_oldest_modification(void)
|
|
/*==================================*/
|
|
/* out: oldest modification in pool,
|
|
ut_dulint_zero if none */
|
|
{
|
|
buf_block_t* block;
|
|
dulint lsn;
|
|
|
|
mutex_enter(&(buf_pool->mutex));
|
|
|
|
block = UT_LIST_GET_LAST(buf_pool->flush_list);
|
|
|
|
if (block == NULL) {
|
|
lsn = ut_dulint_zero;
|
|
} else {
|
|
lsn = block->oldest_modification;
|
|
}
|
|
|
|
mutex_exit(&(buf_pool->mutex));
|
|
|
|
return(lsn);
|
|
}
|
|
|
|
/***********************************************************************
|
|
Increments the buf_pool clock by one and returns its new value. Remember
|
|
that in the 32 bit version the clock wraps around at 4 billion! */
|
|
UNIV_INLINE
|
|
ulint
|
|
buf_pool_clock_tic(void)
|
|
/*====================*/
|
|
/* out: new clock value */
|
|
{
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
ut_ad(mutex_own(&(buf_pool->mutex)));
|
|
#endif /* UNIV_SYNC_DEBUG */
|
|
|
|
buf_pool->ulint_clock++;
|
|
|
|
return(buf_pool->ulint_clock);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Gets a pointer to the memory frame of a block. */
|
|
UNIV_INLINE
|
|
buf_frame_t*
|
|
buf_block_get_frame(
|
|
/*================*/
|
|
/* out: pointer to the frame */
|
|
buf_block_t* block) /* in: pointer to the control block */
|
|
{
|
|
ut_ad(block);
|
|
ut_ad(block >= buf_pool->blocks);
|
|
ut_ad(block < buf_pool->blocks + buf_pool->max_size);
|
|
ut_ad(block->state != BUF_BLOCK_NOT_USED);
|
|
ut_ad((block->state != BUF_BLOCK_FILE_PAGE)
|
|
|| (block->buf_fix_count > 0));
|
|
|
|
return(block->frame);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Gets the space id of a block. */
|
|
UNIV_INLINE
|
|
ulint
|
|
buf_block_get_space(
|
|
/*================*/
|
|
/* out: space id */
|
|
buf_block_t* block) /* in: pointer to the control block */
|
|
{
|
|
ut_ad(block);
|
|
ut_ad(block >= buf_pool->blocks);
|
|
ut_ad(block < buf_pool->blocks + buf_pool->max_size);
|
|
ut_a(block->state == BUF_BLOCK_FILE_PAGE);
|
|
ut_ad(block->buf_fix_count > 0);
|
|
|
|
return(block->space);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Gets the page number of a block. */
|
|
UNIV_INLINE
|
|
ulint
|
|
buf_block_get_page_no(
|
|
/*==================*/
|
|
/* out: page number */
|
|
buf_block_t* block) /* in: pointer to the control block */
|
|
{
|
|
ut_ad(block);
|
|
ut_ad(block >= buf_pool->blocks);
|
|
ut_ad(block < buf_pool->blocks + buf_pool->max_size);
|
|
ut_a(block->state == BUF_BLOCK_FILE_PAGE);
|
|
ut_ad(block->buf_fix_count > 0);
|
|
|
|
return(block->offset);
|
|
}
|
|
|
|
/***********************************************************************
|
|
Gets the block to whose frame the pointer is pointing to. */
|
|
UNIV_INLINE
|
|
buf_block_t*
|
|
buf_block_align(
|
|
/*============*/
|
|
/* out: pointer to block */
|
|
byte* ptr) /* in: pointer to a frame */
|
|
{
|
|
buf_block_t* block;
|
|
buf_frame_t* frame_zero;
|
|
|
|
ut_ad(ptr);
|
|
|
|
frame_zero = buf_pool->frame_zero;
|
|
|
|
if (UNIV_UNLIKELY((ulint)ptr < (ulint)frame_zero)
|
|
|| UNIV_UNLIKELY((ulint)ptr > (ulint)(buf_pool->high_end))) {
|
|
|
|
ut_print_timestamp(stderr);
|
|
fprintf(stderr,
|
|
"InnoDB: Error: trying to access a stray pointer %p\n"
|
|
"InnoDB: buf pool start is at %p, end at %p\n"
|
|
"InnoDB: Probable reason is database corruption or memory\n"
|
|
"InnoDB: corruption. If this happens in an InnoDB database recovery, see\n"
|
|
"InnoDB: http://dev.mysql.com/doc/refman/5.0/en/forcing-recovery.html\n"
|
|
"InnoDB: how to force recovery.\n",
|
|
ptr, frame_zero,
|
|
buf_pool->high_end);
|
|
ut_error;
|
|
}
|
|
|
|
block = *(buf_pool->blocks_of_frames + (((ulint)(ptr - frame_zero))
|
|
>> UNIV_PAGE_SIZE_SHIFT));
|
|
return(block);
|
|
}
|
|
|
|
/***********************************************************************
|
|
Gets the frame the pointer is pointing to. */
|
|
UNIV_INLINE
|
|
buf_frame_t*
|
|
buf_frame_align(
|
|
/*============*/
|
|
/* out: pointer to frame */
|
|
byte* ptr) /* in: pointer to a frame */
|
|
{
|
|
buf_frame_t* frame;
|
|
|
|
ut_ad(ptr);
|
|
|
|
frame = ut_align_down(ptr, UNIV_PAGE_SIZE);
|
|
|
|
if (UNIV_UNLIKELY((ulint)frame < (ulint)(buf_pool->frame_zero))
|
|
|| UNIV_UNLIKELY((ulint)frame >= (ulint)(buf_pool->high_end))) {
|
|
|
|
ut_print_timestamp(stderr);
|
|
fprintf(stderr,
|
|
"InnoDB: Error: trying to access a stray pointer %p\n"
|
|
"InnoDB: buf pool start is at %p, end at %p\n"
|
|
"InnoDB: Probable reason is database corruption or memory\n"
|
|
"InnoDB: corruption. If this happens in an InnoDB database recovery, see\n"
|
|
"InnoDB: http://dev.mysql.com/doc/refman/5.0/en/forcing-recovery.html\n"
|
|
"InnoDB: how to force recovery.\n",
|
|
ptr, buf_pool->frame_zero,
|
|
buf_pool->high_end);
|
|
ut_error;
|
|
}
|
|
|
|
return(frame);
|
|
}
|
|
|
|
/**************************************************************************
|
|
Gets the page number of a pointer pointing within a buffer frame containing
|
|
a file page. */
|
|
UNIV_INLINE
|
|
ulint
|
|
buf_frame_get_page_no(
|
|
/*==================*/
|
|
/* out: page number */
|
|
byte* ptr) /* in: pointer to within a buffer frame */
|
|
{
|
|
return(buf_block_get_page_no(buf_block_align(ptr)));
|
|
}
|
|
|
|
/**************************************************************************
|
|
Gets the space id of a pointer pointing within a buffer frame containing a
|
|
file page. */
|
|
UNIV_INLINE
|
|
ulint
|
|
buf_frame_get_space_id(
|
|
/*===================*/
|
|
/* out: space id */
|
|
byte* ptr) /* in: pointer to within a buffer frame */
|
|
{
|
|
return(buf_block_get_space(buf_block_align(ptr)));
|
|
}
|
|
|
|
/**************************************************************************
|
|
Gets the space id, page offset, and byte offset within page of a
|
|
pointer pointing to a buffer frame containing a file page. */
|
|
UNIV_INLINE
|
|
void
|
|
buf_ptr_get_fsp_addr(
|
|
/*=================*/
|
|
byte* ptr, /* in: pointer to a buffer frame */
|
|
ulint* space, /* out: space id */
|
|
fil_addr_t* addr) /* out: page offset and byte offset */
|
|
{
|
|
buf_block_t* block;
|
|
|
|
block = buf_block_align(ptr);
|
|
|
|
*space = buf_block_get_space(block);
|
|
addr->page = buf_block_get_page_no(block);
|
|
addr->boffset = ptr - buf_frame_align(ptr);
|
|
}
|
|
|
|
/**************************************************************************
|
|
Gets the hash value of the page the pointer is pointing to. This can be used
|
|
in searches in the lock hash table. */
|
|
UNIV_INLINE
|
|
ulint
|
|
buf_frame_get_lock_hash_val(
|
|
/*========================*/
|
|
/* out: lock hash value */
|
|
byte* ptr) /* in: pointer to within a buffer frame */
|
|
{
|
|
buf_block_t* block;
|
|
|
|
block = buf_block_align(ptr);
|
|
|
|
return(block->lock_hash_val);
|
|
}
|
|
|
|
/**************************************************************************
|
|
Gets the mutex number protecting the page record lock hash chain in the lock
|
|
table. */
|
|
UNIV_INLINE
|
|
mutex_t*
|
|
buf_frame_get_mutex(
|
|
/*================*/
|
|
/* out: mutex */
|
|
byte* ptr) /* in: pointer to within a buffer frame */
|
|
{
|
|
buf_block_t* block;
|
|
|
|
block = buf_block_align(ptr);
|
|
|
|
return(&block->mutex);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Copies contents of a buffer frame to a given buffer. */
|
|
UNIV_INLINE
|
|
byte*
|
|
buf_frame_copy(
|
|
/*===========*/
|
|
/* out: buf */
|
|
byte* buf, /* in: buffer to copy to */
|
|
buf_frame_t* frame) /* in: buffer frame */
|
|
{
|
|
ut_ad(buf && frame);
|
|
|
|
ut_memcpy(buf, frame, UNIV_PAGE_SIZE);
|
|
|
|
return(buf);
|
|
}
|
|
|
|
/************************************************************************
|
|
Calculates a folded value of a file page address to use in the page hash
|
|
table. */
|
|
UNIV_INLINE
|
|
ulint
|
|
buf_page_address_fold(
|
|
/*==================*/
|
|
/* out: the folded value */
|
|
ulint space, /* in: space id */
|
|
ulint offset) /* in: offset of the page within space */
|
|
{
|
|
return((space << 20) + space + offset);
|
|
}
|
|
|
|
/************************************************************************
|
|
This function is used to get info if there is an io operation
|
|
going on on a buffer page. */
|
|
UNIV_INLINE
|
|
ibool
|
|
buf_page_io_query(
|
|
/*==============*/
|
|
/* out: TRUE if io going on */
|
|
buf_block_t* block) /* in: buf_pool block, must be bufferfixed */
|
|
{
|
|
mutex_enter(&(buf_pool->mutex));
|
|
|
|
ut_ad(block->state == BUF_BLOCK_FILE_PAGE);
|
|
ut_ad(block->buf_fix_count > 0);
|
|
|
|
if (block->io_fix != 0) {
|
|
mutex_exit(&(buf_pool->mutex));
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
mutex_exit(&(buf_pool->mutex));
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
/************************************************************************
|
|
Gets the youngest modification log sequence number for a frame. Returns zero
|
|
if not a file page or no modification occurred yet. */
|
|
UNIV_INLINE
|
|
dulint
|
|
buf_frame_get_newest_modification(
|
|
/*==============================*/
|
|
/* out: newest modification to the page */
|
|
buf_frame_t* frame) /* in: pointer to a frame */
|
|
{
|
|
buf_block_t* block;
|
|
dulint lsn;
|
|
|
|
ut_ad(frame);
|
|
|
|
block = buf_block_align(frame);
|
|
|
|
mutex_enter(&(buf_pool->mutex));
|
|
|
|
if (block->state == BUF_BLOCK_FILE_PAGE) {
|
|
lsn = block->newest_modification;
|
|
} else {
|
|
lsn = ut_dulint_zero;
|
|
}
|
|
|
|
mutex_exit(&(buf_pool->mutex));
|
|
|
|
return(lsn);
|
|
}
|
|
|
|
/************************************************************************
|
|
Increments the modify clock of a frame by 1. The caller must (1) own the
|
|
buf_pool mutex and block bufferfix count has to be zero, (2) or own an x-lock
|
|
on the block. */
|
|
UNIV_INLINE
|
|
dulint
|
|
buf_frame_modify_clock_inc(
|
|
/*=======================*/
|
|
/* out: new value */
|
|
buf_frame_t* frame) /* in: pointer to a frame */
|
|
{
|
|
buf_block_t* block;
|
|
|
|
ut_ad(frame);
|
|
|
|
block = buf_block_align(frame);
|
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
ut_ad((mutex_own(&(buf_pool->mutex)) && (block->buf_fix_count == 0))
|
|
|| rw_lock_own(&(block->lock), RW_LOCK_EXCLUSIVE));
|
|
#endif /*UNIV_SYNC_DEBUG */
|
|
|
|
UT_DULINT_INC(block->modify_clock);
|
|
|
|
return(block->modify_clock);
|
|
}
|
|
|
|
/************************************************************************
|
|
Increments the modify clock of a frame by 1. The caller must (1) own the
|
|
buf_pool mutex and block bufferfix count has to be zero, (2) or own an x-lock
|
|
on the block. */
|
|
UNIV_INLINE
|
|
dulint
|
|
buf_block_modify_clock_inc(
|
|
/*=======================*/
|
|
/* out: new value */
|
|
buf_block_t* block) /* in: block */
|
|
{
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
ut_ad((mutex_own(&(buf_pool->mutex)) && (block->buf_fix_count == 0))
|
|
|| rw_lock_own(&(block->lock), RW_LOCK_EXCLUSIVE));
|
|
#endif /* UNIV_SYNC_DEBUG */
|
|
|
|
UT_DULINT_INC(block->modify_clock);
|
|
|
|
return(block->modify_clock);
|
|
}
|
|
|
|
/************************************************************************
|
|
Returns the value of the modify clock. The caller must have an s-lock
|
|
or x-lock on the block. */
|
|
UNIV_INLINE
|
|
dulint
|
|
buf_block_get_modify_clock(
|
|
/*=======================*/
|
|
/* out: value */
|
|
buf_block_t* block) /* in: block */
|
|
{
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED)
|
|
|| rw_lock_own(&(block->lock), RW_LOCK_EXCLUSIVE));
|
|
#endif /* UNIV_SYNC_DEBUG */
|
|
|
|
return(block->modify_clock);
|
|
}
|
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
/***********************************************************************
|
|
Increments the bufferfix count. */
|
|
UNIV_INLINE
|
|
void
|
|
buf_block_buf_fix_inc_debug(
|
|
/*========================*/
|
|
buf_block_t* block, /* in: block to bufferfix */
|
|
const char* file __attribute__ ((unused)), /* in: file name */
|
|
ulint line __attribute__ ((unused))) /* in: line */
|
|
{
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
ibool ret;
|
|
|
|
ret = rw_lock_s_lock_func_nowait(&(block->debug_latch), file, line);
|
|
|
|
ut_ad(ret == TRUE);
|
|
ut_ad(mutex_own(&block->mutex));
|
|
#endif
|
|
block->buf_fix_count++;
|
|
}
|
|
#else /* UNIV_SYNC_DEBUG */
|
|
/***********************************************************************
|
|
Increments the bufferfix count. */
|
|
UNIV_INLINE
|
|
void
|
|
buf_block_buf_fix_inc(
|
|
/*==================*/
|
|
buf_block_t* block) /* in: block to bufferfix */
|
|
{
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
ut_ad(mutex_own(&block->mutex));
|
|
#endif
|
|
block->buf_fix_count++;
|
|
}
|
|
#endif /* UNIV_SYNC_DEBUG */
|
|
/**********************************************************************
|
|
Returns the control block of a file page, NULL if not found. */
|
|
UNIV_INLINE
|
|
buf_block_t*
|
|
buf_page_hash_get(
|
|
/*==============*/
|
|
/* out: block, NULL if not found */
|
|
ulint space, /* in: space id */
|
|
ulint offset) /* in: offset of the page within space */
|
|
{
|
|
buf_block_t* block;
|
|
ulint fold;
|
|
|
|
ut_ad(buf_pool);
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
ut_ad(mutex_own(&(buf_pool->mutex)));
|
|
#endif /* UNIV_SYNC_DEBUG */
|
|
|
|
/* Look for the page in the hash table */
|
|
|
|
fold = buf_page_address_fold(space, offset);
|
|
|
|
HASH_SEARCH(hash, buf_pool->page_hash, fold, block,
|
|
(block->space == space) && (block->offset == offset));
|
|
ut_a(block == NULL || block->state == BUF_BLOCK_FILE_PAGE);
|
|
|
|
return(block);
|
|
}
|
|
|
|
/************************************************************************
|
|
Tries to get the page, but if file io is required, releases all latches
|
|
in mtr down to the given savepoint. If io is required, this function
|
|
retrieves the page to buffer buf_pool, but does not bufferfix it or latch
|
|
it. */
|
|
UNIV_INLINE
|
|
buf_frame_t*
|
|
buf_page_get_release_on_io(
|
|
/*=======================*/
|
|
/* out: pointer to the frame, or NULL
|
|
if not in buffer buf_pool */
|
|
ulint space, /* in: space id */
|
|
ulint offset, /* in: offset of the page within space
|
|
in units of a page */
|
|
buf_frame_t* guess, /* in: guessed frame or NULL */
|
|
ulint rw_latch, /* in: RW_X_LATCH, RW_S_LATCH,
|
|
or RW_NO_LATCH */
|
|
ulint savepoint, /* in: mtr savepoint */
|
|
mtr_t* mtr) /* in: mtr */
|
|
{
|
|
buf_frame_t* frame;
|
|
|
|
frame = buf_page_get_gen(space, offset, rw_latch, guess,
|
|
BUF_GET_IF_IN_POOL,
|
|
__FILE__, __LINE__,
|
|
mtr);
|
|
if (frame != NULL) {
|
|
|
|
return(frame);
|
|
}
|
|
|
|
/* The page was not in the buffer buf_pool: release the latches
|
|
down to the savepoint */
|
|
|
|
mtr_rollback_to_savepoint(mtr, savepoint);
|
|
|
|
buf_page_get(space, offset, RW_S_LATCH, mtr);
|
|
|
|
/* When we get here, the page is in buffer, but we release
|
|
the latches again down to the savepoint, before returning */
|
|
|
|
mtr_rollback_to_savepoint(mtr, savepoint);
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
/************************************************************************
|
|
Decrements the bufferfix count of a buffer control block and releases
|
|
a latch, if specified. */
|
|
UNIV_INLINE
|
|
void
|
|
buf_page_release(
|
|
/*=============*/
|
|
buf_block_t* block, /* in: buffer block */
|
|
ulint rw_latch, /* in: RW_S_LATCH, RW_X_LATCH,
|
|
RW_NO_LATCH */
|
|
mtr_t* mtr) /* in: mtr */
|
|
{
|
|
ut_ad(block);
|
|
|
|
ut_a(block->state == BUF_BLOCK_FILE_PAGE);
|
|
|
|
if (rw_latch == RW_X_LATCH && mtr->modifications) {
|
|
mutex_enter(&buf_pool->mutex);
|
|
buf_flush_note_modification(block, mtr);
|
|
mutex_exit(&buf_pool->mutex);
|
|
}
|
|
|
|
mutex_enter(&block->mutex);
|
|
|
|
/* This debug code has been added to narrow down Bug# 26081 */
|
|
if (UNIV_UNLIKELY(block->buf_fix_count == 0)) {
|
|
buf_print_diagnostic(mtr, block);
|
|
ut_error;
|
|
}
|
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
rw_lock_s_unlock(&(block->debug_latch));
|
|
#endif
|
|
--block->buf_fix_count;
|
|
|
|
mutex_exit(&block->mutex);
|
|
|
|
if (rw_latch == RW_S_LATCH) {
|
|
rw_lock_s_unlock(&(block->lock));
|
|
} else if (rw_latch == RW_X_LATCH) {
|
|
rw_lock_x_unlock(&(block->lock));
|
|
}
|
|
}
|
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
/*************************************************************************
|
|
Adds latch level info for the rw-lock protecting the buffer frame. This
|
|
should be called in the debug version after a successful latching of a
|
|
page if we know the latching order level of the acquired latch. If
|
|
UNIV_SYNC_DEBUG is not defined, compiles to an empty function. */
|
|
UNIV_INLINE
|
|
void
|
|
buf_page_dbg_add_level(
|
|
/*===================*/
|
|
buf_frame_t* frame __attribute__((unused)), /* in: buffer page
|
|
where we have acquired latch */
|
|
ulint level __attribute__((unused))) /* in: latching order
|
|
level */
|
|
{
|
|
sync_thread_add_level(&(buf_block_align(frame)->lock), level);
|
|
}
|
|
#endif /* UNIV_SYNC_DEBUG */
|