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