1/***************************************************************************** 2 3Copyright (c) 2007, 2014, Oracle and/or its affiliates. All Rights Reserved. 4Copyright (c) 2018, MariaDB Corporation. 5 6This program is free software; you can redistribute it and/or modify it under 7the terms of the GNU General Public License as published by the Free Software 8Foundation; version 2 of the License. 9 10This program is distributed in the hope that it will be useful, but WITHOUT 11ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 13 14You should have received a copy of the GNU General Public License along with 15this program; if not, write to the Free Software Foundation, Inc., 1651 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA 17 18*****************************************************************************/ 19 20/**************************************************//** 21@file include/lock0priv.ic 22Lock module internal inline methods. 23 24Created July 16, 2007 Vasil Dimov 25*******************************************************/ 26 27/* This file contains only methods which are used in 28lock/lock0* files, other than lock/lock0lock.cc. 29I.e. lock/lock0lock.cc contains more internal inline 30methods but they are used only in that file. */ 31 32#ifndef LOCK_MODULE_IMPLEMENTATION 33#error Do not include lock0priv.ic outside of the lock/ module 34#endif 35 36#include "row0row.h" 37 38/*********************************************************************//** 39Gets the type of a lock. 40@return LOCK_TABLE or LOCK_REC */ 41UNIV_INLINE 42ulint 43lock_get_type_low( 44/*==============*/ 45 const lock_t* lock) /*!< in: lock */ 46{ 47 ut_ad(lock); 48 49 return(lock->type_mode & LOCK_TYPE_MASK); 50} 51 52/*********************************************************************//** 53Checks if some transaction has an implicit x-lock on a record in a clustered 54index. 55@return transaction id of the transaction which has the x-lock, or 0 */ 56UNIV_INLINE 57trx_id_t 58lock_clust_rec_some_has_impl( 59/*=========================*/ 60 const rec_t* rec, /*!< in: user record */ 61 const dict_index_t* index, /*!< in: clustered index */ 62 const rec_offs* offsets)/*!< in: rec_get_offsets(rec, index) */ 63{ 64 ut_ad(dict_index_is_clust(index)); 65 ut_ad(page_rec_is_user_rec(rec)); 66 67 return(row_get_rec_trx_id(rec, index, offsets)); 68} 69 70/*********************************************************************//** 71Gets the number of bits in a record lock bitmap. 72@return number of bits */ 73UNIV_INLINE 74ulint 75lock_rec_get_n_bits( 76/*================*/ 77 const lock_t* lock) /*!< in: record lock */ 78{ 79 return(lock->un_member.rec_lock.n_bits); 80} 81 82/**********************************************************************//** 83Sets the nth bit of a record lock to TRUE. */ 84UNIV_INLINE 85void 86lock_rec_set_nth_bit( 87/*=================*/ 88 lock_t* lock, /*!< in: record lock */ 89 ulint i) /*!< in: index of the bit */ 90{ 91 ulint byte_index; 92 ulint bit_index; 93 94 ut_ad(lock); 95 ut_ad(lock_get_type_low(lock) == LOCK_REC); 96 ut_ad(i < lock->un_member.rec_lock.n_bits); 97 98 byte_index = i / 8; 99 bit_index = i % 8; 100 101 ((byte*) &lock[1])[byte_index] |= 1 << bit_index; 102 103 ++lock->trx->lock.n_rec_locks; 104} 105 106/*********************************************************************//** 107Gets the first or next record lock on a page. 108@return next lock, NULL if none exists */ 109UNIV_INLINE 110lock_t* 111lock_rec_get_next_on_page( 112/*======================*/ 113 lock_t* lock) /*!< in: a record lock */ 114{ 115 return((lock_t*) lock_rec_get_next_on_page_const(lock)); 116} 117 118/*********************************************************************//** 119Gets the first record lock on a page, where the page is identified by its 120file address. 121@return first lock, NULL if none exists */ 122UNIV_INLINE 123lock_t* 124lock_rec_get_first_on_page_addr( 125/*============================*/ 126 hash_table_t* lock_hash, /* Lock hash table */ 127 ulint space, /*!< in: space */ 128 ulint page_no) /*!< in: page number */ 129{ 130 ut_ad(lock_mutex_own()); 131 132 for (lock_t* lock = static_cast<lock_t*>( 133 HASH_GET_FIRST(lock_hash, 134 lock_rec_hash(space, page_no))); 135 lock != NULL; 136 lock = static_cast<lock_t*>(HASH_GET_NEXT(hash, lock))) { 137 138 if (lock->un_member.rec_lock.space == space 139 && lock->un_member.rec_lock.page_no == page_no) { 140 141 return(lock); 142 } 143 } 144 145 return(NULL); 146} 147 148/*********************************************************************//** 149Gets the first record lock on a page, where the page is identified by a 150pointer to it. 151@return first lock, NULL if none exists */ 152UNIV_INLINE 153lock_t* 154lock_rec_get_first_on_page( 155/*=======================*/ 156 hash_table_t* lock_hash, /*!< in: lock hash table */ 157 const buf_block_t* block) /*!< in: buffer block */ 158{ 159 ut_ad(lock_mutex_own()); 160 161 ulint space = block->page.id.space(); 162 ulint page_no = block->page.id.page_no(); 163 ulint hash = buf_block_get_lock_hash_val(block); 164 165 for (lock_t* lock = static_cast<lock_t*>( 166 HASH_GET_FIRST(lock_hash, hash)); 167 lock != NULL; 168 lock = static_cast<lock_t*>(HASH_GET_NEXT(hash, lock))) { 169 170 if (lock->un_member.rec_lock.space == space 171 && lock->un_member.rec_lock.page_no == page_no) { 172 173 return(lock); 174 } 175 } 176 177 return(NULL); 178} 179 180/*********************************************************************//** 181Gets the next explicit lock request on a record. 182@return next lock, NULL if none exists or if heap_no == ULINT_UNDEFINED */ 183UNIV_INLINE 184lock_t* 185lock_rec_get_next( 186/*==============*/ 187 ulint heap_no,/*!< in: heap number of the record */ 188 lock_t* lock) /*!< in: lock */ 189{ 190 ut_ad(lock_mutex_own()); 191 192 do { 193 ut_ad(lock_get_type_low(lock) == LOCK_REC); 194 lock = lock_rec_get_next_on_page(lock); 195 } while (lock && !lock_rec_get_nth_bit(lock, heap_no)); 196 197 return(lock); 198} 199 200/*********************************************************************//** 201Gets the next explicit lock request on a record. 202@return next lock, NULL if none exists or if heap_no == ULINT_UNDEFINED */ 203UNIV_INLINE 204const lock_t* 205lock_rec_get_next_const( 206/*====================*/ 207 ulint heap_no,/*!< in: heap number of the record */ 208 const lock_t* lock) /*!< in: lock */ 209{ 210 return(lock_rec_get_next(heap_no, (lock_t*) lock)); 211} 212 213/*********************************************************************//** 214Gets the first explicit lock request on a record. 215@return first lock, NULL if none exists */ 216UNIV_INLINE 217lock_t* 218lock_rec_get_first( 219/*===============*/ 220 hash_table_t* hash, /*!< in: hash chain the lock on */ 221 const buf_block_t* block, /*!< in: block containing the record */ 222 ulint heap_no)/*!< in: heap number of the record */ 223{ 224 ut_ad(lock_mutex_own()); 225 226 for (lock_t* lock = lock_rec_get_first_on_page(hash, block); lock; 227 lock = lock_rec_get_next_on_page(lock)) { 228 if (lock_rec_get_nth_bit(lock, heap_no)) { 229 return(lock); 230 } 231 } 232 233 return(NULL); 234} 235 236/*********************************************************************//** 237Gets the nth bit of a record lock. 238@return TRUE if bit set also if i == ULINT_UNDEFINED return FALSE*/ 239UNIV_INLINE 240ibool 241lock_rec_get_nth_bit( 242/*=================*/ 243 const lock_t* lock, /*!< in: record lock */ 244 ulint i) /*!< in: index of the bit */ 245{ 246 const byte* b; 247 248 ut_ad(lock); 249 ut_ad(lock_get_type_low(lock) == LOCK_REC); 250 251 if (i >= lock->un_member.rec_lock.n_bits) { 252 253 return(FALSE); 254 } 255 256 b = ((const byte*) &lock[1]) + (i / 8); 257 258 return(1 & *b >> (i % 8)); 259} 260 261/*********************************************************************//** 262Gets the first or next record lock on a page. 263@return next lock, NULL if none exists */ 264UNIV_INLINE 265const lock_t* 266lock_rec_get_next_on_page_const( 267/*============================*/ 268 const lock_t* lock) /*!< in: a record lock */ 269{ 270 ut_ad(lock_mutex_own()); 271 ut_ad(lock_get_type_low(lock) == LOCK_REC); 272 273 ulint space = lock->un_member.rec_lock.space; 274 ulint page_no = lock->un_member.rec_lock.page_no; 275 276 while ((lock = static_cast<const lock_t*>(HASH_GET_NEXT(hash, lock))) 277 != NULL) { 278 279 if (lock->un_member.rec_lock.space == space 280 && lock->un_member.rec_lock.page_no == page_no) { 281 282 return(lock); 283 } 284 } 285 286 return(NULL); 287} 288 289/*********************************************************************//** 290Gets the mode of a lock. 291@return mode */ 292UNIV_INLINE 293enum lock_mode 294lock_get_mode( 295/*==========*/ 296 const lock_t* lock) /*!< in: lock */ 297{ 298 ut_ad(lock); 299 300 return(static_cast<enum lock_mode>(lock->type_mode & LOCK_MODE_MASK)); 301} 302 303/*********************************************************************//** 304Calculates if lock mode 1 is compatible with lock mode 2. 305@return nonzero if mode1 compatible with mode2 */ 306UNIV_INLINE 307ulint 308lock_mode_compatible( 309/*=================*/ 310 enum lock_mode mode1, /*!< in: lock mode */ 311 enum lock_mode mode2) /*!< in: lock mode */ 312{ 313 ut_ad((ulint) mode1 < lock_types); 314 ut_ad((ulint) mode2 < lock_types); 315 316 return(lock_compatibility_matrix[mode1][mode2]); 317} 318 319/*********************************************************************//** 320Calculates if lock mode 1 is stronger or equal to lock mode 2. 321@return nonzero if mode1 stronger or equal to mode2 */ 322UNIV_INLINE 323ulint 324lock_mode_stronger_or_eq( 325/*=====================*/ 326 enum lock_mode mode1, /*!< in: lock mode */ 327 enum lock_mode mode2) /*!< in: lock mode */ 328{ 329 ut_ad((ulint) mode1 < lock_types); 330 ut_ad((ulint) mode2 < lock_types); 331 332 return(lock_strength_matrix[mode1][mode2]); 333} 334 335/*********************************************************************//** 336Gets the wait flag of a lock. 337@return LOCK_WAIT if waiting, 0 if not */ 338UNIV_INLINE 339ulint 340lock_get_wait( 341/*==========*/ 342 const lock_t* lock) /*!< in: lock */ 343{ 344 ut_ad(lock); 345 346 return(lock->type_mode & LOCK_WAIT); 347} 348 349/*********************************************************************//** 350Looks for a suitable type record lock struct by the same trx on the same page. 351This can be used to save space when a new record lock should be set on a page: 352no new struct is needed, if a suitable old is found. 353@return lock or NULL */ 354UNIV_INLINE 355lock_t* 356lock_rec_find_similar_on_page( 357/*==========================*/ 358 ulint type_mode, /*!< in: lock type_mode field */ 359 ulint heap_no, /*!< in: heap number of the record */ 360 lock_t* lock, /*!< in: lock_rec_get_first_on_page() */ 361 const trx_t* trx) /*!< in: transaction */ 362{ 363 ut_ad(lock_mutex_own()); 364 365 for (/* No op */; 366 lock != NULL; 367 lock = lock_rec_get_next_on_page(lock)) { 368 369 if (lock->trx == trx 370 && lock->type_mode == type_mode 371 && lock_rec_get_n_bits(lock) > heap_no) { 372 373 return(lock); 374 } 375 } 376 377 return(NULL); 378} 379 380/*********************************************************************//** 381Checks if a transaction has the specified table lock, or stronger. This 382function should only be called by the thread that owns the transaction. 383@return lock or NULL */ 384UNIV_INLINE 385const lock_t* 386lock_table_has( 387/*===========*/ 388 const trx_t* trx, /*!< in: transaction */ 389 const dict_table_t* table, /*!< in: table */ 390 lock_mode in_mode)/*!< in: lock mode */ 391{ 392 /* Look for stronger locks the same trx already has on the table */ 393 394 for (lock_list::const_iterator it = trx->lock.table_locks.begin(), 395 end = trx->lock.table_locks.end(); it != end; ++it) { 396 397 const lock_t* lock = *it; 398 399 if (lock == NULL) { 400 continue; 401 } 402 403 lock_mode mode = lock_get_mode(lock); 404 405 ut_ad(trx == lock->trx); 406 ut_ad(lock_get_type_low(lock) & LOCK_TABLE); 407 ut_ad(lock->un_member.tab_lock.table != NULL); 408 409 if (table == lock->un_member.tab_lock.table 410 && lock_mode_stronger_or_eq(mode, in_mode)) { 411 412 ut_ad(!lock_get_wait(lock)); 413 414 return(lock); 415 } 416 } 417 418 return(NULL); 419} 420 421/* vim: set filetype=c: */ 422