~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/innobase/lock/lock0lock.c

  • Committer: Brian Aker
  • Date: 2010-05-27 01:25:56 UTC
  • mfrom: (1567.1.4 new-staging)
  • Revision ID: brian@gaz-20100527012556-5zgkirkl7swbigd6
Merge of Brian, Paul. PBXT compile issue, and test framework cleanup. 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************************
 
2
 
 
3
Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
 
4
 
 
5
This program is free software; you can redistribute it and/or modify it under
 
6
the terms of the GNU General Public License as published by the Free Software
 
7
Foundation; version 2 of the License.
 
8
 
 
9
This program is distributed in the hope that it will be useful, but WITHOUT
 
10
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 
11
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 
12
 
 
13
You should have received a copy of the GNU General Public License along with
 
14
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 
15
Place, Suite 330, Boston, MA 02111-1307 USA
 
16
 
 
17
*****************************************************************************/
 
18
 
 
19
/**************************************************//**
 
20
@file lock/lock0lock.c
 
21
The transaction lock system
 
22
 
 
23
Created 5/7/1996 Heikki Tuuri
 
24
*******************************************************/
 
25
 
 
26
#define LOCK_MODULE_IMPLEMENTATION
 
27
 
 
28
#include "lock0lock.h"
 
29
#include "lock0priv.h"
 
30
 
 
31
#ifdef UNIV_NONINL
 
32
#include "lock0lock.ic"
 
33
#include "lock0priv.ic"
 
34
#endif
 
35
 
 
36
#include "ha_prototypes.h"
 
37
#include "usr0sess.h"
 
38
#include "trx0purge.h"
 
39
#include "dict0mem.h"
 
40
#include "trx0sys.h"
 
41
 
 
42
/* Restricts the length of search we will do in the waits-for
 
43
graph of transactions */
 
44
#define LOCK_MAX_N_STEPS_IN_DEADLOCK_CHECK 1000000
 
45
 
 
46
/* Restricts the recursion depth of the search we will do in the waits-for
 
47
graph of transactions */
 
48
#define LOCK_MAX_DEPTH_IN_DEADLOCK_CHECK 200
 
49
 
 
50
/* When releasing transaction locks, this specifies how often we release
 
51
the kernel mutex for a moment to give also others access to it */
 
52
 
 
53
#define LOCK_RELEASE_KERNEL_INTERVAL    1000
 
54
 
 
55
/* Safety margin when creating a new record lock: this many extra records
 
56
can be inserted to the page without need to create a lock with a bigger
 
57
bitmap */
 
58
 
 
59
#define LOCK_PAGE_BITMAP_MARGIN         64
 
60
 
 
61
/* An explicit record lock affects both the record and the gap before it.
 
62
An implicit x-lock does not affect the gap, it only locks the index
 
63
record from read or update.
 
64
 
 
65
If a transaction has modified or inserted an index record, then
 
66
it owns an implicit x-lock on the record. On a secondary index record,
 
67
a transaction has an implicit x-lock also if it has modified the
 
68
clustered index record, the max trx id of the page where the secondary
 
69
index record resides is >= trx id of the transaction (or database recovery
 
70
is running), and there are no explicit non-gap lock requests on the
 
71
secondary index record.
 
72
 
 
73
This complicated definition for a secondary index comes from the
 
74
implementation: we want to be able to determine if a secondary index
 
75
record has an implicit x-lock, just by looking at the present clustered
 
76
index record, not at the historical versions of the record. The
 
77
complicated definition can be explained to the user so that there is
 
78
nondeterminism in the access path when a query is answered: we may,
 
79
or may not, access the clustered index record and thus may, or may not,
 
80
bump into an x-lock set there.
 
81
 
 
82
Different transaction can have conflicting locks set on the gap at the
 
83
same time. The locks on the gap are purely inhibitive: an insert cannot
 
84
be made, or a select cursor may have to wait if a different transaction
 
85
has a conflicting lock on the gap. An x-lock on the gap does not give
 
86
the right to insert into the gap.
 
87
 
 
88
An explicit lock can be placed on a user record or the supremum record of
 
89
a page. The locks on the supremum record are always thought to be of the gap
 
90
type, though the gap bit is not set. When we perform an update of a record
 
91
where the size of the record changes, we may temporarily store its explicit
 
92
locks on the infimum record of the page, though the infimum otherwise never
 
93
carries locks.
 
94
 
 
95
A waiting record lock can also be of the gap type. A waiting lock request
 
96
can be granted when there is no conflicting mode lock request by another
 
97
transaction ahead of it in the explicit lock queue.
 
98
 
 
99
In version 4.0.5 we added yet another explicit lock type: LOCK_REC_NOT_GAP.
 
100
It only locks the record it is placed on, not the gap before the record.
 
101
This lock type is necessary to emulate an Oracle-like READ COMMITTED isolation
 
102
level.
 
103
 
 
104
-------------------------------------------------------------------------
 
105
RULE 1: If there is an implicit x-lock on a record, and there are non-gap
 
106
-------
 
107
lock requests waiting in the queue, then the transaction holding the implicit
 
108
x-lock also has an explicit non-gap record x-lock. Therefore, as locks are
 
109
released, we can grant locks to waiting lock requests purely by looking at
 
110
the explicit lock requests in the queue.
 
111
 
 
112
RULE 3: Different transactions cannot have conflicting granted non-gap locks
 
113
-------
 
114
on a record at the same time. However, they can have conflicting granted gap
 
115
locks.
 
116
RULE 4: If a there is a waiting lock request in a queue, no lock request,
 
117
-------
 
118
gap or not, can be inserted ahead of it in the queue. In record deletes
 
119
and page splits new gap type locks can be created by the database manager
 
120
for a transaction, and without rule 4, the waits-for graph of transactions
 
121
might become cyclic without the database noticing it, as the deadlock check
 
122
is only performed when a transaction itself requests a lock!
 
123
-------------------------------------------------------------------------
 
124
 
 
125
An insert is allowed to a gap if there are no explicit lock requests by
 
126
other transactions on the next record. It does not matter if these lock
 
127
requests are granted or waiting, gap bit set or not, with the exception
 
128
that a gap type request set by another transaction to wait for
 
129
its turn to do an insert is ignored. On the other hand, an
 
130
implicit x-lock by another transaction does not prevent an insert, which
 
131
allows for more concurrency when using an Oracle-style sequence number
 
132
generator for the primary key with many transactions doing inserts
 
133
concurrently.
 
134
 
 
135
A modify of a record is allowed if the transaction has an x-lock on the
 
136
record, or if other transactions do not have any non-gap lock requests on the
 
137
record.
 
138
 
 
139
A read of a single user record with a cursor is allowed if the transaction
 
140
has a non-gap explicit, or an implicit lock on the record, or if the other
 
141
transactions have no x-lock requests on the record. At a page supremum a
 
142
read is always allowed.
 
143
 
 
144
In summary, an implicit lock is seen as a granted x-lock only on the
 
145
record, not on the gap. An explicit lock with no gap bit set is a lock
 
146
both on the record and the gap. If the gap bit is set, the lock is only
 
147
on the gap. Different transaction cannot own conflicting locks on the
 
148
record at the same time, but they may own conflicting locks on the gap.
 
149
Granted locks on a record give an access right to the record, but gap type
 
150
locks just inhibit operations.
 
151
 
 
152
NOTE: Finding out if some transaction has an implicit x-lock on a secondary
 
153
index record can be cumbersome. We may have to look at previous versions of
 
154
the corresponding clustered index record to find out if a delete marked
 
155
secondary index record was delete marked by an active transaction, not by
 
156
a committed one.
 
157
 
 
158
FACT A: If a transaction has inserted a row, it can delete it any time
 
159
without need to wait for locks.
 
160
 
 
161
PROOF: The transaction has an implicit x-lock on every index record inserted
 
162
for the row, and can thus modify each record without the need to wait. Q.E.D.
 
163
 
 
164
FACT B: If a transaction has read some result set with a cursor, it can read
 
165
it again, and retrieves the same result set, if it has not modified the
 
166
result set in the meantime. Hence, there is no phantom problem. If the
 
167
biggest record, in the alphabetical order, touched by the cursor is removed,
 
168
a lock wait may occur, otherwise not.
 
169
 
 
170
PROOF: When a read cursor proceeds, it sets an s-lock on each user record
 
171
it passes, and a gap type s-lock on each page supremum. The cursor must
 
172
wait until it has these locks granted. Then no other transaction can
 
173
have a granted x-lock on any of the user records, and therefore cannot
 
174
modify the user records. Neither can any other transaction insert into
 
175
the gaps which were passed over by the cursor. Page splits and merges,
 
176
and removal of obsolete versions of records do not affect this, because
 
177
when a user record or a page supremum is removed, the next record inherits
 
178
its locks as gap type locks, and therefore blocks inserts to the same gap.
 
179
Also, if a page supremum is inserted, it inherits its locks from the successor
 
180
record. When the cursor is positioned again at the start of the result set,
 
181
the records it will touch on its course are either records it touched
 
182
during the last pass or new inserted page supremums. It can immediately
 
183
access all these records, and when it arrives at the biggest record, it
 
184
notices that the result set is complete. If the biggest record was removed,
 
185
lock wait can occur because the next record only inherits a gap type lock,
 
186
and a wait may be needed. Q.E.D. */
 
187
 
 
188
/* If an index record should be changed or a new inserted, we must check
 
189
the lock on the record or the next. When a read cursor starts reading,
 
190
we will set a record level s-lock on each record it passes, except on the
 
191
initial record on which the cursor is positioned before we start to fetch
 
192
records. Our index tree search has the convention that the B-tree
 
193
cursor is positioned BEFORE the first possibly matching record in
 
194
the search. Optimizations are possible here: if the record is searched
 
195
on an equality condition to a unique key, we could actually set a special
 
196
lock on the record, a lock which would not prevent any insert before
 
197
this record. In the next key locking an x-lock set on a record also
 
198
prevents inserts just before that record.
 
199
        There are special infimum and supremum records on each page.
 
200
A supremum record can be locked by a read cursor. This records cannot be
 
201
updated but the lock prevents insert of a user record to the end of
 
202
the page.
 
203
        Next key locks will prevent the phantom problem where new rows
 
204
could appear to SELECT result sets after the select operation has been
 
205
performed. Prevention of phantoms ensures the serilizability of
 
206
transactions.
 
207
        What should we check if an insert of a new record is wanted?
 
208
Only the lock on the next record on the same page, because also the
 
209
supremum record can carry a lock. An s-lock prevents insertion, but
 
210
what about an x-lock? If it was set by a searched update, then there
 
211
is implicitly an s-lock, too, and the insert should be prevented.
 
212
What if our transaction owns an x-lock to the next record, but there is
 
213
a waiting s-lock request on the next record? If this s-lock was placed
 
214
by a read cursor moving in the ascending order in the index, we cannot
 
215
do the insert immediately, because when we finally commit our transaction,
 
216
the read cursor should see also the new inserted record. So we should
 
217
move the read cursor backward from the the next record for it to pass over
 
218
the new inserted record. This move backward may be too cumbersome to
 
219
implement. If we in this situation just enqueue a second x-lock request
 
220
for our transaction on the next record, then the deadlock mechanism
 
221
notices a deadlock between our transaction and the s-lock request
 
222
transaction. This seems to be an ok solution.
 
223
        We could have the convention that granted explicit record locks,
 
224
lock the corresponding records from changing, and also lock the gaps
 
225
before them from inserting. A waiting explicit lock request locks the gap
 
226
before from inserting. Implicit record x-locks, which we derive from the
 
227
transaction id in the clustered index record, only lock the record itself
 
228
from modification, not the gap before it from inserting.
 
229
        How should we store update locks? If the search is done by a unique
 
230
key, we could just modify the record trx id. Otherwise, we could put a record
 
231
x-lock on the record. If the update changes ordering fields of the
 
232
clustered index record, the inserted new record needs no record lock in
 
233
lock table, the trx id is enough. The same holds for a secondary index
 
234
record. Searched delete is similar to update.
 
235
 
 
236
PROBLEM:
 
237
What about waiting lock requests? If a transaction is waiting to make an
 
238
update to a record which another modified, how does the other transaction
 
239
know to send the end-lock-wait signal to the waiting transaction? If we have
 
240
the convention that a transaction may wait for just one lock at a time, how
 
241
do we preserve it if lock wait ends?
 
242
 
 
243
PROBLEM:
 
244
Checking the trx id label of a secondary index record. In the case of a
 
245
modification, not an insert, is this necessary? A secondary index record
 
246
is modified only by setting or resetting its deleted flag. A secondary index
 
247
record contains fields to uniquely determine the corresponding clustered
 
248
index record. A secondary index record is therefore only modified if we
 
249
also modify the clustered index record, and the trx id checking is done
 
250
on the clustered index record, before we come to modify the secondary index
 
251
record. So, in the case of delete marking or unmarking a secondary index
 
252
record, we do not have to care about trx ids, only the locks in the lock
 
253
table must be checked. In the case of a select from a secondary index, the
 
254
trx id is relevant, and in this case we may have to search the clustered
 
255
index record.
 
256
 
 
257
PROBLEM: How to update record locks when page is split or merged, or
 
258
--------------------------------------------------------------------
 
259
a record is deleted or updated?
 
260
If the size of fields in a record changes, we perform the update by
 
261
a delete followed by an insert. How can we retain the locks set or
 
262
waiting on the record? Because a record lock is indexed in the bitmap
 
263
by the heap number of the record, when we remove the record from the
 
264
record list, it is possible still to keep the lock bits. If the page
 
265
is reorganized, we could make a table of old and new heap numbers,
 
266
and permute the bitmaps in the locks accordingly. We can add to the
 
267
table a row telling where the updated record ended. If the update does
 
268
not require a reorganization of the page, we can simply move the lock
 
269
bits for the updated record to the position determined by its new heap
 
270
number (we may have to allocate a new lock, if we run out of the bitmap
 
271
in the old one).
 
272
        A more complicated case is the one where the reinsertion of the
 
273
updated record is done pessimistically, because the structure of the
 
274
tree may change.
 
275
 
 
276
PROBLEM: If a supremum record is removed in a page merge, or a record
 
277
---------------------------------------------------------------------
 
278
removed in a purge, what to do to the waiting lock requests? In a split to
 
279
the right, we just move the lock requests to the new supremum. If a record
 
280
is removed, we could move the waiting lock request to its inheritor, the
 
281
next record in the index. But, the next record may already have lock
 
282
requests on its own queue. A new deadlock check should be made then. Maybe
 
283
it is easier just to release the waiting transactions. They can then enqueue
 
284
new lock requests on appropriate records.
 
285
 
 
286
PROBLEM: When a record is inserted, what locks should it inherit from the
 
287
-------------------------------------------------------------------------
 
288
upper neighbor? An insert of a new supremum record in a page split is
 
289
always possible, but an insert of a new user record requires that the upper
 
290
neighbor does not have any lock requests by other transactions, granted or
 
291
waiting, in its lock queue. Solution: We can copy the locks as gap type
 
292
locks, so that also the waiting locks are transformed to granted gap type
 
293
locks on the inserted record. */
 
294
 
 
295
/* LOCK COMPATIBILITY MATRIX
 
296
 *    IS IX S  X  AI
 
297
 * IS +  +  +  -  +
 
298
 * IX +  +  -  -  +
 
299
 * S  +  -  +  -  -
 
300
 * X  -  -  -  -  -
 
301
 * AI +  +  -  -  -
 
302
 *
 
303
 * Note that for rows, InnoDB only acquires S or X locks.
 
304
 * For tables, InnoDB normally acquires IS or IX locks.
 
305
 * S or X table locks are only acquired for LOCK TABLES.
 
306
 * Auto-increment (AI) locks are needed because of
 
307
 * statement-level MySQL binlog.
 
308
 * See also lock_mode_compatible().
 
309
 */
 
310
#define LK(a,b) (1 << ((a) * LOCK_NUM + (b)))
 
311
#define LKS(a,b) LK(a,b) | LK(b,a)
 
312
 
 
313
/* Define the lock compatibility matrix in a ulint.  The first line below
 
314
defines the diagonal entries.  The following lines define the compatibility
 
315
for LOCK_IX, LOCK_S, and LOCK_AUTO_INC using LKS(), since the matrix
 
316
is symmetric. */
 
317
#define LOCK_MODE_COMPATIBILITY 0                                       \
 
318
 | LK(LOCK_IS, LOCK_IS) | LK(LOCK_IX, LOCK_IX) | LK(LOCK_S, LOCK_S)     \
 
319
 | LKS(LOCK_IX, LOCK_IS) | LKS(LOCK_IS, LOCK_AUTO_INC)                  \
 
320
 | LKS(LOCK_S, LOCK_IS)                                                 \
 
321
 | LKS(LOCK_AUTO_INC, LOCK_IS) | LKS(LOCK_AUTO_INC, LOCK_IX)
 
322
 
 
323
/* STRONGER-OR-EQUAL RELATION (mode1=row, mode2=column)
 
324
 *    IS IX S  X  AI
 
325
 * IS +  -  -  -  -
 
326
 * IX +  +  -  -  -
 
327
 * S  +  -  +  -  -
 
328
 * X  +  +  +  +  +
 
329
 * AI -  -  -  -  +
 
330
 * See lock_mode_stronger_or_eq().
 
331
 */
 
332
 
 
333
/* Define the stronger-or-equal lock relation in a ulint.  This relation
 
334
contains all pairs LK(mode1, mode2) where mode1 is stronger than or
 
335
equal to mode2. */
 
336
#define LOCK_MODE_STRONGER_OR_EQ 0                                      \
 
337
 | LK(LOCK_IS, LOCK_IS)                                                 \
 
338
 | LK(LOCK_IX, LOCK_IS) | LK(LOCK_IX, LOCK_IX)                          \
 
339
 | LK(LOCK_S, LOCK_IS) | LK(LOCK_S, LOCK_S)                             \
 
340
 | LK(LOCK_AUTO_INC, LOCK_AUTO_INC)                                     \
 
341
 | LK(LOCK_X, LOCK_IS) | LK(LOCK_X, LOCK_IX) | LK(LOCK_X, LOCK_S)       \
 
342
 | LK(LOCK_X, LOCK_AUTO_INC) | LK(LOCK_X, LOCK_X)
 
343
 
 
344
#ifdef UNIV_DEBUG
 
345
UNIV_INTERN ibool       lock_print_waits        = FALSE;
 
346
 
 
347
/*********************************************************************//**
 
348
Validates the lock system.
 
349
@return TRUE if ok */
 
350
static
 
351
ibool
 
352
lock_validate(void);
 
353
/*===============*/
 
354
 
 
355
/*********************************************************************//**
 
356
Validates the record lock queues on a page.
 
357
@return TRUE if ok */
 
358
static
 
359
ibool
 
360
lock_rec_validate_page(
 
361
/*===================*/
 
362
        ulint   space,  /*!< in: space id */
 
363
        ulint   page_no);/*!< in: page number */
 
364
 
 
365
/* Define the following in order to enable lock_rec_validate_page() checks. */
 
366
# undef UNIV_DEBUG_LOCK_VALIDATE
 
367
#endif /* UNIV_DEBUG */
 
368
 
 
369
/* The lock system */
 
370
UNIV_INTERN lock_sys_t* lock_sys        = NULL;
 
371
 
 
372
/* We store info on the latest deadlock error to this buffer. InnoDB
 
373
Monitor will then fetch it and print */
 
374
UNIV_INTERN ibool       lock_deadlock_found = FALSE;
 
375
UNIV_INTERN FILE*       lock_latest_err_file;
 
376
 
 
377
/* Flags for recursive deadlock search */
 
378
#define LOCK_VICTIM_IS_START    1
 
379
#define LOCK_VICTIM_IS_OTHER    2
 
380
 
 
381
/********************************************************************//**
 
382
Checks if a lock request results in a deadlock.
 
383
@return TRUE if a deadlock was detected and we chose trx as a victim;
 
384
FALSE if no deadlock, or there was a deadlock, but we chose other
 
385
transaction(s) as victim(s) */
 
386
static
 
387
ibool
 
388
lock_deadlock_occurs(
 
389
/*=================*/
 
390
        lock_t* lock,   /*!< in: lock the transaction is requesting */
 
391
        trx_t*  trx);   /*!< in: transaction */
 
392
/********************************************************************//**
 
393
Looks recursively for a deadlock.
 
394
@return 0 if no deadlock found, LOCK_VICTIM_IS_START if there was a
 
395
deadlock and we chose 'start' as the victim, LOCK_VICTIM_IS_OTHER if a
 
396
deadlock was found and we chose some other trx as a victim: we must do
 
397
the search again in this last case because there may be another
 
398
deadlock! */
 
399
static
 
400
ulint
 
401
lock_deadlock_recursive(
 
402
/*====================*/
 
403
        trx_t*  start,          /*!< in: recursion starting point */
 
404
        trx_t*  trx,            /*!< in: a transaction waiting for a lock */
 
405
        lock_t* wait_lock,      /*!< in: the lock trx is waiting to be granted */
 
406
        ulint*  cost,           /*!< in/out: number of calculation steps thus
 
407
                                far: if this exceeds LOCK_MAX_N_STEPS_...
 
408
                                we return LOCK_VICTIM_IS_START */
 
409
        ulint   depth);         /*!< in: recursion depth: if this exceeds
 
410
                                LOCK_MAX_DEPTH_IN_DEADLOCK_CHECK, we
 
411
                                return LOCK_VICTIM_IS_START */
 
412
 
 
413
/*********************************************************************//**
 
414
Gets the nth bit of a record lock.
 
415
@return TRUE if bit set */
 
416
UNIV_INLINE
 
417
ibool
 
418
lock_rec_get_nth_bit(
 
419
/*=================*/
 
420
        const lock_t*   lock,   /*!< in: record lock */
 
421
        ulint           i)      /*!< in: index of the bit */
 
422
{
 
423
        ulint   byte_index;
 
424
        ulint   bit_index;
 
425
 
 
426
        ut_ad(lock);
 
427
        ut_ad(lock_get_type_low(lock) == LOCK_REC);
 
428
 
 
429
        if (i >= lock->un_member.rec_lock.n_bits) {
 
430
 
 
431
                return(FALSE);
 
432
        }
 
433
 
 
434
        byte_index = i / 8;
 
435
        bit_index = i % 8;
 
436
 
 
437
        return(1 & ((const byte*) &lock[1])[byte_index] >> bit_index);
 
438
}
 
439
 
 
440
/*************************************************************************/
 
441
 
 
442
#define lock_mutex_enter_kernel()       mutex_enter(&kernel_mutex)
 
443
#define lock_mutex_exit_kernel()        mutex_exit(&kernel_mutex)
 
444
 
 
445
/*********************************************************************//**
 
446
Checks that a transaction id is sensible, i.e., not in the future.
 
447
@return TRUE if ok */
 
448
UNIV_INTERN
 
449
ibool
 
450
lock_check_trx_id_sanity(
 
451
/*=====================*/
 
452
        trx_id_t        trx_id,         /*!< in: trx id */
 
453
        const rec_t*    rec,            /*!< in: user record */
 
454
        dict_index_t*   index,          /*!< in: index */
 
455
        const ulint*    offsets,        /*!< in: rec_get_offsets(rec, index) */
 
456
        ibool           has_kernel_mutex)/*!< in: TRUE if the caller owns the
 
457
                                        kernel mutex */
 
458
{
 
459
        ibool   is_ok           = TRUE;
 
460
 
 
461
        ut_ad(rec_offs_validate(rec, index, offsets));
 
462
 
 
463
        if (!has_kernel_mutex) {
 
464
                mutex_enter(&kernel_mutex);
 
465
        }
 
466
 
 
467
        /* A sanity check: the trx_id in rec must be smaller than the global
 
468
        trx id counter */
 
469
 
 
470
        if (ut_dulint_cmp(trx_id, trx_sys->max_trx_id) >= 0) {
 
471
                ut_print_timestamp(stderr);
 
472
                fputs("  InnoDB: Error: transaction id associated"
 
473
                      " with record\n",
 
474
                      stderr);
 
475
                rec_print_new(stderr, rec, offsets);
 
476
                fputs("InnoDB: in ", stderr);
 
477
                dict_index_name_print(stderr, NULL, index);
 
478
                fprintf(stderr, "\n"
 
479
                        "InnoDB: is " TRX_ID_FMT " which is higher than the"
 
480
                        " global trx id counter " TRX_ID_FMT "!\n"
 
481
                        "InnoDB: The table is corrupt. You have to do"
 
482
                        " dump + drop + reimport.\n",
 
483
                        TRX_ID_PREP_PRINTF(trx_id),
 
484
                        TRX_ID_PREP_PRINTF(trx_sys->max_trx_id));
 
485
 
 
486
                is_ok = FALSE;
 
487
        }
 
488
 
 
489
        if (!has_kernel_mutex) {
 
490
                mutex_exit(&kernel_mutex);
 
491
        }
 
492
 
 
493
        return(is_ok);
 
494
}
 
495
 
 
496
/*********************************************************************//**
 
497
Checks that a record is seen in a consistent read.
 
498
@return TRUE if sees, or FALSE if an earlier version of the record
 
499
should be retrieved */
 
500
UNIV_INTERN
 
501
ibool
 
502
lock_clust_rec_cons_read_sees(
 
503
/*==========================*/
 
504
        const rec_t*    rec,    /*!< in: user record which should be read or
 
505
                                passed over by a read cursor */
 
506
        dict_index_t*   index,  /*!< in: clustered index */
 
507
        const ulint*    offsets,/*!< in: rec_get_offsets(rec, index) */
 
508
        read_view_t*    view)   /*!< in: consistent read view */
 
509
{
 
510
        trx_id_t        trx_id;
 
511
 
 
512
        ut_ad(dict_index_is_clust(index));
 
513
        ut_ad(page_rec_is_user_rec(rec));
 
514
        ut_ad(rec_offs_validate(rec, index, offsets));
 
515
 
 
516
        /* NOTE that we call this function while holding the search
 
517
        system latch. To obey the latching order we must NOT reserve the
 
518
        kernel mutex here! */
 
519
 
 
520
        trx_id = row_get_rec_trx_id(rec, index, offsets);
 
521
 
 
522
        return(read_view_sees_trx_id(view, trx_id));
 
523
}
 
524
 
 
525
/*********************************************************************//**
 
526
Checks that a non-clustered index record is seen in a consistent read.
 
527
 
 
528
NOTE that a non-clustered index page contains so little information on
 
529
its modifications that also in the case FALSE, the present version of
 
530
rec may be the right, but we must check this from the clustered index
 
531
record.
 
532
 
 
533
@return TRUE if certainly sees, or FALSE if an earlier version of the
 
534
clustered index record might be needed */
 
535
UNIV_INTERN
 
536
ulint
 
537
lock_sec_rec_cons_read_sees(
 
538
/*========================*/
 
539
        const rec_t*            rec,    /*!< in: user record which
 
540
                                        should be read or passed over
 
541
                                        by a read cursor */
 
542
        const read_view_t*      view)   /*!< in: consistent read view */
 
543
{
 
544
        trx_id_t        max_trx_id;
 
545
 
 
546
        ut_ad(page_rec_is_user_rec(rec));
 
547
 
 
548
        /* NOTE that we might call this function while holding the search
 
549
        system latch. To obey the latching order we must NOT reserve the
 
550
        kernel mutex here! */
 
551
 
 
552
        if (recv_recovery_is_on()) {
 
553
 
 
554
                return(FALSE);
 
555
        }
 
556
 
 
557
        max_trx_id = page_get_max_trx_id(page_align(rec));
 
558
        ut_ad(!ut_dulint_is_zero(max_trx_id));
 
559
 
 
560
        return(ut_dulint_cmp(max_trx_id, view->up_limit_id) < 0);
 
561
}
 
562
 
 
563
/*********************************************************************//**
 
564
Creates the lock system at database start. */
 
565
UNIV_INTERN
 
566
void
 
567
lock_sys_create(
 
568
/*============*/
 
569
        ulint   n_cells)        /*!< in: number of slots in lock hash table */
 
570
{
 
571
        lock_sys = mem_alloc(sizeof(lock_sys_t));
 
572
 
 
573
        lock_sys->rec_hash = hash_create(n_cells);
 
574
 
 
575
        /* hash_create_mutexes(lock_sys->rec_hash, 2, SYNC_REC_LOCK); */
 
576
 
 
577
        lock_latest_err_file = os_file_create_tmpfile();
 
578
        ut_a(lock_latest_err_file);
 
579
}
 
580
 
 
581
/*********************************************************************//**
 
582
Gets the size of a lock struct.
 
583
@return size in bytes */
 
584
UNIV_INTERN
 
585
ulint
 
586
lock_get_size(void)
 
587
/*===============*/
 
588
{
 
589
        return((ulint)sizeof(lock_t));
 
590
}
 
591
 
 
592
/*********************************************************************//**
 
593
Gets the mode of a lock.
 
594
@return mode */
 
595
UNIV_INLINE
 
596
enum lock_mode
 
597
lock_get_mode(
 
598
/*==========*/
 
599
        const lock_t*   lock)   /*!< in: lock */
 
600
{
 
601
        ut_ad(lock);
 
602
 
 
603
        return(lock->type_mode & LOCK_MODE_MASK);
 
604
}
 
605
 
 
606
/*********************************************************************//**
 
607
Gets the wait flag of a lock.
 
608
@return TRUE if waiting */
 
609
UNIV_INLINE
 
610
ibool
 
611
lock_get_wait(
 
612
/*==========*/
 
613
        const lock_t*   lock)   /*!< in: lock */
 
614
{
 
615
        ut_ad(lock);
 
616
 
 
617
        if (UNIV_UNLIKELY(lock->type_mode & LOCK_WAIT)) {
 
618
 
 
619
                return(TRUE);
 
620
        }
 
621
 
 
622
        return(FALSE);
 
623
}
 
624
 
 
625
/*********************************************************************//**
 
626
Gets the source table of an ALTER TABLE transaction.  The table must be
 
627
covered by an IX or IS table lock.
 
628
@return the source table of transaction, if it is covered by an IX or
 
629
IS table lock; dest if there is no source table, and NULL if the
 
630
transaction is locking more than two tables or an inconsistency is
 
631
found */
 
632
UNIV_INTERN
 
633
dict_table_t*
 
634
lock_get_src_table(
 
635
/*===============*/
 
636
        trx_t*          trx,    /*!< in: transaction */
 
637
        dict_table_t*   dest,   /*!< in: destination of ALTER TABLE */
 
638
        enum lock_mode* mode)   /*!< out: lock mode of the source table */
 
