~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

Merge initial InnoDB+ import.

This was applied by generating a patch between MySQL 5.1.50 InnoDB plugin and
the just-merged innodb+ from mysql-trunk revision-id: vasil.dimov@oracle.com-20100422110752-1zowoqxel5xx3z2e

Then, some manual merge resolving and it worked. This should make it much
easier to merge the rest of InnoDB 1.1 and 1.2 from the mysql tree using
my bzr-reapply script.

This takes us to InnoDB 1.1.1(ish).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1731
1731
Enqueues a waiting request for a lock which cannot be granted immediately.
1732
1732
Checks for deadlocks.
1733
1733
@return DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED, or
1734
 
DB_SUCCESS_LOCKED_REC; DB_SUCCESS_LOCKED_REC means that
1735
 
there was a deadlock, but another transaction was chosen as a victim,
1736
 
and we got the lock immediately: no need to wait then */
 
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 */
1737
1737
static
1738
 
enum db_err
 
1738
ulint
1739
1739
lock_rec_enqueue_waiting(
1740
1740
/*=====================*/
1741
1741
        ulint                   type_mode,/*!< in: lock mode this
1807
1807
 
1808
1808
        if (trx->wait_lock == NULL) {
1809
1809
 
1810
 
                return(DB_SUCCESS_LOCKED_REC);
 
1810
                return(DB_SUCCESS);
1811
1811
        }
1812
1812
 
1813
1813
        trx->que_state = TRX_QUE_LOCK_WAIT;
1923
1923
        return(lock_rec_create(type_mode, block, heap_no, index, trx));
1924
1924
}
1925
1925
 
1926
 
/** Record locking request status */
1927
 
enum lock_rec_req_status {
1928
 
        /** Failed to acquire a lock */
1929
 
        LOCK_REC_FAIL,
1930
 
        /** Succeeded in acquiring a lock (implicit or already acquired) */
1931
 
        LOCK_REC_SUCCESS,
1932
 
        /** Explicitly created a new lock */
1933
 
        LOCK_REC_SUCCESS_CREATED
1934
 
};
1935
 
 
1936
1926
/*********************************************************************//**
1937
1927
This is a fast routine for locking a record in the most common cases:
1938
1928
there are no explicit locks on the page, or there is just one lock, owned
1940
1930
which does NOT look at implicit locks! Checks lock compatibility within
1941
1931
explicit locks. This function sets a normal next-key lock, or in the case of
1942
1932
a page supremum record, a gap type lock.
1943
 
@return whether the locking succeeded */
 
1933
@return TRUE if locking succeeded */
1944
1934
UNIV_INLINE
1945
 
enum lock_rec_req_status
 
1935
ibool
1946
1936
lock_rec_lock_fast(
1947
1937
/*===============*/
1948
1938
        ibool                   impl,   /*!< in: if TRUE, no lock is set
1981
1971
                        lock_rec_create(mode, block, heap_no, index, trx);
1982
1972
                }
1983
1973
 
1984
 
                return(LOCK_REC_SUCCESS_CREATED);
 
1974
                return(TRUE);
1985
1975
        }
1986
1976
 
1987
1977
        if (lock_rec_get_next_on_page(lock)) {
1988
1978
 
1989
 
                return(LOCK_REC_FAIL);
 
1979
                return(FALSE);
1990
1980
        }
1991
1981
 
1992
1982
        if (lock->trx != trx
1993
1983
            || lock->type_mode != (mode | LOCK_REC)
1994
1984
            || lock_rec_get_n_bits(lock) <= heap_no) {
1995
1985
 
1996
 
                return(LOCK_REC_FAIL);
 
1986
                return(FALSE);
1997
1987
        }
1998
1988
 
1999
1989
        if (!impl) {
2002
1992
 
2003
1993
                if (!lock_rec_get_nth_bit(lock, heap_no)) {
2004
1994
                        lock_rec_set_nth_bit(lock, heap_no);
2005
 
                        return(LOCK_REC_SUCCESS_CREATED);
2006
1995
                }
2007
1996
        }
2008
1997
 
2009
 
        return(LOCK_REC_SUCCESS);
 
1998
        return(TRUE);
2010
1999
}
2011
2000
 
2012
2001
/*********************************************************************//**
2014
2003
low-level function which does NOT look at implicit locks! Checks lock
2015
2004
compatibility within explicit locks. This function sets a normal next-key
2016
2005
lock, or in the case of a page supremum record, a gap type lock.
2017
 
@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, DB_DEADLOCK,
2018
 
or DB_QUE_THR_SUSPENDED */
 
2006
@return DB_SUCCESS, DB_LOCK_WAIT, or error code */
2019
2007
static
2020
 
enum db_err
 
2008
ulint
2021
2009
lock_rec_lock_slow(
2022
2010
/*===============*/
2023
2011
        ibool                   impl,   /*!< in: if TRUE, no lock is set
2034
2022
        que_thr_t*              thr)    /*!< in: query thread */
2035
2023
{
2036
2024
        trx_t*  trx;
 
2025
        ulint   err;
2037
2026
 
2038
2027
        ut_ad(mutex_own(&kernel_mutex));
2039
2028
        ut_ad((LOCK_MODE_MASK & mode) != LOCK_S
2052
2041
                /* The trx already has a strong enough lock on rec: do
2053
2042
                nothing */
2054
2043
 
 
2044
                err = DB_SUCCESS;
2055
2045
        } else if (lock_rec_other_has_conflicting(mode, block, heap_no, trx)) {
2056
2046
 
2057
2047
                /* If another transaction has a non-gap conflicting request in
2058
2048
                the queue, as this transaction does not have a lock strong
2059
2049
                enough already granted on the record, we have to wait. */
2060
2050
 
2061
 
                return(lock_rec_enqueue_waiting(mode, block, heap_no,
2062
 
                                                index, thr));
2063
 
        } else if (!impl) {
2064
 
                /* Set the requested lock on the record */
2065
 
 
2066
 
                lock_rec_add_to_queue(LOCK_REC | mode, block,
2067
 
                                      heap_no, index, trx);
2068
 
                return(DB_SUCCESS_LOCKED_REC);
 
2051
                err = lock_rec_enqueue_waiting(mode, block, heap_no,
 
2052
                                               index, thr);
 
2053
        } else {
 
2054
                if (!impl) {
 
2055
                        /* Set the requested lock on the record */
 
2056
 
 
2057
                        lock_rec_add_to_queue(LOCK_REC | mode, block,
 
2058
                                              heap_no, index, trx);
 
2059
                }
 
2060
 
 
2061
                err = DB_SUCCESS;
2069
2062
        }
2070
2063
 
2071
 
        return(DB_SUCCESS);
 
2064
        return(err);
2072
2065
}
2073
2066
 
2074
2067
/*********************************************************************//**
2077
2070
which does NOT look at implicit locks! Checks lock compatibility within
2078
2071
explicit locks. This function sets a normal next-key lock, or in the case
2079
2072
of a page supremum record, a gap type lock.
2080
 
@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, DB_DEADLOCK,
2081
 
or DB_QUE_THR_SUSPENDED */
 
2073
@return DB_SUCCESS, DB_LOCK_WAIT, or error code */
2082
2074
static
2083
 
enum db_err
 
2075
ulint
2084
2076
lock_rec_lock(
2085
2077
/*==========*/
2086
2078
        ibool                   impl,   /*!< in: if TRUE, no lock is set
2096
2088
        dict_index_t*           index,  /*!< in: index of record */
2097
2089
        que_thr_t*              thr)    /*!< in: query thread */
2098
2090
{
 
2091
        ulint   err;
 
2092
 
2099
2093
        ut_ad(mutex_own(&kernel_mutex));
2100
2094
        ut_ad((LOCK_MODE_MASK & mode) != LOCK_S
2101
2095
              || lock_table_has(thr_get_trx(thr), index->table, LOCK_IS));
2107
2101
              || mode - (LOCK_MODE_MASK & mode) == LOCK_REC_NOT_GAP
2108
2102
              || mode - (LOCK_MODE_MASK & mode) == 0);
2109
2103
 
2110
 
        /* We try a simplified and faster subroutine for the most
2111
 
        common cases */
2112
 
        switch (lock_rec_lock_fast(impl, mode, block, heap_no, index, thr)) {
2113
 
        case LOCK_REC_SUCCESS:
2114
 
                return(DB_SUCCESS);
2115
 
        case LOCK_REC_SUCCESS_CREATED:
2116
 
                return(DB_SUCCESS_LOCKED_REC);
2117
 
        case LOCK_REC_FAIL:
2118
 
                return(lock_rec_lock_slow(impl, mode, block,
2119
 
                                          heap_no, index, thr));
 
2104
        if (lock_rec_lock_fast(impl, mode, block, heap_no, index, thr)) {
 
2105
 
 
2106
                /* We try a simplified and faster subroutine for the most
 
2107
                common cases */
 
2108
 
 
2109
                err = DB_SUCCESS;
 
2110
        } else {
 
2111
                err = lock_rec_lock_slow(impl, mode, block,
 
2112
                                         heap_no, index, thr);
2120
2113
        }
2121
2114
 
2122
 
        ut_error;
2123
 
        return(DB_ERROR);
 
2115
        return(err);
2124
2116
}
2125
2117
 
2126
2118
/*********************************************************************//**
2406
2398
                if (!lock_rec_get_insert_intention(lock)
2407
2399
                    && !((srv_locks_unsafe_for_binlog
2408
2400
                          || lock->trx->isolation_level
2409
 
                          <= TRX_ISO_READ_COMMITTED)
 
2401
                          == TRX_ISO_READ_COMMITTED)
2410
2402
                         && lock_get_mode(lock) == LOCK_X)) {
2411
2403
 
2412
2404
                        lock_rec_add_to_queue(LOCK_REC | LOCK_GAP
3937
3929
        const rec_t*            rec,    /*!< in: record */
3938
3930
        enum lock_mode          lock_mode)/*!< in: LOCK_S or LOCK_X */
3939
3931
{
3940
 
        lock_t* first_lock;
3941
3932
        lock_t* lock;
 
3933
        lock_t* release_lock    = NULL;
3942
3934
        ulint   heap_no;
3943
3935
 
3944
3936
        ut_ad(trx && rec);
3948
3940
 
3949
3941
        mutex_enter(&kernel_mutex);
3950
3942
 
3951
 
        first_lock = lock_rec_get_first(block, heap_no);
 
3943
        lock = lock_rec_get_first(block, heap_no);
3952
3944
 
3953
3945
        /* Find the last lock with the same lock_mode and transaction
3954
3946
        from the record. */
3955
3947
 
3956
 
        for (lock = first_lock; lock != NULL;
3957
 
             lock = lock_rec_get_next(heap_no, lock)) {
 
3948
        while (lock != NULL) {
3958
3949
                if (lock->trx == trx && lock_get_mode(lock) == lock_mode) {
 
3950
                        release_lock = lock;
3959
3951
                        ut_a(!lock_get_wait(lock));
3960
 
                        lock_rec_reset_nth_bit(lock, heap_no);
3961
 
                        goto released;
3962
3952
                }
3963
 
        }
3964
 
 
3965
 
        mutex_exit(&kernel_mutex);
3966
 
        ut_print_timestamp(stderr);
3967
 
        fprintf(stderr,
3968
 
                "  InnoDB: Error: unlock row could not"
3969
 
                " find a %lu mode lock on the record\n",
3970
 
                (ulong) lock_mode);
3971
 
 
3972
 
        return;
3973
 
 
3974
 
released:
 
3953
 
 
3954
                lock = lock_rec_get_next(heap_no, lock);
 
3955
        }
 
3956
 
 
3957
        /* If a record lock is found, release the record lock */
 
3958
 
 
3959
        if (UNIV_LIKELY(release_lock != NULL)) {
 
3960
                lock_rec_reset_nth_bit(release_lock, heap_no);
 
3961
        } else {
 
3962
                mutex_exit(&kernel_mutex);
 
3963
                ut_print_timestamp(stderr);
 
3964
                fprintf(stderr,
 
3965
                        "  InnoDB: Error: unlock row could not"
 
3966
                        " find a %lu mode lock on the record\n",
 
3967
                        (ulong) lock_mode);
 
3968
 
 
3969
                return;
 
3970
        }
 
3971
 
3975
3972
        /* Check if we can now grant waiting lock requests */
3976
3973
 
3977
 
        for (lock = first_lock; lock != NULL;
3978
 
             lock = lock_rec_get_next(heap_no, lock)) {
 
3974
        lock = lock_rec_get_first(block, heap_no);
 
3975
 
 
3976
        while (lock != NULL) {
3979
3977
                if (lock_get_wait(lock)
3980
3978
                    && !lock_rec_has_to_wait_in_queue(lock)) {
3981
3979
 
3982
3980
                        /* Grant the lock */
3983
3981
                        lock_grant(lock);
3984
3982
                }
 
3983
 
 
3984
                lock = lock_rec_get_next(heap_no, lock);
3985
3985
        }
3986
3986
 
3987
3987
        mutex_exit(&kernel_mutex);
4704
4704
                        ut_a(lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP,
4705
4705
                                               block, heap_no, impl_trx));
4706
4706
                }
4707
 
#if 0
4708
4707
        } else {
4709
4708
 
4710
4709
                /* The kernel mutex may get released temporarily in the
4715
4714
                (fil_space_t::latch), the following check WILL break
4716
4715
                latching order and may cause a deadlock of threads. */
4717
4716
 
4718
 
                /* NOTE: This is a bogus check that would fail in the
4719
 
                following case: Our transaction is updating a
4720
 
                row. After it has updated the clustered index record,
4721
 
                it goes to a secondary index record and finds someone
4722
 
                else holding an explicit S- or X-lock on that
4723
 
                secondary index record, presumably from a locking
4724
 
                read. Our transaction cannot update the secondary
4725
 
                index immediately, but places a waiting X-lock request
4726
 
                on the secondary index record. There is nothing
4727
 
                illegal in this. The assertion is simply too strong. */
4728
 
 
4729
 
                /* From the locking point of view, each secondary
4730
 
                index is a separate table. A lock that is held on
4731
 
                secondary index rec does not give any rights to modify
4732
 
                or read the clustered index rec. Therefore, we can
4733
 
                think of the sec index as a separate 'table' from the
4734
 
                clust index 'table'. Conversely, a transaction that
4735
 
                has acquired a lock on and modified a clustered index
4736
 
                record may need to wait for a lock on the
4737
 
                corresponding record in a secondary index. */
4738
 
 
4739
4717
                impl_trx = lock_sec_rec_some_has_impl_off_kernel(
4740
4718
                        rec, index, offsets);
4741
4719
 
4746
4724
                        ut_a(lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP,
4747
4725
                                               block, heap_no, impl_trx));
4748
4726
                }
