summaryrefslogtreecommitdiff
path: root/storage/innobase/buf/buf0buf.c
diff options
context:
space:
mode:
authorMichael Widenius <monty@askmonty.org>2012-08-01 17:27:34 +0300
committerMichael Widenius <monty@askmonty.org>2012-08-01 17:27:34 +0300
commit1d0f70c2f894b27e98773a282871d32802f67964 (patch)
tree833e683e0ced29c4323c29a9d845703d4dfcd81b /storage/innobase/buf/buf0buf.c
parent5a86a61219826aadf8d08cbc447fe438f2bf50c3 (diff)
downloadmariadb-git-1d0f70c2f894b27e98773a282871d32802f67964.tar.gz
Temporary commit of merge of MariaDB 10.0-base and MySQL 5.6
Diffstat (limited to 'storage/innobase/buf/buf0buf.c')
-rw-r--r--storage/innobase/buf/buf0buf.c4832
1 files changed, 0 insertions, 4832 deletions
diff --git a/storage/innobase/buf/buf0buf.c b/storage/innobase/buf/buf0buf.c
deleted file mode 100644
index 1672057d552..00000000000
--- a/storage/innobase/buf/buf0buf.c
+++ /dev/null
@@ -1,4832 +0,0 @@
-/*****************************************************************************
-
-Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2008, Google Inc.
-
-Portions of this file contain modifications contributed and copyrighted by
-Google, Inc. Those modifications are gratefully acknowledged and are described
-briefly in the InnoDB documentation. The contributions by Google are
-incorporated with their permission, and subject to the conditions contained in
-the file COPYING.Google.
-
-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., 59 Temple
-Place, Suite 330, Boston, MA 02111-1307 USA
-
-*****************************************************************************/
-
-/**************************************************//**
-@file buf/buf0buf.c
-The database buffer buf_pool
-
-Created 11/5/1995 Heikki Tuuri
-*******************************************************/
-
-#include "buf0buf.h"
-
-#ifdef UNIV_NONINL
-#include "buf0buf.ic"
-#endif
-
-#include "mem0mem.h"
-#include "btr0btr.h"
-#include "fil0fil.h"
-#ifndef UNIV_HOTBACKUP
-#include "buf0buddy.h"
-#include "lock0lock.h"
-#include "btr0sea.h"
-#include "ibuf0ibuf.h"
-#include "trx0undo.h"
-#include "log0log.h"
-#endif /* !UNIV_HOTBACKUP */
-#include "srv0srv.h"
-#include "dict0dict.h"
-#include "log0recv.h"
-#include "page0zip.h"
-
-/*
- IMPLEMENTATION OF THE BUFFER POOL
- =================================
-
-Performance improvement:
-------------------------
-Thread scheduling in NT may be so slow that the OS wait mechanism should
-not be used even in waiting for disk reads to complete.
-Rather, we should put waiting query threads to the queue of
-waiting jobs, and let the OS thread do something useful while the i/o
-is processed. In this way we could remove most OS thread switches in
-an i/o-intensive benchmark like TPC-C.
-
-A possibility is to put a user space thread library between the database
-and NT. User space thread libraries might be very fast.
-
-SQL Server 7.0 can be configured to use 'fibers' which are lightweight
-threads in NT. These should be studied.
-
- Buffer frames and blocks
- ------------------------
-Following the terminology of Gray and Reuter, we call the memory
-blocks where file pages are loaded buffer frames. For each buffer
-frame there is a control block, or shortly, a block, in the buffer
-control array. The control info which does not need to be stored
-in the file along with the file page, resides in the control block.
-
- Buffer pool struct
- ------------------
-The buffer buf_pool contains a single mutex which protects all the
-control data structures of the buf_pool. The content of a buffer frame is
-protected by a separate read-write lock in its control block, though.
-These locks can be locked and unlocked without owning the buf_pool->mutex.
-The OS events in the buf_pool struct can be waited for without owning the
-buf_pool->mutex.
-
-The buf_pool->mutex is a hot-spot in main memory, causing a lot of
-memory bus traffic on multiprocessor systems when processors
-alternately access the mutex. On our Pentium, the mutex is accessed
-maybe every 10 microseconds. We gave up the solution to have mutexes
-for each control block, for instance, because it seemed to be
-complicated.
-
-A solution to reduce mutex contention of the buf_pool->mutex is to
-create a separate mutex for the page hash table. On Pentium,
-accessing the hash table takes 2 microseconds, about half
-of the total buf_pool->mutex hold time.
-
- Control blocks
- --------------
-
-The control block contains, for instance, the bufferfix count
-which is incremented when a thread wants a file page to be fixed
-in a buffer frame. The bufferfix operation does not lock the
-contents of the frame, however. For this purpose, the control
-block contains a read-write lock.
-
-The buffer frames have to be aligned so that the start memory
-address of a frame is divisible by the universal page size, which
-is a power of two.
-
-We intend to make the buffer buf_pool size on-line reconfigurable,
-that is, the buf_pool size can be changed without closing the database.
-Then the database administarator may adjust it to be bigger
-at night, for example. The control block array must
-contain enough control blocks for the maximum buffer buf_pool size
-which is used in the particular database.
-If the buf_pool size is cut, we exploit the virtual memory mechanism of
-the OS, and just refrain from using frames at high addresses. Then the OS
-can swap them to disk.
-
-The control blocks containing file pages are put to a hash table
-according to the file address of the page.
-We could speed up the access to an individual page by using
-"pointer swizzling": we could replace the page references on
-non-leaf index pages by direct pointers to the page, if it exists
-in the buf_pool. We could make a separate hash table where we could
-chain all the page references in non-leaf pages residing in the buf_pool,
-using the page reference as the hash key,
-and at the time of reading of a page update the pointers accordingly.
-Drawbacks of this solution are added complexity and,
-possibly, extra space required on non-leaf pages for memory pointers.
-A simpler solution is just to speed up the hash table mechanism
-in the database, using tables whose size is a power of 2.
-
- Lists of blocks
- ---------------
-
-There are several lists of control blocks.
-
-The free list (buf_pool->free) contains blocks which are currently not
-used.
-
-The common LRU list contains all the blocks holding a file page
-except those for which the bufferfix count is non-zero.
-The pages are in the LRU list roughly in the order of the last
-access to the page, so that the oldest pages are at the end of the
-list. We also keep a pointer to near the end of the LRU list,
-which we can use when we want to artificially age a page in the
-buf_pool. This is used if we know that some page is not needed
-again for some time: we insert the block right after the pointer,
-causing it to be replaced sooner than would normally be the case.
-Currently this aging mechanism is used for read-ahead mechanism
-of pages, and it can also be used when there is a scan of a full
-table which cannot fit in the memory. Putting the pages near the
-end of the LRU list, we make sure that most of the buf_pool stays
-in the main memory, undisturbed.
-
-The unzip_LRU list contains a subset of the common LRU list. The
-blocks on the unzip_LRU list hold a compressed file page and the
-corresponding uncompressed page frame. A block is in unzip_LRU if and
-only if the predicate buf_page_belongs_to_unzip_LRU(&block->page)
-holds. The blocks in unzip_LRU will be in same order as they are in
-the common LRU list. That is, each manipulation of the common LRU
-list will result in the same manipulation of the unzip_LRU list.
-
-The chain of modified blocks (buf_pool->flush_list) contains the blocks
-holding file pages that have been modified in the memory
-but not written to disk yet. The block with the oldest modification
-which has not yet been written to disk is at the end of the chain.
-The access to this list is protected by buf_pool->flush_list_mutex.
-
-The chain of unmodified compressed blocks (buf_pool->zip_clean)
-contains the control blocks (buf_page_t) of those compressed pages
-that are not in buf_pool->flush_list and for which no uncompressed
-page has been allocated in the buffer pool. The control blocks for
-uncompressed pages are accessible via buf_block_t objects that are
-reachable via buf_pool->chunks[].
-
-The chains of free memory blocks (buf_pool->zip_free[]) are used by
-the buddy allocator (buf0buddy.c) to keep track of currently unused
-memory blocks of size sizeof(buf_page_t)..UNIV_PAGE_SIZE / 2. These
-blocks are inside the UNIV_PAGE_SIZE-sized memory blocks of type
-BUF_BLOCK_MEMORY that the buddy allocator requests from the buffer
-pool. The buddy allocator is solely used for allocating control
-blocks for compressed pages (buf_page_t) and compressed page frames.
-
- Loading a file page
- -------------------
-
-First, a victim block for replacement has to be found in the
-buf_pool. It is taken from the free list or searched for from the
-end of the LRU-list. An exclusive lock is reserved for the frame,
-the io_fix field is set in the block fixing the block in buf_pool,
-and the io-operation for loading the page is queued. The io-handler thread
-releases the X-lock on the frame and resets the io_fix field
-when the io operation completes.
-
-A thread may request the above operation using the function
-buf_page_get(). It may then continue to request a lock on the frame.
-The lock is granted when the io-handler releases the x-lock.
-
- Read-ahead
- ----------
-
-The read-ahead mechanism is intended to be intelligent and
-isolated from the semantically higher levels of the database
-index management. From the higher level we only need the
-information if a file page has a natural successor or
-predecessor page. On the leaf level of a B-tree index,
-these are the next and previous pages in the natural
-order of the pages.
-
-Let us first explain the read-ahead mechanism when the leafs
-of a B-tree are scanned in an ascending or descending order.
-When a read page is the first time referenced in the buf_pool,
-the buffer manager checks if it is at the border of a so-called
-linear read-ahead area. The tablespace is divided into these
-areas of size 64 blocks, for example. So if the page is at the
-border of such an area, the read-ahead mechanism checks if
-all the other blocks in the area have been accessed in an
-ascending or descending order. If this is the case, the system
-looks at the natural successor or predecessor of the page,
-checks if that is at the border of another area, and in this case
-issues read-requests for all the pages in that area. Maybe
-we could relax the condition that all the pages in the area
-have to be accessed: if data is deleted from a table, there may
-appear holes of unused pages in the area.
-
-A different read-ahead mechanism is used when there appears
-to be a random access pattern to a file.
-If a new page is referenced in the buf_pool, and several pages
-of its random access area (for instance, 32 consecutive pages
-in a tablespace) have recently been referenced, we may predict
-that the whole area may be needed in the near future, and issue
-the read requests for the whole area.
-*/
-
-#ifndef UNIV_HOTBACKUP
-/** Value in microseconds */
-static const int WAIT_FOR_READ = 5000;
-/** Number of attemtps made to read in a page in the buffer pool */
-static const ulint BUF_PAGE_READ_MAX_RETRIES = 100;
-
-/** The buffer pools of the database */
-UNIV_INTERN buf_pool_t* buf_pool_ptr;
-
-#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
-static ulint buf_dbg_counter = 0; /*!< This is used to insert validation
- operations in execution in the
- debug version */
-#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
-#ifdef UNIV_DEBUG
-/** If this is set TRUE, the program prints info whenever
-read-ahead or flush occurs */
-UNIV_INTERN ibool buf_debug_prints = FALSE;
-#endif /* UNIV_DEBUG */
-
-#ifdef UNIV_PFS_RWLOCK
-/* Keys to register buffer block related rwlocks and mutexes with
-performance schema */
-UNIV_INTERN mysql_pfs_key_t buf_block_lock_key;
-# ifdef UNIV_SYNC_DEBUG
-UNIV_INTERN mysql_pfs_key_t buf_block_debug_latch_key;
-# endif /* UNIV_SYNC_DEBUG */
-#endif /* UNIV_PFS_RWLOCK */
-
-#ifdef UNIV_PFS_MUTEX
-UNIV_INTERN mysql_pfs_key_t buffer_block_mutex_key;
-UNIV_INTERN mysql_pfs_key_t buf_pool_mutex_key;
-UNIV_INTERN mysql_pfs_key_t buf_pool_zip_mutex_key;
-UNIV_INTERN mysql_pfs_key_t flush_list_mutex_key;
-#endif /* UNIV_PFS_MUTEX */
-
-#if defined UNIV_PFS_MUTEX || defined UNIV_PFS_RWLOCK
-# ifndef PFS_SKIP_BUFFER_MUTEX_RWLOCK
-
-/* Buffer block mutexes and rwlocks can be registered
-in one group rather than individually. If PFS_GROUP_BUFFER_SYNC
-is defined, register buffer block mutex and rwlock
-in one group after their initialization. */
-# define PFS_GROUP_BUFFER_SYNC
-
-/* This define caps the number of mutexes/rwlocks can
-be registered with performance schema. Developers can
-modify this define if necessary. Please note, this would
-be effective only if PFS_GROUP_BUFFER_SYNC is defined. */
-# define PFS_MAX_BUFFER_MUTEX_LOCK_REGISTER ULINT_MAX
-
-# endif /* !PFS_SKIP_BUFFER_MUTEX_RWLOCK */
-#endif /* UNIV_PFS_MUTEX || UNIV_PFS_RWLOCK */
-
-/** A chunk of buffers. The buffer pool is allocated in chunks. */
-struct buf_chunk_struct{
- ulint mem_size; /*!< allocated size of the chunk */
- ulint size; /*!< size of frames[] and blocks[] */
- void* mem; /*!< pointer to the memory area which
- was allocated for the frames */
- buf_block_t* blocks; /*!< array of buffer control blocks */
-};
-#endif /* !UNIV_HOTBACKUP */
-
-/********************************************************************//**
-Gets the smallest oldest_modification lsn for any page in the pool. Returns
-zero if all modified pages have been flushed to disk.
-@return oldest modification in pool, zero if none */
-UNIV_INTERN
-ib_uint64_t
-buf_pool_get_oldest_modification(void)
-/*==================================*/
-{
- ulint i;
- buf_page_t* bpage;
- ib_uint64_t lsn = 0;
- ib_uint64_t oldest_lsn = 0;
-
- /* When we traverse all the flush lists we don't want another
- thread to add a dirty page to any flush list. */
- log_flush_order_mutex_enter();
-
- for (i = 0; i < srv_buf_pool_instances; i++) {
- buf_pool_t* buf_pool;
-
- buf_pool = buf_pool_from_array(i);
-
- buf_flush_list_mutex_enter(buf_pool);
-
- bpage = UT_LIST_GET_LAST(buf_pool->flush_list);
-
- if (bpage != NULL) {
- ut_ad(bpage->in_flush_list);
- lsn = bpage->oldest_modification;
- }
-
- buf_flush_list_mutex_exit(buf_pool);
-
- if (!oldest_lsn || oldest_lsn > lsn) {
- oldest_lsn = lsn;
- }
- }
-
- log_flush_order_mutex_exit();
-
- /* The returned answer may be out of date: the flush_list can
- change after the mutex has been released. */
-
- return(oldest_lsn);
-}
-
-/********************************************************************//**
-Get total buffer pool statistics. */
-UNIV_INTERN
-void
-buf_get_total_list_len(
-/*===================*/
- ulint* LRU_len, /*!< out: length of all LRU lists */
- ulint* free_len, /*!< out: length of all free lists */
- ulint* flush_list_len) /*!< out: length of all flush lists */
-{
- ulint i;
-
- *LRU_len = 0;
- *free_len = 0;
- *flush_list_len = 0;
-
- for (i = 0; i < srv_buf_pool_instances; i++) {
- buf_pool_t* buf_pool;
-
- buf_pool = buf_pool_from_array(i);
- *LRU_len += UT_LIST_GET_LEN(buf_pool->LRU);
- *free_len += UT_LIST_GET_LEN(buf_pool->free);
- *flush_list_len += UT_LIST_GET_LEN(buf_pool->flush_list);
- }
-}
-
-/********************************************************************//**
-Get total buffer pool statistics. */
-UNIV_INTERN
-void
-buf_get_total_stat(
-/*===============*/
- buf_pool_stat_t* tot_stat) /*!< out: buffer pool stats */
-{
- ulint i;
-
- memset(tot_stat, 0, sizeof(*tot_stat));
-
- for (i = 0; i < srv_buf_pool_instances; i++) {
- buf_pool_stat_t*buf_stat;
- buf_pool_t* buf_pool;
-
- buf_pool = buf_pool_from_array(i);
-
- buf_stat = &buf_pool->stat;
- tot_stat->n_page_gets += buf_stat->n_page_gets;
- tot_stat->n_pages_read += buf_stat->n_pages_read;
- tot_stat->n_pages_written += buf_stat->n_pages_written;
- tot_stat->n_pages_created += buf_stat->n_pages_created;
- tot_stat->n_ra_pages_read_rnd += buf_stat->n_ra_pages_read_rnd;
- tot_stat->n_ra_pages_read += buf_stat->n_ra_pages_read;
- tot_stat->n_ra_pages_evicted += buf_stat->n_ra_pages_evicted;
- tot_stat->n_pages_made_young += buf_stat->n_pages_made_young;
-
- tot_stat->n_pages_not_made_young +=
- buf_stat->n_pages_not_made_young;
- }
-}
-
-/********************************************************************//**
-Allocates a buffer block.
-@return own: the allocated block, in state BUF_BLOCK_MEMORY */
-UNIV_INTERN
-buf_block_t*
-buf_block_alloc(
-/*============*/
- buf_pool_t* buf_pool) /*!< in/out: buffer pool instance,
- or NULL for round-robin selection
- of the buffer pool */
-{
- buf_block_t* block;
- ulint index;
- static ulint buf_pool_index;
-
- if (buf_pool == NULL) {
- /* We are allocating memory from any buffer pool, ensure
- we spread the grace on all buffer pool instances. */
- index = buf_pool_index++ % srv_buf_pool_instances;
- buf_pool = buf_pool_from_array(index);
- }
-
- block = buf_LRU_get_free_block(buf_pool);
-
- buf_block_set_state(block, BUF_BLOCK_MEMORY);
-
- return(block);
-}
-
-/********************************************************************//**
-Calculates a page checksum which is stored to the page when it is written
-to a file. Note that we must be careful to calculate the same value on
-32-bit and 64-bit architectures.
-@return checksum */
-UNIV_INTERN
-ulint
-buf_calc_page_new_checksum(
-/*=======================*/
- const byte* page) /*!< in: buffer page */
-{
- ulint checksum;
-
- /* Since the field FIL_PAGE_FILE_FLUSH_LSN, and in versions <= 4.1.x
- ..._ARCH_LOG_NO, are written outside the buffer pool to the first
- pages of data files, we have to skip them in the page checksum
- calculation.
- We must also skip the field FIL_PAGE_SPACE_OR_CHKSUM where the
- checksum is stored, and also the last 8 bytes of page because
- there we store the old formula checksum. */
-
- checksum = ut_fold_binary(page + FIL_PAGE_OFFSET,
- FIL_PAGE_FILE_FLUSH_LSN - FIL_PAGE_OFFSET)
- + ut_fold_binary(page + FIL_PAGE_DATA,
- UNIV_PAGE_SIZE - FIL_PAGE_DATA
- - FIL_PAGE_END_LSN_OLD_CHKSUM);
- checksum = checksum & 0xFFFFFFFFUL;
-
- return(checksum);
-}
-
-/********************************************************************//**
-In versions < 4.0.14 and < 4.1.1 there was a bug that the checksum only
-looked at the first few bytes of the page. This calculates that old
-checksum.
-NOTE: we must first store the new formula checksum to
-FIL_PAGE_SPACE_OR_CHKSUM before calculating and storing this old checksum
-because this takes that field as an input!
-@return checksum */
-UNIV_INTERN
-ulint
-buf_calc_page_old_checksum(
-/*=======================*/
- const byte* page) /*!< in: buffer page */
-{
- ulint checksum;
-
- checksum = ut_fold_binary(page, FIL_PAGE_FILE_FLUSH_LSN);
-
- checksum = checksum & 0xFFFFFFFFUL;
-
- return(checksum);
-}
-
-/********************************************************************//**
-Checks if a page is corrupt.
-@return TRUE if corrupted */
-UNIV_INTERN
-ibool
-buf_page_is_corrupted(
-/*==================*/
- const byte* read_buf, /*!< in: a database page */
- ulint zip_size) /*!< in: size of compressed page;
- 0 for uncompressed pages */
-{
- ulint checksum_field;
- ulint old_checksum_field;
-
- if (UNIV_LIKELY(!zip_size)
- && memcmp(read_buf + FIL_PAGE_LSN + 4,
- read_buf + UNIV_PAGE_SIZE
- - FIL_PAGE_END_LSN_OLD_CHKSUM + 4, 4)) {
-
- /* Stored log sequence numbers at the start and the end
- of page do not match */
-
- return(TRUE);
- }
-
-#ifndef UNIV_HOTBACKUP
- if (recv_lsn_checks_on) {
- ib_uint64_t current_lsn;
-
- if (log_peek_lsn(&current_lsn)
- && UNIV_UNLIKELY
- (current_lsn
- < mach_read_from_8(read_buf + FIL_PAGE_LSN))) {
- ut_print_timestamp(stderr);
-
- fprintf(stderr,
- " InnoDB: Error: page %lu log sequence number"
- " %llu\n"
- "InnoDB: is in the future! Current system "
- "log sequence number %llu.\n"
- "InnoDB: Your database may be corrupt or "
- "you may have copied the InnoDB\n"
- "InnoDB: tablespace but not the InnoDB "
- "log files. See\n"
- "InnoDB: " REFMAN "forcing-innodb-recovery.html\n"
- "InnoDB: for more information.\n",
- (ulong) mach_read_from_4(read_buf
- + FIL_PAGE_OFFSET),
- mach_read_from_8(read_buf + FIL_PAGE_LSN),
- current_lsn);
- }
- }
-#endif
-
- /* If we use checksums validation, make additional check before
- returning TRUE to ensure that the checksum is not equal to
- BUF_NO_CHECKSUM_MAGIC which might be stored by InnoDB with checksums
- disabled. Otherwise, skip checksum calculation and return FALSE */
-
- if (UNIV_LIKELY(srv_use_checksums)) {
- checksum_field = mach_read_from_4(read_buf
- + FIL_PAGE_SPACE_OR_CHKSUM);
-
- if (UNIV_UNLIKELY(zip_size)) {
- return(checksum_field != BUF_NO_CHECKSUM_MAGIC
- && checksum_field
- != page_zip_calc_checksum(read_buf, zip_size));
- }
-
- old_checksum_field = mach_read_from_4(
- read_buf + UNIV_PAGE_SIZE
- - FIL_PAGE_END_LSN_OLD_CHKSUM);
-
- /* There are 2 valid formulas for old_checksum_field:
-
- 1. Very old versions of InnoDB only stored 8 byte lsn to the
- start and the end of the page.
-
- 2. Newer InnoDB versions store the old formula checksum
- there. */
-
- if (old_checksum_field != mach_read_from_4(read_buf
- + FIL_PAGE_LSN)
- && old_checksum_field != BUF_NO_CHECKSUM_MAGIC
- && old_checksum_field
- != buf_calc_page_old_checksum(read_buf)) {
-
- return(TRUE);
- }
-
- /* InnoDB versions < 4.0.14 and < 4.1.1 stored the space id
- (always equal to 0), to FIL_PAGE_SPACE_OR_CHKSUM */
-
- if (checksum_field != 0
- && checksum_field != BUF_NO_CHECKSUM_MAGIC
- && checksum_field
- != buf_calc_page_new_checksum(read_buf)) {
-
- return(TRUE);
- }
- }
-
- return(FALSE);
-}
-
-/********************************************************************//**
-Prints a page to stderr. */
-UNIV_INTERN
-void
-buf_page_print(
-/*===========*/
- const byte* read_buf, /*!< in: a database page */
- ulint zip_size, /*!< in: compressed page size, or
- 0 for uncompressed pages */
- ulint flags) /*!< in: 0 or
- BUF_PAGE_PRINT_NO_CRASH or
- BUF_PAGE_PRINT_NO_FULL */
-
-{
-#ifndef UNIV_HOTBACKUP
- dict_index_t* index;
-#endif /* !UNIV_HOTBACKUP */
- ulint checksum;
- ulint old_checksum;
- ulint size = zip_size;
-
- if (!size) {
- size = UNIV_PAGE_SIZE;
- }
-
- if (!(flags & BUF_PAGE_PRINT_NO_FULL)) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Page dump in ascii and hex (%lu bytes):\n",
- (ulong) size);
- ut_print_buf(stderr, read_buf, size);
- fputs("\nInnoDB: End of page dump\n", stderr);
- }
-
- if (zip_size) {
- /* Print compressed page. */
-
- switch (fil_page_get_type(read_buf)) {
- case FIL_PAGE_TYPE_ZBLOB:
- case FIL_PAGE_TYPE_ZBLOB2:
- checksum = srv_use_checksums
- ? page_zip_calc_checksum(read_buf, zip_size)
- : BUF_NO_CHECKSUM_MAGIC;
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Compressed BLOB page"
- " checksum %lu, stored %lu\n"
- "InnoDB: Page lsn %lu %lu\n"
- "InnoDB: Page number (if stored"
- " to page already) %lu,\n"
- "InnoDB: space id (if stored"
- " to page already) %lu\n",
- (ulong) checksum,
- (ulong) mach_read_from_4(
- read_buf + FIL_PAGE_SPACE_OR_CHKSUM),
- (ulong) mach_read_from_4(
- read_buf + FIL_PAGE_LSN),
- (ulong) mach_read_from_4(
- read_buf + (FIL_PAGE_LSN + 4)),
- (ulong) mach_read_from_4(
- read_buf + FIL_PAGE_OFFSET),
- (ulong) mach_read_from_4(
- read_buf
- + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID));
- return;
- default:
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: unknown page type %lu,"
- " assuming FIL_PAGE_INDEX\n",
- fil_page_get_type(read_buf));
- /* fall through */
- case FIL_PAGE_INDEX:
- checksum = srv_use_checksums
- ? page_zip_calc_checksum(read_buf, zip_size)
- : BUF_NO_CHECKSUM_MAGIC;
-
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Compressed page checksum %lu,"
- " stored %lu\n"
- "InnoDB: Page lsn %lu %lu\n"
- "InnoDB: Page number (if stored"
- " to page already) %lu,\n"
- "InnoDB: space id (if stored"
- " to page already) %lu\n",
- (ulong) checksum,
- (ulong) mach_read_from_4(
- read_buf + FIL_PAGE_SPACE_OR_CHKSUM),
- (ulong) mach_read_from_4(
- read_buf + FIL_PAGE_LSN),
- (ulong) mach_read_from_4(
- read_buf + (FIL_PAGE_LSN + 4)),
- (ulong) mach_read_from_4(
- read_buf + FIL_PAGE_OFFSET),
- (ulong) mach_read_from_4(
- read_buf
- + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID));
- return;
- case FIL_PAGE_TYPE_XDES:
- /* This is an uncompressed page. */
- break;
- }
- }
-
- checksum = srv_use_checksums
- ? buf_calc_page_new_checksum(read_buf) : BUF_NO_CHECKSUM_MAGIC;
- old_checksum = srv_use_checksums
- ? buf_calc_page_old_checksum(read_buf) : BUF_NO_CHECKSUM_MAGIC;
-
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Page checksum %lu, prior-to-4.0.14-form"
- " checksum %lu\n"
- "InnoDB: stored checksum %lu, prior-to-4.0.14-form"
- " stored checksum %lu\n"
- "InnoDB: Page lsn %lu %lu, low 4 bytes of lsn"
- " at page end %lu\n"
- "InnoDB: Page number (if stored to page already) %lu,\n"
- "InnoDB: space id (if created with >= MySQL-4.1.1"
- " and stored already) %lu\n",
- (ulong) checksum, (ulong) old_checksum,
- (ulong) mach_read_from_4(read_buf + FIL_PAGE_SPACE_OR_CHKSUM),
- (ulong) mach_read_from_4(read_buf + UNIV_PAGE_SIZE
- - FIL_PAGE_END_LSN_OLD_CHKSUM),
- (ulong) mach_read_from_4(read_buf + FIL_PAGE_LSN),
- (ulong) mach_read_from_4(read_buf + FIL_PAGE_LSN + 4),
- (ulong) mach_read_from_4(read_buf + UNIV_PAGE_SIZE
- - FIL_PAGE_END_LSN_OLD_CHKSUM + 4),
- (ulong) mach_read_from_4(read_buf + FIL_PAGE_OFFSET),
- (ulong) mach_read_from_4(read_buf
- + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID));
-
-#ifndef UNIV_HOTBACKUP
- if (mach_read_from_2(read_buf + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE)
- == TRX_UNDO_INSERT) {
- fprintf(stderr,
- "InnoDB: Page may be an insert undo log page\n");
- } else if (mach_read_from_2(read_buf + TRX_UNDO_PAGE_HDR
- + TRX_UNDO_PAGE_TYPE)
- == TRX_UNDO_UPDATE) {
- fprintf(stderr,
- "InnoDB: Page may be an update undo log page\n");
- }
-#endif /* !UNIV_HOTBACKUP */
-
- switch (fil_page_get_type(read_buf)) {
- index_id_t index_id;
- case FIL_PAGE_INDEX:
- index_id = btr_page_get_index_id(read_buf);
- fprintf(stderr,
- "InnoDB: Page may be an index page where"
- " index id is %llu\n",
- (ullint) index_id);
-#ifndef UNIV_HOTBACKUP
- index = dict_index_find_on_id_low(index_id);
- if (index) {
- fputs("InnoDB: (", stderr);
- dict_index_name_print(stderr, NULL, index);
- fputs(")\n", stderr);
- }
-#endif /* !UNIV_HOTBACKUP */
- break;
- case FIL_PAGE_INODE:
- fputs("InnoDB: Page may be an 'inode' page\n", stderr);
- break;
- case FIL_PAGE_IBUF_FREE_LIST:
- fputs("InnoDB: Page may be an insert buffer free list page\n",
- stderr);
- break;
- case FIL_PAGE_TYPE_ALLOCATED:
- fputs("InnoDB: Page may be a freshly allocated page\n",
- stderr);
- break;
- case FIL_PAGE_IBUF_BITMAP:
- fputs("InnoDB: Page may be an insert buffer bitmap page\n",
- stderr);
- break;
- case FIL_PAGE_TYPE_SYS:
- fputs("InnoDB: Page may be a system page\n",
- stderr);
- break;
- case FIL_PAGE_TYPE_TRX_SYS:
- fputs("InnoDB: Page may be a transaction system page\n",
- stderr);
- break;
- case FIL_PAGE_TYPE_FSP_HDR:
- fputs("InnoDB: Page may be a file space header page\n",
- stderr);
- break;
- case FIL_PAGE_TYPE_XDES:
- fputs("InnoDB: Page may be an extent descriptor page\n",
- stderr);
- break;
- case FIL_PAGE_TYPE_BLOB:
- fputs("InnoDB: Page may be a BLOB page\n",
- stderr);
- break;
- case FIL_PAGE_TYPE_ZBLOB:
- case FIL_PAGE_TYPE_ZBLOB2:
- fputs("InnoDB: Page may be a compressed BLOB page\n",
- stderr);
- break;
- }
-
- ut_ad(flags & BUF_PAGE_PRINT_NO_CRASH);
-}
-
-#ifndef UNIV_HOTBACKUP
-
-# ifdef PFS_GROUP_BUFFER_SYNC
-/********************************************************************//**
-This function registers mutexes and rwlocks in buffer blocks with
-performance schema. If PFS_MAX_BUFFER_MUTEX_LOCK_REGISTER is
-defined to be a value less than chunk->size, then only mutexes
-and rwlocks in the first PFS_MAX_BUFFER_MUTEX_LOCK_REGISTER
-blocks are registered. */
-static
-void
-pfs_register_buffer_block(
-/*======================*/
- buf_chunk_t* chunk) /*!< in/out: chunk of buffers */
-{
- ulint i;
- ulint num_to_register;
- buf_block_t* block;
-
- block = chunk->blocks;
-
- num_to_register = ut_min(chunk->size,
- PFS_MAX_BUFFER_MUTEX_LOCK_REGISTER);
-
- for (i = 0; i < num_to_register; i++) {
- mutex_t* mutex;
- rw_lock_t* rwlock;
-
-# ifdef UNIV_PFS_MUTEX
- mutex = &block->mutex;
- ut_a(!mutex->pfs_psi);
- mutex->pfs_psi = (PSI_server)
- ? PSI_server->init_mutex(buffer_block_mutex_key, mutex)
- : NULL;
-# endif /* UNIV_PFS_MUTEX */
-
-# ifdef UNIV_PFS_RWLOCK
- rwlock = &block->lock;
- ut_a(!rwlock->pfs_psi);
- rwlock->pfs_psi = (PSI_server)
- ? PSI_server->init_rwlock(buf_block_lock_key, rwlock)
- : NULL;
-
-# ifdef UNIV_SYNC_DEBUG
- rwlock = &block->debug_latch;
- ut_a(!rwlock->pfs_psi);
- rwlock->pfs_psi = (PSI_server)
- ? PSI_server->init_rwlock(buf_block_debug_latch_key,
- rwlock)
- : NULL;
-# endif /* UNIV_SYNC_DEBUG */
-
-# endif /* UNIV_PFS_RWLOCK */
- block++;
- }
-}
-# endif /* PFS_GROUP_BUFFER_SYNC */
-
-/********************************************************************//**
-Initializes a buffer control block when the buf_pool is created. */
-static
-void
-buf_block_init(
-/*===========*/
- buf_pool_t* buf_pool, /*!< in: buffer pool instance */
- buf_block_t* block, /*!< in: pointer to control block */
- byte* frame) /*!< in: pointer to buffer frame */
-{
- UNIV_MEM_DESC(frame, UNIV_PAGE_SIZE, block);
-
- block->frame = frame;
-
- block->page.buf_pool_index = buf_pool_index(buf_pool);
- block->page.state = BUF_BLOCK_NOT_USED;
- block->page.buf_fix_count = 0;
- block->page.io_fix = BUF_IO_NONE;
-
- block->modify_clock = 0;
-
-#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
- block->page.file_page_was_freed = FALSE;
-#endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */
-
- block->check_index_page_at_flush = FALSE;
- block->index = NULL;
-
-#ifdef UNIV_DEBUG
- block->page.in_page_hash = FALSE;
- block->page.in_zip_hash = FALSE;
- block->page.in_flush_list = FALSE;
- block->page.in_free_list = FALSE;
- block->page.in_LRU_list = FALSE;
- block->in_unzip_LRU_list = FALSE;
-#endif /* UNIV_DEBUG */
-#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
- block->n_pointers = 0;
-#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
- page_zip_des_init(&block->page.zip);
-
-#if defined PFS_SKIP_BUFFER_MUTEX_RWLOCK || defined PFS_GROUP_BUFFER_SYNC
- /* If PFS_SKIP_BUFFER_MUTEX_RWLOCK is defined, skip registration
- of buffer block mutex/rwlock with performance schema. If
- PFS_GROUP_BUFFER_SYNC is defined, skip the registration
- since buffer block mutex/rwlock will be registered later in
- pfs_register_buffer_block() */
-
- mutex_create(PFS_NOT_INSTRUMENTED, &block->mutex, SYNC_BUF_BLOCK);
- rw_lock_create(PFS_NOT_INSTRUMENTED, &block->lock, SYNC_LEVEL_VARYING);
-
-# ifdef UNIV_SYNC_DEBUG
- rw_lock_create(PFS_NOT_INSTRUMENTED,
- &block->debug_latch, SYNC_NO_ORDER_CHECK);
-# endif /* UNIV_SYNC_DEBUG */
-
-#else /* PFS_SKIP_BUFFER_MUTEX_RWLOCK || PFS_GROUP_BUFFER_SYNC */
- mutex_create(buffer_block_mutex_key, &block->mutex, SYNC_BUF_BLOCK);
- rw_lock_create(buf_block_lock_key, &block->lock, SYNC_LEVEL_VARYING);
-
-# ifdef UNIV_SYNC_DEBUG
- rw_lock_create(buf_block_debug_latch_key,
- &block->debug_latch, SYNC_NO_ORDER_CHECK);
-# endif /* UNIV_SYNC_DEBUG */
-#endif /* PFS_SKIP_BUFFER_MUTEX_RWLOCK || PFS_GROUP_BUFFER_SYNC */
-
- ut_ad(rw_lock_validate(&(block->lock)));
-
-}
-
-/********************************************************************//**
-Allocates a chunk of buffer frames.
-@return chunk, or NULL on failure */
-static
-buf_chunk_t*
-buf_chunk_init(
-/*===========*/
- buf_pool_t* buf_pool, /*!< in: buffer pool instance */
- buf_chunk_t* chunk, /*!< out: chunk of buffers */
- ulint mem_size) /*!< in: requested size in bytes */
-{
- buf_block_t* block;
- byte* frame;
- ulint i;
-
- /* Round down to a multiple of page size,
- although it already should be. */
- mem_size = ut_2pow_round(mem_size, UNIV_PAGE_SIZE);
- /* Reserve space for the block descriptors. */
- mem_size += ut_2pow_round((mem_size / UNIV_PAGE_SIZE) * (sizeof *block)
- + (UNIV_PAGE_SIZE - 1), UNIV_PAGE_SIZE);
-
- chunk->mem_size = mem_size;
- chunk->mem = os_mem_alloc_large(&chunk->mem_size);
-
- if (UNIV_UNLIKELY(chunk->mem == NULL)) {
-
- return(NULL);
- }
-
- /* Allocate the block descriptors from
- the start of the memory block. */
- chunk->blocks = chunk->mem;
-
- /* Align a pointer to the first frame. Note that when
- os_large_page_size is smaller than UNIV_PAGE_SIZE,
- we may allocate one fewer block than requested. When
- it is bigger, we may allocate more blocks than requested. */
-
- frame = ut_align(chunk->mem, UNIV_PAGE_SIZE);
- chunk->size = chunk->mem_size / UNIV_PAGE_SIZE
- - (frame != chunk->mem);
-
- /* Subtract the space needed for block descriptors. */
- {
- ulint size = chunk->size;
-
- while (frame < (byte*) (chunk->blocks + size)) {
- frame += UNIV_PAGE_SIZE;
- size--;
- }
-
- chunk->size = size;
- }
-
- /* Init block structs and assign frames for them. Then we
- assign the frames to the first blocks (we already mapped the
- memory above). */
-
- block = chunk->blocks;
-
- for (i = chunk->size; i--; ) {
-
- buf_block_init(buf_pool, block, frame);
- UNIV_MEM_INVALID(block->frame, UNIV_PAGE_SIZE);
-
- /* Add the block to the free list */
- UT_LIST_ADD_LAST(list, buf_pool->free, (&block->page));
-
- ut_d(block->page.in_free_list = TRUE);
- ut_ad(buf_pool_from_block(block) == buf_pool);
-
- block++;
- frame += UNIV_PAGE_SIZE;
- }
-
-#ifdef PFS_GROUP_BUFFER_SYNC
- pfs_register_buffer_block(chunk);
-#endif
- return(chunk);
-}
-
-#ifdef UNIV_DEBUG
-/*********************************************************************//**
-Finds a block in the given buffer chunk that points to a
-given compressed page.
-@return buffer block pointing to the compressed page, or NULL */
-static
-buf_block_t*
-buf_chunk_contains_zip(
-/*===================*/
- buf_chunk_t* chunk, /*!< in: chunk being checked */
- const void* data) /*!< in: pointer to compressed page */
-{
- buf_block_t* block;
- ulint i;
-
- block = chunk->blocks;
-
- for (i = chunk->size; i--; block++) {
- if (block->page.zip.data == data) {
-
- return(block);
- }
- }
-
- return(NULL);
-}
-
-/*********************************************************************//**
-Finds a block in the buffer pool that points to a
-given compressed page.
-@return buffer block pointing to the compressed page, or NULL */
-UNIV_INTERN
-buf_block_t*
-buf_pool_contains_zip(
-/*==================*/
- buf_pool_t* buf_pool, /*!< in: buffer pool instance */
- const void* data) /*!< in: pointer to compressed page */
-{
- ulint n;
- buf_chunk_t* chunk = buf_pool->chunks;
-
- ut_ad(buf_pool);
- ut_ad(buf_pool_mutex_own(buf_pool));
- for (n = buf_pool->n_chunks; n--; chunk++) {
-
- buf_block_t* block = buf_chunk_contains_zip(chunk, data);
-
- if (block) {
- return(block);
- }
- }
-
- return(NULL);
-}
-#endif /* UNIV_DEBUG */
-
-/*********************************************************************//**
-Checks that all file pages in the buffer chunk are in a replaceable state.
-@return address of a non-free block, or NULL if all freed */
-static
-const buf_block_t*
-buf_chunk_not_freed(
-/*================*/
- buf_chunk_t* chunk) /*!< in: chunk being checked */
-{
- buf_block_t* block;
- ulint i;
-
- block = chunk->blocks;
-
- for (i = chunk->size; i--; block++) {
- ibool ready;
-
- switch (buf_block_get_state(block)) {
- case BUF_BLOCK_ZIP_FREE:
- case BUF_BLOCK_ZIP_PAGE:
- case BUF_BLOCK_ZIP_DIRTY:
- /* The uncompressed buffer pool should never
- contain compressed block descriptors. */
- ut_error;
- break;
- case BUF_BLOCK_NOT_USED:
- case BUF_BLOCK_READY_FOR_USE:
- case BUF_BLOCK_MEMORY:
- case BUF_BLOCK_REMOVE_HASH:
- /* Skip blocks that are not being used for
- file pages. */
- break;
- case BUF_BLOCK_FILE_PAGE:
- mutex_enter(&block->mutex);
- ready = buf_flush_ready_for_replace(&block->page);
- mutex_exit(&block->mutex);
-
- if (!ready) {
-
- return(block);
- }
-
- break;
- }
- }
-
- return(NULL);
-}
-
-/********************************************************************//**
-Set buffer pool size variables after resizing it */
-static
-void
-buf_pool_set_sizes(void)
-/*====================*/
-{
- ulint i;
- ulint curr_size = 0;
-
- buf_pool_mutex_enter_all();
-
- for (i = 0; i < srv_buf_pool_instances; i++) {
- buf_pool_t* buf_pool;
-
- buf_pool = buf_pool_from_array(i);
- curr_size += buf_pool->curr_pool_size;
- }
-
- srv_buf_pool_curr_size = curr_size;
- srv_buf_pool_old_size = srv_buf_pool_size;
-
- buf_pool_mutex_exit_all();
-}
-
-/********************************************************************//**
-Initialize a buffer pool instance.
-@return DB_SUCCESS if all goes well. */
-UNIV_INTERN
-ulint
-buf_pool_init_instance(
-/*===================*/
- buf_pool_t* buf_pool, /*!< in: buffer pool instance */
- ulint buf_pool_size, /*!< in: size in bytes */
- ulint instance_no) /*!< in: id of the instance */
-{
- ulint i;
- buf_chunk_t* chunk;
-
- /* 1. Initialize general fields
- ------------------------------- */
- mutex_create(buf_pool_mutex_key,
- &buf_pool->mutex, SYNC_BUF_POOL);
- mutex_create(buf_pool_zip_mutex_key,
- &buf_pool->zip_mutex, SYNC_BUF_BLOCK);
-
- buf_pool_mutex_enter(buf_pool);
-
- if (buf_pool_size > 0) {
- buf_pool->n_chunks = 1;
- buf_pool->chunks = chunk = mem_zalloc(sizeof *chunk);
-
- UT_LIST_INIT(buf_pool->free);
-
- if (!buf_chunk_init(buf_pool, chunk, buf_pool_size)) {
- mem_free(chunk);
- mem_free(buf_pool);
-
- buf_pool_mutex_exit(buf_pool);
-
- return(DB_ERROR);
- }
-
- buf_pool->instance_no = instance_no;
- buf_pool->old_pool_size = buf_pool_size;
- buf_pool->curr_size = chunk->size;
- buf_pool->curr_pool_size = buf_pool->curr_size * UNIV_PAGE_SIZE;
-
- buf_pool->page_hash = hash_create(2 * buf_pool->curr_size);
- buf_pool->zip_hash = hash_create(2 * buf_pool->curr_size);
-
- buf_pool->last_printout_time = ut_time();
- }
- /* 2. Initialize flushing fields
- -------------------------------- */
-
- mutex_create(flush_list_mutex_key, &buf_pool->flush_list_mutex,
- SYNC_BUF_FLUSH_LIST);
-
- for (i = BUF_FLUSH_LRU; i < BUF_FLUSH_N_TYPES; i++) {
- buf_pool->no_flush[i] = os_event_create(NULL);
- }
-
- /* 3. Initialize LRU fields
- --------------------------- */
-
- /* All fields are initialized by mem_zalloc(). */
-
- buf_pool_mutex_exit(buf_pool);
-
- return(DB_SUCCESS);
-}
-
-/********************************************************************//**
-free one buffer pool instance */
-static
-void
-buf_pool_free_instance(
-/*===================*/
- buf_pool_t* buf_pool) /* in,own: buffer pool instance
- to free */
-{
- buf_chunk_t* chunk;
- buf_chunk_t* chunks;
- buf_page_t* bpage;
-
- bpage = UT_LIST_GET_LAST(buf_pool->LRU);
- while (bpage != NULL) {
- buf_page_t* prev_bpage = UT_LIST_GET_PREV(LRU, bpage);
- enum buf_page_state state = buf_page_get_state(bpage);
-
- ut_ad(buf_page_in_file(bpage));
- ut_ad(bpage->in_LRU_list);
-
- if (state != BUF_BLOCK_FILE_PAGE) {
- /* We must not have any dirty block except
- when doing a fast shutdown. */
- ut_ad(state == BUF_BLOCK_ZIP_PAGE
- || srv_fast_shutdown == 2);
- buf_page_free_descriptor(bpage);
- }
-
- bpage = prev_bpage;
- }
-
- chunks = buf_pool->chunks;
- chunk = chunks + buf_pool->n_chunks;
-
- while (--chunk >= chunks) {
- os_mem_free_large(chunk->mem, chunk->mem_size);
- }
-
- mem_free(buf_pool->chunks);
- hash_table_free(buf_pool->page_hash);
- hash_table_free(buf_pool->zip_hash);
-}
-
-/********************************************************************//**
-Creates the buffer pool.
-@return DB_SUCCESS if success, DB_ERROR if not enough memory or error */
-UNIV_INTERN
-ulint
-buf_pool_init(
-/*==========*/
- ulint total_size, /*!< in: size of the total pool in bytes */
- ulint n_instances) /*!< in: number of instances */
-{
- ulint i;
- const ulint size = total_size / n_instances;
-
- ut_ad(n_instances > 0);
- ut_ad(n_instances <= MAX_BUFFER_POOLS);
- ut_ad(n_instances == srv_buf_pool_instances);
-
- /* We create an extra buffer pool instance, this instance is used
- for flushing the flush lists, to keep track of n_flush for all
- the buffer pools and also used as a waiting object during flushing. */
- buf_pool_ptr = mem_zalloc(n_instances * sizeof *buf_pool_ptr);
-
- for (i = 0; i < n_instances; i++) {
- buf_pool_t* ptr = &buf_pool_ptr[i];
-
- if (buf_pool_init_instance(ptr, size, i) != DB_SUCCESS) {
-
- /* Free all the instances created so far. */
- buf_pool_free(i);
-
- return(DB_ERROR);
- }
- }
-
- buf_pool_set_sizes();
- buf_LRU_old_ratio_update(100 * 3/ 8, FALSE);
-
- btr_search_sys_create(buf_pool_get_curr_size() / sizeof(void*) / 64);
-
- return(DB_SUCCESS);
-}
-
-/********************************************************************//**
-Frees the buffer pool at shutdown. This must not be invoked before
-freeing all mutexes. */
-UNIV_INTERN
-void
-buf_pool_free(
-/*==========*/
- ulint n_instances) /*!< in: numbere of instances to free */
-{
- ulint i;
-
- for (i = 0; i < n_instances; i++) {
- buf_pool_free_instance(buf_pool_from_array(i));
- }
-
- mem_free(buf_pool_ptr);
- buf_pool_ptr = NULL;
-}
-
-/********************************************************************//**
-Clears the adaptive hash index on all pages in the buffer pool. */
-UNIV_INTERN
-void
-buf_pool_clear_hash_index(void)
-/*===========================*/
-{
- ulint p;
-
-#ifdef UNIV_SYNC_DEBUG
- ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX));
-#endif /* UNIV_SYNC_DEBUG */
- ut_ad(!btr_search_enabled);
-
- for (p = 0; p < srv_buf_pool_instances; p++) {
- buf_pool_t* buf_pool = buf_pool_from_array(p);
- buf_chunk_t* chunks = buf_pool->chunks;
- buf_chunk_t* chunk = chunks + buf_pool->n_chunks;
-
- while (--chunk >= chunks) {
- buf_block_t* block = chunk->blocks;
- ulint i = chunk->size;
-
- for (; i--; block++) {
- dict_index_t* index = block->index;
-
- /* We can set block->index = NULL
- when we have an x-latch on btr_search_latch;
- see the comment in buf0buf.h */
-
- if (!index) {
- /* Not hashed */
- continue;
- }
-
- block->index = NULL;
-# if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
- block->n_pointers = 0;
-# endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
- }
- }
- }
-}
-
-/********************************************************************//**
-Relocate a buffer control block. Relocates the block on the LRU list
-and in buf_pool->page_hash. Does not relocate bpage->list.
-The caller must take care of relocating bpage->list. */
-UNIV_INTERN
-void
-buf_relocate(
-/*=========*/
- buf_page_t* bpage, /*!< in/out: control block being relocated;
- buf_page_get_state(bpage) must be
- BUF_BLOCK_ZIP_DIRTY or BUF_BLOCK_ZIP_PAGE */
- buf_page_t* dpage) /*!< in/out: destination control block */
-{
- buf_page_t* b;
- ulint fold;
- buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
-
- ut_ad(buf_pool_mutex_own(buf_pool));
- ut_ad(mutex_own(buf_page_get_mutex(bpage)));
- ut_a(buf_page_get_io_fix(bpage) == BUF_IO_NONE);
- ut_a(bpage->buf_fix_count == 0);
- ut_ad(bpage->in_LRU_list);
- ut_ad(!bpage->in_zip_hash);
- ut_ad(bpage->in_page_hash);
- ut_ad(bpage == buf_page_hash_get(buf_pool,
- bpage->space, bpage->offset));
- ut_ad(!buf_pool_watch_is_sentinel(buf_pool, bpage));
-#ifdef UNIV_DEBUG
- switch (buf_page_get_state(bpage)) {
- case BUF_BLOCK_ZIP_FREE:
- case BUF_BLOCK_NOT_USED:
- case BUF_BLOCK_READY_FOR_USE:
- case BUF_BLOCK_FILE_PAGE:
- case BUF_BLOCK_MEMORY:
- case BUF_BLOCK_REMOVE_HASH:
- ut_error;
- case BUF_BLOCK_ZIP_DIRTY:
- case BUF_BLOCK_ZIP_PAGE:
- break;
- }
-#endif /* UNIV_DEBUG */
-
- memcpy(dpage, bpage, sizeof *dpage);
-
- ut_d(bpage->in_LRU_list = FALSE);
- ut_d(bpage->in_page_hash = FALSE);
-
- /* relocate buf_pool->LRU */
- b = UT_LIST_GET_PREV(LRU, bpage);
- UT_LIST_REMOVE(LRU, buf_pool->LRU, bpage);
-
- if (b) {
- UT_LIST_INSERT_AFTER(LRU, buf_pool->LRU, b, dpage);
- } else {
- UT_LIST_ADD_FIRST(LRU, buf_pool->LRU, dpage);
- }
-
- if (UNIV_UNLIKELY(buf_pool->LRU_old == bpage)) {
- buf_pool->LRU_old = dpage;
-#ifdef UNIV_LRU_DEBUG
- /* buf_pool->LRU_old must be the first item in the LRU list
- whose "old" flag is set. */
- ut_a(buf_pool->LRU_old->old);
- ut_a(!UT_LIST_GET_PREV(LRU, buf_pool->LRU_old)
- || !UT_LIST_GET_PREV(LRU, buf_pool->LRU_old)->old);
- ut_a(!UT_LIST_GET_NEXT(LRU, buf_pool->LRU_old)
- || UT_LIST_GET_NEXT(LRU, buf_pool->LRU_old)->old);
- } else {
- /* Check that the "old" flag is consistent in
- the block and its neighbours. */
- buf_page_set_old(dpage, buf_page_is_old(dpage));
-#endif /* UNIV_LRU_DEBUG */
- }
-
- ut_d(UT_LIST_VALIDATE(LRU, buf_page_t, buf_pool->LRU,
- ut_ad(ut_list_node_313->in_LRU_list)));
-
- /* relocate buf_pool->page_hash */
- fold = buf_page_address_fold(bpage->space, bpage->offset);
-
- HASH_DELETE(buf_page_t, hash, buf_pool->page_hash, fold, bpage);
- HASH_INSERT(buf_page_t, hash, buf_pool->page_hash, fold, dpage);
-}
-
-/********************************************************************//**
-Determine if a block is a sentinel for a buffer pool watch.
-@return TRUE if a sentinel for a buffer pool watch, FALSE if not */
-UNIV_INTERN
-ibool
-buf_pool_watch_is_sentinel(
-/*=======================*/
- buf_pool_t* buf_pool, /*!< buffer pool instance */
- const buf_page_t* bpage) /*!< in: block */
-{
- ut_ad(buf_page_in_file(bpage));
-
- if (bpage < &buf_pool->watch[0]
- || bpage >= &buf_pool->watch[BUF_POOL_WATCH_SIZE]) {
-
- ut_ad(buf_page_get_state(bpage) != BUF_BLOCK_ZIP_PAGE
- || bpage->zip.data != NULL);
-
- return(FALSE);
- }
-
- ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_PAGE);
- ut_ad(!bpage->in_zip_hash);
- ut_ad(bpage->in_page_hash);
- ut_ad(bpage->zip.data == NULL);
- ut_ad(bpage->buf_fix_count > 0);
- return(TRUE);
-}
-
-/****************************************************************//**
-Add watch for the given page to be read in. Caller must have the buffer pool
-mutex reserved.
-@return NULL if watch set, block if the page is in the buffer pool */
-UNIV_INTERN
-buf_page_t*
-buf_pool_watch_set(
-/*===============*/
- ulint space, /*!< in: space id */
- ulint offset, /*!< in: page number */
- ulint fold) /*!< in: buf_page_address_fold(space, offset) */
-{
- buf_page_t* bpage;
- ulint i;
- buf_pool_t* buf_pool = buf_pool_get(space, offset);
-
- ut_ad(buf_pool_mutex_own(buf_pool));
-
- bpage = buf_page_hash_get_low(buf_pool, space, offset, fold);
-
- if (UNIV_LIKELY_NULL(bpage)) {
- if (!buf_pool_watch_is_sentinel(buf_pool, bpage)) {
- /* The page was loaded meanwhile. */
- return(bpage);
- }
- /* Add to an existing watch. */
- bpage->buf_fix_count++;
- return(NULL);
- }
-
- for (i = 0; i < BUF_POOL_WATCH_SIZE; i++) {
- bpage = &buf_pool->watch[i];
-
- ut_ad(bpage->access_time == 0);
- ut_ad(bpage->newest_modification == 0);
- ut_ad(bpage->oldest_modification == 0);
- ut_ad(bpage->zip.data == NULL);
- ut_ad(!bpage->in_zip_hash);
-
- switch (bpage->state) {
- case BUF_BLOCK_POOL_WATCH:
- ut_ad(!bpage->in_page_hash);
- ut_ad(bpage->buf_fix_count == 0);
-
- /* bpage is pointing to buf_pool->watch[],
- which is protected by buf_pool->mutex.
- Normally, buf_page_t objects are protected by
- buf_block_t::mutex or buf_pool->zip_mutex or both. */
-
- bpage->state = BUF_BLOCK_ZIP_PAGE;
- bpage->space = space;
- bpage->offset = offset;
- bpage->buf_fix_count = 1;
-
- ut_d(bpage->in_page_hash = TRUE);
- HASH_INSERT(buf_page_t, hash, buf_pool->page_hash,
- fold, bpage);
- return(NULL);
- case BUF_BLOCK_ZIP_PAGE:
- ut_ad(bpage->in_page_hash);
- ut_ad(bpage->buf_fix_count > 0);
- break;
- default:
- ut_error;
- }
- }
-
- /* Allocation failed. Either the maximum number of purge
- threads should never exceed BUF_POOL_WATCH_SIZE, or this code
- should be modified to return a special non-NULL value and the
- caller should purge the record directly. */
- ut_error;
-
- /* Fix compiler warning */
- return(NULL);
-}
-
-/****************************************************************//**
-Remove the sentinel block for the watch before replacing it with a real block.
-buf_page_watch_clear() or buf_page_watch_occurred() will notice that
-the block has been replaced with the real block.
-@return reference count, to be added to the replacement block */
-static
-void
-buf_pool_watch_remove(
-/*==================*/
- buf_pool_t* buf_pool, /*!< buffer pool instance */
- ulint fold, /*!< in: buf_page_address_fold(
- space, offset) */
- buf_page_t* watch) /*!< in/out: sentinel for watch */
-{
- ut_ad(buf_pool_mutex_own(buf_pool));
-
- HASH_DELETE(buf_page_t, hash, buf_pool->page_hash, fold, watch);
- ut_d(watch->in_page_hash = FALSE);
- watch->buf_fix_count = 0;
- watch->state = BUF_BLOCK_POOL_WATCH;
-}
-
-/****************************************************************//**
-Stop watching if the page has been read in.
-buf_pool_watch_set(space,offset) must have returned NULL before. */
-UNIV_INTERN
-void
-buf_pool_watch_unset(
-/*=================*/
- ulint space, /*!< in: space id */
- ulint offset) /*!< in: page number */
-{
- buf_page_t* bpage;
- buf_pool_t* buf_pool = buf_pool_get(space, offset);
- ulint fold = buf_page_address_fold(space, offset);
-
- buf_pool_mutex_enter(buf_pool);
- bpage = buf_page_hash_get_low(buf_pool, space, offset, fold);
- /* The page must exist because buf_pool_watch_set()
- increments buf_fix_count. */
- ut_a(bpage);
-
- if (UNIV_UNLIKELY(!buf_pool_watch_is_sentinel(buf_pool, bpage))) {
- mutex_t* mutex = buf_page_get_mutex(bpage);
-
- mutex_enter(mutex);
- ut_a(bpage->buf_fix_count > 0);
- bpage->buf_fix_count--;
- mutex_exit(mutex);
- } else {
- ut_a(bpage->buf_fix_count > 0);
-
- if (UNIV_LIKELY(!--bpage->buf_fix_count)) {
- buf_pool_watch_remove(buf_pool, fold, bpage);
- }
- }
-
- buf_pool_mutex_exit(buf_pool);
-}
-
-/****************************************************************//**
-Check if the page has been read in.
-This may only be called after buf_pool_watch_set(space,offset)
-has returned NULL and before invoking buf_pool_watch_unset(space,offset).
-@return FALSE if the given page was not read in, TRUE if it was */
-UNIV_INTERN
-ibool
-buf_pool_watch_occurred(
-/*====================*/
- ulint space, /*!< in: space id */
- ulint offset) /*!< in: page number */
-{
- ibool ret;
- buf_page_t* bpage;
- buf_pool_t* buf_pool = buf_pool_get(space, offset);
- ulint fold = buf_page_address_fold(space, offset);
-
- buf_pool_mutex_enter(buf_pool);
-
- bpage = buf_page_hash_get_low(buf_pool, space, offset, fold);
- /* The page must exist because buf_pool_watch_set()
- increments buf_fix_count. */
- ut_a(bpage);
- ret = !buf_pool_watch_is_sentinel(buf_pool, bpage);
- buf_pool_mutex_exit(buf_pool);
-
- return(ret);
-}
-
-/********************************************************************//**
-Moves a page to the start of the buffer pool LRU list. This high-level
-function can be used to prevent an important page from slipping out of
-the buffer pool. */
-UNIV_INTERN
-void
-buf_page_make_young(
-/*================*/
- buf_page_t* bpage) /*!< in: buffer block of a file page */
-{
- buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
-
- buf_pool_mutex_enter(buf_pool);
-
- ut_a(buf_page_in_file(bpage));
-
- buf_LRU_make_block_young(bpage);
-
- buf_pool_mutex_exit(buf_pool);
-}
-
-/********************************************************************//**
-Sets the time of the first access of a page and moves a page to the
-start of the buffer pool LRU list if it is too old. This high-level
-function can be used to prevent an important page from slipping
-out of the buffer pool. */
-static
-void
-buf_page_set_accessed_make_young(
-/*=============================*/
- buf_page_t* bpage, /*!< in/out: buffer block of a
- file page */
- unsigned access_time) /*!< in: bpage->access_time
- read under mutex protection,
- or 0 if unknown */
-{
- buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
-
- ut_ad(!buf_pool_mutex_own(buf_pool));
- ut_a(buf_page_in_file(bpage));
-
- if (buf_page_peek_if_too_old(bpage)) {
- buf_pool_mutex_enter(buf_pool);
- buf_LRU_make_block_young(bpage);
- buf_pool_mutex_exit(buf_pool);
- } else if (!access_time) {
- ulint time_ms = ut_time_ms();
- buf_pool_mutex_enter(buf_pool);
- buf_page_set_accessed(bpage, time_ms);
- buf_pool_mutex_exit(buf_pool);
- }
-}
-
-/********************************************************************//**
-Resets the check_index_page_at_flush field of a page if found in the buffer
-pool. */
-UNIV_INTERN
-void
-buf_reset_check_index_page_at_flush(
-/*================================*/
- ulint space, /*!< in: space id */
- ulint offset) /*!< in: page number */
-{
- buf_block_t* block;
- buf_pool_t* buf_pool = buf_pool_get(space, offset);
-
- buf_pool_mutex_enter(buf_pool);
-
- block = (buf_block_t*) buf_page_hash_get(buf_pool, space, offset);
-
- if (block && buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE) {
- ut_ad(!buf_pool_watch_is_sentinel(buf_pool, &block->page));
- block->check_index_page_at_flush = FALSE;
- }
-
- buf_pool_mutex_exit(buf_pool);
-}
-
-#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
-/********************************************************************//**
-Sets file_page_was_freed TRUE if the page is found in the buffer pool.
-This function should be called when we free a file page and want the
-debug version to check that it is not accessed any more unless
-reallocated.
-@return control block if found in page hash table, otherwise NULL */
-UNIV_INTERN
-buf_page_t*
-buf_page_set_file_page_was_freed(
-/*=============================*/
- ulint space, /*!< in: space id */
- ulint offset) /*!< in: page number */
-{
- buf_page_t* bpage;
- buf_pool_t* buf_pool = buf_pool_get(space, offset);
-
- buf_pool_mutex_enter(buf_pool);
-
- bpage = buf_page_hash_get(buf_pool, space, offset);
-
- if (bpage) {
- ut_ad(!buf_pool_watch_is_sentinel(buf_pool, bpage));
- /* bpage->file_page_was_freed can already hold
- when this code is invoked from dict_drop_index_tree() */
- bpage->file_page_was_freed = TRUE;
- }
-
- buf_pool_mutex_exit(buf_pool);
-
- return(bpage);
-}
-
-/********************************************************************//**
-Sets file_page_was_freed FALSE if the page is found in the buffer pool.
-This function should be called when we free a file page and want the
-debug version to check that it is not accessed any more unless
-reallocated.
-@return control block if found in page hash table, otherwise NULL */
-UNIV_INTERN
-buf_page_t*
-buf_page_reset_file_page_was_freed(
-/*===============================*/
- ulint space, /*!< in: space id */
- ulint offset) /*!< in: page number */
-{
- buf_page_t* bpage;
- buf_pool_t* buf_pool = buf_pool_get(space, offset);
-
- buf_pool_mutex_enter(buf_pool);
-
- bpage = buf_page_hash_get(buf_pool, space, offset);
-
- if (bpage) {
- ut_ad(!buf_pool_watch_is_sentinel(buf_pool, bpage));
- bpage->file_page_was_freed = FALSE;
- }
-
- buf_pool_mutex_exit(buf_pool);
-
- return(bpage);
-}
-#endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */
-
-/********************************************************************//**
-Get read access to a compressed page (usually of type
-FIL_PAGE_TYPE_ZBLOB or FIL_PAGE_TYPE_ZBLOB2).
-The page must be released with buf_page_release_zip().
-NOTE: the page is not protected by any latch. Mutual exclusion has to
-be implemented at a higher level. In other words, all possible
-accesses to a given page through this function must be protected by
-the same set of mutexes or latches.
-@return pointer to the block */
-UNIV_INTERN
-buf_page_t*
-buf_page_get_zip(
-/*=============*/
- ulint space, /*!< in: space id */
- ulint zip_size,/*!< in: compressed page size */
- ulint offset) /*!< in: page number */
-{
- buf_page_t* bpage;
- mutex_t* block_mutex;
- ibool must_read;
- unsigned access_time;
- buf_pool_t* buf_pool = buf_pool_get(space, offset);
-
- buf_pool->stat.n_page_gets++;
-
- for (;;) {
- buf_pool_mutex_enter(buf_pool);
-lookup:
- bpage = buf_page_hash_get(buf_pool, space, offset);
- if (bpage) {
- ut_ad(!buf_pool_watch_is_sentinel(buf_pool, bpage));
- break;
- }
-
- /* Page not in buf_pool: needs to be read from file */
-
- buf_pool_mutex_exit(buf_pool);
-
- buf_read_page(space, zip_size, offset);
-
-#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
- ut_a(++buf_dbg_counter % 37 || buf_validate());
-#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
- }
-
- if (UNIV_UNLIKELY(!bpage->zip.data)) {
- /* There is no compressed page. */
-err_exit:
- buf_pool_mutex_exit(buf_pool);
- return(NULL);
- }
-
- ut_ad(!buf_pool_watch_is_sentinel(buf_pool, bpage));
-
- switch (buf_page_get_state(bpage)) {
- case BUF_BLOCK_NOT_USED:
- case BUF_BLOCK_READY_FOR_USE:
- case BUF_BLOCK_MEMORY:
- case BUF_BLOCK_REMOVE_HASH:
- case BUF_BLOCK_ZIP_FREE:
- break;
- case BUF_BLOCK_ZIP_PAGE:
- case BUF_BLOCK_ZIP_DIRTY:
- block_mutex = &buf_pool->zip_mutex;
- mutex_enter(block_mutex);
- bpage->buf_fix_count++;
- goto got_block;
- case BUF_BLOCK_FILE_PAGE:
- block_mutex = &((buf_block_t*) bpage)->mutex;
- mutex_enter(block_mutex);
-
- /* Discard the uncompressed page frame if possible. */
- if (buf_LRU_free_block(bpage, FALSE)) {
-
- mutex_exit(block_mutex);
- goto lookup;
- }
-
- buf_block_buf_fix_inc((buf_block_t*) bpage,
- __FILE__, __LINE__);
- goto got_block;
- }
-
- ut_error;
- goto err_exit;
-
-got_block:
- must_read = buf_page_get_io_fix(bpage) == BUF_IO_READ;
- access_time = buf_page_is_accessed(bpage);
-
- buf_pool_mutex_exit(buf_pool);
-
- mutex_exit(block_mutex);
-
- buf_page_set_accessed_make_young(bpage, access_time);
-
-#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
- ut_a(!bpage->file_page_was_freed);
-#endif
-
-#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
- ut_a(++buf_dbg_counter % 5771 || buf_validate());
- ut_a(bpage->buf_fix_count > 0);
- ut_a(buf_page_in_file(bpage));
-#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
-
- if (must_read) {
- /* Let us wait until the read operation
- completes */
-
- for (;;) {
- enum buf_io_fix io_fix;
-
- mutex_enter(block_mutex);
- io_fix = buf_page_get_io_fix(bpage);
- mutex_exit(block_mutex);
-
- if (io_fix == BUF_IO_READ) {
-
- os_thread_sleep(WAIT_FOR_READ);
- } else {
- break;
- }
- }
- }
-
-#ifdef UNIV_IBUF_COUNT_DEBUG
- ut_a(ibuf_count_get(buf_page_get_space(bpage),
- buf_page_get_page_no(bpage)) == 0);
-#endif
- return(bpage);
-}
-
-/********************************************************************//**
-Initialize some fields of a control block. */
-UNIV_INLINE
-void
-buf_block_init_low(
-/*===============*/
- buf_block_t* block) /*!< in: block to init */
-{
- block->check_index_page_at_flush = FALSE;
- block->index = NULL;
-
- block->n_hash_helps = 0;
- block->n_fields = 1;
- block->n_bytes = 0;
- block->left_side = TRUE;
-}
-#endif /* !UNIV_HOTBACKUP */
-
-/********************************************************************//**
-Decompress a block.
-@return TRUE if successful */
-UNIV_INTERN
-ibool
-buf_zip_decompress(
-/*===============*/
- buf_block_t* block, /*!< in/out: block */
- ibool check) /*!< in: TRUE=verify the page checksum */
-{
- const byte* frame = block->page.zip.data;
- ulint stamp_checksum = mach_read_from_4(
- frame + FIL_PAGE_SPACE_OR_CHKSUM);
-
- ut_ad(buf_block_get_zip_size(block));
- ut_a(buf_block_get_space(block) != 0);
-
- if (UNIV_LIKELY(check && stamp_checksum != BUF_NO_CHECKSUM_MAGIC)) {
- ulint calc_checksum = page_zip_calc_checksum(
- frame, page_zip_get_size(&block->page.zip));
-
- if (UNIV_UNLIKELY(stamp_checksum != calc_checksum)) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: compressed page checksum mismatch"
- " (space %u page %u): %lu != %lu\n",
- block->page.space, block->page.offset,
- stamp_checksum, calc_checksum);
- return(FALSE);
- }
- }
-
- switch (fil_page_get_type(frame)) {
- case FIL_PAGE_INDEX:
- if (page_zip_decompress(&block->page.zip,
- block->frame, TRUE)) {
- return(TRUE);
- }
-
- fprintf(stderr,
- "InnoDB: unable to decompress space %lu page %lu\n",
- (ulong) block->page.space,
- (ulong) block->page.offset);
- return(FALSE);
-
- case FIL_PAGE_TYPE_ALLOCATED:
- case FIL_PAGE_INODE:
- case FIL_PAGE_IBUF_BITMAP:
- case FIL_PAGE_TYPE_FSP_HDR:
- case FIL_PAGE_TYPE_XDES:
- case FIL_PAGE_TYPE_ZBLOB:
- case FIL_PAGE_TYPE_ZBLOB2:
- /* Copy to uncompressed storage. */
- memcpy(block->frame, frame,
- buf_block_get_zip_size(block));
- return(TRUE);
- }
-
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: unknown compressed page"
- " type %lu\n",
- fil_page_get_type(frame));
- return(FALSE);
-}
-
-#ifndef UNIV_HOTBACKUP
-/*******************************************************************//**
-Gets the block to whose frame the pointer is pointing to if found
-in this buffer pool instance.
-@return pointer to block */
-UNIV_INTERN
-buf_block_t*
-buf_block_align_instance(
-/*=====================*/
- buf_pool_t* buf_pool, /*!< in: buffer in which the block
- resides */
- const byte* ptr) /*!< in: pointer to a frame */
-{
- buf_chunk_t* chunk;
- ulint i;
-
- /* TODO: protect buf_pool->chunks with a mutex (it will
- currently remain constant after buf_pool_init()) */
- for (chunk = buf_pool->chunks, i = buf_pool->n_chunks; i--; chunk++) {
- ulint offs;
-
- if (UNIV_UNLIKELY(ptr < chunk->blocks->frame)) {
-
- continue;
- }
- /* else */
-
- offs = ptr - chunk->blocks->frame;
-
- offs >>= UNIV_PAGE_SIZE_SHIFT;
-
- if (UNIV_LIKELY(offs < chunk->size)) {
- buf_block_t* block = &chunk->blocks[offs];
-
- /* The function buf_chunk_init() invokes
- buf_block_init() so that block[n].frame ==
- block->frame + n * UNIV_PAGE_SIZE. Check it. */
- ut_ad(block->frame == page_align(ptr));
-#ifdef UNIV_DEBUG
- /* A thread that updates these fields must
- hold buf_pool->mutex and block->mutex. Acquire
- only the latter. */
- mutex_enter(&block->mutex);
-
- switch (buf_block_get_state(block)) {
- case BUF_BLOCK_ZIP_FREE:
- case BUF_BLOCK_ZIP_PAGE:
- case BUF_BLOCK_ZIP_DIRTY:
- /* These types should only be used in
- the compressed buffer pool, whose
- memory is allocated from
- buf_pool->chunks, in UNIV_PAGE_SIZE
- blocks flagged as BUF_BLOCK_MEMORY. */
- ut_error;
- break;
- case BUF_BLOCK_NOT_USED:
- case BUF_BLOCK_READY_FOR_USE:
- case BUF_BLOCK_MEMORY:
- /* Some data structures contain
- "guess" pointers to file pages. The
- file pages may have been freed and
- reused. Do not complain. */
- break;
- case BUF_BLOCK_REMOVE_HASH:
- /* buf_LRU_block_remove_hashed_page()
- will overwrite the FIL_PAGE_OFFSET and
- FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID with
- 0xff and set the state to
- BUF_BLOCK_REMOVE_HASH. */
- ut_ad(page_get_space_id(page_align(ptr))
- == 0xffffffff);
- ut_ad(page_get_page_no(page_align(ptr))
- == 0xffffffff);
- break;
- case BUF_BLOCK_FILE_PAGE:
- ut_ad(block->page.space
- == page_get_space_id(page_align(ptr)));
- ut_ad(block->page.offset
- == page_get_page_no(page_align(ptr)));
- break;
- }
-
- mutex_exit(&block->mutex);
-#endif /* UNIV_DEBUG */
-
- return(block);
- }
- }
-
- return(NULL);
-}
-
-/*******************************************************************//**
-Gets the block to whose frame the pointer is pointing to.
-@return pointer to block, never NULL */
-UNIV_INTERN
-buf_block_t*
-buf_block_align(
-/*============*/
- const byte* ptr) /*!< in: pointer to a frame */
-{
- ulint i;
-
- for (i = 0; i < srv_buf_pool_instances; i++) {
- buf_block_t* block;
-
- block = buf_block_align_instance(
- buf_pool_from_array(i), ptr);
- if (block) {
- return(block);
- }
- }
-
- /* The block should always be found. */
- ut_error;
- return(NULL);
-}
-
-/********************************************************************//**
-Find out if a pointer belongs to a buf_block_t. It can be a pointer to
-the buf_block_t itself or a member of it. This functions checks one of
-the buffer pool instances.
-@return TRUE if ptr belongs to a buf_block_t struct */
-static
-ibool
-buf_pointer_is_block_field_instance(
-/*================================*/
- buf_pool_t* buf_pool, /*!< in: buffer pool instance */
- const void* ptr) /*!< in: pointer not dereferenced */
-{
- const buf_chunk_t* chunk = buf_pool->chunks;
- const buf_chunk_t* const echunk = chunk + buf_pool->n_chunks;
-
- /* TODO: protect buf_pool->chunks with a mutex (it will
- currently remain constant after buf_pool_init()) */
- while (chunk < echunk) {
- if (ptr >= (void *)chunk->blocks
- && ptr < (void *)(chunk->blocks + chunk->size)) {
-
- return(TRUE);
- }
-
- chunk++;
- }
-
- return(FALSE);
-}
-
-/********************************************************************//**
-Find out if a pointer belongs to a buf_block_t. It can be a pointer to
-the buf_block_t itself or a member of it
-@return TRUE if ptr belongs to a buf_block_t struct */
-UNIV_INTERN
-ibool
-buf_pointer_is_block_field(
-/*=======================*/
- const void* ptr) /*!< in: pointer not dereferenced */
-{
- ulint i;
-
- for (i = 0; i < srv_buf_pool_instances; i++) {
- ibool found;
-
- found = buf_pointer_is_block_field_instance(
- buf_pool_from_array(i), ptr);
- if (found) {
- return(TRUE);
- }
- }
-
- return(FALSE);
-}
-
-/********************************************************************//**
-Find out if a buffer block was created by buf_chunk_init().
-@return TRUE if "block" has been added to buf_pool->free by buf_chunk_init() */
-static
-ibool
-buf_block_is_uncompressed(
-/*======================*/
- buf_pool_t* buf_pool, /*!< in: buffer pool instance */
- const buf_block_t* block) /*!< in: pointer to block,
- not dereferenced */
-{
- ut_ad(buf_pool_mutex_own(buf_pool));
-
- if (UNIV_UNLIKELY((((ulint) block) % sizeof *block) != 0)) {
- /* The pointer should be aligned. */
- return(FALSE);
- }
-
- return(buf_pointer_is_block_field_instance(buf_pool, (void *)block));
-}
-
-/********************************************************************//**
-This is the general function used to get access to a database page.
-@return pointer to the block or NULL */
-UNIV_INTERN
-buf_block_t*
-buf_page_get_gen(
-/*=============*/
- ulint space, /*!< in: space id */
- ulint zip_size,/*!< in: compressed page size in bytes
- or 0 for uncompressed pages */
- ulint offset, /*!< in: page number */
- ulint rw_latch,/*!< in: RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */
- buf_block_t* guess, /*!< in: guessed block or NULL */
- ulint mode, /*!< in: BUF_GET, BUF_GET_IF_IN_POOL,
- BUF_PEEK_IF_IN_POOL, BUF_GET_NO_LATCH, or
- BUF_GET_IF_IN_POOL_OR_WATCH */
- const char* file, /*!< in: file name */
- ulint line, /*!< in: line where called */
- mtr_t* mtr) /*!< in: mini-transaction */
-{
- buf_block_t* block;
- ulint fold;
- unsigned access_time;
- ulint fix_type;
- ibool must_read;
- ulint retries = 0;
- buf_pool_t* buf_pool = buf_pool_get(space, offset);
-
- ut_ad(mtr);
- ut_ad(mtr->state == MTR_ACTIVE);
- ut_ad((rw_latch == RW_S_LATCH)
- || (rw_latch == RW_X_LATCH)
- || (rw_latch == RW_NO_LATCH));
-#ifdef UNIV_DEBUG
- switch (mode) {
- case BUF_GET_NO_LATCH:
- ut_ad(rw_latch == RW_NO_LATCH);
- break;
- case BUF_GET:
- case BUF_GET_IF_IN_POOL:
- case BUF_PEEK_IF_IN_POOL:
- case BUF_GET_IF_IN_POOL_OR_WATCH:
- case BUF_GET_POSSIBLY_FREED:
- break;
- default:
- ut_error;
- }
-#endif /* UNIV_DEBUG */
- ut_ad(zip_size == fil_space_get_zip_size(space));
- ut_ad(ut_is_2pow(zip_size));
-#ifndef UNIV_LOG_DEBUG
- ut_ad(!ibuf_inside(mtr)
- || ibuf_page_low(space, zip_size, offset,
- FALSE, file, line, NULL));
-#endif
- buf_pool->stat.n_page_gets++;
- fold = buf_page_address_fold(space, offset);
-loop:
- block = guess;
- buf_pool_mutex_enter(buf_pool);
-
- if (block) {
- /* If the guess is a compressed page descriptor that
- has been allocated by buf_page_alloc_descriptor(),
- it may have been freed by buf_relocate(). */
-
- if (!buf_block_is_uncompressed(buf_pool, block)
- || offset != block->page.offset
- || space != block->page.space
- || buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE) {
-
- block = guess = NULL;
- } else {
- ut_ad(!block->page.in_zip_hash);
- ut_ad(block->page.in_page_hash);
- }
- }
-
- if (block == NULL) {
- block = (buf_block_t*) buf_page_hash_get_low(
- buf_pool, space, offset, fold);
- }
-
-loop2:
- if (block && buf_pool_watch_is_sentinel(buf_pool, &block->page)) {
- block = NULL;
- }
-
- if (block == NULL) {
- /* Page not in buf_pool: needs to be read from file */
-
- if (mode == BUF_GET_IF_IN_POOL_OR_WATCH) {
- block = (buf_block_t*) buf_pool_watch_set(
- space, offset, fold);
-
- if (UNIV_LIKELY_NULL(block)) {
-
- goto got_block;
- }
- }
-
- buf_pool_mutex_exit(buf_pool);
-
- if (mode == BUF_GET_IF_IN_POOL
- || mode == BUF_PEEK_IF_IN_POOL
- || mode == BUF_GET_IF_IN_POOL_OR_WATCH) {
-
- return(NULL);
- }
-
- if (buf_read_page(space, zip_size, offset)) {
- buf_read_ahead_random(space, zip_size, offset,
- ibuf_inside(mtr));
-
- retries = 0;
- } else if (retries < BUF_PAGE_READ_MAX_RETRIES) {
- ++retries;
- } else {
- fprintf(stderr, "InnoDB: Error: Unable"
- " to read tablespace %lu page no"
- " %lu into the buffer pool after"
- " %lu attempts\n"
- "InnoDB: The most probable cause"
- " of this error may be that the"
- " table has been corrupted.\n"
- "InnoDB: You can try to fix this"
- " problem by using"
- " innodb_force_recovery.\n"
- "InnoDB: Please see reference manual"
- " for more details.\n"
- "InnoDB: Aborting...\n",
- space, offset,
- BUF_PAGE_READ_MAX_RETRIES);
-
- ut_error;
- }
-
-#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
- ut_a(++buf_dbg_counter % 37 || buf_validate());
-#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
- goto loop;
- }
-
-got_block:
- ut_ad(page_zip_get_size(&block->page.zip) == zip_size);
-
- must_read = buf_block_get_io_fix(block) == BUF_IO_READ;
-
- if (must_read && (mode == BUF_GET_IF_IN_POOL
- || mode == BUF_PEEK_IF_IN_POOL)) {
-
- /* The page is being read to buffer pool,
- but we cannot wait around for the read to
- complete. */
- buf_pool_mutex_exit(buf_pool);
-
- return(NULL);
- }
-
- switch (buf_block_get_state(block)) {
- buf_page_t* bpage;
- ibool success;
-
- case BUF_BLOCK_FILE_PAGE:
- break;
-
- case BUF_BLOCK_ZIP_PAGE:
- case BUF_BLOCK_ZIP_DIRTY:
- bpage = &block->page;
- /* Protect bpage->buf_fix_count. */
- mutex_enter(&buf_pool->zip_mutex);
-
- if (bpage->buf_fix_count
- || buf_page_get_io_fix(bpage) != BUF_IO_NONE) {
- /* This condition often occurs when the buffer
- is not buffer-fixed, but I/O-fixed by
- buf_page_init_for_read(). */
- mutex_exit(&buf_pool->zip_mutex);
-wait_until_unfixed:
- /* The block is buffer-fixed or I/O-fixed.
- Try again later. */
- buf_pool_mutex_exit(buf_pool);
- os_thread_sleep(WAIT_FOR_READ);
-
- goto loop;
- }
-
- /* Allocate an uncompressed page. */
- buf_pool_mutex_exit(buf_pool);
- mutex_exit(&buf_pool->zip_mutex);
-
- block = buf_LRU_get_free_block(buf_pool);
- ut_a(block);
-
- buf_pool_mutex_enter(buf_pool);
- mutex_enter(&block->mutex);
-
- {
- buf_page_t* hash_bpage;
-
- hash_bpage = buf_page_hash_get_low(
- buf_pool, space, offset, fold);
-
- if (UNIV_UNLIKELY(bpage != hash_bpage)) {
- /* The buf_pool->page_hash was modified
- while buf_pool->mutex was released.
- Free the block that was allocated. */
-
- buf_LRU_block_free_non_file_page(block);
- mutex_exit(&block->mutex);
-
- block = (buf_block_t*) hash_bpage;
- goto loop2;
- }
- }
-
- if (UNIV_UNLIKELY
- (bpage->buf_fix_count
- || buf_page_get_io_fix(bpage) != BUF_IO_NONE)) {
-
- /* The block was buffer-fixed or I/O-fixed
- while buf_pool->mutex was not held by this thread.
- Free the block that was allocated and try again.
- This should be extremely unlikely. */
-
- buf_LRU_block_free_non_file_page(block);
- mutex_exit(&block->mutex);
-
- goto wait_until_unfixed;
- }
-
- /* Move the compressed page from bpage to block,
- and uncompress it. */
-
- mutex_enter(&buf_pool->zip_mutex);
-
- buf_relocate(bpage, &block->page);
- buf_block_init_low(block);
- block->lock_hash_val = lock_rec_hash(space, offset);
-
- UNIV_MEM_DESC(&block->page.zip.data,
- page_zip_get_size(&block->page.zip), block);
-
- if (buf_page_get_state(&block->page)
- == BUF_BLOCK_ZIP_PAGE) {
-#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
- UT_LIST_REMOVE(list, buf_pool->zip_clean,
- &block->page);
-#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
- ut_ad(!block->page.in_flush_list);
- } else {
- /* Relocate buf_pool->flush_list. */
- buf_flush_relocate_on_flush_list(bpage,
- &block->page);
- }
-
- /* Buffer-fix, I/O-fix, and X-latch the block
- for the duration of the decompression.
- Also add the block to the unzip_LRU list. */
- block->page.state = BUF_BLOCK_FILE_PAGE;
-
- /* Insert at the front of unzip_LRU list */
- buf_unzip_LRU_add_block(block, FALSE);
-
- block->page.buf_fix_count = 1;
- buf_block_set_io_fix(block, BUF_IO_READ);
- rw_lock_x_lock_inline(&block->lock, 0, file, line);
-
- UNIV_MEM_INVALID(bpage, sizeof *bpage);
-
- mutex_exit(&block->mutex);
- mutex_exit(&buf_pool->zip_mutex);
- buf_pool->n_pend_unzip++;
-
- buf_pool_mutex_exit(buf_pool);
-
- buf_page_free_descriptor(bpage);
-
- /* Decompress the page and apply buffered operations
- while not holding buf_pool->mutex or block->mutex. */
- success = buf_zip_decompress(block, srv_use_checksums);
- ut_a(success);
-
- if (UNIV_LIKELY(!recv_no_ibuf_operations)) {
- ibuf_merge_or_delete_for_page(block, space, offset,
- zip_size, TRUE);
- }
-
- /* Unfix and unlatch the block. */
- buf_pool_mutex_enter(buf_pool);
- mutex_enter(&block->mutex);
- block->page.buf_fix_count--;
- buf_block_set_io_fix(block, BUF_IO_NONE);
- mutex_exit(&block->mutex);
- buf_pool->n_pend_unzip--;
- rw_lock_x_unlock(&block->lock);
-
- break;
-
- case BUF_BLOCK_ZIP_FREE:
- case BUF_BLOCK_NOT_USED:
- case BUF_BLOCK_READY_FOR_USE:
- case BUF_BLOCK_MEMORY:
- case BUF_BLOCK_REMOVE_HASH:
- ut_error;
- break;
- }
-
- ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
-
- mutex_enter(&block->mutex);
-#if UNIV_WORD_SIZE == 4
- /* On 32-bit systems, there is no padding in buf_page_t. On
- other systems, Valgrind could complain about uninitialized pad
- bytes. */
- UNIV_MEM_ASSERT_RW(&block->page, sizeof block->page);
-#endif
-#if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
- if ((mode == BUF_GET_IF_IN_POOL || mode == BUF_GET_IF_IN_POOL_OR_WATCH)
- && ibuf_debug) {
- /* Try to evict the block from the buffer pool, to use the
- insert buffer (change buffer) as much as possible. */
-
- if (buf_LRU_free_block(&block->page, TRUE)) {
- mutex_exit(&block->mutex);
- if (mode == BUF_GET_IF_IN_POOL_OR_WATCH) {
- /* Set the watch, as it would have
- been set if the page were not in the
- buffer pool in the first place. */
- block = (buf_block_t*) buf_pool_watch_set(
- space, offset, fold);
-
- if (UNIV_LIKELY_NULL(block)) {
-
- /* The page entered the buffer
- pool for some reason. Try to
- evict it again. */
- goto got_block;
- }
- }
- buf_pool_mutex_exit(buf_pool);
- fprintf(stderr,
- "innodb_change_buffering_debug evict %u %u\n",
- (unsigned) space, (unsigned) offset);
- return(NULL);
- } else if (buf_flush_page_try(buf_pool, block)) {
- fprintf(stderr,
- "innodb_change_buffering_debug flush %u %u\n",
- (unsigned) space, (unsigned) offset);
- guess = block;
- goto loop;
- }
-
- /* Failed to evict the page; change it directly */
- }
-#endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
-
- buf_block_buf_fix_inc(block, file, line);
-#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
- ut_a(mode == BUF_GET_POSSIBLY_FREED
- || !block->page.file_page_was_freed);
-#endif
- mutex_exit(&block->mutex);
-
- /* Check if this is the first access to the page */
-
- access_time = buf_page_is_accessed(&block->page);
-
- buf_pool_mutex_exit(buf_pool);
-
- if (UNIV_LIKELY(mode != BUF_PEEK_IF_IN_POOL)) {
- buf_page_set_accessed_make_young(&block->page, access_time);
- }
-
-#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
- ut_a(++buf_dbg_counter % 5771 || buf_validate());
- ut_a(block->page.buf_fix_count > 0);
- ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
-#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
-
- switch (rw_latch) {
- case RW_NO_LATCH:
- if (must_read) {
- /* Let us wait until the read operation
- completes */
-
- for (;;) {
- enum buf_io_fix io_fix;
-
- mutex_enter(&block->mutex);
- io_fix = buf_block_get_io_fix(block);
- mutex_exit(&block->mutex);
-
- if (io_fix == BUF_IO_READ) {
-
- os_thread_sleep(WAIT_FOR_READ);
- } else {
- break;
- }
- }
- }
-
- fix_type = MTR_MEMO_BUF_FIX;
- break;
-
- case RW_S_LATCH:
- rw_lock_s_lock_inline(&(block->lock), 0, file, line);
-
- fix_type = MTR_MEMO_PAGE_S_FIX;
- break;
-
- default:
- ut_ad(rw_latch == RW_X_LATCH);
- rw_lock_x_lock_inline(&(block->lock), 0, file, line);
-
- fix_type = MTR_MEMO_PAGE_X_FIX;
- break;
- }
-
- mtr_memo_push(mtr, block, fix_type);
-
- if (UNIV_LIKELY(mode != BUF_PEEK_IF_IN_POOL) && !access_time) {
- /* In the case of a first access, try to apply linear
- read-ahead */
-
- buf_read_ahead_linear(space, zip_size, offset,
- ibuf_inside(mtr));
- }
-
-#ifdef UNIV_IBUF_COUNT_DEBUG
- ut_a(ibuf_count_get(buf_block_get_space(block),
- buf_block_get_page_no(block)) == 0);
-#endif
- return(block);
-}
-
-/********************************************************************//**
-This is the general function used to get optimistic access to a database
-page.
-@return TRUE if success */
-UNIV_INTERN
-ibool
-buf_page_optimistic_get(
-/*====================*/
- ulint rw_latch,/*!< in: RW_S_LATCH, RW_X_LATCH */
- buf_block_t* block, /*!< in: guessed buffer block */
- ib_uint64_t modify_clock,/*!< in: modify clock value if mode is
- ..._GUESS_ON_CLOCK */
- const char* file, /*!< in: file name */
- ulint line, /*!< in: line where called */
- mtr_t* mtr) /*!< in: mini-transaction */
-{
- buf_pool_t* buf_pool;
- unsigned access_time;
- ibool success;
- ulint fix_type;
-
- ut_ad(block);
- ut_ad(mtr);
- ut_ad(mtr->state == MTR_ACTIVE);
- ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH));
-
- mutex_enter(&block->mutex);
-
- if (UNIV_UNLIKELY(buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE)) {
-
- mutex_exit(&block->mutex);
-
- return(FALSE);
- }
-
- buf_block_buf_fix_inc(block, file, line);
-
- mutex_exit(&block->mutex);
-
- /* Check if this is the first access to the page.
- We do a dirty read on purpose, to avoid mutex contention.
- This field is only used for heuristic purposes; it does not
- affect correctness. */
-
- access_time = buf_page_is_accessed(&block->page);
- buf_page_set_accessed_make_young(&block->page, access_time);
-
- ut_ad(!ibuf_inside(mtr)
- || ibuf_page(buf_block_get_space(block),
- buf_block_get_zip_size(block),
- buf_block_get_page_no(block), NULL));
-
- if (rw_latch == RW_S_LATCH) {
- success = rw_lock_s_lock_nowait(&(block->lock),
- file, line);
- fix_type = MTR_MEMO_PAGE_S_FIX;
- } else {
- success = rw_lock_x_lock_func_nowait_inline(&(block->lock),
- file, line);
- fix_type = MTR_MEMO_PAGE_X_FIX;
- }
-
- if (UNIV_UNLIKELY(!success)) {
- mutex_enter(&block->mutex);
- buf_block_buf_fix_dec(block);
- mutex_exit(&block->mutex);
-
- return(FALSE);
- }
-
- if (UNIV_UNLIKELY(modify_clock != block->modify_clock)) {
- buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
-
- if (rw_latch == RW_S_LATCH) {
- rw_lock_s_unlock(&(block->lock));
- } else {
- rw_lock_x_unlock(&(block->lock));
- }
-
- mutex_enter(&block->mutex);
- buf_block_buf_fix_dec(block);
- mutex_exit(&block->mutex);
-
- return(FALSE);
- }
-
- mtr_memo_push(mtr, block, fix_type);
-
-#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
- ut_a(++buf_dbg_counter % 5771 || buf_validate());
- ut_a(block->page.buf_fix_count > 0);
- ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
-#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
-
-#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
- ut_a(block->page.file_page_was_freed == FALSE);
-#endif
- if (UNIV_UNLIKELY(!access_time)) {
- /* In the case of a first access, try to apply linear
- read-ahead */
-
- buf_read_ahead_linear(buf_block_get_space(block),
- buf_block_get_zip_size(block),
- buf_block_get_page_no(block),
- ibuf_inside(mtr));
- }
-
-#ifdef UNIV_IBUF_COUNT_DEBUG
- ut_a(ibuf_count_get(buf_block_get_space(block),
- buf_block_get_page_no(block)) == 0);
-#endif
- buf_pool = buf_pool_from_block(block);
- buf_pool->stat.n_page_gets++;
-
- return(TRUE);
-}
-
-/********************************************************************//**
-This is used to get access to a known database page, when no waiting can be
-done. For example, if a search in an adaptive hash index leads us to this
-frame.
-@return TRUE if success */
-UNIV_INTERN
-ibool
-buf_page_get_known_nowait(
-/*======================*/
- ulint rw_latch,/*!< in: RW_S_LATCH, RW_X_LATCH */
- buf_block_t* block, /*!< in: the known page */
- ulint mode, /*!< in: BUF_MAKE_YOUNG or BUF_KEEP_OLD */
- const char* file, /*!< in: file name */
- ulint line, /*!< in: line where called */
- mtr_t* mtr) /*!< in: mini-transaction */
-{
- buf_pool_t* buf_pool;
- ibool success;
- ulint fix_type;
-
- ut_ad(mtr);
- ut_ad(mtr->state == MTR_ACTIVE);
- ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH));
-
- mutex_enter(&block->mutex);
-
- if (buf_block_get_state(block) == BUF_BLOCK_REMOVE_HASH) {
- /* Another thread is just freeing the block from the LRU list
- of the buffer pool: do not try to access this page; this
- attempt to access the page can only come through the hash
- index because when the buffer block state is ..._REMOVE_HASH,
- we have already removed it from the page address hash table
- of the buffer pool. */
-
- mutex_exit(&block->mutex);
-
- return(FALSE);
- }
-
- ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
-
- buf_block_buf_fix_inc(block, file, line);
-
- mutex_exit(&block->mutex);
-
- buf_pool = buf_pool_from_block(block);
-
- if (mode == BUF_MAKE_YOUNG && buf_page_peek_if_too_old(&block->page)) {
- buf_pool_mutex_enter(buf_pool);
- buf_LRU_make_block_young(&block->page);
- buf_pool_mutex_exit(buf_pool);
- } else if (!buf_page_is_accessed(&block->page)) {
- /* Above, we do a dirty read on purpose, to avoid
- mutex contention. The field buf_page_t::access_time
- is only used for heuristic purposes. Writes to the
- field must be protected by mutex, however. */
- ulint time_ms = ut_time_ms();
-
- buf_pool_mutex_enter(buf_pool);
- buf_page_set_accessed(&block->page, time_ms);
- buf_pool_mutex_exit(buf_pool);
- }
-
- ut_ad(!ibuf_inside(mtr) || mode == BUF_KEEP_OLD);
-
- if (rw_latch == RW_S_LATCH) {
- success = rw_lock_s_lock_nowait(&(block->lock),
- file, line);
- fix_type = MTR_MEMO_PAGE_S_FIX;
- } else {
- success = rw_lock_x_lock_func_nowait_inline(&(block->lock),
- file, line);
- fix_type = MTR_MEMO_PAGE_X_FIX;
- }
-
- if (!success) {
- mutex_enter(&block->mutex);
- buf_block_buf_fix_dec(block);
- mutex_exit(&block->mutex);
-
- return(FALSE);
- }
-
- mtr_memo_push(mtr, block, fix_type);
-
-#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
- ut_a(++buf_dbg_counter % 5771 || buf_validate());
- ut_a(block->page.buf_fix_count > 0);
- ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
-#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
-#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
- ut_a(mode == BUF_KEEP_OLD || !block->page.file_page_was_freed);
-#endif
-
-#ifdef UNIV_IBUF_COUNT_DEBUG
- ut_a((mode == BUF_KEEP_OLD)
- || (ibuf_count_get(buf_block_get_space(block),
- buf_block_get_page_no(block)) == 0));
-#endif
- buf_pool->stat.n_page_gets++;
-
- return(TRUE);
-}
-
-/*******************************************************************//**
-Given a tablespace id and page number tries to get that page. If the
-page is not in the buffer pool it is not loaded and NULL is returned.
-Suitable for using when holding the kernel mutex.
-@return pointer to a page or NULL */
-UNIV_INTERN
-const buf_block_t*
-buf_page_try_get_func(
-/*==================*/
- ulint space_id,/*!< in: tablespace id */
- ulint page_no,/*!< in: page number */
- const char* file, /*!< in: file name */
- ulint line, /*!< in: line where called */
- mtr_t* mtr) /*!< in: mini-transaction */
-{
- buf_block_t* block;
- ibool success;
- ulint fix_type;
- buf_pool_t* buf_pool = buf_pool_get(space_id, page_no);
-
- ut_ad(mtr);
- ut_ad(mtr->state == MTR_ACTIVE);
-
- buf_pool_mutex_enter(buf_pool);
- block = buf_block_hash_get(buf_pool, space_id, page_no);
-
- if (!block || buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE) {
- buf_pool_mutex_exit(buf_pool);
- return(NULL);
- }
-
- ut_ad(!buf_pool_watch_is_sentinel(buf_pool, &block->page));
-
- mutex_enter(&block->mutex);
- buf_pool_mutex_exit(buf_pool);
-
-#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
- ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
- ut_a(buf_block_get_space(block) == space_id);
- ut_a(buf_block_get_page_no(block) == page_no);
-#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
-
- buf_block_buf_fix_inc(block, file, line);
- mutex_exit(&block->mutex);
-
- fix_type = MTR_MEMO_PAGE_S_FIX;
- success = rw_lock_s_lock_nowait(&block->lock, file, line);
-
- if (!success) {
- /* Let us try to get an X-latch. If the current thread
- is holding an X-latch on the page, we cannot get an
- S-latch. */
-
- fix_type = MTR_MEMO_PAGE_X_FIX;
- success = rw_lock_x_lock_func_nowait_inline(&block->lock,
- file, line);
- }
-
- if (!success) {
- mutex_enter(&block->mutex);
- buf_block_buf_fix_dec(block);
- mutex_exit(&block->mutex);
-
- return(NULL);
- }
-
- mtr_memo_push(mtr, block, fix_type);
-#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
- ut_a(++buf_dbg_counter % 5771 || buf_validate());
- ut_a(block->page.buf_fix_count > 0);
- ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
-#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
-#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
- ut_a(block->page.file_page_was_freed == FALSE);
-#endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */
- buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
-
- buf_pool->stat.n_page_gets++;
-
-#ifdef UNIV_IBUF_COUNT_DEBUG
- ut_a(ibuf_count_get(buf_block_get_space(block),
- buf_block_get_page_no(block)) == 0);
-#endif
-
- return(block);
-}
-
-/********************************************************************//**
-Initialize some fields of a control block. */
-UNIV_INLINE
-void
-buf_page_init_low(
-/*==============*/
- buf_page_t* bpage) /*!< in: block to init */
-{
- bpage->flush_type = BUF_FLUSH_LRU;
- bpage->io_fix = BUF_IO_NONE;
- bpage->buf_fix_count = 0;
- bpage->freed_page_clock = 0;
- bpage->access_time = 0;
- bpage->newest_modification = 0;
- bpage->oldest_modification = 0;
- HASH_INVALIDATE(bpage, hash);
-#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
- bpage->file_page_was_freed = FALSE;
-#endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */
-}
-
-/********************************************************************//**
-Inits a page to the buffer buf_pool. */
-static __attribute__((nonnull))
-void
-buf_page_init(
-/*==========*/
- buf_pool_t* buf_pool,/*!< in/out: buffer pool */
- ulint space, /*!< in: space id */
- ulint offset, /*!< in: offset of the page within space
- in units of a page */
- ulint fold, /*!< in: buf_page_address_fold(space,offset) */
- buf_block_t* block) /*!< in/out: block to init */
-{
- buf_page_t* hash_page;
-
- ut_ad(buf_pool == buf_pool_get(space, offset));
- ut_ad(buf_pool_mutex_own(buf_pool));
- ut_ad(mutex_own(&(block->mutex)));
- ut_a(buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE);
-
- /* Set the state of the block */
- buf_block_set_file_page(block, space, offset);
-
-#ifdef UNIV_DEBUG_VALGRIND
- if (!space) {
- /* Silence valid Valgrind warnings about uninitialized
- data being written to data files. There are some unused
- bytes on some pages that InnoDB does not initialize. */
- UNIV_MEM_VALID(block->frame, UNIV_PAGE_SIZE);
- }
-#endif /* UNIV_DEBUG_VALGRIND */
-
- buf_block_init_low(block);
-
- block->lock_hash_val = lock_rec_hash(space, offset);
-
- buf_page_init_low(&block->page);
-
- /* Insert into the hash table of file pages */
-
- hash_page = buf_page_hash_get_low(buf_pool, space, offset, fold);
-
- if (UNIV_LIKELY(!hash_page)) {
- } else if (buf_pool_watch_is_sentinel(buf_pool, hash_page)) {
- /* Preserve the reference count. */
- ulint buf_fix_count = hash_page->buf_fix_count;
-
- ut_a(buf_fix_count > 0);
- block->page.buf_fix_count += buf_fix_count;
- buf_pool_watch_remove(buf_pool, fold, hash_page);
- } else {
- fprintf(stderr,
- "InnoDB: Error: page %lu %lu already found"
- " in the hash table: %p, %p\n",
- (ulong) space,
- (ulong) offset,
- (const void*) hash_page, (const void*) block);
-#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
- mutex_exit(&block->mutex);
- buf_pool_mutex_exit(buf_pool);
- buf_print();
- buf_LRU_print();
- buf_validate();
- buf_LRU_validate();
-#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
- ut_error;
- }
-
- ut_ad(!block->page.in_zip_hash);
- ut_ad(!block->page.in_page_hash);
- ut_d(block->page.in_page_hash = TRUE);
- HASH_INSERT(buf_page_t, hash, buf_pool->page_hash,
- fold, &block->page);
-}
-
-/********************************************************************//**
-Function which inits a page for read to the buffer buf_pool. If the page is
-(1) already in buf_pool, or
-(2) if we specify to read only ibuf pages and the page is not an ibuf page, or
-(3) if the space is deleted or being deleted,
-then this function does nothing.
-Sets the io_fix flag to BUF_IO_READ and sets a non-recursive exclusive lock
-on the buffer frame. The io-handler must take care that the flag is cleared
-and the lock released later.
-@return pointer to the block or NULL */
-UNIV_INTERN
-buf_page_t*
-buf_page_init_for_read(
-/*===================*/
- ulint* err, /*!< out: DB_SUCCESS or DB_TABLESPACE_DELETED */
- ulint mode, /*!< in: BUF_READ_IBUF_PAGES_ONLY, ... */
- ulint space, /*!< in: space id */
- ulint zip_size,/*!< in: compressed page size, or 0 */
- ibool unzip, /*!< in: TRUE=request uncompressed page */
- ib_int64_t tablespace_version,
- /*!< in: prevents reading from a wrong
- version of the tablespace in case we have done
- DISCARD + IMPORT */
- ulint offset) /*!< in: page number */
-{
- buf_block_t* block;
- buf_page_t* bpage = NULL;
- buf_page_t* watch_page;
- mtr_t mtr;
- ulint fold;
- ibool lru = FALSE;
- void* data;
- buf_pool_t* buf_pool = buf_pool_get(space, offset);
-
- ut_ad(buf_pool);
-
- *err = DB_SUCCESS;
-
- if (mode == BUF_READ_IBUF_PAGES_ONLY) {
- /* It is a read-ahead within an ibuf routine */
-
- ut_ad(!ibuf_bitmap_page(zip_size, offset));
-
- ibuf_mtr_start(&mtr);
-
- if (!recv_no_ibuf_operations
- && !ibuf_page(space, zip_size, offset, &mtr)) {
-
- ibuf_mtr_commit(&mtr);
-
- return(NULL);
- }
- } else {
- ut_ad(mode == BUF_READ_ANY_PAGE);
- }
-
- if (zip_size && UNIV_LIKELY(!unzip)
- && UNIV_LIKELY(!recv_recovery_is_on())) {
- block = NULL;
- } else {
- block = buf_LRU_get_free_block(buf_pool);
- ut_ad(block);
- ut_ad(buf_pool_from_block(block) == buf_pool);
- }
-
- fold = buf_page_address_fold(space, offset);
-
- buf_pool_mutex_enter(buf_pool);
-
- watch_page = buf_page_hash_get_low(buf_pool, space, offset, fold);
- if (watch_page && !buf_pool_watch_is_sentinel(buf_pool, watch_page)) {
- /* The page is already in the buffer pool. */
- watch_page = NULL;
-err_exit:
- if (block) {
- mutex_enter(&block->mutex);
- buf_LRU_block_free_non_file_page(block);
- mutex_exit(&block->mutex);
- }
-
- bpage = NULL;
- goto func_exit;
- }
-
- if (fil_tablespace_deleted_or_being_deleted_in_mem(
- space, tablespace_version)) {
- /* The page belongs to a space which has been
- deleted or is being deleted. */
- *err = DB_TABLESPACE_DELETED;
-
- goto err_exit;
- }
-
- if (block) {
- bpage = &block->page;
- mutex_enter(&block->mutex);
-
- ut_ad(buf_pool_from_bpage(bpage) == buf_pool);
-
- buf_page_init(buf_pool, space, offset, fold, block);
-
- /* The block must be put to the LRU list, to the old blocks */
- buf_LRU_add_block(bpage, TRUE/* to old blocks */);
-
- /* We set a pass-type x-lock on the frame because then
- the same thread which called for the read operation
- (and is running now at this point of code) can wait
- for the read to complete by waiting for the x-lock on
- the frame; if the x-lock were recursive, the same
- thread would illegally get the x-lock before the page
- read is completed. The x-lock is cleared by the
- io-handler thread. */
-
- rw_lock_x_lock_gen(&block->lock, BUF_IO_READ);
- buf_page_set_io_fix(bpage, BUF_IO_READ);
-
- if (UNIV_UNLIKELY(zip_size)) {
- page_zip_set_size(&block->page.zip, zip_size);
-
- /* buf_pool->mutex may be released and
- reacquired by buf_buddy_alloc(). Thus, we
- must release block->mutex in order not to
- break the latching order in the reacquisition
- of buf_pool->mutex. We also must defer this
- operation until after the block descriptor has
- been added to buf_pool->LRU and
- buf_pool->page_hash. */
- mutex_exit(&block->mutex);
- data = buf_buddy_alloc(buf_pool, zip_size, &lru);
- mutex_enter(&block->mutex);
- block->page.zip.data = data;
-
- /* To maintain the invariant
- block->in_unzip_LRU_list
- == buf_page_belongs_to_unzip_LRU(&block->page)
- we have to add this block to unzip_LRU
- after block->page.zip.data is set. */
- ut_ad(buf_page_belongs_to_unzip_LRU(&block->page));
- buf_unzip_LRU_add_block(block, TRUE);
- }
-
- mutex_exit(&block->mutex);
- } else {
- /* The compressed page must be allocated before the
- control block (bpage), in order to avoid the
- invocation of buf_buddy_relocate_block() on
- uninitialized data. */
- data = buf_buddy_alloc(buf_pool, zip_size, &lru);
-
- /* If buf_buddy_alloc() allocated storage from the LRU list,
- it released and reacquired buf_pool->mutex. Thus, we must
- check the page_hash again, as it may have been modified. */
- if (UNIV_UNLIKELY(lru)) {
-
- watch_page = buf_page_hash_get_low(
- buf_pool, space, offset, fold);
-
- if (watch_page
- && !buf_pool_watch_is_sentinel(buf_pool,
- watch_page)) {
-
- /* The block was added by some other thread. */
- watch_page = NULL;
- buf_buddy_free(buf_pool, data, zip_size);
-
- bpage = NULL;
- goto func_exit;
- }
- }
-
- bpage = buf_page_alloc_descriptor();
-
- /* Initialize the buf_pool pointer. */
- bpage->buf_pool_index = buf_pool_index(buf_pool);
-
- page_zip_des_init(&bpage->zip);
- page_zip_set_size(&bpage->zip, zip_size);
- bpage->zip.data = data;
-
- mutex_enter(&buf_pool->zip_mutex);
- UNIV_MEM_DESC(bpage->zip.data,
- page_zip_get_size(&bpage->zip), bpage);
-
- buf_page_init_low(bpage);
-
- bpage->state = BUF_BLOCK_ZIP_PAGE;
- bpage->space = space;
- bpage->offset = offset;
-
-#ifdef UNIV_DEBUG
- bpage->in_page_hash = FALSE;
- bpage->in_zip_hash = FALSE;
- bpage->in_flush_list = FALSE;
- bpage->in_free_list = FALSE;
- bpage->in_LRU_list = FALSE;
-#endif /* UNIV_DEBUG */
-
- ut_d(bpage->in_page_hash = TRUE);
-
- if (UNIV_LIKELY_NULL(watch_page)) {
- /* Preserve the reference count. */
- ulint buf_fix_count = watch_page->buf_fix_count;
- ut_a(buf_fix_count > 0);
- bpage->buf_fix_count += buf_fix_count;
- ut_ad(buf_pool_watch_is_sentinel(buf_pool, watch_page));
- buf_pool_watch_remove(buf_pool, fold, watch_page);
- }
-
- HASH_INSERT(buf_page_t, hash, buf_pool->page_hash, fold,
- bpage);
-
- /* The block must be put to the LRU list, to the old blocks */
- buf_LRU_add_block(bpage, TRUE/* to old blocks */);
-#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
- buf_LRU_insert_zip_clean(bpage);
-#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
-
- buf_page_set_io_fix(bpage, BUF_IO_READ);
-
- mutex_exit(&buf_pool->zip_mutex);
- }
-
- buf_pool->n_pend_reads++;
-func_exit:
- buf_pool_mutex_exit(buf_pool);
-
- if (mode == BUF_READ_IBUF_PAGES_ONLY) {
-
- ibuf_mtr_commit(&mtr);
- }
-
- ut_ad(!bpage || buf_page_in_file(bpage));
- return(bpage);
-}
-
-/********************************************************************//**
-Initializes a page to the buffer buf_pool. The page is usually not read
-from a file even if it cannot be found in the buffer buf_pool. This is one
-of the functions which perform to a block a state transition NOT_USED =>
-FILE_PAGE (the other is buf_page_get_gen).
-@return pointer to the block, page bufferfixed */
-UNIV_INTERN
-buf_block_t*
-buf_page_create(
-/*============*/
- ulint space, /*!< in: space id */
- ulint offset, /*!< in: offset of the page within space in units of
- a page */
- ulint zip_size,/*!< in: compressed page size, or 0 */
- mtr_t* mtr) /*!< in: mini-transaction handle */
-{
- buf_frame_t* frame;
- buf_block_t* block;
- ulint fold;
- buf_block_t* free_block = NULL;
- ulint time_ms = ut_time_ms();
- buf_pool_t* buf_pool = buf_pool_get(space, offset);
-
- ut_ad(mtr);
- ut_ad(mtr->state == MTR_ACTIVE);
- ut_ad(space || !zip_size);
-
- free_block = buf_LRU_get_free_block(buf_pool);
-
- fold = buf_page_address_fold(space, offset);
-
- buf_pool_mutex_enter(buf_pool);
-
- block = (buf_block_t*) buf_page_hash_get_low(
- buf_pool, space, offset, fold);
-
- if (block
- && buf_page_in_file(&block->page)
- && !buf_pool_watch_is_sentinel(buf_pool, &block->page)) {
-#ifdef UNIV_IBUF_COUNT_DEBUG
- ut_a(ibuf_count_get(space, offset) == 0);
-#endif
-#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
- block->page.file_page_was_freed = FALSE;
-#endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */
-
- /* Page can be found in buf_pool */
- buf_pool_mutex_exit(buf_pool);
-
- buf_block_free(free_block);
-
- return(buf_page_get_with_no_latch(space, zip_size,
- offset, mtr));
- }
-
- /* If we get here, the page was not in buf_pool: init it there */
-
-#ifdef UNIV_DEBUG
- if (buf_debug_prints) {
- fprintf(stderr, "Creating space %lu page %lu to buffer\n",
- (ulong) space, (ulong) offset);
- }
-#endif /* UNIV_DEBUG */
-
- block = free_block;
-
- mutex_enter(&block->mutex);
-
- buf_page_init(buf_pool, space, offset, fold, block);
-
- /* The block must be put to the LRU list */
- buf_LRU_add_block(&block->page, FALSE);
-
- buf_block_buf_fix_inc(block, __FILE__, __LINE__);
- buf_pool->stat.n_pages_created++;
-
- if (zip_size) {
- void* data;
- ibool lru;
-
- /* Prevent race conditions during buf_buddy_alloc(),
- which may release and reacquire buf_pool->mutex,
- by IO-fixing and X-latching the block. */
-
- buf_page_set_io_fix(&block->page, BUF_IO_READ);
- rw_lock_x_lock(&block->lock);
-
- page_zip_set_size(&block->page.zip, zip_size);
- mutex_exit(&block->mutex);
- /* buf_pool->mutex may be released and reacquired by
- buf_buddy_alloc(). Thus, we must release block->mutex
- in order not to break the latching order in
- the reacquisition of buf_pool->mutex. We also must
- defer this operation until after the block descriptor
- has been added to buf_pool->LRU and buf_pool->page_hash. */
- data = buf_buddy_alloc(buf_pool, zip_size, &lru);
- mutex_enter(&block->mutex);
- block->page.zip.data = data;
-
- /* To maintain the invariant
- block->in_unzip_LRU_list
- == buf_page_belongs_to_unzip_LRU(&block->page)
- we have to add this block to unzip_LRU after
- block->page.zip.data is set. */
- ut_ad(buf_page_belongs_to_unzip_LRU(&block->page));
- buf_unzip_LRU_add_block(block, FALSE);
-
- buf_page_set_io_fix(&block->page, BUF_IO_NONE);
- rw_lock_x_unlock(&block->lock);
- }
-
- buf_page_set_accessed(&block->page, time_ms);
-
- buf_pool_mutex_exit(buf_pool);
-
- mtr_memo_push(mtr, block, MTR_MEMO_BUF_FIX);
-
- mutex_exit(&block->mutex);
-
- /* Delete possible entries for the page from the insert buffer:
- such can exist if the page belonged to an index which was dropped */
-
- ibuf_merge_or_delete_for_page(NULL, space, offset, zip_size, TRUE);
-
- /* Flush pages from the end of the LRU list if necessary */
- buf_flush_free_margin(buf_pool);
-
- frame = block->frame;
-
- memset(frame + FIL_PAGE_PREV, 0xff, 4);
- memset(frame + FIL_PAGE_NEXT, 0xff, 4);
- mach_write_to_2(frame + FIL_PAGE_TYPE, FIL_PAGE_TYPE_ALLOCATED);
-
- /* Reset to zero the file flush lsn field in the page; if the first
- page of an ibdata file is 'created' in this function into the buffer
- pool then we lose the original contents of the file flush lsn stamp.
- Then InnoDB could in a crash recovery print a big, false, corruption
- warning if the stamp contains an lsn bigger than the ib_logfile lsn. */
-
- memset(frame + FIL_PAGE_FILE_FLUSH_LSN, 0, 8);
-
-#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
- ut_a(++buf_dbg_counter % 357 || buf_validate());
-#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
-#ifdef UNIV_IBUF_COUNT_DEBUG
- ut_a(ibuf_count_get(buf_block_get_space(block),
- buf_block_get_page_no(block)) == 0);
-#endif
- return(block);
-}
-
-/********************************************************************//**
-Mark a table with the specified space pointed by bpage->space corrupted.
-Also remove the bpage from LRU list.
-@return TRUE if successful */
-static
-ibool
-buf_mark_space_corrupt(
-/*===================*/
- buf_page_t* bpage) /*!< in: pointer to the block in question */
-{
- buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
- const ibool uncompressed = (buf_page_get_state(bpage)
- == BUF_BLOCK_FILE_PAGE);
- ulint space = bpage->space;
- ibool ret = TRUE;
-
- /* First unfix and release lock on the bpage */
- buf_pool_mutex_enter(buf_pool);
- mutex_enter(buf_page_get_mutex(bpage));
- ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_READ);
- ut_ad(bpage->buf_fix_count == 0);
-
- /* Set BUF_IO_NONE before we remove the block from LRU list */
- buf_page_set_io_fix(bpage, BUF_IO_NONE);
-
- if (uncompressed) {
- rw_lock_x_unlock_gen(
- &((buf_block_t*) bpage)->lock,
- BUF_IO_READ);
- }
-
- /* Find the table with specified space id, and mark it corrupted */
- if (dict_set_corrupted_by_space(space)) {
- buf_LRU_free_one_page(bpage);
- } else {
- ret = FALSE;
- }
-
- ut_ad(buf_pool->n_pend_reads > 0);
- buf_pool->n_pend_reads--;
-
- mutex_exit(buf_page_get_mutex(bpage));
- buf_pool_mutex_exit(buf_pool);
-
- return(ret);
-}
-
-/********************************************************************//**
-Completes an asynchronous read or write request of a file page to or from
-the buffer pool. */
-UNIV_INTERN
-void
-buf_page_io_complete(
-/*=================*/
- buf_page_t* bpage) /*!< in: pointer to the block in question */
-{
- enum buf_io_fix io_type;
- buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
- const ibool uncompressed = (buf_page_get_state(bpage)
- == BUF_BLOCK_FILE_PAGE);
-
- ut_a(buf_page_in_file(bpage));
-
- /* We do not need protect io_fix here by mutex to read
- it because this is the only function where we can change the value
- from BUF_IO_READ or BUF_IO_WRITE to some other value, and our code
- ensures that this is the only thread that handles the i/o for this
- block. */
-
- io_type = buf_page_get_io_fix(bpage);
- ut_ad(io_type == BUF_IO_READ || io_type == BUF_IO_WRITE);
-
- if (io_type == BUF_IO_READ) {
- ulint read_page_no;
- ulint read_space_id;
- byte* frame;
-
- if (buf_page_get_zip_size(bpage)) {
- frame = bpage->zip.data;
- buf_pool->n_pend_unzip++;
- if (uncompressed
- && !buf_zip_decompress((buf_block_t*) bpage,
- FALSE)) {
-
- buf_pool->n_pend_unzip--;
- goto corrupt;
- }
- buf_pool->n_pend_unzip--;
- } else {
- ut_a(uncompressed);
- frame = ((buf_block_t*) bpage)->frame;
- }
-
- /* If this page is not uninitialized and not in the
- doublewrite buffer, then the page number and space id
- should be the same as in block. */
- read_page_no = mach_read_from_4(frame + FIL_PAGE_OFFSET);
- read_space_id = mach_read_from_4(
- frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
-
- if (bpage->space == TRX_SYS_SPACE
- && trx_doublewrite_page_inside(bpage->offset)) {
-
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Error: reading page %lu\n"
- "InnoDB: which is in the"
- " doublewrite buffer!\n",
- (ulong) bpage->offset);
- } else if (!read_space_id && !read_page_no) {
- /* This is likely an uninitialized page. */
- } else if ((bpage->space
- && bpage->space != read_space_id)
- || bpage->offset != read_page_no) {
- /* We did not compare space_id to read_space_id
- if bpage->space == 0, because the field on the
- page may contain garbage in MySQL < 4.1.1,
- which only supported bpage->space == 0. */
-
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Error: space id and page n:o"
- " stored in the page\n"
- "InnoDB: read in are %lu:%lu,"
- " should be %lu:%lu!\n",
- (ulong) read_space_id, (ulong) read_page_no,
- (ulong) bpage->space,
- (ulong) bpage->offset);
- }
-
- /* From version 3.23.38 up we store the page checksum
- to the 4 first bytes of the page end lsn field */
-
- if (buf_page_is_corrupted(frame,
- buf_page_get_zip_size(bpage))) {
-corrupt:
- fprintf(stderr,
- "InnoDB: Database page corruption on disk"
- " or a failed\n"
- "InnoDB: file read of page %lu.\n"
- "InnoDB: You may have to recover"
- " from a backup.\n",
- (ulong) bpage->offset);
- buf_page_print(frame, buf_page_get_zip_size(bpage),
- BUF_PAGE_PRINT_NO_CRASH);
- fprintf(stderr,
- "InnoDB: Database page corruption on disk"
- " or a failed\n"
- "InnoDB: file read of page %lu.\n"
- "InnoDB: You may have to recover"
- " from a backup.\n",
- (ulong) bpage->offset);
- fputs("InnoDB: It is also possible that"
- " your operating\n"
- "InnoDB: system has corrupted its"
- " own file cache\n"
- "InnoDB: and rebooting your computer"
- " removes the\n"
- "InnoDB: error.\n"
- "InnoDB: If the corrupt page is an index page\n"
- "InnoDB: you can also try to"
- " fix the corruption\n"
- "InnoDB: by dumping, dropping,"
- " and reimporting\n"
- "InnoDB: the corrupt table."
- " You can use CHECK\n"
- "InnoDB: TABLE to scan your"
- " table for corruption.\n"
- "InnoDB: See also "
- REFMAN "forcing-innodb-recovery.html\n"
- "InnoDB: about forcing recovery.\n", stderr);
-
- if (srv_force_recovery < SRV_FORCE_IGNORE_CORRUPT) {
- /* If page space id is larger than TRX_SYS_SPACE
- (0), we will attempt to mark the corresponding
- table as corrupted instead of crashing server */
- if (bpage->space > TRX_SYS_SPACE
- && buf_mark_space_corrupt(bpage)) {
- return;
- } else {
- fputs("InnoDB: Ending processing"
- " because of"
- " a corrupt database page.\n",
- stderr);
- ut_error;
- }
- }
- }
-
- if (recv_recovery_is_on()) {
- /* Pages must be uncompressed for crash recovery. */
- ut_a(uncompressed);
- recv_recover_page(TRUE, (buf_block_t*) bpage);
- }
-
- if (uncompressed && !recv_no_ibuf_operations) {
- ibuf_merge_or_delete_for_page(
- (buf_block_t*) bpage, bpage->space,
- bpage->offset, buf_page_get_zip_size(bpage),
- TRUE);
- }
- }
-
- buf_pool_mutex_enter(buf_pool);
- mutex_enter(buf_page_get_mutex(bpage));
-
-#ifdef UNIV_IBUF_COUNT_DEBUG
- if (io_type == BUF_IO_WRITE || uncompressed) {
- /* For BUF_IO_READ of compressed-only blocks, the
- buffered operations will be merged by buf_page_get_gen()
- after the block has been uncompressed. */
- ut_a(ibuf_count_get(bpage->space, bpage->offset) == 0);
- }
-#endif
- /* Because this thread which does the unlocking is not the same that
- did the locking, we use a pass value != 0 in unlock, which simply
- removes the newest lock debug record, without checking the thread
- id. */
-
- buf_page_set_io_fix(bpage, BUF_IO_NONE);
-
- switch (io_type) {
- case BUF_IO_READ:
- /* NOTE that the call to ibuf may have moved the ownership of
- the x-latch to this OS thread: do not let this confuse you in
- debugging! */
-
- ut_ad(buf_pool->n_pend_reads > 0);
- buf_pool->n_pend_reads--;
- buf_pool->stat.n_pages_read++;
-
- if (uncompressed) {
- rw_lock_x_unlock_gen(&((buf_block_t*) bpage)->lock,
- BUF_IO_READ);
- }
-
- break;
-
- case BUF_IO_WRITE:
- /* Write means a flush operation: call the completion
- routine in the flush system */
-
- buf_flush_write_complete(bpage);
-
- if (uncompressed) {
- rw_lock_s_unlock_gen(&((buf_block_t*) bpage)->lock,
- BUF_IO_WRITE);
- }
-
- buf_pool->stat.n_pages_written++;
-
- break;
-
- default:
- ut_error;
- }
-
-#ifdef UNIV_DEBUG
- if (buf_debug_prints) {
- fprintf(stderr, "Has %s page space %lu page no %lu\n",
- io_type == BUF_IO_READ ? "read" : "written",
- (ulong) buf_page_get_space(bpage),
- (ulong) buf_page_get_page_no(bpage));
- }
-#endif /* UNIV_DEBUG */
-
- mutex_exit(buf_page_get_mutex(bpage));
- buf_pool_mutex_exit(buf_pool);
-}
-
-/*********************************************************************//**
-Asserts that all file pages in the buffer are in a replaceable state.
-@return TRUE */
-static
-ibool
-buf_all_freed_instance(
-/*===================*/
- buf_pool_t* buf_pool) /*!< in: buffer pool instancce */
-{
- ulint i;
- buf_chunk_t* chunk;
-
- ut_ad(buf_pool);
-
- buf_pool_mutex_enter(buf_pool);
-
- chunk = buf_pool->chunks;
-
- for (i = buf_pool->n_chunks; i--; chunk++) {
-
- const buf_block_t* block = buf_chunk_not_freed(chunk);
-
- if (UNIV_LIKELY_NULL(block)) {
- fprintf(stderr,
- "Page %lu %lu still fixed or dirty\n",
- (ulong) block->page.space,
- (ulong) block->page.offset);
- ut_error;
- }
- }
-
- buf_pool_mutex_exit(buf_pool);
-
- return(TRUE);
-}
-
-/*********************************************************************//**
-Invalidates file pages in one buffer pool instance */
-static
-void
-buf_pool_invalidate_instance(
-/*=========================*/
- buf_pool_t* buf_pool) /*!< in: buffer pool instance */
-{
- ibool freed;
- enum buf_flush i;
-
- buf_pool_mutex_enter(buf_pool);
-
- for (i = BUF_FLUSH_LRU; i < BUF_FLUSH_N_TYPES; i++) {
-
- /* As this function is called during startup and
- during redo application phase during recovery, InnoDB
- is single threaded (apart from IO helper threads) at
- this stage. No new write batch can be in intialization
- stage at this point. */
- ut_ad(buf_pool->init_flush[i] == FALSE);
-
- /* However, it is possible that a write batch that has
- been posted earlier is still not complete. For buffer
- pool invalidation to proceed we must ensure there is NO
- write activity happening. */
- if (buf_pool->n_flush[i] > 0) {
- buf_pool_mutex_exit(buf_pool);
- buf_flush_wait_batch_end(buf_pool, i);
- buf_pool_mutex_enter(buf_pool);
- }
- }
-
- buf_pool_mutex_exit(buf_pool);
-
- ut_ad(buf_all_freed_instance(buf_pool));
-
- freed = TRUE;
-
- while (freed) {
- freed = buf_LRU_search_and_free_block(buf_pool, 100);
- }
-
- buf_pool_mutex_enter(buf_pool);
-
- ut_ad(UT_LIST_GET_LEN(buf_pool->LRU) == 0);
- ut_ad(UT_LIST_GET_LEN(buf_pool->unzip_LRU) == 0);
-
- buf_pool->freed_page_clock = 0;
- buf_pool->LRU_old = NULL;
- buf_pool->LRU_old_len = 0;
- buf_pool->LRU_flush_ended = 0;
-
- memset(&buf_pool->stat, 0x00, sizeof(buf_pool->stat));
- buf_refresh_io_stats(buf_pool);
-
- buf_pool_mutex_exit(buf_pool);
-}
-
-/*********************************************************************//**
-Invalidates the file pages in the buffer pool when an archive recovery is
-completed. All the file pages buffered must be in a replaceable state when
-this function is called: not latched and not modified. */
-UNIV_INTERN
-void
-buf_pool_invalidate(void)
-/*=====================*/
-{
- ulint i;
-
- for (i = 0; i < srv_buf_pool_instances; i++) {
- buf_pool_invalidate_instance(buf_pool_from_array(i));
- }
-}
-
-#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
-/*********************************************************************//**
-Validates data in one buffer pool instance
-@return TRUE */
-static
-ibool
-buf_pool_validate_instance(
-/*=======================*/
- buf_pool_t* buf_pool) /*!< in: buffer pool instance */
-{
- buf_page_t* b;
- buf_chunk_t* chunk;
- ulint i;
- ulint n_single_flush = 0;
- ulint n_lru_flush = 0;
- ulint n_list_flush = 0;
- ulint n_lru = 0;
- ulint n_flush = 0;
- ulint n_free = 0;
- ulint n_zip = 0;
-
- ut_ad(buf_pool);
-
- buf_pool_mutex_enter(buf_pool);
-
- chunk = buf_pool->chunks;
-
- /* Check the uncompressed blocks. */
-
- for (i = buf_pool->n_chunks; i--; chunk++) {
-
- ulint j;
- buf_block_t* block = chunk->blocks;
-
- for (j = chunk->size; j--; block++) {
-
- mutex_enter(&block->mutex);
-
- switch (buf_block_get_state(block)) {
- case BUF_BLOCK_ZIP_FREE:
- case BUF_BLOCK_ZIP_PAGE:
- case BUF_BLOCK_ZIP_DIRTY:
- /* These should only occur on
- zip_clean, zip_free[], or flush_list. */
- ut_error;
- break;
-
- case BUF_BLOCK_FILE_PAGE:
- ut_a(buf_page_hash_get(buf_pool,
- buf_block_get_space(
- block),
- buf_block_get_page_no(
- block))
- == &block->page);
-
-#ifdef UNIV_IBUF_COUNT_DEBUG
- ut_a(buf_page_get_io_fix(&block->page)
- == BUF_IO_READ
- || !ibuf_count_get(buf_block_get_space(
- block),
- buf_block_get_page_no(
- block)));
-#endif
- switch (buf_page_get_io_fix(&block->page)) {
- case BUF_IO_NONE:
- break;
-
- case BUF_IO_WRITE:
- switch (buf_page_get_flush_type(
- &block->page)) {
- case BUF_FLUSH_LRU:
- n_lru_flush++;
- ut_a(rw_lock_is_locked(
- &block->lock,
- RW_LOCK_SHARED));
- break;
- case BUF_FLUSH_LIST:
- n_list_flush++;
- break;
- case BUF_FLUSH_SINGLE_PAGE:
- n_single_flush++;
- break;
- default:
- ut_error;
- }
-
- break;
-
- case BUF_IO_READ:
-
- ut_a(rw_lock_is_locked(&block->lock,
- RW_LOCK_EX));
- break;
-
- case BUF_IO_PIN:
- break;
- }
-
- n_lru++;
- break;
-
- case BUF_BLOCK_NOT_USED:
- n_free++;
- break;
-
- case BUF_BLOCK_READY_FOR_USE:
- case BUF_BLOCK_MEMORY:
- case BUF_BLOCK_REMOVE_HASH:
- /* do nothing */
- break;
- }
-
- mutex_exit(&block->mutex);
- }
- }
-
- mutex_enter(&buf_pool->zip_mutex);
-
- /* Check clean compressed-only blocks. */
-
- for (b = UT_LIST_GET_FIRST(buf_pool->zip_clean); b;
- b = UT_LIST_GET_NEXT(list, b)) {
- ut_a(buf_page_get_state(b) == BUF_BLOCK_ZIP_PAGE);
- switch (buf_page_get_io_fix(b)) {
- case BUF_IO_NONE:
- case BUF_IO_PIN:
- /* All clean blocks should be I/O-unfixed. */
- break;
- case BUF_IO_READ:
- /* In buf_LRU_free_block(), we temporarily set
- b->io_fix = BUF_IO_READ for a newly allocated
- control block in order to prevent
- buf_page_get_gen() from decompressing the block. */
- break;
- default:
- ut_error;
- break;
- }
-
- /* It is OK to read oldest_modification here because
- we have acquired buf_pool->zip_mutex above which acts
- as the 'block->mutex' for these bpages. */
- ut_a(!b->oldest_modification);
- ut_a(buf_page_hash_get(buf_pool, b->space, b->offset) == b);
-
- n_lru++;
- n_zip++;
- }
-
- /* Check dirty blocks. */
-
- buf_flush_list_mutex_enter(buf_pool);
- for (b = UT_LIST_GET_FIRST(buf_pool->flush_list); b;
- b = UT_LIST_GET_NEXT(list, b)) {
- ut_ad(b->in_flush_list);
- ut_a(b->oldest_modification);
- n_flush++;
-
- switch (buf_page_get_state(b)) {
- case BUF_BLOCK_ZIP_DIRTY:
- n_lru++;
- n_zip++;
- switch (buf_page_get_io_fix(b)) {
- case BUF_IO_NONE:
- case BUF_IO_READ:
- case BUF_IO_PIN:
- break;
- case BUF_IO_WRITE:
- switch (buf_page_get_flush_type(b)) {
- case BUF_FLUSH_LRU:
- n_lru_flush++;
- break;
- case BUF_FLUSH_LIST:
- n_list_flush++;
- break;
- case BUF_FLUSH_SINGLE_PAGE:
- n_single_flush++;
- break;
- default:
- ut_error;
- }
- break;
- }
- break;
- case BUF_BLOCK_FILE_PAGE:
- /* uncompressed page */
- break;
- case BUF_BLOCK_ZIP_FREE:
- case BUF_BLOCK_ZIP_PAGE:
- case BUF_BLOCK_NOT_USED:
- case BUF_BLOCK_READY_FOR_USE:
- case BUF_BLOCK_MEMORY:
- case BUF_BLOCK_REMOVE_HASH:
- ut_error;
- break;
- }
- ut_a(buf_page_hash_get(buf_pool, b->space, b->offset) == b);
- }
-
- ut_a(UT_LIST_GET_LEN(buf_pool->flush_list) == n_flush);
-
- buf_flush_list_mutex_exit(buf_pool);
-
- mutex_exit(&buf_pool->zip_mutex);
-
- if (n_lru + n_free > buf_pool->curr_size + n_zip) {
- fprintf(stderr, "n LRU %lu, n free %lu, pool %lu zip %lu\n",
- (ulong) n_lru, (ulong) n_free,
- (ulong) buf_pool->curr_size, (ulong) n_zip);
- ut_error;
- }
-
- ut_a(UT_LIST_GET_LEN(buf_pool->LRU) == n_lru);
- if (UT_LIST_GET_LEN(buf_pool->free) != n_free) {
- fprintf(stderr, "Free list len %lu, free blocks %lu\n",
- (ulong) UT_LIST_GET_LEN(buf_pool->free),
- (ulong) n_free);
- ut_error;
- }
-
- ut_a(buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE] == n_single_flush);
- ut_a(buf_pool->n_flush[BUF_FLUSH_LIST] == n_list_flush);
- ut_a(buf_pool->n_flush[BUF_FLUSH_LRU] == n_lru_flush);
-
- buf_pool_mutex_exit(buf_pool);
-
- ut_a(buf_LRU_validate());
- ut_a(buf_flush_validate(buf_pool));
-
- return(TRUE);
-}
-
-/*********************************************************************//**
-Validates the buffer buf_pool data structure.
-@return TRUE */
-UNIV_INTERN
-ibool
-buf_validate(void)
-/*==============*/
-{
- ulint i;
-
- for (i = 0; i < srv_buf_pool_instances; i++) {
- buf_pool_t* buf_pool;
-
- buf_pool = buf_pool_from_array(i);
-
- buf_pool_validate_instance(buf_pool);
- }
- return(TRUE);
-}
-
-#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
-
-#if defined UNIV_DEBUG_PRINT || defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
-/*********************************************************************//**
-Prints info of the buffer buf_pool data structure for one instance. */
-static
-void
-buf_print_instance(
-/*===============*/
- buf_pool_t* buf_pool)
-{
- index_id_t* index_ids;
- ulint* counts;
- ulint size;
- ulint i;
- ulint j;
- index_id_t id;
- ulint n_found;
- buf_chunk_t* chunk;
- dict_index_t* index;
-
- ut_ad(buf_pool);
-
- size = buf_pool->curr_size;
-
- index_ids = mem_alloc(size * sizeof *index_ids);
- counts = mem_alloc(sizeof(ulint) * size);
-
- buf_pool_mutex_enter(buf_pool);
- buf_flush_list_mutex_enter(buf_pool);
-
- fprintf(stderr,
- "buf_pool size %lu\n"
- "database pages %lu\n"
- "free pages %lu\n"
- "modified database pages %lu\n"
- "n pending decompressions %lu\n"
- "n pending reads %lu\n"
- "n pending flush LRU %lu list %lu single page %lu\n"
- "pages made young %lu, not young %lu\n"
- "pages read %lu, created %lu, written %lu\n",
- (ulong) size,
- (ulong) UT_LIST_GET_LEN(buf_pool->LRU),
- (ulong) UT_LIST_GET_LEN(buf_pool->free),
- (ulong) UT_LIST_GET_LEN(buf_pool->flush_list),
- (ulong) buf_pool->n_pend_unzip,
- (ulong) buf_pool->n_pend_reads,
- (ulong) buf_pool->n_flush[BUF_FLUSH_LRU],
- (ulong) buf_pool->n_flush[BUF_FLUSH_LIST],
- (ulong) buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE],
- (ulong) buf_pool->stat.n_pages_made_young,
- (ulong) buf_pool->stat.n_pages_not_made_young,
- (ulong) buf_pool->stat.n_pages_read,
- (ulong) buf_pool->stat.n_pages_created,
- (ulong) buf_pool->stat.n_pages_written);
-
- buf_flush_list_mutex_exit(buf_pool);
-
- /* Count the number of blocks belonging to each index in the buffer */
-
- n_found = 0;
-
- chunk = buf_pool->chunks;
-
- for (i = buf_pool->n_chunks; i--; chunk++) {
- buf_block_t* block = chunk->blocks;
- ulint n_blocks = chunk->size;
-
- for (; n_blocks--; block++) {
- const buf_frame_t* frame = block->frame;
-
- if (fil_page_get_type(frame) == FIL_PAGE_INDEX) {
-
- id = btr_page_get_index_id(frame);
-
- /* Look for the id in the index_ids array */
- j = 0;
-
- while (j < n_found) {
-
- if (index_ids[j] == id) {
- counts[j]++;
-
- break;
- }
- j++;
- }
-
- if (j == n_found) {
- n_found++;
- index_ids[j] = id;
- counts[j] = 1;
- }
- }
- }
- }
-
- buf_pool_mutex_exit(buf_pool);
-
- for (i = 0; i < n_found; i++) {
- index = dict_index_get_if_in_cache(index_ids[i]);
-
- fprintf(stderr,
- "Block count for index %llu in buffer is about %lu",
- (ullint) index_ids[i],
- (ulong) counts[i]);
-
- if (index) {
- putc(' ', stderr);
- dict_index_name_print(stderr, NULL, index);
- }
-
- putc('\n', stderr);
- }
-
- mem_free(index_ids);
- mem_free(counts);
-
- ut_a(buf_pool_validate_instance(buf_pool));
-}
-
-/*********************************************************************//**
-Prints info of the buffer buf_pool data structure. */
-UNIV_INTERN
-void
-buf_print(void)
-/*===========*/
-{
- ulint i;
-
- for (i = 0; i < srv_buf_pool_instances; i++) {
- buf_pool_t* buf_pool;
-
- buf_pool = buf_pool_from_array(i);
- buf_print_instance(buf_pool);
- }
-}
-#endif /* UNIV_DEBUG_PRINT || UNIV_DEBUG || UNIV_BUF_DEBUG */
-
-#ifdef UNIV_DEBUG
-/*********************************************************************//**
-Returns the number of latched pages in the buffer pool.
-@return number of latched pages */
-UNIV_INTERN
-ulint
-buf_get_latched_pages_number_instance(
-/*==================================*/
- buf_pool_t* buf_pool) /*!< in: buffer pool instance */
-{
- buf_page_t* b;
- ulint i;
- buf_chunk_t* chunk;
- ulint fixed_pages_number = 0;
-
- buf_pool_mutex_enter(buf_pool);
-
- chunk = buf_pool->chunks;
-
- for (i = buf_pool->n_chunks; i--; chunk++) {
- buf_block_t* block;
- ulint j;
-
- block = chunk->blocks;
-
- for (j = chunk->size; j--; block++) {
- if (buf_block_get_state(block)
- != BUF_BLOCK_FILE_PAGE) {
-
- continue;
- }
-
- mutex_enter(&block->mutex);
-
- if (block->page.buf_fix_count != 0
- || buf_page_get_io_fix(&block->page)
- != BUF_IO_NONE) {
- fixed_pages_number++;
- }
-
- mutex_exit(&block->mutex);
- }
- }
-
- mutex_enter(&buf_pool->zip_mutex);
-
- /* Traverse the lists of clean and dirty compressed-only blocks. */
-
- for (b = UT_LIST_GET_FIRST(buf_pool->zip_clean); b;
- b = UT_LIST_GET_NEXT(list, b)) {
- ut_a(buf_page_get_state(b) == BUF_BLOCK_ZIP_PAGE);
- ut_a(buf_page_get_io_fix(b) != BUF_IO_WRITE);
-
- if (b->buf_fix_count != 0
- || buf_page_get_io_fix(b) != BUF_IO_NONE) {
- fixed_pages_number++;
- }
- }
-
- buf_flush_list_mutex_enter(buf_pool);
- for (b = UT_LIST_GET_FIRST(buf_pool->flush_list); b;
- b = UT_LIST_GET_NEXT(list, b)) {
- ut_ad(b->in_flush_list);
-
- switch (buf_page_get_state(b)) {
- case BUF_BLOCK_ZIP_DIRTY:
- if (b->buf_fix_count != 0
- || buf_page_get_io_fix(b) != BUF_IO_NONE) {
- fixed_pages_number++;
- }
- break;
- case BUF_BLOCK_FILE_PAGE:
- /* uncompressed page */
- break;
- case BUF_BLOCK_ZIP_FREE:
- case BUF_BLOCK_ZIP_PAGE:
- case BUF_BLOCK_NOT_USED:
- case BUF_BLOCK_READY_FOR_USE:
- case BUF_BLOCK_MEMORY:
- case BUF_BLOCK_REMOVE_HASH:
- ut_error;
- break;
- }
- }
-
- buf_flush_list_mutex_exit(buf_pool);
- mutex_exit(&buf_pool->zip_mutex);
- buf_pool_mutex_exit(buf_pool);
-
- return(fixed_pages_number);
-}
-
-/*********************************************************************//**
-Returns the number of latched pages in all the buffer pools.
-@return number of latched pages */
-UNIV_INTERN
-ulint
-buf_get_latched_pages_number(void)
-/*==============================*/
-{
- ulint i;
- ulint total_latched_pages = 0;
-
- for (i = 0; i < srv_buf_pool_instances; i++) {
- buf_pool_t* buf_pool;
-
- buf_pool = buf_pool_from_array(i);
-
- total_latched_pages += buf_get_latched_pages_number_instance(
- buf_pool);
- }
-
- return(total_latched_pages);
-}
-
-#endif /* UNIV_DEBUG */
-
-/*********************************************************************//**
-Returns the number of pending buf pool ios.
-@return number of pending I/O operations */
-UNIV_INTERN
-ulint
-buf_get_n_pending_ios(void)
-/*=======================*/
-{
- ulint i;
- ulint pend_ios = 0;
-
- for (i = 0; i < srv_buf_pool_instances; i++) {
- buf_pool_t* buf_pool;
-
- buf_pool = buf_pool_from_array(i);
-
- pend_ios +=
- buf_pool->n_pend_reads
- + buf_pool->n_flush[BUF_FLUSH_LRU]
- + buf_pool->n_flush[BUF_FLUSH_LIST]
- + buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE];
- }
-
- return(pend_ios);
-}
-
-/*********************************************************************//**
-Returns the ratio in percents of modified pages in the buffer pool /
-database pages in the buffer pool.
-@return modified page percentage ratio */
-UNIV_INTERN
-ulint
-buf_get_modified_ratio_pct(void)
-/*============================*/
-{
- ulint ratio;
- ulint lru_len = 0;
- ulint free_len = 0;
- ulint flush_list_len = 0;
-
- buf_get_total_list_len(&lru_len, &free_len, &flush_list_len);
-
- ratio = (100 * flush_list_len) / (1 + lru_len + free_len);
-
- /* 1 + is there to avoid division by zero */
-
- return(ratio);
-}
-
-/*******************************************************************//**
-Aggregates a pool stats information with the total buffer pool stats */
-static
-void
-buf_stats_aggregate_pool_info(
-/*==========================*/
- buf_pool_info_t* total_info, /*!< in/out: the buffer pool
- info to store aggregated
- result */
- const buf_pool_info_t* pool_info) /*!< in: individual buffer pool
- stats info */
-{
- ut_a(total_info && pool_info);
-
- /* Nothing to copy if total_info is the same as pool_info */
- if (total_info == pool_info) {
- return;
- }
-
- total_info->pool_size += pool_info->pool_size;
- total_info->lru_len += pool_info->lru_len;
- total_info->old_lru_len += pool_info->old_lru_len;
- total_info->free_list_len += pool_info->free_list_len;
- total_info->flush_list_len += pool_info->flush_list_len;
- total_info->n_pend_unzip += pool_info->n_pend_unzip;
- total_info->n_pend_reads += pool_info->n_pend_reads;
- total_info->n_pending_flush_lru += pool_info->n_pending_flush_lru;
- total_info->n_pending_flush_list += pool_info->n_pending_flush_list;
- total_info->n_pending_flush_single_page +=
- pool_info->n_pending_flush_single_page;
- total_info->n_pages_made_young += pool_info->n_pages_made_young;
- total_info->n_pages_not_made_young += pool_info->n_pages_not_made_young;
- total_info->n_pages_read += pool_info->n_pages_read;
- total_info->n_pages_created += pool_info->n_pages_created;
- total_info->n_pages_written += pool_info->n_pages_written;
- total_info->n_page_gets += pool_info->n_page_gets;
- total_info->n_ra_pages_read_rnd += pool_info->n_ra_pages_read_rnd;
- total_info->n_ra_pages_read += pool_info->n_ra_pages_read;
- total_info->n_ra_pages_evicted += pool_info->n_ra_pages_evicted;
- total_info->page_made_young_rate += pool_info->page_made_young_rate;
- total_info->page_not_made_young_rate +=
- pool_info->page_not_made_young_rate;
- total_info->pages_read_rate += pool_info->pages_read_rate;
- total_info->pages_created_rate += pool_info->pages_created_rate;
- total_info->pages_written_rate += pool_info->pages_written_rate;
- total_info->n_page_get_delta += pool_info->n_page_get_delta;
- total_info->page_read_delta += pool_info->page_read_delta;
- total_info->young_making_delta += pool_info->young_making_delta;
- total_info->not_young_making_delta += pool_info->not_young_making_delta;
- total_info->pages_readahead_rnd_rate += pool_info->pages_readahead_rnd_rate;
- total_info->pages_readahead_rate += pool_info->pages_readahead_rate;
- total_info->pages_evicted_rate += pool_info->pages_evicted_rate;
- total_info->unzip_lru_len += pool_info->unzip_lru_len;
- total_info->io_sum += pool_info->io_sum;
- total_info->io_cur += pool_info->io_cur;
- total_info->unzip_sum += pool_info->unzip_sum;
- total_info->unzip_cur += pool_info->unzip_cur;
-}
-/*******************************************************************//**
-Collect buffer pool stats information for a buffer pool. Also
-record aggregated stats if there are more than one buffer pool
-in the server */
-static
-void
-buf_stats_get_pool_info(
-/*====================*/
- buf_pool_t* buf_pool, /*!< in: buffer pool */
- ulint pool_id, /*!< in: buffer pool ID */
- buf_pool_info_t* all_pool_info) /*!< in/out: buffer pool info
- to fill */
-{
- buf_pool_info_t* pool_info;
- time_t current_time;
- double time_elapsed;
-
- /* Find appropriate pool_info to store stats for this buffer pool */
- pool_info = &all_pool_info[pool_id];
-
- buf_pool_mutex_enter(buf_pool);
- buf_flush_list_mutex_enter(buf_pool);
-
- pool_info->pool_unique_id = pool_id;
-
- pool_info->pool_size = buf_pool->curr_size;
-
- pool_info->lru_len = UT_LIST_GET_LEN(buf_pool->LRU);
-
- pool_info->old_lru_len = buf_pool->LRU_old_len;
-
- pool_info->free_list_len = UT_LIST_GET_LEN(buf_pool->free);
-
- pool_info->flush_list_len = UT_LIST_GET_LEN(buf_pool->flush_list);
-
- pool_info->n_pend_unzip = UT_LIST_GET_LEN(buf_pool->unzip_LRU);
-
- pool_info->n_pend_reads = buf_pool->n_pend_reads;
-
- pool_info->n_pending_flush_lru =
- (buf_pool->n_flush[BUF_FLUSH_LRU]
- + buf_pool->init_flush[BUF_FLUSH_LRU]);
-
- pool_info->n_pending_flush_list =
- (buf_pool->n_flush[BUF_FLUSH_LIST]
- + buf_pool->init_flush[BUF_FLUSH_LIST]);
-
- pool_info->n_pending_flush_single_page =
- buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE];
-
- buf_flush_list_mutex_exit(buf_pool);
-
- current_time = time(NULL);
- time_elapsed = 0.001 + difftime(current_time,
- buf_pool->last_printout_time);
-
- pool_info->n_pages_made_young = buf_pool->stat.n_pages_made_young;
-
- pool_info->n_pages_not_made_young =
- buf_pool->stat.n_pages_not_made_young;
-
- pool_info->n_pages_read = buf_pool->stat.n_pages_read;
-
- pool_info->n_pages_created = buf_pool->stat.n_pages_created;
-
- pool_info->n_pages_written = buf_pool->stat.n_pages_written;
-
- pool_info->n_page_gets = buf_pool->stat.n_page_gets;
-
- pool_info->n_ra_pages_read_rnd = buf_pool->stat.n_ra_pages_read_rnd;
- pool_info->n_ra_pages_read = buf_pool->stat.n_ra_pages_read;
-
- pool_info->n_ra_pages_evicted = buf_pool->stat.n_ra_pages_evicted;
-
- pool_info->page_made_young_rate =
- (buf_pool->stat.n_pages_made_young
- - buf_pool->old_stat.n_pages_made_young) / time_elapsed;
-
- pool_info->page_not_made_young_rate =
- (buf_pool->stat.n_pages_not_made_young
- - buf_pool->old_stat.n_pages_not_made_young) / time_elapsed;
-
- pool_info->pages_read_rate =
- (buf_pool->stat.n_pages_read
- - buf_pool->old_stat.n_pages_read) / time_elapsed;
-
- pool_info->pages_created_rate =
- (buf_pool->stat.n_pages_created
- - buf_pool->old_stat.n_pages_created) / time_elapsed;
-
- pool_info->pages_written_rate =
- (buf_pool->stat.n_pages_written
- - buf_pool->old_stat.n_pages_written) / time_elapsed;
-
- pool_info->n_page_get_delta = buf_pool->stat.n_page_gets
- - buf_pool->old_stat.n_page_gets;
-
- if (pool_info->n_page_get_delta) {
- pool_info->page_read_delta = buf_pool->stat.n_pages_read
- - buf_pool->old_stat.n_pages_read;
-
- pool_info->young_making_delta =
- buf_pool->stat.n_pages_made_young
- - buf_pool->old_stat.n_pages_made_young;
-
- pool_info->not_young_making_delta =
- buf_pool->stat.n_pages_not_made_young
- - buf_pool->old_stat.n_pages_not_made_young;
- }
- pool_info->pages_readahead_rnd_rate =
- (buf_pool->stat.n_ra_pages_read_rnd
- - buf_pool->old_stat.n_ra_pages_read_rnd) / time_elapsed;
-
-
- pool_info->pages_readahead_rate =
- (buf_pool->stat.n_ra_pages_read
- - buf_pool->old_stat.n_ra_pages_read) / time_elapsed;
-
- pool_info->pages_evicted_rate =
- (buf_pool->stat.n_ra_pages_evicted
- - buf_pool->old_stat.n_ra_pages_evicted) / time_elapsed;
-
- pool_info->unzip_lru_len = UT_LIST_GET_LEN(buf_pool->unzip_LRU);
-
- pool_info->io_sum = buf_LRU_stat_sum.io;
-
- pool_info->io_cur = buf_LRU_stat_cur.io;
-
- pool_info->unzip_sum = buf_LRU_stat_sum.unzip;
-
- pool_info->unzip_cur = buf_LRU_stat_cur.unzip;
-
- buf_refresh_io_stats(buf_pool);
- buf_pool_mutex_exit(buf_pool);
-}
-
-/*********************************************************************//**
-Prints info of the buffer i/o. */
-UNIV_INTERN
-void
-buf_print_io_instance(
-/*==================*/
- buf_pool_info_t*pool_info, /*!< in: buffer pool info */
- FILE* file) /*!< in/out: buffer where to print */
-{
- ut_ad(pool_info);
-
- fprintf(file,
- "Buffer pool size %lu\n"
- "Free buffers %lu\n"
- "Database pages %lu\n"
- "Old database pages %lu\n"
- "Modified db pages %lu\n"
- "Pending reads %lu\n"
- "Pending writes: LRU %lu, flush list %lu, single page %lu\n",
- pool_info->pool_size,
- pool_info->free_list_len,
- pool_info->lru_len,
- pool_info->old_lru_len,
- pool_info->flush_list_len,
- pool_info->n_pend_reads,
- pool_info->n_pending_flush_lru,
- pool_info->n_pending_flush_list,
- pool_info->n_pending_flush_single_page);
-
- fprintf(file,
- "Pages made young %lu, not young %lu\n"
- "%.2f youngs/s, %.2f non-youngs/s\n"
- "Pages read %lu, created %lu, written %lu\n"
- "%.2f reads/s, %.2f creates/s, %.2f writes/s\n",
- pool_info->n_pages_made_young,
- pool_info->n_pages_not_made_young,
- pool_info->page_made_young_rate,
- pool_info->page_not_made_young_rate,
- pool_info->n_pages_read,
- pool_info->n_pages_created,
- pool_info->n_pages_written,
- pool_info->pages_read_rate,
- pool_info->pages_created_rate,
- pool_info->pages_written_rate);
-
- if (pool_info->n_page_get_delta) {
- fprintf(file,
- "Buffer pool hit rate %lu / 1000,"
- " young-making rate %lu / 1000 not %lu / 1000\n",
- (ulong) (1000 - (1000 * pool_info->page_read_delta
- / pool_info->n_page_get_delta)),
- (ulong) (1000 * pool_info->young_making_delta
- / pool_info->n_page_get_delta),
- (ulong) (1000 * pool_info->not_young_making_delta
- / pool_info->n_page_get_delta));
- } else {
- fputs("No buffer pool page gets since the last printout\n",
- file);
- }
-
- /* Statistics about read ahead algorithm */
- fprintf(file, "Pages read ahead %.2f/s,"
- " evicted without access %.2f/s,"
- " Random read ahead %.2f/s\n",
-
- pool_info->pages_readahead_rate,
- pool_info->pages_evicted_rate,
- pool_info->pages_readahead_rnd_rate);
-
- /* Print some values to help us with visualizing what is
- happening with LRU eviction. */
- fprintf(file,
- "LRU len: %lu, unzip_LRU len: %lu\n"
- "I/O sum[%lu]:cur[%lu], unzip sum[%lu]:cur[%lu]\n",
- pool_info->lru_len, pool_info->unzip_lru_len,
- pool_info->io_sum, pool_info->io_cur,
- pool_info->unzip_sum, pool_info->unzip_cur);
-}
-
-/*********************************************************************//**
-Prints info of the buffer i/o. */
-UNIV_INTERN
-void
-buf_print_io(
-/*=========*/
- FILE* file) /*!< in/out: buffer where to print */
-{
- ulint i;
- buf_pool_info_t* pool_info;
- buf_pool_info_t* pool_info_total;
-
- /* If srv_buf_pool_instances is greater than 1, allocate
- one extra buf_pool_info_t, the last one stores
- aggregated/total values from all pools */
- if (srv_buf_pool_instances > 1) {
- pool_info = (buf_pool_info_t*) mem_zalloc((
- srv_buf_pool_instances + 1) * sizeof *pool_info);
-
- pool_info_total = &pool_info[srv_buf_pool_instances];
- } else {
- ut_a(srv_buf_pool_instances == 1);
- pool_info_total = pool_info = (buf_pool_info_t*) mem_zalloc(
- sizeof *pool_info)
- }
-
- for (i = 0; i < srv_buf_pool_instances; i++) {
- buf_pool_t* buf_pool;
-
- buf_pool = buf_pool_from_array(i);
-
- /* Fetch individual buffer pool info and calculate
- aggregated stats along the way */
- buf_stats_get_pool_info(buf_pool, i, pool_info);
-
- /* If we have more than one buffer pool, store
- the aggregated stats */
- if (srv_buf_pool_instances > 1) {
- buf_stats_aggregate_pool_info(pool_info_total,
- &pool_info[i]);
- }
- }
-
- /* Print the aggreate buffer pool info */
- buf_print_io_instance(pool_info_total, file);
-
- /* If there are more than one buffer pool, print each individual pool
- info */
- if (srv_buf_pool_instances > 1) {
- fputs("----------------------\n"
- "INDIVIDUAL BUFFER POOL INFO\n"
- "----------------------\n", file);
-
- for (i = 0; i < srv_buf_pool_instances; i++) {
- fprintf(file, "---BUFFER POOL %lu\n", i);
- buf_print_io_instance(&pool_info[i], file);
- }
- }
-
- mem_free(pool_info);
-}
-
-/**********************************************************************//**
-Refreshes the statistics used to print per-second averages. */
-UNIV_INTERN
-void
-buf_refresh_io_stats(
-/*=================*/
- buf_pool_t* buf_pool) /*!< in: buffer pool instance */
-{
- buf_pool->last_printout_time = ut_time();
- buf_pool->old_stat = buf_pool->stat;
-}
-
-/**********************************************************************//**
-Refreshes the statistics used to print per-second averages. */
-UNIV_INTERN
-void
-buf_refresh_io_stats_all(void)
-/*==========================*/
-{
- ulint i;
-
- for (i = 0; i < srv_buf_pool_instances; i++) {
- buf_pool_t* buf_pool;
-
- buf_pool = buf_pool_from_array(i);
-
- buf_refresh_io_stats(buf_pool);
- }
-}
-
-/**********************************************************************//**
-Check if all pages in all buffer pools are in a replacable state.
-@return FALSE if not */
-UNIV_INTERN
-ibool
-buf_all_freed(void)
-/*===============*/
-{
- ulint i;
-
- for (i = 0; i < srv_buf_pool_instances; i++) {
- buf_pool_t* buf_pool;
-
- buf_pool = buf_pool_from_array(i);
-
- if (!buf_all_freed_instance(buf_pool)) {
- return(FALSE);
- }
- }
-
- return(TRUE);
-}
-
-/*********************************************************************//**
-Checks that there currently are no pending i/o-operations for the buffer
-pool.
-@return number of pending i/o */
-UNIV_INTERN
-ulint
-buf_pool_check_num_pending_io(void)
-/*===============================*/
-{
- ulint i;
- ulint pending_io = 0;
-
- buf_pool_mutex_enter_all();
-
- for (i = 0; i < srv_buf_pool_instances; i++) {
- const buf_pool_t* buf_pool;
-
- buf_pool = buf_pool_from_array(i);
-
- pending_io += buf_pool->n_pend_reads
- + buf_pool->n_flush[BUF_FLUSH_LRU]
- + buf_pool->n_flush[BUF_FLUSH_LIST]
- + buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE];
-
- }
-
- buf_pool_mutex_exit_all();
-
- return(pending_io);
-}
-
-#if 0
-Code currently not used
-/*********************************************************************//**
-Gets the current length of the free list of buffer blocks.
-@return length of the free list */
-UNIV_INTERN
-ulint
-buf_get_free_list_len(void)
-/*=======================*/
-{
- ulint len;
-
- buf_pool_mutex_enter(buf_pool);
-
- len = UT_LIST_GET_LEN(buf_pool->free);
-
- buf_pool_mutex_exit(buf_pool);
-
- return(len);
-}
-#endif
-
-#else /* !UNIV_HOTBACKUP */
-/********************************************************************//**
-Inits a page to the buffer buf_pool, for use in ibbackup --restore. */
-UNIV_INTERN
-void
-buf_page_init_for_backup_restore(
-/*=============================*/
- ulint space, /*!< in: space id */
- ulint offset, /*!< in: offset of the page within space
- in units of a page */
- ulint zip_size,/*!< in: compressed page size in bytes
- or 0 for uncompressed pages */
- buf_block_t* block) /*!< in: block to init */
-{
- block->page.state = BUF_BLOCK_FILE_PAGE;
- block->page.space = space;
- block->page.offset = offset;
-
- page_zip_des_init(&block->page.zip);
-
- /* We assume that block->page.data has been allocated
- with zip_size == UNIV_PAGE_SIZE. */
- ut_ad(zip_size <= UNIV_PAGE_SIZE);
- ut_ad(ut_is_2pow(zip_size));
- page_zip_set_size(&block->page.zip, zip_size);
- if (zip_size) {
- block->page.zip.data = block->frame + UNIV_PAGE_SIZE;
- }
-}
-#endif /* !UNIV_HOTBACKUP */