diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2018-08-13 11:46:22 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2018-08-16 05:53:38 +0300 |
commit | 3ce8a0fc494ef8d1561cde4bf3a467d465e0c70e (patch) | |
tree | fcd4decac0246dc4b98cd098e4538881d63deb8e | |
parent | b795134802c486311e1987f18a95fb17c12935e3 (diff) | |
download | mariadb-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.h | 63 | ||||
-rw-r--r-- | storage/innobase/include/lock0priv.h | 139 | ||||
-rw-r--r-- | storage/innobase/include/lock0types.h | 192 | ||||
-rw-r--r-- | storage/innobase/include/trx0trx.h | 14 | ||||
-rw-r--r-- | storage/innobase/lock/lock0lock.cc | 50 | ||||
-rw-r--r-- | storage/innobase/trx/trx0trx.cc | 33 |
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; |