639
{
 
640
        dict_table_t*   src;
 
641
        lock_t*         lock;
 
642
 
 
643
        src = NULL;
 
644
        *mode = LOCK_NONE;
 
645
 
 
646
        for (lock = UT_LIST_GET_FIRST(trx->trx_locks);
 
647
             lock;
 
648
             lock = UT_LIST_GET_NEXT(trx_locks, lock)) {
 
649
                lock_table_t*   tab_lock;
 
650
                enum lock_mode  lock_mode;
 
651
                if (!(lock_get_type_low(lock) & LOCK_TABLE)) {
 
652
                        /* We are only interested in table locks. */
 
653
                        continue;
 
654
                }
 
655
                tab_lock = &lock->un_member.tab_lock;
 
656
                if (dest == tab_lock->table) {
 
657
                        /* We are not interested in the destination table. */
 
658
                        continue;
 
659
                } else if (!src) {
 
660
                        /* This presumably is the source table. */
 
661
                        src = tab_lock->table;
 
662
                        if (UT_LIST_GET_LEN(src->locks) != 1
 
663
                            || UT_LIST_GET_FIRST(src->locks) != lock) {
 
664
                                /* We only support the case when
 
665
                                there is only one lock on this table. */
 
666
                                return(NULL);
 
667
                        }
 
668
                } else if (src != tab_lock->table) {
 
669
                        /* The transaction is locking more than
 
670
                        two tables (src and dest): abort */
 
671
                        return(NULL);
 
672
                }
 
673
 
 
674
                /* Check that the source table is locked by
 
675
                LOCK_IX or LOCK_IS. */
 
676
                lock_mode = lock_get_mode(lock);
 
677
                if (lock_mode == LOCK_IX || lock_mode == LOCK_IS) {
 
678
                        if (*mode != LOCK_NONE && *mode != lock_mode) {
 
679
                                /* There are multiple locks on src. */
 
680
                                return(NULL);
 
681
                        }
 
682
                        *mode = lock_mode;
 
683
                }
 
684
        }
 
685
 
 
686
        if (!src) {
 
687
                /* No source table lock found: flag the situation to caller */
 
688
                src = dest;
 
689
        }
 
690
 
 
691
        return(src);
 
692
}
 
693
 
 
694
/*********************************************************************//**
 
695
Determine if the given table is exclusively "owned" by the given
 
696
transaction, i.e., transaction holds LOCK_IX and possibly LOCK_AUTO_INC
 
697
on the table.
 
698
@return TRUE if table is only locked by trx, with LOCK_IX, and
 
699
possibly LOCK_AUTO_INC */
 
700
UNIV_INTERN
 
701
ibool
 
702
lock_is_table_exclusive(
 
703
/*====================*/
 
704
        dict_table_t*   table,  /*!< in: table */
 
705
        trx_t*          trx)    /*!< in: transaction */
 
706
{
 
707
        const lock_t*   lock;
 
708
        ibool           ok      = FALSE;
 
709
 
 
710
        ut_ad(table);
 
711
        ut_ad(trx);
 
712
 
 
713
        lock_mutex_enter_kernel();
 
714
 
 
715
        for (lock = UT_LIST_GET_FIRST(table->locks);
 
716
             lock;
 
717
             lock = UT_LIST_GET_NEXT(locks, &lock->un_member.tab_lock)) {
 
718
                if (lock->trx != trx) {
 
719
                        /* A lock on the table is held
 
720
                        by some other transaction. */
 
721
                        goto not_ok;
 
722
                }
 
723
 
 
724
                if (!(lock_get_type_low(lock) & LOCK_TABLE)) {
 
725
                        /* We are interested in table locks only. */
 
726
                        continue;
 
727
                }
 
728
 
 
729
                switch (lock_get_mode(lock)) {
 
730
                case LOCK_IX:
 
731
                        ok = TRUE;
 
732
                        break;
 
733
                case LOCK_AUTO_INC:
 
734
                        /* It is allowed for trx to hold an
 
735
                        auto_increment lock. */
 
736
                        break;
 
737
                default:
 
738
not_ok:
 
739
                        /* Other table locks than LOCK_IX are not allowed. */
 
740
                        ok = FALSE;
 
741
                        goto func_exit;
 
742
                }
 
743
        }
 
744
 
 
745
func_exit:
 
746
        lock_mutex_exit_kernel();
 
747
 
 
748
        return(ok);
 
749
}
 
750
 
 
751
/*********************************************************************//**
 
752
Sets the wait flag of a lock and the back pointer in trx to lock. */
 
753
UNIV_INLINE
 
754
void
 
755
lock_set_lock_and_trx_wait(
 
756
/*=======================*/
 
757
        lock_t* lock,   /*!< in: lock */
 
758
        trx_t*  trx)    /*!< in: trx */
 
759
{
 
760
        ut_ad(lock);
 
761
        ut_ad(trx->wait_lock == NULL);
 
762
 
 
763
        trx->wait_lock = lock;
 
764
        lock->type_mode |= LOCK_WAIT;
 
765
}
 
766
 
 
767
/**********************************************************************//**
 
768
The back pointer to a waiting lock request in the transaction is set to NULL
 
769
and the wait bit in lock type_mode is reset. */
 
770
UNIV_INLINE
 
771
void
 
772
lock_reset_lock_and_trx_wait(
 
773
/*=========================*/
 
774
        lock_t* lock)   /*!< in: record lock */
 
775
{
 
776
        ut_ad((lock->trx)->wait_lock == lock);
 
777
        ut_ad(lock_get_wait(lock));
 
778
 
 
779
        /* Reset the back pointer in trx to this waiting lock request */
 
780
 
 
781
        (lock->trx)->wait_lock = NULL;
 
782
        lock->type_mode &= ~LOCK_WAIT;
 
783
}
 
784
 
 
785
/*********************************************************************//**
 
786
Gets the gap flag of a record lock.
 
787
@return TRUE if gap flag set */
 
788
UNIV_INLINE
 
789
ibool
 
790
lock_rec_get_gap(
 
791
/*=============*/
 
792
        const lock_t*   lock)   /*!< in: record lock */
 
793
{
 
794
        ut_ad(lock);
 
795
        ut_ad(lock_get_type_low(lock) == LOCK_REC);
 
796
 
 
797
        if (lock->type_mode & LOCK_GAP) {
 
798
 
 
799
                return(TRUE);
 
800
        }
 
801
 
 
802
        return(FALSE);
 
803
}
 
804
 
 
805
/*********************************************************************//**
 
806
Gets the LOCK_REC_NOT_GAP flag of a record lock.
 
807
@return TRUE if LOCK_REC_NOT_GAP flag set */
 
808
UNIV_INLINE
 
809
ibool
 
810
lock_rec_get_rec_not_gap(
 
811
/*=====================*/
 
812
        const lock_t*   lock)   /*!< in: record lock */
 
813
{
 
814
        ut_ad(lock);
 
815
        ut_ad(lock_get_type_low(lock) == LOCK_REC);
 
816
 
 
817
        if (lock->type_mode & LOCK_REC_NOT_GAP) {
 
818
 
 
819
                return(TRUE);
 
820
        }
 
821
 
 
822
        return(FALSE);
 
823
}
 
824
 
 
825
/*********************************************************************//**
 
826
Gets the waiting insert flag of a record lock.
 
827
@return TRUE if gap flag set */
 
828
UNIV_INLINE
 
829
ibool
 
830
lock_rec_get_insert_intention(
 
831
/*==========================*/
 
832
        const lock_t*   lock)   /*!< in: record lock */
 
833
{
 
834
        ut_ad(lock);
 
835
        ut_ad(lock_get_type_low(lock) == LOCK_REC);
 
836
 
 
837
        if (lock->type_mode & LOCK_INSERT_INTENTION) {
 
838
 
 
839
                return(TRUE);
 
840
        }
 
841
 
 
842
        return(FALSE);
 
843
}
 
844
 
 
845
/*********************************************************************//**
 
846
Calculates if lock mode 1 is stronger or equal to lock mode 2.
 
847
@return nonzero if mode1 stronger or equal to mode2 */
 
848
UNIV_INLINE
 
849
ulint
 
850
lock_mode_stronger_or_eq(
 
851
/*=====================*/
 
852
        enum lock_mode  mode1,  /*!< in: lock mode */
 
853
        enum lock_mode  mode2)  /*!< in: lock mode */
 
854
{
 
855
        ut_ad(mode1 == LOCK_X || mode1 == LOCK_S || mode1 == LOCK_IX
 
856
              || mode1 == LOCK_IS || mode1 == LOCK_AUTO_INC);
 
857
        ut_ad(mode2 == LOCK_X || mode2 == LOCK_S || mode2 == LOCK_IX
 
858
              || mode2 == LOCK_IS || mode2 == LOCK_AUTO_INC);
 
859
 
 
860
        return((LOCK_MODE_STRONGER_OR_EQ) & LK(mode1, mode2));
 
861
}
 
862
 
 
863
/*********************************************************************//**
 
864
Calculates if lock mode 1 is compatible with lock mode 2.
 
865
@return nonzero if mode1 compatible with mode2 */
 
866
UNIV_INLINE
 
867
ulint
 
868
lock_mode_compatible(
 
869
/*=================*/
 
870
        enum lock_mode  mode1,  /*!< in: lock mode */
 
871
        enum lock_mode  mode2)  /*!< in: lock mode */
 
872
{
 
873
        ut_ad(mode1 == LOCK_X || mode1 == LOCK_S || mode1 == LOCK_IX
 
874
              || mode1 == LOCK_IS || mode1 == LOCK_AUTO_INC);
 
875
        ut_ad(mode2 == LOCK_X || mode2 == LOCK_S || mode2 == LOCK_IX
 
876
              || mode2 == LOCK_IS || mode2 == LOCK_AUTO_INC);
 
877
 
 
878
        return((LOCK_MODE_COMPATIBILITY) & LK(mode1, mode2));
 
879
}
 
880
 
 
881
/*********************************************************************//**
 
882
Checks if a lock request for a new lock has to wait for request lock2.
 
883
@return TRUE if new lock has to wait for lock2 to be removed */
 
884
UNIV_INLINE
 
885
ibool
 
886
lock_rec_has_to_wait(
 
887
/*=================*/
 
888
        const trx_t*    trx,    /*!< in: trx of new lock */
 
889
        ulint           type_mode,/*!< in: precise mode of the new lock
 
890
                                to set: LOCK_S or LOCK_X, possibly
 
891
                                ORed to LOCK_GAP or LOCK_REC_NOT_GAP,
 
892
                                LOCK_INSERT_INTENTION */
 
893
        const lock_t*   lock2,  /*!< in: another record lock; NOTE that
 
894
                                it is assumed that this has a lock bit
 
895
                                set on the same record as in the new
 
896
                                lock we are setting */
 
897
        ibool lock_is_on_supremum)  /*!< in: TRUE if we are setting the
 
898
                                lock on the 'supremum' record of an
 
899
                                index page: we know then that the lock
 
900
                                request is really for a 'gap' type lock */
 
901
{
 
902
        ut_ad(trx && lock2);
 
903
        ut_ad(lock_get_type_low(lock2) == LOCK_REC);
 
904
 
 
905
        if (trx != lock2->trx
 
906
            && !lock_mode_compatible(LOCK_MODE_MASK & type_mode,
 
907
                                     lock_get_mode(lock2))) {
 
908
 
 
909
                /* We have somewhat complex rules when gap type record locks
 
910
                cause waits */
 
911
 
 
912
                if ((lock_is_on_supremum || (type_mode & LOCK_GAP))
 
913
                    && !(type_mode & LOCK_INSERT_INTENTION)) {
 
914
 
 
915
                        /* Gap type locks without LOCK_INSERT_INTENTION flag
 
916
                        do not need to wait for anything. This is because
 
917
                        different users can have conflicting lock types
 
918
                        on gaps. */
 
919
 
 
920
                        return(FALSE);
 
921
                }
 
922
 
 
923
                if (!(type_mode & LOCK_INSERT_INTENTION)
 
924
                    && lock_rec_get_gap(lock2)) {
 
925
 
 
926
                        /* Record lock (LOCK_ORDINARY or LOCK_REC_NOT_GAP
 
927
                        does not need to wait for a gap type lock */
 
928
 
 
929
                        return(FALSE);
 
930
                }
 
931
 
 
932
                if ((type_mode & LOCK_GAP)
 
933
                    && lock_rec_get_rec_not_gap(lock2)) {
 
934
 
 
935
                        /* Lock on gap does not need to wait for
 
936
                        a LOCK_REC_NOT_GAP type lock */
 
937
 
 
938
                        return(FALSE);
 
939
                }
 
940
 
 
941
                if (lock_rec_get_insert_intention(lock2)) {
 
942
 
 
943
                        /* No lock request needs to wait for an insert
 
944
                        intention lock to be removed. This is ok since our
 
945
                        rules allow conflicting locks on gaps. This eliminates
 
946
                        a spurious deadlock caused by a next-key lock waiting
 
947
                        for an insert intention lock; when the insert
 
948
                        intention lock was granted, the insert deadlocked on
 
949
                        the waiting next-key lock.
 
950
 
 
951
                        Also, insert intention locks do not disturb each
 
952
                        other. */
 
953
 
 
954
                        return(FALSE);
 
955
                }
 
956
 
 
957
                return(TRUE);
 
958
        }
 
959
 
 
960
        return(FALSE);
 
961
}
 
962
 
 
963
/*********************************************************************//**
 
964
Checks if a lock request lock1 has to wait for request lock2.
 
965
@return TRUE if lock1 has to wait for lock2 to be removed */
 
966
UNIV_INTERN
 
967
ibool
 
968
lock_has_to_wait(
 
969
/*=============*/
 
970
        const lock_t*   lock1,  /*!< in: waiting lock */
 
971
        const lock_t*   lock2)  /*!< in: another lock; NOTE that it is
 
972
                                assumed that this has a lock bit set
 
973
                                on the same record as in lock1 if the
 
974
                                locks are record locks */
 
975
{
 
976
        ut_ad(lock1 && lock2);
 
977
 
 
978
        if (lock1->trx != lock2->trx
 
979
            && !lock_mode_compatible(lock_get_mode(lock1),
 
980
                                     lock_get_mode(lock2))) {
 
981
                if (lock_get_type_low(lock1) == LOCK_REC) {
 
982
                        ut_ad(lock_get_type_low(lock2) == LOCK_REC);
 
983
 
 
984
                        /* If this lock request is for a supremum record
 
985
                        then the second bit on the lock bitmap is set */
 
986
 
 
987
                        return(lock_rec_has_to_wait(lock1->trx,
 
988
                                                    lock1->type_mode, lock2,
 
989
                                                    lock_rec_get_nth_bit(
 
990
                                                            lock1, 1)));
 
991
                }
 
992
 
 
993
                return(TRUE);
 
994
        }
 
995
 
 
996
        return(FALSE);
 
997
}
 
998
 
 
999
/*============== RECORD LOCK BASIC FUNCTIONS ============================*/
 
1000
 
 
1001
/*********************************************************************//**
 
1002
Gets the number of bits in a record lock bitmap.
 
1003
@return number of bits */
 
1004
UNIV_INLINE
 
1005
ulint
 
1006
lock_rec_get_n_bits(
 
1007
/*================*/
 
1008
        const lock_t*   lock)   /*!< in: record lock */
 
1009
{
 
1010
        return(lock->un_member.rec_lock.n_bits);
 
1011
}
 
1012
 
 
1013
/**********************************************************************//**
 
1014
Sets the nth bit of a record lock to TRUE. */
 
1015
UNIV_INLINE
 
1016
void
 
1017
lock_rec_set_nth_bit(
 
1018
/*=================*/
 
1019
        lock_t* lock,   /*!< in: record lock */
 
1020
        ulint   i)      /*!< in: index of the bit */
 
1021
{
 
1022
        ulint   byte_index;
 
1023
        ulint   bit_index;
 
1024
 
 
1025
        ut_ad(lock);
 
1026
        ut_ad(lock_get_type_low(lock) == LOCK_REC);
 
1027
        ut_ad(i < lock->un_member.rec_lock.n_bits);
 
1028
 
 
1029
        byte_index = i / 8;
 
1030
        bit_index = i % 8;
 
1031
 
 
1032
        ((byte*) &lock[1])[byte_index] |= 1 << bit_index;
 
1033
}
 
1034
 
 
1035
/**********************************************************************//**
 
1036
Looks for a set bit in a record lock bitmap. Returns ULINT_UNDEFINED,
 
1037
if none found.
 
1038
@return bit index == heap number of the record, or ULINT_UNDEFINED if
 
1039
none found */
 
1040
UNIV_INTERN
 
1041
ulint
 
1042
lock_rec_find_set_bit(
 
1043
/*==================*/
 
1044
        const lock_t*   lock)   /*!< in: record lock with at least one bit set */
 
1045
{
 
1046
        ulint   i;
 
1047
 
 
1048
        for (i = 0; i < lock_rec_get_n_bits(lock); i++) {
 
1049
 
 
1050
                if (lock_rec_get_nth_bit(lock, i)) {
 
1051
 
 
1052
                        return(i);
 
1053
                }
 
1054
        }
 
1055
 
 
1056
        return(ULINT_UNDEFINED);
 
1057
}
 
1058
 
 
1059
/**********************************************************************//**
 
1060
Resets the nth bit of a record lock. */
 
1061
UNIV_INLINE
 
1062
void
 
1063
lock_rec_reset_nth_bit(
 
1064
/*===================*/
 
1065
        lock_t* lock,   /*!< in: record lock */
 
1066
        ulint   i)      /*!< in: index of the bit which must be set to TRUE
 
1067
                        when this function is called */
 
1068
{
 
1069
        ulint   byte_index;
 
1070
        ulint   bit_index;
 
1071
 
 
1072
        ut_ad(lock);
 
1073
        ut_ad(lock_get_type_low(lock) == LOCK_REC);
 
1074
        ut_ad(i < lock->un_member.rec_lock.n_bits);
 
1075
 
 
1076
        byte_index = i / 8;
 
1077
        bit_index = i % 8;
 
1078
 
 
1079
        ((byte*) &lock[1])[byte_index] &= ~(1 << bit_index);
 
1080
}
 
1081
 
 
1082
/*********************************************************************//**
 
1083
Gets the first or next record lock on a page.
 
1084
@return next lock, NULL if none exists */
 
1085
UNIV_INLINE
 
1086
lock_t*
 
1087
lock_rec_get_next_on_page(
 
1088
/*======================*/
 
1089
        lock_t* lock)   /*!< in: a record lock */
 
1090
{
 
1091
        ulint   space;
 
1092
        ulint   page_no;
 
1093
 
 
1094
        ut_ad(mutex_own(&kernel_mutex));
 
1095
        ut_ad(lock_get_type_low(lock) == LOCK_REC);
 
1096
 
 
1097
        space = lock->un_member.rec_lock.space;
 
1098
        page_no = lock->un_member.rec_lock.page_no;
 
1099
 
 
1100
        for (;;) {
 
1101
                lock = HASH_GET_NEXT(hash, lock);
 
1102
 
 
1103
                if (!lock) {
 
1104
 
 
1105
                        break;
 
1106
                }
 
1107
 
 
1108
                if ((lock->un_member.rec_lock.space == space)
 
1109
                    && (lock->un_member.rec_lock.page_no == page_no)) {
 
1110
 
 
1111
                        break;
 
1112
                }
 
1113
        }
 
1114
 
 
1115
        return(lock);
 
1116
}
 
1117
 
 
1118
/*********************************************************************//**
 
1119
Gets the first record lock on a page, where the page is identified by its
 
1120
file address.
 
1121
@return first lock, NULL if none exists */
 
1122
UNIV_INLINE
 
1123
lock_t*
 
1124
lock_rec_get_first_on_page_addr(
 
1125
/*============================*/
 
1126
        ulint   space,  /*!< in: space */
 
1127
        ulint   page_no)/*!< in: page number */
 
1128
{
 
1129
        lock_t* lock;
 
1130
 
 
1131
        ut_ad(mutex_own(&kernel_mutex));
 
1132
 
 
1133
        lock = HASH_GET_FIRST(lock_sys->rec_hash,
 
1134
                              lock_rec_hash(space, page_no));
 
1135
        while (lock) {
 
1136
                if ((lock->un_member.rec_lock.space == space)
 
1137
                    && (lock->un_member.rec_lock.page_no == page_no)) {
 
1138
 
 
1139
                        break;
 
1140
                }
 
1141
 
 
1142
                lock = HASH_GET_NEXT(hash, lock);
 
1143
        }
 
1144
 
 
1145
        return(lock);
 
1146
}
 
1147
 
 
1148
/*********************************************************************//**
 
1149
Returns TRUE if there are explicit record locks on a page.
 
1150
@return TRUE if there are explicit record locks on the page */
 
1151
UNIV_INTERN
 
1152
ibool
 
1153
lock_rec_expl_exist_on_page(
 
1154
/*========================*/
 
1155
        ulint   space,  /*!< in: space id */
 
1156
        ulint   page_no)/*!< in: page number */
 
1157
{
 
1158
        ibool   ret;
 
1159
 
 
1160
        mutex_enter(&kernel_mutex);
 
1161
 
 
1162
        if (lock_rec_get_first_on_page_addr(space, page_no)) {
 
1163
                ret = TRUE;
 
1164
        } else {
 
1165
                ret = FALSE;
 
1166
        }
 
1167
 
 
1168
        mutex_exit(&kernel_mutex);
 
1169
 
 
1170
        return(ret);
 
1171
}
 
1172
 
 
1173
/*********************************************************************//**
 
1174
Gets the first record lock on a page, where the page is identified by a
 
1175
pointer to it.
 
1176
@return first lock, NULL if none exists */
 
1177
UNIV_INLINE
 
1178
lock_t*
 
1179
lock_rec_get_first_on_page(
 
1180
/*=======================*/
 
1181
        const buf_block_t*      block)  /*!< in: buffer block */
 
1182
{
 
1183
        ulint   hash;
 
1184
        lock_t* lock;
 
1185
        ulint   space   = buf_block_get_space(block);
 
1186
        ulint   page_no = buf_block_get_page_no(block);
 
1187
 
 
1188
        ut_ad(mutex_own(&kernel_mutex));
 
1189
 
 
1190
        hash = buf_block_get_lock_hash_val(block);
 
1191
 
 
1192
        lock = HASH_GET_FIRST(lock_sys->rec_hash, hash);
 
1193
 
 
1194
        while (lock) {
 
1195
                if ((lock->un_member.rec_lock.space == space)
 
1196
                    && (lock->un_member.rec_lock.page_no == page_no)) {
 
1197
 
 
1198
                        break;
 
1199
                }
 
1200
 
 
1201
                lock = HASH_GET_NEXT(hash, lock);
 
1202
        }
 
1203
 
 
1204
        return(lock);
 
1205
}
 
1206
 
 
1207
/*********************************************************************//**
 
1208
Gets the next explicit lock request on a record.
 
1209
@return next lock, NULL if none exists */
 
1210
UNIV_INLINE
 
1211
lock_t*
 
1212
lock_rec_get_next(
 
1213
/*==============*/
 
1214
        ulint   heap_no,/*!< in: heap number of the record */
 
1215
        lock_t* lock)   /*!< in: lock */
 
1216
{
 
1217
        ut_ad(mutex_own(&kernel_mutex));
 
1218
 
 
1219
        do {
 
1220
                ut_ad(lock_get_type_low(lock) == LOCK_REC);
 
1221
                lock = lock_rec_get_next_on_page(lock);
 
1222
        } while (lock && !lock_rec_get_nth_bit(lock, heap_no));
 
1223
 
 
1224
        return(lock);
 
1225
}
 
1226
 
 
1227
/*********************************************************************//**
 
1228
Gets the first explicit lock request on a record.
 
1229
@return first lock, NULL if none exists */
 
1230
UNIV_INLINE
 
1231
lock_t*
 
1232
lock_rec_get_first(
 
1233
/*===============*/
 
1234
        const buf_block_t*      block,  /*!< in: block containing the record */
 
1235
        ulint                   heap_no)/*!< in: heap number of the record */
 
1236
{
 
1237
        lock_t* lock;
 
1238
 
 
1239
        ut_ad(mutex_own(&kernel_mutex));
 
1240
 
 
1241
        for (lock = lock_rec_get_first_on_page(block); lock;
 
1242
             lock = lock_rec_get_next_on_page(lock)) {
 
1243
                if (lock_rec_get_nth_bit(lock, heap_no)) {
 
1244
                        break;
 
1245
                }
 
1246
        }
 
1247
 
 
1248
        return(lock);
 
1249
}
 
1250
 
 
1251
/*********************************************************************//**
 
1252
Resets the record lock bitmap to zero. NOTE: does not touch the wait_lock
 
1253
pointer in the transaction! This function is used in lock object creation
 
1254
and resetting. */
 
1255
static
 
1256
void
 
1257
lock_rec_bitmap_reset(
 
1258
/*==================*/
 
1259
        lock_t* lock)   /*!< in: record lock */
 
1260
{
 
1261
        ulint   n_bytes;
 
1262
 
 
1263
        ut_ad(lock_get_type_low(lock) == LOCK_REC);
 
1264
 
 
1265
        /* Reset to zero the bitmap which resides immediately after the lock
 
1266
        struct */
 
1267
 
 
1268
        n_bytes = lock_rec_get_n_bits(lock) / 8;
 
1269
 
 
1270
        ut_ad((lock_rec_get_n_bits(lock) % 8) == 0);
 
1271
 
 
1272
        memset(&lock[1], 0, n_bytes);
 
1273
}
 
1274
 
 
1275
/*********************************************************************//**
 
1276
Copies a record lock to heap.
 
1277
@return copy of lock */
 
1278
static
 
1279
lock_t*
 
1280
lock_rec_copy(
 
1281
/*==========*/
 
1282
        const lock_t*   lock,   /*!< in: record lock */
 
1283
        mem_heap_t*     heap)   /*!< in: memory heap */
 
1284
{
 
1285
        ulint   size;
 
1286
 
 
1287
        ut_ad(lock_get_type_low(lock) == LOCK_REC);
 
1288
 
 
1289
        size = sizeof(lock_t) + lock_rec_get_n_bits(lock) / 8;
 
1290
 
 
1291
        return(mem_heap_dup(heap, lock, size));
 
1292
}
 
1293
 
 
1294
/*********************************************************************//**
 
1295
Gets the previous record lock set on a record.
 
1296
@return previous lock on the same record, NULL if none exists */
 
1297
UNIV_INTERN
 
1298
const lock_t*
 
1299
lock_rec_get_prev(
 
1300
/*==============*/
 
1301
        const lock_t*   in_lock,/*!< in: record lock */
 
1302
        ulint           heap_no)/*!< in: heap number of the record */
 
1303
{
 
1304
        lock_t* lock;
 
1305
        ulint   space;
 
1306
        ulint   page_no;
 
1307
        lock_t* found_lock      = NULL;
 
1308
 
 
1309
        ut_ad(mutex_own(&kernel_mutex));
 
1310
        ut_ad(lock_get_type_low(in_lock) == LOCK_REC);
 
1311
 
 
1312
        space = in_lock->un_member.rec_lock.space;
 
1313
        page_no = in_lock->un_member.rec_lock.page_no;
 
1314
 
 
1315
        lock = lock_rec_get_first_on_page_addr(space, page_no);
 
1316
 
 
1317
        for (;;) {
 
1318
                ut_ad(lock);
 
1319
 
 
1320
                if (lock == in_lock) {
 
1321
 
 
1322
                        return(found_lock);
 
1323
                }
 
1324
 
 
1325
                if (lock_rec_get_nth_bit(lock, heap_no)) {
 
1326
 
 
1327
                        found_lock = lock;
 
1328
                }
 
1329
 
 
1330
                lock = lock_rec_get_next_on_page(lock);
 
1331
        }
 
1332
}
 
1333
 
 
1334
/*============= FUNCTIONS FOR ANALYZING TABLE LOCK QUEUE ================*/
 
1335
 
 
1336
/*********************************************************************//**
 
1337
Checks if a transaction has the specified table lock, or stronger.
 
1338
@return lock or NULL */
 
1339
UNIV_INLINE
 
1340
lock_t*
 
1341
lock_table_has(
 
1342
/*===========*/
 
1343
        trx_t*          trx,    /*!< in: transaction */
 
1344
        dict_table_t*   table,  /*!< in: table */
 
1345
        enum lock_mode  mode)   /*!< in: lock mode */
 
1346
{
 
1347
        lock_t* lock;
 
1348
 
 
1349
        ut_ad(mutex_own(&kernel_mutex));
 
1350
 
 
1351
        /* Look for stronger locks the same trx already has on the table */
 
1352
 
 
1353
        lock = UT_LIST_GET_LAST(table->locks);
 
1354
 
 
1355
        while (lock != NULL) {
 
1356
 
 
1357
                if (lock->trx == trx
 
1358
                    && lock_mode_stronger_or_eq(lock_get_mode(lock), mode)) {
 
1359
 
 
1360
                        /* The same trx already has locked the table in
 
1361
                        a mode stronger or equal to the mode given */
 
1362
 
 
1363
                        ut_ad(!lock_get_wait(lock));
 
1364
 
 
1365
                        return(lock);
 
1366
                }
 
1367
 
 
1368
                lock = UT_LIST_GET_PREV(un_member.tab_lock.locks, lock);
 
1369
        }
 
1370
 
 
1371
        return(NULL);
 
1372
}
 
1373
 
 
1374
/*============= FUNCTIONS FOR ANALYZING RECORD LOCK QUEUE ================*/
 
1375
 
 
1376
/*********************************************************************//**
 
1377
Checks if a transaction has a GRANTED explicit lock on rec stronger or equal
 
1378
to precise_mode.
 
1379
@return lock or NULL */
 
1380
UNIV_INLINE
 
1381
lock_t*
 
1382
lock_rec_has_expl(
 
1383
/*==============*/
 
1384
        ulint                   precise_mode,/*!< in: LOCK_S or LOCK_X
 
1385
                                        possibly ORed to LOCK_GAP or
 
1386
                                        LOCK_REC_NOT_GAP, for a
 
1387
                                        supremum record we regard this
 
1388
                                        always a gap type request */
 
1389
        const buf_block_t*      block,  /*!< in: buffer block containing
 
1390
                                        the record */
 
1391
        ulint                   heap_no,/*!< in: heap number of the record */
 
1392
        trx_t*                  trx)    /*!< in: transaction */
 
