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:
Sergey Vojtovich 2018-01-30 20:59:42 +04:00
parent c0d5d7c0ef
commit bc7a1dc1fb
17 changed files with 334 additions and 340 deletions

View File

@ -3499,7 +3499,7 @@ ha_innobase::init_table_handle_for_HANDLER(void)
/* 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);
@ -4386,7 +4386,7 @@ innobase_start_trx_and_assign_read_view(
thd_get_trx_isolation(thd));
if (trx->isolation_level == TRX_ISO_REPEATABLE_READ) {
trx_sys.mvcc.view_open(trx);
trx->read_view.open(trx);
} else {
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
HA_ERR_UNSUPPORTED,
@ -16063,7 +16063,7 @@ ha_innobase::external_lock(
}
} 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
each consistent read set its own snapshot */
trx_sys.mvcc.view_close(trx->read_view);
trx->read_view.close();
}
}

View File

@ -5562,7 +5562,7 @@ error_handling_drop_uncached:
if (ctx->online && ctx->num_to_add_index) {
/* Assign a consistent read view for
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) {

View File

@ -35,7 +35,6 @@ Created 5/7/1996 Heikki Tuuri
#include "row0vers.h"
#include "que0que.h"
#include "btr0cur.h"
#include "read0read.h"
#include "log0recv.h"
/*********************************************************************//**

View File

@ -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 */

View File

@ -32,16 +32,154 @@ Created 2/16/1997 Heikki Tuuri
#include "trx0types.h"
// Friend declaration
class MVCC;
/** Read view lists the trx ids of those transactions for which a consistent
read should not see the modifications to the database. */
/** View is not in MVCC and not visible to purge thread. */
#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:
ReadView() : m_creator_trx_id(TRX_ID_MAX), m_ids(),
m_registered(false) {}
ReadView(): m_state(READ_VIEW_STATE_CLOSED) {}
/**
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.
@param[in] id transaction id to check
@param[in] name table name */
@ -85,25 +223,6 @@ public:
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.
@param file file to write to */
@ -129,54 +248,8 @@ public:
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:
/**
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
value. In other words, this is the "high water mark". */
trx_id_t m_low_limit_id;
@ -199,11 +272,8 @@ private:
they can be removed in purge if not needed by other views */
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];
public:
UT_LIST_NODE_T(ReadView) m_view_list;
};

View File

