~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Padraig O'Sullivan
  • Date: 2009-09-13 01:03:01 UTC
  • mto: (1126.9.2 captain-20090915-01)
  • mto: This revision was merged to the branch mainline in revision 1133.
  • Revision ID: osullivan.padraig@gmail.com-20090913010301-tcvvezipx1124acy
Added calls to the dtrace delete begin/end probes.

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
 
}