1393
{
 
1394
        lock_t* lock;
 
1395
 
 
1396
        ut_ad(mutex_own(&kernel_mutex));
 
1397
        ut_ad((precise_mode & LOCK_MODE_MASK) == LOCK_S
 
1398
              || (precise_mode & LOCK_MODE_MASK) == LOCK_X);
 
1399
        ut_ad(!(precise_mode & LOCK_INSERT_INTENTION));
 
1400
 
 
1401
        lock = lock_rec_get_first(block, heap_no);
 
1402
 
 
1403
        while (lock) {
 
1404
                if (lock->trx == trx
 
1405
                    && lock_mode_stronger_or_eq(lock_get_mode(lock),
 
1406
                                                precise_mode & LOCK_MODE_MASK)
 
1407
                    && !lock_get_wait(lock)
 
1408
                    && (!lock_rec_get_rec_not_gap(lock)
 
1409
                        || (precise_mode & LOCK_REC_NOT_GAP)
 
1410
                        || heap_no == PAGE_HEAP_NO_SUPREMUM)
 
1411
                    && (!lock_rec_get_gap(lock)
 
1412
                        || (precise_mode & LOCK_GAP)
 
1413
                        || heap_no == PAGE_HEAP_NO_SUPREMUM)
 
1414
                    && (!lock_rec_get_insert_intention(lock))) {
 
1415
 
 
1416
                        return(lock);
 
1417
                }
 
1418
 
 
1419
                lock = lock_rec_get_next(heap_no, lock);
 
1420
        }
 
1421
 
 
1422
        return(NULL);
 
1423
}
 
1424
 
 
1425
#ifdef UNIV_DEBUG
 
1426
/*********************************************************************//**
 
1427
Checks if some other transaction has a lock request in the queue.
 
1428
@return lock or NULL */
 
1429
static
 
1430
lock_t*
 
1431
lock_rec_other_has_expl_req(
 
1432
/*========================*/
 
1433
        enum lock_mode          mode,   /*!< in: LOCK_S or LOCK_X */
 
1434
        ulint                   gap,    /*!< in: LOCK_GAP if also gap
 
1435
                                        locks are taken into account,
 
1436
                                        or 0 if not */
 
1437
        ulint                   wait,   /*!< in: LOCK_WAIT if also
 
1438
                                        waiting locks are taken into
 
1439
                                        account, or 0 if not */
 
1440
        const buf_block_t*      block,  /*!< in: buffer block containing
 
1441
                                        the record */
 
1442
        ulint                   heap_no,/*!< in: heap number of the record */
 
1443
        const trx_t*            trx)    /*!< in: transaction, or NULL if
 
1444
                                        requests by all transactions
 
1445
                                        are taken into account */
 
1446
{
 
1447
        lock_t* lock;
 
1448
 
 
1449
        ut_ad(mutex_own(&kernel_mutex));
 
1450
        ut_ad(mode == LOCK_X || mode == LOCK_S);
 
1451
        ut_ad(gap == 0 || gap == LOCK_GAP);
 
1452
        ut_ad(wait == 0 || wait == LOCK_WAIT);
 
1453
 
 
1454
        lock = lock_rec_get_first(block, heap_no);
 
1455
 
 
1456
        while (lock) {
 
1457
                if (lock->trx != trx
 
1458
                    && (gap
 
1459
                        || !(lock_rec_get_gap(lock)
 
1460
                             || heap_no == PAGE_HEAP_NO_SUPREMUM))
 
1461
                    && (wait || !lock_get_wait(lock))
 
1462
                    && lock_mode_stronger_or_eq(lock_get_mode(lock), mode)) {
 
1463
 
 
1464
                        return(lock);
 
1465
                }
 
1466
 
 
1467
                lock = lock_rec_get_next(heap_no, lock);
 
1468
        }
 
1469
 
 
1470
        return(NULL);
 
1471
}
 
1472
#endif /* UNIV_DEBUG */
 
1473
 
 
1474
/*********************************************************************//**
 
1475
Checks if some other transaction has a conflicting explicit lock request
 
1476
in the queue, so that we have to wait.
 
1477
@return lock or NULL */
 
1478
static
 
1479
lock_t*
 
1480
lock_rec_other_has_conflicting(
 
1481
/*===========================*/
 
1482
        enum lock_mode          mode,   /*!< in: LOCK_S or LOCK_X,
 
1483
                                        possibly ORed to LOCK_GAP or
 
1484
                                        LOC_REC_NOT_GAP,
 
1485
                                        LOCK_INSERT_INTENTION */
 
1486
        const buf_block_t*      block,  /*!< in: buffer block containing
 
1487
                                        the record */
 
1488
        ulint                   heap_no,/*!< in: heap number of the record */
 
1489
        trx_t*                  trx)    /*!< in: our transaction */
 
1490
{
 
1491
        lock_t* lock;
 
1492
 
 
1493
        ut_ad(mutex_own(&kernel_mutex));
 
1494
 
 
1495
        lock = lock_rec_get_first(block, heap_no);
 
1496
 
 
1497
        if (UNIV_LIKELY_NULL(lock)) {
 
1498
                if (UNIV_UNLIKELY(heap_no == PAGE_HEAP_NO_SUPREMUM)) {
 
1499
 
 
1500
                        do {
 
1501
                                if (lock_rec_has_to_wait(trx, mode, lock,
 
1502
                                                         TRUE)) {
 
1503
                                        return(lock);
 
1504
                                }
 
1505
 
 
1506
                                lock = lock_rec_get_next(heap_no, lock);
 
1507
                        } while (lock);
 
1508
                } else {
 
1509
 
 
1510
                        do {
 
1511
                                if (lock_rec_has_to_wait(trx, mode, lock,
 
1512
                                                         FALSE)) {
 
1513
                                        return(lock);
 
1514
                                }
 
1515
 
 
1516
                                lock = lock_rec_get_next(heap_no, lock);
 
1517
                        } while (lock);
 
1518
                }
 
1519
        }
 
1520
 
 
1521
        return(NULL);
 
1522
}
 
1523
 
 
1524
/*********************************************************************//**
 
1525
Looks for a suitable type record lock struct by the same trx on the same page.
 
1526
This can be used to save space when a new record lock should be set on a page:
 
1527
no new struct is needed, if a suitable old is found.
 
1528
@return lock or NULL */
 
1529
UNIV_INLINE
 
1530
lock_t*
 
1531
lock_rec_find_similar_on_page(
 
1532
/*==========================*/
 
1533
        ulint           type_mode,      /*!< in: lock type_mode field */
 
1534
        ulint           heap_no,        /*!< in: heap number of the record */
 
1535
        lock_t*         lock,           /*!< in: lock_rec_get_first_on_page() */
 
1536
        const trx_t*    trx)            /*!< in: transaction */
 
1537
{
 
1538
        ut_ad(mutex_own(&kernel_mutex));
 
1539
 
 
1540
        while (lock != NULL) {
 
1541
                if (lock->trx == trx
 
1542
                    && lock->type_mode == type_mode
 
1543
                    && lock_rec_get_n_bits(lock) > heap_no) {
 
1544
 
 
1545
                        return(lock);
 
1546
                }
 
1547
 
 
1548
                lock = lock_rec_get_next_on_page(lock);
 
1549
        }
 
1550
 
 
1551
        return(NULL);
 
1552
}
 
1553
 
 
1554
/*********************************************************************//**
 
1555
Checks if some transaction has an implicit x-lock on a record in a secondary
 
1556
index.
 
1557
@return transaction which has the x-lock, or NULL */
 
1558
static
 
1559
trx_t*
 
1560
lock_sec_rec_some_has_impl_off_kernel(
 
1561
/*==================================*/
 
1562
        const rec_t*    rec,    /*!< in: user record */
 
1563
        dict_index_t*   index,  /*!< in: secondary index */
 
1564
        const ulint*    offsets)/*!< in: rec_get_offsets(rec, index) */
 
1565
{
 
1566
        const page_t*   page = page_align(rec);
 
1567
 
 
1568
        ut_ad(mutex_own(&kernel_mutex));
 
1569
        ut_ad(!dict_index_is_clust(index));
 
1570
        ut_ad(page_rec_is_user_rec(rec));
 
1571
        ut_ad(rec_offs_validate(rec, index, offsets));
 
1572
 
 
1573
        /* Some transaction may have an implicit x-lock on the record only
 
1574
        if the max trx id for the page >= min trx id for the trx list, or
 
1575
        database recovery is running. We do not write the changes of a page
 
1576
        max trx id to the log, and therefore during recovery, this value
 
1577
        for a page may be incorrect. */
 
1578
 
 
1579
        if (!(ut_dulint_cmp(page_get_max_trx_id(page),
 
1580
                            trx_list_get_min_trx_id()) >= 0)
 
1581
            && !recv_recovery_is_on()) {
 
1582
 
 
1583
                return(NULL);
 
1584
        }
 
1585
 
 
1586
        /* Ok, in this case it is possible that some transaction has an
 
1587
        implicit x-lock. We have to look in the clustered index. */
 
1588
 
 
1589
        if (!lock_check_trx_id_sanity(page_get_max_trx_id(page),
 
1590
                                      rec, index, offsets, TRUE)) {
 
1591
                buf_page_print(page, 0);
 
1592
 
 
1593
                /* The page is corrupt: try to avoid a crash by returning
 
1594
                NULL */
 
1595
                return(NULL);
 
1596
        }
 
1597
 
 
1598
        return(row_vers_impl_x_locked_off_kernel(rec, index, offsets));
 
1599
}
 
1600
 
 
1601
/*********************************************************************//**
 
1602
Return approximate number or record locks (bits set in the bitmap) for
 
1603
this transaction. Since delete-marked records may be removed, the
 
1604
record count will not be precise. */
 
1605
UNIV_INTERN
 
1606
ulint
 
1607
lock_number_of_rows_locked(
 
1608
/*=======================*/
 
1609
        trx_t*  trx)    /*!< in: transaction */
 
1610
{
 
1611
        lock_t* lock;
 
1612
        ulint   n_records = 0;
 
1613
        ulint   n_bits;
 
1614
        ulint   n_bit;
 
1615
 
 
1616
        lock = UT_LIST_GET_FIRST(trx->trx_locks);
 
1617
 
 
1618
        while (lock) {
 
1619
                if (lock_get_type_low(lock) == LOCK_REC) {
 
1620
                        n_bits = lock_rec_get_n_bits(lock);
 
1621
 
 
1622
                        for (n_bit = 0; n_bit < n_bits; n_bit++) {
 
1623
                                if (lock_rec_get_nth_bit(lock, n_bit)) {
 
1624
                                        n_records++;
 
1625
                                }
 
1626
                        }
 
1627
                }
 
1628
 
 
1629
                lock = UT_LIST_GET_NEXT(trx_locks, lock);
 
1630
        }
 
1631
 
 
1632
        return (n_records);
 
1633
}
 
1634
 
 
1635
/*============== RECORD LOCK CREATION AND QUEUE MANAGEMENT =============*/
 
1636
 
 
1637
/*********************************************************************//**
 
1638
Creates a new record lock and inserts it to the lock queue. Does NOT check
 
1639
for deadlocks or lock compatibility!
 
1640
@return created lock */
 
1641
static
 
1642
lock_t*
 
1643
lock_rec_create(
 
1644
/*============*/
 
1645
        ulint                   type_mode,/*!< in: lock mode and wait
 
1646
                                        flag, type is ignored and
 
1647
                                        replaced by LOCK_REC */
 
1648
        const buf_block_t*      block,  /*!< in: buffer block containing
 
1649
                                        the record */
 
1650
        ulint                   heap_no,/*!< in: heap number of the record */
 
1651
        dict_index_t*           index,  /*!< in: index of record */
 
1652
        trx_t*                  trx)    /*!< in: transaction */
 
1653
{
 
1654
        lock_t*         lock;
 
1655
        ulint           page_no;
 
1656
        ulint           space;
 
1657
        ulint           n_bits;
 
1658
        ulint           n_bytes;
 
1659
        const page_t*   page;
 
1660
 
 
1661
        ut_ad(mutex_own(&kernel_mutex));
 
1662
 
 
1663
        space = buf_block_get_space(block);
 
1664
        page_no = buf_block_get_page_no(block);
 
1665
        page = block->frame;
 
1666
 
 
1667
        ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table));
 
1668
 
 
1669
        /* If rec is the supremum record, then we reset the gap and
 
1670
        LOCK_REC_NOT_GAP bits, as all locks on the supremum are
 
1671
        automatically of the gap type */
 
1672
 
 
1673
        if (UNIV_UNLIKELY(heap_no == PAGE_HEAP_NO_SUPREMUM)) {
 
1674
                ut_ad(!(type_mode & LOCK_REC_NOT_GAP));
 
1675
 
 
1676
                type_mode = type_mode & ~(LOCK_GAP | LOCK_REC_NOT_GAP);
 
1677
        }
 
1678
 
 
1679
        /* Make lock bitmap bigger by a safety margin */
 
1680
        n_bits = page_dir_get_n_heap(page) + LOCK_PAGE_BITMAP_MARGIN;
 
1681
        n_bytes = 1 + n_bits / 8;
 
1682
 
 
1683
        lock = mem_heap_alloc(trx->lock_heap, sizeof(lock_t) + n_bytes);
 
1684
 
 
1685
        UT_LIST_ADD_LAST(trx_locks, trx->trx_locks, lock);
 
1686
 
 
1687
        lock->trx = trx;
 
1688
 
 
1689
        lock->type_mode = (type_mode & ~LOCK_TYPE_MASK) | LOCK_REC;
 
1690
        lock->index = index;
 
1691
 
 
1692
        lock->un_member.rec_lock.space = space;
 
1693
        lock->un_member.rec_lock.page_no = page_no;
 
1694
        lock->un_member.rec_lock.n_bits = n_bytes * 8;
 
1695
 
 
1696
        /* Reset to zero the bitmap which resides immediately after the
 
1697
        lock struct */
 
1698
 
 
1699
        lock_rec_bitmap_reset(lock);
 
1700
 
 
1701
        /* Set the bit corresponding to rec */
 
1702
        lock_rec_set_nth_bit(lock, heap_no);
 
1703
 
 
1704
        HASH_INSERT(lock_t, hash, lock_sys->rec_hash,
 
1705
                    lock_rec_fold(space, page_no), lock);
 
1706
        if (UNIV_UNLIKELY(type_mode & LOCK_WAIT)) {
 
1707
 
 
1708
                lock_set_lock_and_trx_wait(lock, trx);
 
1709
        }
 
1710
 
 
1711
        return(lock);
 
1712
}
 
1713
 
 
1714
/*********************************************************************//**
 
1715
Enqueues a waiting request for a lock which cannot be granted immediately.
 
1716
Checks for deadlocks.
 
1717
@return DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED, or
 
1718
DB_SUCCESS; DB_SUCCESS means that there was a deadlock, but another
 
1719
transaction was chosen as a victim, and we got the lock immediately:
 
1720
no need to wait then */
 
1721
static
 
1722
ulint
 
1723
lock_rec_enqueue_waiting(
 
1724
/*=====================*/
 
1725
        ulint                   type_mode,/*!< in: lock mode this
 
1726
                                        transaction is requesting:
 
1727
                                        LOCK_S or LOCK_X, possibly
 
1728
                                        ORed with LOCK_GAP or
 
1729
                                        LOCK_REC_NOT_GAP, ORed with
 
1730
                                        LOCK_INSERT_INTENTION if this
 
1731
                                        waiting lock request is set
 
1732
                                        when performing an insert of
 
1733
                                        an index record */
 
1734
        const buf_block_t*      block,  /*!< in: buffer block containing
 
1735
                                        the record */
 
1736
        ulint                   heap_no,/*!< in: heap number of the record */
 
1737
        dict_index_t*           index,  /*!< in: index of record */
 
1738
        que_thr_t*              thr)    /*!< in: query thread */
 
1739
{
 
1740
        lock_t* lock;
 
1741
        trx_t*  trx;
 
1742
 
 
1743
        ut_ad(mutex_own(&kernel_mutex));
 
1744
 
 
1745
        /* Test if there already is some other reason to suspend thread:
 
1746
        we do not enqueue a lock request if the query thread should be
 
1747
        stopped anyway */
 
1748
 
 
1749
        if (UNIV_UNLIKELY(que_thr_stop(thr))) {
 
1750
 
 
1751
                ut_error;
 
1752
 
 
1753
                return(DB_QUE_THR_SUSPENDED);
 
1754
        }
 
1755
 
 
1756
        trx = thr_get_trx(thr);
 
1757
 
 
1758
        switch (trx_get_dict_operation(trx)) {
 
1759
        case TRX_DICT_OP_NONE:
 
1760
                break;
 
1761
        case TRX_DICT_OP_TABLE:
 
1762
        case TRX_DICT_OP_INDEX:
 
1763
                ut_print_timestamp(stderr);
 
1764
                fputs("  InnoDB: Error: a record lock wait happens"
 
1765
                      " in a dictionary operation!\n"
 
1766
                      "InnoDB: ", stderr);
 
1767
                dict_index_name_print(stderr, trx, index);
 
1768
                fputs(".\n"
 
1769
                      "InnoDB: Submit a detailed bug report"
 
1770
                      " to http://bugs.mysql.com\n",
 
1771
                      stderr);
 
1772
        }
 
1773
 
 
1774
        /* Enqueue the lock request that will wait to be granted */
 
1775
        lock = lock_rec_create(type_mode | LOCK_WAIT,
 
1776
                               block, heap_no, index, trx);
 
1777
 
 
1778
        /* Check if a deadlock occurs: if yes, remove the lock request and
 
1779
        return an error code */
 
1780
 
 
1781
        if (UNIV_UNLIKELY(lock_deadlock_occurs(lock, trx))) {
 
1782
 
 
1783
                lock_reset_lock_and_trx_wait(lock);
 
1784
                lock_rec_reset_nth_bit(lock, heap_no);
 
1785
 
 
1786
                return(DB_DEADLOCK);
 
1787
        }
 
1788
 
 
1789
        /* If there was a deadlock but we chose another transaction as a
 
1790
        victim, it is possible that we already have the lock now granted! */
 
1791
 
 
1792
        if (trx->wait_lock == NULL) {
 
1793
 
 
1794
                return(DB_SUCCESS);
 
1795
        }
 
1796
 
 
1797
        trx->que_state = TRX_QUE_LOCK_WAIT;
 
1798
        trx->was_chosen_as_deadlock_victim = FALSE;
 
1799
        trx->wait_started = time(NULL);
 
1800
 
 
1801
        ut_a(que_thr_stop(thr));
 
1802
 
 
1803
#ifdef UNIV_DEBUG
 
1804
        if (lock_print_waits) {
 
1805
                fprintf(stderr, "Lock wait for trx %lu in index ",
 
1806
                        (ulong) ut_dulint_get_low(trx->id));
 
1807
                ut_print_name(stderr, trx, FALSE, index->name);
 
1808
        }
 
1809
#endif /* UNIV_DEBUG */
 
1810
 
 
1811
        return(DB_LOCK_WAIT);
 
1812
}
 
1813
 
 
1814
/*********************************************************************//**
 
1815
Adds a record lock request in the record queue. The request is normally
 
1816
added as the last in the queue, but if there are no waiting lock requests
 
1817
on the record, and the request to be added is not a waiting request, we
 
1818
can reuse a suitable record lock object already existing on the same page,
 
1819
just setting the appropriate bit in its bitmap. This is a low-level function
 
1820
which does NOT check for deadlocks or lock compatibility!
 
1821
@return lock where the bit was set */
 
1822
static
 
1823
lock_t*
 
1824
lock_rec_add_to_queue(
 
1825
/*==================*/
 
1826
        ulint                   type_mode,/*!< in: lock mode, wait, gap
 
1827
                                        etc. flags; type is ignored
 
1828
                                        and replaced by LOCK_REC */
 
1829
        const buf_block_t*      block,  /*!< in: buffer block containing
 
1830
                                        the record */
 
1831
        ulint                   heap_no,/*!< in: heap number of the record */
 
1832
        dict_index_t*           index,  /*!< in: index of record */
 
1833
        trx_t*                  trx)    /*!< in: transaction */
 
1834
{
 
1835
        lock_t* lock;
 
1836
 
 
1837
        ut_ad(mutex_own(&kernel_mutex));
 
1838
#ifdef UNIV_DEBUG
 
1839
        switch (type_mode & LOCK_MODE_MASK) {
 
1840
        case LOCK_X:
 
1841
        case LOCK_S:
 
1842
                break;
 
1843
        default:
 
1844
                ut_error;
 
1845
        }
 
1846
 
 
1847
        if (!(type_mode & (LOCK_WAIT | LOCK_GAP))) {
 
1848
                enum lock_mode  mode = (type_mode & LOCK_MODE_MASK) == LOCK_S
 
1849
                        ? LOCK_X
 
1850
                        : LOCK_S;
 
1851
                lock_t*         other_lock
 
1852
                        = lock_rec_other_has_expl_req(mode, 0, LOCK_WAIT,
 
1853
                                                      block, heap_no, trx);
 
1854
                ut_a(!other_lock);
 
1855
        }
 
1856
#endif /* UNIV_DEBUG */
 
1857
 
 
1858
        type_mode |= LOCK_REC;
 
1859
 
 
1860
        /* If rec is the supremum record, then we can reset the gap bit, as
 
1861
        all locks on the supremum are automatically of the gap type, and we
 
1862
        try to avoid unnecessary memory consumption of a new record lock
 
1863
        struct for a gap type lock */
 
1864
 
 
1865
        if (UNIV_UNLIKELY(heap_no == PAGE_HEAP_NO_SUPREMUM)) {
 
1866
                ut_ad(!(type_mode & LOCK_REC_NOT_GAP));
 
1867
 
 
1868
                /* There should never be LOCK_REC_NOT_GAP on a supremum
 
1869
                record, but let us play safe */
 
1870
 
 
1871
                type_mode = type_mode & ~(LOCK_GAP | LOCK_REC_NOT_GAP);
 
1872
        }
 
1873
 
 
1874
        /* Look for a waiting lock request on the same record or on a gap */
 
1875
 
 
1876
        lock = lock_rec_get_first_on_page(block);
 
1877
 
 
1878
        while (lock != NULL) {
 
1879
                if (lock_get_wait(lock)
 
1880
                    && (lock_rec_get_nth_bit(lock, heap_no))) {
 
1881
 
 
1882
                        goto somebody_waits;
 
1883
                }
 
1884
 
 
1885
                lock = lock_rec_get_next_on_page(lock);
 
1886
        }
 
1887
 
 
1888
        if (UNIV_LIKELY(!(type_mode & LOCK_WAIT))) {
 
1889
 
 
1890
                /* Look for a similar record lock on the same page:
 
1891
                if one is found and there are no waiting lock requests,
 
1892
                we can just set the bit */
 
1893
 
 
1894
                lock = lock_rec_find_similar_on_page(
 
1895
                        type_mode, heap_no,
 
1896
                        lock_rec_get_first_on_page(block), trx);
 
1897
 
 
1898
                if (lock) {
 
1899
 
 
1900
                        lock_rec_set_nth_bit(lock, heap_no);
 
1901
 
 
1902
                        return(lock);
 
1903
                }
 
1904
        }
 
1905
 
 
1906
somebody_waits:
 
1907
        return(lock_rec_create(type_mode, block, heap_no, index, trx));
 
1908
}
 
1909
 
 
1910
/*********************************************************************//**
 
1911
This is a fast routine for locking a record in the most common cases:
 
1912
there are no explicit locks on the page, or there is just one lock, owned
 
1913
by this transaction, and of the right type_mode. This is a low-level function
 
1914
which does NOT look at implicit locks! Checks lock compatibility within
 
1915
explicit locks. This function sets a normal next-key lock, or in the case of
 
1916
a page supremum record, a gap type lock.
 
1917
@return TRUE if locking succeeded */
 
1918
UNIV_INLINE
 
1919
ibool
 
1920
lock_rec_lock_fast(
 
1921
/*===============*/
 
1922
        ibool                   impl,   /*!< in: if TRUE, no lock is set
 
1923
                                        if no wait is necessary: we
 
1924
                                        assume that the caller will
 
1925
                                        set an implicit lock */
 
1926
        ulint                   mode,   /*!< in: lock mode: LOCK_X or
 
1927
                                        LOCK_S possibly ORed to either
 
1928
                                        LOCK_GAP or LOCK_REC_NOT_GAP */
 
1929
        const buf_block_t*      block,  /*!< in: buffer block containing
 
1930
                                        the record */
 
1931
        ulint                   heap_no,/*!< in: heap number of record */
 
1932
        dict_index_t*           index,  /*!< in: index of record */
 
1933
        que_thr_t*              thr)    /*!< in: query thread */
 
1934
{
 
1935
        lock_t* lock;
 
1936
        trx_t*  trx;
 
1937
 
 
1938
        ut_ad(mutex_own(&kernel_mutex));
 
1939
        ut_ad((LOCK_MODE_MASK & mode) != LOCK_S
 
1940
              || lock_table_has(thr_get_trx(thr), index->table, LOCK_IS));
 
1941
        ut_ad((LOCK_MODE_MASK & mode) != LOCK_X
 
1942
              || lock_table_has(thr_get_trx(thr), index->table, LOCK_IX));
 
1943
        ut_ad((LOCK_MODE_MASK & mode) == LOCK_S
 
1944
              || (LOCK_MODE_MASK & mode) == LOCK_X);
 
1945
        ut_ad(mode - (LOCK_MODE_MASK & mode) == LOCK_GAP
 
1946
              || mode - (LOCK_MODE_MASK & mode) == 0
 
1947
              || mode - (LOCK_MODE_MASK & mode) == LOCK_REC_NOT_GAP);
 
1948
 
 
1949
        lock = lock_rec_get_first_on_page(block);
 
1950
 
 
1951
        trx = thr_get_trx(thr);
 
1952
 
 
1953
        if (lock == NULL) {
 
1954
                if (!impl) {
 
1955
                        lock_rec_create(mode, block, heap_no, index, trx);
 
1956
                }
 
1957
 
 
1958
                return(TRUE);
 
1959
        }
 
1960
 
 
1961
        if (lock_rec_get_next_on_page(lock)) {
 
1962
 
 
1963
                return(FALSE);
 
1964
        }
 
1965
 
 
1966
        if (lock->trx != trx
 
1967
            || lock->type_mode != (mode | LOCK_REC)
 
1968
            || lock_rec_get_n_bits(lock) <= heap_no) {
 
1969
 
 
1970
                return(FALSE);
 
1971
        }
 
1972
 
 
1973
        if (!impl) {
 
1974
                /* If the nth bit of the record lock is already set then we
 
1975
                do not set a new lock bit, otherwise we do set */
 
1976
 
 
1977
                if (!lock_rec_get_nth_bit(lock, heap_no)) {
 
1978
                        lock_rec_set_nth_bit(lock, heap_no);
 
1979
                }
 
1980
        }
 
1981
 
 
1982
        return(TRUE);
 
1983
}
 
1984
 
 
1985
/*********************************************************************//**
 
1986
This is the general, and slower, routine for locking a record. This is a
 
1987
low-level function which does NOT look at implicit locks! Checks lock
 
1988
compatibility within explicit locks. This function sets a normal next-key
 
1989
lock, or in the case of a page supremum record, a gap type lock.
 
1990
@return DB_SUCCESS, DB_LOCK_WAIT, or error code */
 
1991
static
 
1992
ulint
 
1993
lock_rec_lock_slow(
 
1994
/*===============*/
 
1995
        ibool                   impl,   /*!< in: if TRUE, no lock is set
 
1996
                                        if no wait is necessary: we
 
1997
                                        assume that the caller will
 
1998
                                        set an implicit lock */
 
1999
        ulint                   mode,   /*!< in: lock mode: LOCK_X or
 
2000
                                        LOCK_S possibly ORed to either
 
2001
                                        LOCK_GAP or LOCK_REC_NOT_GAP */
 
2002
        const buf_block_t*      block,  /*!< in: buffer block containing
 
2003
                                        the record */
 
2004
        ulint                   heap_no,/*!< in: heap number of record */
 
2005
        dict_index_t*           index,  /*!< in: index of record */
 
2006
        que_thr_t*              thr)    /*!< in: query thread */
 
2007
{
 
2008
        trx_t*  trx;
 
2009
        ulint   err;
 
2010
 
 
2011
        ut_ad(mutex_own(&kernel_mutex));
 
2012
        ut_ad((LOCK_MODE_MASK & mode) != LOCK_S
 
2013
              || lock_table_has(thr_get_trx(thr), index->table, LOCK_IS));
 
2014
        ut_ad((LOCK_MODE_MASK & mode) != LOCK_X
 
2015
              || lock_table_has(thr_get_trx(thr), index->table, LOCK_IX));
 
2016
        ut_ad((LOCK_MODE_MASK & mode) == LOCK_S
 
2017
              || (LOCK_MODE_MASK & mode) == LOCK_X);
 
2018
        ut_ad(mode - (LOCK_MODE_MASK & mode) == LOCK_GAP
 
2019
              || mode - (LOCK_MODE_MASK & mode) == 0
 
2020
              || mode - (LOCK_MODE_MASK & mode) == LOCK_REC_NOT_GAP);
 
2021
 
 
2022
        trx = thr_get_trx(thr);
 
2023
 
 
2024
        if (lock_rec_has_expl(mode, block, heap_no, trx)) {
 
2025
                /* The trx already has a strong enough lock on rec: do
 
2026
                nothing */
 
2027
 
 
2028
                err = DB_SUCCESS;
 
2029
        } else if (lock_rec_other_has_conflicting(mode, block, heap_no, trx)) {
 
2030
 
 
2031
                /* If another transaction has a non-gap conflicting request in
 
2032
                the queue, as this transaction does not have a lock strong
 
2033
                enough already granted on the record, we have to wait. */
 
2034
 
 
2035
                err = lock_rec_enqueue_waiting(mode, block, heap_no,
 
2036
                                               index, thr);
 
2037
        } else {
 
2038
                if (!impl) {
 
2039
                        /* Set the requested lock on the record */
 
2040
 
 
2041
                        lock_rec_add_to_queue(LOCK_REC | mode, block,
 
2042
                                              heap_no, index, trx);
 
2043
                }
 
2044
 
 
2045
                err = DB_SUCCESS;
 
2046
        }
 
2047
 
 
2048
        return(err);
 
2049
}
 
2050
 
 
2051
/*********************************************************************//**
 
2052
Tries to lock the specified record in the mode requested. If not immediately
 
2053
possible, enqueues a waiting lock request. This is a low-level function
 
2054
which does NOT look at implicit locks! Checks lock compatibility within
 
2055
explicit locks. This function sets a normal next-key lock, or in the case
 
2056
of a page supremum record, a gap type lock.
 
2057
@return DB_SUCCESS, DB_LOCK_WAIT, or error code */
 
