MySQL 8.2.0
Source Code Documentation
Go to the documentation of this file.
3Copyright (c) 2007, 2023, Oracle and/or its affiliates.
5This program is free software; you can redistribute it and/or modify it under
6the terms of the GNU General Public License, version 2.0, as published by the
7Free Software Foundation.
9This program is also distributed with certain software (including but not
10limited to OpenSSL) that is licensed under separate terms, as designated in a
11particular file or component or in included license documentation. The authors
12of MySQL hereby grant you an additional permission to link the program and
13your derivative works with the separately licensed software that they have
14included with MySQL.
16This program is distributed in the hope that it will be useful, but WITHOUT
17ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
19for more details.
21You should have received a copy of the GNU General Public License along with
22this program; if not, write to the Free Software Foundation, Inc.,
2351 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27/** @file include/lock0priv.h
28 Lock module internal structures and methods.
30 Created July 12, 2007 Vasil Dimov
31 *******************************************************/
33#ifndef lock0priv_h
34#define lock0priv_h
37/* If you need to access members of the structures defined in this
38file, please write appropriate functions that retrieve them and put
39those functions in lock/ */
40#error Do not include lock0priv.h outside of the lock/ module
43#include "dict0types.h"
44#include "hash0hash.h"
45#include "trx0types.h"
46#include "univ.i"
48#include <scope_guard.h>
49#include <utility>
51/** A table lock */
53 dict_table_t *table; /*!< database table in dictionary
54 cache */
56 locks; /*!< list of locks on the same
57 table */
58 /** Print the table lock into the given output stream
59 @param[in,out] out the output stream
60 @return the given output stream. */
61 std::ostream &print(std::ostream &out) const;
64/** Print the table lock into the given output stream
65@param[in,out] out the output stream
66@return the given output stream. */
67inline std::ostream &lock_table_t::print(std::ostream &out) const {
68 out << "[lock_table_t: name=" << table->name << "]";
69 return (out);
72/** The global output operator is overloaded to conveniently
73print the lock_table_t object into the given output stream.
74@param[in,out] out the output stream
75@param[in] lock the table lock
76@return the given output stream */
77inline std::ostream &operator<<(std::ostream &out, const lock_table_t &lock) {
78 return (lock.print(out));
81/** Record lock for a page */
82struct lock_rec_t {
83 /** The id of the page on which records referenced by this lock's bitmap are
84 located. */
86 /** number of bits in the lock bitmap;
87 Must be divisible by 8.
88 NOTE: the lock bitmap is placed immediately after the lock struct */
89 uint32_t n_bits;
91 /** Print the record lock into the given output stream
92 @param[in,out] out the output stream
93 @return the given output stream. */
94 std::ostream &print(std::ostream &out) const;
97/** Print the record lock into the given output stream
98@param[in,out] out the output stream
99@return the given output stream. */
100inline std::ostream &lock_rec_t::print(std::ostream &out) const {
101 return out << "[lock_rec_t: page_id=" << page_id << ", n_bits=" << n_bits
102 << "]";
105inline std::ostream &operator<<(std::ostream &out, const lock_rec_t &lock) {
106 return (lock.print(out));
110Checks if the `mode` is LOCK_S or LOCK_X (possibly ORed with LOCK_WAIT or
111LOCK_REC) which means the lock is a
112Next Key Lock, a.k.a. LOCK_ORDINARY, as opposed to Predicate Lock,
113GAP lock, Insert Intention or Record Lock.
114@param mode A mode and flags, of a lock.
115@return true iff the only bits set in `mode` are LOCK_S or LOCK_X and optionally
118 static_assert(LOCK_ORDINARY == 0, "LOCK_ORDINARY must be 0 (no flags)");
119 ut_ad((mode & LOCK_TABLE) == 0);
120 mode &= ~(LOCK_WAIT | LOCK_REC);
121 ut_ad((mode & LOCK_WAIT) == 0);
122 ut_ad((mode & LOCK_TYPE_MASK) == 0);
124 (mode == LOCK_S || mode == LOCK_X));
125 return (mode & ~(LOCK_MODE_MASK)) == LOCK_ORDINARY;
128/** Gets the nth bit of a record lock.
129@param[in] lock record lock
130@param[in] i index of the bit
131@return true if bit set also if i == ULINT_UNDEFINED return false */
132static inline bool lock_rec_get_nth_bit(const lock_t *lock, ulint i);
134/** Lock struct; protected by lock_sys latches */
135struct lock_t {
136 /** transaction owning the lock */
139 /** list of the locks of the transaction */
142 /** Index for a record lock */
145 /** Hash chain node for a record lock. The link node in a singly
146 linked list, used by the hash table. */
149 union {
150 /** Table lock */
153 /** Record lock */
155 };
159 /** Performance schema thread that created the lock. */
162 /** Performance schema event that created the lock. */
167 /** The lock type and mode bit flags.
169 uint32_t type_mode;
171#if defined(UNIV_DEBUG)
172 /** Timestamp when it was created. */
173 uint64_t m_seq;
174#endif /* UNIV_DEBUG */
176 /** Unlock the GAP Lock part of this Next Key Lock */
178 ut_ad(!is_gap());
179 ut_ad(!is_insert_intention());
180 ut_ad(is_next_key_lock());
182 type_mode |= LOCK_REC_NOT_GAP;
183 }
185 /** Determine if the lock object is a record lock.
186 @return true if record lock, false otherwise. */
187 bool is_record_lock() const { return (type() == LOCK_REC); }
189 /** Determine if it is predicate lock.
190 @return true if predicate lock, false otherwise. */
191 bool is_predicate() const {
192 return (type_mode & (LOCK_PREDICATE | LOCK_PRDT_PAGE));
193 }
195 /** @return true if the lock wait flag is set */
196 bool is_waiting() const { return (type_mode & LOCK_WAIT); }
198 /** @return true if the gap lock bit is set */
199 bool is_gap() const { return (type_mode & LOCK_GAP); }
201 /** @return true if the not gap lock bit is set */
202 bool is_record_not_gap() const { return (type_mode & LOCK_REC_NOT_GAP); }
204 /** @return true iff the lock is a Next Key Lock */
205 bool is_next_key_lock() const {
206 return is_record_lock() && lock_mode_is_next_key_lock(type_mode);
207 }
209 /** @return true if the insert intention bit is set */
210 bool is_insert_intention() const {
211 return (type_mode & LOCK_INSERT_INTENTION);
212 }
214 /** @return true iff this lock is (at least) on supremum pseudo-record */
215 bool includes_supremum() const {
217 }
219 /** @return the lock mode */
220 uint32_t type() const { return (type_mode & LOCK_TYPE_MASK); }
222 /** @return the precise lock mode */
223 lock_mode mode() const {
224 return (static_cast<lock_mode>(type_mode & LOCK_MODE_MASK));
225 }
227 /** Get lock hash table
228 @return lock hash table */
229 hash_table_t *hash_table() const { return (lock_hash_get(type_mode)); }
231 /** @return the transaction's query thread state. */
232 trx_que_t trx_que_state() const { return (trx->lock.que_state); }
234 /** Print the lock object into the given output stream.
235 @param[in,out] out the output stream
236 @return the given output stream. */
237 std::ostream &print(std::ostream &out) const;
239 /** Convert the member 'type_mode' into a human readable string.
240 @return human readable string */
241 std::string type_mode_string() const;
243 /* @return the string/text representation of the record type. */
244 const char *type_string() const {
245 switch (type_mode & LOCK_TYPE_MASK) {
246 case LOCK_REC:
247 return ("LOCK_REC");
248 case LOCK_TABLE:
249 return ("LOCK_TABLE");
250 default:
251 ut_error;
252 }
253 }
258/** Convert the member 'type_mode' into a human readable string.
259@return human readable string */
260inline std::string lock_t::type_mode_string() const {
262 sout << type_string();
263 sout << " | " << lock_mode_string(mode());
265 if (is_record_not_gap()) {
266 sout << " | LOCK_REC_NOT_GAP";
267 }
269 if (is_waiting()) {
270 sout << " | LOCK_WAIT";
271 }
273 if (is_gap()) {
274 sout << " | LOCK_GAP";
275 }
277 if (is_insert_intention()) {
278 sout << " | LOCK_INSERT_INTENTION";
279 }
280 return (sout.str());
283inline std::ostream &lock_t::print(std::ostream &out) const {
284 out << "[lock_t: type_mode=" << type_mode << "(" << type_mode_string() << ")";
286 if (is_record_lock()) {
287 out << rec_lock;
288 } else {
289 out << tab_lock;
290 }
292 out << "]";
293 return (out);
296inline std::ostream &operator<<(std::ostream &out, const lock_t &lock) {
297 return (lock.print(out));
300#ifdef UNIV_DEBUG
301extern bool lock_print_waits;
302#endif /* UNIV_DEBUG */
304/* Safety margin when creating a new record lock: this many extra records
305can be inserted to the page without need to create a lock with a bigger
306bitmap */
310/* An explicit record lock affects both the record and the gap before it.
311An implicit x-lock does not affect the gap, it only locks the index
312record from read or update.
314If a transaction has modified or inserted an index record, then
315it owns an implicit x-lock on the record. On a secondary index record,
316a transaction has an implicit x-lock also if it has modified the
317clustered index record, the max trx id of the page where the secondary
318index record resides is >= trx id of the transaction (or database recovery
319is running), and there are no explicit non-gap lock requests on the
320secondary index record.
322This complicated definition for a secondary index comes from the
323implementation: we want to be able to determine if a secondary index
324record has an implicit x-lock, just by looking at the present clustered
325index record, not at the historical versions of the record. The
326complicated definition can be explained to the user so that there is
327nondeterminism in the access path when a query is answered: we may,
328or may not, access the clustered index record and thus may, or may not,
329bump into an x-lock set there.
331Different transaction can have conflicting locks set on the gap at the
332same time. The locks on the gap are purely inhibitive: an insert cannot
333be made, or a select cursor may have to wait if a different transaction
334has a conflicting lock on the gap. An x-lock on the gap does not give
335the right to insert into the gap.
337An explicit lock can be placed on a user record or the supremum record of
338a page. The locks on the supremum record are always thought to be of the gap
339type, though the gap bit is not set. When we perform an update of a record
340where the size of the record changes, we may temporarily store its explicit
341locks on the infimum record of the page, though the infimum otherwise never
342carries locks.
344A waiting record lock can also be of the gap type. A waiting lock request
345can be granted when there is no conflicting mode lock request by another
346transaction ahead of it in the explicit lock queue.
348In version 4.0.5 we added yet another explicit lock type: LOCK_REC_NOT_GAP.
349It only locks the record it is placed on, not the gap before the record.
350This lock type is necessary to emulate an Oracle-like READ COMMITTED isolation
354RULE 1: If there is an implicit x-lock on a record, and there are non-gap
356lock requests waiting in the queue, then the transaction holding the implicit
357x-lock also has an explicit non-gap record x-lock. Therefore, as locks are
358released, we can grant locks to waiting lock requests purely by looking at
359the explicit lock requests in the queue.
361RULE 3: Different transactions cannot have conflicting granted non-gap locks
363on a record at the same time. However, they can have conflicting granted gap
365RULE 4: If a there is a waiting lock request in a queue, no lock request,
367gap or not, can be inserted ahead of it in the queue. In record deletes
368and page splits new gap type locks can be created by the database manager
369for a transaction, and without rule 4, the waits-for graph of transactions
370might become cyclic without the database noticing it, as the deadlock check
371is only performed when a transaction itself requests a lock!
374An insert is allowed to a gap if there are no explicit lock requests by
375other transactions on the next record. It does not matter if these lock
376requests are granted or waiting, gap bit set or not, with the exception
377that a gap type request set by another transaction to wait for
378its turn to do an insert is ignored. On the other hand, an
379implicit x-lock by another transaction does not prevent an insert, which
380allows for more concurrency when using an Oracle-style sequence number
381generator for the primary key with many transactions doing inserts
384A modify of a record is allowed if the transaction has an x-lock on the
385record, or if other transactions do not have any non-gap lock requests on the
388A read of a single user record with a cursor is allowed if the transaction
389has a non-gap explicit, or an implicit lock on the record, or if the other
390transactions have no x-lock requests on the record. At a page supremum a
391read is always allowed.
393In summary, an implicit lock is seen as a granted x-lock only on the
394record, not on the gap. An explicit lock with no gap bit set is a lock
395both on the record and the gap. If the gap bit is set, the lock is only
396on the gap. Different transaction cannot own conflicting locks on the
397record at the same time, but they may own conflicting locks on the gap.
398Granted locks on a record give an access right to the record, but gap type
399locks just inhibit operations.
401NOTE: Finding out if some transaction has an implicit x-lock on a secondary
402index record can be cumbersome. We may have to look at previous versions of
403the corresponding clustered index record to find out if a delete marked
404secondary index record was delete marked by an active transaction, not by
405a committed one.
407FACT A: If a transaction has inserted a row, it can delete it any time
408without need to wait for locks.
410PROOF: The transaction has an implicit x-lock on every index record inserted
411for the row, and can thus modify each record without the need to wait. Q.E.D.
413FACT B: If a transaction has read some result set with a cursor, it can read
414it again, and retrieves the same result set, if it has not modified the
415result set in the meantime. Hence, there is no phantom problem. If the
416biggest record, in the alphabetical order, touched by the cursor is removed,
417a lock wait may occur, otherwise not.
419PROOF: When a read cursor proceeds, it sets an s-lock on each user record
420it passes, and a gap type s-lock on each page supremum. The cursor must
421wait until it has these locks granted. Then no other transaction can
422have a granted x-lock on any of the user records, and therefore cannot
423modify the user records. Neither can any other transaction insert into
424the gaps which were passed over by the cursor. Page splits and merges,
425and removal of obsolete versions of records do not affect this, because
426when a user record or a page supremum is removed, the next record inherits
427its locks as gap type locks, and therefore blocks inserts to the same gap.
428Also, if a page supremum is inserted, it inherits its locks from the successor
429record. When the cursor is positioned again at the start of the result set,
430the records it will touch on its course are either records it touched
431during the last pass or new inserted page supremums. It can immediately
432access all these records, and when it arrives at the biggest record, it
433notices that the result set is complete. If the biggest record was removed,
434lock wait can occur because the next record only inherits a gap type lock,
435and a wait may be needed. Q.E.D. */
437/* If an index record should be changed or a new inserted, we must check
438the lock on the record or the next. When a read cursor starts reading,
439we will set a record level s-lock on each record it passes, except on the
440initial record on which the cursor is positioned before we start to fetch
441records. Our index tree search has the convention that the B-tree
442cursor is positioned BEFORE the first possibly matching record in
443the search. Optimizations are possible here: if the record is searched
444on an equality condition to a unique key, we could actually set a special
445lock on the record, a lock which would not prevent any insert before
446this record. In the next key locking an x-lock set on a record also
447prevents inserts just before that record.
448 There are special infimum and supremum records on each page.
449A supremum record can be locked by a read cursor. This records cannot be
450updated but the lock prevents insert of a user record to the end of
451the page.
452 Next key locks will prevent the phantom problem where new rows
453could appear to SELECT result sets after the select operation has been
454performed. Prevention of phantoms ensures the serilizability of
456 What should we check if an insert of a new record is wanted?
457Only the lock on the next record on the same page, because also the
458supremum record can carry a lock. An s-lock prevents insertion, but
459what about an x-lock? If it was set by a searched update, then there
460is implicitly an s-lock, too, and the insert should be prevented.
461What if our transaction owns an x-lock to the next record, but there is
462a waiting s-lock request on the next record? If this s-lock was placed
463by a read cursor moving in the ascending order in the index, we cannot
464do the insert immediately, because when we finally commit our transaction,
465the read cursor should see also the new inserted record. So we should
466move the read cursor backward from the next record for it to pass over
467the new inserted record. This move backward may be too cumbersome to
468implement. If we in this situation just enqueue a second x-lock request
469for our transaction on the next record, then the deadlock mechanism
470notices a deadlock between our transaction and the s-lock request
471transaction. This seems to be an ok solution.
472 We could have the convention that granted explicit record locks,
473lock the corresponding records from changing, and also lock the gaps
474before them from inserting. A waiting explicit lock request locks the gap
475before from inserting. Implicit record x-locks, which we derive from the
476transaction id in the clustered index record, only lock the record itself
477from modification, not the gap before it from inserting.
478 How should we store update locks? If the search is done by a unique
479key, we could just modify the record trx id. Otherwise, we could put a record
480x-lock on the record. If the update changes ordering fields of the
481clustered index record, the inserted new record needs no record lock in
482lock table, the trx id is enough. The same holds for a secondary index
483record. Searched delete is similar to update.
486What about waiting lock requests? If a transaction is waiting to make an
487update to a record which another modified, how does the other transaction
488know to send the end-lock-wait signal to the waiting transaction? If we have
489the convention that a transaction may wait for just one lock at a time, how
490do we preserve it if lock wait ends?
493Checking the trx id label of a secondary index record. In the case of a
494modification, not an insert, is this necessary? A secondary index record
495is modified only by setting or resetting its deleted flag. A secondary index
496record contains fields to uniquely determine the corresponding clustered
497index record. A secondary index record is therefore only modified if we
498also modify the clustered index record, and the trx id checking is done
499on the clustered index record, before we come to modify the secondary index
500record. So, in the case of delete marking or unmarking a secondary index
501record, we do not have to care about trx ids, only the locks in the lock
502table must be checked. In the case of a select from a secondary index, the
503trx id is relevant, and in this case we may have to search the clustered
504index record.
506PROBLEM: How to update record locks when page is split or merged, or
508a record is deleted or updated?
509If the size of fields in a record changes, we perform the update by
510a delete followed by an insert. How can we retain the locks set or
511waiting on the record? Because a record lock is indexed in the bitmap
512by the heap number of the record, when we remove the record from the
513record list, it is possible still to keep the lock bits. If the page
514is reorganized, we could make a table of old and new heap numbers,
515and permute the bitmaps in the locks accordingly. We can add to the
516table a row telling where the updated record ended. If the update does
517not require a reorganization of the page, we can simply move the lock
518bits for the updated record to the position determined by its new heap
519number (we may have to allocate a new lock, if we run out of the bitmap
520in the old one).
521 A more complicated case is the one where the reinsertion of the
522updated record is done pessimistically, because the structure of the
523tree may change.
525PROBLEM: If a supremum record is removed in a page merge, or a record
527removed in a purge, what to do to the waiting lock requests? In a split to
528the right, we just move the lock requests to the new supremum. If a record
529is removed, we could move the waiting lock request to its inheritor, the
530next record in the index. But, the next record may already have lock
531requests on its own queue. A new deadlock check should be made then. Maybe
532it is easier just to release the waiting transactions. They can then enqueue
533new lock requests on appropriate records.
535PROBLEM: When a record is inserted, what locks should it inherit from the
537upper neighbor? An insert of a new supremum record in a page split is
538always possible, but an insert of a new user record requires that the upper
539neighbor does not have any lock requests by other transactions, granted or
540waiting, in its lock queue. Solution: We can copy the locks as gap type
541locks, so that also the waiting locks are transformed to granted gap type
542locks on the inserted record. */
545 IS IX S X AI
546 IS + + + - +
547 IX + + - - +
548 S + - + - -
549 X - - - - -
550 AI + + - - -
551 *
552 Note that for rows, InnoDB only acquires S or X locks.
553 For tables, InnoDB normally acquires IS or IX locks.
554 S or X table locks are only acquired for LOCK TABLES.
555 Auto-increment (AI) locks are needed because of
556 statement-level MySQL binlog.
557 See also lock_mode_compatible().
558 */
559static const byte lock_compatibility_matrix[5][5] = {
560 /** IS IX S X AI */
561 /* IS */ {true, true, true, false, true},
562 /* IX */ {true, true, false, false, true},
563 /* S */ {true, false, true, false, false},
564 /* X */ {false, false, false, false, false},
565 /* AI */ {true, true, false, false, false}};
567/* STRONGER-OR-EQUAL RELATION (mode1=row, mode2=column)
568 IS IX S X AI
569 IS + - - - -
570 IX + + - - -
571 S + - + - -
572 X + + + + +
573 AI - - - - +
574 See lock_mode_stronger_or_eq().
575 */
576static const byte lock_strength_matrix[5][5] = {
577 /** IS IX S X AI */
578 /* IS */ {true, false, false, false, false},
579 /* IX */ {true, true, false, false, false},
580 /* S */ {true, false, true, false, false},
581 /* X */ {true, true, true, true, true},
582 /* AI */ {false, false, false, false, true}};
584/** Maximum depth of the DFS stack. */
585constexpr uint32_t MAX_STACK_SIZE = 4096;
588/** Record locking request status */
590 /** Failed to acquire a lock */
592 /** Succeeded in acquiring a lock (implicit or already acquired) */
594 /** Explicitly created a new lock */
599Record lock ID */
600struct RecID {
601 /** Constructor
602 @param[in] lock Record lock
603 @param[in] heap_no Heap number in the page */
604 RecID(const lock_t *lock, ulint heap_no)
605 : RecID(lock->rec_lock.page_id, heap_no) {
606 ut_ad(lock->is_record_lock());
607 }
609 /** Constructor
610 @param[in] page_id Tablespace ID and page number within space
611 @param[in] heap_no Heap number in the page */
612 RecID(page_id_t page_id, uint32_t heap_no)
613 : m_page_id(page_id),
614 m_heap_no(heap_no),
615 m_hash_value(lock_rec_hash_value(page_id)) {
616 ut_ad( < UINT32_MAX);
617 ut_ad(m_page_id.page_no() < UINT32_MAX);
618 ut_ad(m_heap_no < UINT32_MAX);
619 }
621 /** Constructor
622 @param[in] block Block in a tablespace
623 @param[in] heap_no Heap number in the block */
624 RecID(const buf_block_t *block, ulint heap_no)
625 : RecID(block->get_page_id(), heap_no) {}
627 /**
628 @return the hashed value of {space, page_no} */
629 uint64_t hash_value() const { return (m_hash_value); }
631 /** @return true if it's the supremum record */
632 bool is_supremum() const { return (m_heap_no == PAGE_HEAP_NO_SUPREMUM); }
634 /* Check if the rec id matches the lock instance.
635 @param[i] lock Lock to compare with
636 @return true if <space, page_no, heap_no> matches the lock. */
637 inline bool matches(const lock_t *lock) const;
639 const page_id_t &get_page_id() const { return m_page_id; }
641 /** Tablespace ID and page number within space */
644 /**
645 Heap number within the page */
646 uint32_t m_heap_no;
648 /**
649 Hash generated from record's location which will be used to get lock queue for
650 this record. */
651 uint64_t m_hash_value;
655Create record locks */
656class RecLock {
657 public:
658 /**
659 @param[in,out] thr Transaction query thread requesting the record
660 lock
661 @param[in] index Index on which record lock requested
662 @param[in] rec_id Record lock tuple {space, page_no, heap_no}
663 @param[in] mode The lock mode */
664 RecLock(que_thr_t *thr, dict_index_t *index, const RecID &rec_id, ulint mode)
665 : m_thr(thr),
666 m_trx(thr_get_trx(thr)),
667 m_mode(mode),
668 m_index(index),
669 m_rec_id(rec_id) {
670 ut_ad(is_predicate_lock(m_mode));
672 init(nullptr);
673 }
675 /**
676 @param[in,out] thr Transaction query thread requesting the record
677 lock
678 @param[in] index Index on which record lock requested
679 @param[in] block Buffer page containing record
680 @param[in] heap_no Heap number within the block
681 @param[in] mode The lock mode */
682 RecLock(que_thr_t *thr, dict_index_t *index, const buf_block_t *block,
683 ulint heap_no, ulint mode)
684 : m_thr(thr),
685 m_trx(thr_get_trx(thr)),
686 m_mode(mode),
687 m_index(index),
688 m_rec_id(block, heap_no) {
689 btr_assert_not_corrupted(block, index);
691 init(block->frame);
692 }
694 /**
695 @param[in] index Index on which record lock requested
696 @param[in] rec_id Record lock tuple {space, page_no, heap_no}
697 @param[in] mode The lock mode */
698 RecLock(dict_index_t *index, const RecID &rec_id, ulint mode)
699 : m_thr(), m_trx(), m_mode(mode), m_index(index), m_rec_id(rec_id) {
700 ut_ad(is_predicate_lock(m_mode));
702 init(nullptr);
703 }
705 /**
706 @param[in] index Index on which record lock requested
707 @param[in] block Buffer page containing record
708 @param[in] heap_no Heap number within block
709 @param[in] mode The lock mode */
710 RecLock(dict_index_t *index, const buf_block_t *block, ulint heap_no,
711 ulint mode)
712 : m_thr(),
713 m_trx(),
714 m_mode(mode),
715 m_index(index),
716 m_rec_id(block, heap_no) {
717 btr_assert_not_corrupted(block, index);
719 init(block->frame);
720 }
722 /**
723 Enqueue a lock wait for a transaction. If it is a high priority transaction
724 (cannot rollback) then try to jump ahead in the record lock wait queue. Also
725 check if async rollback was request for our trx.
726 @param[in, out] wait_for The lock that the the joining transaction is
727 waiting for
728 @param[in] prdt Predicate [optional]
730 @retval DB_DEADLOCK means that async rollback was requested for our trx
731 @retval DB_SUCCESS_LOCKED_REC means that we are High Priority transaction and
732 we've managed to jump in front of other waiting
733 transactions and got the lock granted, so there
734 is no need to wait. */
735 dberr_t add_to_waitq(const lock_t *wait_for,
736 const lock_prdt_t *prdt = nullptr);
738 /**
739 Create a lock for a transaction and initialise it.
740 @param[in, out] trx Transaction requesting the new lock
741 @param[in] prdt Predicate lock (optional)
742 @return new lock instance */
743 lock_t *create(trx_t *trx, const lock_prdt_t *prdt = nullptr);
745 /**
746 Create the lock instance
747 @param[in, out] trx The transaction requesting the lock
748 @param[in, out] index Index on which record lock is required
749 @param[in] mode The lock mode desired
750 @param[in] rec_id The record id
751 @param[in] size Size of the lock + bitmap requested
752 @return a record lock instance */
753 static lock_t *lock_alloc(trx_t *trx, dict_index_t *index, ulint mode,
754 const RecID &rec_id, ulint size);
756 private:
757 /*
758 @return the record lock size in bytes */
759 size_t lock_size() const { return (m_size); }
761 /**
762 Do some checks and prepare for creating a new record lock */
763 void prepare() const;
765 /**
766 Setup the requesting transaction state for lock grant
767 @param[in,out] lock Lock for which to change state */
768 void set_wait_state(lock_t *lock);
770 /**
771 Add the lock to the record lock hash and the transaction's lock list
772 @param[in,out] lock Newly created record lock to add to the
773 rec hash and the transaction lock list */
774 void lock_add(lock_t *lock);
776 /**
777 Setup the context from the requirements */
778 void init(const page_t *page) {
779 ut_ad(locksys::owns_page_shard(m_rec_id.get_page_id()));
781 ut_ad(m_index->is_clustered() || !dict_index_is_online_ddl(m_index));
782 ut_ad(m_thr == nullptr || m_trx == thr_get_trx(m_thr));
784 m_size = is_predicate_lock(m_mode) ? lock_size(m_mode) : lock_size(page);
786 /** If rec is the supremum record, then we reset the
787 gap and LOCK_REC_NOT_GAP bits, as all locks on the
788 supremum are automatically of the gap type */
790 if (m_rec_id.m_heap_no == PAGE_HEAP_NO_SUPREMUM) {
791 ut_ad(!(m_mode & LOCK_REC_NOT_GAP));
793 m_mode &= ~(LOCK_GAP | LOCK_REC_NOT_GAP);
794 }
795 }
797 /**
798 Calculate the record lock physical size required for a predicate lock.
799 @param[in] mode For predicate locks the lock mode
800 @return the size of the lock data structure required in bytes */
801 static size_t lock_size(ulint mode) {
802 ut_ad(is_predicate_lock(mode));
804 /* The lock is always on PAGE_HEAP_NO_INFIMUM(0),
805 so we only need 1 bit (which is rounded up to 1
806 byte) for lock bit setting */
808 size_t n_bytes;
810 if (mode & LOCK_PREDICATE) {
811 const ulint align = UNIV_WORD_SIZE - 1;
813 /* We will attach the predicate structure
814 after lock. Make sure the memory is
815 aligned on 8 bytes, the mem_heap_alloc
816 will align it with MEM_SPACE_NEEDED
817 anyway. */
819 n_bytes = (1 + sizeof(lock_prdt_t) + align) & ~align;
821 /* This should hold now */
823 ut_ad(n_bytes == sizeof(lock_prdt_t) + UNIV_WORD_SIZE);
825 } else {
826 n_bytes = 1;
827 }
829 return (n_bytes);
830 }
832 /**
833 Calculate the record lock physical size required, non-predicate lock.
834 @param[in] page For non-predicate locks the buffer page
835 @return the size of the lock data structure required in bytes */
836 static size_t lock_size(const page_t *page) {
839 /* Make lock bitmap bigger by a safety margin */
841 return (1 + ((n_recs + LOCK_PAGE_BITMAP_MARGIN) / 8));
842 }
844 /**
845 @return true if the requested lock mode is for a predicate
846 or page lock */
848 return (mode & (LOCK_PREDICATE | LOCK_PRDT_PAGE));
849 }
851 private:
852 /** The query thread of the transaction */
855 /**
856 Transaction requesting the record lock */
859 /**
860 Lock mode requested */
863 /**
864 Size of the record lock in bytes */
865 size_t m_size;
867 /**
868 Index on which the record lock is required */
871 /**
872 The record lock tuple {space, page_no, heap_no} */
876#ifdef UNIV_DEBUG
877/** The count of the types of locks. */
879#endif /* UNIV_DEBUG */
881/** Gets the type of a lock.
882 @return LOCK_TABLE or LOCK_REC */
883static inline uint32_t lock_get_type_low(const lock_t *lock); /*!< in: lock */
885/** Gets the previous record lock set on a record.
886 @return previous lock on the same record, NULL if none exists */
888 const lock_t *in_lock, /*!< in: record lock */
889 ulint heap_no); /*!< in: heap number of the record */
891/** Cancels a waiting lock request and releases possible other transactions
892waiting behind it.
893@param[in,out] trx The transaction waiting for a lock */
896/** This function is a wrapper around several functions which need to be called
897in particular order to wake up a transaction waiting for a lock.
898You should not call lock_wait_release_thread_if_suspended(thr) directly,
899but rather use this wrapper, as this makes it much easier to reason about all
900possible states in which lock, trx, and thr can be.
901It makes sure that trx is woken up exactly once, and only if it already went to
903@param[in, out] lock The lock for which lock->trx is waiting */
906/** Checks if some transaction has an implicit x-lock on a record in a clustered
908@param[in] rec User record.
909@param[in] index Clustered index.
910@param[in] offsets rec_get_offsets(rec, index)
911@return transaction id of the transaction which has the x-lock, or 0 */
912[[nodiscard]] static inline trx_id_t lock_clust_rec_some_has_impl(
913 const rec_t *rec, const dict_index_t *index, const ulint *offsets);
915/** Gets the first or next record lock on a page.
916 @return next lock, NULL if none exists */
918 const lock_t *lock); /*!< in: a record lock */
920/** Gets the number of bits in a record lock bitmap.
921@param[in] lock The record lock
922@return number of bits */
923static inline uint32_t lock_rec_get_n_bits(const lock_t *lock);
925/** Sets the nth bit of a record lock to true.
926@param[in] lock record lock
927@param[in] i index of the bit */
928static inline void lock_rec_set_nth_bit(lock_t *lock, ulint i);
930/** Gets the first or next record lock on a page.
931 @return next lock, NULL if none exists */
933 lock_t *lock); /*!< in: a record lock */
935/** Gets the first record lock on a page, where the page is identified by its
936file address.
937@param[in] lock_hash lock hash table
938@param[in] page_id specifies space id and page number of the page
939@return first lock, NULL if none exists */
941 const page_id_t &page_id);
943/** Gets the first record lock on a page, where the page is identified by a
944pointer to it.
945@param[in] lock_hash lock hash table
946@param[in] block buffer block
947@return first lock, NULL if none exists */
949 const buf_block_t *block);
951/** Gets the next explicit lock request on a record.
952@param[in] heap_no heap number of the record
953@param[in] lock lock
954@return next lock, NULL if none exists or if heap_no == ULINT_UNDEFINED */
955static inline lock_t *lock_rec_get_next(ulint heap_no, lock_t *lock);
957/** Gets the next explicit lock request on a record.
958@param[in] heap_no heap number of the record
959@param[in] lock lock
960@return next lock, NULL if none exists or if heap_no == ULINT_UNDEFINED */
961static inline const lock_t *lock_rec_get_next_const(ulint heap_no,
962 const lock_t *lock);
964/** Gets the first explicit lock request on a record.
965@param[in] hash hash chain the lock on
966@param[in] block block containing the record
967@param[in] heap_no heap number of the record
968@return first lock, NULL if none exists */
970 const buf_block_t *block,
971 ulint heap_no);
973/** Gets the mode of a lock.
974 @return mode */
975static inline enum lock_mode lock_get_mode(const lock_t *lock); /*!< in: lock */
977/** Calculates if lock mode 1 is compatible with lock mode 2.
978@param[in] mode1 lock mode
979@param[in] mode2 lock mode
980@return nonzero if mode1 compatible with mode2 */
981static inline ulint lock_mode_compatible(enum lock_mode mode1,
982 enum lock_mode mode2);
984/** Calculates if lock mode 1 is stronger or equal to lock mode 2.
985@param[in] mode1 lock mode 1
986@param[in] mode2 lock mode 2
987@return true iff mode1 stronger or equal to mode2 */
988static inline bool lock_mode_stronger_or_eq(enum lock_mode mode1,
989 enum lock_mode mode2);
991/** Gets the wait flag of a lock.
992 @return LOCK_WAIT if waiting, 0 if not */
993static inline ulint lock_get_wait(const lock_t *lock); /*!< in: lock */
995/** Checks if a transaction has the specified table lock, or stronger. This
996function should only be called by the thread that owns the transaction.
997This function acquires trx->mutex which protects trx->lock.trx_locks, but you
998should understand that this only makes it easier to argue against races at the
999level of access to the data structure, yet does not buy us any protection at
1000the higher level of making actual decisions based on the result of this call -
1001it may happen that another thread is removing a table lock,
1002and even though lock_table_has returned true to the caller, the lock is no
1003longer in possession of trx once the caller gets to evaluate if/else condition
1004based on the result.
1005Therefore it is up to caller to make sure that the context of the call to this
1006function and making any decisions based on the result is protected from any
1007concurrent modifications. This in turn makes the whole trx_mutex_enter/exit
1008a bit redundant, but it does not affect performance yet makes the reasoning
1009about data structure a bit easier and protects trx->lock.trx_locks data
1010structure from corruption in case our high level reasoning about absence of
1011parallel modifications turns out wrong.
1012@param[in] trx transaction
1013@param[in] table table
1014@param[in] mode lock mode
1015@return lock or NULL */
1016static inline bool lock_table_has(const trx_t *trx, const dict_table_t *table,
1017 enum lock_mode mode);
1019/** Handles writing the information about found deadlock to the log files
1020and caches it for future lock_latest_err_file() calls (for example used by
1022@param[in] trxs_on_cycle trxs causing deadlock, i-th waits for i+1-th
1023@param[in] victim_trx the trx from trx_on_cycle which will be rolled back */
1025 const trx_t *victim_trx);
1027#include "lock0priv.ic"
1029/** Iterate over record locks matching <space, page_no, heap_no> */
1031 /* First is the previous lock, and second is the current lock. */
1032 /** Gets the next record lock on a page.
1033 @param[in] rec_id The record ID
1034 @param[in] lock The current lock
1035 @return matching lock or nullptr if end of list */
1036 static lock_t *advance(const RecID &rec_id, lock_t *lock) {
1038 ut_ad(lock->is_record_lock());
1040 while ((lock = static_cast<lock_t *>(lock->hash)) != nullptr) {
1041 ut_ad(lock->is_record_lock());
1043 if (rec_id.matches(lock)) {
1044 return (lock);
1045 }
1046 }
1048 ut_ad(lock == nullptr);
1049 return (nullptr);
1050 }
1052 /** Gets the first explicit lock request on a record.
1053 @param[in] list Record hash
1054 @param[in] rec_id Record ID
1055 @return first lock, nullptr if none exists */
1056 static lock_t *first(hash_cell_t *list, const RecID &rec_id) {
1059 auto lock = static_cast<lock_t *>(list->node);
1061 ut_ad(lock == nullptr || lock->is_record_lock());
1063 if (lock != nullptr && !rec_id.matches(lock)) {
1064 lock = advance(rec_id, lock);
1065 }
1067 return (lock);
1068 }
1070 /** Iterate over all the locks on a specific row
1071 @param[in] rec_id Iterate over locks on this row
1072 @param[in] f Function to call for each entry
1073 @param[in] hash_table The hash table to iterate over
1074 @return lock where the callback returned false */
1075 template <typename F>
1076 static const lock_t *for_each(const RecID &rec_id, F &&f,
1077 hash_table_t *hash_table = lock_sys->rec_hash) {
1080 auto list = hash_get_nth_cell(
1081 hash_table, hash_calc_cell_id(rec_id.m_hash_value, hash_table));
1083 for (auto lock = first(list, rec_id); lock != nullptr;
1084 lock = advance(rec_id, lock)) {
1085 ut_ad(lock->is_record_lock());
1087 if (!std::forward<F>(f)(lock)) {
1088 return (lock);
1089 }
1090 }
1092 return (nullptr);
1093 }
1096namespace locksys {
1098 public:
1100 static void exclusive_latch(ut::Location location) {
1102 }
1105/** Temporarily releases trx->mutex, latches the lock-sys shard containing
1106peeked_lock and latches trx->mutex again and calls f under protection of both
1107latches. The latch on lock-sys shard will be released immediately after f
1108returns. It is a responsibility of the caller to handle shared lock-sys latch,
1109trx->mutex and verify inside f that the trx has not been finished, and the lock
1110was not released meanwhile.
1111@param[in] peeked_lock A lock of the trx. (While trx->mutex is held it can't
1112 be freed, but can be released). It is used to
1113 determine the lock-sys shard to latch.
1114@param[in] f The callback to call once the lock-sys shard is
1115 latched and trx->mutex is relatched.
1116@return The value returned by f.
1118template <typename F>
1119auto latch_peeked_shard_and_do(const lock_t *peeked_lock, F &&f) {
1121 const trx_t *trx = peeked_lock->trx;
1122 ut_ad(trx_mutex_own(trx));
1123 ut_ad(peeked_lock->trx == trx);
1124 /* peeked_wait_lock points to a lock struct which will not be freed while we
1125 hold trx->mutex. Thus it is safe to inspect the peeked_wait_lock's
1126 rec_lock.page_id and tab_lock.table. We have to make a copy of them, though,
1127 before releasing trx->mutex. */
1128 if (peeked_lock->is_record_lock()) {
1129 const auto sharded_by = peeked_lock->rec_lock.page_id;
1130 trx_mutex_exit(trx);
1131 DEBUG_SYNC_C("try_relatch_trx_and_shard_and_do_noted_expected_version");
1134 return std::forward<F>(f)();
1135 } else {
1136 /*Once we release the trx->mutex, the trx may release locks on table and
1137 commit, which in extreme case could lead to freeing the dict_table_t
1138 object, so we have to copy its id first. */
1139 const auto sharded_by = peeked_lock->tab_lock.table->id;
1140 trx_mutex_exit(trx);
1143 return std::forward<F>(f)();
1144 }
1147/** Given a pointer to trx (which the caller guarantees will not be freed) and
1148the expected value of trx->version, will call the provided function f, only if
1149the trx is still in expected version and waiting for a lock, within a critical
1150section which holds latches on the trx, and the shard containing the waiting
1151lock. If the transaction has meanwhile finished waiting for a lock, or committed
1152or rolled back etc. the f will not be called.
1153It may happen that the lock for which the trx is waiting during exectuion of f
1154is not the same as the lock it was waiting at the moment of invocation.
1155@param[in] trx_version The version of the trx that we intend to wake up
1156@param[in] f The callback to call if trx is still waiting for a
1157 lock and is still in version trx_version
1159template <typename F>
1160void run_if_waiting(const TrxVersion trx_version, F &&f) {
1161 const trx_t *trx = trx_version.m_trx;
1162 /* This code would be much simpler with Global_exclusive_latch_guard.
1163 Unfortunately, this lead to long semaphore waits when thousands of
1164 transactions were taking thousands of locks and timing out. Therefore we use
1165 the following tricky code to instead only latch the single shard which
1166 contains the trx->lock.wait_lock. This is a bit difficult, because during
1167 B-tree reorganization a record lock might be removed from one page and moved
1168 to another, temporarily setting wait_lock to nullptr. This should be very
1169 rare and short. In most cases this while loop should do just one iteration
1170 and proceed along a happy path through all ifs. Another reason wait_lock
1171 might become nullptr is because we were granted the lock meanwhile, in which
1172 case the trx->lock.blocking_trx is first set to nullptr */
1173 do {
1174 if (!trx->lock.wait_lock.load()) {
1175 continue;
1176 }
1178 /* We can't use IB_mutex_guard with trx->mutex, as trx_mutex_enter has
1179 custom logic. We want to release trx->mutex before ut_delay or return. */
1180 trx_mutex_enter(trx);
1181 auto guard = create_scope_guard([trx]() { trx_mutex_exit(trx); });
1182 if (trx->version != trx_version.m_version) {
1183 return;
1184 }
1185 if (const lock_t *peeked_wait_lock = trx->lock.wait_lock.load()) {
1186 const bool retry = latch_peeked_shard_and_do(peeked_wait_lock, [&]() {
1187 ut_ad(trx_mutex_own(trx));
1188 if (trx->version != trx_version.m_version) {
1189 return false;
1190 }
1191 if (peeked_wait_lock != trx->lock.wait_lock.load()) {
1192 /* If wait_lock has changed, then in case of record lock it might have
1193 been moved during B-tree reorganization, so we retry. In case of a
1194 table lock the wait_lock can not be "moved" so it had to be released
1195 permanently and there's no point in retrying.*/
1196 return peeked_wait_lock->is_record_lock();
1197 }
1198 std::forward<F>(f)();
1199 ut_ad(trx_mutex_own(trx));
1200 return false;
1201 });
1202 if (!retry) {
1203 return;
1204 }
1205 }
1206 /* wait_lock appears to be null. If blocking_trx isn't nullptr, then
1207 probably the wait_lock will soon be restored, otherwise we can give up */
1208 } while (trx->lock.blocking_trx.load() && ut_delay(10));
1210} // namespace locksys
1212#endif /* lock0priv_h */
static mysql_service_status_t init()
Component initialization.
void btr_assert_not_corrupted(const buf_block_t *block, const dict_index_t *index)
Assert that a B-tree page is not corrupted.
Definition: btr0btr.h:153
Create record locks.
Definition: lock0priv.h:656
ulint m_mode
Lock mode requested.
Definition: lock0priv.h:861
RecLock(dict_index_t *index, const buf_block_t *block, ulint heap_no, ulint mode)
Definition: lock0priv.h:710
RecID m_rec_id
The record lock tuple {space, page_no, heap_no}.
Definition: lock0priv.h:873
RecLock(que_thr_t *thr, dict_index_t *index, const RecID &rec_id, ulint mode)
Definition: lock0priv.h:664
static bool is_predicate_lock(ulint mode)
Definition: lock0priv.h:847
size_t lock_size() const
Definition: lock0priv.h:759
static size_t lock_size(const page_t *page)
Calculate the record lock physical size required, non-predicate lock.
Definition: lock0priv.h:836
RecLock(que_thr_t *thr, dict_index_t *index, const buf_block_t *block, ulint heap_no, ulint mode)
Definition: lock0priv.h:682
static size_t lock_size(ulint mode)
Calculate the record lock physical size required for a predicate lock.
Definition: lock0priv.h:801
size_t m_size
Size of the record lock in bytes.
Definition: lock0priv.h:865
trx_t * m_trx
Transaction requesting the record lock.
Definition: lock0priv.h:857
void init(const page_t *page)
Setup the context from the requirements.
Definition: lock0priv.h:778
que_thr_t * m_thr
The query thread of the transaction.
Definition: lock0priv.h:853
dict_index_t * m_index
Index on which the record lock is required.
Definition: lock0priv.h:869
RecLock(dict_index_t *index, const RecID &rec_id, ulint mode)
Definition: lock0priv.h:698
Definition: hash0hash.h:373
A RAII helper which latches global_latch in shared mode during constructor, and unlatches it during d...
Definition: lock0guards.h:70
void x_lock(ut::Location location)
Definition: lock0latches.h:140
void x_unlock()
Definition: lock0latches.h:141
Unique_sharded_rw_lock global_latch
Definition: lock0latches.h:253
A RAII helper which latches the mutex protecting given shard during constructor, and unlatches it dur...
Definition: lock0guards.h:90
Definition: lock0priv.h:1097
static void exclusive_latch(ut::Location location)
Definition: lock0priv.h:1100
static void exclusive_unlatch()
Definition: lock0priv.h:1099
Page identifier.
Definition: buf0types.h:206
int page
Definition: db0err.h:38
static bool dict_index_is_online_ddl(const dict_index_t *index)
Determines if a secondary index is being or has been created online, or if the table is being rebuilt...
Data dictionary global types.
#define DEBUG_SYNC_C(_sync_point_name_)
Definition: my_sys.h:213
The simple hash table utility.
static hash_cell_t * hash_get_nth_cell(hash_table_t *table, size_t n)
Gets the nth cell in a hash table.
static uint64_t hash_calc_cell_id(uint64_t hash_value, hash_table_t *table)
Calculates the cell index from a hashed value for a specified hash table.
#define UINT32_MAX
constexpr uint32_t LOCK_PRDT_PAGE
Page lock.
Definition: lock0lock.h:1000
constexpr uint32_t LOCK_MODE_MASK
Lock modes and types.
Definition: lock0lock.h:962
constexpr uint32_t LOCK_PREDICATE
Predicate lock.
Definition: lock0lock.h:998
constexpr uint32_t LOCK_WAIT
Waiting lock flag; when set, it means that the lock has not yet been granted, it is just waiting for ...
Definition: lock0lock.h:975
static uint64_t lock_rec_hash_value(const page_id_t &page_id)
Calculates the hash value of a page file address: used in inserting or searching for a lock in the ha...
constexpr uint32_t LOCK_ORDINARY
this flag denotes an ordinary next-key lock in contrast to LOCK_GAP or LOCK_REC_NOT_GAP
Definition: lock0lock.h:979
constexpr uint32_t LOCK_TYPE_MASK
mask used to extract lock type from the type_mode field in a lock
Definition: lock0lock.h:969
constexpr uint32_t LOCK_INSERT_INTENTION
this bit is set when we place a waiting gap type record lock request in order to let an insert of an ...
Definition: lock0lock.h:996
constexpr uint32_t LOCK_TABLE
Lock types.
Definition: lock0lock.h:965
lock_sys_t * lock_sys
The lock system.
static hash_table_t * lock_hash_get(ulint mode)
Get the lock hash table.
constexpr uint32_t LOCK_GAP
when this bit is set, it means that the lock holds only on the gap before the record; for instance,...
Definition: lock0lock.h:984
constexpr uint32_t LOCK_REC_NOT_GAP
this bit means that the lock is only on the index record and does NOT block inserts to the gap before...
Definition: lock0lock.h:990
constexpr uint32_t LOCK_REC
record lock
Definition: lock0lock.h:967
struct lock_prdt lock_prdt_t
static ulint lock_mode_compatible(enum lock_mode mode1, enum lock_mode mode2)
Calculates if lock mode 1 is compatible with lock mode 2.
static lock_t * lock_rec_get_first_on_page(hash_table_t *lock_hash, const buf_block_t *block)
Gets the first record lock on a page, where the page is identified by a pointer to it.
static const byte lock_strength_matrix[5][5]
Definition: lock0priv.h:576
static bool lock_mode_is_next_key_lock(ulint mode)
Checks if the mode is LOCK_S or LOCK_X (possibly ORed with LOCK_WAIT or LOCK_REC) which means the loc...
Definition: lock0priv.h:117
constexpr uint32_t MAX_STACK_SIZE
Maximum depth of the DFS stack.
Definition: lock0priv.h:585
void lock_reset_wait_and_release_thread_if_suspended(lock_t *lock)
This function is a wrapper around several functions which need to be called in particular order to wa...
static const ulint lock_types
The count of the types of locks.
Definition: lock0priv.h:878
static const byte lock_compatibility_matrix[5][5]
Definition: lock0priv.h:559
constexpr uint32_t PRDT_HEAPNO
Definition: lock0priv.h:587
static bool lock_mode_stronger_or_eq(enum lock_mode mode1, enum lock_mode mode2)
Calculates if lock mode 1 is stronger or equal to lock mode 2.
void lock_notify_about_deadlock(const ut::vector< const trx_t * > &trxs_on_cycle, const trx_t *victim_trx)
Handles writing the information about found deadlock to the log files and caches it for future lock_l...
static const lock_t * lock_rec_get_next_const(ulint heap_no, const lock_t *lock)
Gets the next explicit lock request on a record.
static const ulint LOCK_PAGE_BITMAP_MARGIN
Definition: lock0priv.h:308
static const lock_t * lock_rec_get_next_on_page_const(const lock_t *lock)
Gets the first or next record lock on a page.
static lock_t * lock_rec_get_next_on_page(lock_t *lock)
Gets the first or next record lock on a page.
static enum lock_mode lock_get_mode(const lock_t *lock)
Gets the mode of a lock.
std::ostream & operator<<(std::ostream &out, const lock_table_t &lock)
The global output operator is overloaded to conveniently print the lock_table_t object into the given...
Definition: lock0priv.h:77
static ulint lock_get_wait(const lock_t *lock)
Gets the wait flag of a lock.
bool lock_print_waits
static lock_t * lock_rec_get_first(hash_table_t *hash, const buf_block_t *block, ulint heap_no)
Gets the first explicit lock request on a record.
static trx_id_t lock_clust_rec_some_has_impl(const rec_t *rec, const dict_index_t *index, const ulint *offsets)
Checks if some transaction has an implicit x-lock on a record in a clustered index.
static bool lock_rec_get_nth_bit(const lock_t *lock, ulint i)
Gets the nth bit of a record lock.
static lock_t * lock_rec_get_first_on_page_addr(hash_table_t *lock_hash, const page_id_t &page_id)
Gets the first record lock on a page, where the page is identified by its file address.
void lock_cancel_waiting_and_release(trx_t *trx)
Cancels a waiting lock request and releases possible other transactions waiting behind it.
static uint32_t lock_get_type_low(const lock_t *lock)
Gets the type of a lock.
static bool lock_table_has(const trx_t *trx, const dict_table_t *table, enum lock_mode mode)
Checks if a transaction has the specified table lock, or stronger.
Record locking request status.
Definition: lock0priv.h:589
Failed to acquire a lock.
Definition: lock0priv.h:591
Succeeded in acquiring a lock (implicit or already acquired)
Definition: lock0priv.h:593
Explicitly created a new lock.
Definition: lock0priv.h:595
static void lock_rec_set_nth_bit(lock_t *lock, ulint i)
Sets the nth bit of a record lock to true.
static lock_t * lock_rec_get_next(ulint heap_no, lock_t *lock)
Gets the next explicit lock request on a record.
static uint32_t lock_rec_get_n_bits(const lock_t *lock)
Gets the number of bits in a record lock bitmap.
const lock_t * lock_rec_get_prev(const lock_t *in_lock, ulint heap_no)
Gets the previous record lock set on a record.
Lock module internal inline methods.
const char * lock_mode_string(enum lock_mode mode)
Convert the given enum value into string.
Definition: lock0types.h:66
Definition: lock0types.h:51
Definition: lock0types.h:54
Definition: lock0types.h:55
unsigned long long int ulonglong
Definition: my_inttypes.h:55
Provides atomic access in shared-exclusive modes.
Definition: shared_spin_lock.h:78
Definition: lock0guards.h:33
bool owns_page_shard(const page_id_t &page_id)
Tests if given page shard can be safely accessed by the current thread.
auto latch_peeked_shard_and_do(const lock_t *peeked_lock, F &&f)
Temporarily releases trx->mutex, latches the lock-sys shard containing peeked_lock and latches trx->m...
Definition: lock0priv.h:1119
void run_if_waiting(const TrxVersion trx_version, F &&f)
Given a pointer to trx (which the caller guarantees will not be freed) and the expected value of trx-...
Definition: lock0priv.h:1160
bool owns_shared_global_latch()
Tests if lock_sys latch is owned in shared mode by the current thread.
static mysql_service_status_t create(const char *service_names[], reference_caching_channel *out_channel) noexcept
Definition: varlen_sort.h:183
Definition: file_handle.h:59
bool wait_for(TCondition cond, std::chrono::steady_clock::duration max_wait)
Delays execution for at most max_wait or returns earlier if cond becomes true.
Definition: ut0ut.ic:130
std::basic_ostringstream< char, std::char_traits< char >, ut::allocator< char > > ostringstream
Specialization of basic_ostringstream which uses ut::allocator.
Definition: ut0new.h:2869
std::vector< T, ut::allocator< T > > vector
Specialization of vector which uses allocator.
Definition: ut0new.h:2873
std::list< T, ut::allocator< T > > list
Specialization of list which uses ut_allocator.
Definition: ut0new.h:2877
static uint16_t page_dir_get_n_heap(const page_t *page)
Gets the number of records in the heap.
constexpr ulint PAGE_HEAP_NO_INFIMUM
Page infimum.
Definition: page0types.h:130
constexpr ulint PAGE_HEAP_NO_SUPREMUM
Page supremum.
Definition: page0types.h:132
byte page_t
Type of the index page.
Definition: page0types.h:151
static trx_t * thr_get_trx(que_thr_t *thr)
Gets the trx of a query thread.
byte rec_t
Definition: rem0types.h:40
required string type
Definition: replication_group_member_actions.proto:33
Scope_guard< TLambda > create_scope_guard(const TLambda rollback_lambda)
Definition: scope_guard.h:60
bool srv_read_only_mode
Set if InnoDB must operate in read-only mode.
Iterate over record locks matching <space, page_no, heap_no>
Definition: lock0priv.h:1030
static lock_t * advance(const RecID &rec_id, lock_t *lock)
Gets the next record lock on a page.
Definition: lock0priv.h:1036
static lock_t * first(hash_cell_t *list, const RecID &rec_id)
Gets the first explicit lock request on a record.
Definition: lock0priv.h:1056
static const lock_t * for_each(const RecID &rec_id, F &&f, hash_table_t *hash_table=lock_sys->rec_hash)
Iterate over all the locks on a specific row.
Definition: lock0priv.h:1076
Record lock ID.
Definition: lock0priv.h:600
bool is_supremum() const
Definition: lock0priv.h:632
uint64_t m_hash_value
Hash generated from record's location which will be used to get lock queue for this record.
Definition: lock0priv.h:651
uint64_t hash_value() const
Definition: lock0priv.h:629
const page_id_t & get_page_id() const
Definition: lock0priv.h:639
RecID(page_id_t page_id, uint32_t heap_no)
Definition: lock0priv.h:612
RecID(const buf_block_t *block, ulint heap_no)
Definition: lock0priv.h:624
uint32_t m_heap_no
Heap number within the page.
Definition: lock0priv.h:646
bool matches(const lock_t *lock) const
Definition: lock0priv.ic:295
page_id_t m_page_id
Tablespace ID and page number within space
Definition: lock0priv.h:642
RecID(const lock_t *lock, ulint heap_no)
Definition: lock0priv.h:604
Definition: trx0types.h:597
uint64_t m_version
Definition: trx0types.h:601
trx_t * m_trx
Definition: trx0types.h:600
The buffer control block structure.
Definition: buf0buf.h:1750
byte * frame
pointer to buffer frame which is of size UNIV_PAGE_SIZE, and aligned to an address divisible by UNIV_...
Definition: buf0buf.h:1772
Data structure for an index.
Definition: dict0mem.h:1045
Data structure for a database table.
Definition: dict0mem.h:1908
table_id_t id
Id of the table.
Definition: dict0mem.h:1969
table_name_t name
Table name.
Definition: dict0mem.h:1983
Definition: hash0hash.h:60
Definition: lock0prdt.h:39
Record lock for a page.
Definition: lock0priv.h:82
std::ostream & print(std::ostream &out) const
Print the record lock into the given output stream.
Definition: lock0priv.h:100
uint32_t n_bits
number of bits in the lock bitmap; Must be divisible by 8.
Definition: lock0priv.h:89
page_id_t page_id
The id of the page on which records referenced by this lock's bitmap are located.
Definition: lock0priv.h:85
locksys::Latches latches
The latches protecting queues of record and table locks.
Definition: lock0lock.h:1021
hash_table_t * rec_hash
The hash table of the record (LOCK_REC) locks, except for predicate (LOCK_PREDICATE) and predicate pa...
Definition: lock0lock.h:1025
Lock struct; protected by lock_sys latches.
Definition: lock0priv.h:135
bool is_record_not_gap() const
Definition: lock0priv.h:202
dict_index_t * index
Index for a record lock.
Definition: lock0priv.h:143
lock_table_t tab_lock
Table lock.
Definition: lock0priv.h:151
lock_mode mode() const
Definition: lock0priv.h:223
const char * type_string() const
Definition: lock0priv.h:244
lock_rec_t rec_lock
Record lock.
Definition: lock0priv.h:154
bool includes_supremum() const
Definition: lock0priv.h:215
bool is_gap() const
Definition: lock0priv.h:199
ulonglong m_psi_internal_thread_id
Performance schema thread that created the lock.
Definition: lock0priv.h:160
bool is_insert_intention() const
Definition: lock0priv.h:210
bool is_record_lock() const
Determine if the lock object is a record lock.
Definition: lock0priv.h:187
trx_que_t trx_que_state() const
Definition: lock0priv.h:232
std::ostream & print(std::ostream &out) const
Print the lock object into the given output stream.
Definition: lock0priv.h:283
bool is_waiting() const
Definition: lock0priv.h:196
lock_t * hash
Hash chain node for a record lock.
Definition: lock0priv.h:147
ulonglong m_psi_event_id
Performance schema event that created the lock.
Definition: lock0priv.h:163
uint32_t type_mode
The lock type and mode bit flags.
Definition: lock0priv.h:169
trx_t * trx
transaction owning the lock
Definition: lock0priv.h:137
uint64_t m_seq
Timestamp when it was created.
Definition: lock0priv.h:173
bool is_next_key_lock() const
Definition: lock0priv.h:205
bool is_predicate() const
Determine if it is predicate lock.
Definition: lock0priv.h:191
uint32_t type() const
Definition: lock0priv.h:220
UT_LIST_NODE_T(lock_t) trx_locks
list of the locks of the transaction
void unlock_gap_lock()
Unlock the GAP Lock part of this Next Key Lock.
Definition: lock0priv.h:177
hash_table_t * hash_table() const
Get lock hash table.
Definition: lock0priv.h:229
A table lock.
Definition: lock0priv.h:52
std::ostream & print(std::ostream &out) const
Print the table lock into the given output stream.
Definition: lock0priv.h:67
dict_table_t * table
database table in dictionary cache
Definition: lock0priv.h:53
list of locks on the same table
Definition: lock0priv.h:56
Definition: que0que.h:241
std::atomic< trx_t * > blocking_trx
If this transaction is waiting for a lock, then blocking_trx points to a transaction which holds a co...
Definition: trx0trx.h:447
std::atomic< lock_t * > wait_lock
The lock request of this transaction is waiting for.
Definition: trx0trx.h:468
trx_que_t que_state
valid when trx->state == TRX_STATE_ACTIVE: TRX_QUE_RUNNING, TRX_QUE_LOCK_WAIT, ...
Definition: trx0trx.h:415
Definition: trx0trx.h:683
std::atomic_uint64_t version
Version of this instance.
Definition: trx0trx.h:1082
trx_lock_t lock
Information about the transaction locks and state.
Definition: trx0trx.h:830
Definition: ut0core.h:35
#define trx_mutex_enter_first_of_two(t)
Acquire the trx->mutex (and indicate we might request one more).
Definition: trx0trx.h:1393
#define trx_mutex_exit(t)
Release the trx->mutex.
Definition: trx0trx.h:1396
#define trx_mutex_enter(t)
Acquire the trx->mutex (and promise not to request any more).
Definition: trx0trx.h:1390
bool trx_mutex_own(const trx_t *trx)
Test if trx->mutex is owned by the current thread.
Definition: trx0trx.h:1353
Transaction system global type definitions.
Transaction execution states when trx->state == TRX_STATE_ACTIVE.
Definition: trx0types.h:70
ib_id_t trx_id_t
Transaction identifier (DB_TRX_ID, DATA_TRX_ID)
Definition: trx0types.h:137
Version control for database, common definitions, and include files.
constexpr size_t UNIV_WORD_SIZE
MySQL config.h generated by CMake will define SIZEOF_LONG in Posix.
Definition: univ.i:277
unsigned long int ulint
Definition: univ.i:405
#define UT_ARR_SIZE(a)
Definition: univ.i:523
Definition: ut0core.h:72
#define ut_error
Abort execution.
Definition: ut0dbg.h:64
#define ut_ad(EXPR)
Debug assertion.
Definition: ut0dbg.h:68
A helper for the UT_LIST_BASE_NODE_T_EXTERN which declares a node getter struct which extracts member...
Definition: ut0lst.h:269
#define UT_LIST_NODE_T(t)
Macro used for legacy reasons.
Definition: ut0lst.h:63
ulint ut_delay(ulint delay)
Runs an idle loop on CPU.
static task_env * retry
static void prepare(pax_msg *p, pax_op op)