@ -810,17 +810,17 @@ private:
/** Solves race condition between register_rw() and snapshot_ids(). */
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;
public:
MY_ALIGNED(CACHE_LINE_SIZE)
MY_ALIGNED(CACHE_LINE_SIZE) mutable
TrxSysMutex mutex; /*!< mutex protecting most fields in
this structure except when noted
otherwise */
MY_ALIGNED(CACHE_LINE_SIZE)
MVCC mvcc; /*!< Multi version concurrency control
manager */
MY_ALIGNED(CACHE_LINE_SIZE)
trx_ut_list_t mysql_trx_list; /*!< List of transactions created
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:
static my_bool get_min_trx_id_callback(rw_trx_hash_element_t *element,
trx_id_t *id)

View File

@ -24,8 +24,6 @@ The transaction
Created 3/26/1996 Heikki Tuuri
*******************************************************/
#include "read0read.h"
/**********************************************************************//**
Determines if a transaction is in the given state.
The caller must hold trx_sys.mutex, or it must be the thread

View File

@ -24,10 +24,11 @@ Cursor read
Created 2/16/1997 Heikki Tuuri
*******************************************************/
#include "read0read.h"
#include "read0types.h"
#include "srv0srv.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.
*/
#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. */
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
Creates a snapshot where exactly the transactions serialized before this
point in time are seen in the view.
@param[in,out] trx transaction
*/
void ReadView::open(trx_t *trx)
void ReadView::snapshot(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);
m_up_limit_id= m_ids.empty() ? m_low_limit_id : m_ids.front();
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
within the same transaction will get the same read view, which is created
when this function is first called for a new started transaction.
View becomes visible to purge thread via trx_sys.m_views.
@param trx transaction instance of caller
@param[in,out] trx transaction
*/
void MVCC::view_open(trx_t* trx)
void ReadView::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;
}
else if (trx->read_view.is_open())
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())
{
case READ_VIEW_STATE_REGISTERED:
ut_ad(!srv_read_only_mode);
/*
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
and this thread.
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
trx_sys.mutex protection. But we're cutting edges to achieve great
scalability.
set state to READ_VIEW_STATE_OPEN atomically under trx_sys.mutex
protection. But we're cutting edges to achieve great scalability.
There're at least two types of concurrent threads interested in this
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
concurrently.
Speculative execution may reorder set_creator_trx_id() before
get_max_trx_id(). In this case purge thread has short gap to clone
outdated view. Which is probably not that bad: it just won't be able to
purge things that it was actually allowed to purge for a short while.
Speculative execution may reorder state change before get_max_trx_id().
In this case purge thread has short gap to clone outdated view. Which is
probably not that bad: it just won't be able to purge things that it was
actually allowed to purge for a short while.
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
transaction may get started, committed and purged meanwhile. It is
acceptable as well, since this view doesn't see it.
before state is set to READ_VIEW_STATE_OPEN. New read-write transaction
may get started, committed and purged meanwhile. It is acceptable as
well, since this view doesn't see it.
*/
trx->read_view.set_creator_trx_id(trx->id);
return;
}
if (trx_is_autocommit_non_locking(trx) && m_ids.empty() &&
m_low_limit_id == trx_sys.get_max_trx_id())
goto reopen;
mutex_enter(&trx_sys.mutex);
trx->read_view.open(trx);
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);
}
/*
Can't reuse view, take new snapshot.
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)
{
view.close();
if (view.is_registered())
{
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
complicate m_state even further.
*/
mutex_enter(&trx_sys.mutex);
view.set_registered(false);
UT_LIST_REMOVE(m_views, &view);
ut_ad(validate());
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.
@param other view to copy from */
Clones the oldest view and stores it in view.
void
ReadView::copy(const ReadView& other)
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.
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);
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;
}
/** 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 determine whether it should
purge the delete marked record or not.
@param view Preallocated view, owned by the caller */
void
MVCC::clone_oldest_view(ReadView* view)
{
mutex_enter(&trx_sys.mutex);
/* Find oldest view. */
for (const ReadView *oldest_view = UT_LIST_GET_LAST(m_views);
oldest_view != NULL;
oldest_view = UT_LIST_GET_PREV(m_view_list, oldest_view))
{
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);
const ReadView *oldest_view= &purge_sys->view;
purge_sys->view.snapshot(0);
mutex_enter(&mutex);
/* Find oldest view. */
for (const ReadView *v= UT_LIST_GET_FIRST(m_views); v;
v= UT_LIST_GET_NEXT(m_view_list, v))
{
int32_t state;
while ((state= v->get_state()) == READ_VIEW_STATE_SNAPSHOT)
ut_delay(1);
if (state == READ_VIEW_STATE_OPEN &&
v->low_limit_no() < oldest_view->low_limit_no())
oldest_view= v;
}
if (oldest_view != &purge_sys->view)
purge_sys->view.copy(*oldest_view);
mutex_exit(&mutex);
}

View File

@ -41,7 +41,6 @@ Created 4/20/1996 Heikki Tuuri
#include "row0ext.h"
#include "row0upd.h"
#include "rem0cmp.h"
#include "read0read.h"
#include "ut0mem.h"
#include "gis0geo.h"
#include "row0mysql.h"

View File