2058
static
 
2059
ulint
 
2060
lock_rec_lock(
 
2061
/*==========*/
 
2062
        ibool                   impl,   /*!< in: if TRUE, no lock is set
 
2063
                                        if no wait is necessary: we
 
2064
                                        assume that the caller will
 
2065
                                        set an implicit lock */
 
2066
        ulint                   mode,   /*!< in: lock mode: LOCK_X or
 
2067
                                        LOCK_S possibly ORed to either
 
2068
                                        LOCK_GAP or LOCK_REC_NOT_GAP */
 
2069
        const buf_block_t*      block,  /*!< in: buffer block containing
 
2070
                                        the record */
 
2071
        ulint                   heap_no,/*!< in: heap number of record */
 
2072
        dict_index_t*           index,  /*!< in: index of record */
 
2073
        que_thr_t*              thr)    /*!< in: query thread */
 
2074
{
 
2075
        ulint   err;
 
2076
 
 
2077
        ut_ad(mutex_own(&kernel_mutex));
 
2078
        ut_ad((LOCK_MODE_MASK & mode) != LOCK_S
 
2079
              || lock_table_has(thr_get_trx(thr), index->table, LOCK_IS));
 
2080
        ut_ad((LOCK_MODE_MASK & mode) != LOCK_X
 
2081
              || lock_table_has(thr_get_trx(thr), index->table, LOCK_IX));
 
2082
        ut_ad((LOCK_MODE_MASK & mode) == LOCK_S
 
2083
              || (LOCK_MODE_MASK & mode) == LOCK_X);
 
2084
        ut_ad(mode - (LOCK_MODE_MASK & mode) == LOCK_GAP
 
2085
              || mode - (LOCK_MODE_MASK & mode) == LOCK_REC_NOT_GAP
 
2086
              || mode - (LOCK_MODE_MASK & mode) == 0);
 
2087
 
 
2088
        if (lock_rec_lock_fast(impl, mode, block, heap_no, index, thr)) {
 
2089
 
 
2090
                /* We try a simplified and faster subroutine for the most
 
2091
                common cases */
 
2092
 
 
2093
                err = DB_SUCCESS;
 
2094
        } else {
 
2095
                err = lock_rec_lock_slow(impl, mode, block,
 
2096
                                         heap_no, index, thr);
 
2097
        }
 
2098
 
 
2099
        return(err);
 
2100
}
 
2101
 
 
2102
/*********************************************************************//**
 
2103
Checks if a waiting record lock request still has to wait in a queue.
 
2104
@return TRUE if still has to wait */
 
2105
static
 
2106
ibool
 
2107
lock_rec_has_to_wait_in_queue(
 
2108
/*==========================*/
 
2109
        lock_t* wait_lock)      /*!< in: waiting record lock */
 
2110
{
 
2111
        lock_t* lock;
 
2112
        ulint   space;
 
2113
        ulint   page_no;
 
2114
        ulint   heap_no;
 
2115
 
 
2116
        ut_ad(mutex_own(&kernel_mutex));
 
2117
        ut_ad(lock_get_wait(wait_lock));
 
2118
        ut_ad(lock_get_type_low(wait_lock) == LOCK_REC);
 
2119
 
 
2120
        space = wait_lock->un_member.rec_lock.space;
 
2121
        page_no = wait_lock->un_member.rec_lock.page_no;
 
2122
        heap_no = lock_rec_find_set_bit(wait_lock);
 
2123
 
 
2124
        lock = lock_rec_get_first_on_page_addr(space, page_no);
 
2125
 
 
2126
        while (lock != wait_lock) {
 
2127
 
 
2128
                if (lock_rec_get_nth_bit(lock, heap_no)
 
2129
                    && lock_has_to_wait(wait_lock, lock)) {
 
2130
 
 
2131
                        return(TRUE);
 
2132
                }
 
2133
 
 
2134
                lock = lock_rec_get_next_on_page(lock);
 
2135
        }
 
2136
 
 
2137
        return(FALSE);
 
2138
}
 
2139
 
 
2140
/*************************************************************//**
 
2141
Grants a lock to a waiting lock request and releases the waiting
 
2142
transaction. */
 
2143
static
 
2144
void
 
2145
lock_grant(
 
2146
/*=======*/
 
2147
        lock_t* lock)   /*!< in/out: waiting lock request */
 
2148
{
 
2149
        ut_ad(mutex_own(&kernel_mutex));
 
2150
 
 
2151
        lock_reset_lock_and_trx_wait(lock);
 
2152
 
 
2153
        if (lock_get_mode(lock) == LOCK_AUTO_INC) {
 
2154
                trx_t*          trx = lock->trx;
 
2155
                dict_table_t*   table = lock->un_member.tab_lock.table;
 
2156
 
 
2157
                if (table->autoinc_trx == trx) {
 
2158
                        fprintf(stderr,
 
2159
                                "InnoDB: Error: trx already had"
 
2160
                                " an AUTO-INC lock!\n");
 
2161
                } else {
 
2162
                        table->autoinc_trx = trx;
 
2163
 
 
2164
                        ib_vector_push(trx->autoinc_locks, lock);
 
2165
                }
 
2166
        }
 
2167
 
 
2168
#ifdef UNIV_DEBUG
 
2169
        if (lock_print_waits) {
 
2170
                fprintf(stderr, "Lock wait for trx %lu ends\n",
 
2171
                        (ulong) ut_dulint_get_low(lock->trx->id));
 
2172
        }
 
2173
#endif /* UNIV_DEBUG */
 
2174
 
 
2175
        /* If we are resolving a deadlock by choosing another transaction
 
2176
        as a victim, then our original transaction may not be in the
 
2177
        TRX_QUE_LOCK_WAIT state, and there is no need to end the lock wait
 
2178
        for it */
 
2179
 
 
2180
        if (lock->trx->que_state == TRX_QUE_LOCK_WAIT) {
 
2181
                trx_end_lock_wait(lock->trx);
 
2182
        }
 
2183
}
 
2184
 
 
2185
/*************************************************************//**
 
2186
Cancels a waiting record lock request and releases the waiting transaction
 
2187
that requested it. NOTE: does NOT check if waiting lock requests behind this
 
2188
one can now be granted! */
 
2189
static
 
2190
void
 
2191
lock_rec_cancel(
 
2192
/*============*/
 
2193
        lock_t* lock)   /*!< in: waiting record lock request */
 
2194
{
 
2195
        ut_ad(mutex_own(&kernel_mutex));
 
2196
        ut_ad(lock_get_type_low(lock) == LOCK_REC);
 
2197
 
 
2198
        /* Reset the bit (there can be only one set bit) in the lock bitmap */
 
2199
        lock_rec_reset_nth_bit(lock, lock_rec_find_set_bit(lock));
 
2200
 
 
2201
        /* Reset the wait flag and the back pointer to lock in trx */
 
2202
 
 
2203
        lock_reset_lock_and_trx_wait(lock);
 
2204
 
 
2205
        /* The following function releases the trx from lock wait */
 
2206
 
 
2207
        trx_end_lock_wait(lock->trx);
 
2208
}
 
2209
 
 
2210
/*************************************************************//**
 
2211
Removes a record lock request, waiting or granted, from the queue and
 
2212
grants locks to other transactions in the queue if they now are entitled
 
2213
to a lock. NOTE: all record locks contained in in_lock are removed. */
 
2214
static
 
2215
void
 
2216
lock_rec_dequeue_from_page(
 
2217
/*=======================*/
 
2218
        lock_t* in_lock)/*!< in: record lock object: all record locks which
 
2219
                        are contained in this lock object are removed;
 
2220
                        transactions waiting behind will get their lock
 
2221
                        requests granted, if they are now qualified to it */
 
2222
{
 
2223
        ulint   space;
 
2224
        ulint   page_no;
 
2225
        lock_t* lock;
 
2226
        trx_t*  trx;
 
2227
 
 
2228
        ut_ad(mutex_own(&kernel_mutex));
 
2229
        ut_ad(lock_get_type_low(in_lock) == LOCK_REC);
 
2230
 
 
2231
        trx = in_lock->trx;
 
2232
 
 
2233
        space = in_lock->un_member.rec_lock.space;
 
2234
        page_no = in_lock->un_member.rec_lock.page_no;
 
2235
 
 
2236
        HASH_DELETE(lock_t, hash, lock_sys->rec_hash,
 
2237
                    lock_rec_fold(space, page_no), in_lock);
 
2238
 
 
2239
        UT_LIST_REMOVE(trx_locks, trx->trx_locks, in_lock);
 
2240
 
 
2241
        /* Check if waiting locks in the queue can now be granted: grant
 
2242
        locks if there are no conflicting locks ahead. */
 
2243
 
 
2244
        lock = lock_rec_get_first_on_page_addr(space, page_no);
 
2245
 
 
2246
        while (lock != NULL) {
 
2247
                if (lock_get_wait(lock)
 
2248
                    && !lock_rec_has_to_wait_in_queue(lock)) {
 
2249
 
 
2250
                        /* Grant the lock */
 
2251
                        lock_grant(lock);
 
2252
                }
 
2253
 
 
2254
                lock = lock_rec_get_next_on_page(lock);
 
2255
        }
 
2256
}
 
2257
 
 
2258
/*************************************************************//**
 
2259
Removes a record lock request, waiting or granted, from the queue. */
 
2260
static
 
2261
void
 
2262
lock_rec_discard(
 
2263
/*=============*/
 
2264
        lock_t* in_lock)/*!< in: record lock object: all record locks which
 
2265
                        are contained in this lock object are removed */
 
2266
{
 
2267
        ulint   space;
 
2268
        ulint   page_no;
 
2269
        trx_t*  trx;
 
2270
 
 
2271
        ut_ad(mutex_own(&kernel_mutex));
 
2272
        ut_ad(lock_get_type_low(in_lock) == LOCK_REC);
 
2273
 
 
2274
        trx = in_lock->trx;
 
2275
 
 
2276
        space = in_lock->un_member.rec_lock.space;
 
2277
        page_no = in_lock->un_member.rec_lock.page_no;
 
2278
 
 
2279
        HASH_DELETE(lock_t, hash, lock_sys->rec_hash,
 
2280
                    lock_rec_fold(space, page_no), in_lock);
 
2281
 
 
2282
        UT_LIST_REMOVE(trx_locks, trx->trx_locks, in_lock);
 
2283
}
 
2284
 
 
2285
/*************************************************************//**
 
2286
Removes record lock objects set on an index page which is discarded. This
 
2287
function does not move locks, or check for waiting locks, therefore the
 
2288
lock bitmaps must already be reset when this function is called. */
 
2289
static
 
2290
void
 
2291
lock_rec_free_all_from_discard_page(
 
2292
/*================================*/
 
2293
        const buf_block_t*      block)  /*!< in: page to be discarded */
 
2294
{
 
2295
        ulint   space;
 
2296
        ulint   page_no;
 
2297
        lock_t* lock;
 
2298
        lock_t* next_lock;
 
2299
 
 
2300
        ut_ad(mutex_own(&kernel_mutex));
 
2301
 
 
2302
        space = buf_block_get_space(block);
 
2303
        page_no = buf_block_get_page_no(block);
 
2304
 
 
2305
        lock = lock_rec_get_first_on_page_addr(space, page_no);
 
2306
 
 
2307
        while (lock != NULL) {
 
2308
                ut_ad(lock_rec_find_set_bit(lock) == ULINT_UNDEFINED);
 
2309
                ut_ad(!lock_get_wait(lock));
 
2310
 
 
2311
                next_lock = lock_rec_get_next_on_page(lock);
 
2312
 
 
2313
                lock_rec_discard(lock);
 
2314
 
 
2315
                lock = next_lock;
 
2316
        }
 
2317
}
 
2318
 
 
2319
/*============= RECORD LOCK MOVING AND INHERITING ===================*/
 
2320
 
 
2321
/*************************************************************//**
 
2322
Resets the lock bits for a single record. Releases transactions waiting for
 
2323
lock requests here. */
 
2324
static
 
2325
void
 
2326
lock_rec_reset_and_release_wait(
 
2327
/*============================*/
 
2328
        const buf_block_t*      block,  /*!< in: buffer block containing
 
2329
                                        the record */
 
2330
        ulint                   heap_no)/*!< in: heap number of record */
 
2331
{
 
2332
        lock_t* lock;
 
2333
 
 
2334
        ut_ad(mutex_own(&kernel_mutex));
 
2335
 
 
2336
        lock = lock_rec_get_first(block, heap_no);
 
2337
 
 
2338
        while (lock != NULL) {
 
2339
                if (lock_get_wait(lock)) {
 
2340
                        lock_rec_cancel(lock);
 
2341
                } else {
 
2342
                        lock_rec_reset_nth_bit(lock, heap_no);
 
2343
                }
 
2344
 
 
2345
                lock = lock_rec_get_next(heap_no, lock);
 
2346
        }
 
2347
}
 
2348
 
 
2349
/*************************************************************//**
 
2350
Makes a record to inherit the locks (except LOCK_INSERT_INTENTION type)
 
2351
of another record as gap type locks, but does not reset the lock bits of
 
2352
the other record. Also waiting lock requests on rec are inherited as
 
2353
GRANTED gap locks. */
 
2354
static
 
2355
void
 
2356
lock_rec_inherit_to_gap(
 
2357
/*====================*/
 
2358
        const buf_block_t*      heir_block,     /*!< in: block containing the
 
2359
                                                record which inherits */
 
2360
        const buf_block_t*      block,          /*!< in: block containing the
 
2361
                                                record from which inherited;
 
2362
                                                does NOT reset the locks on
 
2363
                                                this record */
 
2364
        ulint                   heir_heap_no,   /*!< in: heap_no of the
 
2365
                                                inheriting record */
 
2366
        ulint                   heap_no)        /*!< in: heap_no of the
 
2367
                                                donating record */
 
2368
{
 
2369
        lock_t* lock;
 
2370
 
 
2371
        ut_ad(mutex_own(&kernel_mutex));
 
2372
 
 
2373
        lock = lock_rec_get_first(block, heap_no);
 
2374
 
 
2375
        /* If srv_locks_unsafe_for_binlog is TRUE or session is using
 
2376
        READ COMMITTED isolation level, we do not want locks set
 
2377
        by an UPDATE or a DELETE to be inherited as gap type locks. But we
 
2378
        DO want S-locks set by a consistency constraint to be inherited also
 
2379
        then. */
 
2380
 
 
2381
        while (lock != NULL) {
 
2382
                if (!lock_rec_get_insert_intention(lock)
 
2383
                    && !((srv_locks_unsafe_for_binlog
 
2384
                          || lock->trx->isolation_level
 
2385
                          == TRX_ISO_READ_COMMITTED)
 
2386
                         && lock_get_mode(lock) == LOCK_X)) {
 
2387
 
 
2388
                        lock_rec_add_to_queue(LOCK_REC | LOCK_GAP
 
2389
                                              | lock_get_mode(lock),
 
2390
                                              heir_block, heir_heap_no,
 
2391
                                              lock->index, lock->trx);
 
2392
                }
 
2393
 
 
2394
                lock = lock_rec_get_next(heap_no, lock);
 
2395
        }
 
2396
}
 
2397
 
 
2398
/*************************************************************//**
 
2399
Makes a record to inherit the gap locks (except LOCK_INSERT_INTENTION type)
 
2400
of another record as gap type locks, but does not reset the lock bits of the
 
2401
other record. Also waiting lock requests are inherited as GRANTED gap locks. */
 
2402
static
 
2403
void
 
2404
lock_rec_inherit_to_gap_if_gap_lock(
 
2405
/*================================*/
 
2406
        const buf_block_t*      block,          /*!< in: buffer block */
 
2407
        ulint                   heir_heap_no,   /*!< in: heap_no of
 
2408
                                                record which inherits */
 
2409
        ulint                   heap_no)        /*!< in: heap_no of record
 
2410
                                                from which inherited;
 
2411
                                                does NOT reset the locks
 
2412
                                                on this record */
 
2413
{
 
2414
        lock_t* lock;
 
2415
 
 
2416
        ut_ad(mutex_own(&kernel_mutex));
 
2417
 
 
2418
        lock = lock_rec_get_first(block, heap_no);
 
2419
 
 
2420
        while (lock != NULL) {
 
2421
                if (!lock_rec_get_insert_intention(lock)
 
2422
                    && (heap_no == PAGE_HEAP_NO_SUPREMUM
 
2423
                        || !lock_rec_get_rec_not_gap(lock))) {
 
2424
 
 
2425
                        lock_rec_add_to_queue(LOCK_REC | LOCK_GAP
 
2426
                                              | lock_get_mode(lock),
 
2427
                                              block, heir_heap_no,
 
2428
                                              lock->index, lock->trx);
 
2429
                }
 
2430
 
 
2431
                lock = lock_rec_get_next(heap_no, lock);
 
2432
        }
 
2433
}
 
2434
 
 
2435
/*************************************************************//**
 
2436
Moves the locks of a record to another record and resets the lock bits of
 
2437
the donating record. */
 
2438
static
 
2439
void
 
2440
lock_rec_move(
 
2441
/*==========*/
 
2442
        const buf_block_t*      receiver,       /*!< in: buffer block containing
 
2443
                                                the receiving record */
 
2444
        const buf_block_t*      donator,        /*!< in: buffer block containing
 
2445
                                                the donating record */
 
2446
        ulint                   receiver_heap_no,/*!< in: heap_no of the record
 
2447
                                                which gets the locks; there
 
2448
                                                must be no lock requests
 
2449
                                                on it! */
 
2450
        ulint                   donator_heap_no)/*!< in: heap_no of the record
 
2451
                                                which gives the locks */
 
2452
{
 
2453
        lock_t* lock;
 
2454
 
 
2455
        ut_ad(mutex_own(&kernel_mutex));
 
2456
 
 
2457
        lock = lock_rec_get_first(donator, donator_heap_no);
 
2458
 
 
2459
        ut_ad(lock_rec_get_first(receiver, receiver_heap_no) == NULL);
 
2460
 
 
2461
        while (lock != NULL) {
 
2462
                const ulint     type_mode = lock->type_mode;
 
2463
 
 
2464
                lock_rec_reset_nth_bit(lock, donator_heap_no);
 
2465
 
 
2466
                if (UNIV_UNLIKELY(type_mode & LOCK_WAIT)) {
 
2467
                        lock_reset_lock_and_trx_wait(lock);
 
2468
                }
 
2469
 
 
2470
                /* Note that we FIRST reset the bit, and then set the lock:
 
2471
                the function works also if donator == receiver */
 
2472
 
 
2473
                lock_rec_add_to_queue(type_mode, receiver, receiver_heap_no,
 
2474
                                      lock->index, lock->trx);
 
2475
                lock = lock_rec_get_next(donator_heap_no, lock);
 
2476
        }
 
2477
 
 
2478
        ut_ad(lock_rec_get_first(donator, donator_heap_no) == NULL);
 
2479
}
 
2480
 
 
2481
/*************************************************************//**
 
2482
Updates the lock table when we have reorganized a page. NOTE: we copy
 
2483
also the locks set on the infimum of the page; the infimum may carry
 
2484
locks if an update of a record is occurring on the page, and its locks
 
2485
were temporarily stored on the infimum. */
 
2486
UNIV_INTERN
 
2487
void
 
2488
lock_move_reorganize_page(
 
2489
/*======================*/
 
2490
        const buf_block_t*      block,  /*!< in: old index page, now
 
2491
                                        reorganized */
 
2492
        const buf_block_t*      oblock) /*!< in: copy of the old, not
 
2493
                                        reorganized page */
 
2494
{
 
2495
        lock_t*         lock;
 
2496
        UT_LIST_BASE_NODE_T(lock_t)     old_locks;
 
2497
        mem_heap_t*     heap            = NULL;
 
2498
        ulint           comp;
 
2499
 
 
2500
        lock_mutex_enter_kernel();
 
2501
 
 
2502
        lock = lock_rec_get_first_on_page(block);
 
2503
 
 
2504
        if (lock == NULL) {
 
2505
                lock_mutex_exit_kernel();
 
2506
 
 
2507
                return;
 
2508
        }
 
2509
 
 
2510
        heap = mem_heap_create(256);
 
2511
 
 
2512
        /* Copy first all the locks on the page to heap and reset the
 
2513
        bitmaps in the original locks; chain the copies of the locks
 
2514
        using the trx_locks field in them. */
 
2515
 
 
2516
        UT_LIST_INIT(old_locks);
 
2517
 
 
2518
        do {
 
2519
                /* Make a copy of the lock */
 
2520
                lock_t* old_lock = lock_rec_copy(lock, heap);
 
2521
 
 
2522
                UT_LIST_ADD_LAST(trx_locks, old_locks, old_lock);
 
2523
 
 
2524
                /* Reset bitmap of lock */
 
2525
                lock_rec_bitmap_reset(lock);
 
2526
 
 
2527
                if (lock_get_wait(lock)) {
 
2528
                        lock_reset_lock_and_trx_wait(lock);
 
2529
                }
 
2530
 
 
2531
                lock = lock_rec_get_next_on_page(lock);
 
2532
        } while (lock != NULL);
 
2533
 
 
2534
        comp = page_is_comp(block->frame);
 
2535
        ut_ad(comp == page_is_comp(oblock->frame));
 
2536
 
 
2537
        for (lock = UT_LIST_GET_FIRST(old_locks); lock;
 
2538
             lock = UT_LIST_GET_NEXT(trx_locks, lock)) {
 
2539
                /* NOTE: we copy also the locks set on the infimum and
 
2540
                supremum of the page; the infimum may carry locks if an
 
2541
                update of a record is occurring on the page, and its locks
 
2542
                were temporarily stored on the infimum */
 
2543
                page_cur_t      cur1;
 
2544
                page_cur_t      cur2;
 
2545
 
 
2546
                page_cur_set_before_first(block, &cur1);
 
2547
                page_cur_set_before_first(oblock, &cur2);
 
2548
 
 
2549
                /* Set locks according to old locks */
 
2550
                for (;;) {
 
2551
                        ulint   old_heap_no;
 
2552
                        ulint   new_heap_no;
 
2553
 
 
2554
                        ut_ad(comp || !memcmp(page_cur_get_rec(&cur1),
 
2555
                                              page_cur_get_rec(&cur2),
 
2556
                                              rec_get_data_size_old(
 
2557
                                                      page_cur_get_rec(
 
2558
                                                              &cur2))));
 
2559
                        if (UNIV_LIKELY(comp)) {
 
2560
                                old_heap_no = rec_get_heap_no_new(
 
2561
                                        page_cur_get_rec(&cur2));
 
2562
                                new_heap_no = rec_get_heap_no_new(
 
2563
                                        page_cur_get_rec(&cur1));
 
2564
                        } else {
 
2565
                                old_heap_no = rec_get_heap_no_old(
 
2566
                                        page_cur_get_rec(&cur2));
 
2567
                                new_heap_no = rec_get_heap_no_old(
 
2568
                                        page_cur_get_rec(&cur1));
 
2569
                        }
 
2570
 
 
2571
                        if (lock_rec_get_nth_bit(lock, old_heap_no)) {
 
2572
 
 
2573
                                /* Clear the bit in old_lock. */
 
2574
                                ut_d(lock_rec_reset_nth_bit(lock,
 
2575
                                                            old_heap_no));
 
2576
 
 
2577
                                /* NOTE that the old lock bitmap could be too
 
2578
                                small for the new heap number! */
 
2579
 
 
2580
                                lock_rec_add_to_queue(lock->type_mode, block,
 
2581
                                                      new_heap_no,
 
2582
                                                      lock->index, lock->trx);
 
2583
 
 
2584
                                /* if (new_heap_no == PAGE_HEAP_NO_SUPREMUM
 
2585
                                && lock_get_wait(lock)) {
 
2586
                                fprintf(stderr,
 
2587
                                "---\n--\n!!!Lock reorg: supr type %lu\n",
 
2588
                                lock->type_mode);
 
2589
                                } */
 
2590
                        }
 
2591
 
 
2592
                        if (UNIV_UNLIKELY
 
2593
                            (new_heap_no == PAGE_HEAP_NO_SUPREMUM)) {
 
2594
 
 
2595
                                ut_ad(old_heap_no == PAGE_HEAP_NO_SUPREMUM);
 
2596
                                break;
 
2597
                        }
 
2598
 
 
2599
                        page_cur_move_to_next(&cur1);
 
2600
                        page_cur_move_to_next(&cur2);
 
2601
                }
 
2602
 
 
2603
#ifdef UNIV_DEBUG
 
2604
                {
 
2605
                        ulint   i = lock_rec_find_set_bit(lock);
 
2606
 
 
2607
                        /* Check that all locks were moved. */
 
2608
                        if (UNIV_UNLIKELY(i != ULINT_UNDEFINED)) {
 
2609
                                fprintf(stderr,
 
2610
                                        "lock_move_reorganize_page():"
 
2611
                                        " %lu not moved in %p\n",
 
2612
                                        (ulong) i, (void*) lock);
 
2613
                                ut_error;
 
2614
                        }
 
2615
                }
 
2616
#endif /* UNIV_DEBUG */
 
2617
        }
 
2618
 
 
2619
        lock_mutex_exit_kernel();
 
2620
 
 
2621
        mem_heap_free(heap);
 
2622
 
 
2623
#ifdef UNIV_DEBUG_LOCK_VALIDATE
 
2624
        ut_ad(lock_rec_validate_page(buf_block_get_space(block),
 
2625
                                     buf_block_get_page_no(block)));
 
2626
#endif
 
2627
}
 
2628
 
 
2629
/*************************************************************//**
 
2630
Moves the explicit locks on user records to another page if a record
 
2631
list end is moved to another page. */
 
2632
UNIV_INTERN
 
2633
void
 
2634
lock_move_rec_list_end(
 
2635
/*===================*/
 
2636
        const buf_block_t*      new_block,      /*!< in: index page to move to */
 
2637
        const buf_block_t*      block,          /*!< in: index page */
 
2638
        const rec_t*            rec)            /*!< in: record on page: this
 
2639
                                                is the first record moved */
 
2640
{
 
2641
        lock_t*         lock;
 
2642
        const ulint     comp    = page_rec_is_comp(rec);
 
2643
 
 
2644
        lock_mutex_enter_kernel();
 
2645
 
 
2646
        /* Note: when we move locks from record to record, waiting locks
 
2647
        and possible granted gap type locks behind them are enqueued in
 
2648
        the original order, because new elements are inserted to a hash
 
2649
        table to the end of the hash chain, and lock_rec_add_to_queue
 
2650
        does not reuse locks if there are waiters in the queue. */
 
2651
 
 
2652
        for (lock = lock_rec_get_first_on_page(block); lock;
 
2653
             lock = lock_rec_get_next_on_page(lock)) {
 
2654
                page_cur_t      cur1;
 
2655
                page_cur_t      cur2;
 
2656
                const ulint     type_mode = lock->type_mode;
 
2657
 
 
2658
                page_cur_position(rec, block, &cur1);
 
2659
 
 
2660
                if (page_cur_is_before_first(&cur1)) {
 
2661
                        page_cur_move_to_next(&cur1);
 
2662
                }
 
2663
 
 
2664
                page_cur_set_before_first(new_block, &cur2);
 
2665
                page_cur_move_to_next(&cur2);
 
2666
 
 
2667
                /* Copy lock requests on user records to new page and
 
2668
                reset the lock bits on the old */
 
2669
 
 
2670
                while (!page_cur_is_after_last(&cur1)) {
 
2671
                        ulint   heap_no;
 
2672
 
 
2673
                        if (comp) {
 
2674
                                heap_no = rec_get_heap_no_new(
 
2675
                                        page_cur_get_rec(&cur1));
 
2676
                        } else {
 
2677
                                heap_no = rec_get_heap_no_old(
 
2678
                                        page_cur_get_rec(&cur1));
 
2679
                                ut_ad(!memcmp(page_cur_get_rec(&cur1),
 
2680
                                         page_cur_get_rec(&cur2),
 
2681
                                         rec_get_data_size_old(
 
2682
                                                 page_cur_get_rec(&cur2))));
 
2683
                        }
 
2684
 
 
2685
                        if (lock_rec_get_nth_bit(lock, heap_no)) {
 
2686
                                lock_rec_reset_nth_bit(lock, heap_no);
 
2687
 
 
2688
                                if (UNIV_UNLIKELY(type_mode & LOCK_WAIT)) {
 
2689
                                        lock_reset_lock_and_trx_wait(lock);
 
2690
                                }
 
2691
 
 
2692
                                if (comp) {
 
2693
                                        heap_no = rec_get_heap_no_new(
 
2694
                                                page_cur_get_rec(&cur2));
 
2695
                                } else {
 
2696
                                        heap_no = rec_get_heap_no_old(
 
2697
                                                page_cur_get_rec(&cur2));
 
2698
                                }
 
2699
 
 
2700
                                lock_rec_add_to_queue(type_mode,
 
2701
                                                      new_block, heap_no,
 
2702
                                                      lock->index, lock->trx);
 
2703
                        }
 
2704
 
 
2705
                        page_cur_move_to_next(&cur1);
 
2706
                        page_cur_move_to_next(&cur2);
 
2707
                }
 
2708
        }
 
2709
 
 
2710
        lock_mutex_exit_kernel();
 
2711
 
 
2712
#ifdef UNIV_DEBUG_LOCK_VALIDATE
 
2713
        ut_ad(lock_rec_validate_page(buf_block_get_space(block),
 
2714
                                     buf_block_get_page_no(block)));
 
2715
        ut_ad(lock_rec_validate_page(buf_block_get_space(new_block),
 
2716
                                     buf_block_get_page_no(new_block)));
 
2717
#endif
 
2718
}
 
2719
 
 
2720
/*************************************************************//**
 
2721
Moves the explicit locks on user records to another page if a record
 
2722
list start is moved to another page. */
 
2723
UNIV_INTERN
 
2724
void
 
2725
lock_move_rec_list_start(
 
2726
/*=====================*/
 
2727
        const buf_block_t*      new_block,      /*!< in: index page to move to */
 
2728
        const buf_block_t*      block,          /*!< in: index page */
 
2729
        const rec_t*            rec,            /*!< in: record on page:
 
2730
                                                this is the first
 
2731
                                                record NOT copied */
 
2732
        const rec_t*            old_end)        /*!< in: old
 
2733
                                                previous-to-last
 
2734
                                                record on new_page
 
2735
                                                before the records
 
2736
                                                were copied */
 