4749
 
#endif
4750
4727
        }
4751
4728
 
4752
4729
        lock = lock_rec_get_first(block, heap_no);
5072
5049
 
5073
5050
        lock_mutex_exit_kernel();
5074
5051
 
5075
 
        switch (err) {
5076
 
        case DB_SUCCESS_LOCKED_REC:
5077
 
                err = DB_SUCCESS;
5078
 
                /* fall through */
5079
 
        case DB_SUCCESS:
5080
 
                if (dict_index_is_clust(index)) {
5081
 
                        break;
5082
 
                }
 
5052
        if ((err == DB_SUCCESS) && !dict_index_is_clust(index)) {
5083
5053
                /* Update the page max trx id field */
5084
5054
                page_update_max_trx_id(block,
5085
5055
                                       buf_block_get_page_zip(block),
5202
5172
 
5203
5173
        ut_ad(lock_rec_queue_validate(block, rec, index, offsets));
5204
5174
 
5205
 
        if (UNIV_UNLIKELY(err == DB_SUCCESS_LOCKED_REC)) {
5206
 
                err = DB_SUCCESS;
5207
 
        }
5208
 
 
5209
5175
        return(err);
5210
5176
}
5211
5177
 
5272
5238
        }
5273
5239
#endif /* UNIV_DEBUG */
5274
5240
 
5275
 
        if (err == DB_SUCCESS || err == DB_SUCCESS_LOCKED_REC) {
 
5241
        if (err == DB_SUCCESS) {
5276
5242
                /* Update the page max trx id field */
5277
 
                /* It might not be necessary to do this if
5278
 
                err == DB_SUCCESS (no new lock created),
5279
 
                but it should not cost too much performance. */
5280
5243
                page_update_max_trx_id(block,
5281
5244
                                       buf_block_get_page_zip(block),
5282
5245
                                       thr_get_trx(thr)->id, mtr);
5283
 
                err = DB_SUCCESS;
5284
5246
        }
5285
5247
 
5286
5248
        return(err);
5287
5249
}
5288
5250
 
5289
5251
/*********************************************************************//**
5290
 
Like lock_clust_rec_read_check_and_lock(), but reads a
 
5252
Like the counterpart for a clustered index below, but now we read a
5291
5253
secondary index record.
5292
 
@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, DB_DEADLOCK,
5293
 
or DB_QUE_THR_SUSPENDED */
 
5254
@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
5294
5255
UNIV_INTERN
5295
 
enum db_err
 
5256
ulint
5296
5257
lock_sec_rec_read_check_and_lock(
5297
5258
/*=============================*/
5298
5259
        ulint                   flags,  /*!< in: if BTR_NO_LOCKING_FLAG
5313
5274
                                        LOCK_REC_NOT_GAP */
5314
5275
        que_thr_t*              thr)    /*!< in: query thread */
5315
5276
{
5316
 
        enum db_err     err;
5317
 
        ulint           heap_no;
 
5277
        ulint   err;
 
5278
        ulint   heap_no;
5318
5279
 
5319
5280
        ut_ad(!dict_index_is_clust(index));
5320
5281
        ut_ad(block->frame == page_align(rec));
5365
5326
puts the transaction and the query thread to the lock wait state and inserts a
5366
5327
waiting request for a record lock to the lock queue. Sets the requested mode
5367
5328
lock on the record.
5368
 
@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, DB_DEADLOCK,
5369
 
or DB_QUE_THR_SUSPENDED */
 
5329
@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
5370
5330
UNIV_INTERN
5371
 
enum db_err
 
5331
ulint
5372
5332
lock_clust_rec_read_check_and_lock(
5373
5333
/*===============================*/
5374
5334
        ulint                   flags,  /*!< in: if BTR_NO_LOCKING_FLAG
5389
5349
                                        LOCK_REC_NOT_GAP */
5390
5350
        que_thr_t*              thr)    /*!< in: query thread */
5391
5351
{
5392
 
        enum db_err     err;
5393
 
        ulint           heap_no;
 
5352
        ulint   err;
 
5353
        ulint   heap_no;
5394
5354
 
5395
5355
        ut_ad(dict_index_is_clust(index));
5396
5356
        ut_ad(block->frame == page_align(rec));
5461
5421
        mem_heap_t*     tmp_heap        = NULL;
5462
5422
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
5463
5423
        ulint*          offsets         = offsets_;
5464
 
        ulint           err;
 
5424
        ulint           ret;
5465
5425
        rec_offs_init(offsets_);
5466
5426
 
5467
5427
        offsets = rec_get_offsets(rec, index, offsets,
5468
5428
                                  ULINT_UNDEFINED, &tmp_heap);
5469
 
        err = lock_clust_rec_read_check_and_lock(flags, block, rec, index,
 
5429
        ret = lock_clust_rec_read_check_and_lock(flags, block, rec, index,
5470
5430
                                                 offsets, mode, gap_mode, thr);
5471
5431
        if (tmp_heap) {
5472
5432
                mem_heap_free(tmp_heap);
5473
5433
        }
5474
 
 
5475
 
        if (UNIV_UNLIKELY(err == DB_SUCCESS_LOCKED_REC)) {
5476
 
                err = DB_SUCCESS;
5477
 
        }
5478
 
 
5479
 
        return(err);
 
5434
        return(ret);
5480
5435
}
5481
5436
 
5482
5437
/*******************************************************************//**