/***************************************************************************** Copyright (c) 2007, 2014, Oracle and/or its affiliates. All Rights Reserved. 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 Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA *****************************************************************************/ /**************************************************//** @file include/lock0priv.ic Lock module internal inline methods. Created July 16, 2007 Vasil Dimov *******************************************************/ /* This file contains only methods which are used in lock/lock0* files, other than lock/lock0lock.cc. I.e. lock/lock0lock.cc contains more internal inline methods but they are used only in that file. */ #ifndef LOCK_MODULE_IMPLEMENTATION #error Do not include lock0priv.ic outside of the lock/ module #endif /*********************************************************************//** Gets the type of a lock. @return LOCK_TABLE or LOCK_REC */ UNIV_INLINE ulint lock_get_type_low( /*==============*/ const lock_t* lock) /*!< in: lock */ { ut_ad(lock); return(lock->type_mode & LOCK_TYPE_MASK); } /*********************************************************************//** Checks if some transaction has an implicit x-lock on a record in a clustered index. @return transaction id of the transaction which has the x-lock, or 0 */ UNIV_INLINE trx_id_t lock_clust_rec_some_has_impl( /*=========================*/ const rec_t* rec, /*!< in: user record */ const dict_index_t* index, /*!< in: clustered index */ const ulint* offsets)/*!< in: rec_get_offsets(rec, index) */ { ut_ad(dict_index_is_clust(index)); ut_ad(page_rec_is_user_rec(rec)); return(row_get_rec_trx_id(rec, index, offsets)); } /*********************************************************************//** Gets the number of bits in a record lock bitmap. @return number of bits */ UNIV_INLINE ulint lock_rec_get_n_bits( /*================*/ const lock_t* lock) /*!< in: record lock */ { return(lock->un_member.rec_lock.n_bits); } /**********************************************************************//** Sets the nth bit of a record lock to TRUE. */ UNIV_INLINE void lock_rec_set_nth_bit( /*=================*/ lock_t* lock, /*!< in: record lock */ ulint i) /*!< in: index of the bit */ { ulint byte_index; ulint bit_index; ut_ad(lock); ut_ad(lock_get_type_low(lock) == LOCK_REC); ut_ad(i < lock->un_member.rec_lock.n_bits); byte_index = i / 8; bit_index = i % 8; ((byte*) &lock[1])[byte_index] |= 1 << bit_index; ++lock->trx->lock.n_rec_locks; } /*********************************************************************//** Gets the first or next record lock on a page. @return next lock, NULL if none exists */ UNIV_INLINE lock_t* lock_rec_get_next_on_page( /*======================*/ lock_t* lock) /*!< in: a record lock */ { return((lock_t*) lock_rec_get_next_on_page_const(lock)); } /*********************************************************************//** Gets the first record lock on a page, where the page is identified by its file address. @return first lock, NULL if none exists */ UNIV_INLINE lock_t* lock_rec_get_first_on_page_addr( /*============================*/ hash_table_t* lock_hash, /* Lock hash table */ ulint space, /*!< in: space */ ulint page_no) /*!< in: page number */ { ut_ad(lock_mutex_own()); for (lock_t* lock = static_cast( HASH_GET_FIRST(lock_hash, lock_rec_hash(space, page_no))); lock != NULL; lock = static_cast(HASH_GET_NEXT(hash, lock))) { if (lock->un_member.rec_lock.space == space && lock->un_member.rec_lock.page_no == page_no) { return(lock); } } return(NULL); } /*********************************************************************//** Gets the first record lock on a page, where the page is identified by a pointer to it. @return first lock, NULL if none exists */ UNIV_INLINE lock_t* lock_rec_get_first_on_page( /*=======================*/ hash_table_t* lock_hash, /*!< in: lock hash table */ const buf_block_t* block) /*!< in: buffer block */ { ut_ad(lock_mutex_own()); ulint space = block->page.id.space(); ulint page_no = block->page.id.page_no(); ulint hash = buf_block_get_lock_hash_val(block); for (lock_t* lock = static_cast( HASH_GET_FIRST(lock_hash, hash)); lock != NULL; lock = static_cast(HASH_GET_NEXT(hash, lock))) { if (lock->un_member.rec_lock.space == space && lock->un_member.rec_lock.page_no == page_no) { return(lock); } } return(NULL); } /*********************************************************************//** Gets the next explicit lock request on a record. @return next lock, NULL if none exists or if heap_no == ULINT_UNDEFINED */ UNIV_INLINE lock_t* lock_rec_get_next( /*==============*/ ulint heap_no,/*!< in: heap number of the record */ lock_t* lock) /*!< in: lock */ { ut_ad(lock_mutex_own()); do { ut_ad(lock_get_type_low(lock) == LOCK_REC); lock = lock_rec_get_next_on_page(lock); } while (lock && !lock_rec_get_nth_bit(lock, heap_no)); return(lock); } /*********************************************************************//** Gets the next explicit lock request on a record. @return next lock, NULL if none exists or if heap_no == ULINT_UNDEFINED */ UNIV_INLINE const lock_t* lock_rec_get_next_const( /*====================*/ ulint heap_no,/*!< in: heap number of the record */ const lock_t* lock) /*!< in: lock */ { return(lock_rec_get_next(heap_no, (lock_t*) lock)); } /*********************************************************************//** Gets the first explicit lock request on a record. @return first lock, NULL if none exists */ UNIV_INLINE lock_t* lock_rec_get_first( /*===============*/ hash_table_t* hash, /*!< in: hash chain the lock on */ const buf_block_t* block, /*!< in: block containing the record */ ulint heap_no)/*!< in: heap number of the record */ { ut_ad(lock_mutex_own()); for (lock_t* lock = lock_rec_get_first_on_page(hash, block); lock; lock = lock_rec_get_next_on_page(lock)) { if (lock_rec_get_nth_bit(lock, heap_no)) { return(lock); } } return(NULL); } /*********************************************************************//** Gets the nth bit of a record lock. @return TRUE if bit set also if i == ULINT_UNDEFINED return FALSE*/ UNIV_INLINE ibool lock_rec_get_nth_bit( /*=================*/ const lock_t* lock, /*!< in: record lock */ ulint i) /*!< in: index of the bit */ { const byte* b; ut_ad(lock); ut_ad(lock_get_type_low(lock) == LOCK_REC); if (i >= lock->un_member.rec_lock.n_bits) { return(FALSE); } b = ((const byte*) &lock[1]) + (i / 8); return(1 & *b >> (i % 8)); } /*********************************************************************//** Gets the first or next record lock on a page. @return next lock, NULL if none exists */ UNIV_INLINE const lock_t* lock_rec_get_next_on_page_const( /*============================*/ const lock_t* lock) /*!< in: a record lock */ { ut_ad(lock_mutex_own()); ut_ad(lock_get_type_low(lock) == LOCK_REC); ulint space = lock->un_member.rec_lock.space; ulint page_no = lock->un_member.rec_lock.page_no; while ((lock = static_cast(HASH_GET_NEXT(hash, lock))) != NULL) { if (lock->un_member.rec_lock.space == space && lock->un_member.rec_lock.page_no == page_no) { return(lock); } } return(NULL); } /*********************************************************************//** Gets the mode of a lock. @return mode */ UNIV_INLINE enum lock_mode lock_get_mode( /*==========*/ const lock_t* lock) /*!< in: lock */ { ut_ad(lock); return(static_cast(lock->type_mode & LOCK_MODE_MASK)); } /*********************************************************************//** Calculates if lock mode 1 is compatible with lock mode 2. @return nonzero if mode1 compatible with mode2 */ UNIV_INLINE ulint lock_mode_compatible( /*=================*/ enum lock_mode mode1, /*!< in: lock mode */ enum lock_mode mode2) /*!< in: lock mode */ { ut_ad((ulint) mode1 < lock_types); ut_ad((ulint) mode2 < lock_types); return(lock_compatibility_matrix[mode1][mode2]); } /*********************************************************************//** Calculates if lock mode 1 is stronger or equal to lock mode 2. @return nonzero if mode1 stronger or equal to mode2 */ UNIV_INLINE ulint lock_mode_stronger_or_eq( /*=====================*/ enum lock_mode mode1, /*!< in: lock mode */ enum lock_mode mode2) /*!< in: lock mode */ { ut_ad((ulint) mode1 < lock_types); ut_ad((ulint) mode2 < lock_types); return(lock_strength_matrix[mode1][mode2]); } /*********************************************************************//** Gets the wait flag of a lock. @return LOCK_WAIT if waiting, 0 if not */ UNIV_INLINE ulint lock_get_wait( /*==========*/ const lock_t* lock) /*!< in: lock */ { ut_ad(lock); return(lock->type_mode & LOCK_WAIT); } /*********************************************************************//** Looks for a suitable type record lock struct by the same trx on the same page. This can be used to save space when a new record lock should be set on a page: no new struct is needed, if a suitable old is found. @return lock or NULL */ UNIV_INLINE lock_t* lock_rec_find_similar_on_page( /*==========================*/ ulint type_mode, /*!< in: lock type_mode field */ ulint heap_no, /*!< in: heap number of the record */ lock_t* lock, /*!< in: lock_rec_get_first_on_page() */ const trx_t* trx) /*!< in: transaction */ { ut_ad(lock_mutex_own()); for (/* No op */; lock != NULL; lock = lock_rec_get_next_on_page(lock)) { if (lock->trx == trx && lock->type_mode == type_mode && lock_rec_get_n_bits(lock) > heap_no) { return(lock); } } return(NULL); } /*********************************************************************//** Checks if a transaction has the specified table lock, or stronger. This function should only be called by the thread that owns the transaction. @return lock or NULL */ UNIV_INLINE const lock_t* lock_table_has( /*===========*/ const trx_t* trx, /*!< in: transaction */ const dict_table_t* table, /*!< in: table */ lock_mode in_mode)/*!< in: lock mode */ { if (trx->lock.table_locks.empty()) { return(NULL); } typedef lock_pool_t::const_reverse_iterator iterator; iterator end = trx->lock.table_locks.rend(); /* Look for stronger locks the same trx already has on the table */ for (iterator it = trx->lock.table_locks.rbegin(); it != end; ++it) { const lock_t* lock = *it; if (lock == NULL) { continue; } lock_mode mode = lock_get_mode(lock); ut_ad(trx == lock->trx); ut_ad(lock_get_type_low(lock) & LOCK_TABLE); ut_ad(lock->un_member.tab_lock.table != NULL); if (table == lock->un_member.tab_lock.table && lock_mode_stronger_or_eq(mode, in_mode)) { ut_ad(!lock_get_wait(lock)); return(lock); } } return(NULL); } /* vim: set filetype=c: */