2737
{
 
2738
        lock_t*         lock;
 
2739
        const ulint     comp    = page_rec_is_comp(rec);
 
2740
 
 
2741
        ut_ad(block->frame == page_align(rec));
 
2742
        ut_ad(new_block->frame == page_align(old_end));
 
2743
 
 
2744
        lock_mutex_enter_kernel();
 
2745
 
 
2746
        for (lock = lock_rec_get_first_on_page(block); lock;
 
2747
             lock = lock_rec_get_next_on_page(lock)) {
 
2748
                page_cur_t      cur1;
 
2749
                page_cur_t      cur2;
 
2750
                const ulint     type_mode = lock->type_mode;
 
2751
 
 
2752
                page_cur_set_before_first(block, &cur1);
 
2753
                page_cur_move_to_next(&cur1);
 
2754
 
 
2755
                page_cur_position(old_end, new_block, &cur2);
 
2756
                page_cur_move_to_next(&cur2);
 
2757
 
 
2758
                /* Copy lock requests on user records to new page and
 
2759
                reset the lock bits on the old */
 
2760
 
 
2761
                while (page_cur_get_rec(&cur1) != rec) {
 
2762
                        ulint   heap_no;
 
2763
 
 
2764
                        if (comp) {
 
2765
                                heap_no = rec_get_heap_no_new(
 
2766
                                        page_cur_get_rec(&cur1));
 
2767
                        } else {
 
2768
                                heap_no = rec_get_heap_no_old(
 
2769
                                        page_cur_get_rec(&cur1));
 
2770
                                ut_ad(!memcmp(page_cur_get_rec(&cur1),
 
2771
                                              page_cur_get_rec(&cur2),
 
2772
                                              rec_get_data_size_old(
 
2773
                                                      page_cur_get_rec(
 
2774
                                                              &cur2))));
 
2775
                        }
 
2776
 
 
2777
                        if (lock_rec_get_nth_bit(lock, heap_no)) {
 
2778
                                lock_rec_reset_nth_bit(lock, heap_no);
 
2779
 
 
2780
                                if (UNIV_UNLIKELY(type_mode & LOCK_WAIT)) {
 
2781
                                        lock_reset_lock_and_trx_wait(lock);
 
2782
                                }
 
2783
 
 
2784
                                if (comp) {
 
2785
                                        heap_no = rec_get_heap_no_new(
 
2786
                                                page_cur_get_rec(&cur2));
 
2787
                                } else {
 
2788
                                        heap_no = rec_get_heap_no_old(
 
2789
                                                page_cur_get_rec(&cur2));
 
2790
                                }
 
2791
 
 
2792
                                lock_rec_add_to_queue(type_mode,
 
2793
                                                      new_block, heap_no,
 
2794
                                                      lock->index, lock->trx);
 
2795
                        }
 
2796
 
 
2797
                        page_cur_move_to_next(&cur1);
 
2798
                        page_cur_move_to_next(&cur2);
 
2799
                }
 
2800
 
 
2801
#ifdef UNIV_DEBUG
 
2802
                if (page_rec_is_supremum(rec)) {
 
2803
                        ulint   i;
 
2804
 
 
2805
                        for (i = PAGE_HEAP_NO_USER_LOW;
 
2806
                             i < lock_rec_get_n_bits(lock); i++) {
 
2807
                                if (UNIV_UNLIKELY
 
2808
                                    (lock_rec_get_nth_bit(lock, i))) {
 
2809
 
 
2810
                                        fprintf(stderr,
 
2811
                                                "lock_move_rec_list_start():"
 
2812
                                                " %lu not moved in %p\n",
 
2813
                                                (ulong) i, (void*) lock);
 
2814
                                        ut_error;
 
2815
                                }
 
2816
                        }
 
2817
                }
 
2818
#endif /* UNIV_DEBUG */
 
2819
        }
 
2820
 
 
2821
        lock_mutex_exit_kernel();
 
2822
 
 
2823
#ifdef UNIV_DEBUG_LOCK_VALIDATE
 
2824
        ut_ad(lock_rec_validate_page(buf_block_get_space(block),
 
2825
                                     buf_block_get_page_no(block)));
 
2826
#endif
 
2827
}
 
2828
 
 
2829
/*************************************************************//**
 
2830
Updates the lock table when a page is split to the right. */
 
2831
UNIV_INTERN
 
2832
void
 
2833
lock_update_split_right(
 
2834
/*====================*/
 
2835
        const buf_block_t*      right_block,    /*!< in: right page */
 
2836
        const buf_block_t*      left_block)     /*!< in: left page */
 
2837
{
 
2838
        ulint   heap_no = lock_get_min_heap_no(right_block);
 
2839
 
 
2840
        lock_mutex_enter_kernel();
 
2841
 
 
2842
        /* Move the locks on the supremum of the left page to the supremum
 
2843
        of the right page */
 
2844
 
 
2845
        lock_rec_move(right_block, left_block,
 
2846
                      PAGE_HEAP_NO_SUPREMUM, PAGE_HEAP_NO_SUPREMUM);
 
2847
 
 
2848
        /* Inherit the locks to the supremum of left page from the successor
 
2849
        of the infimum on right page */
 
2850
 
 
2851
        lock_rec_inherit_to_gap(left_block, right_block,
 
2852
                                PAGE_HEAP_NO_SUPREMUM, heap_no);
 
2853
 
 
2854
        lock_mutex_exit_kernel();
 
2855
}
 
2856
 
 
2857
/*************************************************************//**
 
2858
Updates the lock table when a page is merged to the right. */
 
2859
UNIV_INTERN
 
2860
void
 
2861
lock_update_merge_right(
 
2862
/*====================*/
 
2863
        const buf_block_t*      right_block,    /*!< in: right page to
 
2864
                                                which merged */
 
2865
        const rec_t*            orig_succ,      /*!< in: original
 
2866
                                                successor of infimum
 
2867
                                                on the right page
 
2868
                                                before merge */
 
2869
        const buf_block_t*      left_block)     /*!< in: merged index
 
2870
                                                page which will be
 
2871
                                                discarded */
 
2872
{
 
2873
        lock_mutex_enter_kernel();
 
2874
 
 
2875
        /* Inherit the locks from the supremum of the left page to the
 
2876
        original successor of infimum on the right page, to which the left
 
2877
        page was merged */
 
2878
 
 
2879
        lock_rec_inherit_to_gap(right_block, left_block,
 
2880
                                page_rec_get_heap_no(orig_succ),
 
2881
                                PAGE_HEAP_NO_SUPREMUM);
 
2882
 
 
2883
        /* Reset the locks on the supremum of the left page, releasing
 
2884
        waiting transactions */
 
2885
 
 
2886
        lock_rec_reset_and_release_wait(left_block,
 
2887
                                        PAGE_HEAP_NO_SUPREMUM);
 
2888
 
 
2889
        lock_rec_free_all_from_discard_page(left_block);
 
2890
 
 
2891
        lock_mutex_exit_kernel();
 
2892
}
 
2893
 
 
2894
/*************************************************************//**
 
2895
Updates the lock table when the root page is copied to another in
 
2896
btr_root_raise_and_insert. Note that we leave lock structs on the
 
2897
root page, even though they do not make sense on other than leaf
 
2898
pages: the reason is that in a pessimistic update the infimum record
 
2899
of the root page will act as a dummy carrier of the locks of the record
 
2900
to be updated. */
 
2901
UNIV_INTERN
 
2902
void
 
2903
lock_update_root_raise(
 
2904
/*===================*/
 
2905
        const buf_block_t*      block,  /*!< in: index page to which copied */
 
2906
        const buf_block_t*      root)   /*!< in: root page */
 
2907
{
 
2908
        lock_mutex_enter_kernel();
 
2909
 
 
2910
        /* Move the locks on the supremum of the root to the supremum
 
2911
        of block */
 
2912
 
 
2913
        lock_rec_move(block, root,
 
2914
                      PAGE_HEAP_NO_SUPREMUM, PAGE_HEAP_NO_SUPREMUM);
 
2915
        lock_mutex_exit_kernel();
 
2916
}
 
2917
 
 
2918
/*************************************************************//**
 
2919
Updates the lock table when a page is copied to another and the original page
 
2920
is removed from the chain of leaf pages, except if page is the root! */
 
2921
UNIV_INTERN
 
2922
void
 
2923
lock_update_copy_and_discard(
 
2924
/*=========================*/
 
2925
        const buf_block_t*      new_block,      /*!< in: index page to
 
2926
                                                which copied */
 
2927
        const buf_block_t*      block)          /*!< in: index page;
 
2928
                                                NOT the root! */
 
2929
{
 
2930
        lock_mutex_enter_kernel();
 
2931
 
 
2932
        /* Move the locks on the supremum of the old page to the supremum
 
2933
        of new_page */
 
2934
 
 
2935
        lock_rec_move(new_block, block,
 
2936
                      PAGE_HEAP_NO_SUPREMUM, PAGE_HEAP_NO_SUPREMUM);
 
2937
        lock_rec_free_all_from_discard_page(block);
 
2938
 
 
2939
        lock_mutex_exit_kernel();
 
2940
}
 
2941
 
 
2942
/*************************************************************//**
 
2943
Updates the lock table when a page is split to the left. */
 
2944
UNIV_INTERN
 
2945
void
 
2946
lock_update_split_left(
 
2947
/*===================*/
 
2948
        const buf_block_t*      right_block,    /*!< in: right page */
 
2949
        const buf_block_t*      left_block)     /*!< in: left page */
 
2950
{
 
2951
        ulint   heap_no = lock_get_min_heap_no(right_block);
 
2952
 
 
2953
        lock_mutex_enter_kernel();
 
2954
 
 
2955
        /* Inherit the locks to the supremum of the left page from the
 
2956
        successor of the infimum on the right page */
 
2957
 
 
2958
        lock_rec_inherit_to_gap(left_block, right_block,
 
2959
                                PAGE_HEAP_NO_SUPREMUM, heap_no);
 
2960
 
 
2961
        lock_mutex_exit_kernel();
 
2962
}
 
2963
 
 
2964
/*************************************************************//**
 
2965
Updates the lock table when a page is merged to the left. */
 
2966
UNIV_INTERN
 
2967
void
 
2968
lock_update_merge_left(
 
2969
/*===================*/
 
2970
        const buf_block_t*      left_block,     /*!< in: left page to
 
2971
                                                which merged */
 
2972
        const rec_t*            orig_pred,      /*!< in: original predecessor
 
2973
                                                of supremum on the left page
 
2974
                                                before merge */
 
2975
        const buf_block_t*      right_block)    /*!< in: merged index page
 
2976
                                                which will be discarded */
 
2977
{
 
2978
        const rec_t*    left_next_rec;
 
2979
 
 
2980
        ut_ad(left_block->frame == page_align(orig_pred));
 
2981
 
 
2982
        lock_mutex_enter_kernel();
 
2983
 
 
2984
        left_next_rec = page_rec_get_next_const(orig_pred);
 
2985
 
 
2986
        if (!page_rec_is_supremum(left_next_rec)) {
 
2987
 
 
2988
                /* Inherit the locks on the supremum of the left page to the
 
2989
                first record which was moved from the right page */
 
2990
 
 
2991
                lock_rec_inherit_to_gap(left_block, left_block,
 
2992
                                        page_rec_get_heap_no(left_next_rec),
 
2993
                                        PAGE_HEAP_NO_SUPREMUM);
 
2994
 
 
2995
                /* Reset the locks on the supremum of the left page,
 
2996
                releasing waiting transactions */
 
2997
 
 
2998
                lock_rec_reset_and_release_wait(left_block,
 
2999
                                                PAGE_HEAP_NO_SUPREMUM);
 
3000
        }
 
3001
 
 
3002
        /* Move the locks from the supremum of right page to the supremum
 
3003
        of the left page */
 
3004
 
 
3005
        lock_rec_move(left_block, right_block,
 
3006
                      PAGE_HEAP_NO_SUPREMUM, PAGE_HEAP_NO_SUPREMUM);
 
3007
 
 
3008
        lock_rec_free_all_from_discard_page(right_block);
 
3009
 
 
3010
        lock_mutex_exit_kernel();
 
3011
}
 
3012
 
 
3013
/*************************************************************//**
 
3014
Resets the original locks on heir and replaces them with gap type locks
 
3015
inherited from rec. */
 
3016
UNIV_INTERN
 
3017
void
 
3018
lock_rec_reset_and_inherit_gap_locks(
 
3019
/*=================================*/
 
3020
        const buf_block_t*      heir_block,     /*!< in: block containing the
 
3021
                                                record which inherits */
 
3022
        const buf_block_t*      block,          /*!< in: block containing the
 
3023
                                                record from which inherited;
 
3024
                                                does NOT reset the locks on
 
3025
                                                this record */
 
3026
        ulint                   heir_heap_no,   /*!< in: heap_no of the
 
3027
                                                inheriting record */
 
3028
        ulint                   heap_no)        /*!< in: heap_no of the
 
3029
                                                donating record */
 
3030
{
 
3031
        mutex_enter(&kernel_mutex);
 
3032
 
 
3033
        lock_rec_reset_and_release_wait(heir_block, heir_heap_no);
 
3034
 
 
3035
        lock_rec_inherit_to_gap(heir_block, block, heir_heap_no, heap_no);
 
3036
 
 
3037
        mutex_exit(&kernel_mutex);
 
3038
}
 
3039
 
 
3040
/*************************************************************//**
 
3041
Updates the lock table when a page is discarded. */
 
3042
UNIV_INTERN
 
3043
void
 
3044
lock_update_discard(
 
3045
/*================*/
 
3046
        const buf_block_t*      heir_block,     /*!< in: index page
 
3047
                                                which will inherit the locks */
 
3048
        ulint                   heir_heap_no,   /*!< in: heap_no of the record
 
3049
                                                which will inherit the locks */
 
3050
        const buf_block_t*      block)          /*!< in: index page
 
3051
                                                which will be discarded */
 
3052
{
 
3053
        const page_t*   page = block->frame;
 
3054
        const rec_t*    rec;
 
3055
        ulint           heap_no;
 
3056
 
 
3057
        lock_mutex_enter_kernel();
 
3058
 
 
3059
        if (!lock_rec_get_first_on_page(block)) {
 
3060
                /* No locks exist on page, nothing to do */
 
3061
 
 
3062
                lock_mutex_exit_kernel();
 
3063
 
 
3064
                return;
 
3065
        }
 
3066
 
 
3067
        /* Inherit all the locks on the page to the record and reset all
 
3068
        the locks on the page */
 
3069
 
 
3070
        if (page_is_comp(page)) {
 
3071
                rec = page + PAGE_NEW_INFIMUM;
 
3072
 
 
3073
                do {
 
3074
                        heap_no = rec_get_heap_no_new(rec);
 
3075
 
 
3076
                        lock_rec_inherit_to_gap(heir_block, block,
 
3077
                                                heir_heap_no, heap_no);
 
3078
 
 
3079
                        lock_rec_reset_and_release_wait(block, heap_no);
 
3080
 
 
3081
                        rec = page + rec_get_next_offs(rec, TRUE);
 
3082
                } while (heap_no != PAGE_HEAP_NO_SUPREMUM);
 
3083
        } else {
 
3084
                rec = page + PAGE_OLD_INFIMUM;
 
3085
 
 
3086
                do {
 
3087
                        heap_no = rec_get_heap_no_old(rec);
 
3088
 
 
3089
                        lock_rec_inherit_to_gap(heir_block, block,
 
3090
                                                heir_heap_no, heap_no);
 
3091
 
 
3092
                        lock_rec_reset_and_release_wait(block, heap_no);
 
3093
 
 
3094
                        rec = page + rec_get_next_offs(rec, FALSE);
 
3095
                } while (heap_no != PAGE_HEAP_NO_SUPREMUM);
 
3096
        }
 
3097
 
 
3098
        lock_rec_free_all_from_discard_page(block);
 
3099
 
 
3100
        lock_mutex_exit_kernel();
 
3101
}
 
3102
 
 
3103
/*************************************************************//**
 
3104
Updates the lock table when a new user record is inserted. */
 
3105
UNIV_INTERN
 
3106
void
 
3107
lock_update_insert(
 
3108
/*===============*/
 
3109
        const buf_block_t*      block,  /*!< in: buffer block containing rec */
 
3110
        const rec_t*            rec)    /*!< in: the inserted record */
 
3111
{
 
3112
        ulint   receiver_heap_no;
 
3113
        ulint   donator_heap_no;
 
3114
 
 
3115
        ut_ad(block->frame == page_align(rec));
 
3116
 
 
3117
        /* Inherit the gap-locking locks for rec, in gap mode, from the next
 
3118
        record */
 
3119
 
 
3120
        if (page_rec_is_comp(rec)) {
 
3121
                receiver_heap_no = rec_get_heap_no_new(rec);
 
3122
                donator_heap_no = rec_get_heap_no_new(
 
3123
                        page_rec_get_next_low(rec, TRUE));
 
3124
        } else {
 
3125
                receiver_heap_no = rec_get_heap_no_old(rec);
 
3126
                donator_heap_no = rec_get_heap_no_old(
 
3127
                        page_rec_get_next_low(rec, FALSE));
 
3128
        }
 
3129
 
 
3130
        lock_mutex_enter_kernel();
 
3131
        lock_rec_inherit_to_gap_if_gap_lock(block,
 
3132
                                            receiver_heap_no, donator_heap_no);
 
3133
        lock_mutex_exit_kernel();
 
3134
}
 
3135
 
 
3136
/*************************************************************//**
 
3137
Updates the lock table when a record is removed. */
 
3138
UNIV_INTERN
 
3139
void
 
3140
lock_update_delete(
 
3141
/*===============*/
 
3142
        const buf_block_t*      block,  /*!< in: buffer block containing rec */
 
3143
        const rec_t*            rec)    /*!< in: the record to be removed */
 
3144
{
 
3145
        const page_t*   page = block->frame;
 
3146
        ulint           heap_no;
 
3147
        ulint           next_heap_no;
 
3148
 
 
3149
        ut_ad(page == page_align(rec));
 
3150
 
 
3151
        if (page_is_comp(page)) {
 
3152
                heap_no = rec_get_heap_no_new(rec);
 
3153
                next_heap_no = rec_get_heap_no_new(page
 
3154
                                                   + rec_get_next_offs(rec,
 
3155
                                                                       TRUE));
 
3156
        } else {
 
3157
                heap_no = rec_get_heap_no_old(rec);
 
3158
                next_heap_no = rec_get_heap_no_old(page
 
3159
                                                   + rec_get_next_offs(rec,
 
3160
                                                                       FALSE));
 
3161
        }
 
3162
 
 
3163
        lock_mutex_enter_kernel();
 
3164
 
 
3165
        /* Let the next record inherit the locks from rec, in gap mode */
 
3166
 
 
3167
        lock_rec_inherit_to_gap(block, block, next_heap_no, heap_no);
 
3168
 
 
3169
        /* Reset the lock bits on rec and release waiting transactions */
 
3170
 
 
3171
        lock_rec_reset_and_release_wait(block, heap_no);
 
3172
 
 
3173
        lock_mutex_exit_kernel();
 
3174
}
 
3175
 
 
3176
/*********************************************************************//**
 
3177
Stores on the page infimum record the explicit locks of another record.
 
3178
This function is used to store the lock state of a record when it is
 
3179
updated and the size of the record changes in the update. The record
 
3180
is moved in such an update, perhaps to another page. The infimum record
 
3181
acts as a dummy carrier record, taking care of lock releases while the
 
3182
actual record is being moved. */
 
3183
UNIV_INTERN
 
3184
void
 
3185
lock_rec_store_on_page_infimum(
 
3186
/*===========================*/
 
3187
        const buf_block_t*      block,  /*!< in: buffer block containing rec */
 
3188
        const rec_t*            rec)    /*!< in: record whose lock state
 
3189
                                        is stored on the infimum
 
3190
                                        record of the same page; lock
 
3191
                                        bits are reset on the
 
3192
                                        record */
 
3193
{
 
3194
        ulint   heap_no = page_rec_get_heap_no(rec);
 
3195
 
 
3196
        ut_ad(block->frame == page_align(rec));
 
3197
 
 
3198
        lock_mutex_enter_kernel();
 
3199
 
 
3200
        lock_rec_move(block, block, PAGE_HEAP_NO_INFIMUM, heap_no);
 
3201
 
 
3202
        lock_mutex_exit_kernel();
 
3203
}
 
3204
 
 
3205
/*********************************************************************//**
 
3206
Restores the state of explicit lock requests on a single record, where the
 
3207
state was stored on the infimum of the page. */
 
3208
UNIV_INTERN
 
3209
void
 
3210
lock_rec_restore_from_page_infimum(
 
3211
/*===============================*/
 
3212
        const buf_block_t*      block,  /*!< in: buffer block containing rec */
 
3213
        const rec_t*            rec,    /*!< in: record whose lock state
 
3214
                                        is restored */
 
3215
        const buf_block_t*      donator)/*!< in: page (rec is not
 
3216
                                        necessarily on this page)
 
3217
                                        whose infimum stored the lock
 
3218
                                        state; lock bits are reset on
 
3219
                                        the infimum */
 
3220
{
 
3221
        ulint   heap_no = page_rec_get_heap_no(rec);
 
3222
 
 
3223
        lock_mutex_enter_kernel();
 
3224
 
 
3225
        lock_rec_move(block, donator, heap_no, PAGE_HEAP_NO_INFIMUM);
 
3226
 
 
3227
        lock_mutex_exit_kernel();
 
3228
}
 
3229
 
 
3230
/*=========== DEADLOCK CHECKING ======================================*/
 
3231
 
 
3232
/********************************************************************//**
 
3233
Checks if a lock request results in a deadlock.
 
3234
@return TRUE if a deadlock was detected and we chose trx as a victim;
 
3235
FALSE if no deadlock, or there was a deadlock, but we chose other
 
3236
transaction(s) as victim(s) */
 
3237
static
 
3238
ibool
 
3239
lock_deadlock_occurs(
 
3240
/*=================*/
 
3241
        lock_t* lock,   /*!< in: lock the transaction is requesting */
 
3242
        trx_t*  trx)    /*!< in: transaction */
 
3243
{
 
3244
        dict_table_t*   table;
 
3245
        dict_index_t*   index;
 
3246
        trx_t*          mark_trx;
 
3247
        ulint           ret;
 
3248
        ulint           cost    = 0;
 
3249
 
 
3250
        ut_ad(trx);
 
3251
        ut_ad(lock);
 
3252
        ut_ad(mutex_own(&kernel_mutex));
 
3253
retry:
 
3254
        /* We check that adding this trx to the waits-for graph
 
3255
        does not produce a cycle. First mark all active transactions
 
3256
        with 0: */
 
3257
 
 
3258
        mark_trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
 
3259
 
 
3260
        while (mark_trx) {
 
3261
                mark_trx->deadlock_mark = 0;
 
3262
                mark_trx = UT_LIST_GET_NEXT(trx_list, mark_trx);
 
3263
        }
 
3264
 
 
3265
        ret = lock_deadlock_recursive(trx, trx, lock, &cost, 0);
 
3266
 
 
3267
        if (ret == LOCK_VICTIM_IS_OTHER) {
 
3268
                /* We chose some other trx as a victim: retry if there still
 
3269
                is a deadlock */
 
3270
 
 
3271
                goto retry;
 
3272
        }
 
3273
 
 
3274
        if (UNIV_UNLIKELY(ret == LOCK_VICTIM_IS_START)) {
 
3275
                if (lock_get_type_low(lock) & LOCK_TABLE) {
 
3276
                        table = lock->un_member.tab_lock.table;
 
3277
                        index = NULL;
 
3278
                } else {
 
3279
                        index = lock->index;
 
3280
                        table = index->table;
 
3281
                }
 
3282
 
 
3283
                lock_deadlock_found = TRUE;
 
3284
 
 
3285
                fputs("*** WE ROLL BACK TRANSACTION (2)\n",
 
3286
                      lock_latest_err_file);
 
3287
 
 
3288
                return(TRUE);
 
3289
        }
 
3290
 
 
3291
        return(FALSE);
 
3292
}
 
3293
 
 
3294
/********************************************************************//**
 
3295
Looks recursively for a deadlock.
 
3296
@return 0 if no deadlock found, LOCK_VICTIM_IS_START if there was a
 
3297
deadlock and we chose 'start' as the victim, LOCK_VICTIM_IS_OTHER if a
 
3298
deadlock was found and we chose some other trx as a victim: we must do
 
3299
the search again in this last case because there may be another
 
3300
deadlock! */
 
3301
static
 
3302
ulint
 
3303
lock_deadlock_recursive(
 
3304
/*====================*/
 
3305
        trx_t*  start,          /*!< in: recursion starting point */
 
3306
        trx_t*  trx,            /*!< in: a transaction waiting for a lock */
 
3307
        lock_t* wait_lock,      /*!< in: the lock trx is waiting to be granted */
 
3308
        ulint*  cost,           /*!< in/out: number of calculation steps thus
 
3309
                                far: if this exceeds LOCK_MAX_N_STEPS_...
 
3310
                                we return LOCK_VICTIM_IS_START */
 
3311
        ulint   depth)          /*!< in: recursion depth: if this exceeds
 
3312
                                LOCK_MAX_DEPTH_IN_DEADLOCK_CHECK, we
 
3313
                                return LOCK_VICTIM_IS_START */
 
3314
{
 
3315
        lock_t* lock;
 
3316
        ulint   bit_no          = ULINT_UNDEFINED;
 
3317
        trx_t*  lock_trx;
 
3318
        ulint   ret;
 
3319
 
 
3320
        ut_a(trx);
 
3321
        ut_a(start);
 
3322
        ut_a(wait_lock);
 
3323
        ut_ad(mutex_own(&kernel_mutex));
 
3324
 
 
3325
        if (trx->deadlock_mark == 1) {
 
3326
                /* We have already exhaustively searched the subtree starting
 
3327
                from this trx */
 
3328
 
 
3329
                return(0);
 
3330
        }
 
3331
 
 
3332
        *cost = *cost + 1;
 
3333
 
 
3334
        lock = wait_lock;
 
3335
 
 
3336
        if (lock_get_type_low(wait_lock) == LOCK_REC) {
 
3337
 
 
3338
                bit_no = lock_rec_find_set_bit(wait_lock);
 
3339
 
 
3340
                ut_a(bit_no != ULINT_UNDEFINED);
 
3341
        }
 
3342
 
 
3343
        /* Look at the locks ahead of wait_lock in the lock queue */
 
3344
 
 
3345
        for (;;) {
 
3346
                if (lock_get_type_low(lock) & LOCK_TABLE) {
 
3347
 
 
3348
                        lock = UT_LIST_GET_PREV(un_member.tab_lock.locks,
 
3349
                                                lock);
 
3350
                } else {
 
3351
                        ut_ad(lock_get_type_low(lock) == LOCK_REC);
 
3352
                        ut_a(bit_no != ULINT_UNDEFINED);
 
3353
 
 
3354
                        lock = (lock_t*) lock_rec_get_prev(lock, bit_no);
 
3355
                }
 
3356
 
 
3357
                if (lock == NULL) {
 
3358
                        /* We can mark this subtree as searched */
 
3359
                        trx->deadlock_mark = 1;
 
3360
 
 
3361
                        return(FALSE);
 
3362
                }
 
3363
 
 
3364
                if (lock_has_to_wait(wait_lock, lock)) {
 
3365
 
 
3366
                        ibool   too_far
 
3367
                                = depth > LOCK_MAX_DEPTH_IN_DEADLOCK_CHECK
 
3368
                                || *cost > LOCK_MAX_N_STEPS_IN_DEADLOCK_CHECK;
 
3369
 
 
3370
                        lock_trx = lock->trx;
 
3371
 
 
3372
                        if (lock_trx == start || too_far) {
 
3373
 
 
3374
                                /* We came back to the recursion starting
 
3375
                                point: a deadlock detected; or we have
 
3376
                                searched the waits-for graph too long */
 
3377
 
 
3378
                                FILE*   ef = lock_latest_err_file;
 
3379
 
 
3380
                                rewind(ef);
 
3381
                                ut_print_timestamp(ef);
 
3382
 
 
3383
                                fputs("\n*** (1) TRANSACTION:\n", ef);
 
3384
 
 
3385
                                trx_print(ef, wait_lock->trx, 3000);
 
3386
 
 
3387
                                fputs("*** (1) WAITING FOR THIS LOCK"
 
3388
                                      " TO BE GRANTED:\n", ef);
 
3389
 
 
3390
                                if (lock_get_type_low(wait_lock) == LOCK_REC) {
 
3391
                                        lock_rec_print(ef, wait_lock);
 
3392
                                } else {
 
3393
                                        lock_table_print(ef, wait_lock);
 
3394
                                }
 
3395
 
 
3396
                                fputs("*** (2) TRANSACTION:\n", ef);
 
3397
 
 
3398
                                trx_print(ef, lock->trx, 3000);
 
3399
 
 
3400
                                fputs("*** (2) HOLDS THE LOCK(S):\n", ef);
 
3401
 
 
3402
                                if (lock_get_type_low(lock) == LOCK_REC) {
 
3403
                                        lock_rec_print(ef, lock);
 
3404
                                } else {
 
3405
                                        lock_table_print(ef, lock);
 
3406
                                }
 
3407
 
 
3408
                                fputs("*** (2) WAITING FOR THIS LOCK"
 
3409
                                      " TO BE GRANTED:\n", ef);
 
3410
 
 
3411
                                if (lock_get_type_low(start->wait_lock)
 
3412
                                    == LOCK_REC) {
 
3413
                                        lock_rec_print(ef, start->wait_lock);
 
3414
                                } else {
 
3415
                                        lock_table_print(ef, start->wait_lock);
 
3416
                                }
 
3417
#ifdef UNIV_DEBUG
 
3418
                                if (lock_print_waits) {
 
3419
                                        fputs("Deadlock detected"
 
3420
                                              " or too long search\n",
 
3421
                                              stderr);
 
3422
                                }
 
3423
#endif /* UNIV_DEBUG */
 
3424
                                if (too_far) {
 
3425
 
 
3426
                                        fputs("TOO DEEP OR LONG SEARCH"
 
3427
                                              " IN THE LOCK TABLE"
 
3428
                                              " WAITS-FOR GRAPH\n", ef);
 
3429
 
 
3430
                                        return(LOCK_VICTIM_IS_START);
 
3431
                                }
 
3432
 
 
3433
                                if (trx_weight_cmp(wait_lock->trx,
 
3434
                                                   start) >= 0) {
 
3435
                                        /* Our recursion starting point
 
3436
                                        transaction is 'smaller', let us
 
3437
                                        choose 'start' as the victim and roll
 
3438
                                        back it */
 
3439
 
 
3440
                                        return(LOCK_VICTIM_IS_START);
 
3441
                                }
 
3442
 
 
3443
                                lock_deadlock_found = TRUE;
 
3444
 
 
3445
                                /* Let us choose the transaction of wait_lock
 
3446
                                as a victim to try to avoid deadlocking our
 
3447
                                recursion starting point transaction */
 
3448
 
 
3449
                                fputs("*** WE ROLL BACK TRANSACTION (1)\n",
 
3450
                                      ef);
 
3451
 
 
3452
                                wait_lock->trx->was_chosen_as_deadlock_victim
 
3453
                                        = TRUE;
 
3454
 
 
3455
                                lock_cancel_waiting_and_release(wait_lock);
 
3456
 
 
3457
                                /* Since trx and wait_lock are no longer
 
3458
                                in the waits-for graph, we can return FALSE;
 
3459
                                note that our selective algorithm can choose
 
3460
                                several transactions as victims, but still
 
3461
                                we may end up rolling back also the recursion
 
3462
                                starting point transaction! */
 
3463
 
 
3464
                                return(LOCK_VICTIM_IS_OTHER);
 
3465
                        }
 
3466
 
 
3467
                        if (lock_trx->que_state == TRX_QUE_LOCK_WAIT) {
 
3468
 
 
3469
                                /* Another trx ahead has requested lock in an
 
3470
                                incompatible mode, and is itself waiting for
 
3471
                                a lock */
 
3472
 
 
3473
                                ret = lock_deadlock_recursive(
 
3474
                                        start, lock_trx,
 
3475
                                        lock_trx->wait_lock, cost, depth + 1);
 
3476
                                if (ret != 0) {
 
3477
 
 
3478
                                        return(ret);
 
3479
                                }
 
3480
                        }
 
3481
                }
 
3482
        }/* end of the 'for (;;)'-loop */
 
3483
}
 
