Commit 0ca2ea1a authored by Sergey Vojtovich's avatar Sergey Vojtovich

MDEV-14638 - Replace trx_sys_t::rw_trx_set with LF_HASH

trx reference counter was updated under mutex and read without any
protection. This is both slow and unsafe. Use atomic operations for
reference counter accesses.
parent 380069c2
......@@ -45,7 +45,7 @@ index record.
@param[in] rec secondary index record
@param[in] index secondary index
@param[in] offsets rec_get_offsets(rec, index)
@return the active transaction; trx_release_reference() must be invoked
@return the active transaction; trx->release_reference() must be invoked
@retval NULL if the record was committed */
trx_t*
row_vers_impl_x_locked(
......
......@@ -598,7 +598,7 @@ class rw_trx_hash_t
With do_ref_count == true caller may dereference trx even if it is not
holding lock_sys->mutex. Caller is responsible for calling
trx_release_reference() when it is done playing with trx.
trx->release_reference() when it is done playing with trx.
Ideally this method should get caller rw_trx_hash_pins along with trx
object as a parameter, similar to insert() and erase(). However most
......@@ -646,7 +646,7 @@ class rw_trx_hash_t
if ((trx= element->trx))
{
if (do_ref_count)
trx_reference(trx);
trx->reference();
#ifdef UNIV_DEBUG
mutex_enter(&trx->mutex);
ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE) ||
......
......@@ -532,26 +532,6 @@ void
trx_set_rw_mode(
trx_t* trx);
/**
Increase the reference count.
@param trx Transaction that is being referenced */
UNIV_INLINE
void
trx_reference(
trx_t* trx);
/**
Release the transaction. Decrease the reference count.
@param trx Transaction that is being released */
UNIV_INLINE
void
trx_release_reference(
trx_t* trx);
/**
Check if the transaction is being referenced. */
#define trx_is_referenced(t) ((t)->n_ref > 0)
/**
@param[in] requestor Transaction requesting the lock
@param[in] holder Transaction holding the lock
......@@ -889,6 +869,19 @@ struct TrxVersion {
typedef std::list<TrxVersion, ut_allocator<TrxVersion> > hit_list_t;
struct trx_t {
private:
/**
Count of references.
We can't release the locks nor commit the transaction until this reference
is 0. We can change the state to TRX_STATE_COMMITTED_IN_MEMORY to signify
that it is no longer "active".
*/
int32_t n_ref;
public:
TrxMutex mutex; /*!< Mutex protecting the fields
state and lock (except some fields
of lock, which are protected by
......@@ -1235,14 +1228,6 @@ struct trx_t {
const char* start_file; /*!< Filename where it was started */
#endif /* UNIV_DEBUG */
lint n_ref; /*!< Count of references, protected
by trx_t::mutex. We can't release the
locks nor commit the transaction until
this reference is 0. We can change
the state to COMMITTED_IN_MEMORY to
signify that it is no longer
"active". */
/** Version of this instance. It is incremented each time the
instance is re-used in trx_start_low(). It is used to track
whether a transaction has been restarted since it was tagged
......@@ -1311,6 +1296,33 @@ struct trx_t {
return(assign_temp_rseg());
}
bool is_referenced()
{
return my_atomic_load32_explicit(&n_ref, MY_MEMORY_ORDER_RELAXED) > 0;
}
void reference()
{
#ifdef UNIV_DEBUG
int32_t old_n_ref=
#endif
my_atomic_add32_explicit(&n_ref, 1, MY_MEMORY_ORDER_RELAXED);
ut_ad(old_n_ref >= 0);
}
void release_reference()
{
#ifdef UNIV_DEBUG
int32_t old_n_ref=
#endif
my_atomic_add32_explicit(&n_ref, -1, MY_MEMORY_ORDER_RELAXED);
ut_ad(old_n_ref > 0);
}
private:
/** Assign a rollback segment for modifying temporary tables.
@return the assigned rollback segment */
......
......@@ -213,34 +213,6 @@ ok:
trx->dict_operation = op;
}
/**
Increase the reference count.
@param trx Transaction that is being referenced */
UNIV_INLINE void trx_reference(trx_t *trx)
{
trx_mutex_enter(trx);
ut_ad(trx->n_ref >= 0);
++trx->n_ref;
trx_mutex_exit(trx);
}
/**
Release the transaction. Decrease the reference count.
@param trx Transaction that is being released */
UNIV_INLINE
void
trx_release_reference(
trx_t* trx)
{
trx_mutex_enter(trx);
ut_ad(trx->n_ref > 0);
--trx->n_ref;
trx_mutex_exit(trx);
}
/**
@param trx Get the active view for this transaction, if one exists
@return the transaction's read view or NULL if one not assigned. */
......
......@@ -6813,7 +6813,7 @@ lock_rec_convert_impl_to_expl_for_trx(
trx_t* trx, /*!< in/out: active transaction */
ulint heap_no)/*!< in: rec heap number to lock */
{
ut_ad(trx_is_referenced(trx));
ut_ad(trx->is_referenced());
ut_ad(page_rec_is_leaf(rec));
ut_ad(!rec_is_default_row(rec, index));
......@@ -6837,7 +6837,7 @@ lock_rec_convert_impl_to_expl_for_trx(
lock_mutex_exit();
trx_release_reference(trx);
trx->release_reference();
DEBUG_SYNC_C("after_lock_rec_convert_impl_to_expl_for_trx");
}
......@@ -6883,7 +6883,7 @@ lock_rec_convert_impl_to_expl(
if (trx != 0) {
ulint heap_no = page_rec_get_heap_no(rec);
ut_ad(trx_is_referenced(trx));
ut_ad(trx->is_referenced());
/* If the transaction is still active and has no
explicit x-lock set on the record, set one for it.
......@@ -7655,13 +7655,13 @@ lock_trx_release_locks(
trx->state = TRX_STATE_COMMITTED_IN_MEMORY;
/*--------------------------------------*/
if (trx_is_referenced(trx)) {
if (trx->is_referenced()) {
ut_a(release_lock);
lock_mutex_exit();
while (trx_is_referenced(trx)) {
while (trx->is_referenced()) {
trx_mutex_exit(trx);
......@@ -7681,7 +7681,7 @@ lock_trx_release_locks(
trx_mutex_enter(trx);
}
ut_ad(!trx_is_referenced(trx));
ut_ad(!trx->is_referenced());
/* If the background thread trx_rollback_or_clean_recovered()
is still active then there is a chance that the rollback
......
......@@ -4982,7 +4982,7 @@ row_search_mvcc(
trx, rec, index, offsets)) {
/* The record belongs to an active
transaction. We must acquire a lock. */
trx_release_reference(t);
t->release_reference();
} else {
/* The secondary index record does not
point to a delete-marked clustered index
......
......@@ -73,7 +73,7 @@ index record.
@param[in] index secondary index
@param[in] offsets rec_get_offsets(rec, index)
@param[in,out] mtr mini-transaction
@return the active transaction; trx_release_reference() must be invoked
@return the active transaction; trx->release_reference() must be invoked
@retval NULL if the record was committed */
UNIV_INLINE
trx_t*
......@@ -217,7 +217,7 @@ row_vers_impl_x_locked_low(
or updated, the leaf page record always is
created with a clear delete-mark flag.
(We never insert a delete-marked record.) */
trx_release_reference(trx);
trx->release_reference();
trx = 0;
}
......@@ -328,7 +328,7 @@ row_vers_impl_x_locked_low(
/* prev_version was the first version modified by
the trx_id transaction: no implicit x-lock */
trx_release_reference(trx);
trx->release_reference();
trx = 0;
break;
}
......@@ -350,7 +350,7 @@ index record.
@param[in] rec secondary index record
@param[in] index secondary index
@param[in] offsets rec_get_offsets(rec, index)
@return the active transaction; trx_release_reference() must be invoked
@return the active transaction; trx->release_reference() must be invoked
@retval NULL if the record was committed */
trx_t*
row_vers_impl_x_locked(
......@@ -398,7 +398,7 @@ row_vers_impl_x_locked(
caller_trx, clust_rec, clust_index, rec, index,
offsets, &mtr);
ut_ad(trx == 0 || trx_is_referenced(trx));
ut_ad(trx == 0 || trx->is_referenced());
}
mtr_commit(&mtr);
......
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