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