3484
 
 
3485
/*========================= TABLE LOCKS ==============================*/
 
3486
 
 
3487
/*********************************************************************//**
 
3488
Creates a table lock object and adds it as the last in the lock queue
 
3489
of the table. Does NOT check for deadlocks or lock compatibility.
 
3490
@return own: new lock object */
 
3491
UNIV_INLINE
 
3492
lock_t*
 
3493
lock_table_create(
 
3494
/*==============*/
 
3495
        dict_table_t*   table,  /*!< in: database table in dictionary cache */
 
3496
        ulint           type_mode,/*!< in: lock mode possibly ORed with
 
3497
                                LOCK_WAIT */
 
3498
        trx_t*          trx)    /*!< in: trx */
 
3499
{
 
3500
        lock_t* lock;
 
3501
 
 
3502
        ut_ad(table && trx);
 
3503
        ut_ad(mutex_own(&kernel_mutex));
 
3504
 
 
3505
        if ((type_mode & LOCK_MODE_MASK) == LOCK_AUTO_INC) {
 
3506
                ++table->n_waiting_or_granted_auto_inc_locks;
 
3507
        }
 
3508
 
 
3509
        /* For AUTOINC locking we reuse the lock instance only if
 
3510
        there is no wait involved else we allocate the waiting lock
 
3511
        from the transaction lock heap. */
 
3512
        if (type_mode == LOCK_AUTO_INC) {
 
3513
 
 
3514
                lock = table->autoinc_lock;
 
3515
 
 
3516
                table->autoinc_trx = trx;
 
3517
 
 
3518
                ib_vector_push(trx->autoinc_locks, lock);
 
3519
        } else {
 
3520
                lock = mem_heap_alloc(trx->lock_heap, sizeof(lock_t));
 
3521
        }
 
3522
 
 
3523
        UT_LIST_ADD_LAST(trx_locks, trx->trx_locks, lock);
 
3524
 
 
3525
        lock->type_mode = type_mode | LOCK_TABLE;
 
3526
        lock->trx = trx;
 
3527
 
 
3528
        lock->un_member.tab_lock.table = table;
 
3529
 
 
3530
        UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock);
 
3531
 
 
3532
        if (UNIV_UNLIKELY(type_mode & LOCK_WAIT)) {
 
3533
 
 
3534
                lock_set_lock_and_trx_wait(lock, trx);
 
3535
        }
 
3536
 
 
3537
        return(lock);
 
3538
}
 
3539
 
 
3540
/*************************************************************//**
 
3541
Removes a table lock request from the queue and the trx list of locks;
 
3542
this is a low-level function which does NOT check if waiting requests
 
3543
can now be granted. */
 
3544
UNIV_INLINE
 
3545
void
 
3546
lock_table_remove_low(
 
3547
/*==================*/
 
3548
        lock_t* lock)   /*!< in: table lock */
 
3549
{
 
3550
        trx_t*          trx;
 
3551
        dict_table_t*   table;
 
3552
 
 
3553
        ut_ad(mutex_own(&kernel_mutex));
 
3554
 
 
3555
        trx = lock->trx;
 
3556
        table = lock->un_member.tab_lock.table;
 
3557
 
 
3558
        /* Remove the table from the transaction's AUTOINC vector, if
 
3559
        the lock that is being release is an AUTOINC lock. */
 
3560
        if (lock_get_mode(lock) == LOCK_AUTO_INC) {
 
3561
 
 
3562
                /* The table's AUTOINC lock can get transferred to
 
3563
                another transaction before we get here. */
 
3564
                if (table->autoinc_trx == trx) {
 
3565
                        table->autoinc_trx = NULL;
 
3566
                }
 
3567
 
 
3568
                /* The locks must be freed in the reverse order from
 
3569
                the one in which they were acquired. This is to avoid
 
3570
                traversing the AUTOINC lock vector unnecessarily. 
 
3571
 
 
3572
                We only store locks that were granted in the
 
3573
                trx->autoinc_locks vector (see lock_table_create()
 
3574
                and lock_grant()). Therefore it can be empty and we
 
3575
                need to check for that. */
 
3576
 
 
3577
                if (!ib_vector_is_empty(trx->autoinc_locks)) {
 
3578
                        lock_t* autoinc_lock;
 
3579
 
 
3580
                        autoinc_lock = ib_vector_pop(trx->autoinc_locks);
 
3581
                        ut_a(autoinc_lock == lock);
 
3582
                }
 
3583
 
 
3584
                ut_a(table->n_waiting_or_granted_auto_inc_locks > 0);
 
3585
                --table->n_waiting_or_granted_auto_inc_locks;
 
3586
        }
 
3587
 
 
3588
        UT_LIST_REMOVE(trx_locks, trx->trx_locks, lock);
 
3589
        UT_LIST_REMOVE(un_member.tab_lock.locks, table->locks, lock);
 
3590
}
 
3591
 
 
3592
/*********************************************************************//**
 
3593
Enqueues a waiting request for a table lock which cannot be granted
 
3594
immediately. Checks for deadlocks.
 
3595
@return DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED, or
 
3596
DB_SUCCESS; DB_SUCCESS means that there was a deadlock, but another
 
3597
transaction was chosen as a victim, and we got the lock immediately:
 
3598
no need to wait then */
 
3599
static
 
3600
ulint
 
3601
lock_table_enqueue_waiting(
 
3602
/*=======================*/
 
3603
        ulint           mode,   /*!< in: lock mode this transaction is
 
3604
                                requesting */
 
3605
        dict_table_t*   table,  /*!< in: table */
 
3606
        que_thr_t*      thr)    /*!< in: query thread */
 
3607
{
 
3608
        lock_t* lock;
 
3609
        trx_t*  trx;
 
3610
 
 
3611
        ut_ad(mutex_own(&kernel_mutex));
 
3612
 
 
3613
        /* Test if there already is some other reason to suspend thread:
 
3614
        we do not enqueue a lock request if the query thread should be
 
3615
        stopped anyway */
 
3616
 
 
3617
        if (que_thr_stop(thr)) {
 
3618
                ut_error;
 
3619
 
 
3620
                return(DB_QUE_THR_SUSPENDED);
 
3621
        }
 
3622
 
 
3623
        trx = thr_get_trx(thr);
 
3624
 
 
3625
        switch (trx_get_dict_operation(trx)) {
 
3626
        case TRX_DICT_OP_NONE:
 
3627
                break;
 
3628
        case TRX_DICT_OP_TABLE:
 
3629
        case TRX_DICT_OP_INDEX:
 
3630
                ut_print_timestamp(stderr);
 
3631
                fputs("  InnoDB: Error: a table lock wait happens"
 
3632
                      " in a dictionary operation!\n"
 
3633
                      "InnoDB: Table name ", stderr);
 
3634
                ut_print_name(stderr, trx, TRUE, table->name);
 
3635
                fputs(".\n"
 
3636
                      "InnoDB: Submit a detailed bug report"
 
3637
                      " to http://bugs.mysql.com\n",
 
3638
                      stderr);
 
3639
        }
 
3640
 
 
3641
        /* Enqueue the lock request that will wait to be granted */
 
3642
 
 
3643
        lock = lock_table_create(table, mode | LOCK_WAIT, trx);
 
3644
 
 
3645
        /* Check if a deadlock occurs: if yes, remove the lock request and
 
3646
        return an error code */
 
3647
 
 
3648
        if (lock_deadlock_occurs(lock, trx)) {
 
3649
 
 
3650
                lock_reset_lock_and_trx_wait(lock);
 
3651
                lock_table_remove_low(lock);
 
3652
 
 
3653
                return(DB_DEADLOCK);
 
3654
        }
 
3655
 
 
3656
        if (trx->wait_lock == NULL) {
 
3657
                /* Deadlock resolution chose another transaction as a victim,
 
3658
                and we accidentally got our lock granted! */
 
3659
 
 
3660
                return(DB_SUCCESS);
 
3661
        }
 
3662
 
 
3663
        trx->que_state = TRX_QUE_LOCK_WAIT;
 
3664
        trx->was_chosen_as_deadlock_victim = FALSE;
 
3665
        trx->wait_started = time(NULL);
 
3666
 
 
3667
        ut_a(que_thr_stop(thr));
 
3668
 
 
3669
        return(DB_LOCK_WAIT);
 
3670
}
 
3671
 
 
3672
/*********************************************************************//**
 
3673
Checks if other transactions have an incompatible mode lock request in
 
3674
the lock queue. */
 
3675
UNIV_INLINE
 
3676
ibool
 
3677
lock_table_other_has_incompatible(
 
3678
/*==============================*/
 
3679
        trx_t*          trx,    /*!< in: transaction, or NULL if all
 
3680
                                transactions should be included */
 
3681
        ulint           wait,   /*!< in: LOCK_WAIT if also waiting locks are
 
3682
                                taken into account, or 0 if not */
 
3683
        dict_table_t*   table,  /*!< in: table */
 
3684
        enum lock_mode  mode)   /*!< in: lock mode */
 
3685
{
 
3686
        lock_t* lock;
 
3687
 
 
3688
        ut_ad(mutex_own(&kernel_mutex));
 
3689
 
 
3690
        lock = UT_LIST_GET_LAST(table->locks);
 
3691
 
 
3692
        while (lock != NULL) {
 
3693
 
 
3694
                if ((lock->trx != trx)
 
3695
                    && (!lock_mode_compatible(lock_get_mode(lock), mode))
 
3696
                    && (wait || !(lock_get_wait(lock)))) {
 
3697
 
 
3698
                        return(TRUE);
 
3699
                }
 
3700
 
 
3701
                lock = UT_LIST_GET_PREV(un_member.tab_lock.locks, lock);
 
3702
        }
 
3703
 
 
3704
        return(FALSE);
 
3705
}
 
3706
 
 
3707
/*********************************************************************//**
 
3708
Locks the specified database table in the mode given. If the lock cannot
 
3709
be granted immediately, the query thread is put to wait.
 
3710
@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
 
3711
UNIV_INTERN
 
3712
ulint
 
3713
lock_table(
 
3714
/*=======*/
 
3715
        ulint           flags,  /*!< in: if BTR_NO_LOCKING_FLAG bit is set,
 
3716
                                does nothing */
 
3717
        dict_table_t*   table,  /*!< in: database table in dictionary cache */
 
3718
        enum lock_mode  mode,   /*!< in: lock mode */
 
3719
        que_thr_t*      thr)    /*!< in: query thread */
 
3720
{
 
3721
        trx_t*  trx;
 
3722
        ulint   err;
 
3723
 
 
3724
        ut_ad(table && thr);
 
3725
 
 
3726
        if (flags & BTR_NO_LOCKING_FLAG) {
 
3727
 
 
3728
                return(DB_SUCCESS);
 
3729
        }
 
3730
 
 
3731
        ut_a(flags == 0);
 
3732
 
 
3733
        trx = thr_get_trx(thr);
 
3734
 
 
3735
        lock_mutex_enter_kernel();
 
3736
 
 
3737
        /* Look for stronger locks the same trx already has on the table */
 
3738
 
 
3739
        if (lock_table_has(trx, table, mode)) {
 
3740
 
 
3741
                lock_mutex_exit_kernel();
 
3742
 
 
3743
                return(DB_SUCCESS);
 
3744
        }
 
3745
 
 
3746
        /* We have to check if the new lock is compatible with any locks
 
3747
        other transactions have in the table lock queue. */
 
3748
 
 
3749
        if (lock_table_other_has_incompatible(trx, LOCK_WAIT, table, mode)) {
 
3750
 
 
3751
                /* Another trx has a request on the table in an incompatible
 
3752
                mode: this trx may have to wait */
 
3753
 
 
3754
                err = lock_table_enqueue_waiting(mode | flags, table, thr);
 
3755
 
 
3756
                lock_mutex_exit_kernel();
 
3757
 
 
3758
                return(err);
 
3759
        }
 
3760
 
 
3761
        lock_table_create(table, mode | flags, trx);
 
3762
 
 
3763
        ut_a(!flags || mode == LOCK_S || mode == LOCK_X);
 
3764
 
 
3765
        lock_mutex_exit_kernel();
 
3766
 
 
3767
        return(DB_SUCCESS);
 
3768
}
 
3769
 
 
3770
/*********************************************************************//**
 
3771
Checks if a waiting table lock request still has to wait in a queue.
 
3772
@return TRUE if still has to wait */
 
3773
static
 
3774
ibool
 
3775
lock_table_has_to_wait_in_queue(
 
3776
/*============================*/
 
3777
        lock_t* wait_lock)      /*!< in: waiting table lock */
 
3778
{
 
3779
        dict_table_t*   table;
 
3780
        lock_t*         lock;
 
3781
 
 
3782
        ut_ad(mutex_own(&kernel_mutex));
 
3783
        ut_ad(lock_get_wait(wait_lock));
 
3784
 
 
3785
        table = wait_lock->un_member.tab_lock.table;
 
3786
 
 
3787
        lock = UT_LIST_GET_FIRST(table->locks);
 
3788
 
 
3789
        while (lock != wait_lock) {
 
3790
 
 
3791
                if (lock_has_to_wait(wait_lock, lock)) {
 
3792
 
 
3793
                        return(TRUE);
 
3794
                }
 
3795
 
 
3796
                lock = UT_LIST_GET_NEXT(un_member.tab_lock.locks, lock);
 
3797
        }
 
3798
 
 
3799
        return(FALSE);
 
3800
}
 
3801
 
 
3802
/*************************************************************//**
 
3803
Removes a table lock request, waiting or granted, from the queue and grants
 
3804
locks to other transactions in the queue, if they now are entitled to a
 
3805
lock. */
 
3806
static
 
3807
void
 
3808
lock_table_dequeue(
 
3809
/*===============*/
 
3810
        lock_t* in_lock)/*!< in: table lock object; transactions waiting
 
3811
                        behind will get their lock requests granted, if
 
3812
                        they are now qualified to it */
 
3813
{
 
3814
        lock_t* lock;
 
3815
 
 
3816
        ut_ad(mutex_own(&kernel_mutex));
 
3817
        ut_a(lock_get_type_low(in_lock) == LOCK_TABLE);
 
3818
 
 
3819
        lock = UT_LIST_GET_NEXT(un_member.tab_lock.locks, in_lock);
 
3820
 
 
3821
        lock_table_remove_low(in_lock);
 
3822
 
 
3823
        /* Check if waiting locks in the queue can now be granted: grant
 
3824
        locks if there are no conflicting locks ahead. */
 
3825
 
 
3826
        while (lock != NULL) {
 
3827
 
 
3828
                if (lock_get_wait(lock)
 
3829
                    && !lock_table_has_to_wait_in_queue(lock)) {
 
3830
 
 
3831
                        /* Grant the lock */
 
3832
                        lock_grant(lock);
 
3833
                }
 
3834
 
 
3835
                lock = UT_LIST_GET_NEXT(un_member.tab_lock.locks, lock);
 
3836
        }
 
3837
}
 
3838
 
 
3839
/*=========================== LOCK RELEASE ==============================*/
 
3840
 
 
3841
/*************************************************************//**
 
3842
Removes a granted record lock of a transaction from the queue and grants
 
3843
locks to other transactions waiting in the queue if they now are entitled
 
3844
to a lock. */
 
3845
UNIV_INTERN
 
3846
void
 
3847
lock_rec_unlock(
 
3848
/*============*/
 
3849
        trx_t*                  trx,    /*!< in: transaction that has
 
3850
                                        set a record lock */
 
3851
        const buf_block_t*      block,  /*!< in: buffer block containing rec */
 
3852
        const rec_t*            rec,    /*!< in: record */
 
3853
        enum lock_mode          lock_mode)/*!< in: LOCK_S or LOCK_X */
 
3854
{
 
3855
        lock_t* lock;
 
3856
        lock_t* release_lock    = NULL;
 
3857
        ulint   heap_no;
 
3858
 
 
3859
        ut_ad(trx && rec);
 
3860
        ut_ad(block->frame == page_align(rec));
 
3861
 
 
3862
        heap_no = page_rec_get_heap_no(rec);
 
3863
 
 
3864
        mutex_enter(&kernel_mutex);
 
3865
 
 
3866
        lock = lock_rec_get_first(block, heap_no);
 
3867
 
 
3868
        /* Find the last lock with the same lock_mode and transaction
 
3869
        from the record. */
 
3870
 
 
3871
        while (lock != NULL) {
 
3872
                if (lock->trx == trx && lock_get_mode(lock) == lock_mode) {
 
3873
                        release_lock = lock;
 
3874
                        ut_a(!lock_get_wait(lock));
 
3875
                }
 
3876
 
 
3877
                lock = lock_rec_get_next(heap_no, lock);
 
3878
        }
 
3879
 
 
3880
        /* If a record lock is found, release the record lock */
 
3881
 
 
3882
        if (UNIV_LIKELY(release_lock != NULL)) {
 
3883
                lock_rec_reset_nth_bit(release_lock, heap_no);
 
3884
        } else {
 
3885
                mutex_exit(&kernel_mutex);
 
3886
                ut_print_timestamp(stderr);
 
3887
                fprintf(stderr,
 
3888
                        "  InnoDB: Error: unlock row could not"
 
3889
                        " find a %lu mode lock on the record\n",
 
3890
                        (ulong) lock_mode);
 
3891
 
 
3892
                return;
 
3893
        }
 
3894
 
 
3895
        /* Check if we can now grant waiting lock requests */
 
3896
 
 
3897
        lock = lock_rec_get_first(block, heap_no);
 
3898
 
 
3899
        while (lock != NULL) {
 
3900
                if (lock_get_wait(lock)
 
3901
                    && !lock_rec_has_to_wait_in_queue(lock)) {
 
3902
 
 
3903
                        /* Grant the lock */
 
3904
                        lock_grant(lock);
 
3905
                }
 
3906
 
 
3907
                lock = lock_rec_get_next(heap_no, lock);
 
3908
        }
 
3909
 
 
3910
        mutex_exit(&kernel_mutex);
 
3911
}
 
3912
 
 
3913
/*********************************************************************//**
 
3914
Releases transaction locks, and releases possible other transactions waiting
 
3915
because of these locks. */
 
3916
UNIV_INTERN
 
3917
void
 
3918
lock_release_off_kernel(
 
3919
/*====================*/
 
3920
        trx_t*  trx)    /*!< in: transaction */
 
3921
{
 
3922
        dict_table_t*   table;
 
3923
        ulint           count;
 
3924
        lock_t*         lock;
 
3925
 
 
3926
        ut_ad(mutex_own(&kernel_mutex));
 
3927
 
 
3928
        lock = UT_LIST_GET_LAST(trx->trx_locks);
 
3929
 
 
3930
        count = 0;
 
3931
 
 
3932
        while (lock != NULL) {
 
3933
 
 
3934
                count++;
 
3935
 
 
3936
                if (lock_get_type_low(lock) == LOCK_REC) {
 
3937
 
 
3938
                        lock_rec_dequeue_from_page(lock);
 
3939
                } else {
 
3940
                        ut_ad(lock_get_type_low(lock) & LOCK_TABLE);
 
3941
 
 
3942
                        if (lock_get_mode(lock) != LOCK_IS
 
3943
                            && !ut_dulint_is_zero(trx->undo_no)) {
 
3944
 
 
3945
                                /* The trx may have modified the table. We
 
3946
                                block the use of the MySQL query cache for
 
3947
                                all currently active transactions. */
 
3948
 
 
3949
                                table = lock->un_member.tab_lock.table;
 
3950
 
 
3951
                                table->query_cache_inv_trx_id
 
3952
                                        = trx_sys->max_trx_id;
 
3953
                        }
 
3954
 
 
3955
                        lock_table_dequeue(lock);
 
3956
                }
 
3957
 
 
3958
                if (count == LOCK_RELEASE_KERNEL_INTERVAL) {
 
3959
                        /* Release the kernel mutex for a while, so that we
 
3960
                        do not monopolize it */
 
3961
 
 
3962
                        lock_mutex_exit_kernel();
 
3963
 
 
3964
                        lock_mutex_enter_kernel();
 
3965
 
 
3966
                        count = 0;
 
3967
                }
 
3968
 
 
3969
                lock = UT_LIST_GET_LAST(trx->trx_locks);
 
3970
        }
 
3971
 
 
3972
        ut_a(ib_vector_size(trx->autoinc_locks) == 0);
 
3973
 
 
3974
        mem_heap_empty(trx->lock_heap);
 
3975
}
 
3976
 
 
3977
/*********************************************************************//**
 
3978
Cancels a waiting lock request and releases possible other transactions
 
3979
waiting behind it. */
 
3980
UNIV_INTERN
 
3981
void
 
3982
lock_cancel_waiting_and_release(
 
3983
/*============================*/
 
3984
        lock_t* lock)   /*!< in: waiting lock request */
 
3985
{
 
3986
        ut_ad(mutex_own(&kernel_mutex));
 
3987
 
 
3988
        if (lock_get_type_low(lock) == LOCK_REC) {
 
3989
 
 
3990
                lock_rec_dequeue_from_page(lock);
 
3991
        } else {
 
3992
                ut_ad(lock_get_type_low(lock) & LOCK_TABLE);
 
3993
 
 
3994
                if (lock->trx->autoinc_locks != NULL) {
 
3995
                        /* Release the transaction's AUTOINC locks/ */
 
3996
                        lock_release_autoinc_locks(lock->trx);
 
3997
                }
 
3998
 
 
3999
                lock_table_dequeue(lock);
 
4000
        }
 
4001
 
 
4002
        /* Reset the wait flag and the back pointer to lock in trx */
 
4003
 
 
4004
        lock_reset_lock_and_trx_wait(lock);
 
4005
 
 
4006
        /* The following function releases the trx from lock wait */
 
4007
 
 
4008
        trx_end_lock_wait(lock->trx);
 
4009
}
 
4010
 
 
4011
/* True if a lock mode is S or X */
 
4012
#define IS_LOCK_S_OR_X(lock) \
 
4013
        (lock_get_mode(lock) == LOCK_S \
 
4014
         || lock_get_mode(lock) == LOCK_X)
 
4015
 
 
4016
 
 
4017
/*********************************************************************//**
 
4018
Removes locks of a transaction on a table to be dropped.
 
4019
If remove_also_table_sx_locks is TRUE then table-level S and X locks are
 
4020
also removed in addition to other table-level and record-level locks.
 
4021
No lock, that is going to be removed, is allowed to be a wait lock. */
 
4022
static
 
4023
void
 
4024
lock_remove_all_on_table_for_trx(
 
4025
/*=============================*/
 
4026
        dict_table_t*   table,                  /*!< in: table to be dropped */
 
4027
        trx_t*          trx,                    /*!< in: a transaction */
 
4028
        ibool           remove_also_table_sx_locks)/*!< in: also removes
 
4029
                                                table S and X locks */
 
4030
{
 
4031
        lock_t* lock;
 
4032
        lock_t* prev_lock;
 
4033
 
 
4034
        ut_ad(mutex_own(&kernel_mutex));
 
4035
 
 
4036
        lock = UT_LIST_GET_LAST(trx->trx_locks);
 
4037
 
 
4038
        while (lock != NULL) {
 
4039
                prev_lock = UT_LIST_GET_PREV(trx_locks, lock);
 
4040
 
 
4041
                if (lock_get_type_low(lock) == LOCK_REC
 
4042
                    && lock->index->table == table) {
 
4043
                        ut_a(!lock_get_wait(lock));
 
4044
 
 
4045
                        lock_rec_discard(lock);
 
4046
                } else if (lock_get_type_low(lock) & LOCK_TABLE
 
4047
                           && lock->un_member.tab_lock.table == table
 
4048
                           && (remove_also_table_sx_locks
 
4049
                               || !IS_LOCK_S_OR_X(lock))) {
 
4050
 
 
4051
                        ut_a(!lock_get_wait(lock));
 
4052
 
 
4053
                        lock_table_remove_low(lock);
 
4054
                }
 
4055
 
 
4056
                lock = prev_lock;
 
4057
        }
 
4058
}
 
4059
 
 
4060
/*********************************************************************//**
 
4061
Removes locks on a table to be dropped or truncated.
 
4062
If remove_also_table_sx_locks is TRUE then table-level S and X locks are
 
4063
also removed in addition to other table-level and record-level locks.
 
4064
No lock, that is going to be removed, is allowed to be a wait lock. */
 
4065
UNIV_INTERN
 
4066
void
 
4067
lock_remove_all_on_table(
 
4068
/*=====================*/
 
4069
        dict_table_t*   table,                  /*!< in: table to be dropped
 
4070
                                                or truncated */
 
4071
        ibool           remove_also_table_sx_locks)/*!< in: also removes
 
4072
                                                table S and X locks */
 
4073
{
 
4074
        lock_t* lock;
 
4075
        lock_t* prev_lock;
 
4076
 
 
4077
        mutex_enter(&kernel_mutex);
 
4078
 
 
4079
        lock = UT_LIST_GET_FIRST(table->locks);
 
4080
 
 
4081
        while (lock != NULL) {
 
4082
 
 
4083
                prev_lock = UT_LIST_GET_PREV(un_member.tab_lock.locks,
 
4084
                                             lock);
 
4085
 
 
4086
                /* If we should remove all locks (remove_also_table_sx_locks
 
4087
                is TRUE), or if the lock is not table-level S or X lock,
 
4088
                then check we are not going to remove a wait lock. */
 
4089
                if (remove_also_table_sx_locks
 
4090
                    || !(lock_get_type(lock) == LOCK_TABLE
 
4091
                         && IS_LOCK_S_OR_X(lock))) {
 
4092
 
 
4093
                        ut_a(!lock_get_wait(lock));
 
4094
                }
 
4095
 
 
4096
                lock_remove_all_on_table_for_trx(table, lock->trx,
 
4097
                                                 remove_also_table_sx_locks);
 
4098
 
 
4099
                if (prev_lock == NULL) {
 
4100
                        if (lock == UT_LIST_GET_FIRST(table->locks)) {
 
4101
                                /* lock was not removed, pick its successor */
 
4102
                                lock = UT_LIST_GET_NEXT(
 
4103
                                        un_member.tab_lock.locks, lock);
 
4104
                        } else {
 
4105
                                /* lock was removed, pick the first one */
 
4106
                                lock = UT_LIST_GET_FIRST(table->locks);
 
4107
                        }
 
4108
                } else if (UT_LIST_GET_NEXT(un_member.tab_lock.locks,
 
4109
                                            prev_lock) != lock) {
 
4110
                        /* If lock was removed by
 
4111
                        lock_remove_all_on_table_for_trx() then pick the
 
4112
                        successor of prev_lock ... */
 
4113
                        lock = UT_LIST_GET_NEXT(
 
4114
                                un_member.tab_lock.locks, prev_lock);
 
4115
                } else {
 
4116
                        /* ... otherwise pick the successor of lock. */
 
4117
                        lock = UT_LIST_GET_NEXT(
 
4118
                                un_member.tab_lock.locks, lock);
 
4119
                }
 
4120
        }
 
4121
 
 
4122
        mutex_exit(&kernel_mutex);
 
4123
}
 
4124
 
 
4125
/*===================== VALIDATION AND DEBUGGING  ====================*/
 
4126
 
 
4127
/*********************************************************************//**
 
4128
Prints info of a table lock. */
 
4129
UNIV_INTERN
 
4130
void
 
4131
lock_table_print(
 
4132
/*=============*/
 
4133
        FILE*           file,   /*!< in: file where to print */
 
4134
        const lock_t*   lock)   /*!< in: table type lock */
 
4135
{
 
4136
        ut_ad(mutex_own(&kernel_mutex));
 
4137
        ut_a(lock_get_type_low(lock) == LOCK_TABLE);
 
4138
 
 
4139
        fputs("TABLE LOCK table ", file);
 
4140
        ut_print_name(file, lock->trx, TRUE,
 
4141
                      lock->un_member.tab_lock.table->name);
 
4142
        fprintf(file, " trx id " TRX_ID_FMT,
 
4143
                TRX_ID_PREP_PRINTF(lock->trx->id));
 
4144
 
 
4145
        if (lock_get_mode(lock) == LOCK_S) {
 
4146
                fputs(" lock mode S", file);
 
4147
        } else if (lock_get_mode(lock) == LOCK_X) {
 
4148
                fputs(" lock mode X", file);
 
4149
        } else if (lock_get_mode(lock) == LOCK_IS) {
 
4150
                fputs(" lock mode IS", file);
 
4151
        } else if (lock_get_mode(lock) == LOCK_IX) {
 
4152
                fputs(" lock mode IX", file);
 
4153
        } else if (lock_get_mode(lock) == LOCK_AUTO_INC) {
 
4154
                fputs(" lock mode AUTO-INC", file);
 
4155
        } else {
 
4156
                fprintf(file, " unknown lock mode %lu",
 
4157
                        (ulong) lock_get_mode(lock));
 
4158
        }
 
4159
 
 
4160
        if (lock_get_wait(lock)) {
 
4161
                fputs(" waiting", file);
 
4162
        }
 
4163
 
 
4164
        putc('\n', file);
 
4165
}
 
