Commit 3ce8a0fc authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-16136: Simplify trx_lock_t memory management

Allocate trx->lock.rec_pool and trx->lock.table_pool directly from trx_t.
Remove unnecessary use of std::vector.

In order to do this, move some definitions from lock0priv.h to
lock0types.h, so that ib_lock_t will not be an opaque type.
parent b7951348
...@@ -834,69 +834,6 @@ lock_trx_has_rec_x_lock( ...@@ -834,69 +834,6 @@ lock_trx_has_rec_x_lock(
MY_ATTRIBUTE((warn_unused_result)); MY_ATTRIBUTE((warn_unused_result));
#endif /* UNIV_DEBUG */ #endif /* UNIV_DEBUG */
/**
Allocate cached locks for the transaction.
@param trx allocate cached record locks for this transaction */
void
lock_trx_alloc_locks(trx_t* trx);
/** Lock modes and types */
/* @{ */
#define LOCK_MODE_MASK 0xFUL /*!< mask used to extract mode from the
type_mode field in a lock */
/** Lock types */
/* @{ */
#define LOCK_TABLE 16U /*!< table lock */
#define LOCK_REC 32U /*!< record lock */
#define LOCK_TYPE_MASK 0xF0UL /*!< mask used to extract lock type from the
type_mode field in a lock */
#if LOCK_MODE_MASK & LOCK_TYPE_MASK
# error "LOCK_MODE_MASK & LOCK_TYPE_MASK"
#endif
#define LOCK_WAIT 256U /*!< Waiting lock flag; when set, it
means that the lock has not yet been
granted, it is just waiting for its
turn in the wait queue */
/* Precise modes */
#define LOCK_ORDINARY 0 /*!< this flag denotes an ordinary
next-key lock in contrast to LOCK_GAP
or LOCK_REC_NOT_GAP */
#define LOCK_GAP 512U /*!< when this bit is set, it means that the
lock holds only on the gap before the record;
for instance, an x-lock on the gap does not
give permission to modify the record on which
the bit is set; locks of this type are created
when records are removed from the index chain
of records */
#define LOCK_REC_NOT_GAP 1024U /*!< this bit means that the lock is only on
the index record and does NOT block inserts
to the gap before the index record; this is
used in the case when we retrieve a record
with a unique key, and is also used in
locking plain SELECTs (not part of UPDATE
or DELETE) when the user has set the READ
COMMITTED isolation level */
#define LOCK_INSERT_INTENTION 2048U/*!< this bit is set when we place a waiting
gap type record lock request in order to let
an insert of an index record to wait until
there are no conflicting locks by other
transactions on the gap; note that this flag
remains set when the waiting lock is granted,
or if the lock is inherited to a neighboring
record */
#define LOCK_PREDICATE 8192U /*!< Predicate lock */
#define LOCK_PRDT_PAGE 16384U /*!< Page lock */
#if (LOCK_WAIT|LOCK_GAP|LOCK_REC_NOT_GAP|LOCK_INSERT_INTENTION|LOCK_PREDICATE|LOCK_PRDT_PAGE)&LOCK_MODE_MASK
# error
#endif
#if (LOCK_WAIT|LOCK_GAP|LOCK_REC_NOT_GAP|LOCK_INSERT_INTENTION|LOCK_PREDICATE|LOCK_PRDT_PAGE)&LOCK_TYPE_MASK
# error
#endif
/* @} */
/** Lock operation struct */ /** Lock operation struct */
struct lock_op_t{ struct lock_op_t{
dict_table_t* table; /*!< table to be locked */ dict_table_t* table; /*!< table to be locked */
......
...@@ -42,19 +42,6 @@ those functions in lock/ */ ...@@ -42,19 +42,6 @@ those functions in lock/ */
#define UINT32_MAX (4294967295U) #define UINT32_MAX (4294967295U)
#endif #endif
/** A table lock */
struct lock_table_t {
dict_table_t* table; /*!< database table in dictionary
cache */
UT_LIST_NODE_T(lock_t)
locks; /*!< list of locks on the same
table */
/** Print the table lock into the given output stream
@param[in,out] out the output stream
@return the given output stream. */
std::ostream& print(std::ostream& out) const;
};
/** Print the table lock into the given output stream /** Print the table lock into the given output stream
@param[in,out] out the output stream @param[in,out] out the output stream
@return the given output stream. */ @return the given output stream. */
...@@ -77,131 +64,11 @@ operator<<(std::ostream& out, const lock_table_t& lock) ...@@ -77,131 +64,11 @@ operator<<(std::ostream& out, const lock_table_t& lock)
return(lock.print(out)); return(lock.print(out));
} }
/** Record lock for a page */
struct lock_rec_t {
ib_uint32_t space; /*!< space id */
ib_uint32_t page_no; /*!< page number */
ib_uint32_t n_bits; /*!< number of bits in the lock
bitmap; NOTE: the lock bitmap is
placed immediately after the
lock struct */
/** Print the record lock into the given output stream
@param[in,out] out the output stream
@return the given output stream. */
std::ostream& print(std::ostream& out) const;
};
/** Print the record lock into the given output stream
@param[in,out] out the output stream
@return the given output stream. */
inline
std::ostream& lock_rec_t::print(std::ostream& out) const
{
out << "[lock_rec_t: space=" << space << ", page_no=" << page_no
<< ", n_bits=" << n_bits << "]";
return(out);
}
inline
std::ostream&
operator<<(std::ostream& out, const lock_rec_t& lock)
{
return(lock.print(out));
}
/** Lock struct; protected by lock_sys->mutex */
struct lock_t {
trx_t* trx; /*!< transaction owning the
lock */
UT_LIST_NODE_T(lock_t)
trx_locks; /*!< list of the locks of the
transaction */
dict_index_t* index; /*!< index for a record lock */
lock_t* hash; /*!< hash chain node for a record
lock. The link node in a singly linked
list, used during hashing. */
/* Statistics for how long lock has been held and time
how long this lock had to be waited before it was granted */
time_t requested_time; /*!< Lock request time */
ulint wait_time; /*!< Time waited this lock or 0 */
union {
lock_table_t tab_lock;/*!< table lock */
lock_rec_t rec_lock;/*!< record lock */
} un_member; /*!< lock details */
ib_uint32_t type_mode; /*!< lock type, mode, LOCK_GAP or
LOCK_REC_NOT_GAP,
LOCK_INSERT_INTENTION,
wait flag, ORed */
/** Determine if the lock object is a record lock.
@return true if record lock, false otherwise. */
bool is_record_lock() const
{
return(type() == LOCK_REC);
}
bool is_waiting() const
{
return(type_mode & LOCK_WAIT);
}
bool is_gap() const
{
return(type_mode & LOCK_GAP);
}
bool is_record_not_gap() const
{
return(type_mode & LOCK_REC_NOT_GAP);
}
bool is_insert_intention() const
{
return(type_mode & LOCK_INSERT_INTENTION);
}
ulint type() const {
return(type_mode & LOCK_TYPE_MASK);
}
enum lock_mode mode() const
{
return(static_cast<enum lock_mode>(type_mode & LOCK_MODE_MASK));
}
/** Print the lock object into the given output stream.
@param[in,out] out the output stream
@return the given output stream. */
std::ostream& print(std::ostream& out) const;
/** Convert the member 'type_mode' into a human readable string.
@return human readable string */
std::string type_mode_string() const;
const char* type_string() const
{
switch (type_mode & LOCK_TYPE_MASK) {
case LOCK_REC:
return("LOCK_REC");
case LOCK_TABLE:
return("LOCK_TABLE");
default:
ut_error;
}
}
};
/** Convert the member 'type_mode' into a human readable string. /** Convert the member 'type_mode' into a human readable string.
@return human readable string */ @return human readable string */
inline inline
std::string std::string
lock_t::type_mode_string() const ib_lock_t::type_mode_string() const
{ {
std::ostringstream sout; std::ostringstream sout;
sout << type_string(); sout << type_string();
...@@ -227,7 +94,7 @@ lock_t::type_mode_string() const ...@@ -227,7 +94,7 @@ lock_t::type_mode_string() const
inline inline
std::ostream& std::ostream&
lock_t::print(std::ostream& out) const ib_lock_t::print(std::ostream& out) const
{ {
out << "[lock_t: type_mode=" << type_mode << "(" out << "[lock_t: type_mode=" << type_mode << "("
<< type_mode_string() << ")"; << type_mode_string() << ")";
...@@ -244,7 +111,7 @@ lock_t::print(std::ostream& out) const ...@@ -244,7 +111,7 @@ lock_t::print(std::ostream& out) const
inline inline
std::ostream& std::ostream&
operator<<(std::ostream& out, const lock_t& lock) operator<<(std::ostream& out, const ib_lock_t& lock)
{ {
return(lock.print(out)); return(lock.print(out));
} }
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2018, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free Software
...@@ -73,6 +74,195 @@ const char* lock_mode_string(enum lock_mode mode) ...@@ -73,6 +74,195 @@ const char* lock_mode_string(enum lock_mode mode)
} }
} }
typedef UT_LIST_BASE_NODE_T(lock_t) trx_lock_list_t; /** A table lock */
struct lock_table_t {
dict_table_t* table; /*!< database table in dictionary
cache */
UT_LIST_NODE_T(ib_lock_t)
locks; /*!< list of locks on the same
table */
/** Print the table lock into the given output stream
@param[in,out] out the output stream
@return the given output stream. */
std::ostream& print(std::ostream& out) const;
};
/** Record lock for a page */
struct lock_rec_t {
ib_uint32_t space; /*!< space id */
ib_uint32_t page_no; /*!< page number */
ib_uint32_t n_bits; /*!< number of bits in the lock
bitmap; NOTE: the lock bitmap is
placed immediately after the
lock struct */
/** Print the record lock into the given output stream
@param[in,out] out the output stream
@return the given output stream. */
std::ostream& print(std::ostream& out) const;
};
/** Print the record lock into the given output stream
@param[in,out] out the output stream
@return the given output stream. */
inline
std::ostream& lock_rec_t::print(std::ostream& out) const
{
out << "[lock_rec_t: space=" << space << ", page_no=" << page_no
<< ", n_bits=" << n_bits << "]";
return(out);
}
inline
std::ostream&
operator<<(std::ostream& out, const lock_rec_t& lock)
{
return(lock.print(out));
}
#define LOCK_MODE_MASK 0xFUL /*!< mask used to extract mode from the
type_mode field in a lock */
/** Lock types */
/* @{ */
#define LOCK_TABLE 16U /*!< table lock */
#define LOCK_REC 32U /*!< record lock */
#define LOCK_TYPE_MASK 0xF0UL /*!< mask used to extract lock type from the
type_mode field in a lock */
#if LOCK_MODE_MASK & LOCK_TYPE_MASK
# error "LOCK_MODE_MASK & LOCK_TYPE_MASK"
#endif
#define LOCK_WAIT 256U /*!< Waiting lock flag; when set, it
means that the lock has not yet been
granted, it is just waiting for its
turn in the wait queue */
/* Precise modes */
#define LOCK_ORDINARY 0 /*!< this flag denotes an ordinary
next-key lock in contrast to LOCK_GAP
or LOCK_REC_NOT_GAP */
#define LOCK_GAP 512U /*!< when this bit is set, it means that the
lock holds only on the gap before the record;
for instance, an x-lock on the gap does not
give permission to modify the record on which
the bit is set; locks of this type are created
when records are removed from the index chain
of records */
#define LOCK_REC_NOT_GAP 1024U /*!< this bit means that the lock is only on
the index record and does NOT block inserts
to the gap before the index record; this is
used in the case when we retrieve a record
with a unique key, and is also used in
locking plain SELECTs (not part of UPDATE
or DELETE) when the user has set the READ
COMMITTED isolation level */
#define LOCK_INSERT_INTENTION 2048U/*!< this bit is set when we place a waiting
gap type record lock request in order to let
an insert of an index record to wait until
there are no conflicting locks by other
transactions on the gap; note that this flag
remains set when the waiting lock is granted,
or if the lock is inherited to a neighboring
record */
#define LOCK_PREDICATE 8192U /*!< Predicate lock */
#define LOCK_PRDT_PAGE 16384U /*!< Page lock */
#if (LOCK_WAIT|LOCK_GAP|LOCK_REC_NOT_GAP|LOCK_INSERT_INTENTION|LOCK_PREDICATE|LOCK_PRDT_PAGE)&LOCK_MODE_MASK
# error
#endif
#if (LOCK_WAIT|LOCK_GAP|LOCK_REC_NOT_GAP|LOCK_INSERT_INTENTION|LOCK_PREDICATE|LOCK_PRDT_PAGE)&LOCK_TYPE_MASK
# error
#endif
/* @} */
/** Lock struct; protected by lock_sys->mutex */
struct ib_lock_t
{
trx_t* trx; /*!< transaction owning the
lock */
UT_LIST_NODE_T(ib_lock_t)
trx_locks; /*!< list of the locks of the
transaction */
dict_index_t* index; /*!< index for a record lock */
ib_lock_t* hash; /*!< hash chain node for a record
lock. The link node in a singly linked
list, used during hashing. */
/* Statistics for how long lock has been held and time
how long this lock had to be waited before it was granted */
time_t requested_time; /*!< Lock request time */
ulint wait_time; /*!< Time waited this lock or 0 */
union {
lock_table_t tab_lock;/*!< table lock */
lock_rec_t rec_lock;/*!< record lock */
} un_member; /*!< lock details */
ib_uint32_t type_mode; /*!< lock type, mode, LOCK_GAP or
LOCK_REC_NOT_GAP,
LOCK_INSERT_INTENTION,
wait flag, ORed */
/** Determine if the lock object is a record lock.
@return true if record lock, false otherwise. */
bool is_record_lock() const
{
return(type() == LOCK_REC);
}
bool is_waiting() const
{
return(type_mode & LOCK_WAIT);
}
bool is_gap() const
{
return(type_mode & LOCK_GAP);
}
bool is_record_not_gap() const
{
return(type_mode & LOCK_REC_NOT_GAP);
}
bool is_insert_intention() const
{
return(type_mode & LOCK_INSERT_INTENTION);
}
ulint type() const {
return(type_mode & LOCK_TYPE_MASK);
}
enum lock_mode mode() const
{
return(static_cast<enum lock_mode>(type_mode & LOCK_MODE_MASK));
}
/** Print the lock object into the given output stream.
@param[in,out] out the output stream
@return the given output stream. */
std::ostream& print(std::ostream& out) const;
/** Convert the member 'type_mode' into a human readable string.
@return human readable string */
std::string type_mode_string() const;
const char* type_string() const
{
switch (type_mode & LOCK_TYPE_MASK) {
case LOCK_REC:
return("LOCK_REC");
case LOCK_TABLE:
return("LOCK_TABLE");
default:
ut_error;
}
}
};
typedef UT_LIST_BASE_NODE_T(ib_lock_t) trx_lock_list_t;
#endif /* lock0types_h */ #endif /* lock0types_h */
...@@ -704,13 +704,19 @@ struct trx_lock_t { ...@@ -704,13 +704,19 @@ struct trx_lock_t {
only be modified by the thread that is only be modified by the thread that is
serving the running transaction. */ serving the running transaction. */
lock_pool_t rec_pool; /*!< Pre-allocated record locks */ /** Pre-allocated record locks */
struct {
ib_lock_t lock; byte pad[256];
} rec_pool[8];
lock_pool_t table_pool; /*!< Pre-allocated table locks */ /** Pre-allocated table locks */
ib_lock_t table_pool[8];
ulint rec_cached; /*!< Next free rec lock in pool */ /** Next available rec_pool[] entry */
unsigned rec_cached;
ulint table_cached; /*!< Next free table lock in pool */ /** Next available table_pool[] entry */
unsigned table_cached;
mem_heap_t* lock_heap; /*!< memory heap for trx_locks; mem_heap_t* lock_heap; /*!< memory heap for trx_locks;
protected by lock_sys->mutex */ protected by lock_sys->mutex */
......
...@@ -59,18 +59,6 @@ ulong innodb_lock_schedule_algorithm; ...@@ -59,18 +59,6 @@ ulong innodb_lock_schedule_algorithm;
/** The value of innodb_deadlock_detect */ /** The value of innodb_deadlock_detect */
my_bool innobase_deadlock_detect; my_bool innobase_deadlock_detect;
/** Total number of cached record locks */
static const ulint REC_LOCK_CACHE = 8;
/** Maximum record lock size in bytes */
static const ulint REC_LOCK_SIZE = sizeof(ib_lock_t) + 256;
/** Total number of cached table locks */
static const ulint TABLE_LOCK_CACHE = 8;
/** Size in bytes, of the table lock instance */
static const ulint TABLE_LOCK_SIZE = sizeof(ib_lock_t);
/*********************************************************************//** /*********************************************************************//**
Checks if a waiting record lock request still has to wait in a queue. Checks if a waiting record lock request still has to wait in a queue.
@return lock that is causing the wait */ @return lock that is causing the wait */
...@@ -1469,13 +1457,13 @@ lock_rec_create_low( ...@@ -1469,13 +1457,13 @@ lock_rec_create_low(
} }
} }
if (trx->lock.rec_cached >= trx->lock.rec_pool.size() if (trx->lock.rec_cached >= UT_ARR_SIZE(trx->lock.rec_pool)
|| sizeof *lock + n_bytes > REC_LOCK_SIZE) { || sizeof *lock + n_bytes > sizeof *trx->lock.rec_pool) {
lock = static_cast<lock_t*>( lock = static_cast<lock_t*>(
mem_heap_alloc(trx->lock.lock_heap, mem_heap_alloc(trx->lock.lock_heap,
sizeof *lock + n_bytes)); sizeof *lock + n_bytes));
} else { } else {
lock = trx->lock.rec_pool[trx->lock.rec_cached++]; lock = &trx->lock.rec_pool[trx->lock.rec_cached++].lock;
} }
lock->trx = trx; lock->trx = trx;
...@@ -3653,8 +3641,9 @@ lock_table_create( ...@@ -3653,8 +3641,9 @@ lock_table_create(
ib_vector_push(trx->autoinc_locks, &lock); ib_vector_push(trx->autoinc_locks, &lock);
} else if (trx->lock.table_cached < trx->lock.table_pool.size()) { } else if (trx->lock.table_cached
lock = trx->lock.table_pool[trx->lock.table_cached++]; < UT_ARR_SIZE(trx->lock.table_pool)) {
lock = &trx->lock.table_pool[trx->lock.table_cached++];
} else { } else {
lock = static_cast<lock_t*>( lock = static_cast<lock_t*>(
...@@ -7678,33 +7667,6 @@ DeadlockChecker::check_and_resolve(const lock_t* lock, trx_t* trx) ...@@ -7678,33 +7667,6 @@ DeadlockChecker::check_and_resolve(const lock_t* lock, trx_t* trx)
return(victim_trx); return(victim_trx);
} }
/**
Allocate cached locks for the transaction.
@param trx allocate cached record locks for this transaction */
void
lock_trx_alloc_locks(trx_t* trx)
{
ulint sz = REC_LOCK_SIZE * REC_LOCK_CACHE;
byte* ptr = reinterpret_cast<byte*>(ut_malloc_nokey(sz));
/* We allocate one big chunk and then distribute it among
the rest of the elements. The allocated chunk pointer is always
at index 0. */
for (ulint i = 0; i < REC_LOCK_CACHE; ++i, ptr += REC_LOCK_SIZE) {
trx->lock.rec_pool.push_back(
reinterpret_cast<ib_lock_t*>(ptr));
}
sz = TABLE_LOCK_SIZE * TABLE_LOCK_CACHE;
ptr = reinterpret_cast<byte*>(ut_malloc_nokey(sz));
for (ulint i = 0; i < TABLE_LOCK_CACHE; ++i, ptr += TABLE_LOCK_SIZE) {
trx->lock.table_pool.push_back(
reinterpret_cast<ib_lock_t*>(ptr));
}
}
/*************************************************************//** /*************************************************************//**
Updates the lock table when a page is split and merged to Updates the lock table when a page is split and merged to
two pages. */ two pages. */
......
...@@ -190,10 +190,6 @@ struct TrxFactory { ...@@ -190,10 +190,6 @@ struct TrxFactory {
the constructors of the trx_t members. */ the constructors of the trx_t members. */
new(&trx->mod_tables) trx_mod_tables_t(); new(&trx->mod_tables) trx_mod_tables_t();
new(&trx->lock.rec_pool) lock_pool_t();
new(&trx->lock.table_pool) lock_pool_t();
new(&trx->lock.table_locks) lock_pool_t(); new(&trx->lock.table_locks) lock_pool_t();
trx_init(trx); trx_init(trx);
...@@ -216,8 +212,6 @@ struct TrxFactory { ...@@ -216,8 +212,6 @@ struct TrxFactory {
mutex_create(LATCH_ID_TRX, &trx->mutex); mutex_create(LATCH_ID_TRX, &trx->mutex);
mutex_create(LATCH_ID_TRX_UNDO, &trx->undo_mutex); mutex_create(LATCH_ID_TRX_UNDO, &trx->undo_mutex);
lock_trx_alloc_locks(trx);
} }
/** Release resources held by the transaction object. /** Release resources held by the transaction object.
...@@ -249,26 +243,6 @@ struct TrxFactory { ...@@ -249,26 +243,6 @@ struct TrxFactory {
ut_ad(trx->read_view == NULL); ut_ad(trx->read_view == NULL);
if (!trx->lock.rec_pool.empty()) {
/* See lock_trx_alloc_locks() why we only free
the first element. */
ut_free(trx->lock.rec_pool[0]);
}
if (!trx->lock.table_pool.empty()) {
/* See lock_trx_alloc_locks() why we only free
the first element. */
ut_free(trx->lock.table_pool[0]);
}
trx->lock.rec_pool.~lock_pool_t();
trx->lock.table_pool.~lock_pool_t();
trx->lock.table_locks.~lock_pool_t(); trx->lock.table_locks.~lock_pool_t();
} }
...@@ -407,7 +381,12 @@ trx_create_low() ...@@ -407,7 +381,12 @@ trx_create_low()
/* Should have been either just initialized or .clear()ed by /* Should have been either just initialized or .clear()ed by
trx_free(). */ trx_free(). */
ut_a(trx->mod_tables.size() == 0); ut_ad(trx->mod_tables.empty());
ut_ad(trx->lock.table_locks.empty());
ut_ad(UT_LIST_GET_LEN(trx->lock.trx_locks) == 0);
ut_ad(trx->lock.n_rec_locks == 0);
ut_ad(trx->lock.table_cached == 0);
ut_ad(trx->lock.rec_cached == 0);
#ifdef WITH_WSREP #ifdef WITH_WSREP
trx->wsrep_event = NULL; trx->wsrep_event = NULL;
......
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