1 | /***************************************************************************** |
2 | |
3 | Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. |
4 | Copyright (c) 2017, 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/lock0lock.h |
22 | The transaction lock system |
23 | |
24 | Created 5/7/1996 Heikki Tuuri |
25 | *******************************************************/ |
26 | |
27 | #ifndef lock0lock_h |
28 | #define lock0lock_h |
29 | |
30 | #include "univ.i" |
31 | #include "buf0types.h" |
32 | #include "trx0types.h" |
33 | #include "mtr0types.h" |
34 | #include "rem0types.h" |
35 | #include "dict0types.h" |
36 | #include "que0types.h" |
37 | #include "lock0types.h" |
38 | #include "hash0hash.h" |
39 | #include "srv0srv.h" |
40 | #include "ut0vec.h" |
41 | #include "gis0rtree.h" |
42 | #include "lock0prdt.h" |
43 | |
44 | /** Alternatives for innodb_lock_schedule_algorithm, which can be changed by |
45 | setting innodb_lock_schedule_algorithm. */ |
46 | enum innodb_lock_schedule_algorithm_t { |
47 | /*!< First Come First Served */ |
48 | INNODB_LOCK_SCHEDULE_ALGORITHM_FCFS, |
49 | /*!< Variance-Aware-Transaction-Scheduling */ |
50 | INNODB_LOCK_SCHEDULE_ALGORITHM_VATS |
51 | }; |
52 | |
53 | extern ulong innodb_lock_schedule_algorithm; |
54 | |
55 | // Forward declaration |
56 | class ReadView; |
57 | |
58 | /** The value of innodb_deadlock_detect */ |
59 | extern my_bool innobase_deadlock_detect; |
60 | |
61 | /*********************************************************************//** |
62 | Gets the size of a lock struct. |
63 | @return size in bytes */ |
64 | ulint |
65 | lock_get_size(void); |
66 | /*===============*/ |
67 | /*********************************************************************//** |
68 | Gets the heap_no of the smallest user record on a page. |
69 | @return heap_no of smallest user record, or PAGE_HEAP_NO_SUPREMUM */ |
70 | UNIV_INLINE |
71 | ulint |
72 | lock_get_min_heap_no( |
73 | /*=================*/ |
74 | const buf_block_t* block); /*!< in: buffer block */ |
75 | /*************************************************************//** |
76 | Updates the lock table when we have reorganized a page. NOTE: we copy |
77 | also the locks set on the infimum of the page; the infimum may carry |
78 | locks if an update of a record is occurring on the page, and its locks |
79 | were temporarily stored on the infimum. */ |
80 | void |
81 | lock_move_reorganize_page( |
82 | /*======================*/ |
83 | const buf_block_t* block, /*!< in: old index page, now |
84 | reorganized */ |
85 | const buf_block_t* oblock);/*!< in: copy of the old, not |
86 | reorganized page */ |
87 | /*************************************************************//** |
88 | Moves the explicit locks on user records to another page if a record |
89 | list end is moved to another page. */ |
90 | void |
91 | lock_move_rec_list_end( |
92 | /*===================*/ |
93 | const buf_block_t* new_block, /*!< in: index page to move to */ |
94 | const buf_block_t* block, /*!< in: index page */ |
95 | const rec_t* rec); /*!< in: record on page: this |
96 | is the first record moved */ |
97 | /*************************************************************//** |
98 | Moves the explicit locks on user records to another page if a record |
99 | list start is moved to another page. */ |
100 | void |
101 | lock_move_rec_list_start( |
102 | /*=====================*/ |
103 | const buf_block_t* new_block, /*!< in: index page to move to */ |
104 | const buf_block_t* block, /*!< in: index page */ |
105 | const rec_t* rec, /*!< in: record on page: |
106 | this is the first |
107 | record NOT copied */ |
108 | const rec_t* old_end); /*!< in: old |
109 | previous-to-last |
110 | record on new_page |
111 | before the records |
112 | were copied */ |
113 | /*************************************************************//** |
114 | Updates the lock table when a page is split to the right. */ |
115 | void |
116 | lock_update_split_right( |
117 | /*====================*/ |
118 | const buf_block_t* right_block, /*!< in: right page */ |
119 | const buf_block_t* left_block); /*!< in: left page */ |
120 | /*************************************************************//** |
121 | Updates the lock table when a page is merged to the right. */ |
122 | void |
123 | lock_update_merge_right( |
124 | /*====================*/ |
125 | const buf_block_t* right_block, /*!< in: right page to |
126 | which merged */ |
127 | const rec_t* orig_succ, /*!< in: original |
128 | successor of infimum |
129 | on the right page |
130 | before merge */ |
131 | const buf_block_t* left_block); /*!< in: merged index |
132 | page which will be |
133 | discarded */ |
134 | /*************************************************************//** |
135 | Updates the lock table when the root page is copied to another in |
136 | btr_root_raise_and_insert. Note that we leave lock structs on the |
137 | root page, even though they do not make sense on other than leaf |
138 | pages: the reason is that in a pessimistic update the infimum record |
139 | of the root page will act as a dummy carrier of the locks of the record |
140 | to be updated. */ |
141 | void |
142 | lock_update_root_raise( |
143 | /*===================*/ |
144 | const buf_block_t* block, /*!< in: index page to which copied */ |
145 | const buf_block_t* root); /*!< in: root page */ |
146 | /*************************************************************//** |
147 | Updates the lock table when a page is copied to another and the original page |
148 | is removed from the chain of leaf pages, except if page is the root! */ |
149 | void |
150 | lock_update_copy_and_discard( |
151 | /*=========================*/ |
152 | const buf_block_t* new_block, /*!< in: index page to |
153 | which copied */ |
154 | const buf_block_t* block); /*!< in: index page; |
155 | NOT the root! */ |
156 | /*************************************************************//** |
157 | Updates the lock table when a page is split to the left. */ |
158 | void |
159 | lock_update_split_left( |
160 | /*===================*/ |
161 | const buf_block_t* right_block, /*!< in: right page */ |
162 | const buf_block_t* left_block); /*!< in: left page */ |
163 | /*************************************************************//** |
164 | Updates the lock table when a page is merged to the left. */ |
165 | void |
166 | lock_update_merge_left( |
167 | /*===================*/ |
168 | const buf_block_t* left_block, /*!< in: left page to |
169 | which merged */ |
170 | const rec_t* orig_pred, /*!< in: original predecessor |
171 | of supremum on the left page |
172 | before merge */ |
173 | const buf_block_t* right_block); /*!< in: merged index page |
174 | which will be discarded */ |
175 | /*************************************************************//** |
176 | Updates the lock table when a page is split and merged to |
177 | two pages. */ |
178 | UNIV_INTERN |
179 | void |
180 | lock_update_split_and_merge( |
181 | const buf_block_t* left_block, /*!< in: left page to which merged */ |
182 | const rec_t* orig_pred, /*!< in: original predecessor of |
183 | supremum on the left page before merge*/ |
184 | const buf_block_t* right_block);/*!< in: right page from which merged */ |
185 | /*************************************************************//** |
186 | Resets the original locks on heir and replaces them with gap type locks |
187 | inherited from rec. */ |
188 | void |
189 | lock_rec_reset_and_inherit_gap_locks( |
190 | /*=================================*/ |
191 | const buf_block_t* heir_block, /*!< in: block containing the |
192 | record which inherits */ |
193 | const buf_block_t* block, /*!< in: block containing the |
194 | record from which inherited; |
195 | does NOT reset the locks on |
196 | this record */ |
197 | ulint heir_heap_no, /*!< in: heap_no of the |
198 | inheriting record */ |
199 | ulint heap_no); /*!< in: heap_no of the |
200 | donating record */ |
201 | /*************************************************************//** |
202 | Updates the lock table when a page is discarded. */ |
203 | void |
204 | lock_update_discard( |
205 | /*================*/ |
206 | const buf_block_t* heir_block, /*!< in: index page |
207 | which will inherit the locks */ |
208 | ulint heir_heap_no, /*!< in: heap_no of the record |
209 | which will inherit the locks */ |
210 | const buf_block_t* block); /*!< in: index page |
211 | which will be discarded */ |
212 | /*************************************************************//** |
213 | Updates the lock table when a new user record is inserted. */ |
214 | void |
215 | lock_update_insert( |
216 | /*===============*/ |
217 | const buf_block_t* block, /*!< in: buffer block containing rec */ |
218 | const rec_t* rec); /*!< in: the inserted record */ |
219 | /*************************************************************//** |
220 | Updates the lock table when a record is removed. */ |
221 | void |
222 | lock_update_delete( |
223 | /*===============*/ |
224 | const buf_block_t* block, /*!< in: buffer block containing rec */ |
225 | const rec_t* rec); /*!< in: the record to be removed */ |
226 | /*********************************************************************//** |
227 | Stores on the page infimum record the explicit locks of another record. |
228 | This function is used to store the lock state of a record when it is |
229 | updated and the size of the record changes in the update. The record |
230 | is in such an update moved, perhaps to another page. The infimum record |
231 | acts as a dummy carrier record, taking care of lock releases while the |
232 | actual record is being moved. */ |
233 | void |
234 | lock_rec_store_on_page_infimum( |
235 | /*===========================*/ |
236 | const buf_block_t* block, /*!< in: buffer block containing rec */ |
237 | const rec_t* rec); /*!< in: record whose lock state |
238 | is stored on the infimum |
239 | record of the same page; lock |
240 | bits are reset on the |
241 | record */ |
242 | /*********************************************************************//** |
243 | Restores the state of explicit lock requests on a single record, where the |
244 | state was stored on the infimum of the page. */ |
245 | void |
246 | lock_rec_restore_from_page_infimum( |
247 | /*===============================*/ |
248 | const buf_block_t* block, /*!< in: buffer block containing rec */ |
249 | const rec_t* rec, /*!< in: record whose lock state |
250 | is restored */ |
251 | const buf_block_t* donator);/*!< in: page (rec is not |
252 | necessarily on this page) |
253 | whose infimum stored the lock |
254 | state; lock bits are reset on |
255 | the infimum */ |
256 | /*********************************************************************//** |
257 | Determines if there are explicit record locks on a page. |
258 | @return an explicit record lock on the page, or NULL if there are none */ |
259 | lock_t* |
260 | lock_rec_expl_exist_on_page( |
261 | /*========================*/ |
262 | ulint space, /*!< in: space id */ |
263 | ulint page_no)/*!< in: page number */ |
264 | MY_ATTRIBUTE((warn_unused_result)); |
265 | /*********************************************************************//** |
266 | Checks if locks of other transactions prevent an immediate insert of |
267 | a record. If they do, first tests if the query thread should anyway |
268 | be suspended for some reason; if not, then puts the transaction and |
269 | the query thread to the lock wait state and inserts a waiting request |
270 | for a gap x-lock to the lock queue. |
271 | @return DB_SUCCESS, DB_LOCK_WAIT, or DB_DEADLOCK */ |
272 | dberr_t |
273 | lock_rec_insert_check_and_lock( |
274 | /*===========================*/ |
275 | ulint flags, /*!< in: if BTR_NO_LOCKING_FLAG bit is |
276 | set, does nothing */ |
277 | const rec_t* rec, /*!< in: record after which to insert */ |
278 | buf_block_t* block, /*!< in/out: buffer block of rec */ |
279 | dict_index_t* index, /*!< in: index */ |
280 | que_thr_t* thr, /*!< in: query thread */ |
281 | mtr_t* mtr, /*!< in/out: mini-transaction */ |
282 | bool* inherit)/*!< out: set to true if the new |
283 | inserted record maybe should inherit |
284 | LOCK_GAP type locks from the successor |
285 | record */ |
286 | MY_ATTRIBUTE((warn_unused_result)); |
287 | |
288 | /*********************************************************************//** |
289 | Checks if locks of other transactions prevent an immediate modify (update, |
290 | delete mark, or delete unmark) of a clustered index record. If they do, |
291 | first tests if the query thread should anyway be suspended for some |
292 | reason; if not, then puts the transaction and the query thread to the |
293 | lock wait state and inserts a waiting request for a record x-lock to the |
294 | lock queue. |
295 | @return DB_SUCCESS, DB_LOCK_WAIT, or DB_DEADLOCK */ |
296 | dberr_t |
297 | lock_clust_rec_modify_check_and_lock( |
298 | /*=================================*/ |
299 | ulint flags, /*!< in: if BTR_NO_LOCKING_FLAG |
300 | bit is set, does nothing */ |
301 | const buf_block_t* block, /*!< in: buffer block of rec */ |
302 | const rec_t* rec, /*!< in: record which should be |
303 | modified */ |
304 | dict_index_t* index, /*!< in: clustered index */ |
305 | const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */ |
306 | que_thr_t* thr) /*!< in: query thread */ |
307 | MY_ATTRIBUTE((warn_unused_result)); |
308 | /*********************************************************************//** |
309 | Checks if locks of other transactions prevent an immediate modify |
310 | (delete mark or delete unmark) of a secondary index record. |
311 | @return DB_SUCCESS, DB_LOCK_WAIT, or DB_DEADLOCK */ |
312 | dberr_t |
313 | lock_sec_rec_modify_check_and_lock( |
314 | /*===============================*/ |
315 | ulint flags, /*!< in: if BTR_NO_LOCKING_FLAG |
316 | bit is set, does nothing */ |
317 | buf_block_t* block, /*!< in/out: buffer block of rec */ |
318 | const rec_t* rec, /*!< in: record which should be |
319 | modified; NOTE: as this is a secondary |
320 | index, we always have to modify the |
321 | clustered index record first: see the |
322 | comment below */ |
323 | dict_index_t* index, /*!< in: secondary index */ |
324 | que_thr_t* thr, /*!< in: query thread |
325 | (can be NULL if BTR_NO_LOCKING_FLAG) */ |
326 | mtr_t* mtr) /*!< in/out: mini-transaction */ |
327 | MY_ATTRIBUTE((warn_unused_result)); |
328 | /*********************************************************************//** |
329 | Like lock_clust_rec_read_check_and_lock(), but reads a |
330 | secondary index record. |
331 | @return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, or DB_DEADLOCK */ |
332 | dberr_t |
333 | lock_sec_rec_read_check_and_lock( |
334 | /*=============================*/ |
335 | ulint flags, /*!< in: if BTR_NO_LOCKING_FLAG |
336 | bit is set, does nothing */ |
337 | const buf_block_t* block, /*!< in: buffer block of rec */ |
338 | const rec_t* rec, /*!< in: user record or page |
339 | supremum record which should |
340 | be read or passed over by a |
341 | read cursor */ |
342 | dict_index_t* index, /*!< in: secondary index */ |
343 | const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */ |
344 | lock_mode mode, /*!< in: mode of the lock which |
345 | the read cursor should set on |
346 | records: LOCK_S or LOCK_X; the |
347 | latter is possible in |
348 | SELECT FOR UPDATE */ |
349 | ulint gap_mode,/*!< in: LOCK_ORDINARY, LOCK_GAP, or |
350 | LOCK_REC_NOT_GAP */ |
351 | que_thr_t* thr); /*!< in: query thread */ |
352 | /*********************************************************************//** |
353 | Checks if locks of other transactions prevent an immediate read, or passing |
354 | over by a read cursor, of a clustered index record. If they do, first tests |
355 | if the query thread should anyway be suspended for some reason; if not, then |
356 | puts the transaction and the query thread to the lock wait state and inserts a |
357 | waiting request for a record lock to the lock queue. Sets the requested mode |
358 | lock on the record. |
359 | @return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, or DB_DEADLOCK */ |
360 | dberr_t |
361 | lock_clust_rec_read_check_and_lock( |
362 | /*===============================*/ |
363 | ulint flags, /*!< in: if BTR_NO_LOCKING_FLAG |
364 | bit is set, does nothing */ |
365 | const buf_block_t* block, /*!< in: buffer block of rec */ |
366 | const rec_t* rec, /*!< in: user record or page |
367 | supremum record which should |
368 | be read or passed over by a |
369 | read cursor */ |
370 | dict_index_t* index, /*!< in: clustered index */ |
371 | const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */ |
372 | lock_mode mode, /*!< in: mode of the lock which |
373 | the read cursor should set on |
374 | records: LOCK_S or LOCK_X; the |
375 | latter is possible in |
376 | SELECT FOR UPDATE */ |
377 | ulint gap_mode,/*!< in: LOCK_ORDINARY, LOCK_GAP, or |
378 | LOCK_REC_NOT_GAP */ |
379 | que_thr_t* thr); /*!< in: query thread */ |
380 | /*********************************************************************//** |
381 | Checks if locks of other transactions prevent an immediate read, or passing |
382 | over by a read cursor, of a clustered index record. If they do, first tests |
383 | if the query thread should anyway be suspended for some reason; if not, then |
384 | puts the transaction and the query thread to the lock wait state and inserts a |
385 | waiting request for a record lock to the lock queue. Sets the requested mode |
386 | lock on the record. This is an alternative version of |
387 | lock_clust_rec_read_check_and_lock() that does not require the parameter |
388 | "offsets". |
389 | @return DB_SUCCESS, DB_LOCK_WAIT, or DB_DEADLOCK */ |
390 | dberr_t |
391 | lock_clust_rec_read_check_and_lock_alt( |
392 | /*===================================*/ |
393 | ulint flags, /*!< in: if BTR_NO_LOCKING_FLAG |
394 | bit is set, does nothing */ |
395 | const buf_block_t* block, /*!< in: buffer block of rec */ |
396 | const rec_t* rec, /*!< in: user record or page |
397 | supremum record which should |
398 | be read or passed over by a |
399 | read cursor */ |
400 | dict_index_t* index, /*!< in: clustered index */ |
401 | lock_mode mode, /*!< in: mode of the lock which |
402 | the read cursor should set on |
403 | records: LOCK_S or LOCK_X; the |
404 | latter is possible in |
405 | SELECT FOR UPDATE */ |
406 | ulint gap_mode,/*!< in: LOCK_ORDINARY, LOCK_GAP, or |
407 | LOCK_REC_NOT_GAP */ |
408 | que_thr_t* thr) /*!< in: query thread */ |
409 | MY_ATTRIBUTE((warn_unused_result)); |
410 | /*********************************************************************//** |
411 | Checks that a record is seen in a consistent read. |
412 | @return true if sees, or false if an earlier version of the record |
413 | should be retrieved */ |
414 | bool |
415 | lock_clust_rec_cons_read_sees( |
416 | /*==========================*/ |
417 | const rec_t* rec, /*!< in: user record which should be read or |
418 | passed over by a read cursor */ |
419 | dict_index_t* index, /*!< in: clustered index */ |
420 | const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */ |
421 | ReadView* view); /*!< in: consistent read view */ |
422 | /*********************************************************************//** |
423 | Checks that a non-clustered index record is seen in a consistent read. |
424 | |
425 | NOTE that a non-clustered index page contains so little information on |
426 | its modifications that also in the case false, the present version of |
427 | rec may be the right, but we must check this from the clustered index |
428 | record. |
429 | |
430 | @return true if certainly sees, or false if an earlier version of the |
431 | clustered index record might be needed */ |
432 | bool |
433 | lock_sec_rec_cons_read_sees( |
434 | /*========================*/ |
435 | const rec_t* rec, /*!< in: user record which |
436 | should be read or passed over |
437 | by a read cursor */ |
438 | const dict_index_t* index, /*!< in: index */ |
439 | const ReadView* view) /*!< in: consistent read view */ |
440 | MY_ATTRIBUTE((warn_unused_result)); |
441 | /*********************************************************************//** |
442 | Locks the specified database table in the mode given. If the lock cannot |
443 | be granted immediately, the query thread is put to wait. |
444 | @return DB_SUCCESS, DB_LOCK_WAIT, or DB_DEADLOCK */ |
445 | dberr_t |
446 | lock_table( |
447 | /*=======*/ |
448 | ulint flags, /*!< in: if BTR_NO_LOCKING_FLAG bit is set, |
449 | does nothing */ |
450 | dict_table_t* table, /*!< in/out: database table |
451 | in dictionary cache */ |
452 | lock_mode mode, /*!< in: lock mode */ |
453 | que_thr_t* thr) /*!< in: query thread */ |
454 | MY_ATTRIBUTE((warn_unused_result)); |
455 | /*********************************************************************//** |
456 | Creates a table IX lock object for a resurrected transaction. */ |
457 | void |
458 | lock_table_ix_resurrect( |
459 | /*====================*/ |
460 | dict_table_t* table, /*!< in/out: table */ |
461 | trx_t* trx); /*!< in/out: transaction */ |
462 | |
463 | /** Sets a lock on a table based on the given mode. |
464 | @param[in] table table to lock |
465 | @param[in,out] trx transaction |
466 | @param[in] mode LOCK_X or LOCK_S |
467 | @return error code or DB_SUCCESS. */ |
468 | dberr_t |
469 | lock_table_for_trx( |
470 | dict_table_t* table, |
471 | trx_t* trx, |
472 | enum lock_mode mode) |
473 | MY_ATTRIBUTE((nonnull, warn_unused_result)); |
474 | |
475 | /*************************************************************//** |
476 | Removes a granted record lock of a transaction from the queue and grants |
477 | locks to other transactions waiting in the queue if they now are entitled |
478 | to a lock. */ |
479 | void |
480 | lock_rec_unlock( |
481 | /*============*/ |
482 | trx_t* trx, /*!< in/out: transaction that has |
483 | set a record lock */ |
484 | const buf_block_t* block, /*!< in: buffer block containing rec */ |
485 | const rec_t* rec, /*!< in: record */ |
486 | lock_mode lock_mode);/*!< in: LOCK_S or LOCK_X */ |
487 | /*********************************************************************//** |
488 | Releases a transaction's locks, and releases possible other transactions |
489 | waiting because of these locks. Change the state of the transaction to |
490 | TRX_STATE_COMMITTED_IN_MEMORY. */ |
491 | void |
492 | lock_trx_release_locks( |
493 | /*===================*/ |
494 | trx_t* trx); /*!< in/out: transaction */ |
495 | |
496 | /*********************************************************************//** |
497 | Calculates the fold value of a page file address: used in inserting or |
498 | searching for a lock in the hash table. |
499 | @return folded value */ |
500 | UNIV_INLINE |
501 | ulint |
502 | lock_rec_fold( |
503 | /*==========*/ |
504 | ulint space, /*!< in: space */ |
505 | ulint page_no)/*!< in: page number */ |
506 | MY_ATTRIBUTE((const)); |
507 | /*********************************************************************//** |
508 | Calculates the hash value of a page file address: used in inserting or |
509 | searching for a lock in the hash table. |
510 | @return hashed value */ |
511 | UNIV_INLINE |
512 | unsigned |
513 | lock_rec_hash( |
514 | /*==========*/ |
515 | ulint space, /*!< in: space */ |
516 | ulint page_no);/*!< in: page number */ |
517 | |
518 | /*************************************************************//** |
519 | Get the lock hash table */ |
520 | UNIV_INLINE |
521 | hash_table_t* |
522 | lock_hash_get( |
523 | /*==========*/ |
524 | ulint mode); /*!< in: lock mode */ |
525 | |
526 | /**********************************************************************//** |
527 | Looks for a set bit in a record lock bitmap. Returns ULINT_UNDEFINED, |
528 | if none found. |
529 | @return bit index == heap number of the record, or ULINT_UNDEFINED if |
530 | none found */ |
531 | ulint |
532 | lock_rec_find_set_bit( |
533 | /*==================*/ |
534 | const lock_t* lock); /*!< in: record lock with at least one |
535 | bit set */ |
536 | |
537 | /*********************************************************************//** |
538 | Checks if a lock request lock1 has to wait for request lock2. |
539 | @return whether lock1 has to wait for lock2 to be removed */ |
540 | bool |
541 | lock_has_to_wait( |
542 | /*=============*/ |
543 | const lock_t* lock1, /*!< in: waiting lock */ |
544 | const lock_t* lock2); /*!< in: another lock; NOTE that it is |
545 | assumed that this has a lock bit set |
546 | on the same record as in lock1 if the |
547 | locks are record locks */ |
548 | /*********************************************************************//** |
549 | Reports that a transaction id is insensible, i.e., in the future. */ |
550 | void |
551 | lock_report_trx_id_insanity( |
552 | /*========================*/ |
553 | trx_id_t trx_id, /*!< in: trx id */ |
554 | const rec_t* rec, /*!< in: user record */ |
555 | dict_index_t* index, /*!< in: index */ |
556 | const ulint* offsets, /*!< in: rec_get_offsets(rec, index) */ |
557 | trx_id_t max_trx_id); /*!< in: trx_sys.get_max_trx_id() */ |
558 | /*********************************************************************//** |
559 | Prints info of locks for all transactions. |
560 | @return FALSE if not able to obtain lock mutex and exits without |
561 | printing info */ |
562 | ibool |
563 | lock_print_info_summary( |
564 | /*====================*/ |
565 | FILE* file, /*!< in: file where to print */ |
566 | ibool nowait) /*!< in: whether to wait for the lock mutex */ |
567 | MY_ATTRIBUTE((warn_unused_result)); |
568 | |
569 | /** Prints transaction lock wait and MVCC state. |
570 | @param[in,out] file file where to print |
571 | @param[in] trx transaction */ |
572 | void |
573 | lock_trx_print_wait_and_mvcc_state( |
574 | FILE* file, |
575 | const trx_t* trx); |
576 | |
577 | /*********************************************************************//** |
578 | Prints info of locks for each transaction. This function assumes that the |
579 | caller holds the lock mutex and more importantly it will release the lock |
580 | mutex on behalf of the caller. (This should be fixed in the future). */ |
581 | void |
582 | lock_print_info_all_transactions( |
583 | /*=============================*/ |
584 | FILE* file); /*!< in: file where to print */ |
585 | /*********************************************************************//** |
586 | Return approximate number or record locks (bits set in the bitmap) for |
587 | this transaction. Since delete-marked records may be removed, the |
588 | record count will not be precise. |
589 | The caller must be holding lock_sys.mutex. */ |
590 | ulint |
591 | lock_number_of_rows_locked( |
592 | /*=======================*/ |
593 | const trx_lock_t* trx_lock) /*!< in: transaction locks */ |
594 | MY_ATTRIBUTE((warn_unused_result)); |
595 | |
596 | /*********************************************************************//** |
597 | Return the number of table locks for a transaction. |
598 | The caller must be holding lock_sys.mutex. */ |
599 | ulint |
600 | lock_number_of_tables_locked( |
601 | /*=========================*/ |
602 | const trx_lock_t* trx_lock) /*!< in: transaction locks */ |
603 | MY_ATTRIBUTE((warn_unused_result)); |
604 | |
605 | /*******************************************************************//** |
606 | Gets the type of a lock. Non-inline version for using outside of the |
607 | lock module. |
608 | @return LOCK_TABLE or LOCK_REC */ |
609 | ulint |
610 | lock_get_type( |
611 | /*==========*/ |
612 | const lock_t* lock); /*!< in: lock */ |
613 | |
614 | /*******************************************************************//** |
615 | Gets the trx of the lock. Non-inline version for using outside of the |
616 | lock module. |
617 | @return trx_t* */ |
618 | UNIV_INTERN |
619 | trx_t* |
620 | lock_get_trx( |
621 | /*=========*/ |
622 | const lock_t* lock); /*!< in: lock */ |
623 | |
624 | /*******************************************************************//** |
625 | Gets the id of the transaction owning a lock. |
626 | @return transaction id */ |
627 | trx_id_t |
628 | lock_get_trx_id( |
629 | /*============*/ |
630 | const lock_t* lock); /*!< in: lock */ |
631 | |
632 | /*******************************************************************//** |
633 | Gets the mode of a lock in a human readable string. |
634 | The string should not be free()'d or modified. |
635 | @return lock mode */ |
636 | const char* |
637 | lock_get_mode_str( |
638 | /*==============*/ |
639 | const lock_t* lock); /*!< in: lock */ |
640 | |
641 | /*******************************************************************//** |
642 | Gets the type of a lock in a human readable string. |
643 | The string should not be free()'d or modified. |
644 | @return lock type */ |
645 | const char* |
646 | lock_get_type_str( |
647 | /*==============*/ |
648 | const lock_t* lock); /*!< in: lock */ |
649 | |
650 | /*******************************************************************//** |
651 | Gets the id of the table on which the lock is. |
652 | @return id of the table */ |
653 | table_id_t |
654 | lock_get_table_id( |
655 | /*==============*/ |
656 | const lock_t* lock); /*!< in: lock */ |
657 | |
658 | /** Determine which table a lock is associated with. |
659 | @param[in] lock the lock |
660 | @return name of the table */ |
661 | const table_name_t& |
662 | lock_get_table_name( |
663 | const lock_t* lock); |
664 | |
665 | /*******************************************************************//** |
666 | For a record lock, gets the index on which the lock is. |
667 | @return index */ |
668 | const dict_index_t* |
669 | lock_rec_get_index( |
670 | /*===============*/ |
671 | const lock_t* lock); /*!< in: lock */ |
672 | |
673 | /*******************************************************************//** |
674 | For a record lock, gets the name of the index on which the lock is. |
675 | The string should not be free()'d or modified. |
676 | @return name of the index */ |
677 | const char* |
678 | lock_rec_get_index_name( |
679 | /*====================*/ |
680 | const lock_t* lock); /*!< in: lock */ |
681 | |
682 | /*******************************************************************//** |
683 | For a record lock, gets the tablespace number on which the lock is. |
684 | @return tablespace number */ |
685 | ulint |
686 | lock_rec_get_space_id( |
687 | /*==================*/ |
688 | const lock_t* lock); /*!< in: lock */ |
689 | |
690 | /*******************************************************************//** |
691 | For a record lock, gets the page number on which the lock is. |
692 | @return page number */ |
693 | ulint |
694 | lock_rec_get_page_no( |
695 | /*=================*/ |
696 | const lock_t* lock); /*!< in: lock */ |
697 | /*******************************************************************//** |
698 | Check if there are any locks (table or rec) against table. |
699 | @return TRUE if locks exist */ |
700 | bool |
701 | lock_table_has_locks( |
702 | /*=================*/ |
703 | const dict_table_t* table); /*!< in: check if there are any locks |
704 | held on records in this table or on the |
705 | table itself */ |
706 | |
707 | /*********************************************************************//** |
708 | A thread which wakes up threads whose lock wait may have lasted too long. |
709 | @return a dummy parameter */ |
710 | extern "C" |
711 | os_thread_ret_t |
712 | DECLARE_THREAD(lock_wait_timeout_thread)( |
713 | /*=====================================*/ |
714 | void* arg); /*!< in: a dummy parameter required by |
715 | os_thread_create */ |
716 | |
717 | /********************************************************************//** |
718 | Releases a user OS thread waiting for a lock to be released, if the |
719 | thread is already suspended. */ |
720 | void |
721 | lock_wait_release_thread_if_suspended( |
722 | /*==================================*/ |
723 | que_thr_t* thr); /*!< in: query thread associated with the |
724 | user OS thread */ |
725 | |
726 | /***************************************************************//** |
727 | Puts a user OS thread to wait for a lock to be released. If an error |
728 | occurs during the wait trx->error_state associated with thr is |
729 | != DB_SUCCESS when we return. DB_LOCK_WAIT_TIMEOUT and DB_DEADLOCK |
730 | are possible errors. DB_DEADLOCK is returned if selective deadlock |
731 | resolution chose this transaction as a victim. */ |
732 | void |
733 | lock_wait_suspend_thread( |
734 | /*=====================*/ |
735 | que_thr_t* thr); /*!< in: query thread associated with the |
736 | user OS thread */ |
737 | /*********************************************************************//** |
738 | Unlocks AUTO_INC type locks that were possibly reserved by a trx. This |
739 | function should be called at the the end of an SQL statement, by the |
740 | connection thread that owns the transaction (trx->mysql_thd). */ |
741 | void |
742 | lock_unlock_table_autoinc( |
743 | /*======================*/ |
744 | trx_t* trx); /*!< in/out: transaction */ |
745 | /*********************************************************************//** |
746 | Check whether the transaction has already been rolled back because it |
747 | was selected as a deadlock victim, or if it has to wait then cancel |
748 | the wait lock. |
749 | @return DB_DEADLOCK, DB_LOCK_WAIT or DB_SUCCESS */ |
750 | dberr_t |
751 | lock_trx_handle_wait( |
752 | /*=================*/ |
753 | trx_t* trx); /*!< in/out: trx lock state */ |
754 | /*********************************************************************//** |
755 | Get the number of locks on a table. |
756 | @return number of locks */ |
757 | ulint |
758 | lock_table_get_n_locks( |
759 | /*===================*/ |
760 | const dict_table_t* table); /*!< in: table */ |
761 | /*******************************************************************//** |
762 | Initialise the trx lock list. */ |
763 | void |
764 | lock_trx_lock_list_init( |
765 | /*====================*/ |
766 | trx_lock_list_t* lock_list); /*!< List to initialise */ |
767 | |
768 | /*******************************************************************//** |
769 | Set the lock system timeout event. */ |
770 | void |
771 | lock_set_timeout_event(); |
772 | /*====================*/ |
773 | /*********************************************************************//** |
774 | Checks that a transaction id is sensible, i.e., not in the future. |
775 | @return true if ok */ |
776 | bool |
777 | lock_check_trx_id_sanity( |
778 | /*=====================*/ |
779 | trx_id_t trx_id, /*!< in: trx id */ |
780 | const rec_t* rec, /*!< in: user record */ |
781 | dict_index_t* index, /*!< in: index */ |
782 | const ulint* offsets); /*!< in: rec_get_offsets(rec, index) */ |
783 | #ifdef UNIV_DEBUG |
784 | /*******************************************************************//** |
785 | Check if the transaction holds any locks on the sys tables |
786 | or its records. |
787 | @return the strongest lock found on any sys table or 0 for none */ |
788 | const lock_t* |
789 | lock_trx_has_sys_table_locks( |
790 | /*=========================*/ |
791 | const trx_t* trx) /*!< in: transaction to check */ |
792 | MY_ATTRIBUTE((warn_unused_result)); |
793 | |
794 | /*******************************************************************//** |
795 | Check if the transaction holds an exclusive lock on a record. |
796 | @return whether the locks are held */ |
797 | bool |
798 | lock_trx_has_rec_x_lock( |
799 | /*====================*/ |
800 | const trx_t* trx, /*!< in: transaction to check */ |
801 | const dict_table_t* table, /*!< in: table to check */ |
802 | const buf_block_t* block, /*!< in: buffer block of the record */ |
803 | ulint heap_no)/*!< in: record heap number */ |
804 | MY_ATTRIBUTE((warn_unused_result)); |
805 | #endif /* UNIV_DEBUG */ |
806 | |
807 | /** |
808 | Allocate cached locks for the transaction. |
809 | @param trx allocate cached record locks for this transaction */ |
810 | void |
811 | lock_trx_alloc_locks(trx_t* trx); |
812 | |
813 | /** Lock modes and types */ |
814 | /* @{ */ |
815 | #define LOCK_MODE_MASK 0xFUL /*!< mask used to extract mode from the |
816 | type_mode field in a lock */ |
817 | /** Lock types */ |
818 | /* @{ */ |
819 | #define LOCK_TABLE 16U /*!< table lock */ |
820 | #define LOCK_REC 32U /*!< record lock */ |
821 | #define LOCK_TYPE_MASK 0xF0UL /*!< mask used to extract lock type from the |
822 | type_mode field in a lock */ |
823 | #if LOCK_MODE_MASK & LOCK_TYPE_MASK |
824 | # error "LOCK_MODE_MASK & LOCK_TYPE_MASK" |
825 | #endif |
826 | |
827 | #define LOCK_WAIT 256U /*!< Waiting lock flag; when set, it |
828 | means that the lock has not yet been |
829 | granted, it is just waiting for its |
830 | turn in the wait queue */ |
831 | /* Precise modes */ |
832 | #define LOCK_ORDINARY 0 /*!< this flag denotes an ordinary |
833 | next-key lock in contrast to LOCK_GAP |
834 | or LOCK_REC_NOT_GAP */ |
835 | #define LOCK_GAP 512U /*!< when this bit is set, it means that the |
836 | lock holds only on the gap before the record; |
837 | for instance, an x-lock on the gap does not |
838 | give permission to modify the record on which |
839 | the bit is set; locks of this type are created |
840 | when records are removed from the index chain |
841 | of records */ |
842 | #define LOCK_REC_NOT_GAP 1024U /*!< this bit means that the lock is only on |
843 | the index record and does NOT block inserts |
844 | to the gap before the index record; this is |
845 | used in the case when we retrieve a record |
846 | with a unique key, and is also used in |
847 | locking plain SELECTs (not part of UPDATE |
848 | or DELETE) when the user has set the READ |
849 | COMMITTED isolation level */ |
850 | #define LOCK_INSERT_INTENTION 2048U/*!< this bit is set when we place a waiting |
851 | gap type record lock request in order to let |
852 | an insert of an index record to wait until |
853 | there are no conflicting locks by other |
854 | transactions on the gap; note that this flag |
855 | remains set when the waiting lock is granted, |
856 | or if the lock is inherited to a neighboring |
857 | record */ |
858 | #define LOCK_PREDICATE 8192U /*!< Predicate lock */ |
859 | #define LOCK_PRDT_PAGE 16384U /*!< Page lock */ |
860 | |
861 | |
862 | #if (LOCK_WAIT|LOCK_GAP|LOCK_REC_NOT_GAP|LOCK_INSERT_INTENTION|LOCK_PREDICATE|LOCK_PRDT_PAGE)&LOCK_MODE_MASK |
863 | # error |
864 | #endif |
865 | #if (LOCK_WAIT|LOCK_GAP|LOCK_REC_NOT_GAP|LOCK_INSERT_INTENTION|LOCK_PREDICATE|LOCK_PRDT_PAGE)&LOCK_TYPE_MASK |
866 | # error |
867 | #endif |
868 | /* @} */ |
869 | |
870 | /** Lock operation struct */ |
871 | struct lock_op_t{ |
872 | dict_table_t* table; /*!< table to be locked */ |
873 | lock_mode mode; /*!< lock mode */ |
874 | }; |
875 | |
876 | typedef ib_mutex_t LockMutex; |
877 | |
878 | /** The lock system struct */ |
879 | class lock_sys_t |
880 | { |
881 | bool m_initialised; |
882 | |
883 | public: |
884 | MY_ALIGNED(CACHE_LINE_SIZE) |
885 | LockMutex mutex; /*!< Mutex protecting the |
886 | locks */ |
887 | hash_table_t* rec_hash; /*!< hash table of the record |
888 | locks */ |
889 | hash_table_t* prdt_hash; /*!< hash table of the predicate |
890 | lock */ |
891 | hash_table_t* prdt_page_hash; /*!< hash table of the page |
892 | lock */ |
893 | |
894 | MY_ALIGNED(CACHE_LINE_SIZE) |
895 | LockMutex wait_mutex; /*!< Mutex protecting the |
896 | next two fields */ |
897 | srv_slot_t* waiting_threads; /*!< Array of user threads |
898 | suspended while waiting for |
899 | locks within InnoDB, protected |
900 | by the lock_sys.wait_mutex; |
901 | os_event_set() and |
902 | os_event_reset() on |
903 | waiting_threads[]->event |
904 | are protected by |
905 | trx_t::mutex */ |
906 | srv_slot_t* last_slot; /*!< highest slot ever used |
907 | in the waiting_threads array, |
908 | protected by |
909 | lock_sys.wait_mutex */ |
910 | |
911 | ulint n_lock_max_wait_time; /*!< Max wait time */ |
912 | |
913 | os_event_t timeout_event; /*!< An event waited for by |
914 | lock_wait_timeout_thread. |
915 | Not protected by a mutex, |
916 | but the waits are timed. |
917 | Signaled on shutdown only. */ |
918 | |
919 | bool timeout_thread_active; /*!< True if the timeout thread |
920 | is running */ |
921 | |
922 | |
923 | /** |
924 | Constructor. |
925 | |
926 | Some members may require late initialisation, thus we just mark object as |
927 | uninitialised. Real initialisation happens in create(). |
928 | */ |
929 | lock_sys_t(): m_initialised(false) {} |
930 | |
931 | |
932 | bool is_initialised() { return m_initialised; } |
933 | |
934 | |
935 | /** |
936 | Creates the lock system at database start. |
937 | |
938 | @param[in] n_cells number of slots in lock hash table |
939 | */ |
940 | void create(ulint n_cells); |
941 | |
942 | |
943 | /** |
944 | Resize the lock hash table. |
945 | |
946 | @param[in] n_cells number of slots in lock hash table |
947 | */ |
948 | void resize(ulint n_cells); |
949 | |
950 | |
951 | /** Closes the lock system at database shutdown. */ |
952 | void close(); |
953 | }; |
954 | |
955 | /*********************************************************************//** |
956 | Creates a new record lock and inserts it to the lock queue. Does NOT check |
957 | for deadlocks or lock compatibility! |
958 | @return created lock */ |
959 | UNIV_INLINE |
960 | lock_t* |
961 | lock_rec_create( |
962 | /*============*/ |
963 | #ifdef WITH_WSREP |
964 | lock_t* c_lock, /*!< conflicting lock */ |
965 | que_thr_t* thr, /*!< thread owning trx */ |
966 | #endif |
967 | ulint type_mode,/*!< in: lock mode and wait |
968 | flag, type is ignored and |
969 | replaced by LOCK_REC */ |
970 | const buf_block_t* block, /*!< in: buffer block containing |
971 | the record */ |
972 | ulint heap_no,/*!< in: heap number of the record */ |
973 | dict_index_t* index, /*!< in: index of record */ |
974 | trx_t* trx, /*!< in,out: transaction */ |
975 | bool caller_owns_trx_mutex); |
976 | /*!< in: true if caller owns |
977 | trx mutex */ |
978 | |
979 | /*************************************************************//** |
980 | Removes a record lock request, waiting or granted, from the queue. */ |
981 | void |
982 | lock_rec_discard( |
983 | /*=============*/ |
984 | lock_t* in_lock); /*!< in: record lock object: all |
985 | record locks which are contained |
986 | in this lock object are removed */ |
987 | |
988 | /** Create a new record lock and inserts it to the lock queue, |
989 | without checking for deadlocks or conflicts. |
990 | @param[in] type_mode lock mode and wait flag; type will be replaced |
991 | with LOCK_REC |
992 | @param[in] space tablespace id |
993 | @param[in] page_no index page number |
994 | @param[in] page R-tree index page, or NULL |
995 | @param[in] heap_no record heap number in the index page |
996 | @param[in] index the index tree |
997 | @param[in,out] trx transaction |
998 | @param[in] holds_trx_mutex whether the caller holds trx->mutex |
999 | @return created lock */ |
1000 | lock_t* |
1001 | lock_rec_create_low( |
1002 | #ifdef WITH_WSREP |
1003 | lock_t* c_lock, /*!< conflicting lock */ |
1004 | que_thr_t* thr, /*!< thread owning trx */ |
1005 | #endif |
1006 | ulint type_mode, |
1007 | ulint space, |
1008 | ulint page_no, |
1009 | const page_t* page, |
1010 | ulint heap_no, |
1011 | dict_index_t* index, |
1012 | trx_t* trx, |
1013 | bool holds_trx_mutex); |
1014 | /** Enqueue a waiting request for a lock which cannot be granted immediately. |
1015 | Check for deadlocks. |
1016 | @param[in] type_mode the requested lock mode (LOCK_S or LOCK_X) |
1017 | possibly ORed with LOCK_GAP or |
1018 | LOCK_REC_NOT_GAP, ORed with |
1019 | LOCK_INSERT_INTENTION if this |
1020 | waiting lock request is set |
1021 | when performing an insert of |
1022 | an index record |
1023 | @param[in] block leaf page in the index |
1024 | @param[in] heap_no record heap number in the block |
1025 | @param[in] index index tree |
1026 | @param[in,out] thr query thread |
1027 | @param[in] prdt minimum bounding box (spatial index) |
1028 | @retval DB_LOCK_WAIT if the waiting lock was enqueued |
1029 | @retval DB_DEADLOCK if this transaction was chosen as the victim |
1030 | @retval DB_SUCCESS_LOCKED_REC if the other transaction was chosen as a victim |
1031 | (or it happened to commit) */ |
1032 | dberr_t |
1033 | lock_rec_enqueue_waiting( |
1034 | #ifdef WITH_WSREP |
1035 | lock_t* c_lock, /*!< conflicting lock */ |
1036 | #endif |
1037 | ulint type_mode, |
1038 | const buf_block_t* block, |
1039 | ulint heap_no, |
1040 | dict_index_t* index, |
1041 | que_thr_t* thr, |
1042 | lock_prdt_t* prdt); |
1043 | /*************************************************************//** |
1044 | Moves the explicit locks on user records to another page if a record |
1045 | list start is moved to another page. */ |
1046 | void |
1047 | lock_rtr_move_rec_list( |
1048 | /*===================*/ |
1049 | const buf_block_t* new_block, /*!< in: index page to |
1050 | move to */ |
1051 | const buf_block_t* block, /*!< in: index page */ |
1052 | rtr_rec_move_t* rec_move, /*!< in: recording records |
1053 | moved */ |
1054 | ulint num_move); /*!< in: num of rec to move */ |
1055 | |
1056 | /*************************************************************//** |
1057 | Removes record lock objects set on an index page which is discarded. This |
1058 | function does not move locks, or check for waiting locks, therefore the |
1059 | lock bitmaps must already be reset when this function is called. */ |
1060 | void |
1061 | lock_rec_free_all_from_discard_page( |
1062 | /*================================*/ |
1063 | const buf_block_t* block); /*!< in: page to be discarded */ |
1064 | |
1065 | /** The lock system */ |
1066 | extern lock_sys_t lock_sys; |
1067 | |
1068 | /** Test if lock_sys.mutex can be acquired without waiting. */ |
1069 | #define lock_mutex_enter_nowait() \ |
1070 | (lock_sys.mutex.trylock(__FILE__, __LINE__)) |
1071 | |
1072 | /** Test if lock_sys.mutex is owned. */ |
1073 | #define lock_mutex_own() (lock_sys.mutex.is_owned()) |
1074 | |
1075 | /** Acquire the lock_sys.mutex. */ |
1076 | #define lock_mutex_enter() do { \ |
1077 | mutex_enter(&lock_sys.mutex); \ |
1078 | } while (0) |
1079 | |
1080 | /** Release the lock_sys.mutex. */ |
1081 | #define lock_mutex_exit() do { \ |
1082 | lock_sys.mutex.exit(); \ |
1083 | } while (0) |
1084 | |
1085 | /** Test if lock_sys.wait_mutex is owned. */ |
1086 | #define lock_wait_mutex_own() (lock_sys.wait_mutex.is_owned()) |
1087 | |
1088 | /** Acquire the lock_sys.wait_mutex. */ |
1089 | #define lock_wait_mutex_enter() do { \ |
1090 | mutex_enter(&lock_sys.wait_mutex); \ |
1091 | } while (0) |
1092 | |
1093 | /** Release the lock_sys.wait_mutex. */ |
1094 | #define lock_wait_mutex_exit() do { \ |
1095 | lock_sys.wait_mutex.exit(); \ |
1096 | } while (0) |
1097 | |
1098 | #ifdef WITH_WSREP |
1099 | /*********************************************************************//** |
1100 | Cancels a waiting lock request and releases possible other transactions |
1101 | waiting behind it. */ |
1102 | UNIV_INTERN |
1103 | void |
1104 | lock_cancel_waiting_and_release( |
1105 | /*============================*/ |
1106 | lock_t* lock); /*!< in/out: waiting lock request */ |
1107 | |
1108 | /*******************************************************************//** |
1109 | Get lock mode and table/index name |
1110 | @return string containing lock info */ |
1111 | std::string |
1112 | lock_get_info( |
1113 | const lock_t*); |
1114 | |
1115 | /*******************************************************************//** |
1116 | @return whether wsrep_on is true on trx->mysql_thd*/ |
1117 | #define wsrep_on_trx(trx) ((trx)->mysql_thd && wsrep_on((trx)->mysql_thd)) |
1118 | |
1119 | #endif /* WITH_WSREP */ |
1120 | |
1121 | #include "lock0lock.ic" |
1122 | |
1123 | #endif |
1124 | |