4166
 
 
4167
/*********************************************************************//**
 
4168
Prints info of a record lock. */
 
4169
UNIV_INTERN
 
4170
void
 
4171
lock_rec_print(
 
4172
/*===========*/
 
4173
        FILE*           file,   /*!< in: file where to print */
 
4174
        const lock_t*   lock)   /*!< in: record type lock */
 
4175
{
 
4176
        const buf_block_t*      block;
 
4177
        ulint                   space;
 
4178
        ulint                   page_no;
 
4179
        ulint                   i;
 
4180
        mtr_t                   mtr;
 
4181
        mem_heap_t*             heap            = NULL;
 
4182
        ulint                   offsets_[REC_OFFS_NORMAL_SIZE];
 
4183
        ulint*                  offsets         = offsets_;
 
4184
        rec_offs_init(offsets_);
 
4185
 
 
4186
        ut_ad(mutex_own(&kernel_mutex));
 
4187
        ut_a(lock_get_type_low(lock) == LOCK_REC);
 
4188
 
 
4189
        space = lock->un_member.rec_lock.space;
 
4190
        page_no = lock->un_member.rec_lock.page_no;
 
4191
 
 
4192
        fprintf(file, "RECORD LOCKS space id %lu page no %lu n bits %lu ",
 
4193
                (ulong) space, (ulong) page_no,
 
4194
                (ulong) lock_rec_get_n_bits(lock));
 
4195
        dict_index_name_print(file, lock->trx, lock->index);
 
4196
        fprintf(file, " trx id " TRX_ID_FMT,
 
4197
                TRX_ID_PREP_PRINTF(lock->trx->id));
 
4198
 
 
4199
        if (lock_get_mode(lock) == LOCK_S) {
 
4200
                fputs(" lock mode S", file);
 
4201
        } else if (lock_get_mode(lock) == LOCK_X) {
 
4202
                fputs(" lock_mode X", file);
 
4203
        } else {
 
4204
                ut_error;
 
4205
        }
 
4206
 
 
4207
        if (lock_rec_get_gap(lock)) {
 
4208
                fputs(" locks gap before rec", file);
 
4209
        }
 
4210
 
 
4211
        if (lock_rec_get_rec_not_gap(lock)) {
 
4212
                fputs(" locks rec but not gap", file);
 
4213
        }
 
4214
 
 
4215
        if (lock_rec_get_insert_intention(lock)) {
 
4216
                fputs(" insert intention", file);
 
4217
        }
 
4218
 
 
4219
        if (lock_get_wait(lock)) {
 
4220
                fputs(" waiting", file);
 
4221
        }
 
4222
 
 
4223
        mtr_start(&mtr);
 
4224
 
 
4225
        putc('\n', file);
 
4226
 
 
4227
        block = buf_page_try_get(space, page_no, &mtr);
 
4228
 
 
4229
        if (block) {
 
4230
                for (i = 0; i < lock_rec_get_n_bits(lock); i++) {
 
4231
 
 
4232
                        if (lock_rec_get_nth_bit(lock, i)) {
 
4233
 
 
4234
                                const rec_t*    rec
 
4235
                                        = page_find_rec_with_heap_no(
 
4236
                                                buf_block_get_frame(block), i);
 
4237
                                offsets = rec_get_offsets(
 
4238
                                        rec, lock->index, offsets,
 
4239
                                        ULINT_UNDEFINED, &heap);
 
4240
 
 
4241
                                fprintf(file, "Record lock, heap no %lu ",
 
4242
                                        (ulong) i);
 
4243
                                rec_print_new(file, rec, offsets);
 
4244
                                putc('\n', file);
 
4245
                        }
 
4246
                }
 
4247
        } else {
 
4248
                for (i = 0; i < lock_rec_get_n_bits(lock); i++) {
 
4249
                        fprintf(file, "Record lock, heap no %lu\n", (ulong) i);
 
4250
                }
 
4251
        }
 
4252
 
 
4253
        mtr_commit(&mtr);
 
4254
        if (UNIV_LIKELY_NULL(heap)) {
 
4255
                mem_heap_free(heap);
 
4256
        }
 
4257
}
 
4258
 
 
4259
#ifdef UNIV_DEBUG
 
4260
/* Print the number of lock structs from lock_print_info_summary() only
 
4261
in non-production builds for performance reasons, see
 
4262
http://bugs.mysql.com/36942 */
 
4263
#define PRINT_NUM_OF_LOCK_STRUCTS
 
4264
#endif /* UNIV_DEBUG */
 
4265
 
 
4266
#ifdef PRINT_NUM_OF_LOCK_STRUCTS
 
4267
/*********************************************************************//**
 
4268
Calculates the number of record lock structs in the record lock hash table.
 
4269
@return number of record locks */
 
4270
static
 
4271
ulint
 
4272
lock_get_n_rec_locks(void)
 
4273
/*======================*/
 
4274
{
 
4275
        lock_t* lock;
 
4276
        ulint   n_locks = 0;
 
4277
        ulint   i;
 
4278
 
 
4279
        ut_ad(mutex_own(&kernel_mutex));
 
4280
 
 
4281
        for (i = 0; i < hash_get_n_cells(lock_sys->rec_hash); i++) {
 
4282
 
 
4283
                lock = HASH_GET_FIRST(lock_sys->rec_hash, i);
 
4284
 
 
4285
                while (lock) {
 
4286
                        n_locks++;
 
4287
 
 
4288
                        lock = HASH_GET_NEXT(hash, lock);
 
4289
                }
 
4290
        }
 
4291
 
 
4292
        return(n_locks);
 
4293
}
 
4294
#endif /* PRINT_NUM_OF_LOCK_STRUCTS */
 
4295
 
 
4296
/*********************************************************************//**
 
4297
Prints info of locks for all transactions. */
 
4298
UNIV_INTERN
 
4299
void
 
4300
lock_print_info_summary(
 
4301
/*====================*/
 
4302
        FILE*   file)   /*!< in: file where to print */
 
4303
{
 
4304
        /* We must protect the MySQL thd->query field with a MySQL mutex, and
 
4305
        because the MySQL mutex must be reserved before the kernel_mutex of
 
4306
        InnoDB, we call innobase_mysql_prepare_print_arbitrary_thd() here. */
 
4307
 
 
4308
        innobase_mysql_prepare_print_arbitrary_thd();
 
4309
        lock_mutex_enter_kernel();
 
4310
 
 
4311
        if (lock_deadlock_found) {
 
4312
                fputs("------------------------\n"
 
4313
                      "LATEST DETECTED DEADLOCK\n"
 
4314
                      "------------------------\n", file);
 
4315
 
 
4316
                ut_copy_file(file, lock_latest_err_file);
 
4317
        }
 
4318
 
 
4319
        fputs("------------\n"
 
4320
              "TRANSACTIONS\n"
 
4321
              "------------\n", file);
 
4322
 
 
4323
        fprintf(file, "Trx id counter " TRX_ID_FMT "\n",
 
4324
                TRX_ID_PREP_PRINTF(trx_sys->max_trx_id));
 
4325
 
 
4326
        fprintf(file,
 
4327
                "Purge done for trx's n:o < " TRX_ID_FMT
 
4328
                " undo n:o < " TRX_ID_FMT "\n",
 
4329
                TRX_ID_PREP_PRINTF(purge_sys->purge_trx_no),
 
4330
                TRX_ID_PREP_PRINTF(purge_sys->purge_undo_no));
 
4331
 
 
4332
        fprintf(file,
 
4333
                "History list length %lu\n",
 
4334
                (ulong) trx_sys->rseg_history_len);
 
4335
 
 
4336
#ifdef PRINT_NUM_OF_LOCK_STRUCTS
 
4337
        fprintf(file,
 
4338
                "Total number of lock structs in row lock hash table %lu\n",
 
4339
                (ulong) lock_get_n_rec_locks());
 
4340
#endif /* PRINT_NUM_OF_LOCK_STRUCTS */
 
4341
}
 
4342
 
 
4343
/*********************************************************************//**
 
4344
Prints info of locks for each transaction. */
 
4345
UNIV_INTERN
 
4346
void
 
4347
lock_print_info_all_transactions(
 
4348
/*=============================*/
 
4349
        FILE*   file)   /*!< in: file where to print */
 
4350
{
 
4351
        lock_t* lock;
 
4352
        ibool   load_page_first = TRUE;
 
4353
        ulint   nth_trx         = 0;
 
4354
        ulint   nth_lock        = 0;
 
4355
        ulint   i;
 
4356
        mtr_t   mtr;
 
4357
        trx_t*  trx;
 
4358
 
 
4359
        fprintf(file, "LIST OF TRANSACTIONS FOR EACH SESSION:\n");
 
4360
 
 
4361
        /* First print info on non-active transactions */
 
4362
 
 
4363
        trx = UT_LIST_GET_FIRST(trx_sys->mysql_trx_list);
 
4364
 
 
4365
        while (trx) {
 
4366
                if (trx->conc_state == TRX_NOT_STARTED) {
 
4367
                        fputs("---", file);
 
4368
                        trx_print(file, trx, 600);
 
4369
                }
 
4370
 
 
4371
                trx = UT_LIST_GET_NEXT(mysql_trx_list, trx);
 
4372
        }
 
4373
 
 
4374
loop:
 
4375
        trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
 
4376
 
 
4377
        i = 0;
 
4378
 
 
4379
        /* Since we temporarily release the kernel mutex when
 
4380
        reading a database page in below, variable trx may be
 
4381
        obsolete now and we must loop through the trx list to
 
4382
        get probably the same trx, or some other trx. */
 
4383
 
 
4384
        while (trx && (i < nth_trx)) {
 
4385
                trx = UT_LIST_GET_NEXT(trx_list, trx);
 
4386
                i++;
 
4387
        }
 
4388
 
 
4389
        if (trx == NULL) {
 
4390
                lock_mutex_exit_kernel();
 
4391
                innobase_mysql_end_print_arbitrary_thd();
 
4392
 
 
4393
                ut_ad(lock_validate());
 
4394
 
 
4395
                return;
 
4396
        }
 
4397
 
 
4398
        if (nth_lock == 0) {
 
4399
                fputs("---", file);
 
4400
                trx_print(file, trx, 600);
 
4401
 
 
4402
                if (trx->read_view) {
 
4403
                        fprintf(file,
 
4404
                                "Trx read view will not see trx with"
 
4405
                                " id >= " TRX_ID_FMT
 
4406
                                ", sees < " TRX_ID_FMT "\n",
 
4407
                                TRX_ID_PREP_PRINTF(
 
4408
                                        trx->read_view->low_limit_id),
 
4409
                                TRX_ID_PREP_PRINTF(
 
4410
                                        trx->read_view->up_limit_id));
 
4411
                }
 
4412
 
 
4413
                if (trx->que_state == TRX_QUE_LOCK_WAIT) {
 
4414
                        fprintf(file,
 
4415
                                "------- TRX HAS BEEN WAITING %lu SEC"
 
4416
                                " FOR THIS LOCK TO BE GRANTED:\n",
 
4417
                                (ulong) difftime(time(NULL),
 
4418
                                                 trx->wait_started));
 
4419
 
 
4420
                        if (lock_get_type_low(trx->wait_lock) == LOCK_REC) {
 
4421
                                lock_rec_print(file, trx->wait_lock);
 
4422
                        } else {
 
4423
                                lock_table_print(file, trx->wait_lock);
 
4424
                        }
 
4425
 
 
4426
                        fputs("------------------\n", file);
 
4427
                }
 
4428
        }
 
4429
 
 
4430
        if (!srv_print_innodb_lock_monitor) {
 
4431
                nth_trx++;
 
4432
                goto loop;
 
4433
        }
 
4434
 
 
4435
        i = 0;
 
4436
 
 
4437
        /* Look at the note about the trx loop above why we loop here:
 
4438
        lock may be an obsolete pointer now. */
 
4439
 
 
4440
        lock = UT_LIST_GET_FIRST(trx->trx_locks);
 
4441
 
 
4442
        while (lock && (i < nth_lock)) {
 
4443
                lock = UT_LIST_GET_NEXT(trx_locks, lock);
 
4444
                i++;
 
4445
        }
 
4446
 
 
4447
        if (lock == NULL) {
 
4448
                nth_trx++;
 
4449
                nth_lock = 0;
 
4450
 
 
4451
                goto loop;
 
4452
        }
 
4453
 
 
4454
        if (lock_get_type_low(lock) == LOCK_REC) {
 
4455
                if (load_page_first) {
 
4456
                        ulint   space   = lock->un_member.rec_lock.space;
 
4457
                        ulint   zip_size= fil_space_get_zip_size(space);
 
4458
                        ulint   page_no = lock->un_member.rec_lock.page_no;
 
4459
 
 
4460
                        if (UNIV_UNLIKELY(zip_size == ULINT_UNDEFINED)) {
 
4461
 
 
4462
                                /* It is a single table tablespace and
 
4463
                                the .ibd file is missing (TRUNCATE
 
4464
                                TABLE probably stole the locks): just
 
4465
                                print the lock without attempting to
 
4466
                                load the page in the buffer pool. */
 
4467
 
 
4468
                                fprintf(file, "RECORD LOCKS on"
 
4469
                                        " non-existing space %lu\n",
 
4470
                                        (ulong) space);
 
4471
                                goto print_rec;
 
4472
                        }
 
4473
 
 
4474
                        lock_mutex_exit_kernel();
 
4475
                        innobase_mysql_end_print_arbitrary_thd();
 
4476
 
 
4477
                        mtr_start(&mtr);
 
4478
 
 
4479
                        buf_page_get_with_no_latch(space, zip_size,
 
4480
                                                   page_no, &mtr);
 
4481
 
 
4482
                        mtr_commit(&mtr);
 
4483
 
 
4484
                        load_page_first = FALSE;
 
4485
 
 
4486
                        innobase_mysql_prepare_print_arbitrary_thd();
 
4487
                        lock_mutex_enter_kernel();
 
4488
 
 
4489
                        goto loop;
 
4490
                }
 
4491
 
 
4492
print_rec:
 
4493
                lock_rec_print(file, lock);
 
4494
        } else {
 
4495
                ut_ad(lock_get_type_low(lock) & LOCK_TABLE);
 
4496
 
 
4497
                lock_table_print(file, lock);
 
4498
        }
 
4499
 
 
4500
        load_page_first = TRUE;
 
4501
 
 
4502
        nth_lock++;
 
4503
 
 
4504
        if (nth_lock >= 10) {
 
4505
                fputs("10 LOCKS PRINTED FOR THIS TRX:"
 
4506
                      " SUPPRESSING FURTHER PRINTS\n",
 
4507
                      file);
 
4508
 
 
4509
                nth_trx++;
 
4510
                nth_lock = 0;
 
4511
 
 
4512
                goto loop;
 
4513
        }
 
4514
 
 
4515
        goto loop;
 
4516
}
 
4517
 
 
4518
#ifdef UNIV_DEBUG
 
4519
/*********************************************************************//**
 
4520
Validates the lock queue on a table.
 
4521
@return TRUE if ok */
 
4522
static
 
4523
ibool
 
4524
lock_table_queue_validate(
 
4525
/*======================*/
 
4526
        dict_table_t*   table)  /*!< in: table */
 
4527
{
 
4528
        lock_t* lock;
 
4529
 
 
4530
        ut_ad(mutex_own(&kernel_mutex));
 
4531
 
 
4532
        lock = UT_LIST_GET_FIRST(table->locks);
 
4533
 
 
4534
        while (lock) {
 
4535
                ut_a(((lock->trx)->conc_state == TRX_ACTIVE)
 
4536
                     || ((lock->trx)->conc_state == TRX_PREPARED)
 
4537
                     || ((lock->trx)->conc_state == TRX_COMMITTED_IN_MEMORY));
 
4538
 
 
4539
                if (!lock_get_wait(lock)) {
 
4540
 
 
4541
                        ut_a(!lock_table_other_has_incompatible(
 
4542
                                     lock->trx, 0, table,
 
4543
                                     lock_get_mode(lock)));
 
4544
                } else {
 
4545
 
 
4546
                        ut_a(lock_table_has_to_wait_in_queue(lock));
 
4547
                }
 
4548
 
 
4549
                lock = UT_LIST_GET_NEXT(un_member.tab_lock.locks, lock);
 
4550
        }
 
4551
 
 
4552
        return(TRUE);
 
4553
}
 
4554
 
 
4555
/*********************************************************************//**
 
4556
Validates the lock queue on a single record.
 
4557
@return TRUE if ok */
 
4558
static
 
4559
ibool
 
4560
lock_rec_queue_validate(
 
4561
/*====================*/
 
4562
        const buf_block_t*      block,  /*!< in: buffer block containing rec */
 
4563
        const rec_t*            rec,    /*!< in: record to look at */
 
4564
        dict_index_t*           index,  /*!< in: index, or NULL if not known */
 
4565
        const ulint*            offsets)/*!< in: rec_get_offsets(rec, index) */
 
4566
{
 
4567
        trx_t*  impl_trx;
 
4568
        lock_t* lock;
 
4569
        ulint   heap_no;
 
4570
 
 
4571
        ut_a(rec);
 
4572
        ut_a(block->frame == page_align(rec));
 
4573
        ut_ad(rec_offs_validate(rec, index, offsets));
 
4574
        ut_ad(!page_rec_is_comp(rec) == !rec_offs_comp(offsets));
 
4575
 
 
4576
        heap_no = page_rec_get_heap_no(rec);
 
4577
 
 
4578
        lock_mutex_enter_kernel();
 
4579
 
 
4580
        if (!page_rec_is_user_rec(rec)) {
 
4581
 
 
4582
                lock = lock_rec_get_first(block, heap_no);
 
4583
 
 
4584
                while (lock) {
 
4585
                        switch(lock->trx->conc_state) {
 
4586
                        case TRX_ACTIVE:
 
4587
                        case TRX_PREPARED:
 
4588
                        case TRX_COMMITTED_IN_MEMORY:
 
4589
                                break;
 
4590
                        default:
 
4591
                                ut_error;
 
4592
                        }
 
4593
 
 
4594
                        ut_a(trx_in_trx_list(lock->trx));
 
4595
 
 
4596
                        if (lock_get_wait(lock)) {
 
4597
                                ut_a(lock_rec_has_to_wait_in_queue(lock));
 
4598
                        }
 
4599
 
 
4600
                        if (index) {
 
4601
                                ut_a(lock->index == index);
 
4602
                        }
 
4603
 
 
4604
                        lock = lock_rec_get_next(heap_no, lock);
 
4605
                }
 
4606
 
 
4607
                lock_mutex_exit_kernel();
 
4608
 
 
4609
                return(TRUE);
 
4610
        }
 
4611
 
 
4612
        if (!index);
 
4613
        else if (dict_index_is_clust(index)) {
 
4614
 
 
4615
                impl_trx = lock_clust_rec_some_has_impl(rec, index, offsets);
 
4616
 
 
4617
                if (impl_trx
 
4618
                    && lock_rec_other_has_expl_req(LOCK_S, 0, LOCK_WAIT,
 
4619
                                                   block, heap_no, impl_trx)) {
 
4620
 
 
4621
                        ut_a(lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP,
 
4622
                                               block, heap_no, impl_trx));
 
4623
                }
 
4624
        } else {
 
4625
 
 
4626
                /* The kernel mutex may get released temporarily in the
 
4627
                next function call: we have to release lock table mutex
 
4628
                to obey the latching order */
 
4629
 
 
4630
                impl_trx = lock_sec_rec_some_has_impl_off_kernel(
 
4631
                        rec, index, offsets);
 
4632
 
 
4633
                if (impl_trx
 
4634
                    && lock_rec_other_has_expl_req(LOCK_S, 0, LOCK_WAIT,
 
4635
                                                   block, heap_no, impl_trx)) {
 
4636
 
 
4637
                        ut_a(lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP,
 
4638
                                               block, heap_no, impl_trx));
 
4639
                }
 
4640
        }
 
4641
 
 
4642
        lock = lock_rec_get_first(block, heap_no);
 
4643
 
 
4644
        while (lock) {
 
4645
                ut_a(lock->trx->conc_state == TRX_ACTIVE
 
4646
                     || lock->trx->conc_state == TRX_PREPARED
 
4647
                     || lock->trx->conc_state == TRX_COMMITTED_IN_MEMORY);
 
4648
                ut_a(trx_in_trx_list(lock->trx));
 
4649
 
 
4650
                if (index) {
 
4651
                        ut_a(lock->index == index);
 
4652
                }
 
4653
 
 
4654
                if (!lock_rec_get_gap(lock) && !lock_get_wait(lock)) {
 
4655
 
 
4656
                        enum lock_mode  mode;
 
4657
 
 
4658
                        if (lock_get_mode(lock) == LOCK_S) {
 
4659
                                mode = LOCK_X;
 
4660
                        } else {
 
4661
                                mode = LOCK_S;
 
4662
                        }
 
4663
                        ut_a(!lock_rec_other_has_expl_req(
 
4664
                                     mode, 0, 0, block, heap_no, lock->trx));
 
4665
 
 
4666
                } else if (lock_get_wait(lock) && !lock_rec_get_gap(lock)) {
 
4667
 
 
4668
                        ut_a(lock_rec_has_to_wait_in_queue(lock));
 
4669
                }
 
4670
 
 
4671
                lock = lock_rec_get_next(heap_no, lock);
 
4672
        }
 
4673
 
 
4674
        lock_mutex_exit_kernel();
 
4675
 
 
4676
        return(TRUE);
 
4677
}
 
4678
 
 
4679
/*********************************************************************//**
 
4680
Validates the record lock queues on a page.
 
4681
@return TRUE if ok */
 
4682
static
 
4683
ibool
 
4684
lock_rec_validate_page(
 
4685
/*===================*/
 
4686
        ulint   space,  /*!< in: space id */
 
4687
        ulint   page_no)/*!< in: page number */
 
4688
{
 
4689
        dict_index_t*   index;
 
4690
        buf_block_t*    block;
 
4691
        const page_t*   page;
 
4692
        lock_t*         lock;
 
4693
        const rec_t*    rec;
 
4694
        ulint           nth_lock        = 0;
 
4695
        ulint           nth_bit         = 0;
 
4696
        ulint           i;
 
4697
        ulint           zip_size;
 
4698
        mtr_t           mtr;
 
4699
        mem_heap_t*     heap            = NULL;
 
4700
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
 
4701
        ulint*          offsets         = offsets_;
 
4702
        rec_offs_init(offsets_);
 
4703
 
 
4704
        ut_ad(!mutex_own(&kernel_mutex));
 
4705
 
 
4706
        mtr_start(&mtr);
 
4707
 
 
4708
        zip_size = fil_space_get_zip_size(space);
 
4709
        ut_ad(zip_size != ULINT_UNDEFINED);
 
4710
        block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, &mtr);
 
4711
        buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
 
4712
 
 
4713
        page = block->frame;
 
4714
 
 
4715
        lock_mutex_enter_kernel();
 
4716
loop:
 
4717
        lock = lock_rec_get_first_on_page_addr(space, page_no);
 
4718
 
 
4719
        if (!lock) {
 
4720
                goto function_exit;
 
4721
        }
 
4722
 
 
4723
        for (i = 0; i < nth_lock; i++) {
 
4724
 
 
4725
                lock = lock_rec_get_next_on_page(lock);
 
4726
 
 
4727
                if (!lock) {
 
4728
                        goto function_exit;
 
4729
                }
 
4730
        }
 
4731
 
 
4732
        ut_a(trx_in_trx_list(lock->trx));
 
4733
        ut_a(lock->trx->conc_state == TRX_ACTIVE
 
4734
             || lock->trx->conc_state == TRX_PREPARED
 
4735
             || lock->trx->conc_state == TRX_COMMITTED_IN_MEMORY);
 
4736
 
 
4737
        for (i = nth_bit; i < lock_rec_get_n_bits(lock); i++) {
 
4738
 
 
4739
                if (i == 1 || lock_rec_get_nth_bit(lock, i)) {
 
4740
 
 
4741
                        index = lock->index;
 
4742
                        rec = page_find_rec_with_heap_no(page, i);
 
4743
                        ut_a(rec);
 
4744
                        offsets = rec_get_offsets(rec, index, offsets,
 
4745
                                                  ULINT_UNDEFINED, &heap);
 
4746
 
 
4747
                        fprintf(stderr,
 
4748
                                "Validating %lu %lu\n",
 
4749
                                (ulong) space, (ulong) page_no);
 
4750
 
 
4751
                        lock_mutex_exit_kernel();
 
4752
 
 
4753
                        lock_rec_queue_validate(block, rec, index, offsets);
 
4754
 
 
4755
                        lock_mutex_enter_kernel();
 
4756
 
 
4757
                        nth_bit = i + 1;
 
4758
 
 
4759
                        goto loop;
 
4760
                }
 
4761
        }
 
4762
 
 
4763
        nth_bit = 0;
 
4764
        nth_lock++;
 
4765
 
 
4766
        goto loop;
 
4767
 
 
4768
function_exit:
 
4769
        lock_mutex_exit_kernel();
 
4770
 
 
4771
        mtr_commit(&mtr);
 
4772
 
 
4773
        if (UNIV_LIKELY_NULL(heap)) {
 
4774
                mem_heap_free(heap);
 
4775
        }
 
4776
        return(TRUE);
 
4777
}
 
4778
 
 
4779
/*********************************************************************//**
 
4780
Validates the lock system.
 
4781
@return TRUE if ok */
 
4782
static
 
4783
ibool
 
4784
lock_validate(void)
 
4785
/*===============*/
 
4786
{
 
4787
        lock_t* lock;
 
4788
        trx_t*  trx;
 
4789
        dulint  limit;
 
4790
        ulint   space;
 
4791
        ulint   page_no;
 
4792
        ulint   i;
 
4793
 
 
4794
        lock_mutex_enter_kernel();
 
4795
 
 
4796
        trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
 
4797
 
 
4798
        while (trx) {
 
4799
                lock = UT_LIST_GET_FIRST(trx->trx_locks);
 
4800
 
 
4801
                while (lock) {
 
4802
                        if (lock_get_type_low(lock) & LOCK_TABLE) {
 
4803
 
 
4804
                                lock_table_queue_validate(
 
4805
                                        lock->un_member.tab_lock.table);
 
4806
                        }
 
4807
 
 
4808
                        lock = UT_LIST_GET_NEXT(trx_locks, lock);
 
4809
                }
 
4810
 
 
4811
                trx = UT_LIST_GET_NEXT(trx_list, trx);
 
4812
        }
 
4813
 
 
4814
        for (i = 0; i < hash_get_n_cells(lock_sys->rec_hash); i++) {
 
4815
 
 
4816
                limit = ut_dulint_zero;
 
4817
 
 
4818
                for (;;) {
 
4819
                        lock = HASH_GET_FIRST(lock_sys->rec_hash, i);
 
4820
 
 
4821
                        while (lock) {
 
4822
                                ut_a(trx_in_trx_list(lock->trx));
 
4823
 
 
4824
                                space = lock->un_member.rec_lock.space;
 
4825
                                page_no = lock->un_member.rec_lock.page_no;
 
4826
 
 
4827
                                if (ut_dulint_cmp(
 
4828
                                            ut_dulint_create(space, page_no),
 
4829
                                            limit) >= 0) {
 
4830
                                        break;
 
4831
                                }
 
4832
 
 
4833
                                lock = HASH_GET_NEXT(hash, lock);
 
4834
                        }
 
4835
 
 
4836
                        if (!lock) {
 
4837
 
 
4838
                                break;
 
4839
                        }
 
4840
 
 
4841
                        lock_mutex_exit_kernel();
 
4842
 
 
4843
                        lock_rec_validate_page(space, page_no);
 
4844
 
 
4845
                        lock_mutex_enter_kernel();
 
4846
 
 
4847
                        limit = ut_dulint_create(space, page_no + 1);
 
4848
                }
 
4849
        }
 
4850
 
 
4851
        lock_mutex_exit_kernel();
 
4852
 
 
4853
        return(TRUE);
 
4854
}
 
4855
#endif /* UNIV_DEBUG */
 
4856
/*============ RECORD LOCK CHECKS FOR ROW OPERATIONS ====================*/
 
4857
 
 
4858
/*********************************************************************//**
 
4859
Checks if locks of other transactions prevent an immediate insert of
 
4860
a record. If they do, first tests if the query thread should anyway
 
4861
be suspended for some reason; if not, then puts the transaction and
 
4862
the query thread to the lock wait state and inserts a waiting request
 
4863
for a gap x-lock to the lock queue.
 
4864
@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
 
4865
UNIV_INTERN
 
4866
ulint
 
4867
lock_rec_insert_check_and_lock(
 
4868
/*===========================*/
 
4869
        ulint           flags,  /*!< in: if BTR_NO_LOCKING_FLAG bit is
 
4870
                                set, does nothing */
 
4871
        const rec_t*    rec,    /*!< in: record after which to insert */
 
4872
        buf_block_t*    block,  /*!< in/out: buffer block of rec */
 
4873
        dict_index_t*   index,  /*!< in: index */
 
4874
        que_thr_t*      thr,    /*!< in: query thread */
 
4875
        mtr_t*          mtr,    /*!< in/out: mini-transaction */
 
4876
        ibool*          inherit)/*!< out: set to TRUE if the new
 
4877
                                inserted record maybe should inherit
 
4878
                                LOCK_GAP type locks from the successor
 
4879
                                record */
 