@ -51,7 +51,6 @@ Created 12/19/1997 Heikki Tuuri
#include "pars0sym.h"
#include "pars0pars.h"
#include "row0mysql.h"
#include "read0read.h"
#include "buf0lru.h"
#include "srv0srv.h"
#include "ha_prototypes.h"
@ -2270,7 +2269,7 @@ row_sel_step(
if (node->consistent_read) {
trx_t *trx = thr_get_trx(thr);
/* 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() ?
&trx->read_view : NULL;
} else {
@ -4426,7 +4425,7 @@ row_search_mvcc(
/* Assign a read view for the query */
trx_start_if_not_started(trx, false);
trx_sys.mvcc.view_open(trx);
trx->read_view.open(trx);
prebuilt->sql_stat_start = FALSE;
} else {
@ -5878,8 +5877,7 @@ row_search_check_if_query_cache_permitted(
transaction if it does not yet have one */
if (trx->isolation_level >= TRX_ISO_REPEATABLE_READ) {
trx_sys.mvcc.view_open(trx);
trx->read_view.open(trx);
}
}

View File

@ -41,7 +41,6 @@ Created 2/6/1997 Heikki Tuuri
#include "row0row.h"
#include "row0upd.h"
#include "rem0cmp.h"
#include "read0read.h"
#include "lock0lock.h"
#include "row0mysql.h"

View File

@ -1365,9 +1365,8 @@ srv_printf_innodb_monitor(
srv_conc_get_active_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",
trx_sys.mvcc.size());
trx_sys.view_count());
n_reserved = fil_space_get_n_reserved_extents(0);
if (n_reserved > 0) {

View File

@ -33,7 +33,6 @@ Created 3/26/1996 Heikki Tuuri
#include "mtr0log.h"
#include "os0thread.h"
#include "que0que.h"
#include "read0read.h"
#include "row0purge.h"
#include "row0upd.h"
#include "srv0mon.h"
@ -1615,7 +1614,7 @@ trx_purge(
ut_a(purge_sys->n_submitted == purge_sys->n_completed);
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);
#ifdef UNIV_DEBUG

View File

@ -31,7 +31,6 @@ Created 3/26/1996 Heikki Tuuri
#include "mtr0log.h"
#include "dict0dict.h"
#include "ut0mem.h"
#include "read0read.h"
#include "row0ext.h"
#include "row0upd.h"
#include "que0que.h"

View File

@ -37,7 +37,6 @@ Created 3/26/1996 Heikki Tuuri
#include "mach0data.h"
#include "pars0pars.h"
#include "que0que.h"
#include "read0read.h"
#include "row0mysql.h"
#include "row0undo.h"
#include "srv0mon.h"

View File

@ -42,7 +42,6 @@ Created 3/26/1996 Heikki Tuuri
#include "log0log.h"
#include "log0recv.h"
#include "os0file.h"
#include "read0read.h"
#include "fsp0sysspace.h"
#include <mysql/service_wsrep.h>
@ -402,6 +401,8 @@ trx_sys_t::create()
m_initialised = true;
mutex_create(LATCH_ID_TRX_SYS, &mutex);
UT_LIST_INIT(mysql_trx_list, &trx_t::mysql_trx_list);
UT_LIST_INIT(m_views, &ReadView::m_view_list);
rw_trx_hash.init();
}
@ -507,7 +508,7 @@ trx_sys_t::close()
return;
}
if (ulint size = mvcc.size()) {
if (size_t size = view_count()) {
ib::error() << "All read views were not closed before"
" shutdown: " << size << " read views open";
}
@ -532,6 +533,7 @@ trx_sys_t::close()
}
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. */
mutex_free(&mutex);
@ -564,7 +566,7 @@ ulint trx_sys_t::any_active_transactions()
reinterpret_cast<my_hash_walk_action>
(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);
trx != NULL;
trx = UT_LIST_GET_NEXT(mysql_trx_list, trx)) {
@ -572,7 +574,7 @@ ulint trx_sys_t::any_active_transactions()
total_trx++;
}
}
mutex_exit(&trx_sys.mutex);
mutex_exit(&mutex);
return(total_trx);
}

View File

@ -39,7 +39,6 @@ Created 3/26/1996 Heikki Tuuri
#include "log0log.h"
#include "os0proc.h"
#include "que0que.h"
#include "read0read.h"
#include "srv0mon.h"
#include "srv0srv.h"
#include "fsp0sysspace.h"
@ -511,7 +510,7 @@ trx_free(trx_t*& trx)
trx->mod_tables.clear();
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
to pool */
@ -673,7 +672,7 @@ trx_disconnect_from_mysql(
trx_t* trx,
bool prepared)
{
trx_sys.mvcc.view_close(trx->read_view);
trx->read_view.close();
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();
}
trx_sys.mvcc.clone_oldest_view(&purge_sys->view);
trx_sys.clone_oldest_view();
}
/** Assign a persistent rollback segment in a round-robin fashion,
@ -1512,7 +1511,7 @@ trx_commit_in_memory(
the transaction did not modify anything */
{
trx->must_flush_log_later = false;
trx->read_view.close();
trx->read_view.unuse();
if (trx_is_autocommit_non_locking(trx)) {
ut_ad(trx->id == 0);