~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2010-01-22 00:53:13 UTC
  • Revision ID: brian@gaz-20100122005313-jmizcbcdi1lt4tcx
Revert db patch.

Show diffs side-by-side

added added

removed removed

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