4880
{
 
4881
        const rec_t*    next_rec;
 
4882
        trx_t*          trx;
 
4883
        lock_t*         lock;
 
4884
        ulint           err;
 
4885
        ulint           next_rec_heap_no;
 
4886
 
 
4887
        ut_ad(block->frame == page_align(rec));
 
4888
 
 
4889
        if (flags & BTR_NO_LOCKING_FLAG) {
 
4890
 
 
4891
                return(DB_SUCCESS);
 
4892
        }
 
4893
 
 
4894
        trx = thr_get_trx(thr);
 
4895
        next_rec = page_rec_get_next_const(rec);
 
4896
        next_rec_heap_no = page_rec_get_heap_no(next_rec);
 
4897
 
 
4898
        lock_mutex_enter_kernel();
 
4899
 
 
4900
        /* When inserting a record into an index, the table must be at
 
4901
        least IX-locked or we must be building an index, in which case
 
4902
        the table must be at least S-locked. */
 
4903
        ut_ad(lock_table_has(trx, index->table, LOCK_IX)
 
4904
              || (*index->name == TEMP_INDEX_PREFIX
 
4905
                  && lock_table_has(trx, index->table, LOCK_S)));
 
4906
 
 
4907
        lock = lock_rec_get_first(block, next_rec_heap_no);
 
4908
 
 
4909
        if (UNIV_LIKELY(lock == NULL)) {
 
4910
                /* We optimize CPU time usage in the simplest case */
 
4911
 
 
4912
                lock_mutex_exit_kernel();
 
4913
 
 
4914
                if (!dict_index_is_clust(index)) {
 
4915
                        /* Update the page max trx id field */
 
4916
                        page_update_max_trx_id(block,
 
4917
                                               buf_block_get_page_zip(block),
 
4918
                                               trx->id, mtr);
 
4919
                }
 
4920
 
 
4921
                *inherit = FALSE;
 
4922
 
 
4923
                return(DB_SUCCESS);
 
4924
        }
 
4925
 
 
4926
        *inherit = TRUE;
 
4927
 
 
4928
        /* If another transaction has an explicit lock request which locks
 
4929
        the gap, waiting or granted, on the successor, the insert has to wait.
 
4930
 
 
4931
        An exception is the case where the lock by the another transaction
 
4932
        is a gap type lock which it placed to wait for its turn to insert. We
 
4933
        do not consider that kind of a lock conflicting with our insert. This
 
4934
        eliminates an unnecessary deadlock which resulted when 2 transactions
 
4935
        had to wait for their insert. Both had waiting gap type lock requests
 
4936
        on the successor, which produced an unnecessary deadlock. */
 
4937
 
 
4938
        if (lock_rec_other_has_conflicting(
 
4939
                    LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION,
 
4940
                    block, next_rec_heap_no, trx)) {
 
4941
 
 
4942
                /* Note that we may get DB_SUCCESS also here! */
 
4943
                err = lock_rec_enqueue_waiting(LOCK_X | LOCK_GAP
 
4944
                                               | LOCK_INSERT_INTENTION,
 
4945
                                               block, next_rec_heap_no,
 
4946
                                               index, thr);
 
4947
        } else {
 
4948
                err = DB_SUCCESS;
 
4949
        }
 
4950
 
 
4951
        lock_mutex_exit_kernel();
 
4952
 
 
4953
        if ((err == DB_SUCCESS) && !dict_index_is_clust(index)) {
 
4954
                /* Update the page max trx id field */
 
4955
                page_update_max_trx_id(block,
 
4956
                                       buf_block_get_page_zip(block),
 
4957
                                       trx->id, mtr);
 
4958
        }
 
4959
 
 
4960
#ifdef UNIV_DEBUG
 
4961
        {
 
4962
                mem_heap_t*     heap            = NULL;
 
4963
                ulint           offsets_[REC_OFFS_NORMAL_SIZE];
 
4964
                const ulint*    offsets;
 
4965
                rec_offs_init(offsets_);
 
4966
 
 
4967
                offsets = rec_get_offsets(next_rec, index, offsets_,
 
4968
                                          ULINT_UNDEFINED, &heap);
 
4969
                ut_ad(lock_rec_queue_validate(block,
 
4970
                                              next_rec, index, offsets));
 
4971
                if (UNIV_LIKELY_NULL(heap)) {
 
4972
                        mem_heap_free(heap);
 
4973
                }
 
4974
        }
 
4975
#endif /* UNIV_DEBUG */
 
4976
 
 
4977
        return(err);
 
4978
}
 
4979
 
 
4980
/*********************************************************************//**
 
4981
If a transaction has an implicit x-lock on a record, but no explicit x-lock
 
4982
set on the record, sets one for it. NOTE that in the case of a secondary
 
4983
index, the kernel mutex may get temporarily released. */
 
4984
static
 
4985
void
 
4986
lock_rec_convert_impl_to_expl(
 
4987
/*==========================*/
 
4988
        const buf_block_t*      block,  /*!< in: buffer block of rec */
 
4989
        const rec_t*            rec,    /*!< in: user record on page */
 
4990
        dict_index_t*           index,  /*!< in: index of record */
 
4991
        const ulint*            offsets)/*!< in: rec_get_offsets(rec, index) */
 
4992
{
 
4993
        trx_t*  impl_trx;
 
4994
 
 
4995
        ut_ad(mutex_own(&kernel_mutex));
 
4996
        ut_ad(page_rec_is_user_rec(rec));
 
4997
        ut_ad(rec_offs_validate(rec, index, offsets));
 
4998
        ut_ad(!page_rec_is_comp(rec) == !rec_offs_comp(offsets));
 
4999
 
 
5000
        if (dict_index_is_clust(index)) {
 
5001
                impl_trx = lock_clust_rec_some_has_impl(rec, index, offsets);
 
5002
        } else {
 
5003
                impl_trx = lock_sec_rec_some_has_impl_off_kernel(
 
5004
                        rec, index, offsets);
 
5005
        }
 
5006
 
 
5007
        if (impl_trx) {
 
5008
                ulint   heap_no = page_rec_get_heap_no(rec);
 
5009
 
 
5010
                /* If the transaction has no explicit x-lock set on the
 
5011
                record, set one for it */
 
5012
 
 
5013
                if (!lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP, block,
 
5014
                                       heap_no, impl_trx)) {
 
5015
 
 
5016
                        lock_rec_add_to_queue(
 
5017
                                LOCK_REC | LOCK_X | LOCK_REC_NOT_GAP,
 
5018
                                block, heap_no, index, impl_trx);
 
5019
                }
 
5020
        }
 
5021
}
 
5022
 
 
5023
/*********************************************************************//**
 
5024
Checks if locks of other transactions prevent an immediate modify (update,
 
5025
delete mark, or delete unmark) of a clustered index record. If they do,
 
5026
first tests if the query thread should anyway be suspended for some
 
5027
reason; if not, then puts the transaction and the query thread to the
 
5028
lock wait state and inserts a waiting request for a record x-lock to the
 
5029
lock queue.
 
5030
@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
 
5031
UNIV_INTERN
 
5032
ulint
 
5033
lock_clust_rec_modify_check_and_lock(
 
5034
/*=================================*/
 
5035
        ulint                   flags,  /*!< in: if BTR_NO_LOCKING_FLAG
 
5036
                                        bit is set, does nothing */
 
5037
        const buf_block_t*      block,  /*!< in: buffer block of rec */
 
5038
        const rec_t*            rec,    /*!< in: record which should be
 
5039
                                        modified */
 
5040
        dict_index_t*           index,  /*!< in: clustered index */
 
5041
        const ulint*            offsets,/*!< in: rec_get_offsets(rec, index) */
 
5042
        que_thr_t*              thr)    /*!< in: query thread */
 
5043
{
 
5044
        ulint   err;
 
5045
        ulint   heap_no;
 
5046
 
 
5047
        ut_ad(rec_offs_validate(rec, index, offsets));
 
5048
        ut_ad(dict_index_is_clust(index));
 
5049
        ut_ad(block->frame == page_align(rec));
 
5050
 
 
5051
        if (flags & BTR_NO_LOCKING_FLAG) {
 
5052
 
 
5053
                return(DB_SUCCESS);
 
5054
        }
 
5055
 
 
5056
        heap_no = rec_offs_comp(offsets)
 
5057
                ? rec_get_heap_no_new(rec)
 
5058
                : rec_get_heap_no_old(rec);
 
5059
 
 
5060
        lock_mutex_enter_kernel();
 
5061
 
 
5062
        ut_ad(lock_table_has(thr_get_trx(thr), index->table, LOCK_IX));
 
5063
 
 
5064
        /* If a transaction has no explicit x-lock set on the record, set one
 
5065
        for it */
 
5066
 
 
5067
        lock_rec_convert_impl_to_expl(block, rec, index, offsets);
 
5068
 
 
5069
        err = lock_rec_lock(TRUE, LOCK_X | LOCK_REC_NOT_GAP,
 
5070
                            block, heap_no, index, thr);
 
5071
 
 
5072
        lock_mutex_exit_kernel();
 
5073
 
 
5074
        ut_ad(lock_rec_queue_validate(block, rec, index, offsets));
 
5075
 
 
5076
        return(err);
 
5077
}
 
5078
 
 
5079
/*********************************************************************//**
 
5080
Checks if locks of other transactions prevent an immediate modify (delete
 
5081
mark or delete unmark) of a secondary index record.
 
5082
@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
 
5083
UNIV_INTERN
 
5084
ulint
 
5085
lock_sec_rec_modify_check_and_lock(
 
5086
/*===============================*/
 
5087
        ulint           flags,  /*!< in: if BTR_NO_LOCKING_FLAG
 
5088
                                bit is set, does nothing */
 
5089
        buf_block_t*    block,  /*!< in/out: buffer block of rec */
 
5090
        const rec_t*    rec,    /*!< in: record which should be
 
5091
                                modified; NOTE: as this is a secondary
 
5092
                                index, we always have to modify the
 
5093
                                clustered index record first: see the
 
5094
                                comment below */
 
5095
        dict_index_t*   index,  /*!< in: secondary index */
 
5096
        que_thr_t*      thr,    /*!< in: query thread */
 
5097
        mtr_t*          mtr)    /*!< in/out: mini-transaction */
 
5098
{
 
5099
        ulint   err;
 
5100
        ulint   heap_no;
 
5101
 
 
5102
        ut_ad(!dict_index_is_clust(index));
 
5103
        ut_ad(block->frame == page_align(rec));
 
5104
 
 
5105
        if (flags & BTR_NO_LOCKING_FLAG) {
 
5106
 
 
5107
                return(DB_SUCCESS);
 
5108
        }
 
5109
 
 
5110
        heap_no = page_rec_get_heap_no(rec);
 
5111
 
 
5112
        /* Another transaction cannot have an implicit lock on the record,
 
5113
        because when we come here, we already have modified the clustered
 
5114
        index record, and this would not have been possible if another active
 
5115
        transaction had modified this secondary index record. */
 
5116
 
 
5117
        lock_mutex_enter_kernel();
 
5118
 
 
5119
        ut_ad(lock_table_has(thr_get_trx(thr), index->table, LOCK_IX));
 
5120
 
 
5121
        err = lock_rec_lock(TRUE, LOCK_X | LOCK_REC_NOT_GAP,
 
5122
                            block, heap_no, index, thr);
 
5123
 
 
5124
        lock_mutex_exit_kernel();
 
5125
 
 
5126
#ifdef UNIV_DEBUG
 
5127
        {
 
5128
                mem_heap_t*     heap            = NULL;
 
5129
                ulint           offsets_[REC_OFFS_NORMAL_SIZE];
 
5130
                const ulint*    offsets;
 
5131
                rec_offs_init(offsets_);
 
5132
 
 
5133
                offsets = rec_get_offsets(rec, index, offsets_,
 
5134
                                          ULINT_UNDEFINED, &heap);
 
5135
                ut_ad(lock_rec_queue_validate(block, rec, index, offsets));
 
5136
                if (UNIV_LIKELY_NULL(heap)) {
 
5137
                        mem_heap_free(heap);
 
5138
                }
 
5139
        }
 
5140
#endif /* UNIV_DEBUG */
 
5141
 
 
5142
        if (err == DB_SUCCESS) {
 
5143
                /* Update the page max trx id field */
 
5144
                page_update_max_trx_id(block,
 
5145
                                       buf_block_get_page_zip(block),
 
5146
                                       thr_get_trx(thr)->id, mtr);
 
5147
        }
 
5148
 
 
5149
        return(err);
 
5150
}
 
5151
 
 
5152
/*********************************************************************//**
 
5153
Like the counterpart for a clustered index below, but now we read a
 
5154
secondary index record.
 
5155
@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
 
5156
UNIV_INTERN
 
5157
ulint
 
5158
lock_sec_rec_read_check_and_lock(
 
5159
/*=============================*/
 
5160
        ulint                   flags,  /*!< in: if BTR_NO_LOCKING_FLAG
 
5161
                                        bit is set, does nothing */
 
5162
        const buf_block_t*      block,  /*!< in: buffer block of rec */
 
5163
        const rec_t*            rec,    /*!< in: user record or page
 
5164
                                        supremum record which should
 
5165
                                        be read or passed over by a
 
5166
                                        read cursor */
 
5167
        dict_index_t*           index,  /*!< in: secondary index */
 
5168
        const ulint*            offsets,/*!< in: rec_get_offsets(rec, index) */
 
5169
        enum lock_mode          mode,   /*!< in: mode of the lock which
 
5170
                                        the read cursor should set on
 
5171
                                        records: LOCK_S or LOCK_X; the
 
5172
                                        latter is possible in
 
5173
                                        SELECT FOR UPDATE */
 
5174
        ulint                   gap_mode,/*!< in: LOCK_ORDINARY, LOCK_GAP, or
 
5175
                                        LOCK_REC_NOT_GAP */
 
5176
        que_thr_t*              thr)    /*!< in: query thread */
 
5177
{
 
5178
        ulint   err;
 
5179
        ulint   heap_no;
 
5180
 
 
5181
        ut_ad(!dict_index_is_clust(index));
 
5182
        ut_ad(block->frame == page_align(rec));
 
5183
        ut_ad(page_rec_is_user_rec(rec) || page_rec_is_supremum(rec));
 
5184
        ut_ad(rec_offs_validate(rec, index, offsets));
 
5185
        ut_ad(mode == LOCK_X || mode == LOCK_S);
 
5186
 
 
5187
        if (flags & BTR_NO_LOCKING_FLAG) {
 
5188
 
 
5189
                return(DB_SUCCESS);
 
5190
        }
 
5191
 
 
5192
        heap_no = page_rec_get_heap_no(rec);
 
5193
 
 
5194
        lock_mutex_enter_kernel();
 
5195
 
 
5196
        ut_ad(mode != LOCK_X
 
5197
              || lock_table_has(thr_get_trx(thr), index->table, LOCK_IX));
 
5198
        ut_ad(mode != LOCK_S
 
5199
              || lock_table_has(thr_get_trx(thr), index->table, LOCK_IS));
 
5200
 
 
5201
        /* Some transaction may have an implicit x-lock on the record only
 
5202
        if the max trx id for the page >= min trx id for the trx list or a
 
5203
        database recovery is running. */
 
5204
 
 
5205
        if (((ut_dulint_cmp(page_get_max_trx_id(block->frame),
 
5206
                            trx_list_get_min_trx_id()) >= 0)
 
5207
             || recv_recovery_is_on())
 
5208
            && !page_rec_is_supremum(rec)) {
 
5209
 
 
5210
                lock_rec_convert_impl_to_expl(block, rec, index, offsets);
 
5211
        }
 
5212
 
 
5213
        err = lock_rec_lock(FALSE, mode | gap_mode,
 
5214
                            block, heap_no, index, thr);
 
5215
 
 
5216
        lock_mutex_exit_kernel();
 
5217
 
 
5218
        ut_ad(lock_rec_queue_validate(block, rec, index, offsets));
 
5219
 
 
5220
        return(err);
 
5221
}
 
5222
 
 
5223
/*********************************************************************//**
 
5224
Checks if locks of other transactions prevent an immediate read, or passing
 
5225
over by a read cursor, of a clustered index record. If they do, first tests
 
5226
if the query thread should anyway be suspended for some reason; if not, then
 
5227
puts the transaction and the query thread to the lock wait state and inserts a
 
5228
waiting request for a record lock to the lock queue. Sets the requested mode
 
5229
lock on the record.
 
5230
@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
 
5231
UNIV_INTERN
 
5232
ulint
 
5233
lock_clust_rec_read_check_and_lock(
 
5234
/*===============================*/
 
5235
        ulint                   flags,  /*!< in: if BTR_NO_LOCKING_FLAG
 
5236
                                        bit is set, does nothing */
 
5237
        const buf_block_t*      block,  /*!< in: buffer block of rec */
 
5238
        const rec_t*            rec,    /*!< in: user record or page
 
5239
                                        supremum record which should
 
5240
                                        be read or passed over by a
 
5241
                                        read cursor */
 
5242
        dict_index_t*           index,  /*!< in: clustered index */
 
5243
        const ulint*            offsets,/*!< in: rec_get_offsets(rec, index) */
 
5244
        enum lock_mode          mode,   /*!< in: mode of the lock which
 
5245
                                        the read cursor should set on
 
5246
                                        records: LOCK_S or LOCK_X; the
 
5247
                                        latter is possible in
 
5248
                                        SELECT FOR UPDATE */
 
5249
        ulint                   gap_mode,/*!< in: LOCK_ORDINARY, LOCK_GAP, or
 
5250
                                        LOCK_REC_NOT_GAP */
 
5251
        que_thr_t*              thr)    /*!< in: query thread */
 
5252
{
 
5253
        ulint   err;
 
5254
        ulint   heap_no;
 
5255
 
 
5256
        ut_ad(dict_index_is_clust(index));
 
5257
        ut_ad(block->frame == page_align(rec));
 
5258
        ut_ad(page_rec_is_user_rec(rec) || page_rec_is_supremum(rec));
 
5259
        ut_ad(gap_mode == LOCK_ORDINARY || gap_mode == LOCK_GAP
 
5260
              || gap_mode == LOCK_REC_NOT_GAP);
 
5261
        ut_ad(rec_offs_validate(rec, index, offsets));
 
5262
 
 
5263
        if (flags & BTR_NO_LOCKING_FLAG) {
 
5264
 
 
5265
                return(DB_SUCCESS);
 
5266
        }
 
5267
 
 
5268
        heap_no = page_rec_get_heap_no(rec);
 
5269
 
 
5270
        lock_mutex_enter_kernel();
 
5271
 
 
5272
        ut_ad(mode != LOCK_X
 
5273
              || lock_table_has(thr_get_trx(thr), index->table, LOCK_IX));
 
5274
        ut_ad(mode != LOCK_S
 
5275
              || lock_table_has(thr_get_trx(thr), index->table, LOCK_IS));
 
5276
 
 
5277
        if (UNIV_LIKELY(heap_no != PAGE_HEAP_NO_SUPREMUM)) {
 
5278
 
 
5279
                lock_rec_convert_impl_to_expl(block, rec, index, offsets);
 
5280
        }
 
5281
 
 
5282
        err = lock_rec_lock(FALSE, mode | gap_mode,
 
5283
                            block, heap_no, index, thr);
 
5284
 
 
5285
        lock_mutex_exit_kernel();
 
5286
 
 
5287
        ut_ad(lock_rec_queue_validate(block, rec, index, offsets));
 
5288
 
 
5289
        return(err);
 
5290
}
 
5291
/*********************************************************************//**
 
5292
Checks if locks of other transactions prevent an immediate read, or passing
 
5293
over by a read cursor, of a clustered index record. If they do, first tests
 
5294
if the query thread should anyway be suspended for some reason; if not, then
 
5295
puts the transaction and the query thread to the lock wait state and inserts a
 
5296
waiting request for a record lock to the lock queue. Sets the requested mode
 
5297
lock on the record. This is an alternative version of
 
5298
lock_clust_rec_read_check_and_lock() that does not require the parameter
 
5299
"offsets".
 
5300
@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
 
5301
UNIV_INTERN
 
5302
ulint
 
5303
lock_clust_rec_read_check_and_lock_alt(
 
5304
/*===================================*/
 
5305
        ulint                   flags,  /*!< in: if BTR_NO_LOCKING_FLAG
 
5306
                                        bit is set, does nothing */
 
5307
        const buf_block_t*      block,  /*!< in: buffer block of rec */
 
5308
        const rec_t*            rec,    /*!< in: user record or page
 
5309
                                        supremum record which should
 
5310
                                        be read or passed over by a
 
5311
                                        read cursor */
 
5312
        dict_index_t*           index,  /*!< in: clustered index */
 
5313
        enum lock_mode          mode,   /*!< in: mode of the lock which
 
5314
                                        the read cursor should set on
 
5315
                                        records: LOCK_S or LOCK_X; the
 
5316
                                        latter is possible in
 
5317
                                        SELECT FOR UPDATE */
 
5318
        ulint                   gap_mode,/*!< in: LOCK_ORDINARY, LOCK_GAP, or
 
5319
                                        LOCK_REC_NOT_GAP */
 
5320
        que_thr_t*              thr)    /*!< in: query thread */
 
5321
{
 
5322
        mem_heap_t*     tmp_heap        = NULL;
 
5323
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
 
5324
        ulint*          offsets         = offsets_;
 
5325
        ulint           ret;
 
5326
        rec_offs_init(offsets_);
 
5327
 
 
5328
        offsets = rec_get_offsets(rec, index, offsets,
 
5329
                                  ULINT_UNDEFINED, &tmp_heap);
 
5330
        ret = lock_clust_rec_read_check_and_lock(flags, block, rec, index,
 
5331
                                                 offsets, mode, gap_mode, thr);
 
5332
        if (tmp_heap) {
 
5333
                mem_heap_free(tmp_heap);
 
5334
        }
 
5335
        return(ret);
 
5336
}
 
5337
 
 
5338
/*******************************************************************//**
 
5339
Release the last lock from the transaction's autoinc locks. */
 
5340
UNIV_INLINE
 
5341
void
 
5342
lock_release_autoinc_last_lock(
 
5343
/*===========================*/
 
5344
        ib_vector_t*    autoinc_locks)  /*!< in/out: vector of AUTOINC locks */
 
5345
{
 
5346
        ulint           last;
 
5347
        lock_t*         lock;
 
5348
 
 
5349
        ut_ad(mutex_own(&kernel_mutex));
 
5350
        ut_a(!ib_vector_is_empty(autoinc_locks));
 
5351
 
 
5352
        /* The lock to be release must be the last lock acquired. */
 
5353
        last = ib_vector_size(autoinc_locks) - 1;
 
5354
        lock = ib_vector_get(autoinc_locks, last);
 
5355
 
 
5356
        /* Should have only AUTOINC locks in the vector. */
 
5357
        ut_a(lock_get_mode(lock) == LOCK_AUTO_INC);
 
5358
        ut_a(lock_get_type(lock) == LOCK_TABLE);
 
5359
 
 
5360
        ut_a(lock->un_member.tab_lock.table != NULL);
 
5361
 
 
5362
        /* This will remove the lock from the trx autoinc_locks too. */
 
5363
        lock_table_dequeue(lock);
 
5364
}
 
5365
 
 
5366
/*******************************************************************//**
 
5367
Release all the transaction's autoinc locks. */
 
5368
UNIV_INTERN
 
5369
void
 
5370
lock_release_autoinc_locks(
 
5371
/*=======================*/
 
5372
        trx_t*          trx)            /*!< in/out: transaction */
 
5373
{
 
5374
        ut_ad(mutex_own(&kernel_mutex));
 
5375
 
 
5376
        ut_a(trx->autoinc_locks != NULL);
 
5377
 
 
5378
        /* We release the locks in the reverse order. This is to
 
5379
        avoid searching the vector for the element to delete at
 
5380
        the lower level. See (lock_table_remove_low()) for details. */
 
5381
        while (!ib_vector_is_empty(trx->autoinc_locks)) {
 
5382
 
 
5383
                /* lock_table_remove_low() will also remove the lock from
 
5384
                the transaction's autoinc_locks vector. */
 
5385
                lock_release_autoinc_last_lock(trx->autoinc_locks);
 
5386
        }
 
5387
 
 
5388
        /* Should release all locks. */
 
5389
        ut_a(ib_vector_is_empty(trx->autoinc_locks));
 
5390
}
 
5391
 
 
5392
/*******************************************************************//**
 
5393
Gets the type of a lock. Non-inline version for using outside of the
 
5394
lock module.
 
5395
@return LOCK_TABLE or LOCK_REC */
 
5396
UNIV_INTERN
 
5397
ulint
 
5398
lock_get_type(
 
5399
/*==========*/
 
5400
        const lock_t*   lock)   /*!< in: lock */
 
5401
{
 
5402
        return(lock_get_type_low(lock));
 
5403
}
 
5404
 
 
5405
/*******************************************************************//**
 
5406
Gets the id of the transaction owning a lock.
 
5407
@return transaction id */
 
5408
UNIV_INTERN
 
5409
ullint
 
5410
lock_get_trx_id(
 
5411
/*============*/
 
5412
        const lock_t*   lock)   /*!< in: lock */
 
5413
{
 
5414
        return(trx_get_id(lock->trx));
 
5415
}
 
5416
 
 
5417
/*******************************************************************//**
 
5418
Gets the mode of a lock in a human readable string.
 
5419
The string should not be free()'d or modified.
 
5420
@return lock mode */
 
5421
UNIV_INTERN
 
5422
const char*
 
5423
lock_get_mode_str(
 
5424
/*==============*/
 
5425
        const lock_t*   lock)   /*!< in: lock */
 
5426
{
 
5427
        ibool   is_gap_lock;
 
5428
 
 
5429
        is_gap_lock = lock_get_type_low(lock) == LOCK_REC
 
5430
                && lock_rec_get_gap(lock);
 
5431
 
 
5432
        switch (lock_get_mode(lock)) {
 
5433
        case LOCK_S:
 
5434
                if (is_gap_lock) {
 
5435
                        return("S,GAP");
 
5436
                } else {
 
5437
                        return("S");
 
5438
                }
 
5439
        case LOCK_X:
 
5440
                if (is_gap_lock) {
 
5441
                        return("X,GAP");
 
5442
                } else {
 
5443
                        return("X");
 
5444
                }
 
5445
        case LOCK_IS:
 
5446
                if (is_gap_lock) {
 
5447
                        return("IS,GAP");
 
5448
                } else {
 
5449
                        return("IS");
 
5450
                }
 
5451
        case LOCK_IX:
 
5452
                if (is_gap_lock) {
 
5453
                        return("IX,GAP");
 
5454
                } else {
 
5455
                        return("IX");
 
5456
                }
 
5457
        case LOCK_AUTO_INC:
 
5458
                return("AUTO_INC");
 
5459
        default:
 
5460
                return("UNKNOWN");
 
5461
        }
 
5462
}
 
5463
 
 
5464
/*******************************************************************//**
 
5465
Gets the type of a lock in a human readable string.
 
5466
The string should not be free()'d or modified.
 
5467
@return lock type */
 
5468
UNIV_INTERN
 
5469
const char*
 
5470
lock_get_type_str(
 
5471
/*==============*/
 
5472
        const lock_t*   lock)   /*!< in: lock */
 
5473
{
 
5474
        switch (lock_get_type_low(lock)) {
 
5475
        case LOCK_REC:
 
5476
                return("RECORD");
 
5477
        case LOCK_TABLE:
 
5478
                return("TABLE");
 
5479
        default:
 
5480
                return("UNKNOWN");
 
5481
        }
 
5482
}
 
5483
 
 
5484
/*******************************************************************//**
 
5485
Gets the table on which the lock is.
 
5486
@return table */
 
5487
UNIV_INLINE
 
5488
dict_table_t*
 
5489
lock_get_table(
 
5490
/*===========*/
 
5491
        const lock_t*   lock)   /*!< in: lock */
 
5492
{
 
5493
        switch (lock_get_type_low(lock)) {
 
5494
        case LOCK_REC:
 
5495
                return(lock->index->table);
 
5496
        case LOCK_TABLE:
 
5497
                return(lock->un_member.tab_lock.table);
 
5498
        default:
 
5499
                ut_error;
 
5500
                return(NULL);
 
5501
        }
 
5502
}
 
5503
 
 
5504
/*******************************************************************//**
 
5505
Gets the id of the table on which the lock is.
 
5506
@return id of the table */
 
5507
UNIV_INTERN
 
5508
ullint
 
5509
lock_get_table_id(
 
5510
/*==============*/
 
5511
        const lock_t*   lock)   /*!< in: lock */
 
5512
{
 
5513
        dict_table_t*   table;
 
5514
 
 
5515
        table = lock_get_table(lock);
 
5516
 
 
5517
        return((ullint)ut_conv_dulint_to_longlong(table->id));
 
5518
}
 
5519
 
 
5520
/*******************************************************************//**
 
5521
Gets the name of the table on which the lock is.
 
5522
The string should not be free()'d or modified.
 
5523
@return name of the table */
 
5524
UNIV_INTERN
 
5525
const char*
 
5526
lock_get_table_name(
 
5527
/*================*/
 
5528
        const lock_t*   lock)   /*!< in: lock */
 
5529
{
 
5530
        dict_table_t*   table;
 
5531
 
 
5532
        table = lock_get_table(lock);
 
5533
 
 
5534
        return(table->name);
 
5535
}
 
5536
 
 
5537
/*******************************************************************//**
 
5538
For a record lock, gets the index on which the lock is.
 
5539
@return index */
 
5540
UNIV_INTERN
 
5541
const dict_index_t*
 
5542
lock_rec_get_index(
 
5543
/*===============*/
 
5544
        const lock_t*   lock)   /*!< in: lock */
 
5545
{
 
5546
        ut_a(lock_get_type_low(lock) == LOCK_REC);
 
5547
 
 
5548
        return(lock->index);
 
5549
}
 
5550
 
 
5551
/*******************************************************************//**
 
5552
For a record lock, gets the name of the index on which the lock is.
 
5553
The string should not be free()'d or modified.
 
5554
@return name of the index */
 
5555
UNIV_INTERN
 
5556
const char*
 
5557
lock_rec_get_index_name(
 
5558
/*====================*/
 
5559
        const lock_t*   lock)   /*!< in: lock */
 
5560
{
 
5561
        ut_a(lock_get_type_low(lock) == LOCK_REC);
 
5562
 
 
5563
        return(lock->index->name);
 
5564
}
 
5565
 
 
5566
/*******************************************************************//**
 
5567
For a record lock, gets the tablespace number on which the lock is.
 
5568
@return tablespace number */
 
5569
UNIV_INTERN
 
5570
ulint
 
5571
lock_rec_get_space_id(
 
5572
/*==================*/
 
5573
        const lock_t*   lock)   /*!< in: lock */
 
5574
{
 
5575
        ut_a(lock_get_type_low(lock) == LOCK_REC);
 
5576
 
 
5577
        return(lock->un_member.rec_lock.space);
 
5578
}
 
5579
 
 
5580
/*******************************************************************//**
 
5581
For a record lock, gets the page number on which the lock is.
 
5582
@return page number */
 
5583
UNIV_INTERN
 
5584
ulint
 
5585
lock_rec_get_page_no(
 
5586
/*=================*/
 
5587
        const lock_t*   lock)   /*!< in: lock */
 
5588
{
 
5589
        ut_a(lock_get_type_low(lock) == LOCK_REC);
 
5590
 
 
5591
        return(lock->un_member.rec_lock.page_no);
 
5592
}