Commit e6a9ce27 authored by Sergey Vojtovich's avatar Sergey Vojtovich

MDEV-15773 - Simplified away trx_sys_t::m_views

Use trx_sys_t::trx_list instead.
parent 3d5f7ad2
...@@ -33,17 +33,14 @@ Created 2/16/1997 Heikki Tuuri ...@@ -33,17 +33,14 @@ Created 2/16/1997 Heikki Tuuri
#include "trx0types.h" #include "trx0types.h"
/** View is not in MVCC and not visible to purge thread. */ /** View is not visible to purge thread. */
#define READ_VIEW_STATE_CLOSED 0 #define READ_VIEW_STATE_CLOSED 0
/** View is in MVCC, but not visible to purge thread. */ /** View is being opened, purge thread must wait for state change. */
#define READ_VIEW_STATE_REGISTERED 1 #define READ_VIEW_STATE_SNAPSHOT 1
/** View is in MVCC, purge thread must wait for READ_VIEW_STATE_OPEN. */ /** View is visible to purge thread. */
#define READ_VIEW_STATE_SNAPSHOT 2 #define READ_VIEW_STATE_OPEN 2
/** View is in MVCC and is visible to purge thread. */
#define READ_VIEW_STATE_OPEN 3
/** /**
...@@ -56,34 +53,25 @@ class ReadView ...@@ -56,34 +53,25 @@ class ReadView
View state. View state.
It is not defined as enum as it has to be updated using atomic operations. 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, Possible values are READ_VIEW_STATE_CLOSED, READ_VIEW_STATE_SNAPSHOT and
READ_VIEW_STATE_SNAPSHOT and READ_VIEW_STATE_OPEN. READ_VIEW_STATE_OPEN.
Possible state transfers... Possible state transfers...
Opening view for the first time: Start view open:
READ_VIEW_STATE_CLOSED -> READ_VIEW_STATE_SNAPSHOT (non-atomic) READ_VIEW_STATE_CLOSED -> READ_VIEW_STATE_SNAPSHOT
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: Complete view open:
READ_VIEW_STATE_OPEN -> READ_VIEW_STATE_CLOSED (non-atomic) READ_VIEW_STATE_SNAPSHOT -> READ_VIEW_STATE_OPEN
Reusing view: Close view:
READ_VIEW_STATE_REGISTERED -> READ_VIEW_STATE_SNAPSHOT (atomic) READ_VIEW_STATE_OPEN -> READ_VIEW_STATE_CLOSED
Removing closed view from list:
READ_VIEW_STATE_REGISTERED -> READ_VIEW_STATE_CLOSED (non-atomic)
*/ */
int32_t m_state; int32_t m_state;
public: public:
ReadView(): m_state(READ_VIEW_STATE_CLOSED) {} ReadView(): m_state(READ_VIEW_STATE_CLOSED), m_low_limit_id(0) {}
/** /**
...@@ -136,7 +124,7 @@ class ReadView ...@@ -136,7 +124,7 @@ class ReadView
Opens a read view where exactly the transactions serialized before this 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.
View becomes visible to purge thread via trx_sys.m_views. View becomes visible to purge thread.
@param[in,out] trx transaction @param[in,out] trx transaction
*/ */
...@@ -146,23 +134,14 @@ class ReadView ...@@ -146,23 +134,14 @@ class ReadView
/** /**
Closes the view. Closes the view.
View becomes not visible to purge thread via trx_sys.m_views. View becomes not visible to purge thread.
*/ */
void close(); 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 || ut_ad(m_state == READ_VIEW_STATE_CLOSED ||
m_state == READ_VIEW_STATE_REGISTERED ||
m_state == READ_VIEW_STATE_OPEN); m_state == READ_VIEW_STATE_OPEN);
if (m_state == READ_VIEW_STATE_OPEN) if (m_state == READ_VIEW_STATE_OPEN)
my_atomic_store32_explicit(&m_state, READ_VIEW_STATE_REGISTERED, my_atomic_store32_explicit(&m_state, READ_VIEW_STATE_CLOSED,
MY_MEMORY_ORDER_RELAXED); MY_MEMORY_ORDER_RELAXED);
} }
...@@ -183,8 +162,7 @@ class ReadView ...@@ -183,8 +162,7 @@ class ReadView
bool is_open() const bool is_open() const
{ {
ut_ad(m_state == READ_VIEW_STATE_OPEN || ut_ad(m_state == READ_VIEW_STATE_OPEN ||
m_state == READ_VIEW_STATE_CLOSED || m_state == READ_VIEW_STATE_CLOSED);
m_state == READ_VIEW_STATE_REGISTERED);
return m_state == READ_VIEW_STATE_OPEN; return m_state == READ_VIEW_STATE_OPEN;
} }
...@@ -302,10 +280,6 @@ class ReadView ...@@ -302,10 +280,6 @@ class ReadView
whose transaction number is strictly smaller (<) than this value: whose transaction number is strictly smaller (<) than this value:
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;
byte pad1[CACHE_LINE_SIZE];
public:
UT_LIST_NODE_T(ReadView) m_view_list;
}; };
#endif #endif
...@@ -802,9 +802,6 @@ class trx_sys_t ...@@ -802,9 +802,6 @@ class trx_sys_t
*/ */
MY_ALIGNED(CACHE_LINE_SIZE) int32 rseg_history_len; MY_ALIGNED(CACHE_LINE_SIZE) int32 rseg_history_len;
/** Active views. */
MY_ALIGNED(CACHE_LINE_SIZE) UT_LIST_BASE_NODE_T(ReadView) m_views;
bool m_initialised; bool m_initialised;
public: public:
...@@ -1051,27 +1048,27 @@ class trx_sys_t ...@@ -1051,27 +1048,27 @@ class trx_sys_t
/** /**
Registers view in MVCC. Registers transaction in trx_sys.
@param view view owned by the caller @param trx transaction
*/ */
void register_view(ReadView *view) void register_trx(trx_t *trx)
{ {
mutex_enter(&mutex); mutex_enter(&mutex);
UT_LIST_ADD_FIRST(m_views, view); UT_LIST_ADD_FIRST(trx_list, trx);
mutex_exit(&mutex); mutex_exit(&mutex);
} }
/** /**
Deregisters view in MVCC. Deregisters transaction in trx_sys.
@param view view owned by the caller @param trx transaction
*/ */
void deregister_view(ReadView *view) void deregister_trx(trx_t *trx)
{ {
mutex_enter(&mutex); mutex_enter(&mutex);
UT_LIST_REMOVE(m_views, view); UT_LIST_REMOVE(trx_list, trx);
mutex_exit(&mutex); mutex_exit(&mutex);
} }
...@@ -1092,10 +1089,10 @@ class trx_sys_t ...@@ -1092,10 +1089,10 @@ class trx_sys_t
size_t count= 0; size_t count= 0;
mutex_enter(&mutex); mutex_enter(&mutex);
for (const ReadView* view= UT_LIST_GET_FIRST(m_views); view; for (const trx_t *trx= UT_LIST_GET_FIRST(trx_list); trx;
view= UT_LIST_GET_NEXT(m_view_list, view)) trx= UT_LIST_GET_NEXT(trx_list, trx))
{ {
if (view->get_state() == READ_VIEW_STATE_OPEN) if (trx->read_view.get_state() == READ_VIEW_STATE_OPEN)
++count; ++count;
} }
mutex_exit(&mutex); mutex_exit(&mutex);
......
...@@ -193,7 +193,7 @@ inline void ReadView::snapshot(trx_t *trx) ...@@ -193,7 +193,7 @@ inline void ReadView::snapshot(trx_t *trx)
Opens a read view where exactly the transactions serialized before this 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.
View becomes visible to purge thread via trx_sys.m_views. View becomes visible to purge thread.
@param[in,out] trx transaction @param[in,out] trx transaction
*/ */
...@@ -205,8 +205,9 @@ void ReadView::open(trx_t *trx) ...@@ -205,8 +205,9 @@ void ReadView::open(trx_t *trx)
case READ_VIEW_STATE_OPEN: case READ_VIEW_STATE_OPEN:
ut_ad(!srv_read_only_mode); ut_ad(!srv_read_only_mode);
return; return;
case READ_VIEW_STATE_REGISTERED: case READ_VIEW_STATE_CLOSED:
ut_ad(!srv_read_only_mode); if (srv_read_only_mode)
return;
/* /*
Reuse closed view if there were no read-write transactions since (and at) Reuse closed view if there were no read-write transactions since (and at)
its creation time. its creation time.
...@@ -224,18 +225,6 @@ void ReadView::open(trx_t *trx) ...@@ -224,18 +225,6 @@ void ReadView::open(trx_t *trx)
What bad things can happen because we allow this race? What bad things can happen because we allow this race?
First, purge thread may be affected by this race condition only if this
view is the oldest open view. In other words this view is either last in
m_views list or there're no open views beyond.
In this case purge may not catch this view and clone some younger view
instead. It might be kind of alright, because there were no read-write
transactions and there should be nothing to purge. Besides younger view
must have exactly the same values.
Second, scary things start when there's a read-write transaction starting
concurrently.
Speculative execution may reorder state change before get_max_trx_id(). 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 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 probably not that bad: it just won't be able to purge things that it was
...@@ -268,12 +257,6 @@ void ReadView::open(trx_t *trx) ...@@ -268,12 +257,6 @@ void ReadView::open(trx_t *trx)
my_atomic_store32_explicit(&m_state, READ_VIEW_STATE_SNAPSHOT, my_atomic_store32_explicit(&m_state, READ_VIEW_STATE_SNAPSHOT,
MY_MEMORY_ORDER_RELAXED); MY_MEMORY_ORDER_RELAXED);
break; 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: default:
ut_ad(0); ut_ad(0);
} }
...@@ -286,52 +269,28 @@ void ReadView::open(trx_t *trx) ...@@ -286,52 +269,28 @@ void ReadView::open(trx_t *trx)
} }
/**
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;
}
}
/** /**
Clones the oldest view and stores it in view. Clones the oldest view and stores it in view.
No need to call ReadView::close(). The caller owns the view that is passed 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 in. This function is called by purge thread to determine whether it should
purge the delete marked record or not. 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() void trx_sys_t::clone_oldest_view()
{ {
purge_sys.view.snapshot(0); purge_sys.view.snapshot(0);
mutex_enter(&mutex); mutex_enter(&mutex);
/* Find oldest view. */ /* Find oldest view. */
for (const ReadView *v= UT_LIST_GET_FIRST(m_views); v; for (const trx_t *trx= UT_LIST_GET_FIRST(trx_list); trx;
v= UT_LIST_GET_NEXT(m_view_list, v)) trx= UT_LIST_GET_NEXT(trx_list, trx))
{ {
int32_t state; int32_t state;
while ((state= v->get_state()) == READ_VIEW_STATE_SNAPSHOT) while ((state= trx->read_view.get_state()) == READ_VIEW_STATE_SNAPSHOT)
ut_delay(1); ut_delay(1);
if (state == READ_VIEW_STATE_OPEN) if (state == READ_VIEW_STATE_OPEN)
purge_sys.view.copy(*v); purge_sys.view.copy(trx->read_view);
} }
mutex_exit(&mutex); mutex_exit(&mutex);
} }
...@@ -218,7 +218,6 @@ trx_sys_t::create() ...@@ -218,7 +218,6 @@ 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(trx_list, &trx_t::trx_list); UT_LIST_INIT(trx_list, &trx_t::trx_list);
UT_LIST_INIT(m_views, &ReadView::m_view_list);
my_atomic_store32(&rseg_history_len, 0); my_atomic_store32(&rseg_history_len, 0);
rw_trx_hash.init(); rw_trx_hash.init();
...@@ -346,7 +345,6 @@ trx_sys_t::close() ...@@ -346,7 +345,6 @@ trx_sys_t::close()
} }
ut_a(UT_LIST_GET_LEN(trx_list) == 0); ut_a(UT_LIST_GET_LEN(trx_list) == 0);
ut_ad(UT_LIST_GET_LEN(m_views) == 0);
mutex_free(&mutex); mutex_free(&mutex);
m_initialised = false; m_initialised = false;
} }
......
...@@ -423,9 +423,7 @@ trx_t *trx_create() ...@@ -423,9 +423,7 @@ trx_t *trx_create()
trx->wsrep_event = NULL; trx->wsrep_event = NULL;
#endif /* WITH_WSREP */ #endif /* WITH_WSREP */
mutex_enter(&trx_sys.mutex); trx_sys.register_trx(trx);
UT_LIST_ADD_FIRST(trx_sys.trx_list, trx);
mutex_exit(&trx_sys.mutex);
return(trx); return(trx);
} }
...@@ -472,9 +470,7 @@ void trx_free(trx_t*& trx) ...@@ -472,9 +470,7 @@ void trx_free(trx_t*& trx)
trx->dict_operation = TRX_DICT_OP_NONE; trx->dict_operation = TRX_DICT_OP_NONE;
assert_trx_is_inactive(trx); assert_trx_is_inactive(trx);
mutex_enter(&trx_sys.mutex); trx_sys.deregister_trx(trx);
UT_LIST_REMOVE(trx_sys.trx_list, trx);
mutex_exit(&trx_sys.mutex);
assert_trx_is_free(trx); assert_trx_is_free(trx);
...@@ -492,9 +488,6 @@ void trx_free(trx_t*& trx) ...@@ -492,9 +488,6 @@ void trx_free(trx_t*& trx)
trx->mod_tables.clear(); trx->mod_tables.clear();
ut_ad(!trx->read_view.is_open());
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 */
ut_ad(trx->will_lock == 0); ut_ad(trx->will_lock == 0);
...@@ -1308,7 +1301,7 @@ trx_commit_in_memory( ...@@ -1308,7 +1301,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.unuse(); trx->read_view.close();
if (trx_is_autocommit_non_locking(trx)) { if (trx_is_autocommit_non_locking(trx)) {
ut_ad(trx->id == 0); ut_ad(trx->id == 0);
......
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