Commit 5098d708 authored by Marko Mäkelä's avatar Marko Mäkelä

Merge 10.2 into 10.3

parents d103c5a4 2570cb8b
......@@ -30,7 +30,7 @@ SET GLOBAL master_verify_checksum=0;
SET GLOBAL debug_dbug="+d,corrupt_read_log_event2_set";
connection slave;
START SLAVE IO_THREAD;
include/wait_for_slave_io_error.inc [errno=1595,1913]
include/wait_for_slave_io_error.inc [errno=1595,1743]
connection master;
SET GLOBAL debug_dbug="-d,corrupt_read_log_event2_set";
SET GLOBAL debug_dbug= "";
......@@ -39,7 +39,7 @@ SET GLOBAL master_verify_checksum=1;
connection slave;
SET GLOBAL debug_dbug="+d,corrupt_queue_event";
START SLAVE IO_THREAD;
include/wait_for_slave_io_error.inc [errno=1595,1913]
include/wait_for_slave_io_error.inc [errno=1595,1743]
SET GLOBAL debug_dbug="-d,corrupt_queue_event";
# 6. Slave. Corruption in relay log
SET GLOBAL debug_dbug="+d,corrupt_read_log_event_char";
......
......@@ -122,11 +122,11 @@ SET GLOBAL master_verify_checksum=0;
SET GLOBAL debug_dbug="+d,corrupt_read_log_event2_set";
--connection slave
START SLAVE IO_THREAD;
# When the checksum error is detected, the slave sets error code 1913
# When the checksum error is detected, the slave sets error code 1743
# (ER_NETWORK_READ_EVENT_CHECKSUM_FAILURE) in queue_event(), then immediately
# sets error 1595 (ER_SLAVE_RELAY_LOG_WRITE_FAILURE) in handle_slave_io().
# So we usually get 1595, but it is occasionally possible to get 1913.
let $slave_io_errno= 1595,1913;
# So we usually get 1595, but it is occasionally possible to get 1743.
let $slave_io_errno= 1595,1743; # ER_SLAVE_RELAY_LOG_WRITE_FAILURE, ER_NETWORK_READ_EVENT_CHECKSUM_FAILURE
--source include/wait_for_slave_io_error.inc
--connection master
SET GLOBAL debug_dbug="-d,corrupt_read_log_event2_set";
......@@ -138,7 +138,7 @@ SET GLOBAL master_verify_checksum=1;
--connection slave
SET GLOBAL debug_dbug="+d,corrupt_queue_event";
START SLAVE IO_THREAD;
let $slave_io_errno= 1595,1913;
let $slave_io_errno= 1595,1743; # ER_SLAVE_RELAY_LOG_WRITE_FAILURE, ER_NETWORK_READ_EVENT_CHECKSUM_FAILURE
--source include/wait_for_slave_io_error.inc
SET GLOBAL debug_dbug="-d,corrupt_queue_event";
......
......@@ -30,7 +30,7 @@ SET GLOBAL master_verify_checksum=0;
SET GLOBAL debug_dbug="+d,corrupt_read_log_event2_set";
connection slave;
START SLAVE IO_THREAD;
include/wait_for_slave_io_error.inc [errno=1595,1913]
include/wait_for_slave_io_error.inc [errno=1595,1743]
connection master;
SET GLOBAL debug_dbug="-d,corrupt_read_log_event2_set";
SET GLOBAL debug_dbug= "";
......@@ -39,7 +39,7 @@ SET GLOBAL master_verify_checksum=1;
connection slave;
SET GLOBAL debug_dbug="+d,corrupt_queue_event";
START SLAVE IO_THREAD;
include/wait_for_slave_io_error.inc [errno=1595,1913]
include/wait_for_slave_io_error.inc [errno=1595,1743]
SET GLOBAL debug_dbug="-d,corrupt_queue_event";
# 6. Slave. Corruption in relay log
SET GLOBAL debug_dbug="+d,corrupt_read_log_event_char";
......
......@@ -2,7 +2,7 @@
Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
Copyright (c) 2013, 2018, MariaDB Corporation.
Copyright (c) 2013, 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
......@@ -134,62 +134,7 @@ struct mtr_memo_slot_t {
/** Mini-transaction handle and buffer */
struct mtr_t {
/** State variables of the mtr */
struct Impl {
/** memo stack for locks etc. */
mtr_buf_t m_memo;
/** mini-transaction log */
mtr_buf_t m_log;
/** true if mtr has made at least one buffer pool page dirty */
bool m_made_dirty;
/** true if inside ibuf changes */
bool m_inside_ibuf;
/** true if the mini-transaction modified buffer pool pages */
bool m_modifications;
/** Count of how many page initial log records have been
written to the mtr log */
ib_uint32_t m_n_log_recs;
/** specifies which operations should be logged; default
value MTR_LOG_ALL */
mtr_log_t m_log_mode;
#ifdef UNIV_DEBUG
/** Persistent user tablespace associated with the
mini-transaction, or 0 (TRX_SYS_SPACE) if none yet */
ulint m_user_space_id;
#endif /* UNIV_DEBUG */
/** User tablespace that is being modified by the
mini-transaction */
fil_space_t* m_user_space;
/** State of the transaction */
mtr_state_t m_state;
/** Flush Observer */
FlushObserver* m_flush_observer;
#ifdef UNIV_DEBUG
/** For checking corruption. */
ulint m_magic_n;
#endif /* UNIV_DEBUG */
/** Owning mini-transaction */
mtr_t* m_mtr;
};
mtr_t()
{
m_impl.m_state = MTR_STATE_INIT;
}
~mtr_t() { }
mtr_t() : m_state(MTR_STATE_INIT) {}
/** Start a mini-transaction. */
void start();
......@@ -211,14 +156,7 @@ struct mtr_t {
/** Return current size of the buffer.
@return savepoint */
ulint get_savepoint() const
MY_ATTRIBUTE((warn_unused_result))
{
ut_ad(is_active());
ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
return(m_impl.m_memo.size());
}
ulint get_savepoint() const {ut_ad(is_active()); return m_memo.size();}
/** Release the (index tree) s-latch stored in an mtr memo after a
savepoint.
......@@ -255,11 +193,11 @@ struct mtr_t {
the same set of tablespaces as this one */
void set_spaces(const mtr_t& mtr)
{
ut_ad(!m_impl.m_user_space_id);
ut_ad(!m_impl.m_user_space);
ut_ad(!m_user_space_id);
ut_ad(!m_user_space);
ut_d(m_impl.m_user_space_id = mtr.m_impl.m_user_space_id);
m_impl.m_user_space = mtr.m_impl.m_user_space;
ut_d(m_user_space_id = mtr.m_user_space_id);
m_user_space = mtr.m_user_space;
}
/** Set the tablespace associated with the mini-transaction
......@@ -268,16 +206,16 @@ struct mtr_t {
@return the tablespace */
fil_space_t* set_named_space_id(ulint space_id)
{
ut_ad(!m_impl.m_user_space_id);
ut_d(m_impl.m_user_space_id = space_id);
ut_ad(!m_user_space_id);
ut_d(m_user_space_id = space_id);
if (!space_id) {
return fil_system.sys_space;
} else {
ut_ad(m_impl.m_user_space_id == space_id);
ut_ad(!m_impl.m_user_space);
m_impl.m_user_space = fil_space_get(space_id);
ut_ad(m_impl.m_user_space);
return m_impl.m_user_space;
ut_ad(m_user_space_id == space_id);
ut_ad(!m_user_space);
m_user_space = fil_space_get(space_id);
ut_ad(m_user_space);
return m_user_space;
}
}
......@@ -286,10 +224,10 @@ struct mtr_t {
@param[in] space user or system tablespace */
void set_named_space(fil_space_t* space)
{
ut_ad(!m_impl.m_user_space_id);
ut_d(m_impl.m_user_space_id = space->id);
ut_ad(!m_user_space_id);
ut_d(m_user_space_id = space->id);
if (space->id) {
m_impl.m_user_space = space;
m_user_space = space;
}
}
......@@ -356,18 +294,12 @@ struct mtr_t {
void release_page(const void* ptr, mtr_memo_type_t type);
/** Note that the mini-transaction has modified data. */
void set_modified()
{
m_impl.m_modifications = true;
}
void set_modified() { m_modifications = true; }
/** Set the state to not-modified. This will not log the
changes. This is only used during redo log apply, to avoid
logging the changes. */
void discard_modifications()
{
m_impl.m_modifications = false;
}
void discard_modifications() { m_modifications = false; }
/** Get the LSN of commit().
@return the commit LSN
......@@ -379,45 +311,28 @@ struct mtr_t {
}
/** Note that we are inside the change buffer code. */
void enter_ibuf()
{
m_impl.m_inside_ibuf = true;
}
void enter_ibuf() { m_inside_ibuf = true; }
/** Note that we have exited from the change buffer code. */
void exit_ibuf()
{
m_impl.m_inside_ibuf = false;
}
void exit_ibuf() { m_inside_ibuf = false; }
/** @return true if we are inside the change buffer code */
bool is_inside_ibuf() const
{
return(m_impl.m_inside_ibuf);
}
bool is_inside_ibuf() const { return m_inside_ibuf; }
/*
@return true if the mini-transaction is active */
bool is_active() const
{
return(m_impl.m_state == MTR_STATE_ACTIVE);
}
bool is_active() const { return m_state == MTR_STATE_ACTIVE; }
/** Get flush observer
@return flush observer */
FlushObserver* get_flush_observer() const
{
return(m_impl.m_flush_observer);
}
FlushObserver* get_flush_observer() const { return m_flush_observer; }
/** Set flush observer
@param[in] observer flush observer */
void set_flush_observer(FlushObserver* observer)
{
ut_ad(observer == NULL
|| m_impl.m_log_mode == MTR_LOG_NO_REDO);
m_impl.m_flush_observer = observer;
ut_ad(observer == NULL || m_log_mode == MTR_LOG_NO_REDO);
m_flush_observer = observer;
}
#ifdef UNIV_DEBUG
......@@ -457,65 +372,31 @@ struct mtr_t {
void print() const;
/** @return true if the mini-transaction has committed */
bool has_committed() const
{
return(m_impl.m_state == MTR_STATE_COMMITTED);
}
/** @return true if the mini-transaction is committing */
bool is_committing() const
{
return(m_impl.m_state == MTR_STATE_COMMITTING);
}
bool has_committed() const { return m_state == MTR_STATE_COMMITTED; }
/** @return true if mini-transaction contains modifications. */
bool has_modifications() const
{
return(m_impl.m_modifications);
}
bool has_modifications() const { return m_modifications; }
/** @return the memo stack */
const mtr_buf_t* get_memo() const
{
return(&m_impl.m_memo);
}
const mtr_buf_t* get_memo() const { return &m_memo; }
/** @return the memo stack */
mtr_buf_t* get_memo()
{
return(&m_impl.m_memo);
}
mtr_buf_t* get_memo() { return &m_memo; }
#endif /* UNIV_DEBUG */
/** @return true if a record was added to the mini-transaction */
bool is_dirty() const
{
return(m_impl.m_made_dirty);
}
bool is_dirty() const { return m_made_dirty; }
/** Note that a record has been added to the log */
void added_rec()
{
++m_impl.m_n_log_recs;
}
void added_rec() { ++m_n_log_recs; }
/** Get the buffered redo log of this mini-transaction.
@return redo log */
const mtr_buf_t* get_log() const
{
ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
return(&m_impl.m_log);
}
const mtr_buf_t* get_log() const { return &m_log; }
/** Get the buffered redo log of this mini-transaction.
@return redo log */
mtr_buf_t* get_log()
{
ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
return(&m_impl.m_log);
}
mtr_buf_t* get_log() { return &m_log; }
/** Push an object to an mtr memo stack.
@param object object
......@@ -529,15 +410,56 @@ struct mtr_t {
MY_ATTRIBUTE((warn_unused_result));
private:
class Command;
/** Prepare to write the mini-transaction log to the redo log buffer.
@return number of bytes to write in finish_write() */
inline ulint prepare_write();
friend class Command;
/** Append the redo log records to the redo log buffer.
@param[in] len number of bytes to write
@return start_lsn */
inline lsn_t finish_write(ulint len);
private:
Impl m_impl;
/** Release the resources */
inline void release_resources();
/** memo stack for locks etc. */
mtr_buf_t m_memo;
/** mini-transaction log */
mtr_buf_t m_log;
/** true if mtr has made at least one buffer pool page dirty */
bool m_made_dirty;
/** true if inside ibuf changes */
bool m_inside_ibuf;
/** true if the mini-transaction modified buffer pool pages */
bool m_modifications;
/** Count of how many page initial log records have been
written to the mtr log */
ib_uint32_t m_n_log_recs;
/** specifies which operations should be logged; default
value MTR_LOG_ALL */
mtr_log_t m_log_mode;
#ifdef UNIV_DEBUG
/** Persistent user tablespace associated with the
mini-transaction, or 0 (TRX_SYS_SPACE) if none yet */
ulint m_user_space_id;
#endif /* UNIV_DEBUG */
/** User tablespace that is being modified by the mini-transaction */
fil_space_t* m_user_space;
/** State of the transaction */
mtr_state_t m_state;
/** Flush Observer */
FlushObserver* m_flush_observer;
/** LSN at commit time */
volatile lsn_t m_commit_lsn;
lsn_t m_commit_lsn;
};
#include "mtr0mtr.ic"
......
......@@ -49,7 +49,6 @@ mtr_t::memo_push(void* object, mtr_memo_type_t type)
ut_ad(object != NULL);
ut_ad(type >= MTR_MEMO_PAGE_S_FIX);
ut_ad(type <= MTR_MEMO_SX_LOCK);
ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
ut_ad(ut_is_2pow(type));
/* If this mtr has x-fixed a clean page then we set
......@@ -58,15 +57,13 @@ mtr_t::memo_push(void* object, mtr_memo_type_t type)
can insert the dirtied page to the flush list. */
if ((type == MTR_MEMO_PAGE_X_FIX || type == MTR_MEMO_PAGE_SX_FIX)
&& !m_impl.m_made_dirty) {
&& !m_made_dirty) {
m_impl.m_made_dirty = is_block_dirtied(
m_made_dirty = is_block_dirtied(
reinterpret_cast<const buf_block_t*>(object));
}
mtr_memo_slot_t* slot;
slot = m_impl.m_memo.push<mtr_memo_slot_t*>(sizeof(*slot));
mtr_memo_slot_t* slot = m_memo.push<mtr_memo_slot_t*>(sizeof(*slot));
slot->type = type;
slot->object = object;
......@@ -81,11 +78,9 @@ mtr_t::release_s_latch_at_savepoint(
rw_lock_t* lock)
{
ut_ad(is_active());
ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
ut_ad(m_impl.m_memo.size() > savepoint);
ut_ad(m_memo.size() > savepoint);
mtr_memo_slot_t* slot = m_impl.m_memo.at<mtr_memo_slot_t*>(savepoint);
mtr_memo_slot_t* slot = m_memo.at<mtr_memo_slot_t*>(savepoint);
ut_ad(slot->object == lock);
ut_ad(slot->type == MTR_MEMO_S_LOCK);
......@@ -104,8 +99,7 @@ mtr_t::sx_latch_at_savepoint(
buf_block_t* block)
{
ut_ad(is_active());
ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
ut_ad(m_impl.m_memo.size() > savepoint);
ut_ad(m_memo.size() > savepoint);
ut_ad(!memo_contains_flagged(
block,
......@@ -113,9 +107,7 @@ mtr_t::sx_latch_at_savepoint(
| MTR_MEMO_PAGE_X_FIX
| MTR_MEMO_PAGE_SX_FIX));
mtr_memo_slot_t* slot;
slot = m_impl.m_memo.at<mtr_memo_slot_t*>(savepoint);
mtr_memo_slot_t* slot = m_memo.at<mtr_memo_slot_t*>(savepoint);
ut_ad(slot->object == block);
......@@ -124,8 +116,8 @@ mtr_t::sx_latch_at_savepoint(
rw_lock_sx_lock(&block->lock);
if (!m_impl.m_made_dirty) {
m_impl.m_made_dirty = is_block_dirtied(block);
if (!m_made_dirty) {
m_made_dirty = is_block_dirtied(block);
}
slot->type = MTR_MEMO_PAGE_SX_FIX;
......@@ -140,8 +132,7 @@ mtr_t::x_latch_at_savepoint(
buf_block_t* block)
{
ut_ad(is_active());
ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
ut_ad(m_impl.m_memo.size() > savepoint);
ut_ad(m_memo.size() > savepoint);
ut_ad(!memo_contains_flagged(
block,
......@@ -149,9 +140,7 @@ mtr_t::x_latch_at_savepoint(
| MTR_MEMO_PAGE_X_FIX
| MTR_MEMO_PAGE_SX_FIX));
mtr_memo_slot_t* slot;
slot = m_impl.m_memo.at<mtr_memo_slot_t*>(savepoint);
mtr_memo_slot_t* slot = m_memo.at<mtr_memo_slot_t*>(savepoint);
ut_ad(slot->object == block);
......@@ -160,8 +149,8 @@ mtr_t::x_latch_at_savepoint(
rw_lock_x_lock(&block->lock);
if (!m_impl.m_made_dirty) {
m_impl.m_made_dirty = is_block_dirtied(block);
if (!m_made_dirty) {
m_made_dirty = is_block_dirtied(block);
}
slot->type = MTR_MEMO_PAGE_X_FIX;
......@@ -176,11 +165,8 @@ mtr_t::release_block_at_savepoint(
buf_block_t* block)
{
ut_ad(is_active());
ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
mtr_memo_slot_t* slot;
slot = m_impl.m_memo.at<mtr_memo_slot_t*>(savepoint);
mtr_memo_slot_t* slot = m_memo.at<mtr_memo_slot_t*>(savepoint);
ut_a(slot->object == block);
......@@ -198,10 +184,10 @@ Gets the logging mode of a mini-transaction.
mtr_log_t
mtr_t::get_log_mode() const
{
ut_ad(m_impl.m_log_mode >= MTR_LOG_ALL);
ut_ad(m_impl.m_log_mode <= MTR_LOG_SHORT_INSERTS);
ut_ad(m_log_mode >= MTR_LOG_ALL);
ut_ad(m_log_mode <= MTR_LOG_SHORT_INSERTS);
return(m_impl.m_log_mode);
return m_log_mode;
}
/**
......@@ -214,7 +200,7 @@ mtr_t::set_log_mode(mtr_log_t mode)
ut_ad(mode >= MTR_LOG_ALL);
ut_ad(mode <= MTR_LOG_SHORT_INSERTS);
const mtr_log_t old_mode = m_impl.m_log_mode;
const mtr_log_t old_mode = m_log_mode;
switch (old_mode) {
case MTR_LOG_NO_REDO:
......@@ -233,9 +219,8 @@ mtr_t::set_log_mode(mtr_log_t mode)
case MTR_LOG_ALL:
/* MTR_LOG_NO_REDO can only be set before generating
any redo log records. */
ut_ad(mode != MTR_LOG_NO_REDO
|| m_impl.m_n_log_recs == 0);
m_impl.m_log_mode = mode;
ut_ad(mode != MTR_LOG_NO_REDO || m_n_log_recs == 0);
m_log_mode = mode;
return(old_mode);
}
......
/*****************************************************************************
Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 2018, MariaDB Corporation.
Copyright (c) 2017, 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
......@@ -36,18 +36,18 @@ struct mtr_t;
/** Logging modes for a mini-transaction */
enum mtr_log_t {
/** Default mode: log all operations modifying disk-based data */
MTR_LOG_ALL = 21,
MTR_LOG_ALL = 0,
/** Log no operations and dirty pages are not added to the flush list.
Set when applying log in crash recovery or when a modification of a
ROW_FORMAT=COMPRESSED page is attempted. */
MTR_LOG_NONE = 22,
MTR_LOG_NONE,
/** Don't generate REDO log but add dirty pages to flush list */
MTR_LOG_NO_REDO = 23,
MTR_LOG_NO_REDO,
/** Inserts are logged in a shorter form */
MTR_LOG_SHORT_INSERTS = 24
MTR_LOG_SHORT_INSERTS
};
/** @name Log item types
......@@ -271,15 +271,10 @@ enum mtr_memo_type_t {
};
#endif /* !UNIV_CHECKSUM */
#ifdef UNIV_DEBUG
# define MTR_MAGIC_N 54551
#endif /* UNIV_DEBUG */
enum mtr_state_t {
MTR_STATE_INIT = 0,
MTR_STATE_ACTIVE = 12231,
MTR_STATE_COMMITTING = 56456,
MTR_STATE_COMMITTED = 34676
MTR_STATE_ACTIVE,
MTR_STATE_COMMITTED
};
#endif /* mtr0types_h */
......@@ -27,7 +27,6 @@ Created 9/20/1997 Heikki Tuuri
#include "univ.i"
#include <vector>
#include <map>
#include <string>
#include <my_service_manager.h>
......@@ -3971,44 +3970,26 @@ recv_recovery_rollback_active(void)
@param[in] page_no page number
@return page frame
@retval NULL if no page was found */
const byte*
recv_dblwr_t::find_page(ulint space_id, ulint page_no)
{
typedef std::vector<const byte*, ut_allocator<const byte*> >
matches_t;
matches_t matches;
const byte* result = 0;
for (list::iterator i = pages.begin(); i != pages.end(); ++i) {
if (page_get_space_id(*i) == space_id
&& page_get_page_no(*i) == page_no) {
matches.push_back(*i);
}
}
if (matches.size() == 1) {
result = matches[0];
} else if (matches.size() > 1) {
lsn_t max_lsn = 0;
lsn_t page_lsn = 0;
const byte *result= NULL;
lsn_t max_lsn= 0;
for (matches_t::iterator i = matches.begin();
i != matches.end();
++i) {
page_lsn = mach_read_from_8(*i + FIL_PAGE_LSN);
if (page_lsn > max_lsn) {
max_lsn = page_lsn;
result = *i;
}
}
for (list::const_iterator i = pages.begin(); i != pages.end(); ++i)
{
const byte *page= *i;
if (page_get_page_no(page) != page_no ||
page_get_space_id(page) != space_id)
continue;
const lsn_t lsn= mach_read_from_8(page + FIL_PAGE_LSN);
if (lsn <= max_lsn)
continue;
max_lsn= lsn;
result= page;
}
return(result);
return result;
}
#ifndef DBUG_OFF
......
......@@ -343,6 +343,7 @@ struct ReleaseAll {
}
};
#ifdef UNIV_DEBUG
/** Check that all slots have been handled. */
struct DebugCheck {
/** @return true always. */
......@@ -352,6 +353,7 @@ struct DebugCheck {
return(true);
}
};
#endif
/** Release a resource acquired by the mini-transaction. */
struct ReleaseBlocks {
......@@ -404,59 +406,6 @@ struct ReleaseBlocks {
FlushObserver* m_flush_observer;
};
class mtr_t::Command {
public:
/** Constructor.
Takes ownership of the mtr->m_impl, is responsible for deleting it.
@param[in,out] mtr mini-transaction */
explicit Command(mtr_t* mtr) : m_impl(&mtr->m_impl), m_locks_released()
{}
/** Destructor */
~Command()
{
ut_ad(m_impl == 0);
}
/** Write the redo log record, add dirty pages to the flush list and
release the resources. */
void execute();
/** Release the blocks used in this mini-transaction. */
void release_blocks();
/** Release the latches acquired by the mini-transaction. */
void release_latches();
/** Release both the latches and blocks used in the mini-transaction. */
void release_all();
/** Release the resources */
void release_resources();
/** Append the redo log records to the redo log buffer.
@param[in] len number of bytes to write */
void finish_write(ulint len);
private:
/** Prepare to write the mini-transaction log to the redo log buffer.
@return number of bytes to write in finish_write() */
ulint prepare_write();
/** The mini-transaction state. */
mtr_t::Impl* m_impl;
/** Set to 1 after the user thread releases the latches. The log
writer thread must wait for this to be set to 1. */
volatile ulint m_locks_released;
/** Start lsn of the possible log entry for this mtr */
lsn_t m_start_lsn;
/** End lsn of the possible log entry for this mtr */
lsn_t m_end_lsn;
};
/** Write the block contents to the REDO log */
struct mtr_write_log_t {
/** Append a block to the redo log buffer.
......@@ -490,48 +439,30 @@ mtr_write_log(
/** Start a mini-transaction. */
void mtr_t::start()
{
UNIV_MEM_INVALID(this, sizeof(*this));
UNIV_MEM_INVALID(&m_impl, sizeof(m_impl));
m_commit_lsn = 0;
new(&m_impl.m_log) mtr_buf_t();
new(&m_impl.m_memo) mtr_buf_t();
m_impl.m_mtr = this;
m_impl.m_log_mode = MTR_LOG_ALL;
m_impl.m_inside_ibuf = false;
m_impl.m_modifications = false;
m_impl.m_made_dirty = false;
m_impl.m_n_log_recs = 0;
m_impl.m_state = MTR_STATE_ACTIVE;
ut_d(m_impl.m_user_space_id = TRX_SYS_SPACE);
m_impl.m_user_space = NULL;
m_impl.m_flush_observer = NULL;
ut_d(m_impl.m_magic_n = MTR_MAGIC_N);
UNIV_MEM_INVALID(this, sizeof *this);
new(&m_memo) mtr_buf_t();
new(&m_log) mtr_buf_t();
m_made_dirty= false;
m_inside_ibuf= false;
m_modifications= false;
m_n_log_recs= 0;
m_log_mode= MTR_LOG_ALL;
ut_d(m_user_space_id= TRX_SYS_SPACE);
m_user_space= NULL;
m_state= MTR_STATE_ACTIVE;
m_flush_observer= NULL;
m_commit_lsn= 0;
}
/** Release the resources */
void
mtr_t::Command::release_resources()
inline void mtr_t::release_resources()
{
ut_ad(m_impl->m_magic_n == MTR_MAGIC_N);
/* Currently only used in commit */
ut_ad(m_impl->m_state == MTR_STATE_COMMITTING);
ut_d(m_impl->m_memo.for_each_block_in_reverse(CIterate<DebugCheck>()));
/* Reset the mtr buffers */
m_impl->m_log.erase();
m_impl->m_memo.erase();
m_impl->m_state = MTR_STATE_COMMITTED;
m_impl = 0;
ut_d(m_memo.for_each_block_in_reverse(CIterate<DebugCheck>()));
m_log.erase();
m_memo.erase();
m_state= MTR_STATE_COMMITTED;
}
/** Commit a mini-transaction. */
......@@ -540,26 +471,43 @@ mtr_t::commit()
{
ut_ad(is_active());
ut_ad(!is_inside_ibuf());
ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
m_impl.m_state = MTR_STATE_COMMITTING;
/* This is a dirty read, for debugging. */
ut_ad(!m_impl.m_modifications || !recv_no_log_write);
ut_ad(!m_modifications || !recv_no_log_write);
ut_ad(!m_modifications || m_log_mode != MTR_LOG_NONE);
Command cmd(this);
if (m_modifications
&& (m_n_log_recs || m_log_mode == MTR_LOG_NO_REDO))
{
ut_ad(!srv_read_only_mode || m_log_mode == MTR_LOG_NO_REDO);
if (m_impl.m_modifications
&& (m_impl.m_n_log_recs > 0
|| m_impl.m_log_mode == MTR_LOG_NO_REDO)) {
lsn_t start_lsn;
ut_ad(!srv_read_only_mode
|| m_impl.m_log_mode == MTR_LOG_NO_REDO);
if (const ulint len= prepare_write())
start_lsn= finish_write(len);
else
start_lsn= m_commit_lsn;
cmd.execute();
} else {
cmd.release_all();
cmd.release_resources();
if (m_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_mutex_exit();
m_memo.for_each_block_in_reverse(CIterate<const ReleaseBlocks>
(ReleaseBlocks(start_lsn, m_commit_lsn,
m_flush_observer)));
if (m_made_dirty)
log_flush_order_mutex_exit();
m_memo.for_each_block_in_reverse(CIterate<ReleaseLatches>());
}
else
m_memo.for_each_block_in_reverse(CIterate<ReleaseAll>());
release_resources();
}
/** Commit a mini-transaction that did not modify any pages,
......@@ -578,35 +526,31 @@ mtr_t::commit_checkpoint(
ut_ad(log_mutex_own());
ut_ad(is_active());
ut_ad(!is_inside_ibuf());
ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
ut_ad(get_log_mode() == MTR_LOG_ALL);
ut_ad(!m_impl.m_made_dirty);
ut_ad(m_impl.m_memo.size() == 0);
ut_ad(!m_made_dirty);
ut_ad(m_memo.size() == 0);
ut_ad(!srv_read_only_mode);
ut_d(m_impl.m_state = MTR_STATE_COMMITTING);
ut_ad(write_mlog_checkpoint || m_impl.m_n_log_recs > 1);
ut_ad(write_mlog_checkpoint || m_n_log_recs > 1);
switch (m_impl.m_n_log_recs) {
switch (m_n_log_recs) {
case 0:
break;
case 1:
*m_impl.m_log.front()->begin() |= MLOG_SINGLE_REC_FLAG;
*m_log.front()->begin() |= MLOG_SINGLE_REC_FLAG;
break;
default:
mlog_catenate_ulint(
&m_impl.m_log, MLOG_MULTI_REC_END, MLOG_1BYTE);
mlog_catenate_ulint(&m_log, MLOG_MULTI_REC_END, MLOG_1BYTE);
}
if (write_mlog_checkpoint) {
byte* ptr = m_impl.m_log.push<byte*>(SIZE_OF_MLOG_CHECKPOINT);
byte* ptr = m_log.push<byte*>(SIZE_OF_MLOG_CHECKPOINT);
compile_time_assert(SIZE_OF_MLOG_CHECKPOINT == 1 + 8);
*ptr = MLOG_CHECKPOINT;
mach_write_to_8(ptr + 1, checkpoint_lsn);
}
Command cmd(this);
cmd.finish_write(m_impl.m_log.size());
cmd.release_resources();
finish_write(m_log.size());
release_resources();
if (write_mlog_checkpoint) {
DBUG_PRINT("ib_log",
......@@ -623,8 +567,7 @@ mtr_t::commit_checkpoint(
bool
mtr_t::is_named_space(ulint space) const
{
ut_ad(!m_impl.m_user_space
|| m_impl.m_user_space->id != TRX_SYS_SPACE);
ut_ad(!m_user_space || m_user_space->id != TRX_SYS_SPACE);
switch (get_log_mode()) {
case MTR_LOG_NONE:
......@@ -632,7 +575,7 @@ mtr_t::is_named_space(ulint space) const
return(true);
case MTR_LOG_ALL:
case MTR_LOG_SHORT_INSERTS:
return(m_impl.m_user_space_id == space
return(m_user_space_id == space
|| is_predefined_tablespace(space));
}
......@@ -645,8 +588,7 @@ mtr_t::is_named_space(ulint space) const
@return whether the mini-transaction is associated with the space */
bool mtr_t::is_named_space(const fil_space_t* space) const
{
ut_ad(!m_impl.m_user_space
|| m_impl.m_user_space->id != TRX_SYS_SPACE);
ut_ad(!m_user_space || m_user_space->id != TRX_SYS_SPACE);
switch (get_log_mode()) {
case MTR_LOG_NONE:
......@@ -654,8 +596,7 @@ bool mtr_t::is_named_space(const fil_space_t* space) const
return true;
case MTR_LOG_ALL:
case MTR_LOG_SHORT_INSERTS:
return(m_impl.m_user_space == space
|| is_predefined_tablespace(space->id));
return m_user_space == space || is_predefined_tablespace(space->id);
}
ut_error;
......@@ -674,12 +615,11 @@ mtr_t::x_lock_space(ulint space_id, const char* file, unsigned line)
{
fil_space_t* space;
ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
ut_ad(is_active());
if (space_id == TRX_SYS_SPACE) {
space = fil_system.sys_space;
} else if ((space = m_impl.m_user_space) && space_id == space->id) {
} else if ((space = m_user_space) && space_id == space->id) {
} else {
space = fil_space_get(space_id);
ut_ad(get_log_mode() != MTR_LOG_NO_REDO
......@@ -703,16 +643,15 @@ mtr_t::x_lock_space(ulint space_id, const char* file, unsigned line)
bool
mtr_t::memo_release(const void* object, ulint type)
{
ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
ut_ad(is_active());
/* We cannot release a page that has been written to in the
middle of a mini-transaction. */
ut_ad(!m_impl.m_modifications || type != MTR_MEMO_PAGE_X_FIX);
ut_ad(!m_modifications || type != MTR_MEMO_PAGE_X_FIX);
Iterate<Find> iteration(Find(object, type));
if (!m_impl.m_memo.for_each_block_in_reverse(iteration)) {
if (!m_memo.for_each_block_in_reverse(iteration)) {
memo_slot_release(iteration.functor.m_slot);
return(true);
}
......@@ -726,16 +665,15 @@ mtr_t::memo_release(const void* object, ulint type)
void
mtr_t::release_page(const void* ptr, mtr_memo_type_t type)
{
ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
ut_ad(is_active());
/* We cannot release a page that has been written to in the
middle of a mini-transaction. */
ut_ad(!m_impl.m_modifications || type != MTR_MEMO_PAGE_X_FIX);
ut_ad(!m_modifications || type != MTR_MEMO_PAGE_X_FIX);
Iterate<FindPage> iteration(FindPage(ptr, type));
if (!m_impl.m_memo.for_each_block_in_reverse(iteration)) {
if (!m_memo.for_each_block_in_reverse(iteration)) {
memo_slot_release(iteration.functor.get_slot());
return;
}
......@@ -746,27 +684,20 @@ mtr_t::release_page(const void* ptr, mtr_memo_type_t type)
/** Prepare to write the mini-transaction log to the redo log buffer.
@return number of bytes to write in finish_write() */
ulint
mtr_t::Command::prepare_write()
inline ulint mtr_t::prepare_write()
{
ut_ad(!recv_no_log_write);
switch (m_impl->m_log_mode) {
case MTR_LOG_SHORT_INSERTS:
ut_ad(0);
/* fall through */
case MTR_LOG_NO_REDO:
case MTR_LOG_NONE:
ut_ad(m_impl->m_log.size() == 0);
if (UNIV_UNLIKELY(m_log_mode != MTR_LOG_ALL)) {
ut_ad(m_log_mode == MTR_LOG_NO_REDO);
ut_ad(m_log.size() == 0);
log_mutex_enter();
m_end_lsn = m_start_lsn = log_sys.lsn;
return(0);
case MTR_LOG_ALL:
break;
m_commit_lsn = log_sys.lsn;
return 0;
}
ulint len = m_impl->m_log.size();
ulint n_recs = m_impl->m_n_log_recs;
ulint len = m_log.size();
ulint n_recs = m_n_log_recs;
ut_ad(len > 0);
ut_ad(n_recs > 0);
......@@ -774,9 +705,9 @@ mtr_t::Command::prepare_write()
log_buffer_extend(ulong((len + 1) * 2));
}
ut_ad(m_impl->m_n_log_recs == n_recs);
ut_ad(m_n_log_recs == n_recs);
fil_space_t* space = m_impl->m_user_space;
fil_space_t* space = m_user_space;
if (space != NULL && is_predefined_tablespace(space->id)) {
/* Omit MLOG_FILE_NAME for predefined tablespaces. */
......@@ -785,34 +716,31 @@ mtr_t::Command::prepare_write()
log_mutex_enter();
if (fil_names_write_if_was_clean(space, m_impl->m_mtr)) {
if (fil_names_write_if_was_clean(space, this)) {
/* This mini-transaction was the first one to modify
this tablespace since the latest checkpoint, so
some MLOG_FILE_NAME records were appended to m_log. */
ut_ad(m_impl->m_n_log_recs > n_recs);
mlog_catenate_ulint(
&m_impl->m_log, MLOG_MULTI_REC_END, MLOG_1BYTE);
len = m_impl->m_log.size();
ut_ad(m_n_log_recs > n_recs);
mlog_catenate_ulint(&m_log, MLOG_MULTI_REC_END, MLOG_1BYTE);
len = m_log.size();
} else {
/* This was not the first time of dirtying a
tablespace since the latest checkpoint. */
ut_ad(n_recs == m_impl->m_n_log_recs);
ut_ad(n_recs == m_n_log_recs);
if (n_recs <= 1) {
ut_ad(n_recs == 1);
/* Flag the single log record as the
only record in this mini-transaction. */
*m_impl->m_log.front()->begin()
|= MLOG_SINGLE_REC_FLAG;
*m_log.front()->begin() |= MLOG_SINGLE_REC_FLAG;
} else {
/* Because this mini-transaction comprises
multiple log records, append MLOG_MULTI_REC_END
at the end. */
mlog_catenate_ulint(
&m_impl->m_log, MLOG_MULTI_REC_END,
mlog_catenate_ulint(&m_log, MLOG_MULTI_REC_END,
MLOG_1BYTE);
len++;
}
......@@ -825,98 +753,37 @@ mtr_t::Command::prepare_write()
}
/** Append the redo log records to the redo log buffer
@param[in] len number of bytes to write */
void
mtr_t::Command::finish_write(
ulint len)
@param[in] len number of bytes to write
@return start_lsn */
inline lsn_t mtr_t::finish_write(ulint len)
{
ut_ad(m_impl->m_log_mode == MTR_LOG_ALL);
ut_ad(m_log_mode == MTR_LOG_ALL);
ut_ad(log_mutex_own());
ut_ad(m_impl->m_log.size() == len);
ut_ad(m_log.size() == len);
ut_ad(len > 0);
if (m_impl->m_log.is_small()) {
const mtr_buf_t::block_t* front = m_impl->m_log.front();
lsn_t start_lsn;
if (m_log.is_small()) {
const mtr_buf_t::block_t* front = m_log.front();
ut_ad(len <= front->used());
m_end_lsn = log_reserve_and_write_fast(
front->begin(), len, &m_start_lsn);
m_commit_lsn = log_reserve_and_write_fast(front->begin(), len,
&start_lsn);
if (m_end_lsn > 0) {
return;
if (m_commit_lsn) {
return start_lsn;
}
}
/* Open the database log for log_write_low */
m_start_lsn = log_reserve_and_open(len);
start_lsn = log_reserve_and_open(len);
mtr_write_log_t write_log;
m_impl->m_log.for_each_block(write_log);
m_end_lsn = log_close();
}
/** Release the latches and blocks acquired by this mini-transaction */
void
mtr_t::Command::release_all()
{
m_impl->m_memo.for_each_block_in_reverse(CIterate<ReleaseAll>());
/* Note that we have released the latches. */
m_locks_released = 1;
}
/** Release the latches acquired by this mini-transaction */
void
mtr_t::Command::release_latches()
{
m_impl->m_memo.for_each_block_in_reverse(CIterate<ReleaseLatches>());
/* Note that we have released the latches. */
m_locks_released = 1;
}
/** Release the blocks used in this mini-transaction */
void
mtr_t::Command::release_blocks()
{
m_impl->m_memo.for_each_block_in_reverse(
CIterate<const ReleaseBlocks>(
ReleaseBlocks(m_start_lsn, m_end_lsn,
m_impl->m_flush_observer)));
}
/** Write the redo log record, add dirty pages to the flush list and release
the resources. */
void
mtr_t::Command::execute()
{
ut_ad(m_impl->m_log_mode != MTR_LOG_NONE);
if (const ulint len = prepare_write()) {
finish_write(len);
}
if (m_impl->m_made_dirty) {
log_flush_order_mutex_enter();
}
m_log.for_each_block(write_log);
/* 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_mutex_exit();
m_impl->m_mtr->m_commit_lsn = m_end_lsn;
release_blocks();
if (m_impl->m_made_dirty) {
log_flush_order_mutex_exit();
}
release_latches();
release_resources();
m_commit_lsn = log_close();
return start_lsn;
}
#ifdef UNIV_DEBUG
......@@ -1015,10 +882,9 @@ struct FlaggedCheck {
bool
mtr_t::memo_contains_flagged(const void* ptr, ulint flags) const
{
ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
ut_ad(is_committing() || is_active());
ut_ad(is_active());
return !m_impl.m_memo.for_each_block_in_reverse(
return !m_memo.for_each_block_in_reverse(
CIterate<FlaggedCheck>(FlaggedCheck(ptr, flags)));
}
......@@ -1034,7 +900,7 @@ mtr_t::memo_contains_page_flagged(
ulint flags) const
{
Iterate<FindPage> iteration(FindPage(ptr, flags));
return m_impl.m_memo.for_each_block_in_reverse(iteration)
return m_memo.for_each_block_in_reverse(iteration)
? NULL : iteration.functor.get_block();
}
......@@ -1057,7 +923,7 @@ void
mtr_t::print() const
{
ib::info() << "Mini-transaction handle: memo size "
<< m_impl.m_memo.size() << " bytes log size "
<< m_memo.size() << " bytes log size "
<< get_log()->size() << " bytes";
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment