summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2018-08-13 11:46:22 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2018-08-16 05:53:38 +0300
commit3ce8a0fc494ef8d1561cde4bf3a467d465e0c70e (patch)
treefcd4decac0246dc4b98cd098e4538881d63deb8e
parentb795134802c486311e1987f18a95fb17c12935e3 (diff)
downloadmariadb-git-3ce8a0fc494ef8d1561cde4bf3a467d465e0c70e.tar.gz
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.
-rw-r--r--storage/innobase/include/lock0lock.h63
-rw-r--r--storage/innobase/include/lock0priv.h139
-rw-r--r--storage/innobase/include/lock0types.h192
-rw-r--r--storage/innobase/include/trx0trx.h14
-rw-r--r--storage/innobase/lock/lock0lock.cc50
-rw-r--r--storage/innobase/trx/trx0trx.cc33
6 files changed, 216 insertions, 275 deletions
diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h
index c9500f7fd49..f7d507813e3 100644
--- a/storage/innobase/include/lock0lock.h
+++ b/storage/innobase/include/lock0lock.h
@@ -834,69 +834,6 @@ lock_trx_has_rec_x_lock(
MY_ATTRIBUTE((warn_unused_result));
#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 */
struct lock_op_t{
dict_table_t* table; /*!< table to be locked */
diff --git a/storage/innobase/include/lock0priv.h b/storage/innobase/include/lock0priv.h
index 1c297a5b945..d9377e97d40 100644
--- a/storage/innobase/include/lock0priv.h
+++ b/storage/innobase/include/lock0priv.h
@@ -42,19 +42,6 @@ those functions in lock/ */
#define UINT32_MAX (4294967295U)
#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
@param[in,out] out the output stream
@return the given output stream. */
@@ -77,131 +64,11 @@ operator<<(std::ostream& out, const lock_table_t& lock)
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.
@return human readable string */
inline
std::string
-lock_t::type_mode_string() const
+ib_lock_t::type_mode_string() const
{
std::ostringstream sout;
sout << type_string();
@@ -227,7 +94,7 @@ lock_t::type_mode_string() const
inline
std::ostream&
-lock_t::print(std::ostream& out) const
+ib_lock_t::print(std::ostream& out) const
{
out << "[lock_t: type_mode=" << type_mode << "("
<< type_mode_string() << ")";
@@ -244,7 +111,7 @@ lock_t::print(std::ostream& out) const
inline
std::ostream&
-operator<<(std::ostream& out, const lock_t& lock)
+operator<<(std::ostream& out, const ib_lock_t& lock)
{
return(lock.print(out));
}
diff --git a/storage/innobase/include/lock0types.h b/storage/innobase/include/lock0types.h
index d08eaabfb1e..1a03d1d0297 100644
--- a/storage/innobase/include/lock0types.h
+++ b/storage/innobase/include/lock0types.h
@@ -1,6 +1,7 @@
/*****************************************************************************
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
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)
}
}
-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 */
diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h
index 6ed69e6c5c4..adfe4f41955 100644
--- a/storage/innobase/include/trx0trx.h
+++ b/storage/innobase/include/trx0trx.h
@@ -704,13 +704,19 @@ struct trx_lock_t {
only be modified by the thread that is
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;
protected by lock_sys->mutex */
diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc
index 61f62d1e054..18e4c164860 100644
--- a/storage/innobase/lock/lock0lock.cc
+++ b/storage/innobase/lock/lock0lock.cc
@@ -59,18 +59,6 @@ ulong innodb_lock_schedule_algorithm;
/** The value of innodb_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.
@return lock that is causing the wait */
@@ -1469,13 +1457,13 @@ lock_rec_create_low(
}
}
- if (trx->lock.rec_cached >= trx->lock.rec_pool.size()
- || sizeof *lock + n_bytes > REC_LOCK_SIZE) {
+ if (trx->lock.rec_cached >= UT_ARR_SIZE(trx->lock.rec_pool)
+ || sizeof *lock + n_bytes > sizeof *trx->lock.rec_pool) {
lock = static_cast<lock_t*>(
mem_heap_alloc(trx->lock.lock_heap,
sizeof *lock + n_bytes));
} else {
- lock = trx->lock.rec_pool[trx->lock.rec_cached++];
+ lock = &trx->lock.rec_pool[trx->lock.rec_cached++].lock;
}
lock->trx = trx;
@@ -3653,8 +3641,9 @@ lock_table_create(
ib_vector_push(trx->autoinc_locks, &lock);
- } else if (trx->lock.table_cached < trx->lock.table_pool.size()) {
- lock = trx->lock.table_pool[trx->lock.table_cached++];
+ } else if (trx->lock.table_cached
+ < UT_ARR_SIZE(trx->lock.table_pool)) {
+ lock = &trx->lock.table_pool[trx->lock.table_cached++];
} else {
lock = static_cast<lock_t*>(
@@ -7678,33 +7667,6 @@ DeadlockChecker::check_and_resolve(const lock_t* lock, trx_t* 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
two pages. */
diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc
index 7ebf41b3143..ae2611020de 100644
--- a/storage/innobase/trx/trx0trx.cc
+++ b/storage/innobase/trx/trx0trx.cc
@@ -190,10 +190,6 @@ struct TrxFactory {
the constructors of the trx_t members. */
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();
trx_init(trx);
@@ -216,8 +212,6 @@ struct TrxFactory {
mutex_create(LATCH_ID_TRX, &trx->mutex);
mutex_create(LATCH_ID_TRX_UNDO, &trx->undo_mutex);
-
- lock_trx_alloc_locks(trx);
}
/** Release resources held by the transaction object.
@@ -249,26 +243,6 @@ struct TrxFactory {
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();
}
@@ -407,7 +381,12 @@ trx_create_low()
/* Should have been either just initialized or .clear()ed by
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
trx->wsrep_event = NULL;