1/*****************************************************************************
2
3Copyright (c) 2007, 2016, Oracle and/or its affiliates. All Rights Reserved.
4Copyright (c) 2015, 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, Suite 500, Boston, MA 02110-1335 USA
17
18*****************************************************************************/
19
20/**************************************************//**
21@file include/lock0priv.h
22Lock module internal structures and methods.
23
24Created July 12, 2007 Vasil Dimov
25*******************************************************/
26
27#ifndef lock0priv_h
28#define lock0priv_h
29
30#ifndef LOCK_MODULE_IMPLEMENTATION
31/* If you need to access members of the structures defined in this
32file, please write appropriate functions that retrieve them and put
33those functions in lock/ */
34#error Do not include lock0priv.h outside of the lock/ module
35#endif
36
37#include "univ.i"
38#include "hash0hash.h"
39#include "trx0trx.h"
40
41#ifndef UINT32_MAX
42#define UINT32_MAX (4294967295U)
43#endif
44
45/** A table lock */
46struct lock_table_t {
47 dict_table_t* table; /*!< database table in dictionary
48 cache */
49 UT_LIST_NODE_T(lock_t)
50 locks; /*!< list of locks on the same
51 table */
52 /** Print the table lock into the given output stream
53 @param[in,out] out the output stream
54 @return the given output stream. */
55 std::ostream& print(std::ostream& out) const;
56};
57
58/** Print the table lock into the given output stream
59@param[in,out] out the output stream
60@return the given output stream. */
61inline
62std::ostream& lock_table_t::print(std::ostream& out) const
63{
64 out << "[lock_table_t: name=" << table->name << "]";
65 return(out);
66}
67
68/** The global output operator is overloaded to conveniently
69print the lock_table_t object into the given output stream.
70@param[in,out] out the output stream
71@param[in] lock the table lock
72@return the given output stream */
73inline
74std::ostream&
75operator<<(std::ostream& out, const lock_table_t& lock)
76{
77 return(lock.print(out));
78}
79
80/** Record lock for a page */
81struct lock_rec_t {
82 ib_uint32_t space; /*!< space id */
83 ib_uint32_t page_no; /*!< page number */
84 ib_uint32_t n_bits; /*!< number of bits in the lock
85 bitmap; NOTE: the lock bitmap is
86 placed immediately after the
87 lock struct */
88
89 /** Print the record lock into the given output stream
90 @param[in,out] out the output stream
91 @return the given output stream. */
92 std::ostream& print(std::ostream& out) const;
93};
94
95/** Print the record lock into the given output stream
96@param[in,out] out the output stream
97@return the given output stream. */
98inline
99std::ostream& lock_rec_t::print(std::ostream& out) const
100{
101 out << "[lock_rec_t: space=" << space << ", page_no=" << page_no
102 << ", n_bits=" << n_bits << "]";
103 return(out);
104}
105
106inline
107std::ostream&
108operator<<(std::ostream& out, const lock_rec_t& lock)
109{
110 return(lock.print(out));
111}
112
113/** Lock struct; protected by lock_sys.mutex */
114struct lock_t {
115 trx_t* trx; /*!< transaction owning the
116 lock */
117 UT_LIST_NODE_T(lock_t)
118 trx_locks; /*!< list of the locks of the
119 transaction */
120
121 dict_index_t* index; /*!< index for a record lock */
122
123 lock_t* hash; /*!< hash chain node for a record
124 lock. The link node in a singly linked
125 list, used during hashing. */
126
127 /* Statistics for how long lock has been held and time
128 how long this lock had to be waited before it was granted */
129 time_t requested_time; /*!< Lock request time */
130 ulint wait_time; /*!< Time waited this lock or 0 */
131
132 union {
133 lock_table_t tab_lock;/*!< table lock */
134 lock_rec_t rec_lock;/*!< record lock */
135 } un_member; /*!< lock details */
136
137 ib_uint32_t type_mode; /*!< lock type, mode, LOCK_GAP or
138 LOCK_REC_NOT_GAP,
139 LOCK_INSERT_INTENTION,
140 wait flag, ORed */
141
142 /** Determine if the lock object is a record lock.
143 @return true if record lock, false otherwise. */
144 bool is_record_lock() const
145 {
146 return(type() == LOCK_REC);
147 }
148
149 bool is_waiting() const
150 {
151 return(type_mode & LOCK_WAIT);
152 }
153
154 bool is_gap() const
155 {
156 return(type_mode & LOCK_GAP);
157 }
158
159 bool is_record_not_gap() const
160 {
161 return(type_mode & LOCK_REC_NOT_GAP);
162 }
163
164 bool is_insert_intention() const
165 {
166 return(type_mode & LOCK_INSERT_INTENTION);
167 }
168
169 ulint type() const {
170 return(type_mode & LOCK_TYPE_MASK);
171 }
172
173 enum lock_mode mode() const
174 {
175 return(static_cast<enum lock_mode>(type_mode & LOCK_MODE_MASK));
176 }
177
178 /** Print the lock object into the given output stream.
179 @param[in,out] out the output stream
180 @return the given output stream. */
181 std::ostream& print(std::ostream& out) const;
182
183 /** Convert the member 'type_mode' into a human readable string.
184 @return human readable string */
185 std::string type_mode_string() const;
186
187 const char* type_string() const
188 {
189 switch (type_mode & LOCK_TYPE_MASK) {
190 case LOCK_REC:
191 return("LOCK_REC");
192 case LOCK_TABLE:
193 return("LOCK_TABLE");
194 default:
195 ut_error;
196 }
197 }
198};
199
200/** Convert the member 'type_mode' into a human readable string.
201@return human readable string */
202inline
203std::string
204lock_t::type_mode_string() const
205{
206 std::ostringstream sout;
207 sout << type_string();
208 sout << " | " << lock_mode_string(mode());
209
210 if (is_record_not_gap()) {
211 sout << " | LOCK_REC_NOT_GAP";
212 }
213
214 if (is_waiting()) {
215 sout << " | LOCK_WAIT";
216 }
217
218 if (is_gap()) {
219 sout << " | LOCK_GAP";
220 }
221
222 if (is_insert_intention()) {
223 sout << " | LOCK_INSERT_INTENTION";
224 }
225 return(sout.str());
226}
227
228inline
229std::ostream&
230lock_t::print(std::ostream& out) const
231{
232 out << "[lock_t: type_mode=" << type_mode << "("
233 << type_mode_string() << ")";
234
235 if (is_record_lock()) {
236 out << un_member.rec_lock;
237 } else {
238 out << un_member.tab_lock;
239 }
240
241 out << "]";
242 return(out);
243}
244
245inline
246std::ostream&
247operator<<(std::ostream& out, const lock_t& lock)
248{
249 return(lock.print(out));
250}
251
252#ifdef UNIV_DEBUG
253extern ibool lock_print_waits;
254#endif /* UNIV_DEBUG */
255
256/** Restricts the length of search we will do in the waits-for
257graph of transactions */
258static const ulint LOCK_MAX_N_STEPS_IN_DEADLOCK_CHECK = 1000000;
259
260/** Restricts the search depth we will do in the waits-for graph of
261transactions */
262static const ulint LOCK_MAX_DEPTH_IN_DEADLOCK_CHECK = 200;
263
264/** When releasing transaction locks, this specifies how often we release
265the lock mutex for a moment to give also others access to it */
266static const ulint LOCK_RELEASE_INTERVAL = 1000;
267
268/* Safety margin when creating a new record lock: this many extra records
269can be inserted to the page without need to create a lock with a bigger
270bitmap */
271
272static const ulint LOCK_PAGE_BITMAP_MARGIN = 64;
273
274/* An explicit record lock affects both the record and the gap before it.
275An implicit x-lock does not affect the gap, it only locks the index
276record from read or update.
277
278If a transaction has modified or inserted an index record, then
279it owns an implicit x-lock on the record. On a secondary index record,
280a transaction has an implicit x-lock also if it has modified the
281clustered index record, the max trx id of the page where the secondary
282index record resides is >= trx id of the transaction (or database recovery
283is running), and there are no explicit non-gap lock requests on the
284secondary index record.
285
286This complicated definition for a secondary index comes from the
287implementation: we want to be able to determine if a secondary index
288record has an implicit x-lock, just by looking at the present clustered
289index record, not at the historical versions of the record. The
290complicated definition can be explained to the user so that there is
291nondeterminism in the access path when a query is answered: we may,
292or may not, access the clustered index record and thus may, or may not,
293bump into an x-lock set there.
294
295Different transaction can have conflicting locks set on the gap at the
296same time. The locks on the gap are purely inhibitive: an insert cannot
297be made, or a select cursor may have to wait if a different transaction
298has a conflicting lock on the gap. An x-lock on the gap does not give
299the right to insert into the gap.
300
301An explicit lock can be placed on a user record or the supremum record of
302a page. The locks on the supremum record are always thought to be of the gap
303type, though the gap bit is not set. When we perform an update of a record
304where the size of the record changes, we may temporarily store its explicit
305locks on the infimum record of the page, though the infimum otherwise never
306carries locks.
307
308A waiting record lock can also be of the gap type. A waiting lock request
309can be granted when there is no conflicting mode lock request by another
310transaction ahead of it in the explicit lock queue.
311
312In version 4.0.5 we added yet another explicit lock type: LOCK_REC_NOT_GAP.
313It only locks the record it is placed on, not the gap before the record.
314This lock type is necessary to emulate an Oracle-like READ COMMITTED isolation
315level.
316
317-------------------------------------------------------------------------
318RULE 1: If there is an implicit x-lock on a record, and there are non-gap
319-------
320lock requests waiting in the queue, then the transaction holding the implicit
321x-lock also has an explicit non-gap record x-lock. Therefore, as locks are
322released, we can grant locks to waiting lock requests purely by looking at
323the explicit lock requests in the queue.
324
325RULE 3: Different transactions cannot have conflicting granted non-gap locks
326-------
327on a record at the same time. However, they can have conflicting granted gap
328locks.
329RULE 4: If a there is a waiting lock request in a queue, no lock request,
330-------
331gap or not, can be inserted ahead of it in the queue. In record deletes
332and page splits new gap type locks can be created by the database manager
333for a transaction, and without rule 4, the waits-for graph of transactions
334might become cyclic without the database noticing it, as the deadlock check
335is only performed when a transaction itself requests a lock!
336-------------------------------------------------------------------------
337
338An insert is allowed to a gap if there are no explicit lock requests by
339other transactions on the next record. It does not matter if these lock
340requests are granted or waiting, gap bit set or not, with the exception
341that a gap type request set by another transaction to wait for
342its turn to do an insert is ignored. On the other hand, an
343implicit x-lock by another transaction does not prevent an insert, which
344allows for more concurrency when using an Oracle-style sequence number
345generator for the primary key with many transactions doing inserts
346concurrently.
347
348A modify of a record is allowed if the transaction has an x-lock on the
349record, or if other transactions do not have any non-gap lock requests on the
350record.
351
352A read of a single user record with a cursor is allowed if the transaction
353has a non-gap explicit, or an implicit lock on the record, or if the other
354transactions have no x-lock requests on the record. At a page supremum a
355read is always allowed.
356
357In summary, an implicit lock is seen as a granted x-lock only on the
358record, not on the gap. An explicit lock with no gap bit set is a lock
359both on the record and the gap. If the gap bit is set, the lock is only
360on the gap. Different transaction cannot own conflicting locks on the
361record at the same time, but they may own conflicting locks on the gap.
362Granted locks on a record give an access right to the record, but gap type
363locks just inhibit operations.
364
365NOTE: Finding out if some transaction has an implicit x-lock on a secondary
366index record can be cumbersome. We may have to look at previous versions of
367the corresponding clustered index record to find out if a delete marked
368secondary index record was delete marked by an active transaction, not by
369a committed one.
370
371FACT A: If a transaction has inserted a row, it can delete it any time
372without need to wait for locks.
373
374PROOF: The transaction has an implicit x-lock on every index record inserted
375for the row, and can thus modify each record without the need to wait. Q.E.D.
376
377FACT B: If a transaction has read some result set with a cursor, it can read
378it again, and retrieves the same result set, if it has not modified the
379result set in the meantime. Hence, there is no phantom problem. If the
380biggest record, in the alphabetical order, touched by the cursor is removed,
381a lock wait may occur, otherwise not.
382
383PROOF: When a read cursor proceeds, it sets an s-lock on each user record
384it passes, and a gap type s-lock on each page supremum. The cursor must
385wait until it has these locks granted. Then no other transaction can
386have a granted x-lock on any of the user records, and therefore cannot
387modify the user records. Neither can any other transaction insert into
388the gaps which were passed over by the cursor. Page splits and merges,
389and removal of obsolete versions of records do not affect this, because
390when a user record or a page supremum is removed, the next record inherits
391its locks as gap type locks, and therefore blocks inserts to the same gap.
392Also, if a page supremum is inserted, it inherits its locks from the successor
393record. When the cursor is positioned again at the start of the result set,
394the records it will touch on its course are either records it touched
395during the last pass or new inserted page supremums. It can immediately
396access all these records, and when it arrives at the biggest record, it
397notices that the result set is complete. If the biggest record was removed,
398lock wait can occur because the next record only inherits a gap type lock,
399and a wait may be needed. Q.E.D. */
400
401/* If an index record should be changed or a new inserted, we must check
402the lock on the record or the next. When a read cursor starts reading,
403we will set a record level s-lock on each record it passes, except on the
404initial record on which the cursor is positioned before we start to fetch
405records. Our index tree search has the convention that the B-tree
406cursor is positioned BEFORE the first possibly matching record in
407the search. Optimizations are possible here: if the record is searched
408on an equality condition to a unique key, we could actually set a special
409lock on the record, a lock which would not prevent any insert before
410this record. In the next key locking an x-lock set on a record also
411prevents inserts just before that record.
412 There are special infimum and supremum records on each page.
413A supremum record can be locked by a read cursor. This records cannot be
414updated but the lock prevents insert of a user record to the end of
415the page.
416 Next key locks will prevent the phantom problem where new rows
417could appear to SELECT result sets after the select operation has been
418performed. Prevention of phantoms ensures the serilizability of
419transactions.
420 What should we check if an insert of a new record is wanted?
421Only the lock on the next record on the same page, because also the
422supremum record can carry a lock. An s-lock prevents insertion, but
423what about an x-lock? If it was set by a searched update, then there
424is implicitly an s-lock, too, and the insert should be prevented.
425What if our transaction owns an x-lock to the next record, but there is
426a waiting s-lock request on the next record? If this s-lock was placed
427by a read cursor moving in the ascending order in the index, we cannot
428do the insert immediately, because when we finally commit our transaction,
429the read cursor should see also the new inserted record. So we should
430move the read cursor backward from the next record for it to pass over
431the new inserted record. This move backward may be too cumbersome to
432implement. If we in this situation just enqueue a second x-lock request
433for our transaction on the next record, then the deadlock mechanism
434notices a deadlock between our transaction and the s-lock request
435transaction. This seems to be an ok solution.
436 We could have the convention that granted explicit record locks,
437lock the corresponding records from changing, and also lock the gaps
438before them from inserting. A waiting explicit lock request locks the gap
439before from inserting. Implicit record x-locks, which we derive from the
440transaction id in the clustered index record, only lock the record itself
441from modification, not the gap before it from inserting.
442 How should we store update locks? If the search is done by a unique
443key, we could just modify the record trx id. Otherwise, we could put a record
444x-lock on the record. If the update changes ordering fields of the
445clustered index record, the inserted new record needs no record lock in
446lock table, the trx id is enough. The same holds for a secondary index
447record. Searched delete is similar to update.
448
449PROBLEM:
450What about waiting lock requests? If a transaction is waiting to make an
451update to a record which another modified, how does the other transaction
452know to send the end-lock-wait signal to the waiting transaction? If we have
453the convention that a transaction may wait for just one lock at a time, how
454do we preserve it if lock wait ends?
455
456PROBLEM:
457Checking the trx id label of a secondary index record. In the case of a
458modification, not an insert, is this necessary? A secondary index record
459is modified only by setting or resetting its deleted flag. A secondary index
460record contains fields to uniquely determine the corresponding clustered
461index record. A secondary index record is therefore only modified if we
462also modify the clustered index record, and the trx id checking is done
463on the clustered index record, before we come to modify the secondary index
464record. So, in the case of delete marking or unmarking a secondary index
465record, we do not have to care about trx ids, only the locks in the lock
466table must be checked. In the case of a select from a secondary index, the
467trx id is relevant, and in this case we may have to search the clustered
468index record.
469
470PROBLEM: How to update record locks when page is split or merged, or
471--------------------------------------------------------------------
472a record is deleted or updated?
473If the size of fields in a record changes, we perform the update by
474a delete followed by an insert. How can we retain the locks set or
475waiting on the record? Because a record lock is indexed in the bitmap
476by the heap number of the record, when we remove the record from the
477record list, it is possible still to keep the lock bits. If the page
478is reorganized, we could make a table of old and new heap numbers,
479and permute the bitmaps in the locks accordingly. We can add to the
480table a row telling where the updated record ended. If the update does
481not require a reorganization of the page, we can simply move the lock
482bits for the updated record to the position determined by its new heap
483number (we may have to allocate a new lock, if we run out of the bitmap
484in the old one).
485 A more complicated case is the one where the reinsertion of the
486updated record is done pessimistically, because the structure of the
487tree may change.
488
489PROBLEM: If a supremum record is removed in a page merge, or a record
490---------------------------------------------------------------------
491removed in a purge, what to do to the waiting lock requests? In a split to
492the right, we just move the lock requests to the new supremum. If a record
493is removed, we could move the waiting lock request to its inheritor, the
494next record in the index. But, the next record may already have lock
495requests on its own queue. A new deadlock check should be made then. Maybe
496it is easier just to release the waiting transactions. They can then enqueue
497new lock requests on appropriate records.
498
499PROBLEM: When a record is inserted, what locks should it inherit from the
500-------------------------------------------------------------------------
501upper neighbor? An insert of a new supremum record in a page split is
502always possible, but an insert of a new user record requires that the upper
503neighbor does not have any lock requests by other transactions, granted or
504waiting, in its lock queue. Solution: We can copy the locks as gap type
505locks, so that also the waiting locks are transformed to granted gap type
506locks on the inserted record. */
507
508/* LOCK COMPATIBILITY MATRIX
509 * IS IX S X AI
510 * IS + + + - +
511 * IX + + - - +
512 * S + - + - -
513 * X - - - - -
514 * AI + + - - -
515 *
516 * Note that for rows, InnoDB only acquires S or X locks.
517 * For tables, InnoDB normally acquires IS or IX locks.
518 * S or X table locks are only acquired for LOCK TABLES.
519 * Auto-increment (AI) locks are needed because of
520 * statement-level MySQL binlog.
521 * See also lock_mode_compatible().
522 */
523static const byte lock_compatibility_matrix[5][5] = {
524 /** IS IX S X AI */
525 /* IS */ { TRUE, TRUE, TRUE, FALSE, TRUE},
526 /* IX */ { TRUE, TRUE, FALSE, FALSE, TRUE},
527 /* S */ { TRUE, FALSE, TRUE, FALSE, FALSE},
528 /* X */ { FALSE, FALSE, FALSE, FALSE, FALSE},
529 /* AI */ { TRUE, TRUE, FALSE, FALSE, FALSE}
530};
531
532/* STRONGER-OR-EQUAL RELATION (mode1=row, mode2=column)
533 * IS IX S X AI
534 * IS + - - - -
535 * IX + + - - -
536 * S + - + - -
537 * X + + + + +
538 * AI - - - - +
539 * See lock_mode_stronger_or_eq().
540 */
541static const byte lock_strength_matrix[5][5] = {
542 /** IS IX S X AI */
543 /* IS */ { TRUE, FALSE, FALSE, FALSE, FALSE},
544 /* IX */ { TRUE, TRUE, FALSE, FALSE, FALSE},
545 /* S */ { TRUE, FALSE, TRUE, FALSE, FALSE},
546 /* X */ { TRUE, TRUE, TRUE, TRUE, TRUE},
547 /* AI */ { FALSE, FALSE, FALSE, FALSE, TRUE}
548};
549
550/** Maximum depth of the DFS stack. */
551static const ulint MAX_STACK_SIZE = 4096;
552
553#define PRDT_HEAPNO PAGE_HEAP_NO_INFIMUM
554/** Record locking request status */
555enum lock_rec_req_status {
556 /** Failed to acquire a lock */
557 LOCK_REC_FAIL,
558 /** Succeeded in acquiring a lock (implicit or already acquired) */
559 LOCK_REC_SUCCESS,
560 /** Explicitly created a new lock */
561 LOCK_REC_SUCCESS_CREATED
562};
563
564#ifdef UNIV_DEBUG
565/** The count of the types of locks. */
566static const ulint lock_types = UT_ARR_SIZE(lock_compatibility_matrix);
567#endif /* UNIV_DEBUG */
568
569/*********************************************************************//**
570Gets the type of a lock.
571@return LOCK_TABLE or LOCK_REC */
572UNIV_INLINE
573ulint
574lock_get_type_low(
575/*==============*/
576 const lock_t* lock); /*!< in: lock */
577
578/*********************************************************************//**
579Gets the previous record lock set on a record.
580@return previous lock on the same record, NULL if none exists */
581const lock_t*
582lock_rec_get_prev(
583/*==============*/
584 const lock_t* in_lock,/*!< in: record lock */
585 ulint heap_no);/*!< in: heap number of the record */
586
587/*********************************************************************//**
588Cancels a waiting lock request and releases possible other transactions
589waiting behind it. */
590void
591lock_cancel_waiting_and_release(
592/*============================*/
593 lock_t* lock); /*!< in/out: waiting lock request */
594
595/*********************************************************************//**
596Checks if some transaction has an implicit x-lock on a record in a clustered
597index.
598@return transaction id of the transaction which has the x-lock, or 0 */
599UNIV_INLINE
600trx_id_t
601lock_clust_rec_some_has_impl(
602/*=========================*/
603 const rec_t* rec, /*!< in: user record */
604 const dict_index_t* index, /*!< in: clustered index */
605 const ulint* offsets)/*!< in: rec_get_offsets(rec, index) */
606 MY_ATTRIBUTE((warn_unused_result));
607
608/*********************************************************************//**
609Gets the first or next record lock on a page.
610@return next lock, NULL if none exists */
611UNIV_INLINE
612const lock_t*
613lock_rec_get_next_on_page_const(
614/*============================*/
615 const lock_t* lock); /*!< in: a record lock */
616
617/*********************************************************************//**
618Gets the nth bit of a record lock.
619@return TRUE if bit set also if i == ULINT_UNDEFINED return FALSE*/
620UNIV_INLINE
621ibool
622lock_rec_get_nth_bit(
623/*=================*/
624 const lock_t* lock, /*!< in: record lock */
625 ulint i); /*!< in: index of the bit */
626
627/*********************************************************************//**
628Gets the number of bits in a record lock bitmap.
629@return number of bits */
630UNIV_INLINE
631ulint
632lock_rec_get_n_bits(
633/*================*/
634 const lock_t* lock); /*!< in: record lock */
635
636/**********************************************************************//**
637Sets the nth bit of a record lock to TRUE. */
638UNIV_INLINE
639void
640lock_rec_set_nth_bit(
641/*=================*/
642 lock_t* lock, /*!< in: record lock */
643 ulint i); /*!< in: index of the bit */
644
645/** Reset the nth bit of a record lock.
646@param[in,out] lock record lock
647@param[in] i index of the bit that will be reset
648@return previous value of the bit */
649inline byte lock_rec_reset_nth_bit(lock_t* lock, ulint i)
650{
651 ut_ad(lock_get_type_low(lock) == LOCK_REC);
652 ut_ad(i < lock->un_member.rec_lock.n_bits);
653
654 byte* b = reinterpret_cast<byte*>(&lock[1]) + (i >> 3);
655 byte mask = byte(1U << (i & 7));
656 byte bit = *b & mask;
657 *b &= ~mask;
658
659 if (bit != 0) {
660 ut_ad(lock->trx->lock.n_rec_locks > 0);
661 --lock->trx->lock.n_rec_locks;
662 }
663
664 return(bit);
665}
666
667/*********************************************************************//**
668Gets the first or next record lock on a page.
669@return next lock, NULL if none exists */
670UNIV_INLINE
671lock_t*
672lock_rec_get_next_on_page(
673/*======================*/
674 lock_t* lock); /*!< in: a record lock */
675/*********************************************************************//**
676Gets the first record lock on a page, where the page is identified by its
677file address.
678@return first lock, NULL if none exists */
679UNIV_INLINE
680lock_t*
681lock_rec_get_first_on_page_addr(
682/*============================*/
683 hash_table_t* lock_hash, /* Lock hash table */
684 ulint space, /*!< in: space */
685 ulint page_no); /*!< in: page number */
686
687/*********************************************************************//**
688Gets the first record lock on a page, where the page is identified by a
689pointer to it.
690@return first lock, NULL if none exists */
691UNIV_INLINE
692lock_t*
693lock_rec_get_first_on_page(
694/*=======================*/
695 hash_table_t* lock_hash, /*!< in: lock hash table */
696 const buf_block_t* block); /*!< in: buffer block */
697
698
699/*********************************************************************//**
700Gets the next explicit lock request on a record.
701@return next lock, NULL if none exists or if heap_no == ULINT_UNDEFINED */
702UNIV_INLINE
703lock_t*
704lock_rec_get_next(
705/*==============*/
706 ulint heap_no,/*!< in: heap number of the record */
707 lock_t* lock); /*!< in: lock */
708
709/*********************************************************************//**
710Gets the next explicit lock request on a record.
711@return next lock, NULL if none exists or if heap_no == ULINT_UNDEFINED */
712UNIV_INLINE
713const lock_t*
714lock_rec_get_next_const(
715/*====================*/
716 ulint heap_no,/*!< in: heap number of the record */
717 const lock_t* lock); /*!< in: lock */
718
719/*********************************************************************//**
720Gets the first explicit lock request on a record.
721@return first lock, NULL if none exists */
722UNIV_INLINE
723lock_t*
724lock_rec_get_first(
725/*===============*/
726 hash_table_t* hash, /*!< in: hash chain the lock on */
727 const buf_block_t* block, /*!< in: block containing the record */
728 ulint heap_no);/*!< in: heap number of the record */
729
730/*********************************************************************//**
731Gets the mode of a lock.
732@return mode */
733UNIV_INLINE
734enum lock_mode
735lock_get_mode(
736/*==========*/
737 const lock_t* lock); /*!< in: lock */
738
739/*********************************************************************//**
740Calculates if lock mode 1 is compatible with lock mode 2.
741@return nonzero if mode1 compatible with mode2 */
742UNIV_INLINE
743ulint
744lock_mode_compatible(
745/*=================*/
746 enum lock_mode mode1, /*!< in: lock mode */
747 enum lock_mode mode2); /*!< in: lock mode */
748
749/*********************************************************************//**
750Calculates if lock mode 1 is stronger or equal to lock mode 2.
751@return nonzero if mode1 stronger or equal to mode2 */
752UNIV_INLINE
753ulint
754lock_mode_stronger_or_eq(
755/*=====================*/
756 enum lock_mode mode1, /*!< in: lock mode */
757 enum lock_mode mode2); /*!< in: lock mode */
758
759/*********************************************************************//**
760Gets the wait flag of a lock.
761@return LOCK_WAIT if waiting, 0 if not */
762UNIV_INLINE
763ulint
764lock_get_wait(
765/*==========*/
766 const lock_t* lock); /*!< in: lock */
767
768/*********************************************************************//**
769Looks for a suitable type record lock struct by the same trx on the same page.
770This can be used to save space when a new record lock should be set on a page:
771no new struct is needed, if a suitable old is found.
772@return lock or NULL */
773UNIV_INLINE
774lock_t*
775lock_rec_find_similar_on_page(
776/*==========================*/
777 ulint type_mode, /*!< in: lock type_mode field */
778 ulint heap_no, /*!< in: heap number of the record */
779 lock_t* lock, /*!< in: lock_rec_get_first_on_page() */
780 const trx_t* trx); /*!< in: transaction */
781
782/*********************************************************************//**
783Checks if a transaction has the specified table lock, or stronger. This
784function should only be called by the thread that owns the transaction.
785@return lock or NULL */
786UNIV_INLINE
787const lock_t*
788lock_table_has(
789/*===========*/
790 const trx_t* trx, /*!< in: transaction */
791 const dict_table_t* table, /*!< in: table */
792 enum lock_mode mode); /*!< in: lock mode */
793
794/** Set the wait status of a lock.
795@param[in,out] lock lock that will be waited for
796@param[in,out] trx transaction that will wait for the lock */
797inline void lock_set_lock_and_trx_wait(lock_t* lock, trx_t* trx)
798{
799 ut_ad(lock);
800 ut_ad(lock->trx == trx);
801 ut_ad(trx->lock.wait_lock == NULL);
802 ut_ad(lock_mutex_own());
803 ut_ad(trx_mutex_own(trx));
804
805 trx->lock.wait_lock = lock;
806 lock->type_mode |= LOCK_WAIT;
807}
808
809/** Reset the wait status of a lock.
810@param[in,out] lock lock that was possibly being waited for */
811inline void lock_reset_lock_and_trx_wait(lock_t* lock)
812{
813 ut_ad(lock_get_wait(lock));
814 ut_ad(lock_mutex_own());
815 ut_ad(lock->trx->lock.wait_lock == NULL
816 || lock->trx->lock.wait_lock == lock);
817 lock->trx->lock.wait_lock = NULL;
818 lock->type_mode &= ~LOCK_WAIT;
819}
820
821#include "lock0priv.ic"
822
823#endif /* lock0priv_h */
824