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