1
1
/*****************************************************************************
3
Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved.
3
Copyright (C) 1996, 2010, Innobase Oy. All Rights Reserved.
5
5
This program is free software; you can redistribute it and/or modify it under
6
6
the terms of the GNU General Public License as published by the Free Software
466
466
/* A sanity check: the trx_id in rec must be smaller than the global
467
467
trx id counter */
469
if (ut_dulint_cmp(trx_id, trx_sys->max_trx_id) >= 0) {
469
if (UNIV_UNLIKELY(trx_id >= trx_sys->max_trx_id)) {
470
470
ut_print_timestamp(stderr);
471
471
fputs(" InnoDB: Error: transaction id associated"
472
472
" with record\n",
479
479
" global trx id counter " TRX_ID_FMT "!\n"
480
480
"InnoDB: The table is corrupt. You have to do"
481
481
" dump + drop + reimport.\n",
482
TRX_ID_PREP_PRINTF(trx_id),
483
TRX_ID_PREP_PRINTF(trx_sys->max_trx_id));
482
trx_id, trx_sys->max_trx_id);
556
555
max_trx_id = page_get_max_trx_id(page_align(rec));
557
ut_ad(!ut_dulint_is_zero(max_trx_id));
559
return(ut_dulint_cmp(max_trx_id, view->up_limit_id) < 0);
558
return(max_trx_id < view->up_limit_id);
562
561
/*********************************************************************//**
568
567
ulint n_cells) /*!< in: number of slots in lock hash table */
570
lock_sys = mem_alloc(sizeof(lock_sys_t));
569
lock_sys = static_cast<lock_sys_t *>(mem_alloc(sizeof(lock_sys_t)));
572
571
lock_sys->rec_hash = hash_create(n_cells);
919
918
ut_ad(lock_get_type_low(lock2) == LOCK_REC);
921
920
if (trx != lock2->trx
922
&& !lock_mode_compatible(LOCK_MODE_MASK & type_mode,
921
&& !lock_mode_compatible(static_cast<lock_mode>(LOCK_MODE_MASK & type_mode),
923
922
lock_get_mode(lock2))) {
925
924
/* We have somewhat complex rules when gap type record locks
1147
1146
ut_ad(mutex_own(&kernel_mutex));
1149
lock = HASH_GET_FIRST(lock_sys->rec_hash,
1150
lock_rec_hash(space, page_no));
1148
lock = static_cast<lock_t *>(HASH_GET_FIRST(lock_sys->rec_hash,
1149
lock_rec_hash(space, page_no)));
1152
1151
if ((lock->un_member.rec_lock.space == space)
1153
1152
&& (lock->un_member.rec_lock.page_no == page_no)) {
1206
1205
hash = buf_block_get_lock_hash_val(block);
1208
lock = HASH_GET_FIRST(lock_sys->rec_hash, hash);
1207
lock = static_cast<lock_t *>(HASH_GET_FIRST(lock_sys->rec_hash, hash));
1211
1210
if ((lock->un_member.rec_lock.space == space)
1305
1304
size = sizeof(lock_t) + lock_rec_get_n_bits(lock) / 8;
1307
return(mem_heap_dup(heap, lock, size));
1306
return static_cast<lock_t *>(mem_heap_dup(heap, lock, size));
1310
1309
/*********************************************************************//**
1420
1419
if (lock->trx == trx
1421
1420
&& lock_mode_stronger_or_eq(lock_get_mode(lock),
1422
precise_mode & LOCK_MODE_MASK)
1421
static_cast<lock_mode>(precise_mode & LOCK_MODE_MASK))
1423
1422
&& !lock_get_wait(lock)
1424
1423
&& (!lock_rec_get_rec_not_gap(lock)
1425
1424
|| (precise_mode & LOCK_REC_NOT_GAP)
1592
1591
max trx id to the log, and therefore during recovery, this value
1593
1592
for a page may be incorrect. */
1595
if (!(ut_dulint_cmp(page_get_max_trx_id(page),
1596
trx_list_get_min_trx_id()) >= 0)
1594
if (page_get_max_trx_id(page) < trx_list_get_min_trx_id()
1597
1595
&& !recv_recovery_is_on()) {
1696
1694
n_bits = page_dir_get_n_heap(page) + LOCK_PAGE_BITMAP_MARGIN;
1697
1695
n_bytes = 1 + n_bits / 8;
1699
lock = mem_heap_alloc(trx->lock_heap, sizeof(lock_t) + n_bytes);
1697
lock = static_cast<lock_t *>(mem_heap_alloc(trx->lock_heap, sizeof(lock_t) + n_bytes));
1701
1699
UT_LIST_ADD_LAST(trx_locks, trx->trx_locks, lock);
1731
1729
Enqueues a waiting request for a lock which cannot be granted immediately.
1732
1730
Checks for deadlocks.
1733
1731
@return DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED, or
1734
DB_SUCCESS; DB_SUCCESS means that there was a deadlock, but another
1735
transaction was chosen as a victim, and we got the lock immediately:
1736
no need to wait then */
1732
DB_SUCCESS_LOCKED_REC; DB_SUCCESS_LOCKED_REC means that
1733
there was a deadlock, but another transaction was chosen as a victim,
1734
and we got the lock immediately: no need to wait then */
1739
1737
lock_rec_enqueue_waiting(
1740
1738
/*=====================*/
1741
1739
ulint type_mode,/*!< in: lock mode this
1819
1817
#ifdef UNIV_DEBUG
1820
1818
if (lock_print_waits) {
1821
fprintf(stderr, "Lock wait for trx %lu in index ",
1822
(ulong) ut_dulint_get_low(trx->id));
1819
fprintf(stderr, "Lock wait for trx " TRX_ID_FMT " in index ",
1823
1821
ut_print_name(stderr, trx, FALSE, index->name);
1825
1823
#endif /* UNIV_DEBUG */
1923
1921
return(lock_rec_create(type_mode, block, heap_no, index, trx));
1924
/** Record locking request status */
1925
enum lock_rec_req_status {
1926
/** Failed to acquire a lock */
1928
/** Succeeded in acquiring a lock (implicit or already acquired) */
1930
/** Explicitly created a new lock */
1931
LOCK_REC_SUCCESS_CREATED
1926
1934
/*********************************************************************//**
1927
1935
This is a fast routine for locking a record in the most common cases:
1928
1936
there are no explicit locks on the page, or there is just one lock, owned
1930
1938
which does NOT look at implicit locks! Checks lock compatibility within
1931
1939
explicit locks. This function sets a normal next-key lock, or in the case of
1932
1940
a page supremum record, a gap type lock.
1933
@return TRUE if locking succeeded */
1941
@return whether the locking succeeded */
1943
enum lock_rec_req_status
1936
1944
lock_rec_lock_fast(
1937
1945
/*===============*/
1938
1946
ibool impl, /*!< in: if TRUE, no lock is set
1971
1979
lock_rec_create(mode, block, heap_no, index, trx);
1982
return(LOCK_REC_SUCCESS_CREATED);
1977
1985
if (lock_rec_get_next_on_page(lock)) {
1987
return(LOCK_REC_FAIL);
1982
1990
if (lock->trx != trx
1983
1991
|| lock->type_mode != (mode | LOCK_REC)
1984
1992
|| lock_rec_get_n_bits(lock) <= heap_no) {
1994
return(LOCK_REC_FAIL);
1993
2001
if (!lock_rec_get_nth_bit(lock, heap_no)) {
1994
2002
lock_rec_set_nth_bit(lock, heap_no);
2003
return(LOCK_REC_SUCCESS_CREATED);
2007
return(LOCK_REC_SUCCESS);
2001
2010
/*********************************************************************//**
2003
2012
low-level function which does NOT look at implicit locks! Checks lock
2004
2013
compatibility within explicit locks. This function sets a normal next-key
2005
2014
lock, or in the case of a page supremum record, a gap type lock.
2006
@return DB_SUCCESS, DB_LOCK_WAIT, or error code */
2015
@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, DB_DEADLOCK,
2016
or DB_QUE_THR_SUSPENDED */
2009
2019
lock_rec_lock_slow(
2010
2020
/*===============*/
2011
2021
ibool impl, /*!< in: if TRUE, no lock is set
2041
2050
/* The trx already has a strong enough lock on rec: do
2045
} else if (lock_rec_other_has_conflicting(mode, block, heap_no, trx)) {
2053
} else if (lock_rec_other_has_conflicting(static_cast<lock_mode>(mode), block, heap_no, trx)) {
2047
2055
/* If another transaction has a non-gap conflicting request in
2048
2056
the queue, as this transaction does not have a lock strong
2049
2057
enough already granted on the record, we have to wait. */
2051
err = lock_rec_enqueue_waiting(mode, block, heap_no,
2055
/* Set the requested lock on the record */
2057
lock_rec_add_to_queue(LOCK_REC | mode, block,
2058
heap_no, index, trx);
2059
return(lock_rec_enqueue_waiting(mode, block, heap_no,
2062
/* Set the requested lock on the record */
2064
lock_rec_add_to_queue(LOCK_REC | mode, block,
2065
heap_no, index, trx);
2066
return(DB_SUCCESS_LOCKED_REC);
2067
2072
/*********************************************************************//**
2070
2075
which does NOT look at implicit locks! Checks lock compatibility within
2071
2076
explicit locks. This function sets a normal next-key lock, or in the case
2072
2077
of a page supremum record, a gap type lock.
2073
@return DB_SUCCESS, DB_LOCK_WAIT, or error code */
2078
@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, DB_DEADLOCK,
2079
or DB_QUE_THR_SUSPENDED */
2078
2084
ibool impl, /*!< in: if TRUE, no lock is set
2088
2094
dict_index_t* index, /*!< in: index of record */
2089
2095
que_thr_t* thr) /*!< in: query thread */
2093
2097
ut_ad(mutex_own(&kernel_mutex));
2094
2098
ut_ad((LOCK_MODE_MASK & mode) != LOCK_S
2095
2099
|| lock_table_has(thr_get_trx(thr), index->table, LOCK_IS));
2101
2105
|| mode - (LOCK_MODE_MASK & mode) == LOCK_REC_NOT_GAP
2102
2106
|| mode - (LOCK_MODE_MASK & mode) == 0);
2104
if (lock_rec_lock_fast(impl, mode, block, heap_no, index, thr)) {
2106
/* We try a simplified and faster subroutine for the most
2111
err = lock_rec_lock_slow(impl, mode, block,
2112
heap_no, index, thr);
2108
/* We try a simplified and faster subroutine for the most
2110
switch (lock_rec_lock_fast(impl, mode, block, heap_no, index, thr)) {
2111
case LOCK_REC_SUCCESS:
2113
case LOCK_REC_SUCCESS_CREATED:
2114
return(DB_SUCCESS_LOCKED_REC);
2116
return(lock_rec_lock_slow(impl, mode, block,
2117
heap_no, index, thr));
2118
2124
/*********************************************************************//**
2184
2190
#ifdef UNIV_DEBUG
2185
2191
if (lock_print_waits) {
2186
fprintf(stderr, "Lock wait for trx %lu ends\n",
2187
(ulong) ut_dulint_get_low(lock->trx->id));
2192
fprintf(stderr, "Lock wait for trx " TRX_ID_FMT " ends\n",
2189
2195
#endif /* UNIV_DEBUG */
3473
3479
#endif /* UNIV_DEBUG */
3475
if (trx_weight_cmp(wait_lock->trx,
3481
if (trx_weight_ge(wait_lock->trx, start)) {
3477
3482
/* Our recursion starting point
3478
3483
transaction is 'smaller', let us
3479
3484
choose 'start' as the victim and roll
3591
3596
ib_vector_push(trx->autoinc_locks, lock);
3593
lock = mem_heap_alloc(trx->lock_heap, sizeof(lock_t));
3598
lock = static_cast<lock_t *>(mem_heap_alloc(trx->lock_heap, sizeof(lock_t)));
3596
3601
UT_LIST_ADD_LAST(trx_locks, trx->trx_locks, lock);
3733
3738
/* Deadlock resolution chose another transaction as a victim,
3734
3739
and we accidentally got our lock granted! */
3741
return(DB_SUCCESS_LOCKED_REC);
3739
3744
trx->que_state = TRX_QUE_LOCK_WAIT;
3941
3946
mutex_enter(&kernel_mutex);
3943
lock = lock_rec_get_first(block, heap_no);
3948
first_lock = lock_rec_get_first(block, heap_no);
3945
3950
/* Find the last lock with the same lock_mode and transaction
3946
3951
from the record. */
3948
while (lock != NULL) {
3953
for (lock = first_lock; lock != NULL;
3954
lock = lock_rec_get_next(heap_no, lock)) {
3949
3955
if (lock->trx == trx && lock_get_mode(lock) == lock_mode) {
3950
release_lock = lock;
3951
3956
ut_a(!lock_get_wait(lock));
3957
lock_rec_reset_nth_bit(lock, heap_no);
3954
lock = lock_rec_get_next(heap_no, lock);
3957
/* If a record lock is found, release the record lock */
3959
if (UNIV_LIKELY(release_lock != NULL)) {
3960
lock_rec_reset_nth_bit(release_lock, heap_no);
3962
mutex_exit(&kernel_mutex);
3963
ut_print_timestamp(stderr);
3965
" InnoDB: Error: unlock row could not"
3966
" find a %lu mode lock on the record\n",
3962
mutex_exit(&kernel_mutex);
3963
ut_print_timestamp(stderr);
3965
" InnoDB: Error: unlock row could not"
3966
" find a %lu mode lock on the record\n",
3972
3972
/* Check if we can now grant waiting lock requests */
3974
lock = lock_rec_get_first(block, heap_no);
3976
while (lock != NULL) {
3974
for (lock = first_lock; lock != NULL;
3975
lock = lock_rec_get_next(heap_no, lock)) {
3977
3976
if (lock_get_wait(lock)
3978
3977
&& !lock_rec_has_to_wait_in_queue(lock)) {
3980
3979
/* Grant the lock */
3981
3980
lock_grant(lock);
3984
lock = lock_rec_get_next(heap_no, lock);
3987
3984
mutex_exit(&kernel_mutex);
4017
4014
ut_ad(lock_get_type_low(lock) & LOCK_TABLE);
4019
4016
if (lock_get_mode(lock) != LOCK_IS
4020
&& !ut_dulint_is_zero(trx->undo_no)) {
4017
&& trx->undo_no != 0) {
4022
4019
/* The trx may have modified the table. We
4023
4020
block the use of the MySQL query cache for
4216
4213
fputs("TABLE LOCK table ", file);
4217
4214
ut_print_name(file, lock->trx, TRUE,
4218
4215
lock->un_member.tab_lock.table->name);
4219
fprintf(file, " trx id " TRX_ID_FMT,
4220
TRX_ID_PREP_PRINTF(lock->trx->id));
4216
fprintf(file, " trx id " TRX_ID_FMT, lock->trx->id);
4222
4218
if (lock_get_mode(lock) == LOCK_S) {
4223
4219
fputs(" lock mode S", file);
4270
4266
(ulong) space, (ulong) page_no,
4271
4267
(ulong) lock_rec_get_n_bits(lock));
4272
4268
dict_index_name_print(file, lock->trx, lock->index);
4273
fprintf(file, " trx id " TRX_ID_FMT,
4274
TRX_ID_PREP_PRINTF(lock->trx->id));
4269
fprintf(file, " trx id " TRX_ID_FMT, lock->trx->id);
4276
4271
if (lock_get_mode(lock) == LOCK_S) {
4277
4272
fputs(" lock mode S", file);
4406
4401
"------------\n", file);
4408
4403
fprintf(file, "Trx id counter " TRX_ID_FMT "\n",
4409
TRX_ID_PREP_PRINTF(trx_sys->max_trx_id));
4404
trx_sys->max_trx_id);
4412
4407
"Purge done for trx's n:o < " TRX_ID_FMT
4413
4408
" undo n:o < " TRX_ID_FMT "\n",
4414
TRX_ID_PREP_PRINTF(purge_sys->purge_trx_no),
4415
TRX_ID_PREP_PRINTF(purge_sys->purge_undo_no));
4409
purge_sys->purge_trx_no,
4410
purge_sys->purge_undo_no);
4418
4413
"History list length %lu\n",
4489
4484
"Trx read view will not see trx with"
4490
4485
" id >= " TRX_ID_FMT
4491
4486
", sees < " TRX_ID_FMT "\n",
4493
trx->read_view->low_limit_id),
4495
trx->read_view->up_limit_id));
4487
trx->read_view->low_limit_id,
4488
trx->read_view->up_limit_id);
4498
4491
if (trx->que_state == TRX_QUE_LOCK_WAIT) {
4861
4854
offsets = rec_get_offsets(rec, index, offsets,
4862
4855
ULINT_UNDEFINED, &heap);
4864
4857
fprintf(stderr,
4865
4858
"Validating %lu %lu\n",
4866
4859
(ulong) space, (ulong) page_no);
4868
4861
lock_mutex_exit_kernel();
4870
4863
/* If this thread is holding the file space
4936
4929
for (i = 0; i < hash_get_n_cells(lock_sys->rec_hash); i++) {
4938
limit = ut_dulint_zero;
4941
4934
lock = HASH_GET_FIRST(lock_sys->rec_hash, i);
4937
ib_uint64_t space_page;
4944
4938
ut_a(trx_in_trx_list(lock->trx));
4946
4940
space = lock->un_member.rec_lock.space;
4947
4941
page_no = lock->un_member.rec_lock.page_no;
4950
ut_dulint_create(space, page_no),
4943
space_page = ut_ull_create(space, page_no);
4945
if (space_page >= limit) {
5058
5052
on the successor, which produced an unnecessary deadlock. */
5060
5054
if (lock_rec_other_has_conflicting(
5061
LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION,
5055
static_cast<lock_mode>(LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION),
5062
5056
block, next_rec_heap_no, trx)) {
5064
5058
/* Note that we may get DB_SUCCESS also here! */
5073
5067
lock_mutex_exit_kernel();
5075
if ((err == DB_SUCCESS) && !dict_index_is_clust(index)) {
5070
case DB_SUCCESS_LOCKED_REC:
5074
if (dict_index_is_clust(index)) {
5076
5077
/* Update the page max trx id field */
5077
5078
page_update_max_trx_id(block,
5078
5079
buf_block_get_page_zip(block),
5262
5267
#endif /* UNIV_DEBUG */
5264
if (err == DB_SUCCESS) {
5269
if (err == DB_SUCCESS || err == DB_SUCCESS_LOCKED_REC) {
5265
5270
/* Update the page max trx id field */
5271
/* It might not be necessary to do this if
5272
err == DB_SUCCESS (no new lock created),
5273
but it should not cost too much performance. */
5266
5274
page_update_max_trx_id(block,
5267
5275
buf_block_get_page_zip(block),
5268
5276
thr_get_trx(thr)->id, mtr);
5274
5283
/*********************************************************************//**
5275
Like the counterpart for a clustered index below, but now we read a
5284
Like lock_clust_rec_read_check_and_lock(), but reads a
5276
5285
secondary index record.
5277
@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
5286
@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, DB_DEADLOCK,
5287
or DB_QUE_THR_SUSPENDED */
5280
5290
lock_sec_rec_read_check_and_lock(
5281
5291
/*=============================*/
5282
5292
ulint flags, /*!< in: if BTR_NO_LOCKING_FLAG
5324
5334
if the max trx id for the page >= min trx id for the trx list or a
5325
5335
database recovery is running. */
5327
if (((ut_dulint_cmp(page_get_max_trx_id(block->frame),
5328
trx_list_get_min_trx_id()) >= 0)
5337
if ((page_get_max_trx_id(block->frame) >= trx_list_get_min_trx_id()
5329
5338
|| recv_recovery_is_on())
5330
5339
&& !page_rec_is_supremum(rec)) {
5349
5362
puts the transaction and the query thread to the lock wait state and inserts a
5350
5363
waiting request for a record lock to the lock queue. Sets the requested mode
5351
5364
lock on the record.
5352
@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
5365
@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, DB_DEADLOCK,
5366
or DB_QUE_THR_SUSPENDED */
5355
5369
lock_clust_rec_read_check_and_lock(
5356
5370
/*===============================*/
5357
5371
ulint flags, /*!< in: if BTR_NO_LOCKING_FLAG
5444
5458
mem_heap_t* tmp_heap = NULL;
5445
5459
ulint offsets_[REC_OFFS_NORMAL_SIZE];
5446
5460
ulint* offsets = offsets_;
5448
5462
rec_offs_init(offsets_);
5450
5464
offsets = rec_get_offsets(rec, index, offsets,
5451
5465
ULINT_UNDEFINED, &tmp_heap);
5452
ret = lock_clust_rec_read_check_and_lock(flags, block, rec, index,
5466
err = lock_clust_rec_read_check_and_lock(flags, block, rec, index,
5453
5467
offsets, mode, gap_mode, thr);
5454
5468
if (tmp_heap) {
5455
5469
mem_heap_free(tmp_heap);
5472
if (UNIV_UNLIKELY(err == DB_SUCCESS_LOCKED_REC)) {
5460
5479
/*******************************************************************//**
5474
5493
/* The lock to be release must be the last lock acquired. */
5475
5494
last = ib_vector_size(autoinc_locks) - 1;
5476
lock = ib_vector_get(autoinc_locks, last);
5495
lock = static_cast<lock_t *>(ib_vector_get(autoinc_locks, last));
5478
5497
/* Should have only AUTOINC locks in the vector. */
5479
5498
ut_a(lock_get_mode(lock) == LOCK_AUTO_INC);
5542
5561
Gets the id of the transaction owning a lock.
5543
5562
@return transaction id */
5546
5565
lock_get_trx_id(
5547
5566
/*============*/
5548
5567
const lock_t* lock) /*!< in: lock */
5550
return(trx_get_id(lock->trx));
5569
return(lock->trx->id);
5553
5572
/*******************************************************************//**