2005-10-27 09:29:40 +02:00
|
|
|
/* Innobase relational database engine; Copyright (C) 2001 Innobase Oy
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License 2
|
|
|
|
as published by the Free Software Foundation in June 1991.
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
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.
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
You should have received a copy of the GNU General Public License 2
|
|
|
|
along with this program (in file COPYING); if not, write to the Free
|
|
|
|
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|
|
|
/******************************************************
|
|
|
|
The database buffer buf_pool
|
|
|
|
|
|
|
|
(c) 1995 Innobase Oy
|
|
|
|
|
|
|
|
Created 11/5/1995 Heikki Tuuri
|
|
|
|
*******************************************************/
|
|
|
|
|
|
|
|
#include "buf0buf.h"
|
|
|
|
|
|
|
|
#ifdef UNIV_NONINL
|
|
|
|
#include "buf0buf.ic"
|
|
|
|
#endif
|
|
|
|
|
2006-12-15 16:05:18 +01:00
|
|
|
#include "buf0buddy.h"
|
2005-10-27 09:29:40 +02:00
|
|
|
#include "mem0mem.h"
|
|
|
|
#include "btr0btr.h"
|
|
|
|
#include "fil0fil.h"
|
|
|
|
#include "lock0lock.h"
|
|
|
|
#include "btr0sea.h"
|
|
|
|
#include "ibuf0ibuf.h"
|
|
|
|
#include "dict0dict.h"
|
|
|
|
#include "log0recv.h"
|
|
|
|
#include "log0log.h"
|
|
|
|
#include "trx0undo.h"
|
|
|
|
#include "srv0srv.h"
|
2005-10-27 13:48:10 +02:00
|
|
|
#include "page0zip.h"
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
IMPLEMENTATION OF THE BUFFER POOL
|
|
|
|
=================================
|
|
|
|
|
2006-02-23 20:25:29 +01:00
|
|
|
Performance improvement:
|
2005-10-27 09:29:40 +02:00
|
|
|
------------------------
|
|
|
|
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 contains
|
|
|
|
blocks which are currently not used.
|
|
|
|
|
|
|
|
The 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 noramlly 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
|
|
|
|
of the LRU list, we make sure that most of the buf_pool stays in the
|
|
|
|
main memory, undisturbed.
|
|
|
|
|
|
|
|
The chain of modified blocks 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.
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
2006-08-29 11:30:31 +02:00
|
|
|
A thread may request the above operation using the function
|
|
|
|
buf_page_get(). It may then continue to request a lock on the frame.
|
2005-10-27 09:29:40 +02:00
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
2006-11-10 12:15:59 +01:00
|
|
|
/* Value in microseconds */
|
|
|
|
static const int WAIT_FOR_READ = 20000;
|
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
buf_pool_t* buf_pool = NULL; /* The buffer buf_pool of the database */
|
|
|
|
|
2006-11-16 10:00:30 +01:00
|
|
|
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
|
|
|
|
static ulint buf_dbg_counter = 0; /* This is used to insert validation
|
2005-10-27 09:29:40 +02:00
|
|
|
operations in excution in the
|
|
|
|
debug version */
|
2006-11-16 10:00:30 +01:00
|
|
|
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
|
|
|
|
#ifdef UNIV_DEBUG
|
2005-10-27 09:29:40 +02:00
|
|
|
ibool buf_debug_prints = FALSE; /* If this is set TRUE,
|
|
|
|
the program prints info whenever
|
|
|
|
read-ahead or flush occurs */
|
|
|
|
#endif /* UNIV_DEBUG */
|
2006-04-05 15:41:12 +02:00
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
/* 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 */
|
|
|
|
};
|
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
/************************************************************************
|
|
|
|
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. */
|
|
|
|
|
|
|
|
ulint
|
|
|
|
buf_calc_page_new_checksum(
|
|
|
|
/*=======================*/
|
2006-10-23 21:14:36 +02:00
|
|
|
/* out: checksum */
|
|
|
|
const byte* page) /* in: buffer page */
|
2005-10-27 09:29:40 +02:00
|
|
|
{
|
2006-02-23 20:25:29 +01:00
|
|
|
ulint checksum;
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-02-23 20:25:29 +01:00
|
|
|
/* 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.
|
2005-10-27 09:29:40 +02:00
|
|
|
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. */
|
2006-02-23 20:25:29 +01:00
|
|
|
|
|
|
|
checksum = ut_fold_binary(page + FIL_PAGE_OFFSET,
|
2006-08-29 11:30:31 +02:00
|
|
|
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);
|
2006-02-23 20:25:29 +01:00
|
|
|
checksum = checksum & 0xFFFFFFFFUL;
|
|
|
|
|
|
|
|
return(checksum);
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
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
|
2006-02-23 20:25:29 +01:00
|
|
|
checksum.
|
2005-10-27 09:29:40 +02:00
|
|
|
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! */
|
|
|
|
|
|
|
|
ulint
|
|
|
|
buf_calc_page_old_checksum(
|
|
|
|
/*=======================*/
|
2006-10-23 21:14:36 +02:00
|
|
|
/* out: checksum */
|
|
|
|
const byte* page) /* in: buffer page */
|
2005-10-27 09:29:40 +02:00
|
|
|
{
|
2006-02-23 20:25:29 +01:00
|
|
|
ulint checksum;
|
|
|
|
|
|
|
|
checksum = ut_fold_binary(page, FIL_PAGE_FILE_FLUSH_LSN);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-02-23 20:25:29 +01:00
|
|
|
checksum = checksum & 0xFFFFFFFFUL;
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-02-23 20:25:29 +01:00
|
|
|
return(checksum);
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
Checks if a page is corrupt. */
|
|
|
|
|
|
|
|
ibool
|
|
|
|
buf_page_is_corrupted(
|
|
|
|
/*==================*/
|
2006-10-23 21:14:36 +02:00
|
|
|
/* out: TRUE if corrupted */
|
|
|
|
const byte* read_buf, /* in: a database page */
|
|
|
|
ulint zip_size) /* in: size of compressed page;
|
|
|
|
0 for uncompressed pages */
|
2005-10-27 09:29:40 +02:00
|
|
|
{
|
2006-11-24 14:05:01 +01:00
|
|
|
ulint checksum_field;
|
|
|
|
ulint old_checksum_field;
|
2005-10-27 09:29:40 +02:00
|
|
|
#ifndef UNIV_HOTBACKUP
|
2006-11-29 15:52:16 +01:00
|
|
|
ib_uint64_t current_lsn;
|
2005-10-27 09:29:40 +02:00
|
|
|
#endif
|
2006-04-05 15:41:12 +02:00
|
|
|
if (UNIV_LIKELY(!zip_size)
|
2006-08-29 11:30:31 +02:00
|
|
|
&& memcmp(read_buf + FIL_PAGE_LSN + 4,
|
|
|
|
read_buf + UNIV_PAGE_SIZE
|
|
|
|
- FIL_PAGE_END_LSN_OLD_CHKSUM + 4, 4)) {
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
/* 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 && log_peek_lsn(¤t_lsn)) {
|
2006-11-24 14:05:01 +01:00
|
|
|
if (current_lsn < mach_read_ull(read_buf + FIL_PAGE_LSN)) {
|
2005-10-27 09:29:40 +02:00
|
|
|
ut_print_timestamp(stderr);
|
|
|
|
|
|
|
|
fprintf(stderr,
|
2006-08-29 11:30:31 +02:00
|
|
|
" InnoDB: Error: page %lu log sequence number"
|
2006-11-24 14:05:01 +01:00
|
|
|
" %llu\n"
|
2006-08-29 11:30:31 +02:00
|
|
|
"InnoDB: is in the future! Current system "
|
2006-11-24 14:05:01 +01:00
|
|
|
"log sequence number %llu.\n"
|
2006-08-29 11:30:31 +02:00
|
|
|
"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: http://dev.mysql.com/doc/refman/"
|
|
|
|
"5.1/en/forcing-recovery.html\n"
|
|
|
|
"InnoDB: for more information.\n",
|
|
|
|
(ulong) mach_read_from_4(read_buf
|
|
|
|
+ FIL_PAGE_OFFSET),
|
2006-11-24 14:05:01 +01:00
|
|
|
mach_read_ull(read_buf + FIL_PAGE_LSN),
|
|
|
|
current_lsn);
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-02-23 20:25:29 +01:00
|
|
|
/* 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 */
|
|
|
|
|
2006-04-05 15:41:12 +02:00
|
|
|
if (UNIV_LIKELY(srv_use_checksums)) {
|
|
|
|
checksum_field = mach_read_from_4(read_buf
|
2006-08-29 11:30:31 +02:00
|
|
|
+ FIL_PAGE_SPACE_OR_CHKSUM);
|
2006-04-05 15:41:12 +02:00
|
|
|
|
|
|
|
if (UNIV_UNLIKELY(zip_size)) {
|
|
|
|
return(checksum_field != BUF_NO_CHECKSUM_MAGIC
|
2006-08-29 11:30:31 +02:00
|
|
|
&& checksum_field
|
|
|
|
!= page_zip_calc_checksum(read_buf, zip_size));
|
2006-04-05 15:41:12 +02:00
|
|
|
}
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-09-19 12:14:07 +02:00
|
|
|
old_checksum_field = mach_read_from_4(
|
|
|
|
read_buf + UNIV_PAGE_SIZE
|
|
|
|
- FIL_PAGE_END_LSN_OLD_CHKSUM);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-02-23 20:25:29 +01:00
|
|
|
/* There are 2 valid formulas for old_checksum_field:
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-02-23 20:25:29 +01:00
|
|
|
1. Very old versions of InnoDB only stored 8 byte lsn to the
|
|
|
|
start and the end of the page.
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-02-23 20:25:29 +01:00
|
|
|
2. Newer InnoDB versions store the old formula checksum
|
|
|
|
there. */
|
|
|
|
|
|
|
|
if (old_checksum_field != mach_read_from_4(read_buf
|
2006-08-29 11:30:31 +02:00
|
|
|
+ FIL_PAGE_LSN)
|
|
|
|
&& old_checksum_field != BUF_NO_CHECKSUM_MAGIC
|
|
|
|
&& old_checksum_field
|
|
|
|
!= buf_calc_page_old_checksum(read_buf)) {
|
2006-02-23 20:25:29 +01:00
|
|
|
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* InnoDB versions < 4.0.14 and < 4.1.1 stored the space id
|
|
|
|
(always equal to 0), to FIL_PAGE_SPACE_SPACE_OR_CHKSUM */
|
|
|
|
|
2006-04-05 15:41:12 +02:00
|
|
|
if (checksum_field != 0
|
2006-08-29 11:30:31 +02:00
|
|
|
&& checksum_field != BUF_NO_CHECKSUM_MAGIC
|
|
|
|
&& checksum_field
|
|
|
|
!= buf_calc_page_new_checksum(read_buf)) {
|
2006-02-23 20:25:29 +01:00
|
|
|
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
}
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
Prints a page to stderr. */
|
|
|
|
|
|
|
|
void
|
|
|
|
buf_page_print(
|
|
|
|
/*===========*/
|
2006-10-23 21:14:36 +02:00
|
|
|
const byte* read_buf, /* in: a database page */
|
|
|
|
ulint zip_size) /* in: compressed page size, or
|
2006-05-02 13:44:39 +02:00
|
|
|
0 for uncompressed pages */
|
2005-10-27 09:29:40 +02:00
|
|
|
{
|
|
|
|
dict_index_t* index;
|
|
|
|
ulint checksum;
|
|
|
|
ulint old_checksum;
|
2006-05-02 13:44:39 +02:00
|
|
|
ulint size = zip_size;
|
|
|
|
|
|
|
|
if (!size) {
|
|
|
|
size = UNIV_PAGE_SIZE;
|
|
|
|
}
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
ut_print_timestamp(stderr);
|
|
|
|
fprintf(stderr, " InnoDB: Page dump in ascii and hex (%lu bytes):\n",
|
2006-05-02 13:44:39 +02:00
|
|
|
(ulong) size);
|
|
|
|
ut_print_buf(stderr, read_buf, size);
|
2005-10-27 09:29:40 +02:00
|
|
|
fputs("InnoDB: End of page dump\n", stderr);
|
|
|
|
|
2006-05-02 13:44:39 +02:00
|
|
|
if (zip_size) {
|
|
|
|
/* Print compressed page. */
|
|
|
|
|
|
|
|
switch (fil_page_get_type(read_buf)) {
|
|
|
|
case FIL_PAGE_TYPE_ZBLOB:
|
|
|
|
checksum = srv_use_checksums
|
2006-08-29 11:30:31 +02:00
|
|
|
? page_zip_calc_checksum(read_buf, zip_size)
|
|
|
|
: BUF_NO_CHECKSUM_MAGIC;
|
2006-05-02 13:44:39 +02:00
|
|
|
ut_print_timestamp(stderr);
|
|
|
|
fprintf(stderr,
|
2006-08-29 11:30:31 +02:00
|
|
|
" 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",
|
2006-05-02 13:44:39 +02:00
|
|
|
(ulong) checksum,
|
2006-09-19 12:14:07 +02:00
|
|
|
(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(
|
2006-09-27 12:51:05 +02:00
|
|
|
read_buf
|
|
|
|
+ FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID));
|
2006-05-02 13:44:39 +02:00
|
|
|
return;
|
|
|
|
default:
|
|
|
|
ut_print_timestamp(stderr);
|
|
|
|
fprintf(stderr,
|
2006-08-29 11:30:31 +02:00
|
|
|
" InnoDB: unknown page type %lu,"
|
|
|
|
" assuming FIL_PAGE_INDEX\n",
|
2006-05-02 13:44:39 +02:00
|
|
|
fil_page_get_type(read_buf));
|
|
|
|
/* fall through */
|
|
|
|
case FIL_PAGE_INDEX:
|
|
|
|
checksum = srv_use_checksums
|
2006-08-29 11:30:31 +02:00
|
|
|
? page_zip_calc_checksum(read_buf, zip_size)
|
|
|
|
: BUF_NO_CHECKSUM_MAGIC;
|
2006-05-02 13:44:39 +02:00
|
|
|
|
|
|
|
ut_print_timestamp(stderr);
|
|
|
|
fprintf(stderr,
|
2006-08-29 11:30:31 +02:00
|
|
|
" 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",
|
2006-05-02 13:44:39 +02:00
|
|
|
(ulong) checksum,
|
2006-09-19 12:14:07 +02:00
|
|
|
(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));
|
2006-05-02 13:44:39 +02:00
|
|
|
return;
|
|
|
|
case FIL_PAGE_TYPE_XDES:
|
|
|
|
/* This is an uncompressed page. */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-08-29 11:30:31 +02:00
|
|
|
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;
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
ut_print_timestamp(stderr);
|
2006-02-23 20:25:29 +01:00
|
|
|
fprintf(stderr,
|
2006-08-29 11:30:31 +02:00
|
|
|
" 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),
|
2005-10-27 09:29:40 +02:00
|
|
|
(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
|
2006-08-29 11:30:31 +02:00
|
|
|
- FIL_PAGE_END_LSN_OLD_CHKSUM + 4),
|
2005-10-27 09:29:40 +02:00
|
|
|
(ulong) mach_read_from_4(read_buf + FIL_PAGE_OFFSET),
|
2006-08-29 11:30:31 +02:00
|
|
|
(ulong) mach_read_from_4(read_buf
|
|
|
|
+ FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID));
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
if (mach_read_from_2(read_buf + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE)
|
2006-08-29 11:30:31 +02:00
|
|
|
== TRX_UNDO_INSERT) {
|
2006-02-23 20:25:29 +01:00
|
|
|
fprintf(stderr,
|
2005-10-27 09:29:40 +02:00
|
|
|
"InnoDB: Page may be an insert undo log page\n");
|
|
|
|
} else if (mach_read_from_2(read_buf + TRX_UNDO_PAGE_HDR
|
2006-08-29 11:30:31 +02:00
|
|
|
+ TRX_UNDO_PAGE_TYPE)
|
|
|
|
== TRX_UNDO_UPDATE) {
|
2006-02-23 20:25:29 +01:00
|
|
|
fprintf(stderr,
|
2005-10-27 09:29:40 +02:00
|
|
|
"InnoDB: Page may be an update undo log page\n");
|
|
|
|
}
|
|
|
|
|
2006-02-23 20:25:29 +01:00
|
|
|
switch (fil_page_get_type(read_buf)) {
|
|
|
|
case FIL_PAGE_INDEX:
|
|
|
|
fprintf(stderr,
|
2006-08-29 11:30:31 +02:00
|
|
|
"InnoDB: Page may be an index page where"
|
|
|
|
" index id is %lu %lu\n",
|
2006-09-19 12:14:07 +02:00
|
|
|
(ulong) ut_dulint_get_high(
|
|
|
|
btr_page_get_index_id(read_buf)),
|
|
|
|
(ulong) ut_dulint_get_low(
|
|
|
|
btr_page_get_index_id(read_buf)));
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-05-02 13:44:39 +02:00
|
|
|
#ifdef UNIV_HOTBACKUP
|
2005-10-27 09:29:40 +02:00
|
|
|
/* If the code is in ibbackup, dict_sys may be uninitialized,
|
|
|
|
i.e., NULL */
|
|
|
|
|
2006-05-02 13:44:39 +02:00
|
|
|
if (dict_sys == NULL) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif /* UNIV_HOTBACKUP */
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-09-19 12:14:07 +02:00
|
|
|
index = dict_index_find_on_id_low(
|
|
|
|
btr_page_get_index_id(read_buf));
|
2006-05-02 13:44:39 +02:00
|
|
|
if (index) {
|
|
|
|
fputs("InnoDB: (", stderr);
|
|
|
|
dict_index_name_print(stderr, NULL, index);
|
|
|
|
fputs(")\n", stderr);
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
2006-02-23 20:25:29 +01:00
|
|
|
break;
|
|
|
|
case FIL_PAGE_INODE:
|
2005-10-27 09:29:40 +02:00
|
|
|
fputs("InnoDB: Page may be an 'inode' page\n", stderr);
|
2006-02-23 20:25:29 +01:00
|
|
|
break;
|
|
|
|
case FIL_PAGE_IBUF_FREE_LIST:
|
2005-10-27 09:29:40 +02:00
|
|
|
fputs("InnoDB: Page may be an insert buffer free list page\n",
|
2006-08-29 11:30:31 +02:00
|
|
|
stderr);
|
2006-02-23 20:25:29 +01:00
|
|
|
break;
|
|
|
|
case FIL_PAGE_TYPE_ALLOCATED:
|
|
|
|
fputs("InnoDB: Page may be a freshly allocated page\n",
|
2006-08-29 11:30:31 +02:00
|
|
|
stderr);
|
2006-02-23 20:25:29 +01:00
|
|
|
break;
|
|
|
|
case FIL_PAGE_IBUF_BITMAP:
|
|
|
|
fputs("InnoDB: Page may be an insert buffer bitmap page\n",
|
2006-08-29 11:30:31 +02:00
|
|
|
stderr);
|
2006-02-23 20:25:29 +01:00
|
|
|
break;
|
|
|
|
case FIL_PAGE_TYPE_SYS:
|
|
|
|
fputs("InnoDB: Page may be a system page\n",
|
2006-08-29 11:30:31 +02:00
|
|
|
stderr);
|
2006-02-23 20:25:29 +01:00
|
|
|
break;
|
|
|
|
case FIL_PAGE_TYPE_TRX_SYS:
|
|
|
|
fputs("InnoDB: Page may be a transaction system page\n",
|
2006-08-29 11:30:31 +02:00
|
|
|
stderr);
|
2006-02-23 20:25:29 +01:00
|
|
|
break;
|
|
|
|
case FIL_PAGE_TYPE_FSP_HDR:
|
|
|
|
fputs("InnoDB: Page may be a file space header page\n",
|
2006-08-29 11:30:31 +02:00
|
|
|
stderr);
|
2006-02-23 20:25:29 +01:00
|
|
|
break;
|
|
|
|
case FIL_PAGE_TYPE_XDES:
|
|
|
|
fputs("InnoDB: Page may be an extent descriptor page\n",
|
2006-08-29 11:30:31 +02:00
|
|
|
stderr);
|
2006-02-23 20:25:29 +01:00
|
|
|
break;
|
|
|
|
case FIL_PAGE_TYPE_BLOB:
|
|
|
|
fputs("InnoDB: Page may be a BLOB page\n",
|
2006-08-29 11:30:31 +02:00
|
|
|
stderr);
|
2006-02-23 20:25:29 +01:00
|
|
|
break;
|
2006-04-05 15:41:12 +02:00
|
|
|
case FIL_PAGE_TYPE_ZBLOB:
|
|
|
|
fputs("InnoDB: Page may be a compressed BLOB page\n",
|
2006-08-29 11:30:31 +02:00
|
|
|
stderr);
|
2006-04-05 15:41:12 +02:00
|
|
|
break;
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
Initializes a buffer control block when the buf_pool is created. */
|
|
|
|
static
|
|
|
|
void
|
|
|
|
buf_block_init(
|
|
|
|
/*===========*/
|
|
|
|
buf_block_t* block, /* in: pointer to control block */
|
2006-10-30 14:48:08 +01:00
|
|
|
byte* frame) /* in: pointer to buffer frame */
|
2005-10-27 09:29:40 +02:00
|
|
|
{
|
2007-01-12 13:36:40 +01:00
|
|
|
UNIV_MEM_DESC(frame, UNIV_PAGE_SIZE, block);
|
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
block->frame = frame;
|
|
|
|
|
2006-11-30 13:27:49 +01:00
|
|
|
block->page.state = BUF_BLOCK_NOT_USED;
|
|
|
|
block->page.buf_fix_count = 0;
|
|
|
|
block->page.io_fix = BUF_IO_NONE;
|
2006-02-17 15:19:39 +01:00
|
|
|
|
2006-11-24 14:05:01 +01:00
|
|
|
block->modify_clock = 0;
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2006-11-16 09:48:28 +01:00
|
|
|
#ifdef UNIV_DEBUG_FILE_ACCESSES
|
2006-11-29 14:23:28 +01:00
|
|
|
block->page.file_page_was_freed = FALSE;
|
2006-11-16 09:48:28 +01:00
|
|
|
#endif /* UNIV_DEBUG_FILE_ACCESSES */
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
block->check_index_page_at_flush = FALSE;
|
|
|
|
block->index = NULL;
|
|
|
|
|
2006-10-18 20:52:04 +02:00
|
|
|
#ifdef UNIV_DEBUG
|
2007-01-24 11:36:05 +01:00
|
|
|
block->page.in_page_hash = FALSE;
|
|
|
|
block->page.in_zip_hash = FALSE;
|
2007-01-09 13:35:42 +01:00
|
|
|
block->page.in_flush_list = FALSE;
|
2006-12-04 13:44:06 +01:00
|
|
|
block->page.in_free_list = FALSE;
|
2006-11-30 13:27:49 +01:00
|
|
|
block->page.in_LRU_list = FALSE;
|
2005-10-27 09:29:40 +02:00
|
|
|
block->n_pointers = 0;
|
2006-10-18 20:52:04 +02:00
|
|
|
#endif /* UNIV_DEBUG */
|
2006-11-24 09:32:18 +01:00
|
|
|
page_zip_des_init(&block->page.zip);
|
2005-10-27 13:48:10 +02:00
|
|
|
|
2006-11-10 12:15:59 +01:00
|
|
|
mutex_create(&block->mutex, SYNC_BUF_BLOCK);
|
|
|
|
|
2006-05-08 08:18:59 +02:00
|
|
|
rw_lock_create(&block->lock, SYNC_LEVEL_VARYING);
|
2005-10-27 09:29:40 +02:00
|
|
|
ut_ad(rw_lock_validate(&(block->lock)));
|
|
|
|
|
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
2006-05-08 08:18:59 +02:00
|
|
|
rw_lock_create(&block->debug_latch, SYNC_NO_ORDER_CHECK);
|
2005-10-27 09:29:40 +02:00
|
|
|
#endif /* UNIV_SYNC_DEBUG */
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
2006-11-14 15:27:26 +01:00
|
|
|
Allocates a chunk of buffer frames. */
|
|
|
|
static
|
|
|
|
buf_chunk_t*
|
|
|
|
buf_chunk_init(
|
|
|
|
/*===========*/
|
|
|
|
/* out: chunk, or NULL on failure */
|
|
|
|
buf_chunk_t* chunk, /* out: chunk of buffers */
|
|
|
|
ulint mem_size) /* in: requested size in bytes */
|
2005-10-27 09:29:40 +02:00
|
|
|
{
|
2006-11-14 15:27:26 +01:00
|
|
|
buf_block_t* block;
|
2005-10-27 09:29:40 +02:00
|
|
|
byte* frame;
|
|
|
|
ulint i;
|
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
/* 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);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
chunk->mem_size = mem_size;
|
|
|
|
chunk->mem = os_mem_alloc_large(&chunk->mem_size);
|
2006-11-01 09:13:58 +01:00
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
if (UNIV_UNLIKELY(chunk->mem == NULL)) {
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
/* Allocate the block descriptors from
|
|
|
|
the start of the memory block. */
|
|
|
|
chunk->blocks = chunk->mem;
|
2006-11-01 09:13:58 +01:00
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
/* Align pointer to the first frame */
|
2006-11-01 09:13:58 +01:00
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
frame = ut_align(chunk->mem, UNIV_PAGE_SIZE);
|
|
|
|
chunk->size = chunk->mem_size / UNIV_PAGE_SIZE
|
|
|
|
- (frame != chunk->mem);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
/* Subtract the space needed for block descriptors. */
|
|
|
|
{
|
|
|
|
ulint size = chunk->size;
|
2006-11-01 09:13:58 +01:00
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
while (frame < (byte*) (chunk->blocks + size)) {
|
|
|
|
frame += UNIV_PAGE_SIZE;
|
|
|
|
size--;
|
|
|
|
}
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
chunk->size = size;
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
2006-10-30 14:48:08 +01:00
|
|
|
/* Init block structs and assign frames for them. Then we
|
|
|
|
assign the frames to the first blocks (we already mapped the
|
|
|
|
memory above). */
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
block = chunk->blocks;
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
for (i = chunk->size; i--; ) {
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
buf_block_init(block, frame);
|
2006-10-31 10:59:15 +01:00
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
#ifdef HAVE_purify
|
|
|
|
/* Wipe contents of frame to eliminate a Purify warning */
|
|
|
|
memset(block->frame, '\0', UNIV_PAGE_SIZE);
|
|
|
|
#endif
|
|
|
|
/* Add the block to the free list */
|
2006-12-05 13:31:38 +01:00
|
|
|
UT_LIST_ADD_LAST(list, buf_pool->free, (&block->page));
|
2006-12-04 13:44:06 +01:00
|
|
|
ut_d(block->page.in_free_list = TRUE);
|
2006-11-14 15:27:26 +01:00
|
|
|
|
|
|
|
block++;
|
2006-10-31 10:59:15 +01:00
|
|
|
frame += UNIV_PAGE_SIZE;
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
return(chunk);
|
|
|
|
}
|
|
|
|
|
2006-12-19 23:12:44 +01:00
|
|
|
#ifdef UNIV_DEBUG
|
|
|
|
/*************************************************************************
|
|
|
|
Finds a block in the given buffer chunk that points to a
|
|
|
|
given compressed page. */
|
|
|
|
static
|
|
|
|
buf_block_t*
|
|
|
|
buf_chunk_contains_zip(
|
|
|
|
/*===================*/
|
|
|
|
/* out: buffer block pointing to
|
|
|
|
the compressed page, or NULL */
|
|
|
|
buf_chunk_t* chunk, /* in: chunk being checked */
|
|
|
|
const void* data) /* in: pointer to compressed page */
|
|
|
|
{
|
|
|
|
buf_block_t* block;
|
|
|
|
ulint i;
|
|
|
|
|
|
|
|
ut_ad(buf_pool);
|
2007-01-18 19:29:12 +01:00
|
|
|
ut_ad(mutex_own(&buf_pool->mutex));
|
2007-01-03 14:10:46 +01:00
|
|
|
|
2006-12-19 23:12:44 +01:00
|
|
|
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. */
|
|
|
|
|
|
|
|
buf_block_t*
|
|
|
|
buf_pool_contains_zip(
|
|
|
|
/*==================*/
|
|
|
|
/* out: buffer block pointing to
|
|
|
|
the compressed page, or NULL */
|
|
|
|
const void* data) /* in: pointer to compressed page */
|
|
|
|
{
|
|
|
|
ulint n;
|
|
|
|
buf_chunk_t* chunk = buf_pool->chunks;
|
|
|
|
|
|
|
|
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 */
|
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
/*************************************************************************
|
|
|
|
Checks that all file pages in the buffer chunk are in a replaceable state. */
|
|
|
|
static
|
|
|
|
const buf_block_t*
|
|
|
|
buf_chunk_not_freed(
|
|
|
|
/*================*/
|
|
|
|
/* out: address of a non-free block,
|
|
|
|
or NULL if all freed */
|
|
|
|
buf_chunk_t* chunk) /* in: chunk being checked */
|
|
|
|
{
|
|
|
|
buf_block_t* block;
|
|
|
|
ulint i;
|
|
|
|
|
|
|
|
ut_ad(buf_pool);
|
|
|
|
ut_ad(mutex_own(&(buf_pool->mutex)));
|
|
|
|
|
|
|
|
block = chunk->blocks;
|
|
|
|
|
|
|
|
for (i = chunk->size; i--; block++) {
|
|
|
|
mutex_enter(&block->mutex);
|
|
|
|
|
2006-11-23 14:26:01 +01:00
|
|
|
if (buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE
|
2006-11-30 13:27:49 +01:00
|
|
|
&& !buf_flush_ready_for_replace(&block->page)) {
|
2006-11-14 15:27:26 +01:00
|
|
|
|
|
|
|
mutex_exit(&block->mutex);
|
|
|
|
return(block);
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_exit(&block->mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
Checks that all blocks in the buffer chunk are in BUF_BLOCK_NOT_USED state. */
|
|
|
|
static
|
|
|
|
ibool
|
|
|
|
buf_chunk_all_free(
|
|
|
|
/*===============*/
|
|
|
|
/* out: TRUE if all freed */
|
|
|
|
const buf_chunk_t* chunk) /* in: chunk being checked */
|
|
|
|
{
|
|
|
|
const buf_block_t* block;
|
|
|
|
ulint i;
|
|
|
|
|
|
|
|
ut_ad(buf_pool);
|
|
|
|
ut_ad(mutex_own(&(buf_pool->mutex)));
|
|
|
|
|
|
|
|
block = chunk->blocks;
|
|
|
|
|
|
|
|
for (i = chunk->size; i--; block++) {
|
|
|
|
|
2006-11-23 14:26:01 +01:00
|
|
|
if (buf_block_get_state(block) != BUF_BLOCK_NOT_USED) {
|
2006-11-14 15:27:26 +01:00
|
|
|
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
Frees a chunk of buffer frames. */
|
|
|
|
static
|
|
|
|
void
|
|
|
|
buf_chunk_free(
|
|
|
|
/*===========*/
|
|
|
|
buf_chunk_t* chunk) /* out: chunk of buffers */
|
|
|
|
{
|
|
|
|
buf_block_t* block;
|
|
|
|
const buf_block_t* block_end;
|
|
|
|
|
|
|
|
ut_ad(mutex_own(&(buf_pool->mutex)));
|
|
|
|
|
|
|
|
block_end = chunk->blocks + chunk->size;
|
|
|
|
|
|
|
|
for (block = chunk->blocks; block < block_end; block++) {
|
2006-11-23 14:26:01 +01:00
|
|
|
ut_a(buf_block_get_state(block) == BUF_BLOCK_NOT_USED);
|
2006-11-24 09:32:18 +01:00
|
|
|
ut_a(!block->page.zip.data);
|
2006-11-14 15:27:26 +01:00
|
|
|
|
2006-11-30 13:27:49 +01:00
|
|
|
ut_ad(!block->page.in_LRU_list);
|
2007-01-09 13:35:42 +01:00
|
|
|
ut_ad(!block->page.in_flush_list);
|
2006-11-14 15:27:26 +01:00
|
|
|
/* Remove the block from the free list. */
|
2006-12-04 13:44:06 +01:00
|
|
|
ut_ad(block->page.in_free_list);
|
2006-12-05 13:31:38 +01:00
|
|
|
UT_LIST_REMOVE(list, buf_pool->free, (&block->page));
|
2006-11-14 15:27:26 +01:00
|
|
|
|
|
|
|
/* Free the latches. */
|
|
|
|
mutex_free(&block->mutex);
|
|
|
|
rw_lock_free(&block->lock);
|
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
|
|
rw_lock_free(&block->debug_latch);
|
|
|
|
#endif /* UNIV_SYNC_DEBUG */
|
2007-01-12 13:36:40 +01:00
|
|
|
UNIV_MEM_UNDESC(block);
|
2006-11-14 15:27:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
os_mem_free_large(chunk->mem, chunk->mem_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
Creates the buffer pool. */
|
|
|
|
|
|
|
|
buf_pool_t*
|
|
|
|
buf_pool_init(void)
|
|
|
|
/*===============*/
|
|
|
|
/* out, own: buf_pool object, NULL if not
|
|
|
|
enough memory or error */
|
|
|
|
{
|
|
|
|
buf_chunk_t* chunk;
|
|
|
|
ulint i;
|
|
|
|
|
|
|
|
buf_pool = mem_alloc(sizeof(buf_pool_t));
|
|
|
|
|
|
|
|
/* 1. Initialize general fields
|
|
|
|
------------------------------- */
|
|
|
|
mutex_create(&buf_pool->mutex, SYNC_BUF_POOL);
|
|
|
|
|
|
|
|
mutex_enter(&(buf_pool->mutex));
|
|
|
|
|
2006-12-07 14:29:04 +01:00
|
|
|
mutex_create(&buf_pool->zip_mutex, SYNC_BUF_BLOCK);
|
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
buf_pool->n_chunks = 1;
|
|
|
|
buf_pool->chunks = chunk = mem_alloc(sizeof *chunk);
|
|
|
|
|
|
|
|
UT_LIST_INIT(buf_pool->free);
|
|
|
|
|
|
|
|
if (!buf_chunk_init(chunk, srv_buf_pool_size)) {
|
|
|
|
mem_free(chunk);
|
|
|
|
mem_free(buf_pool);
|
|
|
|
buf_pool = NULL;
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
srv_buf_pool_old_size = srv_buf_pool_size;
|
|
|
|
buf_pool->curr_size = chunk->size;
|
|
|
|
srv_buf_pool_curr_size = buf_pool->curr_size * UNIV_PAGE_SIZE;
|
|
|
|
|
|
|
|
buf_pool->page_hash = hash_create(2 * buf_pool->curr_size);
|
2006-12-11 10:54:13 +01:00
|
|
|
buf_pool->zip_hash = hash_create(2 * buf_pool->curr_size);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
buf_pool->n_pend_reads = 0;
|
|
|
|
|
|
|
|
buf_pool->last_printout_time = time(NULL);
|
|
|
|
|
|
|
|
buf_pool->n_pages_read = 0;
|
|
|
|
buf_pool->n_pages_written = 0;
|
|
|
|
buf_pool->n_pages_created = 0;
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
buf_pool->n_page_gets = 0;
|
|
|
|
buf_pool->n_page_gets_old = 0;
|
|
|
|
buf_pool->n_pages_read_old = 0;
|
|
|
|
buf_pool->n_pages_written_old = 0;
|
|
|
|
buf_pool->n_pages_created_old = 0;
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
/* 2. Initialize flushing fields
|
2006-02-23 20:25:29 +01:00
|
|
|
-------------------------------- */
|
2005-10-27 09:29:40 +02:00
|
|
|
UT_LIST_INIT(buf_pool->flush_list);
|
|
|
|
|
2006-11-27 15:12:09 +01:00
|
|
|
for (i = BUF_FLUSH_LRU; i < BUF_FLUSH_N_TYPES; i++) {
|
2005-10-27 09:29:40 +02:00
|
|
|
buf_pool->n_flush[i] = 0;
|
|
|
|
buf_pool->init_flush[i] = FALSE;
|
|
|
|
buf_pool->no_flush[i] = os_event_create(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
buf_pool->LRU_flush_ended = 0;
|
|
|
|
|
|
|
|
buf_pool->ulint_clock = 1;
|
|
|
|
buf_pool->freed_page_clock = 0;
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
/* 3. Initialize LRU fields
|
2006-02-23 20:25:29 +01:00
|
|
|
--------------------------- */
|
2005-10-27 09:29:40 +02:00
|
|
|
UT_LIST_INIT(buf_pool->LRU);
|
|
|
|
|
|
|
|
buf_pool->LRU_old = NULL;
|
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
mutex_exit(&(buf_pool->mutex));
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
btr_search_sys_create(buf_pool->curr_size
|
|
|
|
* UNIV_PAGE_SIZE / sizeof(void*) / 64);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-12-07 14:29:04 +01:00
|
|
|
/* 4. Initialize the buddy allocator fields */
|
|
|
|
|
|
|
|
UT_LIST_INIT(buf_pool->zip_clean);
|
|
|
|
|
|
|
|
for (i = 0; i < BUF_BUDDY_SIZES; i++) {
|
|
|
|
UT_LIST_INIT(buf_pool->zip_free[i]);
|
|
|
|
}
|
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
return(buf_pool);
|
|
|
|
}
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-12-14 16:15:51 +01:00
|
|
|
/************************************************************************
|
|
|
|
Relocate a buffer control block. Relocates the block on the LRU list
|
|
|
|
and in buf_pool->page_hash. Does not relocate bpage->list. */
|
|
|
|
|
|
|
|
void
|
|
|
|
buf_relocate(
|
|
|
|
/*=========*/
|
|
|
|
buf_page_t* bpage, /* control block being relocated */
|
|
|
|
buf_page_t* dpage) /* destination control block */
|
|
|
|
{
|
|
|
|
buf_page_t* b;
|
|
|
|
ulint fold;
|
2007-01-18 19:29:12 +01:00
|
|
|
|
|
|
|
ut_ad(mutex_own(&buf_pool->mutex));
|
|
|
|
ut_ad(mutex_own(buf_page_get_mutex(bpage)));
|
2006-12-14 16:15:51 +01:00
|
|
|
ut_a(buf_page_get_io_fix(bpage) == BUF_IO_NONE);
|
|
|
|
ut_a(bpage->buf_fix_count == 0);
|
|
|
|
ut_a(buf_page_in_file(bpage));
|
2007-01-24 11:36:05 +01:00
|
|
|
ut_ad(bpage->in_LRU_list);
|
|
|
|
ut_ad(!bpage->in_zip_hash);
|
|
|
|
ut_ad(bpage->in_page_hash);
|
2007-01-12 10:14:15 +01:00
|
|
|
ut_ad(bpage == buf_page_hash_get(bpage->space, bpage->offset));
|
2006-12-14 16:15:51 +01:00
|
|
|
|
2007-01-12 10:14:15 +01:00
|
|
|
memcpy(dpage, bpage, sizeof *dpage);
|
2006-12-14 16:15:51 +01:00
|
|
|
|
2007-01-24 11:36:05 +01:00
|
|
|
ut_d(bpage->in_LRU_list = FALSE);
|
|
|
|
ut_d(bpage->in_page_hash = FALSE);
|
|
|
|
|
2007-01-12 10:14:15 +01:00
|
|
|
/* relocate buf_pool->LRU */
|
2006-12-14 16:15:51 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2007-01-04 16:45:42 +01:00
|
|
|
if (UNIV_UNLIKELY(buf_pool->LRU_old == bpage)) {
|
|
|
|
buf_pool->LRU_old = dpage;
|
|
|
|
}
|
|
|
|
|
|
|
|
ut_d(UT_LIST_VALIDATE(LRU, buf_page_t, buf_pool->LRU));
|
|
|
|
|
2006-12-14 16:15:51 +01:00
|
|
|
/* 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);
|
2007-01-12 10:14:15 +01:00
|
|
|
|
|
|
|
UNIV_MEM_INVALID(bpage, sizeof *bpage);
|
2006-12-14 16:15:51 +01:00
|
|
|
}
|
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
/************************************************************************
|
2006-11-21 15:40:14 +01:00
|
|
|
Shrinks the buffer pool. */
|
|
|
|
static
|
2006-11-14 15:27:26 +01:00
|
|
|
void
|
2006-11-21 15:40:14 +01:00
|
|
|
buf_pool_shrink(
|
|
|
|
/*============*/
|
|
|
|
/* out: TRUE if shrunk */
|
|
|
|
ulint chunk_size) /* in: number of pages to remove */
|
2006-11-14 15:27:26 +01:00
|
|
|
{
|
|
|
|
buf_chunk_t* chunks;
|
|
|
|
buf_chunk_t* chunk;
|
2006-11-21 15:40:14 +01:00
|
|
|
ulint max_size;
|
|
|
|
ulint max_free_size;
|
|
|
|
buf_chunk_t* max_chunk;
|
|
|
|
buf_chunk_t* max_free_chunk;
|
|
|
|
|
|
|
|
ut_ad(!mutex_own(&buf_pool->mutex));
|
2006-11-14 15:27:26 +01:00
|
|
|
|
2006-11-15 22:49:14 +01:00
|
|
|
try_again:
|
2006-11-21 15:40:14 +01:00
|
|
|
btr_search_disable(); /* Empty the adaptive hash index again */
|
2006-11-14 15:27:26 +01:00
|
|
|
mutex_enter(&buf_pool->mutex);
|
|
|
|
|
2006-11-21 15:40:14 +01:00
|
|
|
shrink_again:
|
|
|
|
if (buf_pool->n_chunks <= 1) {
|
2006-11-14 15:27:26 +01:00
|
|
|
|
2006-11-21 15:40:14 +01:00
|
|
|
/* Cannot shrink if there is only one chunk */
|
|
|
|
goto func_done;
|
2006-11-14 15:27:26 +01:00
|
|
|
}
|
|
|
|
|
2006-11-21 15:40:14 +01:00
|
|
|
/* Search for the largest free chunk
|
|
|
|
not larger than the size difference */
|
|
|
|
chunks = buf_pool->chunks;
|
|
|
|
chunk = chunks + buf_pool->n_chunks;
|
|
|
|
max_size = max_free_size = 0;
|
|
|
|
max_chunk = max_free_chunk = NULL;
|
|
|
|
|
|
|
|
while (--chunk >= chunks) {
|
|
|
|
if (chunk->size <= chunk_size
|
|
|
|
&& chunk->size > max_free_size) {
|
|
|
|
if (chunk->size > max_size) {
|
|
|
|
max_size = chunk->size;
|
|
|
|
max_chunk = chunk;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (buf_chunk_all_free(chunk)) {
|
|
|
|
max_free_size = chunk->size;
|
|
|
|
max_free_chunk = chunk;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-11-14 15:27:26 +01:00
|
|
|
|
2006-11-21 15:40:14 +01:00
|
|
|
if (!max_free_size) {
|
2006-11-14 15:27:26 +01:00
|
|
|
|
2006-11-21 15:40:14 +01:00
|
|
|
ulint dirty = 0;
|
|
|
|
ulint nonfree = 0;
|
|
|
|
buf_block_t* block;
|
|
|
|
buf_block_t* bend;
|
2006-11-14 15:27:26 +01:00
|
|
|
|
2006-11-21 15:40:14 +01:00
|
|
|
/* Cannot shrink: try again later
|
|
|
|
(do not assign srv_buf_pool_old_size) */
|
|
|
|
if (!max_chunk) {
|
2006-11-14 15:27:26 +01:00
|
|
|
|
2006-11-21 15:40:14 +01:00
|
|
|
goto func_exit;
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
2006-11-21 15:40:14 +01:00
|
|
|
block = max_chunk->blocks;
|
|
|
|
bend = block + max_chunk->size;
|
|
|
|
|
|
|
|
/* Move the blocks of chunk to the end of the
|
|
|
|
LRU list and try to flush them. */
|
|
|
|
for (; block < bend; block++) {
|
2006-11-23 14:26:01 +01:00
|
|
|
switch (buf_block_get_state(block)) {
|
2006-11-21 15:40:14 +01:00
|
|
|
case BUF_BLOCK_NOT_USED:
|
|
|
|
continue;
|
|
|
|
case BUF_BLOCK_FILE_PAGE:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
nonfree++;
|
|
|
|
continue;
|
2006-11-14 15:27:26 +01:00
|
|
|
}
|
2006-11-21 15:40:14 +01:00
|
|
|
|
|
|
|
mutex_enter(&block->mutex);
|
|
|
|
/* The following calls will temporarily
|
|
|
|
release block->mutex and buf_pool->mutex.
|
|
|
|
Therefore, we have to always retry,
|
|
|
|
even if !dirty && !nonfree. */
|
|
|
|
|
2006-11-30 13:27:49 +01:00
|
|
|
if (!buf_flush_ready_for_replace(&block->page)) {
|
2006-11-21 15:40:14 +01:00
|
|
|
|
2006-11-30 13:27:49 +01:00
|
|
|
buf_LRU_make_block_old(&block->page);
|
2006-11-21 15:40:14 +01:00
|
|
|
dirty++;
|
2006-12-15 16:05:18 +01:00
|
|
|
} else if (!buf_LRU_free_block(&block->page, TRUE)) {
|
2006-11-21 15:40:14 +01:00
|
|
|
nonfree++;
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_exit(&block->mutex);
|
2006-11-14 15:27:26 +01:00
|
|
|
}
|
|
|
|
|
2006-11-21 15:40:14 +01:00
|
|
|
mutex_exit(&buf_pool->mutex);
|
2006-11-15 22:49:14 +01:00
|
|
|
|
2006-11-21 15:40:14 +01:00
|
|
|
/* Request for a flush of the chunk if it helps.
|
|
|
|
Do not flush if there are non-free blocks, since
|
|
|
|
flushing will not make the chunk freeable. */
|
|
|
|
if (nonfree) {
|
|
|
|
/* Avoid busy-waiting. */
|
|
|
|
os_thread_sleep(100000);
|
|
|
|
} else if (dirty
|
2006-11-24 14:05:01 +01:00
|
|
|
&& buf_flush_batch(BUF_FLUSH_LRU, dirty, 0)
|
2006-11-21 15:40:14 +01:00
|
|
|
== ULINT_UNDEFINED) {
|
|
|
|
|
|
|
|
buf_flush_wait_batch_end(BUF_FLUSH_LRU);
|
|
|
|
}
|
2006-11-14 15:27:26 +01:00
|
|
|
|
2006-11-21 15:40:14 +01:00
|
|
|
goto try_again;
|
|
|
|
}
|
2006-11-15 22:49:14 +01:00
|
|
|
|
2006-11-21 15:40:14 +01:00
|
|
|
max_size = max_free_size;
|
|
|
|
max_chunk = max_free_chunk;
|
2006-11-15 22:49:14 +01:00
|
|
|
|
2006-11-21 15:40:14 +01:00
|
|
|
srv_buf_pool_old_size = srv_buf_pool_size;
|
2006-11-15 22:49:14 +01:00
|
|
|
|
2006-11-21 15:40:14 +01:00
|
|
|
/* Rewrite buf_pool->chunks. Copy everything but max_chunk. */
|
|
|
|
chunks = mem_alloc((buf_pool->n_chunks - 1) * sizeof *chunks);
|
|
|
|
memcpy(chunks, buf_pool->chunks,
|
|
|
|
(max_chunk - buf_pool->chunks) * sizeof *chunks);
|
|
|
|
memcpy(chunks + (max_chunk - buf_pool->chunks),
|
|
|
|
max_chunk + 1,
|
|
|
|
buf_pool->chunks + buf_pool->n_chunks
|
|
|
|
- (max_chunk + 1));
|
|
|
|
ut_a(buf_pool->curr_size > max_chunk->size);
|
|
|
|
buf_pool->curr_size -= max_chunk->size;
|
|
|
|
srv_buf_pool_curr_size = buf_pool->curr_size * UNIV_PAGE_SIZE;
|
|
|
|
chunk_size -= max_chunk->size;
|
|
|
|
buf_chunk_free(max_chunk);
|
|
|
|
mem_free(buf_pool->chunks);
|
|
|
|
buf_pool->chunks = chunks;
|
|
|
|
buf_pool->n_chunks--;
|
2006-11-15 22:49:14 +01:00
|
|
|
|
2006-11-21 15:40:14 +01:00
|
|
|
/* Allow a slack of one megabyte. */
|
|
|
|
if (chunk_size > 1048576 / UNIV_PAGE_SIZE) {
|
2006-11-15 22:49:14 +01:00
|
|
|
|
2006-11-21 15:40:14 +01:00
|
|
|
goto shrink_again;
|
|
|
|
}
|
2006-11-15 22:49:14 +01:00
|
|
|
|
2006-11-21 15:40:14 +01:00
|
|
|
func_done:
|
|
|
|
srv_buf_pool_old_size = srv_buf_pool_size;
|
|
|
|
func_exit:
|
|
|
|
mutex_exit(&buf_pool->mutex);
|
|
|
|
btr_search_enable();
|
|
|
|
}
|
2006-11-14 15:27:26 +01:00
|
|
|
|
2006-11-21 16:38:18 +01:00
|
|
|
/************************************************************************
|
|
|
|
Rebuild buf_pool->page_hash. */
|
|
|
|
static
|
|
|
|
void
|
|
|
|
buf_pool_page_hash_rebuild(void)
|
|
|
|
/*============================*/
|
|
|
|
{
|
|
|
|
ulint i;
|
|
|
|
ulint n_chunks;
|
|
|
|
buf_chunk_t* chunk;
|
|
|
|
hash_table_t* page_hash;
|
2007-01-05 11:49:56 +01:00
|
|
|
hash_table_t* zip_hash;
|
|
|
|
buf_page_t* b;
|
2006-11-21 16:38:18 +01:00
|
|
|
|
|
|
|
mutex_enter(&buf_pool->mutex);
|
|
|
|
|
|
|
|
/* Free, create, and populate the hash table. */
|
|
|
|
hash_table_free(buf_pool->page_hash);
|
|
|
|
buf_pool->page_hash = page_hash = hash_create(2 * buf_pool->curr_size);
|
2007-01-05 11:49:56 +01:00
|
|
|
zip_hash = hash_create(2 * buf_pool->curr_size);
|
|
|
|
|
|
|
|
HASH_MIGRATE(buf_pool->zip_hash, zip_hash, buf_page_t, hash,
|
|
|
|
BUF_POOL_ZIP_FOLD_BPAGE);
|
|
|
|
|
|
|
|
hash_table_free(buf_pool->zip_hash);
|
|
|
|
buf_pool->zip_hash = zip_hash;
|
|
|
|
|
|
|
|
/* Insert the uncompressed file pages to buf_pool->page_hash. */
|
2006-11-21 16:38:18 +01:00
|
|
|
|
|
|
|
chunk = buf_pool->chunks;
|
|
|
|
n_chunks = buf_pool->n_chunks;
|
|
|
|
|
|
|
|
for (i = 0; i < n_chunks; i++, chunk++) {
|
|
|
|
ulint j;
|
|
|
|
buf_block_t* block = chunk->blocks;
|
|
|
|
|
|
|
|
for (j = 0; j < chunk->size; j++, block++) {
|
2006-11-23 14:26:01 +01:00
|
|
|
if (buf_block_get_state(block)
|
|
|
|
== BUF_BLOCK_FILE_PAGE) {
|
2007-01-24 11:36:05 +01:00
|
|
|
ut_ad(!block->page.in_zip_hash);
|
|
|
|
ut_ad(block->page.in_page_hash);
|
|
|
|
|
2006-11-29 14:23:28 +01:00
|
|
|
HASH_INSERT(buf_page_t, hash, page_hash,
|
2006-11-21 16:38:18 +01:00
|
|
|
buf_page_address_fold(
|
2006-11-24 09:32:18 +01:00
|
|
|
block->page.space,
|
|
|
|
block->page.offset),
|
2006-11-29 14:23:28 +01:00
|
|
|
&block->page);
|
2006-11-21 16:38:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-01-05 11:49:56 +01:00
|
|
|
/* Insert the compressed-only pages to buf_pool->page_hash.
|
|
|
|
All such blocks are either in buf_pool->zip_clean or
|
|
|
|
in buf_pool->flush_list. */
|
|
|
|
|
|
|
|
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);
|
2007-01-09 13:35:42 +01:00
|
|
|
ut_ad(!b->in_flush_list);
|
2007-01-24 11:36:05 +01:00
|
|
|
ut_ad(b->in_LRU_list);
|
|
|
|
ut_ad(b->in_page_hash);
|
|
|
|
ut_ad(!b->in_zip_hash);
|
2007-01-05 11:49:56 +01:00
|
|
|
|
|
|
|
HASH_INSERT(buf_page_t, hash, page_hash,
|
|
|
|
buf_page_address_fold(b->space, b->offset), b);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (b = UT_LIST_GET_FIRST(buf_pool->flush_list); b;
|
|
|
|
b = UT_LIST_GET_NEXT(list, b)) {
|
2007-01-09 13:35:42 +01:00
|
|
|
ut_ad(b->in_flush_list);
|
2007-01-24 11:36:05 +01:00
|
|
|
ut_ad(b->in_LRU_list);
|
|
|
|
ut_ad(b->in_page_hash);
|
|
|
|
ut_ad(!b->in_zip_hash);
|
2007-01-09 13:35:42 +01:00
|
|
|
|
2007-01-05 11:49:56 +01:00
|
|
|
switch (buf_page_get_state(b)) {
|
|
|
|
case BUF_BLOCK_ZIP_DIRTY:
|
|
|
|
HASH_INSERT(buf_page_t, hash, page_hash,
|
|
|
|
buf_page_address_fold(b->space,
|
|
|
|
b->offset), b);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-11-21 16:38:18 +01:00
|
|
|
mutex_exit(&buf_pool->mutex);
|
|
|
|
}
|
|
|
|
|
2006-11-21 15:40:14 +01:00
|
|
|
/************************************************************************
|
|
|
|
Resizes the buffer pool. */
|
2006-11-15 22:49:14 +01:00
|
|
|
|
2006-11-21 15:40:14 +01:00
|
|
|
void
|
|
|
|
buf_pool_resize(void)
|
|
|
|
/*=================*/
|
|
|
|
{
|
|
|
|
mutex_enter(&buf_pool->mutex);
|
2006-11-14 15:27:26 +01:00
|
|
|
|
2006-11-21 15:40:14 +01:00
|
|
|
if (srv_buf_pool_old_size == srv_buf_pool_size) {
|
|
|
|
|
|
|
|
mutex_exit(&buf_pool->mutex);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (srv_buf_pool_curr_size + 1048576 > srv_buf_pool_size) {
|
|
|
|
|
|
|
|
mutex_exit(&buf_pool->mutex);
|
|
|
|
|
|
|
|
/* Disable adaptive hash indexes and empty the index
|
|
|
|
in order to free up memory in the buffer pool chunks. */
|
|
|
|
buf_pool_shrink((srv_buf_pool_curr_size - srv_buf_pool_size)
|
|
|
|
/ UNIV_PAGE_SIZE);
|
2006-11-14 15:27:26 +01:00
|
|
|
} else if (srv_buf_pool_curr_size + 1048576 < srv_buf_pool_size) {
|
|
|
|
|
|
|
|
/* Enlarge the buffer pool by at least one megabyte */
|
|
|
|
|
|
|
|
ulint mem_size
|
|
|
|
= srv_buf_pool_size - srv_buf_pool_curr_size;
|
2006-11-21 15:40:14 +01:00
|
|
|
buf_chunk_t* chunks;
|
|
|
|
buf_chunk_t* chunk;
|
2006-11-14 15:27:26 +01:00
|
|
|
|
|
|
|
chunks = mem_alloc((buf_pool->n_chunks + 1) * sizeof *chunks);
|
|
|
|
|
|
|
|
memcpy(chunks, buf_pool->chunks, buf_pool->n_chunks
|
|
|
|
* sizeof *chunks);
|
|
|
|
|
|
|
|
chunk = &chunks[buf_pool->n_chunks];
|
|
|
|
|
|
|
|
if (!buf_chunk_init(chunk, mem_size)) {
|
|
|
|
mem_free(chunks);
|
|
|
|
} else {
|
|
|
|
buf_pool->curr_size += chunk->size;
|
|
|
|
srv_buf_pool_curr_size = buf_pool->curr_size
|
|
|
|
* UNIV_PAGE_SIZE;
|
|
|
|
mem_free(buf_pool->chunks);
|
|
|
|
buf_pool->chunks = chunks;
|
|
|
|
buf_pool->n_chunks++;
|
|
|
|
}
|
2006-11-21 15:40:14 +01:00
|
|
|
|
|
|
|
srv_buf_pool_old_size = srv_buf_pool_size;
|
|
|
|
mutex_exit(&buf_pool->mutex);
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
2006-11-21 16:38:18 +01:00
|
|
|
buf_pool_page_hash_rebuild();
|
2006-02-23 20:25:29 +01:00
|
|
|
}
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
Moves to the block to the start of the LRU list if there is a danger
|
|
|
|
that the block would drift out of the buffer pool. */
|
|
|
|
UNIV_INLINE
|
|
|
|
void
|
|
|
|
buf_block_make_young(
|
|
|
|
/*=================*/
|
2006-11-30 13:27:49 +01:00
|
|
|
buf_page_t* bpage) /* in: block to make younger */
|
2005-10-27 09:29:40 +02:00
|
|
|
{
|
2006-11-10 12:15:59 +01:00
|
|
|
ut_ad(!mutex_own(&(buf_pool->mutex)));
|
|
|
|
|
|
|
|
/* Note that we read freed_page_clock's without holding any mutex:
|
|
|
|
this is allowed since the result is used only in heuristics */
|
|
|
|
|
2006-11-30 13:27:49 +01:00
|
|
|
if (buf_pool->freed_page_clock
|
|
|
|
>= buf_page_get_freed_page_clock(bpage)
|
|
|
|
+ 1 + (buf_pool->curr_size / 4)) {
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-10 12:15:59 +01:00
|
|
|
mutex_enter(&buf_pool->mutex);
|
2005-10-27 09:29:40 +02:00
|
|
|
/* There has been freeing activity in the LRU list:
|
|
|
|
best to move to the head of the LRU list */
|
|
|
|
|
2006-11-30 13:27:49 +01:00
|
|
|
buf_LRU_make_block_young(bpage);
|
2006-11-10 12:15:59 +01:00
|
|
|
mutex_exit(&buf_pool->mutex);
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
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 from slipping out of
|
|
|
|
the buffer pool. */
|
|
|
|
|
|
|
|
void
|
|
|
|
buf_page_make_young(
|
2006-02-23 20:25:29 +01:00
|
|
|
/*================*/
|
2006-11-30 13:27:49 +01:00
|
|
|
buf_page_t* bpage) /* in: buffer block of a file page */
|
2005-10-27 09:29:40 +02:00
|
|
|
{
|
|
|
|
mutex_enter(&(buf_pool->mutex));
|
|
|
|
|
2006-11-30 16:09:33 +01:00
|
|
|
ut_a(buf_page_in_file(bpage));
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-30 13:27:49 +01:00
|
|
|
buf_LRU_make_block_young(bpage);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
mutex_exit(&(buf_pool->mutex));
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
Resets the check_index_page_at_flush field of a page if found in the buffer
|
|
|
|
pool. */
|
|
|
|
|
|
|
|
void
|
|
|
|
buf_reset_check_index_page_at_flush(
|
|
|
|
/*================================*/
|
|
|
|
ulint space, /* in: space id */
|
|
|
|
ulint offset) /* in: page number */
|
|
|
|
{
|
|
|
|
buf_block_t* block;
|
|
|
|
|
|
|
|
mutex_enter_fast(&(buf_pool->mutex));
|
|
|
|
|
2006-11-29 14:23:28 +01:00
|
|
|
block = (buf_block_t*) buf_page_hash_get(space, offset);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-29 14:23:28 +01:00
|
|
|
if (block && buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE) {
|
2005-10-27 09:29:40 +02:00
|
|
|
block->check_index_page_at_flush = FALSE;
|
|
|
|
}
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
mutex_exit(&(buf_pool->mutex));
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
Returns the current state of is_hashed of a page. FALSE if the page is
|
|
|
|
not in the pool. NOTE that this operation does not fix the page in the
|
|
|
|
pool if it is found there. */
|
|
|
|
|
|
|
|
ibool
|
|
|
|
buf_page_peek_if_search_hashed(
|
|
|
|
/*===========================*/
|
|
|
|
/* out: TRUE if page hash index is built in search
|
|
|
|
system */
|
|
|
|
ulint space, /* in: space id */
|
|
|
|
ulint offset) /* in: page number */
|
|
|
|
{
|
|
|
|
buf_block_t* block;
|
|
|
|
ibool is_hashed;
|
|
|
|
|
|
|
|
mutex_enter_fast(&(buf_pool->mutex));
|
|
|
|
|
2006-11-29 14:23:28 +01:00
|
|
|
block = (buf_block_t*) buf_page_hash_get(space, offset);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-29 14:23:28 +01:00
|
|
|
if (!block || buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE) {
|
2005-10-27 09:29:40 +02:00
|
|
|
is_hashed = FALSE;
|
|
|
|
} else {
|
|
|
|
is_hashed = block->is_hashed;
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_exit(&(buf_pool->mutex));
|
|
|
|
|
|
|
|
return(is_hashed);
|
|
|
|
}
|
|
|
|
|
2006-11-16 09:48:28 +01:00
|
|
|
#ifdef UNIV_DEBUG_FILE_ACCESSES
|
2005-10-27 09:29:40 +02:00
|
|
|
/************************************************************************
|
|
|
|
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. */
|
|
|
|
|
2006-11-29 14:23:28 +01:00
|
|
|
buf_page_t*
|
2005-10-27 09:29:40 +02:00
|
|
|
buf_page_set_file_page_was_freed(
|
|
|
|
/*=============================*/
|
2006-11-29 14:23:28 +01:00
|
|
|
/* out: control block if found in page hash table,
|
2005-10-27 09:29:40 +02:00
|
|
|
otherwise NULL */
|
|
|
|
ulint space, /* in: space id */
|
|
|
|
ulint offset) /* in: page number */
|
|
|
|
{
|
2006-11-29 14:23:28 +01:00
|
|
|
buf_page_t* bpage;
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
mutex_enter_fast(&(buf_pool->mutex));
|
|
|
|
|
2006-11-29 14:23:28 +01:00
|
|
|
bpage = buf_page_hash_get(space, offset);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-29 14:23:28 +01:00
|
|
|
if (bpage) {
|
|
|
|
bpage->file_page_was_freed = TRUE;
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
mutex_exit(&(buf_pool->mutex));
|
|
|
|
|
2006-11-29 14:23:28 +01:00
|
|
|
return(bpage);
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
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. */
|
|
|
|
|
2006-11-29 14:23:28 +01:00
|
|
|
buf_page_t*
|
2005-10-27 09:29:40 +02:00
|
|
|
buf_page_reset_file_page_was_freed(
|
|
|
|
/*===============================*/
|
2006-11-29 14:23:28 +01:00
|
|
|
/* out: control block if found in page hash table,
|
2005-10-27 09:29:40 +02:00
|
|
|
otherwise NULL */
|
|
|
|
ulint space, /* in: space id */
|
|
|
|
ulint offset) /* in: page number */
|
|
|
|
{
|
2006-11-29 14:23:28 +01:00
|
|
|
buf_page_t* bpage;
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
mutex_enter_fast(&(buf_pool->mutex));
|
|
|
|
|
2006-11-29 14:23:28 +01:00
|
|
|
bpage = buf_page_hash_get(space, offset);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-29 14:23:28 +01:00
|
|
|
if (bpage) {
|
|
|
|
bpage->file_page_was_freed = FALSE;
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
mutex_exit(&(buf_pool->mutex));
|
|
|
|
|
2006-11-29 14:23:28 +01:00
|
|
|
return(bpage);
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
2006-11-16 09:48:28 +01:00
|
|
|
#endif /* UNIV_DEBUG_FILE_ACCESSES */
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2007-01-19 00:10:49 +01:00
|
|
|
/************************************************************************
|
|
|
|
Get read access to a compressed page (usually FIL_PAGE_TYPE_ZBLOB). */
|
|
|
|
|
|
|
|
buf_page_t*
|
|
|
|
buf_page_get_zip(
|
|
|
|
/*=============*/
|
|
|
|
/* out: pointer to the block */
|
|
|
|
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;
|
|
|
|
|
|
|
|
#ifndef UNIV_LOG_DEBUG
|
|
|
|
ut_ad(!ibuf_inside());
|
|
|
|
#endif
|
|
|
|
buf_pool->n_page_gets++;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
mutex_enter_fast(&buf_pool->mutex);
|
|
|
|
lookup:
|
|
|
|
bpage = buf_page_hash_get(space, offset);
|
|
|
|
if (bpage) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Page not in buf_pool: needs to be read from file */
|
|
|
|
|
|
|
|
mutex_exit(&buf_pool->mutex);
|
|
|
|
|
|
|
|
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. */
|
|
|
|
mutex_exit(&buf_pool->mutex);
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
block_mutex = buf_page_get_mutex(bpage);
|
|
|
|
mutex_enter(block_mutex);
|
|
|
|
|
|
|
|
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:
|
|
|
|
ut_error;
|
|
|
|
break;
|
|
|
|
case BUF_BLOCK_ZIP_PAGE:
|
|
|
|
case BUF_BLOCK_ZIP_DIRTY:
|
|
|
|
bpage->buf_fix_count++;
|
|
|
|
break;
|
|
|
|
case BUF_BLOCK_FILE_PAGE:
|
|
|
|
/* 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__);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
must_read = buf_page_get_io_fix(bpage) == BUF_IO_READ;
|
|
|
|
|
|
|
|
mutex_exit(&buf_pool->mutex);
|
|
|
|
|
|
|
|
buf_page_set_accessed(bpage, TRUE);
|
|
|
|
|
|
|
|
mutex_exit(block_mutex);
|
|
|
|
|
|
|
|
buf_block_make_young(bpage);
|
|
|
|
|
|
|
|
#ifdef UNIV_DEBUG_FILE_ACCESSES
|
|
|
|
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_DEBUG
|
|
|
|
ut_a(ibuf_count_get(buf_page_get_space(bpage),
|
|
|
|
buf_page_get_page_no(bpage)) == 0);
|
|
|
|
#endif
|
|
|
|
return(bpage);
|
|
|
|
}
|
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
/************************************************************************
|
|
|
|
This is the general function used to get access to a database page. */
|
|
|
|
|
2006-10-12 13:05:22 +02:00
|
|
|
buf_block_t*
|
2005-10-27 09:29:40 +02:00
|
|
|
buf_page_get_gen(
|
|
|
|
/*=============*/
|
2006-10-12 13:05:22 +02:00
|
|
|
/* out: pointer to the block or NULL */
|
2005-10-27 09:29:40 +02:00
|
|
|
ulint space, /* in: space id */
|
2007-01-18 10:59:00 +01:00
|
|
|
ulint zip_size,/* in: compressed page size in bytes
|
|
|
|
or 0 for uncompressed pages */
|
2005-10-27 09:29:40 +02:00
|
|
|
ulint offset, /* in: page number */
|
|
|
|
ulint rw_latch,/* in: RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */
|
2006-10-23 21:34:45 +02:00
|
|
|
buf_block_t* guess, /* in: guessed block or NULL */
|
2005-10-27 09:29:40 +02:00
|
|
|
ulint mode, /* in: BUF_GET, BUF_GET_IF_IN_POOL,
|
|
|
|
BUF_GET_NO_LATCH, BUF_GET_NOWAIT */
|
|
|
|
const char* file, /* in: file name */
|
|
|
|
ulint line, /* in: line where called */
|
|
|
|
mtr_t* mtr) /* in: mini-transaction */
|
|
|
|
{
|
|
|
|
buf_block_t* block;
|
|
|
|
ibool accessed;
|
|
|
|
ulint fix_type;
|
|
|
|
ibool success;
|
|
|
|
ibool must_read;
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
ut_ad(mtr);
|
|
|
|
ut_ad((rw_latch == RW_S_LATCH)
|
2006-08-29 11:30:31 +02:00
|
|
|
|| (rw_latch == RW_X_LATCH)
|
|
|
|
|| (rw_latch == RW_NO_LATCH));
|
2005-10-27 09:29:40 +02:00
|
|
|
ut_ad((mode != BUF_GET_NO_LATCH) || (rw_latch == RW_NO_LATCH));
|
|
|
|
ut_ad((mode == BUF_GET) || (mode == BUF_GET_IF_IN_POOL)
|
2006-08-29 11:30:31 +02:00
|
|
|
|| (mode == BUF_GET_NO_LATCH) || (mode == BUF_GET_NOWAIT));
|
2007-01-18 10:59:00 +01:00
|
|
|
ut_ad(zip_size == fil_space_get_zip_size(space));
|
2005-10-27 09:29:40 +02:00
|
|
|
#ifndef UNIV_LOG_DEBUG
|
2006-12-29 10:07:01 +01:00
|
|
|
ut_ad(!ibuf_inside() || ibuf_page(space, zip_size, offset));
|
2005-10-27 09:29:40 +02:00
|
|
|
#endif
|
|
|
|
buf_pool->n_page_gets++;
|
|
|
|
loop:
|
|
|
|
block = NULL;
|
2006-11-10 12:15:59 +01:00
|
|
|
mutex_enter_fast(&(buf_pool->mutex));
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
if (guess) {
|
2006-10-23 21:34:45 +02:00
|
|
|
block = guess;
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-24 09:32:18 +01:00
|
|
|
if (offset != block->page.offset
|
2007-01-02 22:25:40 +01:00
|
|
|
|| space != block->page.space
|
|
|
|
|| !buf_page_in_file(&block->page)) {
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2007-01-02 22:25:40 +01:00
|
|
|
block = guess = NULL;
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (block == NULL) {
|
2006-11-29 14:23:28 +01:00
|
|
|
block = (buf_block_t*) buf_page_hash_get(space, offset);
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
2006-11-29 14:23:28 +01:00
|
|
|
if (block == NULL
|
|
|
|
|| UNIV_UNLIKELY(buf_block_get_state(block)
|
|
|
|
!= BUF_BLOCK_FILE_PAGE)) {
|
2007-01-05 15:03:44 +01:00
|
|
|
/* Uncompressed page not in buf_pool: needs to be
|
|
|
|
decompressed or read from file */
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
mutex_exit(&(buf_pool->mutex));
|
|
|
|
|
2007-01-05 15:03:44 +01:00
|
|
|
if (!block && mode == BUF_GET_IF_IN_POOL) {
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
|
2006-12-29 10:07:01 +01:00
|
|
|
buf_read_page(space, zip_size, offset);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-16 10:00:30 +01:00
|
|
|
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
|
|
|
|
ut_a(++buf_dbg_counter % 37 || buf_validate());
|
|
|
|
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
|
2005-10-27 09:29:40 +02:00
|
|
|
goto loop;
|
|
|
|
}
|
|
|
|
|
2006-11-10 12:15:59 +01:00
|
|
|
mutex_enter(&block->mutex);
|
|
|
|
|
2006-11-23 14:26:01 +01:00
|
|
|
ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-30 13:27:49 +01:00
|
|
|
must_read = buf_block_get_io_fix(block) == BUF_IO_READ;
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2006-11-30 13:27:49 +01:00
|
|
|
if (must_read && mode == BUF_GET_IF_IN_POOL) {
|
|
|
|
/* The page is only being read to buffer */
|
|
|
|
mutex_exit(&buf_pool->mutex);
|
|
|
|
mutex_exit(&block->mutex);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-30 13:27:49 +01:00
|
|
|
return(NULL);
|
2006-02-23 20:25:29 +01:00
|
|
|
}
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-30 10:24:57 +01:00
|
|
|
buf_block_buf_fix_inc(block, file, line);
|
2006-11-10 12:15:59 +01:00
|
|
|
mutex_exit(&buf_pool->mutex);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
/* Check if this is the first access to the page */
|
|
|
|
|
2006-11-30 13:27:49 +01:00
|
|
|
accessed = buf_page_is_accessed(&block->page);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-30 13:27:49 +01:00
|
|
|
buf_page_set_accessed(&block->page, TRUE);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-10 12:15:59 +01:00
|
|
|
mutex_exit(&block->mutex);
|
|
|
|
|
2006-11-30 13:27:49 +01:00
|
|
|
buf_block_make_young(&block->page);
|
2006-11-10 12:15:59 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
#ifdef UNIV_DEBUG_FILE_ACCESSES
|
2006-11-29 14:23:28 +01:00
|
|
|
ut_a(!block->page.file_page_was_freed);
|
2006-02-23 20:25:29 +01:00
|
|
|
#endif
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-16 10:00:30 +01:00
|
|
|
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
|
|
|
|
ut_a(++buf_dbg_counter % 5771 || buf_validate());
|
2006-11-30 13:27:49 +01:00
|
|
|
ut_a(block->page.buf_fix_count > 0);
|
2006-11-23 15:12:58 +01:00
|
|
|
ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
|
2006-11-16 10:00:30 +01:00
|
|
|
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
if (mode == BUF_GET_NOWAIT) {
|
|
|
|
if (rw_latch == RW_S_LATCH) {
|
|
|
|
success = rw_lock_s_lock_func_nowait(&(block->lock),
|
2006-08-29 11:30:31 +02:00
|
|
|
file, line);
|
2005-10-27 09:29:40 +02:00
|
|
|
fix_type = MTR_MEMO_PAGE_S_FIX;
|
|
|
|
} else {
|
|
|
|
ut_ad(rw_latch == RW_X_LATCH);
|
|
|
|
success = rw_lock_x_lock_func_nowait(&(block->lock),
|
2006-08-29 11:30:31 +02:00
|
|
|
file, line);
|
2005-10-27 09:29:40 +02:00
|
|
|
fix_type = MTR_MEMO_PAGE_X_FIX;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!success) {
|
2006-11-10 12:15:59 +01:00
|
|
|
mutex_enter(&block->mutex);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-30 13:27:49 +01:00
|
|
|
block->page.buf_fix_count--;
|
2006-11-10 12:15:59 +01:00
|
|
|
|
|
|
|
mutex_exit(&block->mutex);
|
2005-10-27 09:29:40 +02:00
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
|
|
rw_lock_s_unlock(&(block->debug_latch));
|
2006-02-23 20:25:29 +01:00
|
|
|
#endif
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
} else if (rw_latch == RW_NO_LATCH) {
|
|
|
|
|
|
|
|
if (must_read) {
|
2006-02-23 20:25:29 +01:00
|
|
|
/* Let us wait until the read operation
|
2005-10-27 09:29:40 +02:00
|
|
|
completes */
|
|
|
|
|
2006-02-23 20:25:29 +01:00
|
|
|
for (;;) {
|
2006-11-30 13:27:49 +01:00
|
|
|
enum buf_io_fix io_fix;
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-30 13:27:49 +01:00
|
|
|
mutex_enter(&block->mutex);
|
|
|
|
io_fix = buf_block_get_io_fix(block);
|
|
|
|
mutex_exit(&block->mutex);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-30 13:27:49 +01:00
|
|
|
if (io_fix == BUF_IO_READ) {
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-10 12:15:59 +01:00
|
|
|
os_thread_sleep(WAIT_FOR_READ);
|
2006-12-20 15:07:08 +01:00
|
|
|
} else {
|
|
|
|
break;
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fix_type = MTR_MEMO_BUF_FIX;
|
|
|
|
} else if (rw_latch == RW_S_LATCH) {
|
|
|
|
|
|
|
|
rw_lock_s_lock_func(&(block->lock), 0, file, line);
|
|
|
|
|
|
|
|
fix_type = MTR_MEMO_PAGE_S_FIX;
|
|
|
|
} else {
|
|
|
|
rw_lock_x_lock_func(&(block->lock), 0, file, line);
|
|
|
|
|
|
|
|
fix_type = MTR_MEMO_PAGE_X_FIX;
|
|
|
|
}
|
|
|
|
|
|
|
|
mtr_memo_push(mtr, block, fix_type);
|
|
|
|
|
|
|
|
if (!accessed) {
|
|
|
|
/* In the case of a first access, try to apply linear
|
|
|
|
read-ahead */
|
|
|
|
|
2006-12-29 10:07:01 +01:00
|
|
|
buf_read_ahead_linear(space, zip_size, offset);
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef UNIV_IBUF_DEBUG
|
2006-11-24 13:49:59 +01:00
|
|
|
ut_a(ibuf_count_get(buf_block_get_space(block),
|
|
|
|
buf_block_get_page_no(block)) == 0);
|
2005-10-27 09:29:40 +02:00
|
|
|
#endif
|
2006-10-12 13:05:22 +02:00
|
|
|
return(block);
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
This is the general function used to get optimistic access to a database
|
|
|
|
page. */
|
|
|
|
|
|
|
|
ibool
|
|
|
|
buf_page_optimistic_get_func(
|
|
|
|
/*=========================*/
|
|
|
|
/* out: TRUE if success */
|
|
|
|
ulint rw_latch,/* in: RW_S_LATCH, RW_X_LATCH */
|
|
|
|
buf_block_t* block, /* in: guessed buffer block */
|
2006-11-29 15:52:16 +01:00
|
|
|
ib_uint64_t modify_clock,/* in: modify clock value if mode is
|
2005-10-27 09:29:40 +02:00
|
|
|
..._GUESS_ON_CLOCK */
|
|
|
|
const char* file, /* in: file name */
|
|
|
|
ulint line, /* in: line where called */
|
|
|
|
mtr_t* mtr) /* in: mini-transaction */
|
|
|
|
{
|
|
|
|
ibool accessed;
|
|
|
|
ibool success;
|
|
|
|
ulint fix_type;
|
|
|
|
|
|
|
|
ut_ad(mtr && block);
|
|
|
|
ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH));
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2006-11-10 12:15:59 +01:00
|
|
|
mutex_enter(&block->mutex);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-23 14:26:01 +01:00
|
|
|
if (UNIV_UNLIKELY(buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE)) {
|
2006-11-10 12:15:59 +01:00
|
|
|
|
|
|
|
mutex_exit(&block->mutex);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
|
2006-11-30 10:24:57 +01:00
|
|
|
buf_block_buf_fix_inc(block, file, line);
|
2006-11-30 13:27:49 +01:00
|
|
|
accessed = buf_page_is_accessed(&block->page);
|
|
|
|
buf_page_set_accessed(&block->page, TRUE);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-10 12:15:59 +01:00
|
|
|
mutex_exit(&block->mutex);
|
|
|
|
|
2006-11-30 13:27:49 +01:00
|
|
|
buf_block_make_young(&block->page);
|
2006-11-10 12:15:59 +01:00
|
|
|
|
|
|
|
/* Check if this is the first access to the page */
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-10-19 13:07:50 +02:00
|
|
|
ut_ad(!ibuf_inside()
|
2006-11-24 13:49:59 +01:00
|
|
|
|| ibuf_page(buf_block_get_space(block),
|
|
|
|
buf_block_get_zip_size(block),
|
|
|
|
buf_block_get_page_no(block)));
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
if (rw_latch == RW_S_LATCH) {
|
|
|
|
success = rw_lock_s_lock_func_nowait(&(block->lock),
|
2006-08-29 11:30:31 +02:00
|
|
|
file, line);
|
2005-10-27 09:29:40 +02:00
|
|
|
fix_type = MTR_MEMO_PAGE_S_FIX;
|
|
|
|
} else {
|
|
|
|
success = rw_lock_x_lock_func_nowait(&(block->lock),
|
2006-08-29 11:30:31 +02:00
|
|
|
file, line);
|
2005-10-27 09:29:40 +02:00
|
|
|
fix_type = MTR_MEMO_PAGE_X_FIX;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (UNIV_UNLIKELY(!success)) {
|
2006-11-10 12:15:59 +01:00
|
|
|
mutex_enter(&block->mutex);
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2006-11-30 13:27:49 +01:00
|
|
|
block->page.buf_fix_count--;
|
2006-11-10 12:15:59 +01:00
|
|
|
|
|
|
|
mutex_exit(&block->mutex);
|
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
|
|
rw_lock_s_unlock(&(block->debug_latch));
|
|
|
|
#endif
|
2006-11-10 12:15:59 +01:00
|
|
|
return(FALSE);
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
2006-11-24 14:05:01 +01:00
|
|
|
if (UNIV_UNLIKELY(modify_clock != block->modify_clock)) {
|
2005-10-27 09:29:40 +02:00
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
2006-10-12 13:05:22 +02:00
|
|
|
buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
|
2005-10-27 09:29:40 +02:00
|
|
|
#endif /* UNIV_SYNC_DEBUG */
|
|
|
|
if (rw_latch == RW_S_LATCH) {
|
|
|
|
rw_lock_s_unlock(&(block->lock));
|
|
|
|
} else {
|
|
|
|
rw_lock_x_unlock(&(block->lock));
|
|
|
|
}
|
|
|
|
|
2006-11-10 12:15:59 +01:00
|
|
|
mutex_enter(&block->mutex);
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2006-11-30 13:27:49 +01:00
|
|
|
block->page.buf_fix_count--;
|
2006-11-10 12:15:59 +01:00
|
|
|
|
|
|
|
mutex_exit(&block->mutex);
|
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
|
|
rw_lock_s_unlock(&(block->debug_latch));
|
|
|
|
#endif
|
2006-11-10 12:15:59 +01:00
|
|
|
return(FALSE);
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
mtr_memo_push(mtr, block, fix_type);
|
|
|
|
|
2006-11-16 10:00:30 +01:00
|
|
|
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
|
|
|
|
ut_a(++buf_dbg_counter % 5771 || buf_validate());
|
2006-11-30 13:27:49 +01:00
|
|
|
ut_a(block->page.buf_fix_count > 0);
|
2006-11-23 15:12:58 +01:00
|
|
|
ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
|
2006-11-16 10:00:30 +01:00
|
|
|
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
#ifdef UNIV_DEBUG_FILE_ACCESSES
|
2006-11-29 14:23:28 +01:00
|
|
|
ut_a(block->page.file_page_was_freed == FALSE);
|
2005-10-27 09:29:40 +02:00
|
|
|
#endif
|
|
|
|
if (UNIV_UNLIKELY(!accessed)) {
|
|
|
|
/* In the case of a first access, try to apply linear
|
|
|
|
read-ahead */
|
|
|
|
|
2006-10-19 13:07:50 +02:00
|
|
|
buf_read_ahead_linear(buf_block_get_space(block),
|
|
|
|
buf_block_get_zip_size(block),
|
|
|
|
buf_block_get_page_no(block));
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef UNIV_IBUF_DEBUG
|
2006-11-24 13:49:59 +01:00
|
|
|
ut_a(ibuf_count_get(buf_block_get_space(block),
|
|
|
|
buf_block_get_page_no(block)) == 0);
|
2005-10-27 09:29:40 +02:00
|
|
|
#endif
|
|
|
|
buf_pool->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. */
|
|
|
|
|
|
|
|
ibool
|
|
|
|
buf_page_get_known_nowait(
|
|
|
|
/*======================*/
|
|
|
|
/* out: TRUE if success */
|
|
|
|
ulint rw_latch,/* in: RW_S_LATCH, RW_X_LATCH */
|
2006-10-12 13:05:22 +02:00
|
|
|
buf_block_t* block, /* in: the known page */
|
2005-10-27 09:29:40 +02:00
|
|
|
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 */
|
|
|
|
{
|
|
|
|
ibool success;
|
|
|
|
ulint fix_type;
|
|
|
|
|
|
|
|
ut_ad(mtr);
|
|
|
|
ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH));
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2006-11-10 12:15:59 +01:00
|
|
|
mutex_enter(&block->mutex);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-23 14:26:01 +01:00
|
|
|
if (buf_block_get_state(block) == BUF_BLOCK_REMOVE_HASH) {
|
2006-02-23 20:25:29 +01:00
|
|
|
/* Another thread is just freeing the block from the LRU list
|
|
|
|
of the buffer pool: do not try to access this page; this
|
2005-10-27 09:29:40 +02:00
|
|
|
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. */
|
|
|
|
|
2006-11-10 12:15:59 +01:00
|
|
|
mutex_exit(&block->mutex);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
|
2006-11-23 14:26:01 +01:00
|
|
|
ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-30 10:24:57 +01:00
|
|
|
buf_block_buf_fix_inc(block, file, line);
|
|
|
|
|
2006-11-10 12:15:59 +01:00
|
|
|
mutex_exit(&block->mutex);
|
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
if (mode == BUF_MAKE_YOUNG) {
|
2006-11-30 13:27:49 +01:00
|
|
|
buf_block_make_young(&block->page);
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ut_ad(!ibuf_inside() || (mode == BUF_KEEP_OLD));
|
|
|
|
|
|
|
|
if (rw_latch == RW_S_LATCH) {
|
|
|
|
success = rw_lock_s_lock_func_nowait(&(block->lock),
|
2006-08-29 11:30:31 +02:00
|
|
|
file, line);
|
2005-10-27 09:29:40 +02:00
|
|
|
fix_type = MTR_MEMO_PAGE_S_FIX;
|
|
|
|
} else {
|
|
|
|
success = rw_lock_x_lock_func_nowait(&(block->lock),
|
2006-08-29 11:30:31 +02:00
|
|
|
file, line);
|
2005-10-27 09:29:40 +02:00
|
|
|
fix_type = MTR_MEMO_PAGE_X_FIX;
|
|
|
|
}
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
if (!success) {
|
2006-11-10 12:15:59 +01:00
|
|
|
mutex_enter(&block->mutex);
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2006-11-30 13:27:49 +01:00
|
|
|
block->page.buf_fix_count--;
|
2006-11-10 12:15:59 +01:00
|
|
|
|
|
|
|
mutex_exit(&block->mutex);
|
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
|
|
rw_lock_s_unlock(&(block->debug_latch));
|
2006-02-23 20:25:29 +01:00
|
|
|
#endif
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
mtr_memo_push(mtr, block, fix_type);
|
|
|
|
|
2006-11-16 10:00:30 +01:00
|
|
|
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
|
|
|
|
ut_a(++buf_dbg_counter % 5771 || buf_validate());
|
2006-11-30 13:27:49 +01:00
|
|
|
ut_a(block->page.buf_fix_count > 0);
|
2006-11-23 15:12:58 +01:00
|
|
|
ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
|
2006-11-16 10:00:30 +01:00
|
|
|
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
|
2005-10-27 09:29:40 +02:00
|
|
|
#ifdef UNIV_DEBUG_FILE_ACCESSES
|
2006-11-29 14:23:28 +01:00
|
|
|
ut_a(block->page.file_page_was_freed == FALSE);
|
2005-10-27 09:29:40 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef UNIV_IBUF_DEBUG
|
|
|
|
ut_a((mode == BUF_KEEP_OLD)
|
2006-11-24 13:49:59 +01:00
|
|
|
|| (ibuf_count_get(buf_block_get_space(block),
|
|
|
|
buf_block_get_page_no(block)) == 0));
|
2005-10-27 09:29:40 +02:00
|
|
|
#endif
|
|
|
|
buf_pool->n_page_gets++;
|
|
|
|
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
|
2007-01-23 15:08:37 +01:00
|
|
|
/************************************************************************
|
|
|
|
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->is_hashed = FALSE;
|
|
|
|
block->n_fields = 1;
|
|
|
|
block->n_bytes = 0;
|
|
|
|
block->left_side = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
Initialize some fields of a control block. */
|
|
|
|
UNIV_INLINE
|
|
|
|
void
|
|
|
|
buf_page_init_low(
|
|
|
|
/*==============*/
|
|
|
|
buf_page_t* bpage) /* in: block to init */
|
|
|
|
{
|
|
|
|
bpage->accessed = FALSE;
|
|
|
|
bpage->io_fix = BUF_IO_NONE;
|
|
|
|
bpage->buf_fix_count = 0;
|
|
|
|
bpage->freed_page_clock = 0;
|
|
|
|
// bpage->hash = (buf_page_t*) -1;
|
|
|
|
bpage->newest_modification = 0;
|
|
|
|
bpage->oldest_modification = 0;
|
|
|
|
#ifdef UNIV_DEBUG_FILE_ACCESSES
|
|
|
|
bpage->file_page_was_freed = FALSE;
|
|
|
|
#endif /* UNIV_DEBUG_FILE_ACCESSES */
|
|
|
|
}
|
|
|
|
|
2006-04-26 11:35:18 +02:00
|
|
|
#ifdef UNIV_HOTBACKUP
|
2005-10-27 09:29:40 +02:00
|
|
|
/************************************************************************
|
|
|
|
Inits a page to the buffer buf_pool, for use in ibbackup --restore. */
|
|
|
|
|
|
|
|
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 */
|
2006-10-06 13:23:19 +02:00
|
|
|
ulint zip_size,/* in: compressed page size in bytes
|
|
|
|
or 0 for uncompressed pages */
|
2005-10-27 09:29:40 +02:00
|
|
|
buf_block_t* block) /* in: block to init */
|
|
|
|
{
|
2007-01-23 15:08:37 +01:00
|
|
|
buf_block_init_low(block);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
block->lock_hash_val = 0;
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2007-01-23 15:08:37 +01:00
|
|
|
buf_page_init_low(&block->page);
|
2006-11-30 13:27:49 +01:00
|
|
|
block->page.state = BUF_BLOCK_FILE_PAGE;
|
2007-01-23 15:08:37 +01:00
|
|
|
block->page.space = space;
|
|
|
|
block->page.offset = offset;
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-30 16:25:52 +01:00
|
|
|
page_zip_des_init(&block->page.zip);
|
2006-11-24 14:02:31 +01:00
|
|
|
|
2006-11-24 09:32:18 +01:00
|
|
|
/* We assume that block->page.data has been allocated
|
2006-10-06 13:23:19 +02:00
|
|
|
with zip_size == UNIV_PAGE_SIZE. */
|
|
|
|
ut_ad(zip_size <= UNIV_PAGE_SIZE);
|
|
|
|
ut_ad(ut_is_2pow(zip_size));
|
2006-11-30 16:25:52 +01:00
|
|
|
page_zip_set_size(&block->page.zip, zip_size);
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
2006-04-26 11:35:18 +02:00
|
|
|
#endif /* UNIV_HOTBACKUP */
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
Inits a page to the buffer buf_pool. */
|
|
|
|
static
|
|
|
|
void
|
|
|
|
buf_page_init(
|
|
|
|
/*==========*/
|
|
|
|
ulint space, /* in: space id */
|
|
|
|
ulint offset, /* in: offset of the page within space
|
|
|
|
in units of a page */
|
|
|
|
buf_block_t* block) /* in: block to init */
|
|
|
|
{
|
2007-01-10 15:36:15 +01:00
|
|
|
buf_page_t* hash_page;
|
2007-01-18 19:29:12 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
ut_ad(mutex_own(&(buf_pool->mutex)));
|
2006-11-10 12:15:59 +01:00
|
|
|
ut_ad(mutex_own(&(block->mutex)));
|
2006-11-23 14:26:01 +01:00
|
|
|
ut_a(buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
/* Set the state of the block */
|
2006-11-23 15:12:58 +01:00
|
|
|
buf_block_set_file_page(block, space, offset);
|
2007-01-13 22:15:55 +01:00
|
|
|
|
|
|
|
#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 */
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2007-01-23 15:08:37 +01:00
|
|
|
buf_block_init_low(block);
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
block->lock_hash_val = lock_rec_hash(space, offset);
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
/* Insert into the hash table of file pages */
|
|
|
|
|
2007-01-10 15:36:15 +01:00
|
|
|
hash_page = buf_page_hash_get(space, offset);
|
|
|
|
|
|
|
|
if (UNIV_LIKELY_NULL(hash_page)) {
|
2006-02-23 20:25:29 +01:00
|
|
|
fprintf(stderr,
|
2006-08-29 11:30:31 +02:00
|
|
|
"InnoDB: Error: page %lu %lu already found"
|
2007-01-10 15:36:15 +01:00
|
|
|
" in the hash table: %p, %p\n",
|
2005-10-27 09:29:40 +02:00
|
|
|
(ulong) space,
|
2007-01-10 15:36:15 +01:00
|
|
|
(ulong) offset,
|
|
|
|
hash_page, block);
|
2006-11-16 10:00:30 +01:00
|
|
|
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
|
2007-01-03 16:54:05 +01:00
|
|
|
mutex_exit(&block->mutex);
|
|
|
|
mutex_exit(&buf_pool->mutex);
|
2006-02-23 20:25:29 +01:00
|
|
|
buf_print();
|
|
|
|
buf_LRU_print();
|
|
|
|
buf_validate();
|
|
|
|
buf_LRU_validate();
|
2006-11-16 10:00:30 +01:00
|
|
|
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
|
2006-04-26 11:35:18 +02:00
|
|
|
ut_error;
|
2006-02-23 20:25:29 +01:00
|
|
|
}
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2007-01-24 11:36:05 +01:00
|
|
|
ut_ad(!block->page.in_zip_hash);
|
|
|
|
ut_ad(!block->page.in_page_hash);
|
|
|
|
ut_d(block->page.in_page_hash = TRUE);
|
2006-11-29 14:23:28 +01:00
|
|
|
HASH_INSERT(buf_page_t, hash, buf_pool->page_hash,
|
|
|
|
buf_page_address_fold(space, offset), &block->page);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2007-01-23 15:08:37 +01:00
|
|
|
buf_page_init_low(&block->page);
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
2007-01-03 14:10:46 +01:00
|
|
|
/************************************************************************
|
|
|
|
Decompress a block. */
|
|
|
|
static
|
|
|
|
ibool
|
|
|
|
buf_zip_decompress(
|
|
|
|
/*===============*/
|
|
|
|
/* out: TRUE if successful */
|
2007-01-08 18:08:57 +01:00
|
|
|
buf_block_t* block, /* in/out: block */
|
|
|
|
ibool check) /* in: TRUE=verify the page checksum */
|
2007-01-03 14:10:46 +01:00
|
|
|
{
|
|
|
|
const byte* frame = block->page.zip.data;
|
|
|
|
|
|
|
|
ut_ad(buf_block_get_zip_size(block));
|
|
|
|
ut_a(buf_block_get_space(block) != 0);
|
|
|
|
|
2007-01-08 18:08:57 +01:00
|
|
|
if (UNIV_LIKELY(check)) {
|
|
|
|
ulint stamp_checksum = mach_read_from_4(
|
|
|
|
frame + FIL_PAGE_SPACE_OR_CHKSUM);
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-01-03 14:10:46 +01:00
|
|
|
switch (fil_page_get_type(frame)) {
|
|
|
|
case FIL_PAGE_INDEX:
|
|
|
|
if (page_zip_decompress(&block->page.zip,
|
|
|
|
block->frame)) {
|
|
|
|
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:
|
|
|
|
/* Copy to uncompressed storage. */
|
|
|
|
memcpy(block->frame, frame,
|
|
|
|
buf_block_get_zip_size(block));
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
ut_print_timestamp(stderr);
|
|
|
|
fprintf(stderr,
|
2007-01-08 18:08:57 +01:00
|
|
|
" InnoDB: unknown compressed page"
|
2007-01-03 14:10:46 +01:00
|
|
|
" type %lu\n",
|
|
|
|
fil_page_get_type(frame));
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
/************************************************************************
|
|
|
|
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. This is one of the functions which perform the
|
|
|
|
state transition NOT_USED => FILE_PAGE to a block (the other is
|
2006-02-23 20:25:29 +01:00
|
|
|
buf_page_create). */
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
buf_block_t*
|
|
|
|
buf_page_init_for_read(
|
|
|
|
/*===================*/
|
|
|
|
/* out: pointer to the block or NULL */
|
|
|
|
ulint* err, /* out: DB_SUCCESS or DB_TABLESPACE_DELETED */
|
|
|
|
ulint mode, /* in: BUF_READ_IBUF_PAGES_ONLY, ... */
|
|
|
|
ulint space, /* in: space id */
|
2006-04-26 11:35:18 +02:00
|
|
|
ulint zip_size,/* in: compressed page size, or 0 */
|
2005-10-27 09:29:40 +02:00
|
|
|
ib_longlong 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;
|
2006-12-15 16:05:18 +01:00
|
|
|
buf_page_t* bpage;
|
2005-10-27 09:29:40 +02:00
|
|
|
mtr_t mtr;
|
|
|
|
|
|
|
|
ut_ad(buf_pool);
|
|
|
|
|
|
|
|
*err = DB_SUCCESS;
|
|
|
|
|
|
|
|
if (mode == BUF_READ_IBUF_PAGES_ONLY) {
|
|
|
|
/* It is a read-ahead within an ibuf routine */
|
|
|
|
|
2006-06-05 11:04:19 +02:00
|
|
|
ut_ad(!ibuf_bitmap_page(zip_size, offset));
|
2005-10-27 09:29:40 +02:00
|
|
|
ut_ad(ibuf_inside());
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
mtr_start(&mtr);
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2006-10-19 13:07:50 +02:00
|
|
|
if (!ibuf_page_low(space, zip_size, offset, &mtr)) {
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
mtr_commit(&mtr);
|
|
|
|
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ut_ad(mode == BUF_READ_ANY_PAGE);
|
|
|
|
}
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2007-01-03 14:10:46 +01:00
|
|
|
block = buf_LRU_get_free_block(0);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
ut_a(block);
|
|
|
|
|
|
|
|
mutex_enter(&(buf_pool->mutex));
|
2006-11-10 12:15:59 +01:00
|
|
|
mutex_enter(&block->mutex);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-09-19 12:14:07 +02:00
|
|
|
if (fil_tablespace_deleted_or_being_deleted_in_mem(
|
|
|
|
space, tablespace_version)) {
|
2005-10-27 09:29:40 +02:00
|
|
|
*err = DB_TABLESPACE_DELETED;
|
2006-12-15 16:05:18 +01:00
|
|
|
|
|
|
|
goto err_exit;
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
2006-12-15 16:05:18 +01:00
|
|
|
bpage = buf_page_hash_get(space, offset);
|
|
|
|
|
|
|
|
if (UNIV_LIKELY_NULL(bpage)) {
|
|
|
|
|
|
|
|
switch (buf_page_get_state(bpage)) {
|
|
|
|
case BUF_BLOCK_ZIP_PAGE:
|
|
|
|
case BUF_BLOCK_ZIP_DIRTY:
|
|
|
|
ut_a(page_zip_get_size(&bpage->zip) == zip_size);
|
|
|
|
|
|
|
|
if (bpage->buf_fix_count
|
|
|
|
|| buf_page_get_io_fix(bpage)
|
|
|
|
!= BUF_IO_NONE) {
|
|
|
|
|
|
|
|
goto err_exit;
|
|
|
|
}
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-12-15 16:05:18 +01:00
|
|
|
/* Move the compressed page from bpage to block,
|
|
|
|
and uncompress it. */
|
|
|
|
|
|
|
|
mutex_enter(&buf_pool->zip_mutex);
|
|
|
|
|
|
|
|
buf_relocate(bpage, &block->page);
|
2007-01-23 15:08:37 +01:00
|
|
|
buf_block_init_low(block);
|
|
|
|
block->lock_hash_val = lock_rec_hash(space, offset);
|
|
|
|
|
2007-01-12 13:36:40 +01:00
|
|
|
UNIV_MEM_DESC(bpage->zip.data, zip_size, block);
|
2006-12-15 16:05:18 +01:00
|
|
|
|
2007-01-12 10:14:15 +01:00
|
|
|
if (buf_page_get_state(&block->page)
|
|
|
|
== BUF_BLOCK_ZIP_PAGE) {
|
2006-12-15 16:05:18 +01:00
|
|
|
UT_LIST_REMOVE(list, buf_pool->zip_clean,
|
2007-01-12 10:14:15 +01:00
|
|
|
&block->page);
|
2007-01-23 15:08:37 +01:00
|
|
|
ut_ad(!block->page.in_flush_list);
|
2006-12-15 16:05:18 +01:00
|
|
|
} else {
|
|
|
|
/* Relocate buf_pool->flush_list. */
|
|
|
|
buf_page_t* b;
|
|
|
|
|
2007-01-12 10:14:15 +01:00
|
|
|
b = UT_LIST_GET_PREV(list, &block->page);
|
|
|
|
ut_ad(block->page.in_flush_list);
|
2006-12-15 16:05:18 +01:00
|
|
|
UT_LIST_REMOVE(list, buf_pool->flush_list,
|
2007-01-12 10:14:15 +01:00
|
|
|
&block->page);
|
2006-12-15 16:05:18 +01:00
|
|
|
|
|
|
|
if (b) {
|
|
|
|
UT_LIST_INSERT_AFTER(
|
|
|
|
list, buf_pool->flush_list, b,
|
|
|
|
&block->page);
|
|
|
|
} else {
|
|
|
|
UT_LIST_ADD_FIRST(
|
|
|
|
list, buf_pool->flush_list,
|
|
|
|
&block->page);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-01-23 15:08:37 +01:00
|
|
|
/* Buffer-fix, I/O-fix, and X-latch the block
|
|
|
|
for the duration of the decompression. */
|
2007-01-12 10:14:15 +01:00
|
|
|
block->page.state = BUF_BLOCK_FILE_PAGE;
|
2007-01-23 15:08:37 +01:00
|
|
|
block->page.buf_fix_count = 1;
|
2007-01-16 13:40:15 +01:00
|
|
|
buf_block_set_io_fix(block, BUF_IO_READ);
|
2007-01-10 11:08:34 +01:00
|
|
|
rw_lock_x_lock(&block->lock);
|
2007-01-03 16:54:05 +01:00
|
|
|
mutex_exit(&block->mutex);
|
|
|
|
mutex_exit(&buf_pool->zip_mutex);
|
2006-12-15 16:05:18 +01:00
|
|
|
|
|
|
|
buf_buddy_free(bpage, sizeof *bpage);
|
|
|
|
|
2007-01-03 14:10:46 +01:00
|
|
|
mutex_exit(&buf_pool->mutex);
|
|
|
|
|
|
|
|
if (mode == BUF_READ_IBUF_PAGES_ONLY) {
|
|
|
|
|
|
|
|
mtr_commit(&mtr);
|
|
|
|
}
|
|
|
|
|
2007-01-23 15:08:37 +01:00
|
|
|
/* Decompress the page while not holding
|
|
|
|
buf_pool->mutex or block->mutex. */
|
2007-01-08 18:08:57 +01:00
|
|
|
buf_zip_decompress(block, srv_use_checksums);
|
2007-01-23 15:08:37 +01:00
|
|
|
|
|
|
|
/* Unfix and unlatch the block. */
|
2007-01-16 13:40:15 +01:00
|
|
|
mutex_enter(&buf_pool->mutex);
|
2007-01-10 13:50:10 +01:00
|
|
|
mutex_enter(&block->mutex);
|
2007-01-23 17:12:14 +01:00
|
|
|
block->page.buf_fix_count--;
|
2007-01-16 13:40:15 +01:00
|
|
|
buf_block_set_io_fix(block, BUF_IO_NONE);
|
|
|
|
mutex_exit(&buf_pool->mutex);
|
2007-01-10 13:50:10 +01:00
|
|
|
mutex_exit(&block->mutex);
|
2007-01-10 11:08:34 +01:00
|
|
|
rw_lock_x_unlock(&block->lock);
|
2007-01-03 14:10:46 +01:00
|
|
|
|
|
|
|
return(NULL);
|
2006-12-15 16:05:18 +01:00
|
|
|
case BUF_BLOCK_FILE_PAGE:
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
err_exit:
|
|
|
|
/* The page belongs to a space which has been
|
|
|
|
deleted or is being deleted, or the page is
|
|
|
|
already in buf_pool, return */
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-10 12:15:59 +01:00
|
|
|
mutex_exit(&block->mutex);
|
2006-12-15 16:05:18 +01:00
|
|
|
mutex_exit(&(buf_pool->mutex));
|
2006-11-10 12:15:59 +01:00
|
|
|
|
2006-12-15 16:05:18 +01:00
|
|
|
buf_block_free(block);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-12-15 16:05:18 +01:00
|
|
|
if (mode == BUF_READ_IBUF_PAGES_ONLY) {
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-12-15 16:05:18 +01:00
|
|
|
mtr_commit(&mtr);
|
|
|
|
}
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-12-15 16:05:18 +01:00
|
|
|
return(NULL);
|
|
|
|
}
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
ut_ad(block);
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2006-05-04 13:44:49 +02:00
|
|
|
buf_page_init(space, offset, block);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
/* The block must be put to the LRU list, to the old blocks */
|
|
|
|
|
2006-11-30 13:27:49 +01:00
|
|
|
buf_LRU_add_block(&block->page, TRUE/* to old blocks */);
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2006-11-30 13:27:49 +01:00
|
|
|
buf_page_set_io_fix(&block->page, BUF_IO_READ);
|
2006-11-10 12:15:59 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
buf_pool->n_pend_reads++;
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2007-01-16 14:45:52 +01:00
|
|
|
/* 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);
|
|
|
|
|
2007-01-15 17:51:39 +01:00
|
|
|
if (zip_size) {
|
|
|
|
void* data;
|
|
|
|
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(zip_size, TRUE);
|
|
|
|
mutex_enter(&block->mutex);
|
|
|
|
block->page.zip.data = data;
|
|
|
|
}
|
|
|
|
|
2006-11-10 12:15:59 +01:00
|
|
|
mutex_exit(&block->mutex);
|
2006-02-23 20:25:29 +01:00
|
|
|
mutex_exit(&(buf_pool->mutex));
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
if (mode == BUF_READ_IBUF_PAGES_ONLY) {
|
|
|
|
|
|
|
|
mtr_commit(&mtr);
|
|
|
|
}
|
|
|
|
|
|
|
|
return(block);
|
2006-02-23 20:25:29 +01:00
|
|
|
}
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
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_init_for_read above). */
|
|
|
|
|
2006-10-12 13:05:22 +02:00
|
|
|
buf_block_t*
|
2005-10-27 09:29:40 +02:00
|
|
|
buf_page_create(
|
|
|
|
/*============*/
|
2006-10-12 13:05:22 +02:00
|
|
|
/* out: pointer to the block, page bufferfixed */
|
2005-10-27 09:29:40 +02:00
|
|
|
ulint space, /* in: space id */
|
|
|
|
ulint offset, /* in: offset of the page within space in units of
|
|
|
|
a page */
|
2006-04-26 11:35:18 +02:00
|
|
|
ulint zip_size,/* in: compressed page size, or 0 */
|
2005-10-27 09:29:40 +02:00
|
|
|
mtr_t* mtr) /* in: mini-transaction handle */
|
|
|
|
{
|
|
|
|
buf_frame_t* frame;
|
|
|
|
buf_block_t* block;
|
|
|
|
buf_block_t* free_block = NULL;
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
ut_ad(mtr);
|
2006-04-26 11:35:18 +02:00
|
|
|
ut_ad(space || !zip_size);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2007-01-03 14:10:46 +01:00
|
|
|
free_block = buf_LRU_get_free_block(0);
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
mutex_enter(&(buf_pool->mutex));
|
|
|
|
|
2006-11-29 14:23:28 +01:00
|
|
|
block = (buf_block_t*) buf_page_hash_get(space, offset);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2007-01-05 15:03:44 +01:00
|
|
|
if (block && buf_page_in_file(&block->page)) {
|
2005-10-27 09:29:40 +02:00
|
|
|
#ifdef UNIV_IBUF_DEBUG
|
2007-01-05 15:03:44 +01:00
|
|
|
ut_a(ibuf_count_get(space, offset) == 0);
|
2005-10-27 09:29:40 +02:00
|
|
|
#endif
|
2006-11-16 09:48:28 +01:00
|
|
|
#ifdef UNIV_DEBUG_FILE_ACCESSES
|
2006-11-29 14:23:28 +01:00
|
|
|
block->page.file_page_was_freed = FALSE;
|
2006-11-16 09:48:28 +01:00
|
|
|
#endif /* UNIV_DEBUG_FILE_ACCESSES */
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
/* Page can be found in buf_pool */
|
|
|
|
mutex_exit(&(buf_pool->mutex));
|
|
|
|
|
|
|
|
buf_block_free(free_block);
|
|
|
|
|
2007-01-18 10:59:00 +01:00
|
|
|
return(buf_page_get_with_no_latch(space, zip_size,
|
|
|
|
offset, mtr));
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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;
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2006-11-10 12:15:59 +01:00
|
|
|
mutex_enter(&block->mutex);
|
|
|
|
|
2006-05-04 13:44:49 +02:00
|
|
|
buf_page_init(space, offset, block);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
/* The block must be put to the LRU list */
|
2006-11-30 13:27:49 +01:00
|
|
|
buf_LRU_add_block(&block->page, FALSE);
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2006-11-30 10:24:57 +01:00
|
|
|
buf_block_buf_fix_inc(block, __FILE__, __LINE__);
|
2006-11-10 12:15:59 +01:00
|
|
|
buf_pool->n_pages_created++;
|
|
|
|
|
2007-01-16 14:45:52 +01:00
|
|
|
/* 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);
|
|
|
|
|
2007-01-15 17:51:39 +01:00
|
|
|
if (zip_size) {
|
|
|
|
void* data;
|
|
|
|
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(zip_size, TRUE);
|
|
|
|
mutex_enter(&block->mutex);
|
|
|
|
block->page.zip.data = data;
|
|
|
|
}
|
|
|
|
|
2007-01-16 14:45:52 +01:00
|
|
|
buf_page_set_io_fix(&block->page, BUF_IO_NONE);
|
|
|
|
rw_lock_x_unlock(&block->lock);
|
|
|
|
|
2006-11-10 12:15:59 +01:00
|
|
|
mutex_exit(&(buf_pool->mutex));
|
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
mtr_memo_push(mtr, block, MTR_MEMO_BUF_FIX);
|
|
|
|
|
2006-11-30 13:27:49 +01:00
|
|
|
buf_page_set_accessed(&block->page, TRUE);
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2006-11-10 12:15:59 +01:00
|
|
|
mutex_exit(&block->mutex);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
/* Delete possible entries for the page from the insert buffer:
|
|
|
|
such can exist if the page belonged to an index which was dropped */
|
|
|
|
|
2006-10-19 10:27:34 +02:00
|
|
|
ibuf_merge_or_delete_for_page(NULL, space, offset, zip_size, TRUE);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
/* Flush pages from the end of the LRU list if necessary */
|
|
|
|
buf_flush_free_margin();
|
|
|
|
|
|
|
|
frame = block->frame;
|
|
|
|
|
2006-02-23 20:25:29 +01:00
|
|
|
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);
|
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
/* 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);
|
|
|
|
|
2006-11-16 10:00:30 +01:00
|
|
|
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
|
|
|
|
ut_a(++buf_dbg_counter % 357 || buf_validate());
|
|
|
|
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
|
2005-10-27 09:29:40 +02:00
|
|
|
#ifdef UNIV_IBUF_DEBUG
|
2006-11-24 13:49:59 +01:00
|
|
|
ut_a(ibuf_count_get(buf_block_get_space(block),
|
|
|
|
buf_block_get_page_no(block)) == 0);
|
2005-10-27 09:29:40 +02:00
|
|
|
#endif
|
2006-10-12 13:05:22 +02:00
|
|
|
return(block);
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
Completes an asynchronous read or write request of a file page to or from
|
|
|
|
the buffer pool. */
|
|
|
|
|
|
|
|
void
|
|
|
|
buf_page_io_complete(
|
|
|
|
/*=================*/
|
2007-01-10 15:36:39 +01:00
|
|
|
buf_page_t* bpage) /* in: pointer to the block in question */
|
2005-10-27 09:29:40 +02:00
|
|
|
{
|
2006-11-30 13:27:49 +01:00
|
|
|
enum buf_io_fix io_type;
|
2007-01-10 15:36:39 +01:00
|
|
|
const ibool uncompressed = (buf_page_get_state(bpage)
|
|
|
|
== BUF_BLOCK_FILE_PAGE);
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2007-01-10 15:36:39 +01:00
|
|
|
ut_a(buf_page_in_file(bpage));
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-30 13:27:49 +01:00
|
|
|
/* We do not need protect io_fix here by mutex to read
|
2006-11-10 12:15:59 +01:00
|
|
|
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. */
|
|
|
|
|
2007-01-10 15:36:39 +01:00
|
|
|
io_type = buf_page_get_io_fix(bpage);
|
|
|
|
ut_ad(io_type == BUF_IO_READ || io_type == BUF_IO_WRITE);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
if (io_type == BUF_IO_READ) {
|
2006-05-10 15:58:35 +02:00
|
|
|
ulint read_page_no;
|
|
|
|
ulint read_space_id;
|
2006-05-30 11:04:57 +02:00
|
|
|
byte* frame;
|
2006-05-10 15:58:35 +02:00
|
|
|
|
2007-01-10 15:36:39 +01:00
|
|
|
if (buf_page_get_zip_size(bpage)) {
|
|
|
|
frame = bpage->zip.data;
|
|
|
|
if (uncompressed
|
|
|
|
&& !buf_zip_decompress((buf_block_t*) bpage,
|
|
|
|
FALSE)) {
|
2007-01-03 14:10:46 +01:00
|
|
|
|
2006-05-30 11:04:57 +02:00
|
|
|
goto corrupt;
|
2006-05-04 13:44:49 +02:00
|
|
|
}
|
2006-05-30 11:04:57 +02:00
|
|
|
} else {
|
2007-01-10 15:36:39 +01:00
|
|
|
ut_a(uncompressed);
|
|
|
|
frame = ((buf_block_t*) bpage)->frame;
|
2006-05-04 13:44:49 +02:00
|
|
|
}
|
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
/* If this page is not uninitialized and not in the
|
2006-05-08 08:18:59 +02:00
|
|
|
doublewrite buffer, then the page number and space id
|
|
|
|
should be the same as in block. */
|
2006-08-02 07:49:15 +02:00
|
|
|
read_page_no = mach_read_from_4(frame + FIL_PAGE_OFFSET);
|
2006-09-27 12:51:05 +02:00
|
|
|
read_space_id = mach_read_from_4(
|
|
|
|
frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
|
2006-05-08 08:18:59 +02:00
|
|
|
|
2007-01-10 15:36:39 +01:00
|
|
|
if (bpage->space == TRX_SYS_SPACE
|
|
|
|
&& trx_doublewrite_page_inside(bpage->offset)) {
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-05-08 08:18:59 +02:00
|
|
|
ut_print_timestamp(stderr);
|
2005-10-27 09:29:40 +02:00
|
|
|
fprintf(stderr,
|
2006-08-29 11:30:31 +02:00
|
|
|
" InnoDB: Error: reading page %lu\n"
|
|
|
|
"InnoDB: which is in the"
|
|
|
|
" doublewrite buffer!\n",
|
2007-01-10 15:36:39 +01:00
|
|
|
(ulong) bpage->offset);
|
2006-05-08 08:18:59 +02:00
|
|
|
} else if (!read_space_id && !read_page_no) {
|
|
|
|
/* This is likely an uninitialized page. */
|
2007-01-10 15:36:39 +01:00
|
|
|
} else if ((bpage->space
|
|
|
|
&& bpage->space != read_space_id)
|
|
|
|
|| bpage->offset != read_page_no) {
|
2006-05-08 08:18:59 +02:00
|
|
|
/* We did not compare space_id to read_space_id
|
2007-01-10 15:36:39 +01:00
|
|
|
if bpage->space == 0, because the field on the
|
2006-05-08 08:18:59 +02:00
|
|
|
page may contain garbage in MySQL < 4.1.1,
|
2007-01-10 15:36:39 +01:00
|
|
|
which only supported bpage->space == 0. */
|
2006-05-08 08:18:59 +02:00
|
|
|
|
|
|
|
ut_print_timestamp(stderr);
|
|
|
|
fprintf(stderr,
|
2006-08-29 11:30:31 +02:00
|
|
|
" InnoDB: Error: space id and page n:o"
|
|
|
|
" stored in the page\n"
|
|
|
|
"InnoDB: read in are %lu:%lu,"
|
|
|
|
" should be %lu:%lu!\n",
|
2006-05-08 08:18:59 +02:00
|
|
|
(ulong) read_space_id, (ulong) read_page_no,
|
2007-01-10 15:36:39 +01:00
|
|
|
(ulong) bpage->space,
|
|
|
|
(ulong) bpage->offset);
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
2006-05-04 13:44:49 +02:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
/* From version 3.23.38 up we store the page checksum
|
2006-02-23 20:25:29 +01:00
|
|
|
to the 4 first bytes of the page end lsn field */
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-27 14:44:32 +01:00
|
|
|
if (buf_page_is_corrupted(frame,
|
2007-01-10 15:36:39 +01:00
|
|
|
buf_page_get_zip_size(bpage))) {
|
2006-05-30 11:04:57 +02:00
|
|
|
corrupt:
|
2006-02-23 20:25:29 +01:00
|
|
|
fprintf(stderr,
|
2006-08-29 11:30:31 +02:00
|
|
|
"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",
|
2007-01-10 15:36:39 +01:00
|
|
|
(ulong) bpage->offset);
|
|
|
|
buf_page_print(frame, buf_page_get_zip_size(bpage));
|
2006-02-23 20:25:29 +01:00
|
|
|
fprintf(stderr,
|
2006-08-29 11:30:31 +02:00
|
|
|
"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",
|
2007-01-10 15:36:39 +01:00
|
|
|
(ulong) bpage->offset);
|
2006-08-29 11:30:31 +02:00
|
|
|
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"
|
|
|
|
" http://dev.mysql.com/doc/refman/5.1/en/"
|
|
|
|
"forcing-recovery.html\n"
|
|
|
|
"InnoDB: about forcing recovery.\n", stderr);
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
if (srv_force_recovery < SRV_FORCE_IGNORE_CORRUPT) {
|
2006-08-29 11:30:31 +02:00
|
|
|
fputs("InnoDB: Ending processing because of"
|
|
|
|
" a corrupt database page.\n",
|
|
|
|
stderr);
|
2006-02-23 20:25:29 +01:00
|
|
|
exit(1);
|
|
|
|
}
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (recv_recovery_is_on()) {
|
2007-01-10 15:36:39 +01:00
|
|
|
/* Pages must be uncompressed for crash recovery. */
|
|
|
|
ut_a(uncompressed);
|
|
|
|
recv_recover_page(FALSE, TRUE, (buf_block_t*) bpage);
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
2007-01-10 15:36:39 +01:00
|
|
|
if (uncompressed && !recv_no_ibuf_operations) {
|
2006-09-19 12:14:07 +02:00
|
|
|
ibuf_merge_or_delete_for_page(
|
2007-01-10 15:36:39 +01:00
|
|
|
(buf_block_t*) bpage, bpage->space,
|
|
|
|
bpage->offset, buf_page_get_zip_size(bpage),
|
|
|
|
TRUE);
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
}
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2006-11-10 12:15:59 +01:00
|
|
|
mutex_enter(&(buf_pool->mutex));
|
2007-01-10 15:36:39 +01:00
|
|
|
mutex_enter(buf_page_get_mutex(bpage));
|
2006-11-10 12:15:59 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
#ifdef UNIV_IBUF_DEBUG
|
2007-01-10 15:36:39 +01:00
|
|
|
ut_a(ibuf_count_get(bpage->space, bpage->offset) == 0);
|
2005-10-27 09:29:40 +02:00
|
|
|
#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. */
|
|
|
|
|
2007-01-10 15:36:39 +01:00
|
|
|
buf_page_set_io_fix(bpage, BUF_IO_NONE);
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2007-01-10 15:36:39 +01:00
|
|
|
switch (io_type) {
|
|
|
|
case BUF_IO_READ:
|
2005-10-27 09:29:40 +02:00
|
|
|
/* 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
|
2006-02-23 20:25:29 +01:00
|
|
|
debugging! */
|
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
ut_ad(buf_pool->n_pend_reads > 0);
|
|
|
|
buf_pool->n_pend_reads--;
|
|
|
|
buf_pool->n_pages_read++;
|
|
|
|
|
2007-01-10 15:36:39 +01:00
|
|
|
if (uncompressed) {
|
|
|
|
rw_lock_x_unlock_gen(&((buf_block_t*) bpage)->lock,
|
|
|
|
BUF_IO_READ);
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
2007-01-10 15:36:39 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case BUF_IO_WRITE:
|
2005-10-27 09:29:40 +02:00
|
|
|
/* Write means a flush operation: call the completion
|
|
|
|
routine in the flush system */
|
|
|
|
|
2007-01-10 15:36:39 +01:00
|
|
|
buf_flush_write_complete(bpage);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2007-01-10 15:36:39 +01:00
|
|
|
if (uncompressed) {
|
|
|
|
rw_lock_s_unlock_gen(&((buf_block_t*) bpage)->lock,
|
|
|
|
BUF_IO_WRITE);
|
|
|
|
}
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
buf_pool->n_pages_written++;
|
|
|
|
|
2007-01-10 15:36:39 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
ut_error;
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2007-01-10 15:36:39 +01:00
|
|
|
mutex_exit(buf_page_get_mutex(bpage));
|
2005-10-27 09:29:40 +02:00
|
|
|
mutex_exit(&(buf_pool->mutex));
|
|
|
|
|
|
|
|
#ifdef UNIV_DEBUG
|
|
|
|
if (buf_debug_prints) {
|
2007-01-10 15:36:39 +01:00
|
|
|
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));
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
#endif /* UNIV_DEBUG */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
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. */
|
|
|
|
|
|
|
|
void
|
|
|
|
buf_pool_invalidate(void)
|
|
|
|
/*=====================*/
|
|
|
|
{
|
|
|
|
ibool freed;
|
|
|
|
|
|
|
|
ut_ad(buf_all_freed());
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
freed = TRUE;
|
|
|
|
|
|
|
|
while (freed) {
|
|
|
|
freed = buf_LRU_search_and_free_block(100);
|
|
|
|
}
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
mutex_enter(&(buf_pool->mutex));
|
|
|
|
|
|
|
|
ut_ad(UT_LIST_GET_LEN(buf_pool->LRU) == 0);
|
|
|
|
|
|
|
|
mutex_exit(&(buf_pool->mutex));
|
|
|
|
}
|
|
|
|
|
2006-11-16 10:00:30 +01:00
|
|
|
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
|
2005-10-27 09:29:40 +02:00
|
|
|
/*************************************************************************
|
|
|
|
Validates the buffer buf_pool data structure. */
|
|
|
|
|
|
|
|
ibool
|
|
|
|
buf_validate(void)
|
|
|
|
/*==============*/
|
|
|
|
{
|
2007-01-05 13:13:28 +01:00
|
|
|
buf_page_t* b;
|
2006-11-14 15:27:26 +01:00
|
|
|
buf_chunk_t* chunk;
|
2005-10-27 09:29:40 +02:00
|
|
|
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;
|
2007-01-05 13:13:28 +01:00
|
|
|
ulint n_zip = 0;
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
ut_ad(buf_pool);
|
|
|
|
|
|
|
|
mutex_enter(&(buf_pool->mutex));
|
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
chunk = buf_pool->chunks;
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2007-01-05 13:13:28 +01:00
|
|
|
/* Check the uncompressed blocks. */
|
2006-12-05 13:10:30 +01:00
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
for (i = buf_pool->n_chunks; i--; chunk++) {
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
ulint j;
|
|
|
|
buf_block_t* block = chunk->blocks;
|
|
|
|
|
|
|
|
for (j = chunk->size; j--; block++) {
|
|
|
|
|
|
|
|
mutex_enter(&block->mutex);
|
2006-11-10 12:15:59 +01:00
|
|
|
|
2006-11-23 14:26:01 +01:00
|
|
|
switch (buf_block_get_state(block)) {
|
2006-12-05 13:10:30 +01:00
|
|
|
case BUF_BLOCK_ZIP_FREE:
|
2006-11-24 13:49:59 +01:00
|
|
|
case BUF_BLOCK_ZIP_PAGE:
|
2006-12-05 13:10:30 +01:00
|
|
|
case BUF_BLOCK_ZIP_DIRTY:
|
|
|
|
/* These should only occur on
|
|
|
|
zip_clean, zip_free[], or flush_list. */
|
2006-11-24 13:49:59 +01:00
|
|
|
ut_error;
|
|
|
|
break;
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-12-05 13:10:30 +01:00
|
|
|
case BUF_BLOCK_FILE_PAGE:
|
2006-11-24 13:49:59 +01:00
|
|
|
ut_a(buf_page_hash_get(buf_block_get_space(
|
|
|
|
block),
|
|
|
|
buf_block_get_page_no(
|
|
|
|
block))
|
2006-11-29 14:23:28 +01:00
|
|
|
== &block->page);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
#ifdef UNIV_IBUF_DEBUG
|
2006-11-30 13:27:49 +01:00
|
|
|
ut_a(buf_page_get_io_fix(&block->page)
|
|
|
|
== BUF_IO_READ
|
2006-11-24 13:49:59 +01:00
|
|
|
|| !ibuf_count_get(buf_block_get_space(
|
|
|
|
block),
|
|
|
|
buf_block_get_page_no(
|
|
|
|
block)));
|
2005-10-27 09:29:40 +02:00
|
|
|
#endif
|
2006-11-30 13:27:49 +01:00
|
|
|
switch (buf_page_get_io_fix(&block->page)) {
|
|
|
|
case BUF_IO_NONE:
|
|
|
|
break;
|
2006-11-14 15:27:26 +01:00
|
|
|
|
2006-11-30 13:27:49 +01:00
|
|
|
case BUF_IO_WRITE:
|
2006-11-28 12:08:33 +01:00
|
|
|
switch (buf_page_get_flush_type(
|
|
|
|
&block->page)) {
|
2006-11-14 15:27:26 +01:00
|
|
|
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;
|
|
|
|
}
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-30 13:27:49 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case BUF_IO_READ:
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
ut_a(rw_lock_is_locked(&block->lock,
|
|
|
|
RW_LOCK_EX));
|
2006-11-30 13:27:49 +01:00
|
|
|
break;
|
2006-11-14 15:27:26 +01:00
|
|
|
}
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
n_lru++;
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-28 12:08:33 +01:00
|
|
|
if (block->page.oldest_modification > 0) {
|
2006-11-14 15:27:26 +01:00
|
|
|
n_flush++;
|
|
|
|
}
|
|
|
|
|
2006-11-23 14:26:01 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case BUF_BLOCK_NOT_USED:
|
2006-11-14 15:27:26 +01:00
|
|
|
n_free++;
|
2006-11-23 14:26:01 +01:00
|
|
|
break;
|
2006-11-23 15:12:58 +01:00
|
|
|
|
|
|
|
case BUF_BLOCK_READY_FOR_USE:
|
|
|
|
case BUF_BLOCK_MEMORY:
|
|
|
|
case BUF_BLOCK_REMOVE_HASH:
|
|
|
|
/* do nothing */
|
|
|
|
break;
|
2006-02-23 20:25:29 +01:00
|
|
|
}
|
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
mutex_exit(&block->mutex);
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
2006-02-23 20:25:29 +01:00
|
|
|
}
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2007-01-05 13:13:28 +01:00
|
|
|
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);
|
2007-01-18 21:29:35 +01:00
|
|
|
switch (buf_page_get_io_fix(b)) {
|
|
|
|
case BUF_IO_NONE:
|
|
|
|
/* 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 lock out
|
|
|
|
buf_page_init_for_read(). */
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ut_error;
|
|
|
|
break;
|
|
|
|
}
|
2007-01-05 13:13:28 +01:00
|
|
|
ut_a(!b->oldest_modification);
|
|
|
|
ut_a(buf_page_hash_get(b->space, b->offset) == b);
|
|
|
|
|
|
|
|
n_lru++;
|
|
|
|
n_zip++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check dirty compressed-only blocks. */
|
|
|
|
|
|
|
|
for (b = UT_LIST_GET_FIRST(buf_pool->flush_list); b;
|
|
|
|
b = UT_LIST_GET_NEXT(list, b)) {
|
2007-01-09 13:35:42 +01:00
|
|
|
ut_ad(b->in_flush_list);
|
|
|
|
|
2007-01-05 13:13:28 +01:00
|
|
|
switch (buf_page_get_state(b)) {
|
|
|
|
case BUF_BLOCK_ZIP_DIRTY:
|
|
|
|
ut_a(b->oldest_modification);
|
|
|
|
n_lru++;
|
|
|
|
n_flush++;
|
|
|
|
n_zip++;
|
|
|
|
switch (buf_page_get_io_fix(b)) {
|
|
|
|
case BUF_IO_NONE:
|
|
|
|
case BUF_IO_READ:
|
|
|
|
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(b->space, b->offset) == b);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2005-10-27 09:29:40 +02:00
|
|
|
ut_error;
|
|
|
|
}
|
|
|
|
|
2007-01-05 13:13:28 +01:00
|
|
|
ut_a(UT_LIST_GET_LEN(buf_pool->LRU) == n_lru);
|
2005-10-27 09:29:40 +02:00
|
|
|
if (UT_LIST_GET_LEN(buf_pool->free) != n_free) {
|
|
|
|
fprintf(stderr, "Free list len %lu, free blocks %lu\n",
|
2006-08-29 11:30:31 +02:00
|
|
|
(ulong) UT_LIST_GET_LEN(buf_pool->free),
|
|
|
|
(ulong) n_free);
|
2005-10-27 09:29:40 +02:00
|
|
|
ut_error;
|
|
|
|
}
|
|
|
|
ut_a(UT_LIST_GET_LEN(buf_pool->flush_list) == n_flush);
|
|
|
|
|
2007-01-05 13:13:28 +01:00
|
|
|
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);
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
mutex_exit(&(buf_pool->mutex));
|
|
|
|
|
|
|
|
ut_a(buf_LRU_validate());
|
|
|
|
ut_a(buf_flush_validate());
|
|
|
|
|
|
|
|
return(TRUE);
|
2006-02-23 20:25:29 +01:00
|
|
|
}
|
2006-11-16 10:00:30 +01:00
|
|
|
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-16 10:00:30 +01:00
|
|
|
#if defined UNIV_DEBUG_PRINT || defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
|
2005-10-27 09:29:40 +02:00
|
|
|
/*************************************************************************
|
|
|
|
Prints info of the buffer buf_pool data structure. */
|
|
|
|
|
|
|
|
void
|
|
|
|
buf_print(void)
|
|
|
|
/*===========*/
|
|
|
|
{
|
|
|
|
dulint* index_ids;
|
|
|
|
ulint* counts;
|
|
|
|
ulint size;
|
|
|
|
ulint i;
|
|
|
|
ulint j;
|
|
|
|
dulint id;
|
|
|
|
ulint n_found;
|
2006-11-14 15:27:26 +01:00
|
|
|
buf_chunk_t* chunk;
|
2005-10-27 09:29:40 +02:00
|
|
|
dict_index_t* index;
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
ut_ad(buf_pool);
|
|
|
|
|
|
|
|
size = buf_pool->curr_size;
|
|
|
|
|
|
|
|
index_ids = mem_alloc(sizeof(dulint) * size);
|
|
|
|
counts = mem_alloc(sizeof(ulint) * size);
|
|
|
|
|
|
|
|
mutex_enter(&(buf_pool->mutex));
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
fprintf(stderr,
|
|
|
|
"buf_pool size %lu\n"
|
|
|
|
"database pages %lu\n"
|
|
|
|
"free pages %lu\n"
|
|
|
|
"modified database pages %lu\n"
|
|
|
|
"n pending reads %lu\n"
|
|
|
|
"n pending flush LRU %lu list %lu single page %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_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->n_pages_read, buf_pool->n_pages_created,
|
|
|
|
(ulong) buf_pool->n_pages_written);
|
|
|
|
|
|
|
|
/* Count the number of blocks belonging to each index in the buffer */
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
n_found = 0;
|
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
chunk = buf_pool->chunks;
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
for (i = buf_pool->n_chunks; i--; chunk++) {
|
|
|
|
buf_block_t* block = chunk->blocks;
|
|
|
|
ulint n_blocks = chunk->size;
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
for (; n_blocks--; block++) {
|
|
|
|
const buf_frame_t* frame = block->frame;
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
if (fil_page_get_type(frame) == FIL_PAGE_INDEX) {
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
id = btr_page_get_index_id(frame);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
/* Look for the id in the index_ids array */
|
|
|
|
j = 0;
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
while (j < n_found) {
|
|
|
|
|
|
|
|
if (ut_dulint_cmp(index_ids[j],
|
|
|
|
id) == 0) {
|
|
|
|
counts[j]++;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
j++;
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
if (j == n_found) {
|
|
|
|
n_found++;
|
|
|
|
index_ids[j] = id;
|
|
|
|
counts[j] = 1;
|
|
|
|
}
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_exit(&(buf_pool->mutex));
|
|
|
|
|
|
|
|
for (i = 0; i < n_found; i++) {
|
|
|
|
index = dict_index_get_if_in_cache(index_ids[i]);
|
|
|
|
|
|
|
|
fprintf(stderr,
|
|
|
|
"Block count for index %lu in buffer is about %lu",
|
2006-02-23 20:25:29 +01:00
|
|
|
(ulong) ut_dulint_get_low(index_ids[i]),
|
|
|
|
(ulong) counts[i]);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
if (index) {
|
|
|
|
putc(' ', stderr);
|
|
|
|
dict_index_name_print(stderr, NULL, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
putc('\n', stderr);
|
|
|
|
}
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
mem_free(index_ids);
|
|
|
|
mem_free(counts);
|
|
|
|
|
2006-11-16 10:00:30 +01:00
|
|
|
ut_a(buf_validate());
|
2006-02-23 20:25:29 +01:00
|
|
|
}
|
2006-11-16 10:00:30 +01:00
|
|
|
#endif /* UNIV_DEBUG_PRINT || UNIV_DEBUG || UNIV_BUF_DEBUG */
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
Returns the number of latched pages in the buffer pool. */
|
|
|
|
|
|
|
|
ulint
|
|
|
|
buf_get_latched_pages_number(void)
|
2007-01-05 22:00:07 +01:00
|
|
|
/*==============================*/
|
2005-10-27 09:29:40 +02:00
|
|
|
{
|
2006-11-14 15:27:26 +01:00
|
|
|
buf_chunk_t* chunk;
|
2007-01-05 22:00:07 +01:00
|
|
|
buf_page_t* b;
|
2006-08-29 11:30:31 +02:00
|
|
|
ulint i;
|
|
|
|
ulint fixed_pages_number = 0;
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-02-23 20:25:29 +01:00
|
|
|
mutex_enter(&(buf_pool->mutex));
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
chunk = buf_pool->chunks;
|
|
|
|
|
|
|
|
for (i = buf_pool->n_chunks; i--; chunk++) {
|
|
|
|
buf_block_t* block;
|
|
|
|
ulint j;
|
|
|
|
|
|
|
|
block = chunk->blocks;
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
for (j = chunk->size; j--; block++) {
|
2006-11-23 15:12:58 +01:00
|
|
|
if (buf_block_get_state(block)
|
|
|
|
!= BUF_BLOCK_FILE_PAGE) {
|
2006-11-14 15:27:26 +01:00
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-10 12:15:59 +01:00
|
|
|
mutex_enter(&block->mutex);
|
|
|
|
|
2006-11-30 13:27:49 +01:00
|
|
|
if (block->page.buf_fix_count != 0
|
|
|
|
|| buf_page_get_io_fix(&block->page)
|
|
|
|
!= BUF_IO_NONE) {
|
2006-11-10 12:15:59 +01:00
|
|
|
fixed_pages_number++;
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_exit(&block->mutex);
|
2006-08-29 11:30:31 +02:00
|
|
|
}
|
2006-02-23 20:25:29 +01:00
|
|
|
}
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2007-01-05 22:00:07 +01:00
|
|
|
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_NONE);
|
|
|
|
|
|
|
|
if (b->buf_fix_count != 0
|
|
|
|
|| buf_page_get_io_fix(b) != BUF_IO_NONE) {
|
|
|
|
fixed_pages_number++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (b = UT_LIST_GET_FIRST(buf_pool->flush_list); b;
|
|
|
|
b = UT_LIST_GET_NEXT(list, b)) {
|
2007-01-09 13:35:42 +01:00
|
|
|
ut_ad(b->in_flush_list);
|
|
|
|
|
2007-01-05 22:00:07 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_exit(&buf_pool->zip_mutex);
|
2006-02-23 20:25:29 +01:00
|
|
|
mutex_exit(&(buf_pool->mutex));
|
2006-05-08 08:18:59 +02:00
|
|
|
|
|
|
|
return(fixed_pages_number);
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
Returns the number of pending buf pool ios. */
|
|
|
|
|
|
|
|
ulint
|
|
|
|
buf_get_n_pending_ios(void)
|
|
|
|
/*=======================*/
|
|
|
|
{
|
|
|
|
return(buf_pool->n_pend_reads
|
2006-08-29 11:30:31 +02:00
|
|
|
+ buf_pool->n_flush[BUF_FLUSH_LRU]
|
|
|
|
+ buf_pool->n_flush[BUF_FLUSH_LIST]
|
|
|
|
+ buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]);
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
Returns the ratio in percents of modified pages in the buffer pool /
|
|
|
|
database pages in the buffer pool. */
|
|
|
|
|
|
|
|
ulint
|
|
|
|
buf_get_modified_ratio_pct(void)
|
|
|
|
/*============================*/
|
|
|
|
{
|
|
|
|
ulint ratio;
|
|
|
|
|
|
|
|
mutex_enter(&(buf_pool->mutex));
|
|
|
|
|
|
|
|
ratio = (100 * UT_LIST_GET_LEN(buf_pool->flush_list))
|
2006-02-23 20:25:29 +01:00
|
|
|
/ (1 + UT_LIST_GET_LEN(buf_pool->LRU)
|
2006-08-29 11:30:31 +02:00
|
|
|
+ UT_LIST_GET_LEN(buf_pool->free));
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-02-23 20:25:29 +01:00
|
|
|
/* 1 + is there to avoid division by zero */
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
mutex_exit(&(buf_pool->mutex));
|
|
|
|
|
|
|
|
return(ratio);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
Prints info of the buffer i/o. */
|
|
|
|
|
|
|
|
void
|
|
|
|
buf_print_io(
|
|
|
|
/*=========*/
|
|
|
|
FILE* file) /* in/out: buffer where to print */
|
|
|
|
{
|
|
|
|
time_t current_time;
|
|
|
|
double time_elapsed;
|
|
|
|
ulint size;
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
ut_ad(buf_pool);
|
|
|
|
size = buf_pool->curr_size;
|
|
|
|
|
|
|
|
mutex_enter(&(buf_pool->mutex));
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
fprintf(file,
|
|
|
|
"Buffer pool size %lu\n"
|
|
|
|
"Free buffers %lu\n"
|
|
|
|
"Database pages %lu\n"
|
|
|
|
"Modified db pages %lu\n"
|
|
|
|
"Pending reads %lu\n"
|
|
|
|
"Pending writes: LRU %lu, flush list %lu, single page %lu\n",
|
|
|
|
(ulong) size,
|
|
|
|
(ulong) UT_LIST_GET_LEN(buf_pool->free),
|
|
|
|
(ulong) UT_LIST_GET_LEN(buf_pool->LRU),
|
|
|
|
(ulong) UT_LIST_GET_LEN(buf_pool->flush_list),
|
|
|
|
(ulong) buf_pool->n_pend_reads,
|
|
|
|
(ulong) buf_pool->n_flush[BUF_FLUSH_LRU]
|
2006-08-29 11:30:31 +02:00
|
|
|
+ buf_pool->init_flush[BUF_FLUSH_LRU],
|
2005-10-27 09:29:40 +02:00
|
|
|
(ulong) buf_pool->n_flush[BUF_FLUSH_LIST]
|
2006-08-29 11:30:31 +02:00
|
|
|
+ buf_pool->init_flush[BUF_FLUSH_LIST],
|
2005-10-27 09:29:40 +02:00
|
|
|
(ulong) buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]);
|
|
|
|
|
|
|
|
current_time = time(NULL);
|
|
|
|
time_elapsed = 0.001 + difftime(current_time,
|
2006-08-29 11:30:31 +02:00
|
|
|
buf_pool->last_printout_time);
|
2005-10-27 09:29:40 +02:00
|
|
|
buf_pool->last_printout_time = current_time;
|
|
|
|
|
|
|
|
fprintf(file,
|
|
|
|
"Pages read %lu, created %lu, written %lu\n"
|
|
|
|
"%.2f reads/s, %.2f creates/s, %.2f writes/s\n",
|
|
|
|
(ulong) buf_pool->n_pages_read,
|
|
|
|
(ulong) buf_pool->n_pages_created,
|
|
|
|
(ulong) buf_pool->n_pages_written,
|
|
|
|
(buf_pool->n_pages_read - buf_pool->n_pages_read_old)
|
|
|
|
/ time_elapsed,
|
|
|
|
(buf_pool->n_pages_created - buf_pool->n_pages_created_old)
|
|
|
|
/ time_elapsed,
|
|
|
|
(buf_pool->n_pages_written - buf_pool->n_pages_written_old)
|
|
|
|
/ time_elapsed);
|
|
|
|
|
|
|
|
if (buf_pool->n_page_gets > buf_pool->n_page_gets_old) {
|
|
|
|
fprintf(file, "Buffer pool hit rate %lu / 1000\n",
|
2006-08-29 11:30:31 +02:00
|
|
|
(ulong)
|
|
|
|
(1000 - ((1000 * (buf_pool->n_pages_read
|
|
|
|
- buf_pool->n_pages_read_old))
|
|
|
|
/ (buf_pool->n_page_gets
|
|
|
|
- buf_pool->n_page_gets_old))));
|
2005-10-27 09:29:40 +02:00
|
|
|
} else {
|
|
|
|
fputs("No buffer pool page gets since the last printout\n",
|
2006-08-29 11:30:31 +02:00
|
|
|
file);
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
buf_pool->n_page_gets_old = buf_pool->n_page_gets;
|
|
|
|
buf_pool->n_pages_read_old = buf_pool->n_pages_read;
|
|
|
|
buf_pool->n_pages_created_old = buf_pool->n_pages_created;
|
|
|
|
buf_pool->n_pages_written_old = buf_pool->n_pages_written;
|
|
|
|
|
|
|
|
mutex_exit(&(buf_pool->mutex));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
Refreshes the statistics used to print per-second averages. */
|
|
|
|
|
|
|
|
void
|
|
|
|
buf_refresh_io_stats(void)
|
|
|
|
/*======================*/
|
|
|
|
{
|
2006-02-23 20:25:29 +01:00
|
|
|
buf_pool->last_printout_time = time(NULL);
|
2005-10-27 09:29:40 +02:00
|
|
|
buf_pool->n_page_gets_old = buf_pool->n_page_gets;
|
|
|
|
buf_pool->n_pages_read_old = buf_pool->n_pages_read;
|
|
|
|
buf_pool->n_pages_created_old = buf_pool->n_pages_created;
|
|
|
|
buf_pool->n_pages_written_old = buf_pool->n_pages_written;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
Checks that all file pages in the buffer are in a replaceable state. */
|
|
|
|
|
|
|
|
ibool
|
|
|
|
buf_all_freed(void)
|
|
|
|
/*===============*/
|
|
|
|
{
|
2006-11-14 15:27:26 +01:00
|
|
|
buf_chunk_t* chunk;
|
2005-10-27 09:29:40 +02:00
|
|
|
ulint i;
|
2006-02-23 20:25:29 +01:00
|
|
|
|
2005-10-27 09:29:40 +02:00
|
|
|
ut_ad(buf_pool);
|
|
|
|
|
|
|
|
mutex_enter(&(buf_pool->mutex));
|
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
chunk = buf_pool->chunks;
|
2006-11-10 12:15:59 +01:00
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
for (i = buf_pool->n_chunks; i--; chunk++) {
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
const buf_block_t* block = buf_chunk_not_freed(chunk);
|
2005-10-27 09:29:40 +02:00
|
|
|
|
2006-11-14 15:27:26 +01:00
|
|
|
if (UNIV_LIKELY_NULL(block)) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Page %lu %lu still fixed or dirty\n",
|
2006-11-24 09:32:18 +01:00
|
|
|
(ulong) block->page.space,
|
|
|
|
(ulong) block->page.offset);
|
2006-11-14 15:27:26 +01:00
|
|
|
ut_error;
|
2005-10-27 09:29:40 +02:00
|
|
|
}
|
2006-02-23 20:25:29 +01:00
|
|
|
}
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
mutex_exit(&(buf_pool->mutex));
|
|
|
|
|
|
|
|
return(TRUE);
|
2006-02-23 20:25:29 +01:00
|
|
|
}
|
2005-10-27 09:29:40 +02:00
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
Checks that there currently are no pending i/o-operations for the buffer
|
|
|
|
pool. */
|
|
|
|
|
|
|
|
ibool
|
|
|
|
buf_pool_check_no_pending_io(void)
|
|
|
|
/*==============================*/
|
|
|
|
/* out: TRUE if there is no pending i/o */
|
|
|
|
{
|
|
|
|
ibool ret;
|
|
|
|
|
|
|
|
mutex_enter(&(buf_pool->mutex));
|
|
|
|
|
|
|
|
if (buf_pool->n_pend_reads + buf_pool->n_flush[BUF_FLUSH_LRU]
|
2006-08-29 11:30:31 +02:00
|
|
|
+ buf_pool->n_flush[BUF_FLUSH_LIST]
|
|
|
|
+ buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]) {
|
2005-10-27 09:29:40 +02:00
|
|
|
ret = FALSE;
|
|
|
|
} else {
|
|
|
|
ret = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_exit(&(buf_pool->mutex));
|
|
|
|
|
|
|
|
return(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
Gets the current length of the free list of buffer blocks. */
|
|
|
|
|
|
|
|
ulint
|
|
|
|
buf_get_free_list_len(void)
|
|
|
|
/*=======================*/
|
|
|
|
{
|
|
|
|
ulint len;
|
|
|
|
|
|
|
|
mutex_enter(&(buf_pool->mutex));
|
|
|
|
|
|
|
|
len = UT_LIST_GET_LEN(buf_pool->free);
|
|
|
|
|
|
|
|
mutex_exit(&(buf_pool->mutex));
|
|
|
|
|
|
|
|
return(len);
|
|
|
|
}
|