The world's most popular open source database
00001 /****************************************************** 00002 The transaction lock system 00003 00004 (c) 1996 Innobase Oy 00005 00006 Created 5/7/1996 Heikki Tuuri 00007 *******************************************************/ 00008 00009 #include "lock0lock.h" 00010 00011 #ifdef UNIV_NONINL 00012 #include "lock0lock.ic" 00013 #endif 00014 00015 #include "usr0sess.h" 00016 #include "trx0purge.h" 00017 #include "dict0mem.h" 00018 #include "trx0sys.h" 00019 00020 00021 /* 2 function prototypes copied from ha_innodb.cc: */ 00022 00023 /***************************************************************** 00024 If you want to print a thd that is not associated with the current thread, 00025 you must call this function before reserving the InnoDB kernel_mutex, to 00026 protect MySQL from setting thd->query NULL. If you print a thd of the current 00027 thread, we know that MySQL cannot modify thd->query, and it is not necessary 00028 to call this. Call innobase_mysql_end_print_arbitrary_thd() after you release 00029 the kernel_mutex. 00030 NOTE that /mysql/innobase/lock/lock0lock.c must contain the prototype for this 00031 function! */ 00032 00033 void 00034 innobase_mysql_prepare_print_arbitrary_thd(void); 00035 /*============================================*/ 00036 00037 /***************************************************************** 00038 Relases the mutex reserved by innobase_mysql_prepare_print_arbitrary_thd(). 00039 NOTE that /mysql/innobase/lock/lock0lock.c must contain the prototype for this 00040 function! */ 00041 00042 void 00043 innobase_mysql_end_print_arbitrary_thd(void); 00044 /*========================================*/ 00045 00046 /* Restricts the length of search we will do in the waits-for 00047 graph of transactions */ 00048 #define LOCK_MAX_N_STEPS_IN_DEADLOCK_CHECK 1000000 00049 00050 /* Restricts the recursion depth of the search we will do in the waits-for 00051 graph of transactions */ 00052 #define LOCK_MAX_DEPTH_IN_DEADLOCK_CHECK 200 00053 00054 /* When releasing transaction locks, this specifies how often we release 00055 the kernel mutex for a moment to give also others access to it */ 00056 00057 #define LOCK_RELEASE_KERNEL_INTERVAL 1000 00058 00059 /* Safety margin when creating a new record lock: this many extra records 00060 can be inserted to the page without need to create a lock with a bigger 00061 bitmap */ 00062 00063 #define LOCK_PAGE_BITMAP_MARGIN 64 00064 00065 /* An explicit record lock affects both the record and the gap before it. 00066 An implicit x-lock does not affect the gap, it only locks the index 00067 record from read or update. 00068 00069 If a transaction has modified or inserted an index record, then 00070 it owns an implicit x-lock on the record. On a secondary index record, 00071 a transaction has an implicit x-lock also if it has modified the 00072 clustered index record, the max trx id of the page where the secondary 00073 index record resides is >= trx id of the transaction (or database recovery 00074 is running), and there are no explicit non-gap lock requests on the 00075 secondary index record. 00076 00077 This complicated definition for a secondary index comes from the 00078 implementation: we want to be able to determine if a secondary index 00079 record has an implicit x-lock, just by looking at the present clustered 00080 index record, not at the historical versions of the record. The 00081 complicated definition can be explained to the user so that there is 00082 nondeterminism in the access path when a query is answered: we may, 00083 or may not, access the clustered index record and thus may, or may not, 00084 bump into an x-lock set there. 00085 00086 Different transaction can have conflicting locks set on the gap at the 00087 same time. The locks on the gap are purely inhibitive: an insert cannot 00088 be made, or a select cursor may have to wait if a different transaction 00089 has a conflicting lock on the gap. An x-lock on the gap does not give 00090 the right to insert into the gap. 00091 00092 An explicit lock can be placed on a user record or the supremum record of 00093 a page. The locks on the supremum record are always thought to be of the gap 00094 type, though the gap bit is not set. When we perform an update of a record 00095 where the size of the record changes, we may temporarily store its explicit 00096 locks on the infimum record of the page, though the infimum otherwise never 00097 carries locks. 00098 00099 A waiting record lock can also be of the gap type. A waiting lock request 00100 can be granted when there is no conflicting mode lock request by another 00101 transaction ahead of it in the explicit lock queue. 00102 00103 In version 4.0.5 we added yet another explicit lock type: LOCK_REC_NOT_GAP. 00104 It only locks the record it is placed on, not the gap before the record. 00105 This lock type is necessary to emulate an Oracle-like READ COMMITTED isolation 00106 level. 00107 00108 ------------------------------------------------------------------------- 00109 RULE 1: If there is an implicit x-lock on a record, and there are non-gap 00110 ------- 00111 lock requests waiting in the queue, then the transaction holding the implicit 00112 x-lock also has an explicit non-gap record x-lock. Therefore, as locks are 00113 released, we can grant locks to waiting lock requests purely by looking at 00114 the explicit lock requests in the queue. 00115 00116 RULE 3: Different transactions cannot have conflicting granted non-gap locks 00117 ------- 00118 on a record at the same time. However, they can have conflicting granted gap 00119 locks. 00120 RULE 4: If a there is a waiting lock request in a queue, no lock request, 00121 ------- 00122 gap or not, can be inserted ahead of it in the queue. In record deletes 00123 and page splits new gap type locks can be created by the database manager 00124 for a transaction, and without rule 4, the waits-for graph of transactions 00125 might become cyclic without the database noticing it, as the deadlock check 00126 is only performed when a transaction itself requests a lock! 00127 ------------------------------------------------------------------------- 00128 00129 An insert is allowed to a gap if there are no explicit lock requests by 00130 other transactions on the next record. It does not matter if these lock 00131 requests are granted or waiting, gap bit set or not, with the exception 00132 that a gap type request set by another transaction to wait for 00133 its turn to do an insert is ignored. On the other hand, an 00134 implicit x-lock by another transaction does not prevent an insert, which 00135 allows for more concurrency when using an Oracle-style sequence number 00136 generator for the primary key with many transactions doing inserts 00137 concurrently. 00138 00139 A modify of a record is allowed if the transaction has an x-lock on the 00140 record, or if other transactions do not have any non-gap lock requests on the 00141 record. 00142 00143 A read of a single user record with a cursor is allowed if the transaction 00144 has a non-gap explicit, or an implicit lock on the record, or if the other 00145 transactions have no x-lock requests on the record. At a page supremum a 00146 read is always allowed. 00147 00148 In summary, an implicit lock is seen as a granted x-lock only on the 00149 record, not on the gap. An explicit lock with no gap bit set is a lock 00150 both on the record and the gap. If the gap bit is set, the lock is only 00151 on the gap. Different transaction cannot own conflicting locks on the 00152 record at the same time, but they may own conflicting locks on the gap. 00153 Granted locks on a record give an access right to the record, but gap type 00154 locks just inhibit operations. 00155 00156 NOTE: Finding out if some transaction has an implicit x-lock on a secondary 00157 index record can be cumbersome. We may have to look at previous versions of 00158 the corresponding clustered index record to find out if a delete marked 00159 secondary index record was delete marked by an active transaction, not by 00160 a committed one. 00161 00162 FACT A: If a transaction has inserted a row, it can delete it any time 00163 without need to wait for locks. 00164 00165 PROOF: The transaction has an implicit x-lock on every index record inserted 00166 for the row, and can thus modify each record without the need to wait. Q.E.D. 00167 00168 FACT B: If a transaction has read some result set with a cursor, it can read 00169 it again, and retrieves the same result set, if it has not modified the 00170 result set in the meantime. Hence, there is no phantom problem. If the 00171 biggest record, in the alphabetical order, touched by the cursor is removed, 00172 a lock wait may occur, otherwise not. 00173 00174 PROOF: When a read cursor proceeds, it sets an s-lock on each user record 00175 it passes, and a gap type s-lock on each page supremum. The cursor must 00176 wait until it has these locks granted. Then no other transaction can 00177 have a granted x-lock on any of the user records, and therefore cannot 00178 modify the user records. Neither can any other transaction insert into 00179 the gaps which were passed over by the cursor. Page splits and merges, 00180 and removal of obsolete versions of records do not affect this, because 00181 when a user record or a page supremum is removed, the next record inherits 00182 its locks as gap type locks, and therefore blocks inserts to the same gap. 00183 Also, if a page supremum is inserted, it inherits its locks from the successor 00184 record. When the cursor is positioned again at the start of the result set, 00185 the records it will touch on its course are either records it touched 00186 during the last pass or new inserted page supremums. It can immediately 00187 access all these records, and when it arrives at the biggest record, it 00188 notices that the result set is complete. If the biggest record was removed, 00189 lock wait can occur because the next record only inherits a gap type lock, 00190 and a wait may be needed. Q.E.D. */ 00191 00192 /* If an index record should be changed or a new inserted, we must check 00193 the lock on the record or the next. When a read cursor starts reading, 00194 we will set a record level s-lock on each record it passes, except on the 00195 initial record on which the cursor is positioned before we start to fetch 00196 records. Our index tree search has the convention that the B-tree 00197 cursor is positioned BEFORE the first possibly matching record in 00198 the search. Optimizations are possible here: if the record is searched 00199 on an equality condition to a unique key, we could actually set a special 00200 lock on the record, a lock which would not prevent any insert before 00201 this record. In the next key locking an x-lock set on a record also 00202 prevents inserts just before that record. 00203 There are special infimum and supremum records on each page. 00204 A supremum record can be locked by a read cursor. This records cannot be 00205 updated but the lock prevents insert of a user record to the end of 00206 the page. 00207 Next key locks will prevent the phantom problem where new rows 00208 could appear to SELECT result sets after the select operation has been 00209 performed. Prevention of phantoms ensures the serilizability of 00210 transactions. 00211 What should we check if an insert of a new record is wanted? 00212 Only the lock on the next record on the same page, because also the 00213 supremum record can carry a lock. An s-lock prevents insertion, but 00214 what about an x-lock? If it was set by a searched update, then there 00215 is implicitly an s-lock, too, and the insert should be prevented. 00216 What if our transaction owns an x-lock to the next record, but there is 00217 a waiting s-lock request on the next record? If this s-lock was placed 00218 by a read cursor moving in the ascending order in the index, we cannot 00219 do the insert immediately, because when we finally commit our transaction, 00220 the read cursor should see also the new inserted record. So we should 00221 move the read cursor backward from the the next record for it to pass over 00222 the new inserted record. This move backward may be too cumbersome to 00223 implement. If we in this situation just enqueue a second x-lock request 00224 for our transaction on the next record, then the deadlock mechanism 00225 notices a deadlock between our transaction and the s-lock request 00226 transaction. This seems to be an ok solution. 00227 We could have the convention that granted explicit record locks, 00228 lock the corresponding records from changing, and also lock the gaps 00229 before them from inserting. A waiting explicit lock request locks the gap 00230 before from inserting. Implicit record x-locks, which we derive from the 00231 transaction id in the clustered index record, only lock the record itself 00232 from modification, not the gap before it from inserting. 00233 How should we store update locks? If the search is done by a unique 00234 key, we could just modify the record trx id. Otherwise, we could put a record 00235 x-lock on the record. If the update changes ordering fields of the 00236 clustered index record, the inserted new record needs no record lock in 00237 lock table, the trx id is enough. The same holds for a secondary index 00238 record. Searched delete is similar to update. 00239 00240 PROBLEM: 00241 What about waiting lock requests? If a transaction is waiting to make an 00242 update to a record which another modified, how does the other transaction 00243 know to send the end-lock-wait signal to the waiting transaction? If we have 00244 the convention that a transaction may wait for just one lock at a time, how 00245 do we preserve it if lock wait ends? 00246 00247 PROBLEM: 00248 Checking the trx id label of a secondary index record. In the case of a 00249 modification, not an insert, is this necessary? A secondary index record 00250 is modified only by setting or resetting its deleted flag. A secondary index 00251 record contains fields to uniquely determine the corresponding clustered 00252 index record. A secondary index record is therefore only modified if we 00253 also modify the clustered index record, and the trx id checking is done 00254 on the clustered index record, before we come to modify the secondary index 00255 record. So, in the case of delete marking or unmarking a secondary index 00256 record, we do not have to care about trx ids, only the locks in the lock 00257 table must be checked. In the case of a select from a secondary index, the 00258 trx id is relevant, and in this case we may have to search the clustered 00259 index record. 00260 00261 PROBLEM: How to update record locks when page is split or merged, or 00262 -------------------------------------------------------------------- 00263 a record is deleted or updated? 00264 If the size of fields in a record changes, we perform the update by 00265 a delete followed by an insert. How can we retain the locks set or 00266 waiting on the record? Because a record lock is indexed in the bitmap 00267 by the heap number of the record, when we remove the record from the 00268 record list, it is possible still to keep the lock bits. If the page 00269 is reorganized, we could make a table of old and new heap numbers, 00270 and permute the bitmaps in the locks accordingly. We can add to the 00271 table a row telling where the updated record ended. If the update does 00272 not require a reorganization of the page, we can simply move the lock 00273 bits for the updated record to the position determined by its new heap 00274 number (we may have to allocate a new lock, if we run out of the bitmap 00275 in the old one). 00276 A more complicated case is the one where the reinsertion of the 00277 updated record is done pessimistically, because the structure of the 00278 tree may change. 00279 00280 PROBLEM: If a supremum record is removed in a page merge, or a record 00281 --------------------------------------------------------------------- 00282 removed in a purge, what to do to the waiting lock requests? In a split to 00283 the right, we just move the lock requests to the new supremum. If a record 00284 is removed, we could move the waiting lock request to its inheritor, the 00285 next record in the index. But, the next record may already have lock 00286 requests on its own queue. A new deadlock check should be made then. Maybe 00287 it is easier just to release the waiting transactions. They can then enqueue 00288 new lock requests on appropriate records. 00289 00290 PROBLEM: When a record is inserted, what locks should it inherit from the 00291 ------------------------------------------------------------------------- 00292 upper neighbor? An insert of a new supremum record in a page split is 00293 always possible, but an insert of a new user record requires that the upper 00294 neighbor does not have any lock requests by other transactions, granted or 00295 waiting, in its lock queue. Solution: We can copy the locks as gap type 00296 locks, so that also the waiting locks are transformed to granted gap type 00297 locks on the inserted record. */ 00298 00299 /* LOCK COMPATIBILITY MATRIX 00300 * IS IX S X AI 00301 * IS + + + - + 00302 * IX + + - - + 00303 * S + - + - - 00304 * X - - - - - 00305 * AI + + - - - 00306 * 00307 * Note that for rows, InnoDB only acquires S or X locks. 00308 * For tables, InnoDB normally acquires IS or IX locks. 00309 * S or X table locks are only acquired for LOCK TABLES. 00310 * Auto-increment (AI) locks are needed because of 00311 * statement-level MySQL binlog. 00312 * See also lock_mode_compatible(). 00313 */ 00314 00315 #ifdef UNIV_DEBUG 00316 ibool lock_print_waits = FALSE; 00317 #endif /* UNIV_DEBUG */ 00318 00319 /* The lock system */ 00320 lock_sys_t* lock_sys = NULL; 00321 00322 /* A table lock */ 00323 typedef struct lock_table_struct lock_table_t; 00324 struct lock_table_struct{ 00325 dict_table_t* table; /* database table in dictionary cache */ 00326 UT_LIST_NODE_T(lock_t) 00327 locks; /* list of locks on the same table */ 00328 }; 00329 00330 /* Record lock for a page */ 00331 typedef struct lock_rec_struct lock_rec_t; 00332 struct lock_rec_struct{ 00333 ulint space; /* space id */ 00334 ulint page_no; /* page number */ 00335 ulint n_bits; /* number of bits in the lock bitmap */ 00336 /* NOTE: the lock bitmap is placed immediately 00337 after the lock struct */ 00338 }; 00339 00340 /* Lock struct */ 00341 struct lock_struct{ 00342 trx_t* trx; /* transaction owning the lock */ 00343 UT_LIST_NODE_T(lock_t) 00344 trx_locks; /* list of the locks of the 00345 transaction */ 00346 ulint type_mode; /* lock type, mode, LOCK_GAP or 00347 LOCK_REC_NOT_GAP, 00348 LOCK_INSERT_INTENTION, 00349 wait flag, ORed */ 00350 hash_node_t hash; /* hash chain node for a record lock */ 00351 dict_index_t* index; /* index for a record lock */ 00352 union { 00353 lock_table_t tab_lock;/* table lock */ 00354 lock_rec_t rec_lock;/* record lock */ 00355 } un_member; 00356 }; 00357 00358 /* We store info on the latest deadlock error to this buffer. InnoDB 00359 Monitor will then fetch it and print */ 00360 ibool lock_deadlock_found = FALSE; 00361 FILE* lock_latest_err_file; 00362 00363 /* Flags for recursive deadlock search */ 00364 #define LOCK_VICTIM_IS_START 1 00365 #define LOCK_VICTIM_IS_OTHER 2 00366 00367 /************************************************************************ 00368 Checks if a lock request results in a deadlock. */ 00369 static 00370 ibool 00371 lock_deadlock_occurs( 00372 /*=================*/ 00373 /* out: TRUE if a deadlock was detected and we 00374 chose trx as a victim; FALSE if no deadlock, or 00375 there was a deadlock, but we chose other 00376 transaction(s) as victim(s) */ 00377 lock_t* lock, /* in: lock the transaction is requesting */ 00378 trx_t* trx); /* in: transaction */ 00379 /************************************************************************ 00380 Looks recursively for a deadlock. */ 00381 static 00382 ulint 00383 lock_deadlock_recursive( 00384 /*====================*/ 00385 /* out: 0 if no deadlock found, 00386 LOCK_VICTIM_IS_START if there was a deadlock 00387 and we chose 'start' as the victim, 00388 LOCK_VICTIM_IS_OTHER if a deadlock 00389 was found and we chose some other trx as a 00390 victim: we must do the search again in this 00391 last case because there may be another 00392 deadlock! */ 00393 trx_t* start, /* in: recursion starting point */ 00394 trx_t* trx, /* in: a transaction waiting for a lock */ 00395 lock_t* wait_lock, /* in: the lock trx is waiting to be granted */ 00396 ulint* cost, /* in/out: number of calculation steps thus 00397 far: if this exceeds LOCK_MAX_N_STEPS_... 00398 we return LOCK_VICTIM_IS_START */ 00399 ulint depth); /* in: recursion depth: if this exceeds 00400 LOCK_MAX_DEPTH_IN_DEADLOCK_CHECK, we 00401 return LOCK_VICTIM_IS_START */ 00402 00403 /************************************************************************* 00404 Gets the type of a lock. */ 00405 UNIV_INLINE 00406 ulint 00407 lock_get_type( 00408 /*==========*/ 00409 /* out: LOCK_TABLE or LOCK_REC */ 00410 lock_t* lock) /* in: lock */ 00411 { 00412 ut_ad(lock); 00413 00414 return(lock->type_mode & LOCK_TYPE_MASK); 00415 } 00416 00417 /************************************************************************* 00418 Gets the nth bit of a record lock. */ 00419 UNIV_INLINE 00420 ibool 00421 lock_rec_get_nth_bit( 00422 /*=================*/ 00423 /* out: TRUE if bit set */ 00424 lock_t* lock, /* in: record lock */ 00425 ulint i) /* in: index of the bit */ 00426 { 00427 ulint byte_index; 00428 ulint bit_index; 00429 ulint b; 00430 00431 ut_ad(lock); 00432 ut_ad(lock_get_type(lock) == LOCK_REC); 00433 00434 if (i >= lock->un_member.rec_lock.n_bits) { 00435 00436 return(FALSE); 00437 } 00438 00439 byte_index = i / 8; 00440 bit_index = i % 8; 00441 00442 b = (ulint)*((byte*)lock + sizeof(lock_t) + byte_index); 00443 00444 return(ut_bit_get_nth(b, bit_index)); 00445 } 00446 00447 /*************************************************************************/ 00448 00449 #define lock_mutex_enter_kernel() mutex_enter(&kernel_mutex) 00450 #define lock_mutex_exit_kernel() mutex_exit(&kernel_mutex) 00451 00452 /************************************************************************* 00453 Checks that a transaction id is sensible, i.e., not in the future. */ 00454 00455 ibool 00456 lock_check_trx_id_sanity( 00457 /*=====================*/ 00458 /* out: TRUE if ok */ 00459 dulint trx_id, /* in: trx id */ 00460 rec_t* rec, /* in: user record */ 00461 dict_index_t* index, /* in: index */ 00462 const ulint* offsets, /* in: rec_get_offsets(rec, index) */ 00463 ibool has_kernel_mutex)/* in: TRUE if the caller owns the 00464 kernel mutex */ 00465 { 00466 ibool is_ok = TRUE; 00467 00468 ut_ad(rec_offs_validate(rec, index, offsets)); 00469 00470 if (!has_kernel_mutex) { 00471 mutex_enter(&kernel_mutex); 00472 } 00473 00474 /* A sanity check: the trx_id in rec must be smaller than the global 00475 trx id counter */ 00476 00477 if (ut_dulint_cmp(trx_id, trx_sys->max_trx_id) >= 0) { 00478 ut_print_timestamp(stderr); 00479 fputs(" InnoDB: Error: transaction id associated" 00480 " with record\n", 00481 stderr); 00482 rec_print_new(stderr, rec, offsets); 00483 fputs("InnoDB: in ", stderr); 00484 dict_index_name_print(stderr, NULL, index); 00485 fprintf(stderr, "\n" 00486 "InnoDB: is %lu %lu which is higher than the global trx id counter %lu %lu!\n" 00487 "InnoDB: The table is corrupt. You have to do dump + drop + reimport.\n", 00488 (ulong) ut_dulint_get_high(trx_id), 00489 (ulong) ut_dulint_get_low(trx_id), 00490 (ulong) ut_dulint_get_high(trx_sys->max_trx_id), 00491 (ulong) ut_dulint_get_low(trx_sys->max_trx_id)); 00492 00493 is_ok = FALSE; 00494 } 00495 00496 if (!has_kernel_mutex) { 00497 mutex_exit(&kernel_mutex); 00498 } 00499 00500 return(is_ok); 00501 } 00502 00503 /************************************************************************* 00504 Checks that a record is seen in a consistent read. */ 00505 00506 ibool 00507 lock_clust_rec_cons_read_sees( 00508 /*==========================*/ 00509 /* out: TRUE if sees, or FALSE if an earlier 00510 version of the record should be retrieved */ 00511 rec_t* rec, /* in: user record which should be read or 00512 passed over by a read cursor */ 00513 dict_index_t* index, /* in: clustered index */ 00514 const ulint* offsets,/* in: rec_get_offsets(rec, index) */ 00515 read_view_t* view) /* in: consistent read view */ 00516 { 00517 dulint trx_id; 00518 00519 ut_ad(index->type & DICT_CLUSTERED); 00520 ut_ad(page_rec_is_user_rec(rec)); 00521 ut_ad(rec_offs_validate(rec, index, offsets)); 00522 00523 /* NOTE that we call this function while holding the search 00524 system latch. To obey the latching order we must NOT reserve the 00525 kernel mutex here! */ 00526 00527 trx_id = row_get_rec_trx_id(rec, index, offsets); 00528 00529 return(read_view_sees_trx_id(view, trx_id)); 00530 } 00531 00532 /************************************************************************* 00533 Checks that a non-clustered index record is seen in a consistent read. */ 00534 00535 ulint 00536 lock_sec_rec_cons_read_sees( 00537 /*========================*/ 00538 /* out: TRUE if certainly sees, or FALSE if an 00539 earlier version of the clustered index record 00540 might be needed: NOTE that a non-clustered 00541 index page contains so little information on 00542 its modifications that also in the case FALSE, 00543 the present version of rec may be the right, 00544 but we must check this from the clustered 00545 index record */ 00546 rec_t* rec, /* in: user record which should be read or 00547 passed over by a read cursor */ 00548 dict_index_t* index, /* in: non-clustered index */ 00549 read_view_t* view) /* in: consistent read view */ 00550 { 00551 dulint max_trx_id; 00552 00553 UT_NOT_USED(index); 00554 00555 ut_ad(!(index->type & DICT_CLUSTERED)); 00556 ut_ad(page_rec_is_user_rec(rec)); 00557 00558 /* NOTE that we might call this function while holding the search 00559 system latch. To obey the latching order we must NOT reserve the 00560 kernel mutex here! */ 00561 00562 if (recv_recovery_is_on()) { 00563 00564 return(FALSE); 00565 } 00566 00567 max_trx_id = page_get_max_trx_id(buf_frame_align(rec)); 00568 00569 if (ut_dulint_cmp(max_trx_id, view->up_limit_id) >= 0) { 00570 00571 return(FALSE); 00572 } 00573 00574 return(TRUE); 00575 } 00576 00577 /************************************************************************* 00578 Creates the lock system at database start. */ 00579 00580 void 00581 lock_sys_create( 00582 /*============*/ 00583 ulint n_cells) /* in: number of slots in lock hash table */ 00584 { 00585 lock_sys = mem_alloc(sizeof(lock_sys_t)); 00586 00587 lock_sys->rec_hash = hash_create(n_cells); 00588 00589 /* hash_create_mutexes(lock_sys->rec_hash, 2, SYNC_REC_LOCK); */ 00590 00591 lock_latest_err_file = os_file_create_tmpfile(); 00592 ut_a(lock_latest_err_file); 00593 } 00594 00595 /************************************************************************* 00596 Gets the size of a lock struct. */ 00597 00598 ulint 00599 lock_get_size(void) 00600 /*===============*/ 00601 /* out: size in bytes */ 00602 { 00603 return((ulint)sizeof(lock_t)); 00604 } 00605 00606 /************************************************************************* 00607 Gets the mode of a lock. */ 00608 UNIV_INLINE 00609 ulint 00610 lock_get_mode( 00611 /*==========*/ 00612 /* out: mode */ 00613 lock_t* lock) /* in: lock */ 00614 { 00615 ut_ad(lock); 00616 00617 return(lock->type_mode & LOCK_MODE_MASK); 00618 } 00619 00620 /************************************************************************* 00621 Gets the wait flag of a lock. */ 00622 UNIV_INLINE 00623 ibool 00624 lock_get_wait( 00625 /*==========*/ 00626 /* out: TRUE if waiting */ 00627 lock_t* lock) /* in: lock */ 00628 { 00629 ut_ad(lock); 00630 00631 if (lock->type_mode & LOCK_WAIT) { 00632 00633 return(TRUE); 00634 } 00635 00636 return(FALSE); 00637 } 00638 00639 /************************************************************************* 00640 Gets the source table of an ALTER TABLE transaction. The table must be 00641 covered by an IX or IS table lock. */ 00642 00643 dict_table_t* 00644 lock_get_src_table( 00645 /*===============*/ 00646 /* out: the source table of transaction, 00647 if it is covered by an IX or IS table lock; 00648 dest if there is no source table, and 00649 NULL if the transaction is locking more than 00650 two tables or an inconsistency is found */ 00651 trx_t* trx, /* in: transaction */ 00652 dict_table_t* dest, /* in: destination of ALTER TABLE */ 00653 ulint* mode) /* out: lock mode of the source table */ 00654 { 00655 dict_table_t* src; 00656 lock_t* lock; 00657 00658 src = NULL; 00659 *mode = LOCK_NONE; 00660 00661 for (lock = UT_LIST_GET_FIRST(trx->trx_locks); 00662 lock; 00663 lock = UT_LIST_GET_NEXT(trx_locks, lock)) { 00664 lock_table_t* tab_lock; 00665 ulint lock_mode; 00666 if (!(lock_get_type(lock) & LOCK_TABLE)) { 00667 /* We are only interested in table locks. */ 00668 continue; 00669 } 00670 tab_lock = &lock->un_member.tab_lock; 00671 if (dest == tab_lock->table) { 00672 /* We are not interested in the destination table. */ 00673 continue; 00674 } else if (!src) { 00675 /* This presumably is the source table. */ 00676 src = tab_lock->table; 00677 if (UT_LIST_GET_LEN(src->locks) != 1 || 00678 UT_LIST_GET_FIRST(src->locks) != lock) { 00679 /* We only support the case when 00680 there is only one lock on this table. */ 00681 return(NULL); 00682 } 00683 } else if (src != tab_lock->table) { 00684 /* The transaction is locking more than 00685 two tables (src and dest): abort */ 00686 return(NULL); 00687 } 00688 00689 /* Check that the source table is locked by 00690 LOCK_IX or LOCK_IS. */ 00691 lock_mode = lock_get_mode(lock); 00692 switch (lock_mode) { 00693 case LOCK_IX: 00694 case LOCK_IS: 00695 if (*mode != LOCK_NONE && *mode != lock_mode) { 00696 /* There are multiple locks on src. */ 00697 return(NULL); 00698 } 00699 *mode = lock_mode; 00700 break; 00701 } 00702 } 00703 00704 if (!src) { 00705 /* No source table lock found: flag the situation to caller */ 00706 src = dest; 00707 } 00708 00709 return(src); 00710 } 00711 00712 /************************************************************************* 00713 Determine if the given table is exclusively "owned" by the given 00714 transaction, i.e., transaction holds LOCK_IX and possibly LOCK_AUTO_INC 00715 on the table. */ 00716 00717 ibool 00718 lock_is_table_exclusive( 00719 /*====================*/ 00720 /* out: TRUE if table is only locked by trx, 00721 with LOCK_IX, and possibly LOCK_AUTO_INC */ 00722 dict_table_t* table, /* in: table */ 00723 trx_t* trx) /* in: transaction */ 00724 { 00725 lock_t* lock; 00726 ibool ok = FALSE; 00727 00728 ut_ad(table && trx); 00729 00730 for (lock = UT_LIST_GET_FIRST(table->locks); 00731 lock; 00732 lock = UT_LIST_GET_NEXT(locks, &lock->un_member.tab_lock)) { 00733 if (lock->trx != trx) { 00734 /* A lock on the table is held 00735 by some other transaction. */ 00736 return(FALSE); 00737 } 00738 00739 if (!(lock_get_type(lock) & LOCK_TABLE)) { 00740 /* We are interested in table locks only. */ 00741 continue; 00742 } 00743 00744 switch (lock_get_mode(lock)) { 00745 case LOCK_IX: 00746 ok = TRUE; 00747 break; 00748 case LOCK_AUTO_INC: 00749 /* It is allowed for trx to hold an 00750 auto_increment lock. */ 00751 break; 00752 default: 00753 /* Other table locks than LOCK_IX are not allowed. */ 00754 return(FALSE); 00755 } 00756 } 00757 00758 return(ok); 00759 } 00760 00761 /************************************************************************* 00762 Sets the wait flag of a lock and the back pointer in trx to lock. */ 00763 UNIV_INLINE 00764 void 00765 lock_set_lock_and_trx_wait( 00766 /*=======================*/ 00767 lock_t* lock, /* in: lock */ 00768 trx_t* trx) /* in: trx */ 00769 { 00770 ut_ad(lock); 00771 ut_ad(trx->wait_lock == NULL); 00772 00773 trx->wait_lock = lock; 00774 lock->type_mode = lock->type_mode | LOCK_WAIT; 00775 } 00776 00777 /************************************************************************** 00778 The back pointer to a waiting lock request in the transaction is set to NULL 00779 and the wait bit in lock type_mode is reset. */ 00780 UNIV_INLINE 00781 void 00782 lock_reset_lock_and_trx_wait( 00783 /*=========================*/ 00784 lock_t* lock) /* in: record lock */ 00785 { 00786 ut_ad((lock->trx)->wait_lock == lock); 00787 ut_ad(lock_get_wait(lock)); 00788 00789 /* Reset the back pointer in trx to this waiting lock request */ 00790 00791 (lock->trx)->wait_lock = NULL; 00792 lock->type_mode = lock->type_mode & ~LOCK_WAIT; 00793 } 00794 00795 /************************************************************************* 00796 Gets the gap flag of a record lock. */ 00797 UNIV_INLINE 00798 ibool 00799 lock_rec_get_gap( 00800 /*=============*/ 00801 /* out: TRUE if gap flag set */ 00802 lock_t* lock) /* in: record lock */ 00803 { 00804 ut_ad(lock); 00805 ut_ad(lock_get_type(lock) == LOCK_REC); 00806 00807 if (lock->type_mode & LOCK_GAP) { 00808 00809 return(TRUE); 00810 } 00811 00812 return(FALSE); 00813 } 00814 00815 /************************************************************************* 00816 Gets the LOCK_REC_NOT_GAP flag of a record lock. */ 00817 UNIV_INLINE 00818 ibool 00819 lock_rec_get_rec_not_gap( 00820 /*=====================*/ 00821 /* out: TRUE if LOCK_REC_NOT_GAP flag set */ 00822 lock_t* lock) /* in: record lock */ 00823 { 00824 ut_ad(lock); 00825 ut_ad(lock_get_type(lock) == LOCK_REC); 00826 00827 if (lock->type_mode & LOCK_REC_NOT_GAP) { 00828 00829 return(TRUE); 00830 } 00831 00832 return(FALSE); 00833 } 00834 00835 /************************************************************************* 00836 Gets the waiting insert flag of a record lock. */ 00837 UNIV_INLINE 00838 ibool 00839 lock_rec_get_insert_intention( 00840 /*==========================*/ 00841 /* out: TRUE if gap flag set */ 00842 lock_t* lock) /* in: record lock */ 00843 { 00844 ut_ad(lock); 00845 ut_ad(lock_get_type(lock) == LOCK_REC); 00846 00847 if (lock->type_mode & LOCK_INSERT_INTENTION) { 00848 00849 return(TRUE); 00850 } 00851 00852 return(FALSE); 00853 } 00854 00855 /************************************************************************* 00856 Calculates if lock mode 1 is stronger or equal to lock mode 2. */ 00857 UNIV_INLINE 00858 ibool 00859 lock_mode_stronger_or_eq( 00860 /*=====================*/ 00861 /* out: TRUE if mode1 stronger or equal to mode2 */ 00862 ulint mode1, /* in: lock mode */ 00863 ulint mode2) /* in: lock mode */ 00864 { 00865 ut_ad(mode1 == LOCK_X || mode1 == LOCK_S || mode1 == LOCK_IX 00866 || mode1 == LOCK_IS || mode1 == LOCK_AUTO_INC); 00867 ut_ad(mode2 == LOCK_X || mode2 == LOCK_S || mode2 == LOCK_IX 00868 || mode2 == LOCK_IS || mode2 == LOCK_AUTO_INC); 00869 if (mode1 == LOCK_X) { 00870 00871 return(TRUE); 00872 00873 } else if (mode1 == LOCK_AUTO_INC && mode2 == LOCK_AUTO_INC) { 00874 00875 return(TRUE); 00876 00877 } else if (mode1 == LOCK_S 00878 && (mode2 == LOCK_S || mode2 == LOCK_IS)) { 00879 return(TRUE); 00880 00881 } else if (mode1 == LOCK_IS && mode2 == LOCK_IS) { 00882 00883 return(TRUE); 00884 00885 } else if (mode1 == LOCK_IX && (mode2 == LOCK_IX 00886 || mode2 == LOCK_IS)) { 00887 return(TRUE); 00888 } 00889 00890 return(FALSE); 00891 } 00892 00893 /************************************************************************* 00894 Calculates if lock mode 1 is compatible with lock mode 2. */ 00895 UNIV_INLINE 00896 ibool 00897 lock_mode_compatible( 00898 /*=================*/ 00899 /* out: TRUE if mode1 compatible with mode2 */ 00900 ulint mode1, /* in: lock mode */ 00901 ulint mode2) /* in: lock mode */ 00902 { 00903 ut_ad(mode1 == LOCK_X || mode1 == LOCK_S || mode1 == LOCK_IX 00904 || mode1 == LOCK_IS || mode1 == LOCK_AUTO_INC); 00905 ut_ad(mode2 == LOCK_X || mode2 == LOCK_S || mode2 == LOCK_IX 00906 || mode2 == LOCK_IS || mode2 == LOCK_AUTO_INC); 00907 00908 if (mode1 == LOCK_S && (mode2 == LOCK_IS || mode2 == LOCK_S)) { 00909 00910 return(TRUE); 00911 00912 } else if (mode1 == LOCK_X) { 00913 00914 return(FALSE); 00915 00916 } else if (mode1 == LOCK_AUTO_INC && (mode2 == LOCK_IS 00917 || mode2 == LOCK_IX)) { 00918 return(TRUE); 00919 00920 } else if (mode1 == LOCK_IS && (mode2 == LOCK_IS 00921 || mode2 == LOCK_IX 00922 || mode2 == LOCK_AUTO_INC 00923 || mode2 == LOCK_S)) { 00924 return(TRUE); 00925 00926 } else if (mode1 == LOCK_IX && (mode2 == LOCK_IS 00927 || mode2 == LOCK_AUTO_INC 00928 || mode2 == LOCK_IX)) { 00929 return(TRUE); 00930 } 00931 00932 return(FALSE); 00933 } 00934 00935 /************************************************************************* 00936 Checks if a lock request for a new lock has to wait for request lock2. */ 00937 UNIV_INLINE 00938 ibool 00939 lock_rec_has_to_wait( 00940 /*=================*/ 00941 /* out: TRUE if new lock has to wait for lock2 to be 00942 removed */ 00943 trx_t* trx, /* in: trx of new lock */ 00944 ulint type_mode,/* in: precise mode of the new lock to set: 00945 LOCK_S or LOCK_X, possibly ORed to 00946 LOCK_GAP or LOCK_REC_NOT_GAP, LOCK_INSERT_INTENTION */ 00947 lock_t* lock2, /* in: another record lock; NOTE that it is assumed 00948 that this has a lock bit set on the same record as 00949 in the new lock we are setting */ 00950 ibool lock_is_on_supremum) /* in: TRUE if we are setting the lock 00951 on the 'supremum' record of an index 00952 page: we know then that the lock request 00953 is really for a 'gap' type lock */ 00954 { 00955 ut_ad(trx && lock2); 00956 ut_ad(lock_get_type(lock2) == LOCK_REC); 00957 00958 if (trx != lock2->trx 00959 && !lock_mode_compatible(LOCK_MODE_MASK & type_mode, 00960 lock_get_mode(lock2))) { 00961 00962 /* We have somewhat complex rules when gap type record locks 00963 cause waits */ 00964 00965 if ((lock_is_on_supremum || (type_mode & LOCK_GAP)) 00966 && !(type_mode & LOCK_INSERT_INTENTION)) { 00967 00968 /* Gap type locks without LOCK_INSERT_INTENTION flag 00969 do not need to wait for anything. This is because 00970 different users can have conflicting lock types 00971 on gaps. */ 00972 00973 return(FALSE); 00974 } 00975 00976 if (!(type_mode & LOCK_INSERT_INTENTION) 00977 && lock_rec_get_gap(lock2)) { 00978 00979 /* Record lock (LOCK_ORDINARY or LOCK_REC_NOT_GAP 00980 does not need to wait for a gap type lock */ 00981 00982 return(FALSE); 00983 } 00984 00985 if ((type_mode & LOCK_GAP) 00986 && lock_rec_get_rec_not_gap(lock2)) { 00987 00988 /* Lock on gap does not need to wait for 00989 a LOCK_REC_NOT_GAP type lock */ 00990 00991 return(FALSE); 00992 } 00993 00994 if (lock_rec_get_insert_intention(lock2)) { 00995 00996 /* No lock request needs to wait for an insert 00997 intention lock to be removed. This is ok since our 00998 rules allow conflicting locks on gaps. This eliminates 00999 a spurious deadlock caused by a next-key lock waiting 01000 for an insert intention lock; when the insert 01001 intention lock was granted, the insert deadlocked on 01002 the waiting next-key lock. 01003 01004 Also, insert intention locks do not disturb each 01005 other. */ 01006 01007 return(FALSE); 01008 } 01009 01010 return(TRUE); 01011 } 01012 01013 return(FALSE); 01014 } 01015 01016 /************************************************************************* 01017 Checks if a lock request lock1 has to wait for request lock2. */ 01018 static 01019 ibool 01020 lock_has_to_wait( 01021 /*=============*/ 01022 /* out: TRUE if lock1 has to wait for lock2 to be 01023 removed */ 01024 lock_t* lock1, /* in: waiting lock */ 01025 lock_t* lock2) /* in: another lock; NOTE that it is assumed that this 01026 has a lock bit set on the same record as in lock1 if 01027 the locks are record locks */ 01028 { 01029 ut_ad(lock1 && lock2); 01030 01031 if (lock1->trx != lock2->trx 01032 && !lock_mode_compatible(lock_get_mode(lock1), 01033 lock_get_mode(lock2))) { 01034 if (lock_get_type(lock1) == LOCK_REC) { 01035 ut_ad(lock_get_type(lock2) == LOCK_REC); 01036 01037 /* If this lock request is for a supremum record 01038 then the second bit on the lock bitmap is set */ 01039 01040 return(lock_rec_has_to_wait(lock1->trx, 01041 lock1->type_mode, lock2, 01042 lock_rec_get_nth_bit(lock1,1))); 01043 } 01044 01045 return(TRUE); 01046 } 01047 01048 return(FALSE); 01049 } 01050 01051 /*============== RECORD LOCK BASIC FUNCTIONS ============================*/ 01052 01053 /************************************************************************* 01054 Gets the number of bits in a record lock bitmap. */ 01055 UNIV_INLINE 01056 ulint 01057 lock_rec_get_n_bits( 01058 /*================*/ 01059 /* out: number of bits */ 01060 lock_t* lock) /* in: record lock */ 01061 { 01062 return(lock->un_member.rec_lock.n_bits); 01063 } 01064 01065 /************************************************************************** 01066 Sets the nth bit of a record lock to TRUE. */ 01067 UNIV_INLINE 01068 void 01069 lock_rec_set_nth_bit( 01070 /*=================*/ 01071 lock_t* lock, /* in: record lock */ 01072 ulint i) /* in: index of the bit */ 01073 { 01074 ulint byte_index; 01075 ulint bit_index; 01076 byte* ptr; 01077 ulint b; 01078 01079 ut_ad(lock); 01080 ut_ad(lock_get_type(lock) == LOCK_REC); 01081 ut_ad(i < lock->un_member.rec_lock.n_bits); 01082 01083 byte_index = i / 8; 01084 bit_index = i % 8; 01085 01086 ptr = (byte*)lock + sizeof(lock_t) + byte_index; 01087 01088 b = (ulint)*ptr; 01089 01090 b = ut_bit_set_nth(b, bit_index, TRUE); 01091 01092 *ptr = (byte)b; 01093 } 01094 01095 /************************************************************************** 01096 Looks for a set bit in a record lock bitmap. Returns ULINT_UNDEFINED, 01097 if none found. */ 01098 static 01099 ulint 01100 lock_rec_find_set_bit( 01101 /*==================*/ 01102 /* out: bit index == heap number of the record, or 01103 ULINT_UNDEFINED if none found */ 01104 lock_t* lock) /* in: record lock with at least one bit set */ 01105 { 01106 ulint i; 01107 01108 for (i = 0; i < lock_rec_get_n_bits(lock); i++) { 01109 01110 if (lock_rec_get_nth_bit(lock, i)) { 01111 01112 return(i); 01113 } 01114 } 01115 01116 return(ULINT_UNDEFINED); 01117 } 01118 01119 /************************************************************************** 01120 Resets the nth bit of a record lock. */ 01121 UNIV_INLINE 01122 void 01123 lock_rec_reset_nth_bit( 01124 /*===================*/ 01125 lock_t* lock, /* in: record lock */ 01126 ulint i) /* in: index of the bit which must be set to TRUE 01127 when this function is called */ 01128 { 01129 ulint byte_index; 01130 ulint bit_index; 01131 byte* ptr; 01132 ulint b; 01133 01134 ut_ad(lock); 01135 ut_ad(lock_get_type(lock) == LOCK_REC); 01136 ut_ad(i < lock->un_member.rec_lock.n_bits); 01137 01138 byte_index = i / 8; 01139 bit_index = i % 8; 01140 01141 ptr = (byte*)lock + sizeof(lock_t) + byte_index; 01142 01143 b = (ulint)*ptr; 01144 01145 b = ut_bit_set_nth(b, bit_index, FALSE); 01146 01147 *ptr = (byte)b; 01148 } 01149 01150 /************************************************************************* 01151 Gets the first or next record lock on a page. */ 01152 UNIV_INLINE 01153 lock_t* 01154 lock_rec_get_next_on_page( 01155 /*======================*/ 01156 /* out: next lock, NULL if none exists */ 01157 lock_t* lock) /* in: a record lock */ 01158 { 01159 ulint space; 01160 ulint page_no; 01161 01162 #ifdef UNIV_SYNC_DEBUG 01163 ut_ad(mutex_own(&kernel_mutex)); 01164 #endif /* UNIV_SYNC_DEBUG */ 01165 ut_ad(lock_get_type(lock) == LOCK_REC); 01166 01167 space = lock->un_member.rec_lock.space; 01168 page_no = lock->un_member.rec_lock.page_no; 01169 01170 for (;;) { 01171 lock = HASH_GET_NEXT(hash, lock); 01172 01173 if (!lock) { 01174 01175 break; 01176 } 01177 01178 if ((lock->un_member.rec_lock.space == space) 01179 && (lock->un_member.rec_lock.page_no == page_no)) { 01180 01181 break; 01182 } 01183 } 01184 01185 return(lock); 01186 } 01187 01188 /************************************************************************* 01189 Gets the first record lock on a page, where the page is identified by its 01190 file address. */ 01191 UNIV_INLINE 01192 lock_t* 01193 lock_rec_get_first_on_page_addr( 01194 /*============================*/ 01195 /* out: first lock, NULL if none exists */ 01196 ulint space, /* in: space */ 01197 ulint page_no)/* in: page number */ 01198 { 01199 lock_t* lock; 01200 01201 #ifdef UNIV_SYNC_DEBUG 01202 ut_ad(mutex_own(&kernel_mutex)); 01203 #endif /* UNIV_SYNC_DEBUG */ 01204 01205 lock = HASH_GET_FIRST(lock_sys->rec_hash, 01206 lock_rec_hash(space, page_no)); 01207 while (lock) { 01208 if ((lock->un_member.rec_lock.space == space) 01209 && (lock->un_member.rec_lock.page_no == page_no)) { 01210 01211 break; 01212 } 01213 01214 lock = HASH_GET_NEXT(hash, lock); 01215 } 01216 01217 return(lock); 01218 } 01219 01220 /************************************************************************* 01221 Returns TRUE if there are explicit record locks on a page. */ 01222 01223 ibool 01224 lock_rec_expl_exist_on_page( 01225 /*========================*/ 01226 /* out: TRUE if there are explicit record locks on 01227 the page */ 01228 ulint space, /* in: space id */ 01229 ulint page_no)/* in: page number */ 01230 { 01231 ibool ret; 01232 01233 mutex_enter(&kernel_mutex); 01234 01235 if (lock_rec_get_first_on_page_addr(space, page_no)) { 01236 ret = TRUE; 01237 } else { 01238 ret = FALSE; 01239 } 01240 01241 mutex_exit(&kernel_mutex); 01242 01243 return(ret); 01244 } 01245 01246 /************************************************************************* 01247 Gets the first record lock on a page, where the page is identified by a 01248 pointer to it. */ 01249 UNIV_INLINE 01250 lock_t* 01251 lock_rec_get_first_on_page( 01252 /*=======================*/ 01253 /* out: first lock, NULL if none exists */ 01254 byte* ptr) /* in: pointer to somewhere on the page */ 01255 { 01256 ulint hash; 01257 lock_t* lock; 01258 ulint space; 01259 ulint page_no; 01260 01261 #ifdef UNIV_SYNC_DEBUG 01262 ut_ad(mutex_own(&kernel_mutex)); 01263 #endif /* UNIV_SYNC_DEBUG */ 01264 01265 hash = buf_frame_get_lock_hash_val(ptr); 01266 01267 lock = HASH_GET_FIRST(lock_sys->rec_hash, hash); 01268 01269 while (lock) { 01270 space = buf_frame_get_space_id(ptr); 01271 page_no = buf_frame_get_page_no(ptr); 01272 01273 if ((lock->un_member.rec_lock.space == space) 01274 && (lock->un_member.rec_lock.page_no == page_no)) { 01275 01276 break; 01277 } 01278 01279 lock = HASH_GET_NEXT(hash, lock); 01280 } 01281 01282 return(lock); 01283 } 01284 01285 /************************************************************************* 01286 Gets the next explicit lock request on a record. */ 01287 UNIV_INLINE 01288 lock_t* 01289 lock_rec_get_next( 01290 /*==============*/ 01291 /* out: next lock, NULL if none exists */ 01292 rec_t* rec, /* in: record on a page */ 01293 lock_t* lock) /* in: lock */ 01294 { 01295 #ifdef UNIV_SYNC_DEBUG 01296 ut_ad(mutex_own(&kernel_mutex)); 01297 #endif /* UNIV_SYNC_DEBUG */ 01298 ut_ad(lock_get_type(lock) == LOCK_REC); 01299 01300 if (page_rec_is_comp(rec)) { 01301 do { 01302 lock = lock_rec_get_next_on_page(lock); 01303 } while (lock && !lock_rec_get_nth_bit(lock, 01304 rec_get_heap_no(rec, TRUE))); 01305 } else { 01306 do { 01307 lock = lock_rec_get_next_on_page(lock); 01308 } while (lock && !lock_rec_get_nth_bit(lock, 01309 rec_get_heap_no(rec, FALSE))); 01310 } 01311 01312 return(lock); 01313 } 01314 01315 /************************************************************************* 01316 Gets the first explicit lock request on a record. */ 01317 UNIV_INLINE 01318 lock_t* 01319 lock_rec_get_first( 01320 /*===============*/ 01321 /* out: first lock, NULL if none exists */ 01322 rec_t* rec) /* in: record on a page */ 01323 { 01324 lock_t* lock; 01325 01326 #ifdef UNIV_SYNC_DEBUG 01327 ut_ad(mutex_own(&kernel_mutex)); 01328 #endif /* UNIV_SYNC_DEBUG */ 01329 01330 lock = lock_rec_get_first_on_page(rec); 01331 if (UNIV_LIKELY_NULL(lock)) { 01332 ulint heap_no = rec_get_heap_no(rec, page_rec_is_comp(rec)); 01333 01334 while (lock && !lock_rec_get_nth_bit(lock, heap_no)) { 01335 lock = lock_rec_get_next_on_page(lock); 01336 } 01337 } 01338 01339 return(lock); 01340 } 01341 01342 /************************************************************************* 01343 Resets the record lock bitmap to zero. NOTE: does not touch the wait_lock 01344 pointer in the transaction! This function is used in lock object creation 01345 and resetting. */ 01346 static 01347 void 01348 lock_rec_bitmap_reset( 01349 /*==================*/ 01350 lock_t* lock) /* in: record lock */ 01351 { 01352 byte* ptr; 01353 ulint n_bytes; 01354 ulint i; 01355 01356 ut_ad(lock_get_type(lock) == LOCK_REC); 01357 01358 /* Reset to zero the bitmap which resides immediately after the lock 01359 struct */ 01360 01361 ptr = (byte*)lock + sizeof(lock_t); 01362 01363 n_bytes = lock_rec_get_n_bits(lock) / 8; 01364 01365 ut_ad((lock_rec_get_n_bits(lock) % 8) == 0); 01366 01367 for (i = 0; i < n_bytes; i++) { 01368 01369 *ptr = 0; 01370 ptr++; 01371 } 01372 } 01373 01374 /************************************************************************* 01375 Copies a record lock to heap. */ 01376 static 01377 lock_t* 01378 lock_rec_copy( 01379 /*==========*/ 01380 /* out: copy of lock */ 01381 lock_t* lock, /* in: record lock */ 01382 mem_heap_t* heap) /* in: memory heap */ 01383 { 01384 lock_t* dupl_lock; 01385 ulint size; 01386 01387 ut_ad(lock_get_type(lock) == LOCK_REC); 01388 01389 size = sizeof(lock_t) + lock_rec_get_n_bits(lock) / 8; 01390 01391 dupl_lock = mem_heap_alloc(heap, size); 01392 01393 ut_memcpy(dupl_lock, lock, size); 01394 01395 return(dupl_lock); 01396 } 01397 01398 /************************************************************************* 01399 Gets the previous record lock set on a record. */ 01400 static 01401 lock_t* 01402 lock_rec_get_prev( 01403 /*==============*/ 01404 /* out: previous lock on the same record, NULL if 01405 none exists */ 01406 lock_t* in_lock,/* in: record lock */ 01407 ulint heap_no)/* in: heap number of the record */ 01408 { 01409 lock_t* lock; 01410 ulint space; 01411 ulint page_no; 01412 lock_t* found_lock = NULL; 01413 01414 #ifdef UNIV_SYNC_DEBUG 01415 ut_ad(mutex_own(&kernel_mutex)); 01416 #endif /* UNIV_SYNC_DEBUG */ 01417 ut_ad(lock_get_type(in_lock) == LOCK_REC); 01418 01419 space = in_lock->un_member.rec_lock.space; 01420 page_no = in_lock->un_member.rec_lock.page_no; 01421 01422 lock = lock_rec_get_first_on_page_addr(space, page_no); 01423 01424 for (;;) { 01425 ut_ad(lock); 01426 01427 if (lock == in_lock) { 01428 01429 return(found_lock); 01430 } 01431 01432 if (lock_rec_get_nth_bit(lock, heap_no)) { 01433 01434 found_lock = lock; 01435 } 01436 01437 lock = lock_rec_get_next_on_page(lock); 01438 } 01439 } 01440 01441 /*============= FUNCTIONS FOR ANALYZING TABLE LOCK QUEUE ================*/ 01442 01443 /************************************************************************* 01444 Checks if a transaction has the specified table lock, or stronger. */ 01445 UNIV_INLINE 01446 lock_t* 01447 lock_table_has( 01448 /*===========*/ 01449 /* out: lock or NULL */ 01450 trx_t* trx, /* in: transaction */ 01451 dict_table_t* table, /* in: table */ 01452 ulint mode) /* in: lock mode */ 01453 { 01454 lock_t* lock; 01455 01456 #ifdef UNIV_SYNC_DEBUG 01457 ut_ad(mutex_own(&kernel_mutex)); 01458 #endif /* UNIV_SYNC_DEBUG */ 01459 01460 /* Look for stronger locks the same trx already has on the table */ 01461 01462 lock = UT_LIST_GET_LAST(table->locks); 01463 01464 while (lock != NULL) { 01465 01466 if (lock->trx == trx 01467 && lock_mode_stronger_or_eq(lock_get_mode(lock), mode)) { 01468 01469 /* The same trx already has locked the table in 01470 a mode stronger or equal to the mode given */ 01471 01472 ut_ad(!lock_get_wait(lock)); 01473 01474 return(lock); 01475 } 01476 01477 lock = UT_LIST_GET_PREV(un_member.tab_lock.locks, lock); 01478 } 01479 01480 return(NULL); 01481 } 01482 01483 /*============= FUNCTIONS FOR ANALYZING RECORD LOCK QUEUE ================*/ 01484 01485 /************************************************************************* 01486 Checks if a transaction has a GRANTED explicit lock on rec stronger or equal 01487 to precise_mode. */ 01488 UNIV_INLINE 01489 lock_t* 01490 lock_rec_has_expl( 01491 /*==============*/ 01492 /* out: lock or NULL */ 01493 ulint precise_mode,/* in: LOCK_S or LOCK_X possibly ORed to 01494 LOCK_GAP or LOCK_REC_NOT_GAP, 01495 for a supremum record we regard this always a gap 01496 type request */ 01497 rec_t* rec, /* in: record */ 01498 trx_t* trx) /* in: transaction */ 01499 { 01500 lock_t* lock; 01501 01502 #ifdef UNIV_SYNC_DEBUG 01503 ut_ad(mutex_own(&kernel_mutex)); 01504 #endif /* UNIV_SYNC_DEBUG */ 01505 ut_ad((precise_mode & LOCK_MODE_MASK) == LOCK_S 01506 || (precise_mode & LOCK_MODE_MASK) == LOCK_X); 01507 ut_ad(!(precise_mode & LOCK_INSERT_INTENTION)); 01508 01509 lock = lock_rec_get_first(rec); 01510 01511 while (lock) { 01512 if (lock->trx == trx 01513 && lock_mode_stronger_or_eq(lock_get_mode(lock), 01514 precise_mode & LOCK_MODE_MASK) 01515 && !lock_get_wait(lock) 01516 && (!lock_rec_get_rec_not_gap(lock) 01517 || (precise_mode & LOCK_REC_NOT_GAP) 01518 || page_rec_is_supremum(rec)) 01519 && (!lock_rec_get_gap(lock) 01520 || (precise_mode & LOCK_GAP) 01521 || page_rec_is_supremum(rec)) 01522 && (!lock_rec_get_insert_intention(lock))) { 01523 01524 return(lock); 01525 } 01526 01527 lock = lock_rec_get_next(rec, lock); 01528 } 01529 01530 return(NULL); 01531 } 01532 01533 #ifndef UNIV_HOTBACKUP 01534 /************************************************************************* 01535 Checks if some other transaction has a lock request in the queue. */ 01536 static 01537 lock_t* 01538 lock_rec_other_has_expl_req( 01539 /*========================*/ 01540 /* out: lock or NULL */ 01541 ulint mode, /* in: LOCK_S or LOCK_X */ 01542 ulint gap, /* in: LOCK_GAP if also gap locks are taken 01543 into account, or 0 if not */ 01544 ulint wait, /* in: LOCK_WAIT if also waiting locks are 01545 taken into account, or 0 if not */ 01546 rec_t* rec, /* in: record to look at */ 01547 trx_t* trx) /* in: transaction, or NULL if requests by all 01548 transactions are taken into account */ 01549 { 01550 lock_t* lock; 01551 01552 #ifdef UNIV_SYNC_DEBUG 01553 ut_ad(mutex_own(&kernel_mutex)); 01554 #endif /* UNIV_SYNC_DEBUG */ 01555 ut_ad(mode == LOCK_X || mode == LOCK_S); 01556 ut_ad(gap == 0 || gap == LOCK_GAP); 01557 ut_ad(wait == 0 || wait == LOCK_WAIT); 01558 01559 lock = lock_rec_get_first(rec); 01560 01561 while (lock) { 01562 if (lock->trx != trx 01563 && (gap || 01564 !(lock_rec_get_gap(lock) || page_rec_is_supremum(rec))) 01565 && (wait || !lock_get_wait(lock)) 01566 && lock_mode_stronger_or_eq(lock_get_mode(lock), mode)) { 01567 01568 return(lock); 01569 } 01570 01571 lock = lock_rec_get_next(rec, lock); 01572 } 01573 01574 return(NULL); 01575 } 01576 #endif /* !UNIV_HOTBACKUP */ 01577 01578 /************************************************************************* 01579 Checks if some other transaction has a conflicting explicit lock request 01580 in the queue, so that we have to wait. */ 01581 static 01582 lock_t* 01583 lock_rec_other_has_conflicting( 01584 /*===========================*/ 01585 /* out: lock or NULL */ 01586 ulint mode, /* in: LOCK_S or LOCK_X, 01587 possibly ORed to LOCK_GAP or LOC_REC_NOT_GAP, 01588 LOCK_INSERT_INTENTION */ 01589 rec_t* rec, /* in: record to look at */ 01590 trx_t* trx) /* in: our transaction */ 01591 { 01592 lock_t* lock; 01593 #ifdef UNIV_SYNC_DEBUG 01594 ut_ad(mutex_own(&kernel_mutex)); 01595 #endif /* UNIV_SYNC_DEBUG */ 01596 01597 lock = lock_rec_get_first(rec); 01598 01599 while (lock) { 01600 if (lock_rec_has_to_wait(trx, mode, lock, 01601 page_rec_is_supremum(rec))) { 01602 01603 return(lock); 01604 } 01605 01606 lock = lock_rec_get_next(rec, lock); 01607 } 01608 01609 return(NULL); 01610 } 01611 01612 /************************************************************************* 01613 Looks for a suitable type record lock struct by the same trx on the same page. 01614 This can be used to save space when a new record lock should be set on a page: 01615 no new struct is needed, if a suitable old is found. */ 01616 UNIV_INLINE 01617 lock_t* 01618 lock_rec_find_similar_on_page( 01619 /*==========================*/ 01620 /* out: lock or NULL */ 01621 ulint type_mode, /* in: lock type_mode field */ 01622 rec_t* rec, /* in: record */ 01623 trx_t* trx) /* in: transaction */ 01624 { 01625 lock_t* lock; 01626 ulint heap_no; 01627 01628 #ifdef UNIV_SYNC_DEBUG 01629 ut_ad(mutex_own(&kernel_mutex)); 01630 #endif /* UNIV_SYNC_DEBUG */ 01631 01632 heap_no = rec_get_heap_no(rec, page_rec_is_comp(rec)); 01633 lock = lock_rec_get_first_on_page(rec); 01634 01635 while (lock != NULL) { 01636 if (lock->trx == trx 01637 && lock->type_mode == type_mode 01638 && lock_rec_get_n_bits(lock) > heap_no) { 01639 01640 return(lock); 01641 } 01642 01643 lock = lock_rec_get_next_on_page(lock); 01644 } 01645 01646 return(NULL); 01647 } 01648 01649 /************************************************************************* 01650 Checks if some transaction has an implicit x-lock on a record in a secondary 01651 index. */ 01652 01653 trx_t* 01654 lock_sec_rec_some_has_impl_off_kernel( 01655 /*==================================*/ 01656 /* out: transaction which has the x-lock, or 01657 NULL */ 01658 rec_t* rec, /* in: user record */ 01659 dict_index_t* index, /* in: secondary index */ 01660 const ulint* offsets)/* in: rec_get_offsets(rec, index) */ 01661 { 01662 page_t* page; 01663 01664 #ifdef UNIV_SYNC_DEBUG 01665 ut_ad(mutex_own(&kernel_mutex)); 01666 #endif /* UNIV_SYNC_DEBUG */ 01667 ut_ad(!(index->type & DICT_CLUSTERED)); 01668 ut_ad(page_rec_is_user_rec(rec)); 01669 ut_ad(rec_offs_validate(rec, index, offsets)); 01670 01671 page = buf_frame_align(rec); 01672 01673 /* Some transaction may have an implicit x-lock on the record only 01674 if the max trx id for the page >= min trx id for the trx list, or 01675 database recovery is running. We do not write the changes of a page 01676 max trx id to the log, and therefore during recovery, this value 01677 for a page may be incorrect. */ 01678 01679 if (!(ut_dulint_cmp(page_get_max_trx_id(page), 01680 trx_list_get_min_trx_id()) >= 0) 01681 && !recv_recovery_is_on()) { 01682 01683 return(NULL); 01684 } 01685 01686 /* Ok, in this case it is possible that some transaction has an 01687 implicit x-lock. We have to look in the clustered index. */ 01688 01689 if (!lock_check_trx_id_sanity(page_get_max_trx_id(page), 01690 rec, index, offsets, TRUE)) { 01691 buf_page_print(page); 01692 01693 /* The page is corrupt: try to avoid a crash by returning 01694 NULL */ 01695 return(NULL); 01696 } 01697 01698 return(row_vers_impl_x_locked_off_kernel(rec, index, offsets)); 01699 } 01700 01701 /************************************************************************* 01702 Return approximate number or record locks (bits set in the bitmap) for 01703 this transaction. Since delete-marked records may be removed, the 01704 record count will not be precise. */ 01705 01706 ulint 01707 lock_number_of_rows_locked( 01708 /*=======================*/ 01709 trx_t* trx) /* in: transaction */ 01710 { 01711 lock_t* lock; 01712 ulint n_records = 0; 01713 ulint n_bits; 01714 ulint n_bit; 01715 01716 lock = UT_LIST_GET_FIRST(trx->trx_locks); 01717 01718 while (lock) { 01719 if (lock_get_type(lock) == LOCK_REC) { 01720 n_bits = lock_rec_get_n_bits(lock); 01721 01722 for (n_bit = 0; n_bit < n_bits; n_bit++) { 01723 if (lock_rec_get_nth_bit(lock, n_bit)) { 01724 n_records++; 01725 } 01726 } 01727 } 01728 01729 lock = UT_LIST_GET_NEXT(trx_locks, lock); 01730 } 01731 01732 return (n_records); 01733 } 01734 01735 /*============== RECORD LOCK CREATION AND QUEUE MANAGEMENT =============*/ 01736 01737 /************************************************************************* 01738 Creates a new record lock and inserts it to the lock queue. Does NOT check 01739 for deadlocks or lock compatibility! */ 01740 static 01741 lock_t* 01742 lock_rec_create( 01743 /*============*/ 01744 /* out: created lock */ 01745 ulint type_mode,/* in: lock mode and wait flag, type is 01746 ignored and replaced by LOCK_REC */ 01747 rec_t* rec, /* in: record on page */ 01748 dict_index_t* index, /* in: index of record */ 01749 trx_t* trx) /* in: transaction */ 01750 { 01751 page_t* page; 01752 lock_t* lock; 01753 ulint page_no; 01754 ulint heap_no; 01755 ulint space; 01756 ulint n_bits; 01757 ulint n_bytes; 01758 01759 #ifdef UNIV_SYNC_DEBUG 01760 ut_ad(mutex_own(&kernel_mutex)); 01761 #endif /* UNIV_SYNC_DEBUG */ 01762 01763 page = buf_frame_align(rec); 01764 space = buf_frame_get_space_id(page); 01765 page_no = buf_frame_get_page_no(page); 01766 heap_no = rec_get_heap_no(rec, page_is_comp(page)); 01767 01768 ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table)); 01769 01770 /* If rec is the supremum record, then we reset the gap and 01771 LOCK_REC_NOT_GAP bits, as all locks on the supremum are 01772 automatically of the gap type */ 01773 01774 if (rec == page_get_supremum_rec(page)) { 01775 ut_ad(!(type_mode & LOCK_REC_NOT_GAP)); 01776 01777 type_mode = type_mode & ~(LOCK_GAP | LOCK_REC_NOT_GAP); 01778 } 01779 01780 /* Make lock bitmap bigger by a safety margin */ 01781 n_bits = page_dir_get_n_heap(page) + LOCK_PAGE_BITMAP_MARGIN; 01782 n_bytes = 1 + n_bits / 8; 01783 01784 lock = mem_heap_alloc(trx->lock_heap, sizeof(lock_t) + n_bytes); 01785 01786 UT_LIST_ADD_LAST(trx_locks, trx->trx_locks, lock); 01787 01788 lock->trx = trx; 01789 01790 lock->type_mode = (type_mode & ~LOCK_TYPE_MASK) | LOCK_REC; 01791 lock->index = index; 01792 01793 lock->un_member.rec_lock.space = space; 01794 lock->un_member.rec_lock.page_no = page_no; 01795 lock->un_member.rec_lock.n_bits = n_bytes * 8; 01796 01797 /* Reset to zero the bitmap which resides immediately after the 01798 lock struct */ 01799 01800 lock_rec_bitmap_reset(lock); 01801 01802 /* Set the bit corresponding to rec */ 01803 lock_rec_set_nth_bit(lock, heap_no); 01804 01805 HASH_INSERT(lock_t, hash, lock_sys->rec_hash, 01806 lock_rec_fold(space, page_no), lock); 01807 if (type_mode & LOCK_WAIT) { 01808 01809 lock_set_lock_and_trx_wait(lock, trx); 01810 } 01811 01812 return(lock); 01813 } 01814 01815 /************************************************************************* 01816 Enqueues a waiting request for a lock which cannot be granted immediately. 01817 Checks for deadlocks. */ 01818 static 01819 ulint 01820 lock_rec_enqueue_waiting( 01821 /*=====================*/ 01822 /* out: DB_LOCK_WAIT, DB_DEADLOCK, or 01823 DB_QUE_THR_SUSPENDED, or DB_SUCCESS; 01824 DB_SUCCESS means that there was a deadlock, 01825 but another transaction was chosen as a 01826 victim, and we got the lock immediately: 01827 no need to wait then */ 01828 ulint type_mode,/* in: lock mode this transaction is 01829 requesting: LOCK_S or LOCK_X, possibly ORed 01830 with LOCK_GAP or LOCK_REC_NOT_GAP, ORed 01831 with LOCK_INSERT_INTENTION if this waiting 01832 lock request is set when performing an 01833 insert of an index record */ 01834 rec_t* rec, /* in: record */ 01835 dict_index_t* index, /* in: index of record */ 01836 que_thr_t* thr) /* in: query thread */ 01837 { 01838 lock_t* lock; 01839 trx_t* trx; 01840 01841 #ifdef UNIV_SYNC_DEBUG 01842 ut_ad(mutex_own(&kernel_mutex)); 01843 #endif /* UNIV_SYNC_DEBUG */ 01844 01845 /* Test if there already is some other reason to suspend thread: 01846 we do not enqueue a lock request if the query thread should be 01847 stopped anyway */ 01848 01849 if (que_thr_stop(thr)) { 01850 01851 ut_error; 01852 01853 return(DB_QUE_THR_SUSPENDED); 01854 } 01855 01856 trx = thr_get_trx(thr); 01857 01858 if (trx->dict_operation) { 01859 ut_print_timestamp(stderr); 01860 fputs( 01861 " InnoDB: Error: a record lock wait happens in a dictionary operation!\n" 01862 "InnoDB: Table name ", stderr); 01863 ut_print_name(stderr, trx, TRUE, index->table_name); 01864 fputs(".\n" 01865 "InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n", 01866 stderr); 01867 } 01868 01869 /* Enqueue the lock request that will wait to be granted */ 01870 lock = lock_rec_create(type_mode | LOCK_WAIT, rec, index, trx); 01871 01872 /* Check if a deadlock occurs: if yes, remove the lock request and 01873 return an error code */ 01874 01875 if (lock_deadlock_occurs(lock, trx)) { 01876 01877 lock_reset_lock_and_trx_wait(lock); 01878 lock_rec_reset_nth_bit(lock, rec_get_heap_no(rec, 01879 page_rec_is_comp(rec))); 01880 01881 return(DB_DEADLOCK); 01882 } 01883 01884 /* If there was a deadlock but we chose another transaction as a 01885 victim, it is possible that we already have the lock now granted! */ 01886 01887 if (trx->wait_lock == NULL) { 01888 01889 return(DB_SUCCESS); 01890 } 01891 01892 trx->que_state = TRX_QUE_LOCK_WAIT; 01893 trx->was_chosen_as_deadlock_victim = FALSE; 01894 trx->wait_started = time(NULL); 01895 01896 ut_a(que_thr_stop(thr)); 01897 01898 #ifdef UNIV_DEBUG 01899 if (lock_print_waits) { 01900 fprintf(stderr, "Lock wait for trx %lu in index ", 01901 (ulong) ut_dulint_get_low(trx->id)); 01902 ut_print_name(stderr, trx, FALSE, index->name); 01903 } 01904 #endif /* UNIV_DEBUG */ 01905 01906 return(DB_LOCK_WAIT); 01907 } 01908 01909 /************************************************************************* 01910 Adds a record lock request in the record queue. The request is normally 01911 added as the last in the queue, but if there are no waiting lock requests 01912 on the record, and the request to be added is not a waiting request, we 01913 can reuse a suitable record lock object already existing on the same page, 01914 just setting the appropriate bit in its bitmap. This is a low-level function 01915 which does NOT check for deadlocks or lock compatibility! */ 01916 static 01917 lock_t* 01918 lock_rec_add_to_queue( 01919 /*==================*/ 01920 /* out: lock where the bit was set */ 01921 ulint type_mode,/* in: lock mode, wait, gap etc. flags; 01922 type is ignored and replaced by LOCK_REC */ 01923 rec_t* rec, /* in: record on page */ 01924 dict_index_t* index, /* in: index of record */ 01925 trx_t* trx) /* in: transaction */ 01926 { 01927 lock_t* lock; 01928 lock_t* similar_lock = NULL; 01929 ulint heap_no; 01930 ibool somebody_waits = FALSE; 01931 01932 #ifdef UNIV_SYNC_DEBUG 01933 ut_ad(mutex_own(&kernel_mutex)); 01934 #endif /* UNIV_SYNC_DEBUG */ 01935 ut_ad((type_mode & (LOCK_WAIT | LOCK_GAP)) 01936 || ((type_mode & LOCK_MODE_MASK) != LOCK_S) 01937 || !lock_rec_other_has_expl_req(LOCK_X, 0, LOCK_WAIT, 01938 rec, trx)); 01939 ut_ad((type_mode & (LOCK_WAIT | LOCK_GAP)) 01940 || ((type_mode & LOCK_MODE_MASK) != LOCK_X) 01941 || !lock_rec_other_has_expl_req(LOCK_S, 0, LOCK_WAIT, 01942 rec, trx)); 01943 01944 type_mode = type_mode | LOCK_REC; 01945 01946 /* If rec is the supremum record, then we can reset the gap bit, as 01947 all locks on the supremum are automatically of the gap type, and we 01948 try to avoid unnecessary memory consumption of a new record lock 01949 struct for a gap type lock */ 01950 01951 if (page_rec_is_supremum(rec)) { 01952 ut_ad(!(type_mode & LOCK_REC_NOT_GAP)); 01953 01954 /* There should never be LOCK_REC_NOT_GAP on a supremum 01955 record, but let us play safe */ 01956 01957 type_mode = type_mode & ~(LOCK_GAP | LOCK_REC_NOT_GAP); 01958 } 01959 01960 /* Look for a waiting lock request on the same record or on a gap */ 01961 01962 heap_no = rec_get_heap_no(rec, page_rec_is_comp(rec)); 01963 lock = lock_rec_get_first_on_page(rec); 01964 01965 while (lock != NULL) { 01966 if (lock_get_wait(lock) 01967 && (lock_rec_get_nth_bit(lock, heap_no))) { 01968 01969 somebody_waits = TRUE; 01970 } 01971 01972 lock = lock_rec_get_next_on_page(lock); 01973 } 01974 01975 /* Look for a similar record lock on the same page: if one is found 01976 and there are no waiting lock requests, we can just set the bit */ 01977 01978 similar_lock = lock_rec_find_similar_on_page(type_mode, rec, trx); 01979 01980 if (similar_lock && !somebody_waits && !(type_mode & LOCK_WAIT)) { 01981 01982 lock_rec_set_nth_bit(similar_lock, heap_no); 01983 01984 return(similar_lock); 01985 } 01986 01987 return(lock_rec_create(type_mode, rec, index, trx)); 01988 } 01989 01990 /************************************************************************* 01991 This is a fast routine for locking a record in the most common cases: 01992 there are no explicit locks on the page, or there is just one lock, owned 01993 by this transaction, and of the right type_mode. This is a low-level function 01994 which does NOT look at implicit locks! Checks lock compatibility within 01995 explicit locks. This function sets a normal next-key lock, or in the case of 01996 a page supremum record, a gap type lock. */ 01997 UNIV_INLINE 01998 ibool 01999 lock_rec_lock_fast( 02000 /*===============*/ 02001 /* out: TRUE if locking succeeded */ 02002 ibool impl, /* in: if TRUE, no lock is set if no wait 02003 is necessary: we assume that the caller will 02004 set an implicit lock */ 02005 ulint mode, /* in: lock mode: LOCK_X or LOCK_S possibly 02006 ORed to either LOCK_GAP or LOCK_REC_NOT_GAP */ 02007 rec_t* rec, /* in: record */ 02008 dict_index_t* index, /* in: index of record */ 02009 que_thr_t* thr) /* in: query thread */ 02010 { 02011 lock_t* lock; 02012 ulint heap_no; 02013 trx_t* trx; 02014 02015 #ifdef UNIV_SYNC_DEBUG 02016 ut_ad(mutex_own(&kernel_mutex)); 02017 #endif /* UNIV_SYNC_DEBUG */ 02018 ut_ad((LOCK_MODE_MASK & mode) != LOCK_S 02019 || lock_table_has(thr_get_trx(thr), index->table, LOCK_IS)); 02020 ut_ad((LOCK_MODE_MASK & mode) != LOCK_X 02021 || lock_table_has(thr_get_trx(thr), index->table, LOCK_IX)); 02022 ut_ad((LOCK_MODE_MASK & mode) == LOCK_S 02023 || (LOCK_MODE_MASK & mode) == LOCK_X); 02024 ut_ad(mode - (LOCK_MODE_MASK & mode) == LOCK_GAP 02025 || mode - (LOCK_MODE_MASK & mode) == 0 02026 || mode - (LOCK_MODE_MASK & mode) == LOCK_REC_NOT_GAP); 02027 02028 heap_no = rec_get_heap_no(rec, page_rec_is_comp(rec)); 02029 02030 lock = lock_rec_get_first_on_page(rec); 02031 02032 trx = thr_get_trx(thr); 02033 02034 if (lock == NULL) { 02035 if (!impl) { 02036 lock_rec_create(mode, rec, index, trx); 02037 02038 if (srv_locks_unsafe_for_binlog 02039 || trx->isolation_level == TRX_ISO_READ_COMMITTED) { 02040 trx_register_new_rec_lock(trx, index); 02041 } 02042 } 02043 02044 return(TRUE); 02045 } 02046 02047 if (lock_rec_get_next_on_page(lock)) { 02048 02049 return(FALSE); 02050 } 02051 02052 if (lock->trx != trx 02053 || lock->type_mode != (mode | LOCK_REC) 02054 || lock_rec_get_n_bits(lock) <= heap_no) { 02055 02056 return(FALSE); 02057 } 02058 02059 if (!impl) { 02060 /* If the nth bit of the record lock is already set then we 02061 do not set a new lock bit, otherwise we do set */ 02062 02063 if (!lock_rec_get_nth_bit(lock, heap_no)) { 02064 lock_rec_set_nth_bit(lock, heap_no); 02065 if (srv_locks_unsafe_for_binlog 02066 || trx->isolation_level == TRX_ISO_READ_COMMITTED) { 02067 trx_register_new_rec_lock(trx, index); 02068 } 02069 } 02070 } 02071 02072 return(TRUE); 02073 } 02074 02075 /************************************************************************* 02076 This is the general, and slower, routine for locking a record. This is a 02077 low-level function which does NOT look at implicit locks! Checks lock 02078 compatibility within explicit locks. This function sets a normal next-key 02079 lock, or in the case of a page supremum record, a gap type lock. */ 02080 static 02081 ulint 02082 lock_rec_lock_slow( 02083 /*===============*/ 02084 /* out: DB_SUCCESS, DB_LOCK_WAIT, or error 02085 code */ 02086 ibool impl, /* in: if TRUE, no lock is set if no wait is 02087 necessary: we assume that the caller will set 02088 an implicit lock */ 02089 ulint mode, /* in: lock mode: LOCK_X or LOCK_S possibly 02090 ORed to either LOCK_GAP or LOCK_REC_NOT_GAP */ 02091 rec_t* rec, /* in: record */ 02092 dict_index_t* index, /* in: index of record */ 02093 que_thr_t* thr) /* in: query thread */ 02094 { 02095 trx_t* trx; 02096 ulint err; 02097 02098 #ifdef UNIV_SYNC_DEBUG 02099 ut_ad(mutex_own(&kernel_mutex)); 02100 #endif /* UNIV_SYNC_DEBUG */ 02101 ut_ad((LOCK_MODE_MASK & mode) != LOCK_S 02102 || lock_table_has(thr_get_trx(thr), index->table, LOCK_IS)); 02103 ut_ad((LOCK_MODE_MASK & mode) != LOCK_X 02104 || lock_table_has(thr_get_trx(thr), index->table, LOCK_IX)); 02105 ut_ad((LOCK_MODE_MASK & mode) == LOCK_S 02106 || (LOCK_MODE_MASK & mode) == LOCK_X); 02107 ut_ad(mode - (LOCK_MODE_MASK & mode) == LOCK_GAP 02108 || mode - (LOCK_MODE_MASK & mode) == 0 02109 || mode - (LOCK_MODE_MASK & mode) == LOCK_REC_NOT_GAP); 02110 02111 trx = thr_get_trx(thr); 02112 02113 if (lock_rec_has_expl(mode, rec, trx)) { 02114 /* The trx already has a strong enough lock on rec: do 02115 nothing */ 02116 02117 err = DB_SUCCESS; 02118 } else if (lock_rec_other_has_conflicting(mode, rec, trx)) { 02119 02120 /* If another transaction has a non-gap conflicting request in 02121 the queue, as this transaction does not have a lock strong 02122 enough already granted on the record, we have to wait. */ 02123 02124 err = lock_rec_enqueue_waiting(mode, rec, index, thr); 02125 02126 if (srv_locks_unsafe_for_binlog 02127 || trx->isolation_level == TRX_ISO_READ_COMMITTED) { 02128 trx_register_new_rec_lock(trx, index); 02129 } 02130 } else { 02131 if (!impl) { 02132 /* Set the requested lock on the record */ 02133 02134 lock_rec_add_to_queue(LOCK_REC | mode, rec, index, 02135 trx); 02136 if (srv_locks_unsafe_for_binlog 02137 || trx->isolation_level == TRX_ISO_READ_COMMITTED) { 02138 trx_register_new_rec_lock(trx, index); 02139 } 02140 } 02141 02142 err = DB_SUCCESS; 02143 } 02144 02145 return(err); 02146 } 02147 02148 /************************************************************************* 02149 Tries to lock the specified record in the mode requested. If not immediately 02150 possible, enqueues a waiting lock request. This is a low-level function 02151 which does NOT look at implicit locks! Checks lock compatibility within 02152 explicit locks. This function sets a normal next-key lock, or in the case 02153 of a page supremum record, a gap type lock. */ 02154 static 02155 ulint 02156 lock_rec_lock( 02157 /*==========*/ 02158 /* out: DB_SUCCESS, DB_LOCK_WAIT, or error 02159 code */ 02160 ibool impl, /* in: if TRUE, no lock is set if no wait is 02161 necessary: we assume that the caller will set 02162 an implicit lock */ 02163 ulint mode, /* in: lock mode: LOCK_X or LOCK_S possibly 02164 ORed to either LOCK_GAP or LOCK_REC_NOT_GAP */ 02165 rec_t* rec, /* in: record */ 02166 dict_index_t* index, /* in: index of record */ 02167 que_thr_t* thr) /* in: query thread */ 02168 { 02169 ulint err; 02170 02171 #ifdef UNIV_SYNC_DEBUG 02172 ut_ad(mutex_own(&kernel_mutex)); 02173 #endif /* UNIV_SYNC_DEBUG */ 02174 ut_ad((LOCK_MODE_MASK & mode) != LOCK_S 02175 || lock_table_has(thr_get_trx(thr), index->table, LOCK_IS)); 02176 ut_ad((LOCK_MODE_MASK & mode) != LOCK_X 02177 || lock_table_has(thr_get_trx(thr), index->table, LOCK_IX)); 02178 ut_ad((LOCK_MODE_MASK & mode) == LOCK_S 02179 || (LOCK_MODE_MASK & mode) == LOCK_X); 02180 ut_ad(mode - (LOCK_MODE_MASK & mode) == LOCK_GAP 02181 || mode - (LOCK_MODE_MASK & mode) == LOCK_REC_NOT_GAP 02182 || mode - (LOCK_MODE_MASK & mode) == 0); 02183 02184 if (lock_rec_lock_fast(impl, mode, rec, index, thr)) { 02185 02186 /* We try a simplified and faster subroutine for the most 02187 common cases */ 02188 02189 err = DB_SUCCESS; 02190 } else { 02191 err = lock_rec_lock_slow(impl, mode, rec, index, thr); 02192 } 02193 02194 return(err); 02195 } 02196 02197 /************************************************************************* 02198 Checks if a waiting record lock request still has to wait in a queue. */ 02199 static 02200 ibool 02201 lock_rec_has_to_wait_in_queue( 02202 /*==========================*/ 02203 /* out: TRUE if still has to wait */ 02204 lock_t* wait_lock) /* in: waiting record lock */ 02205 { 02206 lock_t* lock; 02207 ulint space; 02208 ulint page_no; 02209 ulint heap_no; 02210 02211 #ifdef UNIV_SYNC_DEBUG 02212 ut_ad(mutex_own(&kernel_mutex)); 02213 #endif /* UNIV_SYNC_DEBUG */ 02214 ut_ad(lock_get_wait(wait_lock)); 02215 ut_ad(lock_get_type(wait_lock) == LOCK_REC); 02216 02217 space = wait_lock->un_member.rec_lock.space; 02218 page_no = wait_lock->un_member.rec_lock.page_no; 02219 heap_no = lock_rec_find_set_bit(wait_lock); 02220 02221 lock = lock_rec_get_first_on_page_addr(space, page_no); 02222 02223 while (lock != wait_lock) { 02224 02225 if (lock_rec_get_nth_bit(lock, heap_no) 02226 && lock_has_to_wait(wait_lock, lock)) { 02227 02228 return(TRUE); 02229 } 02230 02231 lock = lock_rec_get_next_on_page(lock); 02232 } 02233 02234 return(FALSE); 02235 } 02236 02237 /***************************************************************** 02238 Grants a lock to a waiting lock request and releases the waiting 02239 transaction. */ 02240 static 02241 void 02242 lock_grant( 02243 /*=======*/ 02244 lock_t* lock) /* in: waiting lock request */ 02245 { 02246 #ifdef UNIV_SYNC_DEBUG 02247 ut_ad(mutex_own(&kernel_mutex)); 02248 #endif /* UNIV_SYNC_DEBUG */ 02249 02250 lock_reset_lock_and_trx_wait(lock); 02251 02252 if (lock_get_mode(lock) == LOCK_AUTO_INC) { 02253 02254 if (lock->trx->auto_inc_lock != NULL) { 02255 fprintf(stderr, 02256 "InnoDB: Error: trx already had an AUTO-INC lock!\n"); 02257 } 02258 02259 /* Store pointer to lock to trx so that we know to 02260 release it at the end of the SQL statement */ 02261 02262 lock->trx->auto_inc_lock = lock; 02263 } 02264 02265 #ifdef UNIV_DEBUG 02266 if (lock_print_waits) { 02267 fprintf(stderr, "Lock wait for trx %lu ends\n", 02268 (ulong) ut_dulint_get_low(lock->trx->id)); 02269 } 02270 #endif /* UNIV_DEBUG */ 02271 02272 /* If we are resolving a deadlock by choosing another transaction 02273 as a victim, then our original transaction may not be in the 02274 TRX_QUE_LOCK_WAIT state, and there is no need to end the lock wait 02275 for it */ 02276 02277 if (lock->trx->que_state == TRX_QUE_LOCK_WAIT) { 02278 trx_end_lock_wait(lock->trx); 02279 } 02280 } 02281 02282 /***************************************************************** 02283 Cancels a waiting record lock request and releases the waiting transaction 02284 that requested it. NOTE: does NOT check if waiting lock requests behind this 02285 one can now be granted! */ 02286 static 02287 void 02288 lock_rec_cancel( 02289 /*============*/ 02290 lock_t* lock) /* in: waiting record lock request */ 02291 { 02292 #ifdef UNIV_SYNC_DEBUG 02293 ut_ad(mutex_own(&kernel_mutex)); 02294 #endif /* UNIV_SYNC_DEBUG */ 02295 ut_ad(lock_get_type(lock) == LOCK_REC); 02296 02297 /* Reset the bit (there can be only one set bit) in the lock bitmap */ 02298 lock_rec_reset_nth_bit(lock, lock_rec_find_set_bit(lock)); 02299 02300 /* Reset the wait flag and the back pointer to lock in trx */ 02301 02302 lock_reset_lock_and_trx_wait(lock); 02303 02304 /* The following function releases the trx from lock wait */ 02305 02306 trx_end_lock_wait(lock->trx); 02307 } 02308 02309 /***************************************************************** 02310 Removes a record lock request, waiting or granted, from the queue and 02311 grants locks to other transactions in the queue if they now are entitled 02312 to a lock. NOTE: all record locks contained in in_lock are removed. */ 02313 static 02314 void 02315 lock_rec_dequeue_from_page( 02316 /*=======================*/ 02317 lock_t* in_lock)/* in: record lock object: all record locks which 02318 are contained in this lock object are removed; 02319 transactions waiting behind will get their lock 02320 requests granted, if they are now qualified to it */ 02321 { 02322 ulint space; 02323 ulint page_no; 02324 lock_t* lock; 02325 trx_t* trx; 02326 02327 #ifdef UNIV_SYNC_DEBUG 02328 ut_ad(mutex_own(&kernel_mutex)); 02329 #endif /* UNIV_SYNC_DEBUG */ 02330 ut_ad(lock_get_type(in_lock) == LOCK_REC); 02331 02332 trx = in_lock->trx; 02333 02334 space = in_lock->un_member.rec_lock.space; 02335 page_no = in_lock->un_member.rec_lock.page_no; 02336 02337 HASH_DELETE(lock_t, hash, lock_sys->rec_hash, 02338 lock_rec_fold(space, page_no), in_lock); 02339 02340 UT_LIST_REMOVE(trx_locks, trx->trx_locks, in_lock); 02341 02342 /* Check if waiting locks in the queue can now be granted: grant 02343 locks if there are no conflicting locks ahead. */ 02344 02345 lock = lock_rec_get_first_on_page_addr(space, page_no); 02346 02347 while (lock != NULL) { 02348 if (lock_get_wait(lock) 02349 && !lock_rec_has_to_wait_in_queue(lock)) { 02350 02351 /* Grant the lock */ 02352 lock_grant(lock); 02353 } 02354 02355 lock = lock_rec_get_next_on_page(lock); 02356 } 02357 } 02358 02359 /***************************************************************** 02360 Removes a record lock request, waiting or granted, from the queue. */ 02361 static 02362 void 02363 lock_rec_discard( 02364 /*=============*/ 02365 lock_t* in_lock)/* in: record lock object: all record locks which 02366 are contained in this lock object are removed */ 02367 { 02368 ulint space; 02369 ulint page_no; 02370 trx_t* trx; 02371 02372 #ifdef UNIV_SYNC_DEBUG 02373 ut_ad(mutex_own(&kernel_mutex)); 02374 #endif /* UNIV_SYNC_DEBUG */ 02375 ut_ad(lock_get_type(in_lock) == LOCK_REC); 02376 02377 trx = in_lock->trx; 02378 02379 space = in_lock->un_member.rec_lock.space; 02380 page_no = in_lock->un_member.rec_lock.page_no; 02381 02382 HASH_DELETE(lock_t, hash, lock_sys->rec_hash, 02383 lock_rec_fold(space, page_no), in_lock); 02384 02385 UT_LIST_REMOVE(trx_locks, trx->trx_locks, in_lock); 02386 } 02387 02388 /***************************************************************** 02389 Removes record lock objects set on an index page which is discarded. This 02390 function does not move locks, or check for waiting locks, therefore the 02391 lock bitmaps must already be reset when this function is called. */ 02392 static 02393 void 02394 lock_rec_free_all_from_discard_page( 02395 /*================================*/ 02396 page_t* page) /* in: page to be discarded */ 02397 { 02398 ulint space; 02399 ulint page_no; 02400 lock_t* lock; 02401 lock_t* next_lock; 02402 02403 #ifdef UNIV_SYNC_DEBUG 02404 ut_ad(mutex_own(&kernel_mutex)); 02405 #endif /* UNIV_SYNC_DEBUG */ 02406 02407 space = buf_frame_get_space_id(page); 02408 page_no = buf_frame_get_page_no(page); 02409 02410 lock = lock_rec_get_first_on_page_addr(space, page_no); 02411 02412 while (lock != NULL) { 02413 ut_ad(lock_rec_find_set_bit(lock) == ULINT_UNDEFINED); 02414 ut_ad(!lock_get_wait(lock)); 02415 02416 next_lock = lock_rec_get_next_on_page(lock); 02417 02418 lock_rec_discard(lock); 02419 02420 lock = next_lock; 02421 } 02422 } 02423 02424 /*============= RECORD LOCK MOVING AND INHERITING ===================*/ 02425 02426 /***************************************************************** 02427 Resets the lock bits for a single record. Releases transactions waiting for 02428 lock requests here. */ 02429 static 02430 void 02431 lock_rec_reset_and_release_wait( 02432 /*============================*/ 02433 rec_t* rec) /* in: record whose locks bits should be reset */ 02434 { 02435 lock_t* lock; 02436 ulint heap_no; 02437 02438 #ifdef UNIV_SYNC_DEBUG 02439 ut_ad(mutex_own(&kernel_mutex)); 02440 #endif /* UNIV_SYNC_DEBUG */ 02441 02442 heap_no = rec_get_heap_no(rec, page_rec_is_comp(rec)); 02443 02444 lock = lock_rec_get_first(rec); 02445 02446 while (lock != NULL) { 02447 if (lock_get_wait(lock)) { 02448 lock_rec_cancel(lock); 02449 } else { 02450 lock_rec_reset_nth_bit(lock, heap_no); 02451 } 02452 02453 lock = lock_rec_get_next(rec, lock); 02454 } 02455 } 02456 02457 /***************************************************************** 02458 Makes a record to inherit the locks (except LOCK_INSERT_INTENTION type) 02459 of another record as gap type locks, but does not reset the lock bits of 02460 the other record. Also waiting lock requests on rec are inherited as 02461 GRANTED gap locks. */ 02462 02463 void 02464 lock_rec_inherit_to_gap( 02465 /*====================*/ 02466 rec_t* heir, /* in: record which inherits */ 02467 rec_t* rec) /* in: record from which inherited; does NOT reset 02468 the locks on this record */ 02469 { 02470 lock_t* lock; 02471 #ifdef UNIV_SYNC_DEBUG 02472 ut_ad(mutex_own(&kernel_mutex)); 02473 #endif /* UNIV_SYNC_DEBUG */ 02474 02475 lock = lock_rec_get_first(rec); 02476 02477 /* If srv_locks_unsafe_for_binlog is TRUE or session is using 02478 READ COMMITTED isolation level, we do not want locks set 02479 by an UPDATE or a DELETE to be inherited as gap type locks. But we 02480 DO want S-locks set by a consistency constraint to be inherited also 02481 then. */ 02482 02483 while (lock != NULL) { 02484 if (!lock_rec_get_insert_intention(lock) 02485 && !((srv_locks_unsafe_for_binlog 02486 || lock->trx->isolation_level == 02487 TRX_ISO_READ_COMMITTED) 02488 && lock_get_mode(lock) == LOCK_X)) { 02489 02490 lock_rec_add_to_queue(LOCK_REC | lock_get_mode(lock) 02491 | LOCK_GAP, 02492 heir, lock->index, lock->trx); 02493 } 02494 02495 lock = lock_rec_get_next(rec, lock); 02496 } 02497 } 02498 02499 /***************************************************************** 02500 Makes a record to inherit the gap locks (except LOCK_INSERT_INTENTION type) 02501 of another record as gap type locks, but does not reset the lock bits of the 02502 other record. Also waiting lock requests are inherited as GRANTED gap locks. */ 02503 static 02504 void 02505 lock_rec_inherit_to_gap_if_gap_lock( 02506 /*================================*/ 02507 rec_t* heir, /* in: record which inherits */ 02508 rec_t* rec) /* in: record from which inherited; does NOT reset 02509 the locks on this record */ 02510 { 02511 lock_t* lock; 02512 #ifdef UNIV_SYNC_DEBUG 02513 ut_ad(mutex_own(&kernel_mutex)); 02514 #endif /* UNIV_SYNC_DEBUG */ 02515 02516 lock = lock_rec_get_first(rec); 02517 02518 while (lock != NULL) { 02519 if (!lock_rec_get_insert_intention(lock) 02520 && (page_rec_is_supremum(rec) 02521 || !lock_rec_get_rec_not_gap(lock))) { 02522 02523 lock_rec_add_to_queue(LOCK_REC | lock_get_mode(lock) 02524 | LOCK_GAP, 02525 heir, lock->index, lock->trx); 02526 } 02527 02528 lock = lock_rec_get_next(rec, lock); 02529 } 02530 } 02531 02532 /***************************************************************** 02533 Moves the locks of a record to another record and resets the lock bits of 02534 the donating record. */ 02535 static 02536 void 02537 lock_rec_move( 02538 /*==========*/ 02539 rec_t* receiver, /* in: record which gets locks; this record 02540 must have no lock requests on it! */ 02541 rec_t* donator, /* in: record which gives locks */ 02542 ulint comp) /* in: nonzero=compact page format */ 02543 { 02544 lock_t* lock; 02545 ulint heap_no; 02546 ulint type_mode; 02547 02548 #ifdef UNIV_SYNC_DEBUG 02549 ut_ad(mutex_own(&kernel_mutex)); 02550 #endif /* UNIV_SYNC_DEBUG */ 02551 02552 heap_no = rec_get_heap_no(donator, comp); 02553 02554 lock = lock_rec_get_first(donator); 02555 02556 ut_ad(lock_rec_get_first(receiver) == NULL); 02557 02558 while (lock != NULL) { 02559 type_mode = lock->type_mode; 02560 02561 lock_rec_reset_nth_bit(lock, heap_no); 02562 02563 if (lock_get_wait(lock)) { 02564 lock_reset_lock_and_trx_wait(lock); 02565 } 02566 02567 /* Note that we FIRST reset the bit, and then set the lock: 02568 the function works also if donator == receiver */ 02569 02570 lock_rec_add_to_queue(type_mode, receiver, lock->index, 02571 lock->trx); 02572 lock = lock_rec_get_next(donator, lock); 02573 } 02574 02575 ut_ad(lock_rec_get_first(donator) == NULL); 02576 } 02577 02578 /***************************************************************** 02579 Updates the lock table when we have reorganized a page. NOTE: we copy 02580 also the locks set on the infimum of the page; the infimum may carry 02581 locks if an update of a record is occurring on the page, and its locks 02582 were temporarily stored on the infimum. */ 02583 02584 void 02585 lock_move_reorganize_page( 02586 /*======================*/ 02587 page_t* page, /* in: old index page, now reorganized */ 02588 page_t* old_page) /* in: copy of the old, not reorganized page */ 02589 { 02590 lock_t* lock; 02591 lock_t* old_lock; 02592 page_cur_t cur1; 02593 page_cur_t cur2; 02594 ulint old_heap_no; 02595 UT_LIST_BASE_NODE_T(lock_t) old_locks; 02596 mem_heap_t* heap = NULL; 02597 rec_t* sup; 02598 ulint comp; 02599 02600 lock_mutex_enter_kernel(); 02601 02602 lock = lock_rec_get_first_on_page(page); 02603 02604 if (lock == NULL) { 02605 lock_mutex_exit_kernel(); 02606 02607 return; 02608 } 02609 02610 heap = mem_heap_create(256); 02611 02612 /* Copy first all the locks on the page to heap and reset the 02613 bitmaps in the original locks; chain the copies of the locks 02614 using the trx_locks field in them. */ 02615 02616 UT_LIST_INIT(old_locks); 02617 02618 while (lock != NULL) { 02619 02620 /* Make a copy of the lock */ 02621 old_lock = lock_rec_copy(lock, heap); 02622 02623 UT_LIST_ADD_LAST(trx_locks, old_locks, old_lock); 02624 02625 /* Reset bitmap of lock */ 02626 lock_rec_bitmap_reset(lock); 02627 02628 if (lock_get_wait(lock)) { 02629 lock_reset_lock_and_trx_wait(lock); 02630 } 02631 02632 lock = lock_rec_get_next_on_page(lock); 02633 } 02634 02635 sup = page_get_supremum_rec(page); 02636 02637 lock = UT_LIST_GET_FIRST(old_locks); 02638 02639 comp = page_is_comp(page); 02640 ut_ad(comp == page_is_comp(old_page)); 02641 02642 while (lock) { 02643 /* NOTE: we copy also the locks set on the infimum and 02644 supremum of the page; the infimum may carry locks if an 02645 update of a record is occurring on the page, and its locks 02646 were temporarily stored on the infimum */ 02647 02648 page_cur_set_before_first(page, &cur1); 02649 page_cur_set_before_first(old_page, &cur2); 02650 02651 /* Set locks according to old locks */ 02652 for (;;) { 02653 ut_ad(comp || 0 == ut_memcmp(page_cur_get_rec(&cur1), 02654 page_cur_get_rec(&cur2), 02655 rec_get_data_size_old( 02656 page_cur_get_rec(&cur2)))); 02657 old_heap_no = rec_get_heap_no(page_cur_get_rec(&cur2), 02658 comp); 02659 02660 if (lock_rec_get_nth_bit(lock, old_heap_no)) { 02661 02662 /* NOTE that the old lock bitmap could be too 02663 small for the new heap number! */ 02664 02665 lock_rec_add_to_queue(lock->type_mode, 02666 page_cur_get_rec(&cur1), 02667 lock->index, lock->trx); 02668 02669 /* if ((page_cur_get_rec(&cur1) == sup) 02670 && lock_get_wait(lock)) { 02671 fprintf(stderr, 02672 "---\n--\n!!!Lock reorg: supr type %lu\n", 02673 lock->type_mode); 02674 } */ 02675 } 02676 02677 if (page_cur_get_rec(&cur1) == sup) { 02678 02679 break; 02680 } 02681 02682 page_cur_move_to_next(&cur1); 02683 page_cur_move_to_next(&cur2); 02684 } 02685 02686 /* Remember that we chained old locks on the trx_locks field: */ 02687 02688 lock = UT_LIST_GET_NEXT(trx_locks, lock); 02689 } 02690 02691 lock_mutex_exit_kernel(); 02692 02693 mem_heap_free(heap); 02694 02695 /* ut_ad(lock_rec_validate_page(buf_frame_get_space_id(page), 02696 buf_frame_get_page_no(page))); */ 02697 } 02698 02699 /***************************************************************** 02700 Moves the explicit locks on user records to another page if a record 02701 list end is moved to another page. */ 02702 02703 void 02704 lock_move_rec_list_end( 02705 /*===================*/ 02706 page_t* new_page, /* in: index page to move to */ 02707 page_t* page, /* in: index page */ 02708 rec_t* rec) /* in: record on page: this is the 02709 first record moved */ 02710 { 02711 lock_t* lock; 02712 page_cur_t cur1; 02713 page_cur_t cur2; 02714 ulint heap_no; 02715 rec_t* sup; 02716 ulint type_mode; 02717 ulint comp; 02718 ut_ad(page == buf_frame_align(rec)); 02719 02720 lock_mutex_enter_kernel(); 02721 02722 /* Note: when we move locks from record to record, waiting locks 02723 and possible granted gap type locks behind them are enqueued in 02724 the original order, because new elements are inserted to a hash 02725 table to the end of the hash chain, and lock_rec_add_to_queue 02726 does not reuse locks if there are waiters in the queue. */ 02727 02728 sup = page_get_supremum_rec(page); 02729 02730 lock = lock_rec_get_first_on_page(page); 02731 02732 comp = page_is_comp(page); 02733 02734 while (lock != NULL) { 02735 02736 page_cur_position(rec, &cur1); 02737 02738 if (page_cur_is_before_first(&cur1)) { 02739 page_cur_move_to_next(&cur1); 02740 } 02741 02742 page_cur_set_before_first(new_page, &cur2); 02743 page_cur_move_to_next(&cur2); 02744 02745 /* Copy lock requests on user records to new page and 02746 reset the lock bits on the old */ 02747 02748 while (page_cur_get_rec(&cur1) != sup) { 02749 ut_ad(comp || 0 == ut_memcmp(page_cur_get_rec(&cur1), 02750 page_cur_get_rec(&cur2), 02751 rec_get_data_size_old( 02752 page_cur_get_rec(&cur2)))); 02753 heap_no = rec_get_heap_no(page_cur_get_rec(&cur1), 02754 comp); 02755 02756 if (lock_rec_get_nth_bit(lock, heap_no)) { 02757 type_mode = lock->type_mode; 02758 02759 lock_rec_reset_nth_bit(lock, heap_no); 02760 02761 if (lock_get_wait(lock)) { 02762 lock_reset_lock_and_trx_wait(lock); 02763 } 02764 02765 lock_rec_add_to_queue(type_mode, 02766 page_cur_get_rec(&cur2), 02767 lock->index, lock->trx); 02768 } 02769 02770 page_cur_move_to_next(&cur1); 02771 page_cur_move_to_next(&cur2); 02772 } 02773 02774 lock = lock_rec_get_next_on_page(lock); 02775 } 02776 02777 lock_mutex_exit_kernel(); 02778 02779 /* ut_ad(lock_rec_validate_page(buf_frame_get_space_id(page), 02780 buf_frame_get_page_no(page))); 02781 ut_ad(lock_rec_validate_page(buf_frame_get_space_id(new_page), 02782 buf_frame_get_page_no(new_page))); */ 02783 } 02784 02785 /***************************************************************** 02786 Moves the explicit locks on user records to another page if a record 02787 list start is moved to another page. */ 02788 02789 void 02790 lock_move_rec_list_start( 02791 /*=====================*/ 02792 page_t* new_page, /* in: index page to move to */ 02793 page_t* page, /* in: index page */ 02794 rec_t* rec, /* in: record on page: this is the 02795 first record NOT copied */ 02796 rec_t* old_end) /* in: old previous-to-last record on 02797 new_page before the records were copied */ 02798 { 02799 lock_t* lock; 02800 page_cur_t cur1; 02801 page_cur_t cur2; 02802 ulint heap_no; 02803 ulint type_mode; 02804 ulint comp; 02805 02806 ut_a(new_page); 02807 02808 lock_mutex_enter_kernel(); 02809 02810 lock = lock_rec_get_first_on_page(page); 02811 comp = page_is_comp(page); 02812 ut_ad(comp == page_is_comp(new_page)); 02813 ut_ad(page == buf_frame_align(rec)); 02814 02815 while (lock != NULL) { 02816 02817 page_cur_set_before_first(page, &cur1); 02818 page_cur_move_to_next(&cur1); 02819 02820 page_cur_position(old_end, &cur2); 02821 page_cur_move_to_next(&cur2); 02822 02823 /* Copy lock requests on user records to new page and 02824 reset the lock bits on the old */ 02825 02826 while (page_cur_get_rec(&cur1) != rec) { 02827 ut_ad(comp || 0 == ut_memcmp(page_cur_get_rec(&cur1), 02828 page_cur_get_rec(&cur2), 02829 rec_get_data_size_old( 02830 page_cur_get_rec(&cur2)))); 02831 heap_no = rec_get_heap_no(page_cur_get_rec(&cur1), 02832 comp); 02833 02834 if (lock_rec_get_nth_bit(lock, heap_no)) { 02835 type_mode = lock->type_mode; 02836 02837 lock_rec_reset_nth_bit(lock, heap_no); 02838 02839 if (lock_get_wait(lock)) { 02840 lock_reset_lock_and_trx_wait(lock); 02841 } 02842 02843 lock_rec_add_to_queue(type_mode, 02844 page_cur_get_rec(&cur2), 02845 lock->index, lock->trx); 02846 } 02847 02848 page_cur_move_to_next(&cur1); 02849 page_cur_move_to_next(&cur2); 02850 } 02851 02852 lock = lock_rec_get_next_on_page(lock); 02853 } 02854 02855 lock_mutex_exit_kernel(); 02856 02857 /* ut_ad(lock_rec_validate_page(buf_frame_get_space_id(page), 02858 buf_frame_get_page_no(page))); 02859 ut_ad(lock_rec_validate_page(buf_frame_get_space_id(new_page), 02860 buf_frame_get_page_no(new_page))); */ 02861 } 02862 02863 /***************************************************************** 02864 Updates the lock table when a page is split to the right. */ 02865 02866 void 02867 lock_update_split_right( 02868 /*====================*/ 02869 page_t* right_page, /* in: right page */ 02870 page_t* left_page) /* in: left page */ 02871 { 02872 ulint comp; 02873 lock_mutex_enter_kernel(); 02874 comp = page_is_comp(left_page); 02875 ut_ad(comp == page_is_comp(right_page)); 02876 02877 /* Move the locks on the supremum of the left page to the supremum 02878 of the right page */ 02879 02880 lock_rec_move(page_get_supremum_rec(right_page), 02881 page_get_supremum_rec(left_page), comp); 02882 02883 /* Inherit the locks to the supremum of left page from the successor 02884 of the infimum on right page */ 02885 02886 lock_rec_inherit_to_gap(page_get_supremum_rec(left_page), 02887 page_rec_get_next(page_get_infimum_rec(right_page))); 02888 02889 lock_mutex_exit_kernel(); 02890 } 02891 02892 /***************************************************************** 02893 Updates the lock table when a page is merged to the right. */ 02894 02895 void 02896 lock_update_merge_right( 02897 /*====================*/ 02898 rec_t* orig_succ, /* in: original successor of infimum 02899 on the right page before merge */ 02900 page_t* left_page) /* in: merged index page which will be 02901 discarded */ 02902 { 02903 lock_mutex_enter_kernel(); 02904 02905 /* Inherit the locks from the supremum of the left page to the 02906 original successor of infimum on the right page, to which the left 02907 page was merged */ 02908 02909 lock_rec_inherit_to_gap(orig_succ, page_get_supremum_rec(left_page)); 02910 02911 /* Reset the locks on the supremum of the left page, releasing 02912 waiting transactions */ 02913 02914 lock_rec_reset_and_release_wait(page_get_supremum_rec(left_page)); 02915 02916 lock_rec_free_all_from_discard_page(left_page); 02917 02918 lock_mutex_exit_kernel(); 02919 } 02920 02921 /***************************************************************** 02922 Updates the lock table when the root page is copied to another in 02923 btr_root_raise_and_insert. Note that we leave lock structs on the 02924 root page, even though they do not make sense on other than leaf 02925 pages: the reason is that in a pessimistic update the infimum record 02926 of the root page will act as a dummy carrier of the locks of the record 02927 to be updated. */ 02928 02929 void 02930 lock_update_root_raise( 02931 /*===================*/ 02932 page_t* new_page, /* in: index page to which copied */ 02933 page_t* root) /* in: root page */ 02934 { 02935 ulint comp; 02936 lock_mutex_enter_kernel(); 02937 comp = page_is_comp(root); 02938 ut_ad(comp == page_is_comp(new_page)); 02939 02940 /* Move the locks on the supremum of the root to the supremum 02941 of new_page */ 02942 02943 lock_rec_move(page_get_supremum_rec(new_page), 02944 page_get_supremum_rec(root), comp); 02945 lock_mutex_exit_kernel(); 02946 } 02947 02948 /***************************************************************** 02949 Updates the lock table when a page is copied to another and the original page 02950 is removed from the chain of leaf pages, except if page is the root! */ 02951 02952 void 02953 lock_update_copy_and_discard( 02954 /*=========================*/ 02955 page_t* new_page, /* in: index page to which copied */ 02956 page_t* page) /* in: index page; NOT the root! */ 02957 { 02958 ulint comp; 02959 lock_mutex_enter_kernel(); 02960 comp = page_is_comp(page); 02961 ut_ad(comp == page_is_comp(new_page)); 02962 02963 /* Move the locks on the supremum of the old page to the supremum 02964 of new_page */ 02965 02966 lock_rec_move(page_get_supremum_rec(new_page), 02967 page_get_supremum_rec(page), comp); 02968 lock_rec_free_all_from_discard_page(page); 02969 02970 lock_mutex_exit_kernel(); 02971 } 02972 02973 /***************************************************************** 02974 Updates the lock table when a page is split to the left. */ 02975 02976 void 02977 lock_update_split_left( 02978 /*===================*/ 02979 page_t* right_page, /* in: right page */ 02980 page_t* left_page) /* in: left page */ 02981 { 02982 lock_mutex_enter_kernel(); 02983 02984 /* Inherit the locks to the supremum of the left page from the 02985 successor of the infimum on the right page */ 02986 02987 lock_rec_inherit_to_gap(page_get_supremum_rec(left_page), 02988 page_rec_get_next(page_get_infimum_rec(right_page))); 02989 02990 lock_mutex_exit_kernel(); 02991 } 02992 02993 /***************************************************************** 02994 Updates the lock table when a page is merged to the left. */ 02995 02996 void 02997 lock_update_merge_left( 02998 /*===================*/ 02999 page_t* left_page, /* in: left page to which merged */ 03000 rec_t* orig_pred, /* in: original predecessor of supremum 03001 on the left page before merge */ 03002 page_t* right_page) /* in: merged index page which will be 03003 discarded */ 03004 { 03005 rec_t* left_next_rec; 03006 rec_t* left_supremum; 03007 ulint comp; 03008 lock_mutex_enter_kernel(); 03009 comp = page_is_comp(left_page); 03010 ut_ad(comp == page_is_comp(right_page)); 03011 ut_ad(left_page == buf_frame_align(orig_pred)); 03012 03013 left_next_rec = page_rec_get_next(orig_pred); 03014 left_supremum = page_get_supremum_rec(left_page); 03015 03016 if (UNIV_LIKELY(left_next_rec != left_supremum)) { 03017 03018 /* Inherit the locks on the supremum of the left page to the 03019 first record which was moved from the right page */ 03020 03021 lock_rec_inherit_to_gap(left_next_rec, left_supremum); 03022 03023 /* Reset the locks on the supremum of the left page, 03024 releasing waiting transactions */ 03025 03026 lock_rec_reset_and_release_wait(left_supremum); 03027 } 03028 03029 /* Move the locks from the supremum of right page to the supremum 03030 of the left page */ 03031 03032 lock_rec_move(left_supremum, page_get_supremum_rec(right_page), comp); 03033 03034 lock_rec_free_all_from_discard_page(right_page); 03035 03036 lock_mutex_exit_kernel(); 03037 } 03038 03039 /***************************************************************** 03040 Resets the original locks on heir and replaces them with gap type locks 03041 inherited from rec. */ 03042 03043 void 03044 lock_rec_reset_and_inherit_gap_locks( 03045 /*=================================*/ 03046 rec_t* heir, /* in: heir record */ 03047 rec_t* rec) /* in: record */ 03048 { 03049 mutex_enter(&kernel_mutex); 03050 03051 lock_rec_reset_and_release_wait(heir); 03052 03053 lock_rec_inherit_to_gap(heir, rec); 03054 03055 mutex_exit(&kernel_mutex); 03056 } 03057 03058 /***************************************************************** 03059 Updates the lock table when a page is discarded. */ 03060 03061 void 03062 lock_update_discard( 03063 /*================*/ 03064 rec_t* heir, /* in: record which will inherit the locks */ 03065 page_t* page) /* in: index page which will be discarded */ 03066 { 03067 rec_t* rec; 03068 03069 lock_mutex_enter_kernel(); 03070 03071 if (NULL == lock_rec_get_first_on_page(page)) { 03072 /* No locks exist on page, nothing to do */ 03073 03074 lock_mutex_exit_kernel(); 03075 03076 return; 03077 } 03078 03079 /* Inherit all the locks on the page to the record and reset all 03080 the locks on the page */ 03081 03082 rec = page_get_infimum_rec(page); 03083 03084 for (;;) { 03085 lock_rec_inherit_to_gap(heir, rec); 03086 03087 /* Reset the locks on rec, releasing waiting transactions */ 03088 03089 lock_rec_reset_and_release_wait(rec); 03090 03091 if (page_rec_is_supremum(rec)) { 03092 03093 break; 03094 } 03095 03096 rec = page_rec_get_next(rec); 03097 } 03098 03099 lock_rec_free_all_from_discard_page(page); 03100 03101 lock_mutex_exit_kernel(); 03102 } 03103 03104 /***************************************************************** 03105 Updates the lock table when a new user record is inserted. */ 03106 03107 void 03108 lock_update_insert( 03109 /*===============*/ 03110 rec_t* rec) /* in: the inserted record */ 03111 { 03112 lock_mutex_enter_kernel(); 03113 03114 /* Inherit the gap-locking locks for rec, in gap mode, from the next 03115 record */ 03116 03117 lock_rec_inherit_to_gap_if_gap_lock(rec, page_rec_get_next(rec)); 03118 03119 lock_mutex_exit_kernel(); 03120 } 03121 03122 /***************************************************************** 03123 Updates the lock table when a record is removed. */ 03124 03125 void 03126 lock_update_delete( 03127 /*===============*/ 03128 rec_t* rec) /* in: the record to be removed */ 03129 { 03130 lock_mutex_enter_kernel(); 03131 03132 /* Let the next record inherit the locks from rec, in gap mode */ 03133 03134 lock_rec_inherit_to_gap(page_rec_get_next(rec), rec); 03135 03136 /* Reset the lock bits on rec and release waiting transactions */ 03137 03138 lock_rec_reset_and_release_wait(rec); 03139 03140 lock_mutex_exit_kernel(); 03141 } 03142 03143 /************************************************************************* 03144 Stores on the page infimum record the explicit locks of another record. 03145 This function is used to store the lock state of a record when it is 03146 updated and the size of the record changes in the update. The record 03147 is moved in such an update, perhaps to another page. The infimum record 03148 acts as a dummy carrier record, taking care of lock releases while the 03149 actual record is being moved. */ 03150 03151 void 03152 lock_rec_store_on_page_infimum( 03153 /*===========================*/ 03154 page_t* page, /* in: page containing the record */ 03155 rec_t* rec) /* in: record whose lock state is stored 03156 on the infimum record of the same page; lock 03157 bits are reset on the record */ 03158 { 03159 ut_ad(page == buf_frame_align(rec)); 03160 03161 lock_mutex_enter_kernel(); 03162 03163 lock_rec_move(page_get_infimum_rec(page), rec, page_is_comp(page)); 03164 03165 lock_mutex_exit_kernel(); 03166 } 03167 03168 /************************************************************************* 03169 Restores the state of explicit lock requests on a single record, where the 03170 state was stored on the infimum of the page. */ 03171 03172 void 03173 lock_rec_restore_from_page_infimum( 03174 /*===============================*/ 03175 rec_t* rec, /* in: record whose lock state is restored */ 03176 page_t* page) /* in: page (rec is not necessarily on this page) 03177 whose infimum stored the lock state; lock bits are 03178 reset on the infimum */ 03179 { 03180 ulint comp; 03181 lock_mutex_enter_kernel(); 03182 comp = page_is_comp(page); 03183 ut_ad(!comp == !page_rec_is_comp(rec)); 03184 03185 lock_rec_move(rec, page_get_infimum_rec(page), comp); 03186 03187 lock_mutex_exit_kernel(); 03188 } 03189 03190 /*=========== DEADLOCK CHECKING ======================================*/ 03191 03192 /************************************************************************ 03193 Checks if a lock request results in a deadlock. */ 03194 static 03195 ibool 03196 lock_deadlock_occurs( 03197 /*=================*/ 03198 /* out: TRUE if a deadlock was detected and we 03199 chose trx as a victim; FALSE if no deadlock, or 03200 there was a deadlock, but we chose other 03201 transaction(s) as victim(s) */ 03202 lock_t* lock, /* in: lock the transaction is requesting */ 03203 trx_t* trx) /* in: transaction */ 03204 { 03205 dict_table_t* table; 03206 dict_index_t* index; 03207 trx_t* mark_trx; 03208 ulint ret; 03209 ulint cost = 0; 03210 03211 ut_ad(trx && lock); 03212 #ifdef UNIV_SYNC_DEBUG 03213 ut_ad(mutex_own(&kernel_mutex)); 03214 #endif /* UNIV_SYNC_DEBUG */ 03215 retry: 03216 /* We check that adding this trx to the waits-for graph 03217 does not produce a cycle. First mark all active transactions 03218 with 0: */ 03219 03220 mark_trx = UT_LIST_GET_FIRST(trx_sys->trx_list); 03221 03222 while (mark_trx) { 03223 mark_trx->deadlock_mark = 0; 03224 mark_trx = UT_LIST_GET_NEXT(trx_list, mark_trx); 03225 } 03226 03227 ret = lock_deadlock_recursive(trx, trx, lock, &cost, 0); 03228 03229 if (ret == LOCK_VICTIM_IS_OTHER) { 03230 /* We chose some other trx as a victim: retry if there still 03231 is a deadlock */ 03232 03233 goto retry; 03234 } 03235 03236 if (ret == LOCK_VICTIM_IS_START) { 03237 if (lock_get_type(lock) & LOCK_TABLE) { 03238 table = lock->un_member.tab_lock.table; 03239 index = NULL; 03240 } else { 03241 index = lock->index; 03242 table = index->table; 03243 } 03244 03245 lock_deadlock_found = TRUE; 03246 03247 fputs("*** WE ROLL BACK TRANSACTION (2)\n", 03248 lock_latest_err_file); 03249 03250 return(TRUE); 03251 } 03252 03253 return(FALSE); 03254 } 03255 03256 /************************************************************************ 03257 Looks recursively for a deadlock. */ 03258 static 03259 ulint 03260 lock_deadlock_recursive( 03261 /*====================*/ 03262 /* out: 0 if no deadlock found, 03263 LOCK_VICTIM_IS_START if there was a deadlock 03264 and we chose 'start' as the victim, 03265 LOCK_VICTIM_IS_OTHER if a deadlock 03266 was found and we chose some other trx as a 03267 victim: we must do the search again in this 03268 last case because there may be another 03269 deadlock! */ 03270 trx_t* start, /* in: recursion starting point */ 03271 trx_t* trx, /* in: a transaction waiting for a lock */ 03272 lock_t* wait_lock, /* in: the lock trx is waiting to be granted */ 03273 ulint* cost, /* in/out: number of calculation steps thus 03274 far: if this exceeds LOCK_MAX_N_STEPS_... 03275 we return LOCK_VICTIM_IS_START */ 03276 ulint depth) /* in: recursion depth: if this exceeds 03277 LOCK_MAX_DEPTH_IN_DEADLOCK_CHECK, we 03278 return LOCK_VICTIM_IS_START */ 03279 { 03280 lock_t* lock; 03281 ulint bit_no = ULINT_UNDEFINED; 03282 trx_t* lock_trx; 03283 ulint ret; 03284 03285 ut_a(trx && start && wait_lock); 03286 #ifdef UNIV_SYNC_DEBUG 03287 ut_ad(mutex_own(&kernel_mutex)); 03288 #endif /* UNIV_SYNC_DEBUG */ 03289 03290 if (trx->deadlock_mark == 1) { 03291 /* We have already exhaustively searched the subtree starting 03292 from this trx */ 03293 03294 return(0); 03295 } 03296 03297 *cost = *cost + 1; 03298 03299 if ((depth > LOCK_MAX_DEPTH_IN_DEADLOCK_CHECK) 03300 || (*cost > LOCK_MAX_N_STEPS_IN_DEADLOCK_CHECK)) { 03301 03302 return(LOCK_VICTIM_IS_START); 03303 } 03304 03305 lock = wait_lock; 03306 03307 if (lock_get_type(wait_lock) == LOCK_REC) { 03308 03309 bit_no = lock_rec_find_set_bit(wait_lock); 03310 03311 ut_a(bit_no != ULINT_UNDEFINED); 03312 } 03313 03314 /* Look at the locks ahead of wait_lock in the lock queue */ 03315 03316 for (;;) { 03317 if (lock_get_type(lock) & LOCK_TABLE) { 03318 03319 lock = UT_LIST_GET_PREV(un_member.tab_lock.locks, lock); 03320 } else { 03321 ut_ad(lock_get_type(lock) == LOCK_REC); 03322 ut_a(bit_no != ULINT_UNDEFINED); 03323 03324 lock = lock_rec_get_prev(lock, bit_no); 03325 } 03326 03327 if (lock == NULL) { 03328 /* We can mark this subtree as searched */ 03329 trx->deadlock_mark = 1; 03330 03331 return(FALSE); 03332 } 03333 03334 if (lock_has_to_wait(wait_lock, lock)) { 03335 03336 lock_trx = lock->trx; 03337 03338 if (lock_trx == start) { 03339 /* We came back to the recursion starting 03340 point: a deadlock detected */ 03341 FILE* ef = lock_latest_err_file; 03342 03343 rewind(ef); 03344 ut_print_timestamp(ef); 03345 03346 fputs("\n*** (1) TRANSACTION:\n", ef); 03347 03348 trx_print(ef, wait_lock->trx, 3000); 03349 03350 fputs( 03351 "*** (1) WAITING FOR THIS LOCK TO BE GRANTED:\n", ef); 03352 03353 if (lock_get_type(wait_lock) == LOCK_REC) { 03354 lock_rec_print(ef, wait_lock); 03355 } else { 03356 lock_table_print(ef, wait_lock); 03357 } 03358 03359 fputs("*** (2) TRANSACTION:\n", ef); 03360 03361 trx_print(ef, lock->trx, 3000); 03362 03363 fputs("*** (2) HOLDS THE LOCK(S):\n", ef); 03364 03365 if (lock_get_type(lock) == LOCK_REC) { 03366 lock_rec_print(ef, lock); 03367 } else { 03368 lock_table_print(ef, lock); 03369 } 03370 03371 fputs( 03372 "*** (2) WAITING FOR THIS LOCK TO BE GRANTED:\n", ef); 03373 03374 if (lock_get_type(start->wait_lock) 03375 == LOCK_REC) { 03376 lock_rec_print(ef, start->wait_lock); 03377 } else { 03378 lock_table_print(ef, start->wait_lock); 03379 } 03380 #ifdef UNIV_DEBUG 03381 if (lock_print_waits) { 03382 fputs("Deadlock detected\n", stderr); 03383 } 03384 #endif /* UNIV_DEBUG */ 03385 if (ut_dulint_cmp(wait_lock->trx->undo_no, 03386 start->undo_no) >= 0) { 03387 /* Our recursion starting point 03388 transaction is 'smaller', let us 03389 choose 'start' as the victim and roll 03390 back it */ 03391 03392 return(LOCK_VICTIM_IS_START); 03393 } 03394 03395 lock_deadlock_found = TRUE; 03396 03397 /* Let us choose the transaction of wait_lock 03398 as a victim to try to avoid deadlocking our 03399 recursion starting point transaction */ 03400 03401 fputs("*** WE ROLL BACK TRANSACTION (1)\n", 03402 ef); 03403 03404 wait_lock->trx->was_chosen_as_deadlock_victim 03405 = TRUE; 03406 03407 lock_cancel_waiting_and_release(wait_lock); 03408 03409 /* Since trx and wait_lock are no longer 03410 in the waits-for graph, we can return FALSE; 03411 note that our selective algorithm can choose 03412 several transactions as victims, but still 03413 we may end up rolling back also the recursion 03414 starting point transaction! */ 03415 03416 return(LOCK_VICTIM_IS_OTHER); 03417 } 03418 03419 if (lock_trx->que_state == TRX_QUE_LOCK_WAIT) { 03420 03421 /* Another trx ahead has requested lock in an 03422 incompatible mode, and is itself waiting for 03423 a lock */ 03424 03425 ret = lock_deadlock_recursive(start, lock_trx, 03426 lock_trx->wait_lock, cost, depth + 1); 03427 if (ret != 0) { 03428 03429 return(ret); 03430 } 03431 } 03432 } 03433 }/* end of the 'for (;;)'-loop */ 03434 } 03435 03436 /*========================= TABLE LOCKS ==============================*/ 03437 03438 /************************************************************************* 03439 Creates a table lock object and adds it as the last in the lock queue 03440 of the table. Does NOT check for deadlocks or lock compatibility. */ 03441 UNIV_INLINE 03442 lock_t* 03443 lock_table_create( 03444 /*==============*/ 03445 /* out, own: new lock object */ 03446 dict_table_t* table, /* in: database table in dictionary cache */ 03447 ulint type_mode,/* in: lock mode possibly ORed with 03448 LOCK_WAIT */ 03449 trx_t* trx) /* in: trx */ 03450 { 03451 lock_t* lock; 03452 03453 ut_ad(table && trx); 03454 #ifdef UNIV_SYNC_DEBUG 03455 ut_ad(mutex_own(&kernel_mutex)); 03456 #endif /* UNIV_SYNC_DEBUG */ 03457 03458 if (type_mode == LOCK_AUTO_INC) { 03459 /* Only one trx can have the lock on the table 03460 at a time: we may use the memory preallocated 03461 to the table object */ 03462 03463 lock = table->auto_inc_lock; 03464 03465 ut_a(trx->auto_inc_lock == NULL); 03466 trx->auto_inc_lock = lock; 03467 } else { 03468 lock = mem_heap_alloc(trx->lock_heap, sizeof(lock_t)); 03469 } 03470 03471 UT_LIST_ADD_LAST(trx_locks, trx->trx_locks, lock); 03472 03473 lock->type_mode = type_mode | LOCK_TABLE; 03474 lock->trx = trx; 03475 03476 lock->un_member.tab_lock.table = table; 03477 03478 UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock); 03479 03480 if (type_mode & LOCK_WAIT) { 03481 03482 lock_set_lock_and_trx_wait(lock, trx); 03483 } 03484 03485 return(lock); 03486 } 03487 03488 /***************************************************************** 03489 Removes a table lock request from the queue and the trx list of locks; 03490 this is a low-level function which does NOT check if waiting requests 03491 can now be granted. */ 03492 UNIV_INLINE 03493 void 03494 lock_table_remove_low( 03495 /*==================*/ 03496 lock_t* lock) /* in: table lock */ 03497 { 03498 dict_table_t* table; 03499 trx_t* trx; 03500 03501 #ifdef UNIV_SYNC_DEBUG 03502 ut_ad(mutex_own(&kernel_mutex)); 03503 #endif /* UNIV_SYNC_DEBUG */ 03504 03505 table = lock->un_member.tab_lock.table; 03506 trx = lock->trx; 03507 03508 if (lock == trx->auto_inc_lock) { 03509 trx->auto_inc_lock = NULL; 03510 } 03511 03512 UT_LIST_REMOVE(trx_locks, trx->trx_locks, lock); 03513 UT_LIST_REMOVE(un_member.tab_lock.locks, table->locks, lock); 03514 } 03515 03516 /************************************************************************* 03517 Enqueues a waiting request for a table lock which cannot be granted 03518 immediately. Checks for deadlocks. */ 03519 static 03520 ulint 03521 lock_table_enqueue_waiting( 03522 /*=======================*/ 03523 /* out: DB_LOCK_WAIT, DB_DEADLOCK, or 03524 DB_QUE_THR_SUSPENDED, or DB_SUCCESS; 03525 DB_SUCCESS means that there was a deadlock, 03526 but another transaction was chosen as a 03527 victim, and we got the lock immediately: 03528 no need to wait then */ 03529 ulint mode, /* in: lock mode this transaction is 03530 requesting */ 03531 dict_table_t* table, /* in: table */ 03532 que_thr_t* thr) /* in: query thread */ 03533 { 03534 lock_t* lock; 03535 trx_t* trx; 03536 03537 #ifdef UNIV_SYNC_DEBUG 03538 ut_ad(mutex_own(&kernel_mutex)); 03539 #endif /* UNIV_SYNC_DEBUG */ 03540 03541 /* Test if there already is some other reason to suspend thread: 03542 we do not enqueue a lock request if the query thread should be 03543 stopped anyway */ 03544 03545 if (que_thr_stop(thr)) { 03546 ut_error; 03547 03548 return(DB_QUE_THR_SUSPENDED); 03549 } 03550 03551 trx = thr_get_trx(thr); 03552 03553 if (trx->dict_operation) { 03554 ut_print_timestamp(stderr); 03555 fputs( 03556 " InnoDB: Error: a table lock wait happens in a dictionary operation!\n" 03557 "InnoDB: Table name ", stderr); 03558 ut_print_name(stderr, trx, TRUE, table->name); 03559 fputs(".\n" 03560 "InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n", 03561 stderr); 03562 } 03563 03564 /* Enqueue the lock request that will wait to be granted */ 03565 03566 lock = lock_table_create(table, mode | LOCK_WAIT, trx); 03567 03568 /* Check if a deadlock occurs: if yes, remove the lock request and 03569 return an error code */ 03570 03571 if (lock_deadlock_occurs(lock, trx)) { 03572 03573 lock_reset_lock_and_trx_wait(lock); 03574 lock_table_remove_low(lock); 03575 03576 return(DB_DEADLOCK); 03577 } 03578 03579 if (trx->wait_lock == NULL) { 03580 /* Deadlock resolution chose another transaction as a victim, 03581 and we accidentally got our lock granted! */ 03582 03583 return(DB_SUCCESS); 03584 } 03585 03586 trx->que_state = TRX_QUE_LOCK_WAIT; 03587 trx->was_chosen_as_deadlock_victim = FALSE; 03588 trx->wait_started = time(NULL); 03589 03590 ut_a(que_thr_stop(thr)); 03591 03592 return(DB_LOCK_WAIT); 03593 } 03594 03595 /************************************************************************* 03596 Checks if other transactions have an incompatible mode lock request in 03597 the lock queue. */ 03598 UNIV_INLINE 03599 ibool 03600 lock_table_other_has_incompatible( 03601 /*==============================*/ 03602 trx_t* trx, /* in: transaction, or NULL if all 03603 transactions should be included */ 03604 ulint wait, /* in: LOCK_WAIT if also waiting locks are 03605 taken into account, or 0 if not */ 03606 dict_table_t* table, /* in: table */ 03607 ulint mode) /* in: lock mode */ 03608 { 03609 lock_t* lock; 03610 03611 #ifdef UNIV_SYNC_DEBUG 03612 ut_ad(mutex_own(&kernel_mutex)); 03613 #endif /* UNIV_SYNC_DEBUG */ 03614 03615 lock = UT_LIST_GET_LAST(table->locks); 03616 03617 while (lock != NULL) { 03618 03619 if ((lock->trx != trx) 03620 && (!lock_mode_compatible(lock_get_mode(lock), mode)) 03621 && (wait || !(lock_get_wait(lock)))) { 03622 03623 return(TRUE); 03624 } 03625 03626 lock = UT_LIST_GET_PREV(un_member.tab_lock.locks, lock); 03627 } 03628 03629 return(FALSE); 03630 } 03631 03632 /************************************************************************* 03633 Locks the specified database table in the mode given. If the lock cannot 03634 be granted immediately, the query thread is put to wait. */ 03635 03636 ulint 03637 lock_table( 03638 /*=======*/ 03639 /* out: DB_SUCCESS, DB_LOCK_WAIT, 03640 DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */ 03641 ulint flags, /* in: if BTR_NO_LOCKING_FLAG bit is set, 03642 does nothing */ 03643 dict_table_t* table, /* in: database table in dictionary cache */ 03644 ulint mode, /* in: lock mode */ 03645 que_thr_t* thr) /* in: query thread */ 03646 { 03647 trx_t* trx; 03648 ulint err; 03649 03650 ut_ad(table && thr); 03651 03652 if (flags & BTR_NO_LOCKING_FLAG) { 03653 03654 return(DB_SUCCESS); 03655 } 03656 03657 ut_a(flags == 0); 03658 03659 trx = thr_get_trx(thr); 03660 03661 lock_mutex_enter_kernel(); 03662 03663 /* Look for stronger locks the same trx already has on the table */ 03664 03665 if (lock_table_has(trx, table, mode)) { 03666 03667 lock_mutex_exit_kernel(); 03668 03669 return(DB_SUCCESS); 03670 } 03671 03672 /* We have to check if the new lock is compatible with any locks 03673 other transactions have in the table lock queue. */ 03674 03675 if (lock_table_other_has_incompatible(trx, LOCK_WAIT, table, mode)) { 03676 03677 /* Another trx has a request on the table in an incompatible 03678 mode: this trx may have to wait */ 03679 03680 err = lock_table_enqueue_waiting(mode | flags, table, thr); 03681 03682 lock_mutex_exit_kernel(); 03683 03684 return(err); 03685 } 03686 03687 lock_table_create(table, mode | flags, trx); 03688 03689 ut_a(!flags || mode == LOCK_S || mode == LOCK_X); 03690 03691 lock_mutex_exit_kernel(); 03692 03693 return(DB_SUCCESS); 03694 } 03695 03696 /************************************************************************* 03697 Checks if there are any locks set on the table. */ 03698 03699 ibool 03700 lock_is_on_table( 03701 /*=============*/ 03702 /* out: TRUE if there are lock(s) */ 03703 dict_table_t* table) /* in: database table in dictionary cache */ 03704 { 03705 ibool ret; 03706 03707 ut_ad(table); 03708 03709 lock_mutex_enter_kernel(); 03710 03711 if (UT_LIST_GET_LAST(table->locks)) { 03712 ret = TRUE; 03713 } else { 03714 ret = FALSE; 03715 } 03716 03717 lock_mutex_exit_kernel(); 03718 03719 return(ret); 03720 } 03721 03722 /************************************************************************* 03723 Checks if a waiting table lock request still has to wait in a queue. */ 03724 static 03725 ibool 03726 lock_table_has_to_wait_in_queue( 03727 /*============================*/ 03728 /* out: TRUE if still has to wait */ 03729 lock_t* wait_lock) /* in: waiting table lock */ 03730 { 03731 dict_table_t* table; 03732 lock_t* lock; 03733 03734 ut_ad(lock_get_wait(wait_lock)); 03735 03736 table = wait_lock->un_member.tab_lock.table; 03737 03738 lock = UT_LIST_GET_FIRST(table->locks); 03739 03740 while (lock != wait_lock) { 03741 03742 if (lock_has_to_wait(wait_lock, lock)) { 03743 03744 return(TRUE); 03745 } 03746 03747 lock = UT_LIST_GET_NEXT(un_member.tab_lock.locks, lock); 03748 } 03749 03750 return(FALSE); 03751 } 03752 03753 /***************************************************************** 03754 Removes a table lock request, waiting or granted, from the queue and grants 03755 locks to other transactions in the queue, if they now are entitled to a 03756 lock. */ 03757 static 03758 void 03759 lock_table_dequeue( 03760 /*===============*/ 03761 lock_t* in_lock)/* in: table lock object; transactions waiting 03762 behind will get their lock requests granted, if 03763 they are now qualified to it */ 03764 { 03765 lock_t* lock; 03766 03767 #ifdef UNIV_SYNC_DEBUG 03768 ut_ad(mutex_own(&kernel_mutex)); 03769 #endif /* UNIV_SYNC_DEBUG */ 03770 ut_a(lock_get_type(in_lock) == LOCK_TABLE); 03771 03772 lock = UT_LIST_GET_NEXT(un_member.tab_lock.locks, in_lock); 03773 03774 lock_table_remove_low(in_lock); 03775 03776 /* Check if waiting locks in the queue can now be granted: grant 03777 locks if there are no conflicting locks ahead. */ 03778 03779 while (lock != NULL) { 03780 03781 if (lock_get_wait(lock) 03782 && !lock_table_has_to_wait_in_queue(lock)) { 03783 03784 /* Grant the lock */ 03785 lock_grant(lock); 03786 } 03787 03788 lock = UT_LIST_GET_NEXT(un_member.tab_lock.locks, lock); 03789 } 03790 } 03791 03792 /*=========================== LOCK RELEASE ==============================*/ 03793 03794 /***************************************************************** 03795 Removes a granted record lock of a transaction from the queue and grants 03796 locks to other transactions waiting in the queue if they now are entitled 03797 to a lock. */ 03798 03799 void 03800 lock_rec_unlock( 03801 /*============*/ 03802 trx_t* trx, /* in: transaction that has set a record 03803 lock */ 03804 rec_t* rec, /* in: record */ 03805 ulint lock_mode) /* in: LOCK_S or LOCK_X */ 03806 { 03807 lock_t* lock; 03808 lock_t* release_lock = NULL; 03809 ulint heap_no; 03810 03811 ut_ad(trx && rec); 03812 03813 mutex_enter(&kernel_mutex); 03814 03815 heap_no = rec_get_heap_no(rec, page_rec_is_comp(rec)); 03816 03817 lock = lock_rec_get_first(rec); 03818 03819 /* Find the last lock with the same lock_mode and transaction 03820 from the record. */ 03821 03822 while (lock != NULL) { 03823 if (lock->trx == trx && lock_get_mode(lock) == lock_mode) { 03824 release_lock = lock; 03825 ut_a(!lock_get_wait(lock)); 03826 } 03827 03828 lock = lock_rec_get_next(rec, lock); 03829 } 03830 03831 /* If a record lock is found, release the record lock */ 03832 03833 if (UNIV_LIKELY(release_lock != NULL)) { 03834 lock_rec_reset_nth_bit(release_lock, heap_no); 03835 } else { 03836 mutex_exit(&kernel_mutex); 03837 ut_print_timestamp(stderr); 03838 fprintf(stderr, 03839 " InnoDB: Error: unlock row could not find a %lu mode lock on the record\n", 03840 (ulong)lock_mode); 03841 03842 return; 03843 } 03844 03845 /* Check if we can now grant waiting lock requests */ 03846 03847 lock = lock_rec_get_first(rec); 03848 03849 while (lock != NULL) { 03850 if (lock_get_wait(lock) 03851 && !lock_rec_has_to_wait_in_queue(lock)) { 03852 03853 /* Grant the lock */ 03854 lock_grant(lock); 03855 } 03856 03857 lock = lock_rec_get_next(rec, lock); 03858 } 03859 03860 mutex_exit(&kernel_mutex); 03861 } 03862 03863 /************************************************************************* 03864 Releases a table lock. 03865 Releases possible other transactions waiting for this lock. */ 03866 03867 void 03868 lock_table_unlock( 03869 /*==============*/ 03870 lock_t* lock) /* in: lock */ 03871 { 03872 mutex_enter(&kernel_mutex); 03873 03874 lock_table_dequeue(lock); 03875 03876 mutex_exit(&kernel_mutex); 03877 } 03878 03879 /************************************************************************* 03880 Releases an auto-inc lock a transaction possibly has on a table. 03881 Releases possible other transactions waiting for this lock. */ 03882 03883 void 03884 lock_table_unlock_auto_inc( 03885 /*=======================*/ 03886 trx_t* trx) /* in: transaction */ 03887 { 03888 if (trx->auto_inc_lock) { 03889 mutex_enter(&kernel_mutex); 03890 03891 lock_table_dequeue(trx->auto_inc_lock); 03892 03893 mutex_exit(&kernel_mutex); 03894 } 03895 } 03896 03897 /************************************************************************* 03898 Releases transaction locks, and releases possible other transactions waiting 03899 because of these locks. */ 03900 03901 void 03902 lock_release_off_kernel( 03903 /*====================*/ 03904 trx_t* trx) /* in: transaction */ 03905 { 03906 dict_table_t* table; 03907 ulint count; 03908 lock_t* lock; 03909 03910 #ifdef UNIV_SYNC_DEBUG 03911 ut_ad(mutex_own(&kernel_mutex)); 03912 #endif /* UNIV_SYNC_DEBUG */ 03913 03914 lock = UT_LIST_GET_LAST(trx->trx_locks); 03915 03916 count = 0; 03917 03918 while (lock != NULL) { 03919 03920 count++; 03921 03922 if (lock_get_type(lock) == LOCK_REC) { 03923 03924 lock_rec_dequeue_from_page(lock); 03925 } else { 03926 ut_ad(lock_get_type(lock) & LOCK_TABLE); 03927 03928 if (lock_get_mode(lock) != LOCK_IS 03929 && 0 != ut_dulint_cmp(trx->undo_no, 03930 ut_dulint_zero)) { 03931 03932 /* The trx may have modified the table. We 03933 block the use of the MySQL query cache for 03934 all currently active transactions. */ 03935 03936 table = lock->un_member.tab_lock.table; 03937 03938 table->query_cache_inv_trx_id = 03939 trx_sys->max_trx_id; 03940 } 03941 03942 lock_table_dequeue(lock); 03943 } 03944 03945 if (count == LOCK_RELEASE_KERNEL_INTERVAL) { 03946 /* Release the kernel mutex for a while, so that we 03947 do not monopolize it */ 03948 03949 lock_mutex_exit_kernel(); 03950 03951 lock_mutex_enter_kernel(); 03952 03953 count = 0; 03954 } 03955 03956 lock = UT_LIST_GET_LAST(trx->trx_locks); 03957 } 03958 03959 mem_heap_empty(trx->lock_heap); 03960 03961 ut_a(trx->auto_inc_lock == NULL); 03962 } 03963 03964 /************************************************************************* 03965 Cancels a waiting lock request and releases possible other transactions 03966 waiting behind it. */ 03967 03968 void 03969 lock_cancel_waiting_and_release( 03970 /*============================*/ 03971 lock_t* lock) /* in: waiting lock request */ 03972 { 03973 #ifdef UNIV_SYNC_DEBUG 03974 ut_ad(mutex_own(&kernel_mutex)); 03975 #endif /* UNIV_SYNC_DEBUG */ 03976 03977 if (lock_get_type(lock) == LOCK_REC) { 03978 03979 lock_rec_dequeue_from_page(lock); 03980 } else { 03981 ut_ad(lock_get_type(lock) & LOCK_TABLE); 03982 03983 lock_table_dequeue(lock); 03984 } 03985 03986 /* Reset the wait flag and the back pointer to lock in trx */ 03987 03988 lock_reset_lock_and_trx_wait(lock); 03989 03990 /* The following function releases the trx from lock wait */ 03991 03992 trx_end_lock_wait(lock->trx); 03993 } 03994 03995 /************************************************************************* 03996 Resets all record and table locks of a transaction on a table to be dropped. 03997 No lock is allowed to be a wait lock. */ 03998 static 03999 void 04000 lock_reset_all_on_table_for_trx( 04001 /*============================*/ 04002 dict_table_t* table, /* in: table to be dropped */ 04003 trx_t* trx) /* in: a transaction */ 04004 { 04005 lock_t* lock; 04006 lock_t* prev_lock; 04007 04008 #ifdef UNIV_SYNC_DEBUG 04009 ut_ad(mutex_own(&kernel_mutex)); 04010 #endif /* UNIV_SYNC_DEBUG */ 04011 04012 lock = UT_LIST_GET_LAST(trx->trx_locks); 04013 04014 while (lock != NULL) { 04015 prev_lock = UT_LIST_GET_PREV(trx_locks, lock); 04016 04017 if (lock_get_type(lock) == LOCK_REC 04018 && lock->index->table == table) { 04019 ut_a(!lock_get_wait(lock)); 04020 04021 lock_rec_discard(lock); 04022 } else if (lock_get_type(lock) & LOCK_TABLE 04023 && lock->un_member.tab_lock.table == table) { 04024 04025 ut_a(!lock_get_wait(lock)); 04026 04027 lock_table_remove_low(lock); 04028 } 04029 04030 lock = prev_lock; 04031 } 04032 } 04033 04034 /************************************************************************* 04035 Resets all locks, both table and record locks, on a table to be dropped. 04036 No lock is allowed to be a wait lock. */ 04037 04038 void 04039 lock_reset_all_on_table( 04040 /*====================*/ 04041 dict_table_t* table) /* in: table to be dropped */ 04042 { 04043 lock_t* lock; 04044 04045 mutex_enter(&kernel_mutex); 04046 04047 lock = UT_LIST_GET_FIRST(table->locks); 04048 04049 while (lock) { 04050 ut_a(!lock_get_wait(lock)); 04051 04052 lock_reset_all_on_table_for_trx(table, lock->trx); 04053 04054 lock = UT_LIST_GET_FIRST(table->locks); 04055 } 04056 04057 mutex_exit(&kernel_mutex); 04058 } 04059 04060 /*===================== VALIDATION AND DEBUGGING ====================*/ 04061 04062 /************************************************************************* 04063 Prints info of a table lock. */ 04064 04065 void 04066 lock_table_print( 04067 /*=============*/ 04068 FILE* file, /* in: file where to print */ 04069 lock_t* lock) /* in: table type lock */ 04070 { 04071 #ifdef UNIV_SYNC_DEBUG 04072 ut_ad(mutex_own(&kernel_mutex)); 04073 #endif /* UNIV_SYNC_DEBUG */ 04074 ut_a(lock_get_type(lock) == LOCK_TABLE); 04075 04076 fputs("TABLE LOCK table ", file); 04077 ut_print_name(file, lock->trx, TRUE, 04078 lock->un_member.tab_lock.table->name); 04079 fprintf(file, " trx id %lu %lu", 04080 (ulong) (lock->trx)->id.high, (ulong) (lock->trx)->id.low); 04081 04082 if (lock_get_mode(lock) == LOCK_S) { 04083 fputs(" lock mode S", file); 04084 } else if (lock_get_mode(lock) == LOCK_X) { 04085 fputs(" lock mode X", file); 04086 } else if (lock_get_mode(lock) == LOCK_IS) { 04087 fputs(" lock mode IS", file); 04088 } else if (lock_get_mode(lock) == LOCK_IX) { 04089 fputs(" lock mode IX", file); 04090 } else if (lock_get_mode(lock) == LOCK_AUTO_INC) { 04091 fputs(" lock mode AUTO-INC", file); 04092 } else { 04093 fprintf(file, " unknown lock mode %lu", (ulong) lock_get_mode(lock)); 04094 } 04095 04096 if (lock_get_wait(lock)) { 04097 fputs(" waiting", file); 04098 } 04099 04100 putc('\n', file); 04101 } 04102 04103 /************************************************************************* 04104 Prints info of a record lock. */ 04105 04106 void 04107 lock_rec_print( 04108 /*===========*/ 04109 FILE* file, /* in: file where to print */ 04110 lock_t* lock) /* in: record type lock */ 04111 { 04112 page_t* page; 04113 ulint space; 04114 ulint page_no; 04115 ulint i; 04116 mtr_t mtr; 04117 mem_heap_t* heap = NULL; 04118 ulint offsets_[REC_OFFS_NORMAL_SIZE]; 04119 ulint* offsets = offsets_; 04120 *offsets_ = (sizeof offsets_) / sizeof *offsets_; 04121 04122 #ifdef UNIV_SYNC_DEBUG 04123 ut_ad(mutex_own(&kernel_mutex)); 04124 #endif /* UNIV_SYNC_DEBUG */ 04125 ut_a(lock_get_type(lock) == LOCK_REC); 04126 04127 space = lock->un_member.rec_lock.space; 04128 page_no = lock->un_member.rec_lock.page_no; 04129 04130 fprintf(file, "RECORD LOCKS space id %lu page no %lu n bits %lu ", 04131 (ulong) space, (ulong) page_no, 04132 (ulong) lock_rec_get_n_bits(lock)); 04133 dict_index_name_print(file, lock->trx, lock->index); 04134 fprintf(file, " trx id %lu %lu", 04135 (ulong) (lock->trx)->id.high, 04136 (ulong) (lock->trx)->id.low); 04137 04138 if (lock_get_mode(lock) == LOCK_S) { 04139 fputs(" lock mode S", file); 04140 } else if (lock_get_mode(lock) == LOCK_X) { 04141 fputs(" lock_mode X", file); 04142 } else { 04143 ut_error; 04144 } 04145 04146 if (lock_rec_get_gap(lock)) { 04147 fputs(" locks gap before rec", file); 04148 } 04149 04150 if (lock_rec_get_rec_not_gap(lock)) { 04151 fputs(" locks rec but not gap", file); 04152 } 04153 04154 if (lock_rec_get_insert_intention(lock)) { 04155 fputs(" insert intention", file); 04156 } 04157 04158 if (lock_get_wait(lock)) { 04159 fputs(" waiting", file); 04160 } 04161 04162 mtr_start(&mtr); 04163 04164 putc('\n', file); 04165 04166 /* If the page is not in the buffer pool, we cannot load it 04167 because we have the kernel mutex and ibuf operations would 04168 break the latching order */ 04169 04170 page = buf_page_get_gen(space, page_no, RW_NO_LATCH, 04171 NULL, BUF_GET_IF_IN_POOL, 04172 __FILE__, __LINE__, &mtr); 04173 if (page) { 04174 page = buf_page_get_nowait(space, page_no, RW_S_LATCH, &mtr); 04175 04176 if (!page) { 04177 /* Let us try to get an X-latch. If the current thread 04178 is holding an X-latch on the page, we cannot get an 04179 S-latch. */ 04180 04181 page = buf_page_get_nowait(space, page_no, RW_X_LATCH, 04182 &mtr); 04183 } 04184 } 04185 04186 if (page) { 04187 #ifdef UNIV_SYNC_DEBUG 04188 buf_page_dbg_add_level(page, SYNC_NO_ORDER_CHECK); 04189 #endif /* UNIV_SYNC_DEBUG */ 04190 } 04191 04192 for (i = 0; i < lock_rec_get_n_bits(lock); i++) { 04193 04194 if (lock_rec_get_nth_bit(lock, i)) { 04195 04196 fprintf(file, "Record lock, heap no %lu ", (ulong) i); 04197 04198 if (page) { 04199 rec_t* rec 04200 = page_find_rec_with_heap_no(page, i); 04201 offsets = rec_get_offsets(rec, lock->index, 04202 offsets, ULINT_UNDEFINED, &heap); 04203 rec_print_new(file, rec, offsets); 04204 } 04205 04206 putc('\n', file); 04207 } 04208 } 04209 04210 mtr_commit(&mtr); 04211 if (UNIV_LIKELY_NULL(heap)) { 04212 mem_heap_free(heap); 04213 } 04214 } 04215 04216 #ifndef UNIV_HOTBACKUP 04217 /************************************************************************* 04218 Calculates the number

