mariadb/storage/xtradb/mtr/mtr0mtr.cc

476 lines
13 KiB
C++
Raw Normal View History

2009-03-25 23:11:11 -07:00
/*****************************************************************************
2013-07-16 14:55:47 +02:00
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
2009-03-25 23:11:11 -07:00
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
2009-03-25 23:11:11 -07:00
*****************************************************************************/
2009-09-07 10:22:53 +00:00
/**************************************************//**
2013-12-16 15:38:05 +01:00
@file mtr/mtr0mtr.cc
Mini-transaction buffer
Created 11/26/1995 Heikki Tuuri
*******************************************************/
#include "mtr0mtr.h"
#ifdef UNIV_NONINL
#include "mtr0mtr.ic"
#endif
#include "buf0buf.h"
2011-07-14 21:22:41 +02:00
#include "buf0flu.h"
#include "page0types.h"
#include "mtr0log.h"
#include "log0log.h"
Fix most Compiler warnings seen in buildbot. Add suppressions for a few warnings that cannot be meaningfully fixed by MariaDB developers. Changes for XtraDB, PBXT, and YaSSL also submitted upstream. Also add a `ccfilter` wrapper that can be used to filter out suppressed warnings in a local build (to check that new warnings are not introduced). client/mysqlbinlog.cc: Fix compiler warnings. config/ac-macros/misc.m4: Fix wrong naming, autoconfig requires _cv_ in cached names. extra/yassl/include/yassl_int.hpp: Fix compiler warnings. extra/yassl/src/handshake.cpp: Fix compiler warnings. extra/yassl/src/yassl_imp.cpp: Fix compiler warnings. extra/yassl/src/yassl_int.cpp: Fix compiler warnings. extra/yassl/taocrypt/include/modes.hpp: Fix compiler warnings. extra/yassl/taocrypt/src/asn.cpp: Fix compiler warnings. mysys/my_compress.c: Fix compiler warnings. sql/mysqld.cc: Fix compiler warnings. sql/strfunc.cc: Fix compiler warnings. storage/pbxt/src/discover_xt.cc: Fix compiler warnings. storage/xtradb/fil/fil0fil.c: Fix compiler warnings. storage/xtradb/mtr/mtr0mtr.c: Fix compiler warnings. storage/xtradb/srv/srv0srv.c: Fix compiler warnings. storage/xtradb/srv/srv0start.c: Fix compiler warnings. strings/decimal.c: Fix compiler warnings. support-files/ccfilter: Add helper for suppressing compiler warnings in local developer source tree. Allows to check for not introducing new warnings into Buildbot without having to actually run the build through Buildbot. support-files/compiler_warnings.supp: Suppress a few warnings that cannot be meaningfully fixed in source code.
2009-09-03 15:20:22 +02:00
#include "buf0flu.h"
2009-09-07 10:22:53 +00:00
#ifndef UNIV_HOTBACKUP
2010-01-06 04:00:14 -08:00
# include "log0recv.h"
2013-05-08 09:52:54 +02:00
/***************************************************//**
Checks if a mini-transaction is dirtying a clean page.
@return TRUE if the mtr is dirtying a clean page. */
UNIV_INTERN
ibool
mtr_block_dirtied(
/*==============*/
const buf_block_t* block) /*!< in: block being x-fixed */
{
ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
ut_ad(block->page.buf_fix_count > 0);
/* It is OK to read oldest_modification because no
other thread can be performing a write of it and it
is only during write that the value is reset to 0. */
return(block->page.oldest_modification == 0);
}
2009-09-07 10:22:53 +00:00
/*****************************************************************//**
Releases the item in the slot given. */
2013-07-16 14:55:47 +02:00
static __attribute__((nonnull))
void
2013-07-16 14:55:47 +02:00
mtr_memo_slot_release_func(
/*=======================*/
#ifdef UNIV_DEBUG
mtr_t* mtr, /*!< in/out: mini-transaction */
#endif /* UNIV_DEBUG */
2009-09-07 10:22:53 +00:00
mtr_memo_slot_t* slot) /*!< in: memo slot */
{
2013-07-16 14:55:47 +02:00
void* object = slot->object;
slot->object = NULL;
2013-07-16 14:55:47 +02:00
/* slot release is a local operation for the current mtr.
We must not be holding the flush_order mutex while
doing this. */
ut_ad(!log_flush_order_mutex_own());
switch (slot->type) {
case MTR_MEMO_PAGE_S_FIX:
case MTR_MEMO_PAGE_X_FIX:
case MTR_MEMO_BUF_FIX:
buf_page_release((buf_block_t*) object, slot->type);
break;
case MTR_MEMO_S_LOCK:
2013-12-16 15:38:05 +01:00
rw_lock_s_unlock((prio_rw_lock_t*) object);
2013-07-16 14:55:47 +02:00
break;
case MTR_MEMO_X_LOCK:
2013-12-16 15:38:05 +01:00
rw_lock_x_unlock((prio_rw_lock_t*) object);
2013-07-16 14:55:47 +02:00
break;
#ifdef UNIV_DEBUG
2013-07-16 14:55:47 +02:00
default:
ut_ad(slot->type == MTR_MEMO_MODIFY);
ut_ad(mtr_memo_contains(mtr, object, MTR_MEMO_PAGE_X_FIX));
#endif /* UNIV_DEBUG */
}
}
2013-07-16 14:55:47 +02:00
#ifdef UNIV_DEBUG
# define mtr_memo_slot_release(mtr, slot) mtr_memo_slot_release_func(mtr, slot)
#else /* UNIV_DEBUG */
# define mtr_memo_slot_release(mtr, slot) mtr_memo_slot_release_func(slot)
#endif /* UNIV_DEBUG */
2009-09-07 10:22:53 +00:00
/**********************************************************//**
2011-07-14 21:22:41 +02:00
Releases the mlocks and other objects stored in an mtr memo.
They are released in the order opposite to which they were pushed
to the memo. */
2013-07-16 14:55:47 +02:00
static __attribute__((nonnull))
void
mtr_memo_pop_all(
/*=============*/
2013-07-16 14:55:47 +02:00
mtr_t* mtr) /*!< in/out: mini-transaction */
{
ut_ad(mtr->magic_n == MTR_MAGIC_N);
ut_ad(mtr->state == MTR_COMMITTING); /* Currently only used in
commit */
2013-12-16 15:38:05 +01:00
for (const dyn_block_t* block = dyn_array_get_last_block(&mtr->memo);
2013-07-16 14:55:47 +02:00
block;
block = dyn_array_get_prev_block(&mtr->memo, block)) {
const mtr_memo_slot_t* start
2013-12-16 15:38:05 +01:00
= reinterpret_cast<mtr_memo_slot_t*>(
dyn_block_get_data(block));
2013-07-16 14:55:47 +02:00
mtr_memo_slot_t* slot
2013-12-16 15:38:05 +01:00
= reinterpret_cast<mtr_memo_slot_t*>(
dyn_block_get_data(block)
+ dyn_block_get_used(block));
2013-07-16 14:55:47 +02:00
ut_ad(!(dyn_block_get_used(block) % sizeof(mtr_memo_slot_t)));
while (slot-- != start) {
if (slot->object != NULL) {
mtr_memo_slot_release(mtr, slot);
}
}
}
}
2011-07-14 21:22:41 +02:00
/*****************************************************************//**
Releases the item in the slot given. */
static
2009-06-24 18:43:25 -07:00
void
2011-07-14 21:22:41 +02:00
mtr_memo_slot_note_modification(
/*============================*/
mtr_t* mtr, /*!< in: mtr */
mtr_memo_slot_t* slot) /*!< in: memo slot */
{
ut_ad(mtr->modifications);
2013-12-16 15:38:05 +01:00
ut_ad(!srv_read_only_mode);
ut_ad(mtr->magic_n == MTR_MAGIC_N);
2011-07-14 21:22:41 +02:00
if (slot->object != NULL && slot->type == MTR_MEMO_PAGE_X_FIX) {
buf_block_t* block = (buf_block_t*) slot->object;
2013-05-08 09:52:54 +02:00
ut_ad(!mtr->made_dirty || log_flush_order_mutex_own());
2011-07-14 21:22:41 +02:00
buf_flush_note_modification(block, mtr);
}
}
/**********************************************************//**
Add the modified pages to the buffer flush list. They are released
in the order opposite to which they were pushed to the memo. NOTE! It is
essential that the x-rw-lock on a modified buffer page is not released
before buf_page_note_modification is called for that page! Otherwise,
some thread might race to modify it, and the flush list sort order on
lsn would be destroyed. */
static
void
mtr_memo_note_modifications(
/*========================*/
mtr_t* mtr) /*!< in: mtr */
2009-06-24 18:43:25 -07:00
{
2013-12-16 15:38:05 +01:00
ut_ad(!srv_read_only_mode);
2009-06-24 18:43:25 -07:00
ut_ad(mtr->magic_n == MTR_MAGIC_N);
ut_ad(mtr->state == MTR_COMMITTING); /* Currently only used in
commit */
2011-07-14 21:22:41 +02:00
2014-02-26 16:25:11 +01:00
for (const dyn_block_t* block = dyn_array_get_last_block(&mtr->memo);
block;
block = dyn_array_get_prev_block(&mtr->memo, block)) {
const mtr_memo_slot_t* start
= reinterpret_cast<mtr_memo_slot_t*>(
dyn_block_get_data(block));
mtr_memo_slot_t* slot
= reinterpret_cast<mtr_memo_slot_t*>(
dyn_block_get_data(block)
+ dyn_block_get_used(block));
2013-12-16 15:38:05 +01:00
2014-02-26 16:25:11 +01:00
ut_ad(!(dyn_block_get_used(block) % sizeof(mtr_memo_slot_t)));
2009-06-24 18:43:25 -07:00
2014-02-26 16:25:11 +01:00
while (slot-- != start) {
if (slot->object != NULL) {
mtr_memo_slot_note_modification(mtr, slot);
}
}
2009-06-24 18:43:25 -07:00
}
}
2013-12-16 15:38:05 +01:00
/************************************************************//**
Append the dirty pages to the flush list. */
static
void
mtr_add_dirtied_pages_to_flush_list(
/*================================*/
mtr_t* mtr) /*!< in/out: mtr */
{
ut_ad(!srv_read_only_mode);
/* No need to acquire log_flush_order_mutex if this mtr has
not dirtied a clean page. log_flush_order_mutex is used to
ensure ordered insertions in the flush_list. We need to
insert in the flush_list iff the page in question was clean
before modifications. */
if (mtr->made_dirty) {
log_flush_order_mutex_enter();
}
/* It is now safe to release the log mutex because the
flush_order mutex will ensure that we are the first one
to insert into the flush list. */
log_release();
if (mtr->modifications) {
mtr_memo_note_modifications(mtr);
}
if (mtr->made_dirty) {
log_flush_order_mutex_exit();
}
}
2009-09-07 10:22:53 +00:00
/************************************************************//**
Writes the contents of a mini-transaction log, if any, to the database log. */
static
void
mtr_log_reserve_and_write(
/*======================*/
2013-12-16 15:38:05 +01:00
mtr_t* mtr) /*!< in/out: mtr */
{
dyn_array_t* mlog;
ulint data_size;
byte* first_data;
2013-12-16 15:38:05 +01:00
ut_ad(!srv_read_only_mode);
mlog = &(mtr->log);
first_data = dyn_block_get_data(mlog);
if (mtr->n_log_recs > 1) {
mlog_catenate_ulint(mtr, MLOG_MULTI_REC_END, MLOG_1BYTE);
} else {
*first_data = (byte)((ulint)*first_data
| MLOG_SINGLE_REC_FLAG);
}
if (mlog->heap == NULL) {
2013-12-16 15:38:05 +01:00
ulint len;
len = mtr->log_mode != MTR_LOG_NO_REDO
? dyn_block_get_used(mlog) : 0;
mtr->end_lsn = log_reserve_and_write_fast(
2013-12-16 15:38:05 +01:00
first_data, len, &mtr->start_lsn);
2010-01-06 04:00:14 -08:00
if (mtr->end_lsn) {
2011-07-14 21:22:41 +02:00
/* Success. We have the log mutex.
Add pages to flush list and exit */
2013-12-16 15:38:05 +01:00
mtr_add_dirtied_pages_to_flush_list(mtr);
return;
}
2013-05-08 09:52:54 +02:00
} else {
mutex_enter(&log_sys->mutex);
}
data_size = dyn_array_get_data_size(mlog);
/* Open the database log for log_write_low */
2013-05-08 09:52:54 +02:00
mtr->start_lsn = log_open(data_size);
if (mtr->log_mode == MTR_LOG_ALL) {
2013-12-16 15:38:05 +01:00
for (dyn_block_t* block = mlog;
block != 0;
block = dyn_array_get_next_block(mlog, block)) {
2013-12-16 15:38:05 +01:00
log_write_low(
dyn_block_get_data(block),
dyn_block_get_used(block));
}
2013-12-16 15:38:05 +01:00
} else {
2013-12-16 15:38:05 +01:00
ut_ad(mtr->log_mode == MTR_LOG_NONE
|| mtr->log_mode == MTR_LOG_NO_REDO);
/* Do nothing */
}
mtr->end_lsn = log_close();
2011-07-14 21:22:41 +02:00
2013-12-16 15:38:05 +01:00
mtr_add_dirtied_pages_to_flush_list(mtr);
}
2009-09-07 10:22:53 +00:00
#endif /* !UNIV_HOTBACKUP */
2009-09-07 10:22:53 +00:00
/***************************************************************//**
Commits a mini-transaction. */
UNIV_INTERN
void
mtr_commit(
/*=======*/
2009-09-07 10:22:53 +00:00
mtr_t* mtr) /*!< in: mini-transaction */
{
ut_ad(mtr);
ut_ad(mtr->magic_n == MTR_MAGIC_N);
ut_ad(mtr->state == MTR_ACTIVE);
2011-07-14 21:22:41 +02:00
ut_ad(!mtr->inside_ibuf);
2009-03-25 23:11:11 -07:00
ut_d(mtr->state = MTR_COMMITTING);
2009-09-07 10:22:53 +00:00
#ifndef UNIV_HOTBACKUP
2010-01-06 04:00:14 -08:00
/* This is a dirty read, for debugging. */
ut_ad(!recv_no_log_write);
2011-07-14 21:22:41 +02:00
if (mtr->modifications && mtr->n_log_recs) {
2013-12-16 15:38:05 +01:00
ut_ad(!srv_read_only_mode);
mtr_log_reserve_and_write(mtr);
}
2009-06-24 18:43:25 -07:00
mtr_memo_pop_all(mtr);
2009-09-07 10:22:53 +00:00
#endif /* !UNIV_HOTBACKUP */
dyn_array_free(&(mtr->memo));
dyn_array_free(&(mtr->log));
#ifdef UNIV_DEBUG_VALGRIND
/* Declare everything uninitialized except
mtr->start_lsn, mtr->end_lsn and mtr->state. */
{
2013-12-16 15:38:05 +01:00
lsn_t start_lsn = mtr->start_lsn;
lsn_t end_lsn = mtr->end_lsn;
UNIV_MEM_INVALID(mtr, sizeof *mtr);
mtr->start_lsn = start_lsn;
mtr->end_lsn = end_lsn;
}
#endif /* UNIV_DEBUG_VALGRIND */
ut_d(mtr->state = MTR_COMMITTED);
}
2009-09-07 10:22:53 +00:00
#ifndef UNIV_HOTBACKUP
/***************************************************//**
2013-12-16 15:38:05 +01:00
Releases an object in the memo stack.
@return true if released */
UNIV_INTERN
2013-12-16 15:38:05 +01:00
bool
mtr_memo_release(
/*=============*/
2013-07-16 14:55:47 +02:00
mtr_t* mtr, /*!< in/out: mini-transaction */
2009-09-07 10:22:53 +00:00
void* object, /*!< in: object */
ulint type) /*!< in: object type: MTR_MEMO_S_LOCK, ... */
{
ut_ad(mtr->magic_n == MTR_MAGIC_N);
ut_ad(mtr->state == MTR_ACTIVE);
2013-07-16 14:55:47 +02:00
/* We cannot release a page that has been written to in the
middle of a mini-transaction. */
ut_ad(!mtr->modifications || type != MTR_MEMO_PAGE_X_FIX);
2013-12-16 15:38:05 +01:00
for (const dyn_block_t* block = dyn_array_get_last_block(&mtr->memo);
2013-07-16 14:55:47 +02:00
block;
block = dyn_array_get_prev_block(&mtr->memo, block)) {
const mtr_memo_slot_t* start
2013-12-16 15:38:05 +01:00
= reinterpret_cast<mtr_memo_slot_t*>(
dyn_block_get_data(block));
2013-07-16 14:55:47 +02:00
mtr_memo_slot_t* slot
2013-12-16 15:38:05 +01:00
= reinterpret_cast<mtr_memo_slot_t*>(
dyn_block_get_data(block)
+ dyn_block_get_used(block));
2013-07-16 14:55:47 +02:00
ut_ad(!(dyn_block_get_used(block) % sizeof(mtr_memo_slot_t)));
while (slot-- != start) {
if (object == slot->object && type == slot->type) {
mtr_memo_slot_release(mtr, slot);
2013-12-16 15:38:05 +01:00
return(true);
2013-07-16 14:55:47 +02:00
}
}
}
2013-12-16 15:38:05 +01:00
return(false);
}
2009-09-07 10:22:53 +00:00
#endif /* !UNIV_HOTBACKUP */
2009-09-07 10:22:53 +00:00
/********************************************************//**
Reads 1 - 4 bytes from a file page buffered in the buffer pool.
@return value read */
UNIV_INTERN
ulint
mtr_read_ulint(
/*===========*/
2009-09-07 10:22:53 +00:00
const byte* ptr, /*!< in: pointer from where to read */
ulint type, /*!< in: MLOG_1BYTE, MLOG_2BYTES, MLOG_4BYTES */
mtr_t* mtr __attribute__((unused)))
2009-09-07 10:22:53 +00:00
/*!< in: mini-transaction handle */
{
ut_ad(mtr->state == MTR_ACTIVE);
ut_ad(mtr_memo_contains_page(mtr, ptr, MTR_MEMO_PAGE_S_FIX)
|| mtr_memo_contains_page(mtr, ptr, MTR_MEMO_PAGE_X_FIX));
2013-12-16 15:38:05 +01:00
return(mach_read_ulint(ptr, type));
}
#ifdef UNIV_DEBUG
2009-09-07 10:22:53 +00:00
# ifndef UNIV_HOTBACKUP
/**********************************************************//**
Checks if memo contains the given page.
@return TRUE if contains */
UNIV_INTERN
ibool
mtr_memo_contains_page(
/*===================*/
2009-09-07 10:22:53 +00:00
mtr_t* mtr, /*!< in: mtr */
const byte* ptr, /*!< in: pointer to buffer frame */
ulint type) /*!< in: type of object */
{
2009-03-25 23:11:11 -07:00
return(mtr_memo_contains(mtr, buf_block_align(ptr), type));
}
2009-09-07 10:22:53 +00:00
/*********************************************************//**
Prints info of an mtr handle. */
UNIV_INTERN
void
mtr_print(
/*======*/
2009-09-07 10:22:53 +00:00
mtr_t* mtr) /*!< in: mtr */
{
fprintf(stderr,
"Mini-transaction handle: memo size %lu bytes"
" log size %lu bytes\n",
(ulong) dyn_array_get_data_size(&(mtr->memo)),
(ulong) dyn_array_get_data_size(&(mtr->log)));
}
2009-09-07 10:22:53 +00:00
# endif /* !UNIV_HOTBACKUP */
#endif /* UNIV_DEBUG */
2014-12-22 16:53:17 +02:00
/**********************************************************//**
Releases a buf_page stored in an mtr memo after a
savepoint. */
UNIV_INTERN
void
mtr_release_buf_page_at_savepoint(
/*=============================*/
mtr_t* mtr, /*!< in: mtr */
ulint savepoint, /*!< in: savepoint */
buf_block_t* block) /*!< in: block to release */
{
mtr_memo_slot_t* slot;
dyn_array_t* memo;
ut_ad(mtr);
ut_ad(mtr->magic_n == MTR_MAGIC_N);
ut_ad(mtr->state == MTR_ACTIVE);
memo = &(mtr->memo);
ut_ad(dyn_array_get_data_size(memo) > savepoint);
slot = (mtr_memo_slot_t*) dyn_array_get_element(memo, savepoint);
ut_ad(slot->object == block);
ut_ad(slot->type == MTR_MEMO_PAGE_S_FIX ||
slot->type == MTR_MEMO_PAGE_X_FIX ||
slot->type == MTR_MEMO_BUF_FIX);
buf_page_release((buf_block_t*) slot->object, slot->type);
slot->object = NULL;
}