MDEV-15104 - Optimise MVCC snapshot
With trx_sys_t::rw_trx_ids removal, MVCC snapshot overhead became slightly higher. That is instead of copying an array we now have to iterate LF_HASH. All this done under trx_sys.mutex protection. This patch moves MVCC snapshot out of trx_sys.mutex. Clean-ups: Removed MVCC: doesn't make too much sense to keep it in a separate class anymore. Refactored ReadView so that it now calls register()/deregister() routines (it was vice versa before). ReadView doesn't have friends anymore. :( Even less trx_sys.mutex references.
This commit is contained in:
parent
c0d5d7c0ef
commit
bc7a1dc1fb
@ -3499,7 +3499,7 @@ ha_innobase::init_table_handle_for_HANDLER(void)
|
|||||||
|
|
||||||
/* Assign a read view if the transaction does not have it yet */
|
/* Assign a read view if the transaction does not have it yet */
|
||||||
|
|
||||||
trx_sys.mvcc.view_open(m_prebuilt->trx);
|
m_prebuilt->trx->read_view.open(m_prebuilt->trx);
|
||||||
|
|
||||||
innobase_register_trx(ht, m_user_thd, m_prebuilt->trx);
|
innobase_register_trx(ht, m_user_thd, m_prebuilt->trx);
|
||||||
|
|
||||||
@ -4386,7 +4386,7 @@ innobase_start_trx_and_assign_read_view(
|
|||||||
thd_get_trx_isolation(thd));
|
thd_get_trx_isolation(thd));
|
||||||
|
|
||||||
if (trx->isolation_level == TRX_ISO_REPEATABLE_READ) {
|
if (trx->isolation_level == TRX_ISO_REPEATABLE_READ) {
|
||||||
trx_sys.mvcc.view_open(trx);
|
trx->read_view.open(trx);
|
||||||
} else {
|
} else {
|
||||||
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
|
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
|
||||||
HA_ERR_UNSUPPORTED,
|
HA_ERR_UNSUPPORTED,
|
||||||
@ -16063,7 +16063,7 @@ ha_innobase::external_lock(
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else if (trx->isolation_level <= TRX_ISO_READ_COMMITTED) {
|
} else if (trx->isolation_level <= TRX_ISO_READ_COMMITTED) {
|
||||||
trx_sys.mvcc.view_close(trx->read_view);
|
trx->read_view.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16728,7 +16728,7 @@ ha_innobase::store_lock(
|
|||||||
|
|
||||||
/* At low transaction isolation levels we let
|
/* At low transaction isolation levels we let
|
||||||
each consistent read set its own snapshot */
|
each consistent read set its own snapshot */
|
||||||
trx_sys.mvcc.view_close(trx->read_view);
|
trx->read_view.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5562,7 +5562,7 @@ error_handling_drop_uncached:
|
|||||||
if (ctx->online && ctx->num_to_add_index) {
|
if (ctx->online && ctx->num_to_add_index) {
|
||||||
/* Assign a consistent read view for
|
/* Assign a consistent read view for
|
||||||
row_merge_read_clustered_index(). */
|
row_merge_read_clustered_index(). */
|
||||||
trx_sys.mvcc.view_open(ctx->prebuilt->trx);
|
ctx->prebuilt->trx->read_view.open(ctx->prebuilt->trx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fts_index) {
|
if (fts_index) {
|
||||||
|
@ -35,7 +35,6 @@ Created 5/7/1996 Heikki Tuuri
|
|||||||
#include "row0vers.h"
|
#include "row0vers.h"
|
||||||
#include "que0que.h"
|
#include "que0que.h"
|
||||||
#include "btr0cur.h"
|
#include "btr0cur.h"
|
||||||
#include "read0read.h"
|
|
||||||
#include "log0recv.h"
|
#include "log0recv.h"
|
||||||
|
|
||||||
/*********************************************************************//**
|
/*********************************************************************//**
|
||||||
|
@ -1,75 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
|
|
||||||
Copyright (c) 1997, 2013, Oracle and/or its affiliates. All Rights Reserved.
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/**************************************************//**
|
|
||||||
@file include/read0read.h
|
|
||||||
Cursor read
|
|
||||||
|
|
||||||
Created 2/16/1997 Heikki Tuuri
|
|
||||||
*******************************************************/
|
|
||||||
|
|
||||||
#ifndef read0read_h
|
|
||||||
#define read0read_h
|
|
||||||
|
|
||||||
#include "univ.i"
|
|
||||||
|
|
||||||
#include "read0types.h"
|
|
||||||
|
|
||||||
/** The MVCC read view manager */
|
|
||||||
class MVCC
|
|
||||||
{
|
|
||||||
/** Active views. */
|
|
||||||
UT_LIST_BASE_NODE_T(ReadView) m_views;
|
|
||||||
|
|
||||||
|
|
||||||
/** Validates a read view list. */
|
|
||||||
bool validate() const;
|
|
||||||
public:
|
|
||||||
MVCC() { UT_LIST_INIT(m_views, &ReadView::m_view_list); }
|
|
||||||
~MVCC() { ut_ad(UT_LIST_GET_LEN(m_views) == 0); }
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Allocate and create a view.
|
|
||||||
@param trx transaction creating the view
|
|
||||||
*/
|
|
||||||
void view_open(trx_t *trx);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Close a view created by the above function.
|
|
||||||
@param view view allocated by view_open.
|
|
||||||
*/
|
|
||||||
void view_close(ReadView &view);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Clones the oldest view and stores it in view. No need to
|
|
||||||
call view_close(). The caller owns the view that is passed in.
|
|
||||||
This function is called by Purge to create it view.
|
|
||||||
|
|
||||||
@param view Preallocated view, owned by the caller
|
|
||||||
*/
|
|
||||||
void clone_oldest_view(ReadView *view);
|
|
||||||
|
|
||||||
|
|
||||||
/** @return the number of active views */
|
|
||||||
size_t size() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* read0read_h */
|
|
@ -32,16 +32,154 @@ Created 2/16/1997 Heikki Tuuri
|
|||||||
|
|
||||||
#include "trx0types.h"
|
#include "trx0types.h"
|
||||||
|
|
||||||
// Friend declaration
|
|
||||||
class MVCC;
|
|
||||||
|
|
||||||
/** Read view lists the trx ids of those transactions for which a consistent
|
/** View is not in MVCC and not visible to purge thread. */
|
||||||
read should not see the modifications to the database. */
|
#define READ_VIEW_STATE_CLOSED 0
|
||||||
|
|
||||||
|
/** View is in MVCC, but not visible to purge thread. */
|
||||||
|
#define READ_VIEW_STATE_REGISTERED 1
|
||||||
|
|
||||||
|
/** View is in MVCC, purge thread must wait for READ_VIEW_STATE_OPEN. */
|
||||||
|
#define READ_VIEW_STATE_SNAPSHOT 2
|
||||||
|
|
||||||
|
/** View is in MVCC and is visible to purge thread. */
|
||||||
|
#define READ_VIEW_STATE_OPEN 3
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Read view lists the trx ids of those transactions for which a consistent read
|
||||||
|
should not see the modifications to the database.
|
||||||
|
*/
|
||||||
|
class ReadView
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
View state.
|
||||||
|
|
||||||
|
It is not defined as enum as it has to be updated using atomic operations.
|
||||||
|
Possible values are READ_VIEW_STATE_CLOSED, READ_VIEW_STATE_REGISTERED,
|
||||||
|
READ_VIEW_STATE_SNAPSHOT and READ_VIEW_STATE_OPEN.
|
||||||
|
|
||||||
|
Possible state transfers...
|
||||||
|
|
||||||
|
Opening view for the first time:
|
||||||
|
READ_VIEW_STATE_CLOSED -> READ_VIEW_STATE_SNAPSHOT (non-atomic)
|
||||||
|
|
||||||
|
Complete first time open or reopen:
|
||||||
|
READ_VIEW_STATE_SNAPSHOT -> READ_VIEW_STATE_OPEN (atomic)
|
||||||
|
|
||||||
|
Close view but keep it in list:
|
||||||
|
READ_VIEW_STATE_OPEN -> READ_VIEW_STATE_REGISTERED (atomic)
|
||||||
|
|
||||||
|
Close view and remove it from list:
|
||||||
|
READ_VIEW_STATE_OPEN -> READ_VIEW_STATE_CLOSED (non-atomic)
|
||||||
|
|
||||||
|
Reusing view:
|
||||||
|
READ_VIEW_STATE_REGISTERED -> READ_VIEW_STATE_SNAPSHOT (atomic)
|
||||||
|
|
||||||
|
Removing closed view from list:
|
||||||
|
READ_VIEW_STATE_REGISTERED -> READ_VIEW_STATE_CLOSED (non-atomic)
|
||||||
|
*/
|
||||||
|
int32_t m_state;
|
||||||
|
|
||||||
|
|
||||||
class ReadView {
|
|
||||||
public:
|
public:
|
||||||
ReadView() : m_creator_trx_id(TRX_ID_MAX), m_ids(),
|
ReadView(): m_state(READ_VIEW_STATE_CLOSED) {}
|
||||||
m_registered(false) {}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Copy state from another view.
|
||||||
|
|
||||||
|
@param other view to copy from
|
||||||
|
*/
|
||||||
|
void copy(const ReadView &other)
|
||||||
|
{
|
||||||
|
ut_ad(&other != this);
|
||||||
|
m_ids= other.m_ids;
|
||||||
|
m_up_limit_id= other.m_up_limit_id;
|
||||||
|
m_low_limit_no= other.m_low_limit_no;
|
||||||
|
m_low_limit_id= other.m_low_limit_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Opens a read view where exactly the transactions serialized before this
|
||||||
|
point in time are seen in the view.
|
||||||
|
|
||||||
|
View becomes visible to purge thread via trx_sys.m_views.
|
||||||
|
|
||||||
|
@param[in,out] trx transaction
|
||||||
|
*/
|
||||||
|
void open(trx_t *trx);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Closes the view.
|
||||||
|
|
||||||
|
View becomes not visible to purge thread via trx_sys.m_views.
|
||||||
|
*/
|
||||||
|
void close();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Marks view unused.
|
||||||
|
|
||||||
|
View is still in trx_sys.m_views list, but is not visible to purge threads.
|
||||||
|
*/
|
||||||
|
void unuse()
|
||||||
|
{
|
||||||
|
ut_ad(m_state == READ_VIEW_STATE_CLOSED ||
|
||||||
|
m_state == READ_VIEW_STATE_REGISTERED ||
|
||||||
|
m_state == READ_VIEW_STATE_OPEN);
|
||||||
|
if (m_state == READ_VIEW_STATE_OPEN)
|
||||||
|
my_atomic_store32_explicit(&m_state, READ_VIEW_STATE_REGISTERED,
|
||||||
|
MY_MEMORY_ORDER_RELAXED);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** m_state getter for trx_sys::clone_oldest_view() trx_sys::size(). */
|
||||||
|
int32_t get_state() const
|
||||||
|
{
|
||||||
|
return my_atomic_load32_explicit(const_cast<int32*>(&m_state),
|
||||||
|
MY_MEMORY_ORDER_ACQUIRE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns true if view is open.
|
||||||
|
|
||||||
|
Only used by view owner thread, thus we can omit atomic operations.
|
||||||
|
*/
|
||||||
|
bool is_open() const
|
||||||
|
{
|
||||||
|
ut_ad(m_state == READ_VIEW_STATE_OPEN ||
|
||||||
|
m_state == READ_VIEW_STATE_CLOSED ||
|
||||||
|
m_state == READ_VIEW_STATE_REGISTERED);
|
||||||
|
return m_state == READ_VIEW_STATE_OPEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates a snapshot where exactly the transactions serialized before this
|
||||||
|
point in time are seen in the view.
|
||||||
|
|
||||||
|
@param[in,out] trx transaction
|
||||||
|
*/
|
||||||
|
void snapshot(trx_t *trx);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Sets the creator transaction id.
|
||||||
|
|
||||||
|
This should be set only for views created by RW transactions.
|
||||||
|
*/
|
||||||
|
void set_creator_trx_id(trx_id_t id)
|
||||||
|
{
|
||||||
|
ut_ad(id > 0);
|
||||||
|
ut_ad(m_creator_trx_id == 0);
|
||||||
|
m_creator_trx_id= id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Check whether transaction id is valid.
|
/** Check whether transaction id is valid.
|
||||||
@param[in] id transaction id to check
|
@param[in] id transaction id to check
|
||||||
@param[in] name table name */
|
@param[in] name table name */
|
||||||
@ -85,25 +223,6 @@ public:
|
|||||||
return(id < m_up_limit_id);
|
return(id < m_up_limit_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
Mark the view as closed */
|
|
||||||
void close()
|
|
||||||
{
|
|
||||||
set_creator_trx_id(TRX_ID_MAX);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_open() const
|
|
||||||
{
|
|
||||||
return static_cast<trx_id_t>(my_atomic_load64_explicit(
|
|
||||||
const_cast<int64*>(
|
|
||||||
reinterpret_cast<const int64*>(
|
|
||||||
&m_creator_trx_id)),
|
|
||||||
MY_MEMORY_ORDER_RELAXED)) != TRX_ID_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_registered() const { return(m_registered); }
|
|
||||||
void set_registered(bool registered) { m_registered= registered; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Write the limits to the file.
|
Write the limits to the file.
|
||||||
@param file file to write to */
|
@param file file to write to */
|
||||||
@ -129,54 +248,8 @@ public:
|
|||||||
return(m_low_limit_id);
|
return(m_low_limit_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
@return true if there are no transaction ids in the snapshot */
|
|
||||||
bool empty() const
|
|
||||||
{
|
|
||||||
return(m_ids.empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Set the creator transaction id, existing id must be 0.
|
|
||||||
|
|
||||||
Note: This shouldbe set only for views created by RW
|
|
||||||
transactions. */
|
|
||||||
void set_creator_trx_id(trx_id_t id)
|
|
||||||
{
|
|
||||||
my_atomic_store64_explicit(
|
|
||||||
reinterpret_cast<int64*>(&m_creator_trx_id),
|
|
||||||
id, MY_MEMORY_ORDER_RELAXED);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef UNIV_DEBUG
|
|
||||||
/**
|
|
||||||
@param rhs view to compare with
|
|
||||||
@return truen if this view is less than or equal rhs */
|
|
||||||
bool le(const ReadView* rhs) const
|
|
||||||
{
|
|
||||||
return(m_low_limit_no <= rhs->m_low_limit_no);
|
|
||||||
}
|
|
||||||
|
|
||||||
trx_id_t up_limit_id() const
|
|
||||||
{
|
|
||||||
return(m_up_limit_id);
|
|
||||||
}
|
|
||||||
#endif /* UNIV_DEBUG */
|
|
||||||
private:
|
private:
|
||||||
/**
|
|
||||||
Opens a read view where exactly the transactions serialized before this
|
|
||||||
point in time are seen in the view.
|
|
||||||
|
|
||||||
@param[in,out] trx transaction */
|
|
||||||
void open(trx_t *trx);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Copy state from another view.
|
|
||||||
@param other view to copy from */
|
|
||||||
inline void copy(const ReadView& other);
|
|
||||||
|
|
||||||
friend class MVCC;
|
|
||||||
|
|
||||||
/** The read should not see any transaction with trx id >= this
|
/** The read should not see any transaction with trx id >= this
|
||||||
value. In other words, this is the "high water mark". */
|
value. In other words, this is the "high water mark". */
|
||||||
trx_id_t m_low_limit_id;
|
trx_id_t m_low_limit_id;
|
||||||
@ -199,11 +272,8 @@ private:
|
|||||||
they can be removed in purge if not needed by other views */
|
they can be removed in purge if not needed by other views */
|
||||||
trx_id_t m_low_limit_no;
|
trx_id_t m_low_limit_no;
|
||||||
|
|
||||||
/** true if transaction is in MVCC::m_views. Only thread that owns
|
|
||||||
this view may access it. */
|
|
||||||
bool m_registered;
|
|
||||||
|
|
||||||
byte pad1[CACHE_LINE_SIZE];
|
byte pad1[CACHE_LINE_SIZE];
|
||||||
|
public:
|
||||||
UT_LIST_NODE_T(ReadView) m_view_list;
|
UT_LIST_NODE_T(ReadView) m_view_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -810,17 +810,17 @@ private:
|
|||||||
/** Solves race condition between register_rw() and snapshot_ids(). */
|
/** Solves race condition between register_rw() and snapshot_ids(). */
|
||||||
MY_ALIGNED(CACHE_LINE_SIZE) trx_id_t m_rw_trx_hash_version;
|
MY_ALIGNED(CACHE_LINE_SIZE) trx_id_t m_rw_trx_hash_version;
|
||||||
|
|
||||||
|
|
||||||
|
/** Active views. */
|
||||||
|
MY_ALIGNED(CACHE_LINE_SIZE) UT_LIST_BASE_NODE_T(ReadView) m_views;
|
||||||
|
|
||||||
bool m_initialised;
|
bool m_initialised;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MY_ALIGNED(CACHE_LINE_SIZE)
|
MY_ALIGNED(CACHE_LINE_SIZE) mutable
|
||||||
TrxSysMutex mutex; /*!< mutex protecting most fields in
|
TrxSysMutex mutex; /*!< mutex protecting most fields in
|
||||||
this structure except when noted
|
this structure except when noted
|
||||||
otherwise */
|
otherwise */
|
||||||
|
|
||||||
MY_ALIGNED(CACHE_LINE_SIZE)
|
|
||||||
MVCC mvcc; /*!< Multi version concurrency control
|
|
||||||
manager */
|
|
||||||
MY_ALIGNED(CACHE_LINE_SIZE)
|
MY_ALIGNED(CACHE_LINE_SIZE)
|
||||||
trx_ut_list_t mysql_trx_list; /*!< List of transactions created
|
trx_ut_list_t mysql_trx_list; /*!< List of transactions created
|
||||||
for MySQL. All user transactions are
|
for MySQL. All user transactions are
|
||||||
@ -1032,6 +1032,59 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Registers view in MVCC.
|
||||||
|
|
||||||
|
@param view view owned by the caller
|
||||||
|
*/
|
||||||
|
void register_view(ReadView *view)
|
||||||
|
{
|
||||||
|
mutex_enter(&mutex);
|
||||||
|
UT_LIST_ADD_FIRST(m_views, view);
|
||||||
|
mutex_exit(&mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Deregisters view in MVCC.
|
||||||
|
|
||||||
|
@param view view owned by the caller
|
||||||
|
*/
|
||||||
|
void deregister_view(ReadView *view)
|
||||||
|
{
|
||||||
|
mutex_enter(&mutex);
|
||||||
|
UT_LIST_REMOVE(m_views, view);
|
||||||
|
mutex_exit(&mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Clones the oldest view and stores it in view.
|
||||||
|
|
||||||
|
No need to call ReadView::close(). The caller owns the view that is passed
|
||||||
|
in. This function is called by purge thread to determine whether it should
|
||||||
|
purge the delete marked record or not.
|
||||||
|
*/
|
||||||
|
void clone_oldest_view();
|
||||||
|
|
||||||
|
|
||||||
|
/** @return the number of active views */
|
||||||
|
size_t view_count() const
|
||||||
|
{
|
||||||
|
size_t count= 0;
|
||||||
|
|
||||||
|
mutex_enter(&mutex);
|
||||||
|
for (const ReadView* view= UT_LIST_GET_FIRST(m_views); view;
|
||||||
|
view= UT_LIST_GET_NEXT(m_view_list, view))
|
||||||
|
{
|
||||||
|
if (view->get_state() == READ_VIEW_STATE_OPEN)
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
mutex_exit(&mutex);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static my_bool get_min_trx_id_callback(rw_trx_hash_element_t *element,
|
static my_bool get_min_trx_id_callback(rw_trx_hash_element_t *element,
|
||||||
trx_id_t *id)
|
trx_id_t *id)
|
||||||
|
@ -24,8 +24,6 @@ The transaction
|
|||||||
Created 3/26/1996 Heikki Tuuri
|
Created 3/26/1996 Heikki Tuuri
|
||||||
*******************************************************/
|
*******************************************************/
|
||||||
|
|
||||||
#include "read0read.h"
|
|
||||||
|
|
||||||
/**********************************************************************//**
|
/**********************************************************************//**
|
||||||
Determines if a transaction is in the given state.
|
Determines if a transaction is in the given state.
|
||||||
The caller must hold trx_sys.mutex, or it must be the thread
|
The caller must hold trx_sys.mutex, or it must be the thread
|
||||||
|
@ -24,10 +24,11 @@ Cursor read
|
|||||||
Created 2/16/1997 Heikki Tuuri
|
Created 2/16/1997 Heikki Tuuri
|
||||||
*******************************************************/
|
*******************************************************/
|
||||||
|
|
||||||
#include "read0read.h"
|
#include "read0types.h"
|
||||||
|
|
||||||
#include "srv0srv.h"
|
#include "srv0srv.h"
|
||||||
#include "trx0sys.h"
|
#include "trx0sys.h"
|
||||||
|
#include "trx0purge.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
@ -172,52 +173,16 @@ RW transaction can commit or rollback (or free views). AC-NL-RO transactions
|
|||||||
will mark their views as closed but not actually free their views.
|
will mark their views as closed but not actually free their views.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef UNIV_DEBUG
|
|
||||||
/** Functor to validate the view list. */
|
|
||||||
struct ViewCheck {
|
|
||||||
|
|
||||||
ViewCheck() : m_prev_view() { }
|
|
||||||
|
|
||||||
void operator()(const ReadView* view)
|
|
||||||
{
|
|
||||||
ut_ad(view->is_registered());
|
|
||||||
ut_a(m_prev_view == NULL
|
|
||||||
|| !view->is_open()
|
|
||||||
|| view->le(m_prev_view));
|
|
||||||
|
|
||||||
m_prev_view = view;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ReadView* m_prev_view;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Validates a read view list. */
|
Creates a snapshot where exactly the transactions serialized before this
|
||||||
|
|
||||||
bool
|
|
||||||
MVCC::validate() const
|
|
||||||
{
|
|
||||||
ViewCheck check;
|
|
||||||
|
|
||||||
ut_ad(mutex_own(&trx_sys.mutex));
|
|
||||||
|
|
||||||
ut_list_map(m_views, check);
|
|
||||||
|
|
||||||
return(true);
|
|
||||||
}
|
|
||||||
#endif /* UNIV_DEBUG */
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Opens a read view where exactly the transactions serialized before this
|
|
||||||
point in time are seen in the view.
|
point in time are seen in the view.
|
||||||
|
|
||||||
@param[in,out] trx transaction
|
@param[in,out] trx transaction
|
||||||
*/
|
*/
|
||||||
|
void ReadView::snapshot(trx_t *trx)
|
||||||
void ReadView::open(trx_t *trx)
|
|
||||||
{
|
{
|
||||||
ut_ad(mutex_own(&trx_sys.mutex));
|
ut_ad(!mutex_own(&trx_sys.mutex));
|
||||||
trx_sys.snapshot_ids(trx, &m_ids, &m_low_limit_id, &m_low_limit_no);
|
trx_sys.snapshot_ids(trx, &m_ids, &m_low_limit_id, &m_low_limit_no);
|
||||||
m_up_limit_id= m_ids.empty() ? m_low_limit_id : m_ids.front();
|
m_up_limit_id= m_ids.empty() ? m_low_limit_id : m_ids.front();
|
||||||
ut_ad(m_up_limit_id <= m_low_limit_id);
|
ut_ad(m_up_limit_id <= m_low_limit_id);
|
||||||
@ -225,42 +190,33 @@ void ReadView::open(trx_t *trx)
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Create a view.
|
Opens a read view where exactly the transactions serialized before this
|
||||||
|
point in time are seen in the view.
|
||||||
|
|
||||||
Assigns a read view for a consistent read query. All the consistent reads
|
View becomes visible to purge thread via trx_sys.m_views.
|
||||||
within the same transaction will get the same read view, which is created
|
|
||||||
when this function is first called for a new started transaction.
|
|
||||||
|
|
||||||
@param trx transaction instance of caller
|
@param[in,out] trx transaction
|
||||||
*/
|
*/
|
||||||
|
void ReadView::open(trx_t *trx)
|
||||||
void MVCC::view_open(trx_t* trx)
|
|
||||||
{
|
{
|
||||||
if (srv_read_only_mode)
|
ut_ad(this == &trx->read_view);
|
||||||
|
switch (m_state)
|
||||||
{
|
{
|
||||||
ut_ad(!trx->read_view.is_open());
|
case READ_VIEW_STATE_OPEN:
|
||||||
|
ut_ad(!srv_read_only_mode);
|
||||||
return;
|
return;
|
||||||
}
|
case READ_VIEW_STATE_REGISTERED:
|
||||||
else if (trx->read_view.is_open())
|
ut_ad(!srv_read_only_mode);
|
||||||
return;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Reuse closed view if there were no read-write transactions since (and at) it's
|
|
||||||
creation time.
|
|
||||||
*/
|
|
||||||
if (trx->read_view.is_registered() &&
|
|
||||||
trx_is_autocommit_non_locking(trx) &&
|
|
||||||
trx->read_view.empty() &&
|
|
||||||
trx->read_view.m_low_limit_id == trx_sys.get_max_trx_id())
|
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
|
Reuse closed view if there were no read-write transactions since (and at)
|
||||||
|
its creation time.
|
||||||
|
|
||||||
Original comment states: there is an inherent race here between purge
|
Original comment states: there is an inherent race here between purge
|
||||||
and this thread.
|
and this thread.
|
||||||
|
|
||||||
To avoid this race we should've checked trx_sys.get_max_trx_id() and
|
To avoid this race we should've checked trx_sys.get_max_trx_id() and
|
||||||
do trx->read_view.set_creator_trx_id(trx->id) atomically under
|
set state to READ_VIEW_STATE_OPEN atomically under trx_sys.mutex
|
||||||
trx_sys.mutex protection. But we're cutting edges to achieve great
|
protection. But we're cutting edges to achieve great scalability.
|
||||||
scalability.
|
|
||||||
|
|
||||||
There're at least two types of concurrent threads interested in this
|
There're at least two types of concurrent threads interested in this
|
||||||
value: purge coordinator thread (see MVCC::clone_oldest_view()) and
|
value: purge coordinator thread (see MVCC::clone_oldest_view()) and
|
||||||
@ -280,108 +236,108 @@ void MVCC::view_open(trx_t* trx)
|
|||||||
Second, scary things start when there's a read-write transaction starting
|
Second, scary things start when there's a read-write transaction starting
|
||||||
concurrently.
|
concurrently.
|
||||||
|
|
||||||
Speculative execution may reorder set_creator_trx_id() before
|
Speculative execution may reorder state change before get_max_trx_id().
|
||||||
get_max_trx_id(). In this case purge thread has short gap to clone
|
In this case purge thread has short gap to clone outdated view. Which is
|
||||||
outdated view. Which is probably not that bad: it just won't be able to
|
probably not that bad: it just won't be able to purge things that it was
|
||||||
purge things that it was actually allowed to purge for a short while.
|
actually allowed to purge for a short while.
|
||||||
|
|
||||||
This thread may as well get suspended after trx_sys.get_max_trx_id() and
|
This thread may as well get suspended after trx_sys.get_max_trx_id() and
|
||||||
before trx->read_view.set_creator_trx_id(trx->id). New read-write
|
before state is set to READ_VIEW_STATE_OPEN. New read-write transaction
|
||||||
transaction may get started, committed and purged meanwhile. It is
|
may get started, committed and purged meanwhile. It is acceptable as
|
||||||
acceptable as well, since this view doesn't see it.
|
well, since this view doesn't see it.
|
||||||
*/
|
*/
|
||||||
trx->read_view.set_creator_trx_id(trx->id);
|
if (trx_is_autocommit_non_locking(trx) && m_ids.empty() &&
|
||||||
return;
|
m_low_limit_id == trx_sys.get_max_trx_id())
|
||||||
}
|
goto reopen;
|
||||||
|
|
||||||
mutex_enter(&trx_sys.mutex);
|
/*
|
||||||
trx->read_view.open(trx);
|
Can't reuse view, take new snapshot.
|
||||||
if (trx->read_view.is_registered())
|
|
||||||
UT_LIST_REMOVE(m_views, &trx->read_view);
|
|
||||||
else
|
|
||||||
trx->read_view.set_registered(true);
|
|
||||||
trx->read_view.set_creator_trx_id(trx->id);
|
|
||||||
UT_LIST_ADD_FIRST(m_views, &trx->read_view);
|
|
||||||
ut_ad(validate());
|
|
||||||
mutex_exit(&trx_sys.mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Alas this empty critical section is simplest way to make sure concurrent
|
||||||
|
purge thread completed snapshot copy. Of course purge thread may come
|
||||||
|
again and try to copy once again after we release this mutex, but in
|
||||||
|
this case it is guaranteed to see READ_VIEW_STATE_REGISTERED and thus
|
||||||
|
it'll skip this view.
|
||||||
|
|
||||||
void MVCC::view_close(ReadView &view)
|
This critical section can be replaced with new state, which purge thread
|
||||||
{
|
would set to inform us to wait until it completes snapshot. However it'd
|
||||||
view.close();
|
complicate m_state even further.
|
||||||
if (view.is_registered())
|
*/
|
||||||
{
|
|
||||||
mutex_enter(&trx_sys.mutex);
|
mutex_enter(&trx_sys.mutex);
|
||||||
view.set_registered(false);
|
|
||||||
UT_LIST_REMOVE(m_views, &view);
|
|
||||||
ut_ad(validate());
|
|
||||||
mutex_exit(&trx_sys.mutex);
|
mutex_exit(&trx_sys.mutex);
|
||||||
|
my_atomic_store32_explicit(&m_state, READ_VIEW_STATE_SNAPSHOT,
|
||||||
|
MY_MEMORY_ORDER_RELAXED);
|
||||||
|
break;
|
||||||
|
case READ_VIEW_STATE_CLOSED:
|
||||||
|
if (srv_read_only_mode)
|
||||||
|
return;
|
||||||
|
m_state= READ_VIEW_STATE_SNAPSHOT;
|
||||||
|
trx_sys.register_view(this);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ut_ad(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshot(trx);
|
||||||
|
reopen:
|
||||||
|
m_creator_trx_id= trx->id;
|
||||||
|
my_atomic_store32_explicit(&m_state, READ_VIEW_STATE_OPEN,
|
||||||
|
MY_MEMORY_ORDER_RELEASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Closes the view.
|
||||||
|
|
||||||
|
The view will become invisible to purge (deregistered from trx_sys).
|
||||||
|
*/
|
||||||
|
void ReadView::close()
|
||||||
|
{
|
||||||
|
ut_ad(m_state == READ_VIEW_STATE_OPEN ||
|
||||||
|
m_state == READ_VIEW_STATE_REGISTERED ||
|
||||||
|
m_state == READ_VIEW_STATE_CLOSED);
|
||||||
|
if (m_state != READ_VIEW_STATE_CLOSED)
|
||||||
|
{
|
||||||
|
trx_sys.deregister_view(this);
|
||||||
|
m_state= READ_VIEW_STATE_CLOSED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Copy state from another view.
|
Clones the oldest view and stores it in view.
|
||||||
@param other view to copy from */
|
|
||||||
|
|
||||||
void
|
No need to call ReadView::close(). The caller owns the view that is passed
|
||||||
ReadView::copy(const ReadView& other)
|
in. This function is called by purge thread to determine whether it should
|
||||||
|
purge the delete marked record or not.
|
||||||
|
|
||||||
|
Since foreign views are accessed under the mutex protection, the only
|
||||||
|
possible state transfers are
|
||||||
|
READ_VIEW_STATE_SNAPSHOT -> READ_VIEW_STATE_OPEN
|
||||||
|
READ_VIEW_STATE_OPEN -> READ_VIEW_STATE_REGISTERED
|
||||||
|
All other state transfers are eliminated by the mutex.
|
||||||
|
*/
|
||||||
|
void trx_sys_t::clone_oldest_view()
|
||||||
{
|
{
|
||||||
ut_ad(&other != this);
|
const ReadView *oldest_view= &purge_sys->view;
|
||||||
m_ids= other.m_ids;
|
|
||||||
m_up_limit_id = other.m_up_limit_id;
|
purge_sys->view.snapshot(0);
|
||||||
m_low_limit_no = other.m_low_limit_no;
|
|
||||||
m_low_limit_id = other.m_low_limit_id;
|
mutex_enter(&mutex);
|
||||||
}
|
/* Find oldest view. */
|
||||||
|
for (const ReadView *v= UT_LIST_GET_FIRST(m_views); v;
|
||||||
/** Clones the oldest view and stores it in view. No need to
|
v= UT_LIST_GET_NEXT(m_view_list, v))
|
||||||
call view_close(). The caller owns the view that is passed in.
|
{
|
||||||
This function is called by Purge to determine whether it should
|
int32_t state;
|
||||||
purge the delete marked record or not.
|
|
||||||
@param view Preallocated view, owned by the caller */
|
while ((state= v->get_state()) == READ_VIEW_STATE_SNAPSHOT)
|
||||||
|
ut_delay(1);
|
||||||
void
|
|
||||||
MVCC::clone_oldest_view(ReadView* view)
|
if (state == READ_VIEW_STATE_OPEN &&
|
||||||
{
|
v->low_limit_no() < oldest_view->low_limit_no())
|
||||||
mutex_enter(&trx_sys.mutex);
|
oldest_view= v;
|
||||||
/* Find oldest view. */
|
}
|
||||||
for (const ReadView *oldest_view = UT_LIST_GET_LAST(m_views);
|
if (oldest_view != &purge_sys->view)
|
||||||
oldest_view != NULL;
|
purge_sys->view.copy(*oldest_view);
|
||||||
oldest_view = UT_LIST_GET_PREV(m_view_list, oldest_view))
|
mutex_exit(&mutex);
|
||||||
{
|
|
||||||
if (oldest_view->is_open())
|
|
||||||
{
|
|
||||||
view->copy(*oldest_view);
|
|
||||||
mutex_exit(&trx_sys.mutex);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* No views in the list: snapshot current state. */
|
|
||||||
view->open(0);
|
|
||||||
mutex_exit(&trx_sys.mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
@return the number of active views */
|
|
||||||
|
|
||||||
size_t
|
|
||||||
MVCC::size() const
|
|
||||||
{
|
|
||||||
mutex_enter(&trx_sys.mutex);
|
|
||||||
|
|
||||||
size_t size = 0;
|
|
||||||
|
|
||||||
for (const ReadView* view = UT_LIST_GET_FIRST(m_views);
|
|
||||||
view != NULL;
|
|
||||||
view = UT_LIST_GET_NEXT(m_view_list, view)) {
|
|
||||||
|
|
||||||
if (view->is_open()) {
|
|
||||||
++size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_exit(&trx_sys.mutex);
|
|
||||||
|
|
||||||
return(size);
|
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,6 @@ Created 4/20/1996 Heikki Tuuri
|
|||||||
#include "row0ext.h"
|
#include "row0ext.h"
|
||||||
#include "row0upd.h"
|
#include "row0upd.h"
|
||||||
#include "rem0cmp.h"
|
#include "rem0cmp.h"
|
||||||
#include "read0read.h"
|
|
||||||
#include "ut0mem.h"
|
#include "ut0mem.h"
|
||||||
#include "gis0geo.h"
|
#include "gis0geo.h"
|
||||||
#include "row0mysql.h"
|
#include "row0mysql.h"
|
||||||
|
@ -51,7 +51,6 @@ Created 12/19/1997 Heikki Tuuri
|
|||||||
#include "pars0sym.h"
|
#include "pars0sym.h"
|
||||||
#include "pars0pars.h"
|
#include "pars0pars.h"
|
||||||
#include "row0mysql.h"
|
#include "row0mysql.h"
|
||||||
#include "read0read.h"
|
|
||||||
#include "buf0lru.h"
|
#include "buf0lru.h"
|
||||||
#include "srv0srv.h"
|
#include "srv0srv.h"
|
||||||
#include "ha_prototypes.h"
|
#include "ha_prototypes.h"
|
||||||
@ -2270,7 +2269,7 @@ row_sel_step(
|
|||||||
if (node->consistent_read) {
|
if (node->consistent_read) {
|
||||||
trx_t *trx = thr_get_trx(thr);
|
trx_t *trx = thr_get_trx(thr);
|
||||||
/* Assign a read view for the query */
|
/* Assign a read view for the query */
|
||||||
trx_sys.mvcc.view_open(trx);
|
trx->read_view.open(trx);
|
||||||
node->read_view = trx->read_view.is_open() ?
|
node->read_view = trx->read_view.is_open() ?
|
||||||
&trx->read_view : NULL;
|
&trx->read_view : NULL;
|
||||||
} else {
|
} else {
|
||||||
@ -4426,7 +4425,7 @@ row_search_mvcc(
|
|||||||
/* Assign a read view for the query */
|
/* Assign a read view for the query */
|
||||||
trx_start_if_not_started(trx, false);
|
trx_start_if_not_started(trx, false);
|
||||||
|
|
||||||
trx_sys.mvcc.view_open(trx);
|
trx->read_view.open(trx);
|
||||||
|
|
||||||
prebuilt->sql_stat_start = FALSE;
|
prebuilt->sql_stat_start = FALSE;
|
||||||
} else {
|
} else {
|
||||||
@ -5878,8 +5877,7 @@ row_search_check_if_query_cache_permitted(
|
|||||||
transaction if it does not yet have one */
|
transaction if it does not yet have one */
|
||||||
|
|
||||||
if (trx->isolation_level >= TRX_ISO_REPEATABLE_READ) {
|
if (trx->isolation_level >= TRX_ISO_REPEATABLE_READ) {
|
||||||
|
trx->read_view.open(trx);
|
||||||
trx_sys.mvcc.view_open(trx);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +41,6 @@ Created 2/6/1997 Heikki Tuuri
|
|||||||
#include "row0row.h"
|
#include "row0row.h"
|
||||||
#include "row0upd.h"
|
#include "row0upd.h"
|
||||||
#include "rem0cmp.h"
|
#include "rem0cmp.h"
|
||||||
#include "read0read.h"
|
|
||||||
#include "lock0lock.h"
|
#include "lock0lock.h"
|
||||||
#include "row0mysql.h"
|
#include "row0mysql.h"
|
||||||
|
|
||||||
|
@ -1365,9 +1365,8 @@ srv_printf_innodb_monitor(
|
|||||||
srv_conc_get_active_threads(),
|
srv_conc_get_active_threads(),
|
||||||
srv_conc_get_waiting_threads());
|
srv_conc_get_waiting_threads());
|
||||||
|
|
||||||
/* This is a dirty read, without holding trx_sys.mutex. */
|
|
||||||
fprintf(file, ULINTPF " read views open inside InnoDB\n",
|
fprintf(file, ULINTPF " read views open inside InnoDB\n",
|
||||||
trx_sys.mvcc.size());
|
trx_sys.view_count());
|
||||||
|
|
||||||
n_reserved = fil_space_get_n_reserved_extents(0);
|
n_reserved = fil_space_get_n_reserved_extents(0);
|
||||||
if (n_reserved > 0) {
|
if (n_reserved > 0) {
|
||||||
|
@ -33,7 +33,6 @@ Created 3/26/1996 Heikki Tuuri
|
|||||||
#include "mtr0log.h"
|
#include "mtr0log.h"
|
||||||
#include "os0thread.h"
|
#include "os0thread.h"
|
||||||
#include "que0que.h"
|
#include "que0que.h"
|
||||||
#include "read0read.h"
|
|
||||||
#include "row0purge.h"
|
#include "row0purge.h"
|
||||||
#include "row0upd.h"
|
#include "row0upd.h"
|
||||||
#include "srv0mon.h"
|
#include "srv0mon.h"
|
||||||
@ -1615,7 +1614,7 @@ trx_purge(
|
|||||||
ut_a(purge_sys->n_submitted == purge_sys->n_completed);
|
ut_a(purge_sys->n_submitted == purge_sys->n_completed);
|
||||||
|
|
||||||
rw_lock_x_lock(&purge_sys->latch);
|
rw_lock_x_lock(&purge_sys->latch);
|
||||||
trx_sys.mvcc.clone_oldest_view(&purge_sys->view);
|
trx_sys.clone_oldest_view();
|
||||||
rw_lock_x_unlock(&purge_sys->latch);
|
rw_lock_x_unlock(&purge_sys->latch);
|
||||||
|
|
||||||
#ifdef UNIV_DEBUG
|
#ifdef UNIV_DEBUG
|
||||||
|
@ -31,7 +31,6 @@ Created 3/26/1996 Heikki Tuuri
|
|||||||
#include "mtr0log.h"
|
#include "mtr0log.h"
|
||||||
#include "dict0dict.h"
|
#include "dict0dict.h"
|
||||||
#include "ut0mem.h"
|
#include "ut0mem.h"
|
||||||
#include "read0read.h"
|
|
||||||
#include "row0ext.h"
|
#include "row0ext.h"
|
||||||
#include "row0upd.h"
|
#include "row0upd.h"
|
||||||
#include "que0que.h"
|
#include "que0que.h"
|
||||||
|
@ -37,7 +37,6 @@ Created 3/26/1996 Heikki Tuuri
|
|||||||
#include "mach0data.h"
|
#include "mach0data.h"
|
||||||
#include "pars0pars.h"
|
#include "pars0pars.h"
|
||||||
#include "que0que.h"
|
#include "que0que.h"
|
||||||
#include "read0read.h"
|
|
||||||
#include "row0mysql.h"
|
#include "row0mysql.h"
|
||||||
#include "row0undo.h"
|
#include "row0undo.h"
|
||||||
#include "srv0mon.h"
|
#include "srv0mon.h"
|
||||||
|
@ -42,7 +42,6 @@ Created 3/26/1996 Heikki Tuuri
|
|||||||
#include "log0log.h"
|
#include "log0log.h"
|
||||||
#include "log0recv.h"
|
#include "log0recv.h"
|
||||||
#include "os0file.h"
|
#include "os0file.h"
|
||||||
#include "read0read.h"
|
|
||||||
#include "fsp0sysspace.h"
|
#include "fsp0sysspace.h"
|
||||||
|
|
||||||
#include <mysql/service_wsrep.h>
|
#include <mysql/service_wsrep.h>
|
||||||
@ -402,6 +401,8 @@ trx_sys_t::create()
|
|||||||
m_initialised = true;
|
m_initialised = true;
|
||||||
mutex_create(LATCH_ID_TRX_SYS, &mutex);
|
mutex_create(LATCH_ID_TRX_SYS, &mutex);
|
||||||
UT_LIST_INIT(mysql_trx_list, &trx_t::mysql_trx_list);
|
UT_LIST_INIT(mysql_trx_list, &trx_t::mysql_trx_list);
|
||||||
|
UT_LIST_INIT(m_views, &ReadView::m_view_list);
|
||||||
|
|
||||||
rw_trx_hash.init();
|
rw_trx_hash.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -507,7 +508,7 @@ trx_sys_t::close()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ulint size = mvcc.size()) {
|
if (size_t size = view_count()) {
|
||||||
ib::error() << "All read views were not closed before"
|
ib::error() << "All read views were not closed before"
|
||||||
" shutdown: " << size << " read views open";
|
" shutdown: " << size << " read views open";
|
||||||
}
|
}
|
||||||
@ -532,6 +533,7 @@ trx_sys_t::close()
|
|||||||
}
|
}
|
||||||
|
|
||||||
ut_a(UT_LIST_GET_LEN(mysql_trx_list) == 0);
|
ut_a(UT_LIST_GET_LEN(mysql_trx_list) == 0);
|
||||||
|
ut_ad(UT_LIST_GET_LEN(m_views) == 0);
|
||||||
|
|
||||||
/* We used placement new to create this mutex. Call the destructor. */
|
/* We used placement new to create this mutex. Call the destructor. */
|
||||||
mutex_free(&mutex);
|
mutex_free(&mutex);
|
||||||
@ -564,7 +566,7 @@ ulint trx_sys_t::any_active_transactions()
|
|||||||
reinterpret_cast<my_hash_walk_action>
|
reinterpret_cast<my_hash_walk_action>
|
||||||
(active_count_callback), &total_trx);
|
(active_count_callback), &total_trx);
|
||||||
|
|
||||||
mutex_enter(&trx_sys.mutex);
|
mutex_enter(&mutex);
|
||||||
for (trx_t* trx = UT_LIST_GET_FIRST(trx_sys.mysql_trx_list);
|
for (trx_t* trx = UT_LIST_GET_FIRST(trx_sys.mysql_trx_list);
|
||||||
trx != NULL;
|
trx != NULL;
|
||||||
trx = UT_LIST_GET_NEXT(mysql_trx_list, trx)) {
|
trx = UT_LIST_GET_NEXT(mysql_trx_list, trx)) {
|
||||||
@ -572,7 +574,7 @@ ulint trx_sys_t::any_active_transactions()
|
|||||||
total_trx++;
|
total_trx++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex_exit(&trx_sys.mutex);
|
mutex_exit(&mutex);
|
||||||
|
|
||||||
return(total_trx);
|
return(total_trx);
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,6 @@ Created 3/26/1996 Heikki Tuuri
|
|||||||
#include "log0log.h"
|
#include "log0log.h"
|
||||||
#include "os0proc.h"
|
#include "os0proc.h"
|
||||||
#include "que0que.h"
|
#include "que0que.h"
|
||||||
#include "read0read.h"
|
|
||||||
#include "srv0mon.h"
|
#include "srv0mon.h"
|
||||||
#include "srv0srv.h"
|
#include "srv0srv.h"
|
||||||
#include "fsp0sysspace.h"
|
#include "fsp0sysspace.h"
|
||||||
@ -511,7 +510,7 @@ trx_free(trx_t*& trx)
|
|||||||
trx->mod_tables.clear();
|
trx->mod_tables.clear();
|
||||||
|
|
||||||
ut_ad(!trx->read_view.is_open());
|
ut_ad(!trx->read_view.is_open());
|
||||||
trx_sys.mvcc.view_close(trx->read_view);
|
trx->read_view.close();
|
||||||
|
|
||||||
/* trx locking state should have been reset before returning trx
|
/* trx locking state should have been reset before returning trx
|
||||||
to pool */
|
to pool */
|
||||||
@ -673,7 +672,7 @@ trx_disconnect_from_mysql(
|
|||||||
trx_t* trx,
|
trx_t* trx,
|
||||||
bool prepared)
|
bool prepared)
|
||||||
{
|
{
|
||||||
trx_sys.mvcc.view_close(trx->read_view);
|
trx->read_view.close();
|
||||||
|
|
||||||
mutex_enter(&trx_sys.mutex);
|
mutex_enter(&trx_sys.mutex);
|
||||||
|
|
||||||
@ -972,7 +971,7 @@ trx_lists_init_at_db_start()
|
|||||||
|
|
||||||
ib::info() << "Trx id counter is " << trx_sys.get_max_trx_id();
|
ib::info() << "Trx id counter is " << trx_sys.get_max_trx_id();
|
||||||
}
|
}
|
||||||
trx_sys.mvcc.clone_oldest_view(&purge_sys->view);
|
trx_sys.clone_oldest_view();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Assign a persistent rollback segment in a round-robin fashion,
|
/** Assign a persistent rollback segment in a round-robin fashion,
|
||||||
@ -1512,7 +1511,7 @@ trx_commit_in_memory(
|
|||||||
the transaction did not modify anything */
|
the transaction did not modify anything */
|
||||||
{
|
{
|
||||||
trx->must_flush_log_later = false;
|
trx->must_flush_log_later = false;
|
||||||
trx->read_view.close();
|
trx->read_view.unuse();
|
||||||
|
|
||||||
if (trx_is_autocommit_non_locking(trx)) {
|
if (trx_is_autocommit_non_locking(trx)) {
|
||||||
ut_ad(trx->id == 0);
|
ut_ad(trx->id == 0);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user