Commit 0f95f99b authored by Marko Mäkelä's avatar Marko Mäkelä

Bug#12584374 LOCK_VALIDATE TRIPS ASSERTION !BLOCK->PAGE.FILE_PAGE_WAS_FREED

lock_clust_rec_some_has_impl(), row_get_rec_trx_id(),
lock_rec_queue_validate(), lock_table_other_has_incompatible(),
lock_table_has_to_wait_in_queue(), lock_table_queue_validate():
Add const qualifiers.

row_get_trx_id_offset(): Add const qualifiers. Keep the parameter rec
only in UNIV_DEBUG builds. Inline the function.

lock_rec_validate_page(): Take the buffer block as a parameter, to
avoid a buf_page_get_gen() call in most cases.

lock_rec_validate_page_low(): A version of lock_rec_validate_page()
that assumes that the lock system mutexes are already being held.

lock_rec_get_next_on_page_const(): A const variant of
lock_rec_get_next_on_page().

lock_validate(): Do not release the lock system mutex while
buffer-fixing the block for the lock_rec_validate_page() call.
Releasing the mutex apparently caused the assertion failure.

rb:665 approved by Sunny Bains
parent 41c13fb5
...@@ -72,9 +72,10 @@ UNIV_INLINE ...@@ -72,9 +72,10 @@ UNIV_INLINE
trx_t* trx_t*
lock_clust_rec_some_has_impl( lock_clust_rec_some_has_impl(
/*=========================*/ /*=========================*/
const rec_t* rec, /*!< in: user record */ const rec_t* rec, /*!< in: user record */
dict_index_t* index, /*!< in: clustered index */ const dict_index_t* index, /*!< in: clustered index */
const ulint* offsets);/*!< in: rec_get_offsets(rec, index) */ const ulint* offsets)/*!< in: rec_get_offsets(rec, index) */
__attribute__((nonnull, warn_unused_result));
/*********************************************************************//** /*********************************************************************//**
Gets the heap_no of the smallest user record on a page. Gets the heap_no of the smallest user record on a page.
@return heap_no of smallest user record, or PAGE_HEAP_NO_SUPREMUM */ @return heap_no of smallest user record, or PAGE_HEAP_NO_SUPREMUM */
......
...@@ -75,9 +75,9 @@ UNIV_INLINE ...@@ -75,9 +75,9 @@ UNIV_INLINE
trx_t* trx_t*
lock_clust_rec_some_has_impl( lock_clust_rec_some_has_impl(
/*=========================*/ /*=========================*/
const rec_t* rec, /*!< in: user record */ const rec_t* rec, /*!< in: user record */
dict_index_t* index, /*!< in: clustered index */ const dict_index_t* index, /*!< in: clustered index */
const ulint* offsets)/*!< in: rec_get_offsets(rec, index) */ const ulint* offsets)/*!< in: rec_get_offsets(rec, index) */
{ {
trx_id_t trx_id; trx_id_t trx_id;
......
...@@ -41,13 +41,24 @@ Created 4/20/1996 Heikki Tuuri ...@@ -41,13 +41,24 @@ Created 4/20/1996 Heikki Tuuri
Gets the offset of the trx id field, in bytes relative to the origin of Gets the offset of the trx id field, in bytes relative to the origin of
a clustered index record. a clustered index record.
@return offset of DATA_TRX_ID */ @return offset of DATA_TRX_ID */
UNIV_INTERN UNIV_INLINE
ulint ulint
row_get_trx_id_offset( row_get_trx_id_offset_func(
/*==================*/ /*=======================*/
const rec_t* rec, /*!< in: record */ #ifdef UNIV_DEBUG
dict_index_t* index, /*!< in: clustered index */ const rec_t* rec, /*!< in: record */
const ulint* offsets);/*!< in: rec_get_offsets(rec, index) */ #endif /* UNIV_DEBUG */
const dict_index_t* index, /*!< in: clustered index */
const ulint* offsets)/*!< in: rec_get_offsets(rec, index) */
__attribute__((nonnull, warn_unused_result));
#ifdef UNIV_DEBUG
# define row_get_trx_id_offset(rec, index, offsets) \
row_get_trx_id_offset_func(rec, index, offsets)
#else /* UNIV_DEBUG */
# define row_get_trx_id_offset(rec, index, offsets) \
row_get_trx_id_offset_func(index, offsets)
#endif /* UNIV_DEBUG */
/*********************************************************************//** /*********************************************************************//**
Reads the trx id field from a clustered index record. Reads the trx id field from a clustered index record.
@return value of the field */ @return value of the field */
...@@ -55,9 +66,10 @@ UNIV_INLINE ...@@ -55,9 +66,10 @@ UNIV_INLINE
trx_id_t trx_id_t
row_get_rec_trx_id( row_get_rec_trx_id(
/*===============*/ /*===============*/
const rec_t* rec, /*!< in: record */ const rec_t* rec, /*!< in: record */
dict_index_t* index, /*!< in: clustered index */ const dict_index_t* index, /*!< in: clustered index */
const ulint* offsets);/*!< in: rec_get_offsets(rec, index) */ const ulint* offsets)/*!< in: rec_get_offsets(rec, index) */
__attribute__((nonnull, warn_unused_result));
/*********************************************************************//** /*********************************************************************//**
Reads the roll pointer field from a clustered index record. Reads the roll pointer field from a clustered index record.
@return value of the field */ @return value of the field */
......
...@@ -27,6 +27,36 @@ Created 4/20/1996 Heikki Tuuri ...@@ -27,6 +27,36 @@ Created 4/20/1996 Heikki Tuuri
#include "rem0rec.h" #include "rem0rec.h"
#include "trx0undo.h" #include "trx0undo.h"
/*********************************************************************//**
Gets the offset of trx id field, in bytes relative to the origin of
a clustered index record.
@return offset of DATA_TRX_ID */
UNIV_INLINE
ulint
row_get_trx_id_offset_func(
/*=======================*/
#ifdef UNIV_DEBUG
const rec_t* rec, /*!< in: record */
#endif /* UNIV_DEBUG */
const dict_index_t* index, /*!< in: clustered index */
const ulint* offsets)/*!< in: rec_get_offsets(rec, index) */
{
ulint pos;
ulint offset;
ulint len;
ut_ad(dict_index_is_clust(index));
ut_ad(rec_offs_validate(rec, index, offsets));
pos = dict_index_get_sys_col_pos(index, DATA_TRX_ID);
offset = rec_get_nth_field_offs(offsets, pos, &len);
ut_ad(len == DATA_TRX_ID_LEN);
return(offset);
}
/*********************************************************************//** /*********************************************************************//**
Reads the trx id field from a clustered index record. Reads the trx id field from a clustered index record.
@return value of the field */ @return value of the field */
...@@ -34,9 +64,9 @@ UNIV_INLINE ...@@ -34,9 +64,9 @@ UNIV_INLINE
trx_id_t trx_id_t
row_get_rec_trx_id( row_get_rec_trx_id(
/*===============*/ /*===============*/
const rec_t* rec, /*!< in: record */ const rec_t* rec, /*!< in: record */
dict_index_t* index, /*!< in: clustered index */ const dict_index_t* index, /*!< in: clustered index */
const ulint* offsets)/*!< in: rec_get_offsets(rec, index) */ const ulint* offsets)/*!< in: rec_get_offsets(rec, index) */
{ {
ulint offset; ulint offset;
......
...@@ -352,6 +352,7 @@ ibool ...@@ -352,6 +352,7 @@ ibool
lock_validate(void); lock_validate(void);
/*===============*/ /*===============*/
# ifdef UNIV_DEBUG_LOCK_VALIDATE
/*********************************************************************//** /*********************************************************************//**
Validates the record lock queues on a page. Validates the record lock queues on a page.
@return TRUE if ok */ @return TRUE if ok */
...@@ -359,10 +360,9 @@ static ...@@ -359,10 +360,9 @@ static
ibool ibool
lock_rec_validate_page( lock_rec_validate_page(
/*===================*/ /*===================*/
ulint space, /*!< in: space id */ const buf_block_t* block) /*!< in: buffer block */
ulint zip_size,/*!< in: compressed page size in bytes __attribute__((nonnull, warn_unused_result));
or 0 for uncompressed pages */ # endif /* UNIV_DEBUG_LOCK_VALIDATE */
ulint page_no);/*!< in: page number */
#endif /* UNIV_DEBUG */ #endif /* UNIV_DEBUG */
/* The lock system */ /* The lock system */
...@@ -1100,10 +1100,10 @@ lock_rec_reset_nth_bit( ...@@ -1100,10 +1100,10 @@ lock_rec_reset_nth_bit(
Gets the first or next record lock on a page. Gets the first or next record lock on a page.
@return next lock, NULL if none exists */ @return next lock, NULL if none exists */
UNIV_INLINE UNIV_INLINE
lock_t* const lock_t*
lock_rec_get_next_on_page( lock_rec_get_next_on_page_const(
/*======================*/ /*============================*/
lock_t* lock) /*!< in: a record lock */ const lock_t* lock) /*!< in: a record lock */
{ {
ulint space; ulint space;
ulint page_no; ulint page_no;
...@@ -1132,6 +1132,18 @@ lock_rec_get_next_on_page( ...@@ -1132,6 +1132,18 @@ lock_rec_get_next_on_page(
return(lock); return(lock);
} }
/*********************************************************************//**
Gets the first or next record lock on a page.
@return next lock, NULL if none exists */
UNIV_INLINE
lock_t*
lock_rec_get_next_on_page(
/*======================*/
lock_t* lock) /*!< in: a record lock */
{
return((lock_t*) lock_rec_get_next_on_page_const(lock));
}
/*********************************************************************//** /*********************************************************************//**
Gets the first record lock on a page, where the page is identified by its Gets the first record lock on a page, where the page is identified by its
file address. file address.
...@@ -2645,9 +2657,7 @@ lock_move_reorganize_page( ...@@ -2645,9 +2657,7 @@ lock_move_reorganize_page(
mem_heap_free(heap); mem_heap_free(heap);
#ifdef UNIV_DEBUG_LOCK_VALIDATE #ifdef UNIV_DEBUG_LOCK_VALIDATE
ut_ad(lock_rec_validate_page(buf_block_get_space(block), ut_ad(lock_rec_validate_page(block));
buf_block_get_zip_size(block),
buf_block_get_page_no(block)));
#endif #endif
} }
...@@ -2735,12 +2745,8 @@ lock_move_rec_list_end( ...@@ -2735,12 +2745,8 @@ lock_move_rec_list_end(
lock_mutex_exit_kernel(); lock_mutex_exit_kernel();
#ifdef UNIV_DEBUG_LOCK_VALIDATE #ifdef UNIV_DEBUG_LOCK_VALIDATE
ut_ad(lock_rec_validate_page(buf_block_get_space(block), ut_ad(lock_rec_validate_page(block));
buf_block_get_zip_size(block), ut_ad(lock_rec_validate_page(new_block));
buf_block_get_page_no(block)));
ut_ad(lock_rec_validate_page(buf_block_get_space(new_block),
buf_block_get_zip_size(block),
buf_block_get_page_no(new_block)));
#endif #endif
} }
...@@ -2848,9 +2854,7 @@ lock_move_rec_list_start( ...@@ -2848,9 +2854,7 @@ lock_move_rec_list_start(
lock_mutex_exit_kernel(); lock_mutex_exit_kernel();
#ifdef UNIV_DEBUG_LOCK_VALIDATE #ifdef UNIV_DEBUG_LOCK_VALIDATE
ut_ad(lock_rec_validate_page(buf_block_get_space(block), ut_ad(lock_rec_validate_page(block));
buf_block_get_zip_size(block),
buf_block_get_page_no(block)));
#endif #endif
} }
...@@ -3833,17 +3837,18 @@ Checks if other transactions have an incompatible mode lock request in ...@@ -3833,17 +3837,18 @@ Checks if other transactions have an incompatible mode lock request in
the lock queue. the lock queue.
@return lock or NULL */ @return lock or NULL */
UNIV_INLINE UNIV_INLINE
lock_t* const lock_t*
lock_table_other_has_incompatible( lock_table_other_has_incompatible(
/*==============================*/ /*==============================*/
trx_t* trx, /*!< in: transaction, or NULL if all const trx_t* trx, /*!< in: transaction, or NULL if all
transactions should be included */ transactions should be included */
ulint wait, /*!< in: LOCK_WAIT if also waiting locks are ulint wait, /*!< in: LOCK_WAIT if also
taken into account, or 0 if not */ waiting locks are taken into
dict_table_t* table, /*!< in: table */ account, or 0 if not */
enum lock_mode mode) /*!< in: lock mode */ const dict_table_t* table, /*!< in: table */
enum lock_mode mode) /*!< in: lock mode */
{ {
lock_t* lock; const lock_t* lock;
ut_ad(mutex_own(&kernel_mutex)); ut_ad(mutex_own(&kernel_mutex));
...@@ -3934,10 +3939,10 @@ static ...@@ -3934,10 +3939,10 @@ static
ibool ibool
lock_table_has_to_wait_in_queue( lock_table_has_to_wait_in_queue(
/*============================*/ /*============================*/
lock_t* wait_lock) /*!< in: waiting table lock */ const lock_t* wait_lock) /*!< in: waiting table lock */
{ {
dict_table_t* table; const dict_table_t* table;
lock_t* lock; const lock_t* lock;
ut_ad(mutex_own(&kernel_mutex)); ut_ad(mutex_own(&kernel_mutex));
ut_ad(lock_get_wait(wait_lock)); ut_ad(lock_get_wait(wait_lock));
...@@ -4677,9 +4682,9 @@ static ...@@ -4677,9 +4682,9 @@ static
ibool ibool
lock_table_queue_validate( lock_table_queue_validate(
/*======================*/ /*======================*/
dict_table_t* table) /*!< in: table */ const dict_table_t* table) /*!< in: table */
{ {
lock_t* lock; const lock_t* lock;
ut_ad(mutex_own(&kernel_mutex)); ut_ad(mutex_own(&kernel_mutex));
...@@ -4715,7 +4720,7 @@ lock_rec_queue_validate( ...@@ -4715,7 +4720,7 @@ lock_rec_queue_validate(
/*====================*/ /*====================*/
const buf_block_t* block, /*!< in: buffer block containing rec */ const buf_block_t* block, /*!< in: buffer block containing rec */
const rec_t* rec, /*!< in: record to look at */ const rec_t* rec, /*!< in: record to look at */
dict_index_t* index, /*!< in: index, or NULL if not known */ const dict_index_t* index, /*!< in: index, or NULL if not known */
const ulint* offsets)/*!< in: rec_get_offsets(rec, index) */ const ulint* offsets)/*!< in: rec_get_offsets(rec, index) */
{ {
trx_t* impl_trx; trx_t* impl_trx;
...@@ -4860,42 +4865,28 @@ lock_rec_queue_validate( ...@@ -4860,42 +4865,28 @@ lock_rec_queue_validate(
/*********************************************************************//** /*********************************************************************//**
Validates the record lock queues on a page. Validates the record lock queues on a page.
@return TRUE if ok */ @return TRUE if ok */
static static __attribute__((nonnull, warn_unused_result))
ibool ibool
lock_rec_validate_page( lock_rec_validate_page_low(
/*===================*/ /*=======================*/
ulint space, /*!< in: space id */ const buf_block_t* block) /*!< in: buffer block */
ulint zip_size,/*!< in: compressed page size in bytes
or 0 for uncompressed pages */
ulint page_no)/*!< in: page number */
{ {
dict_index_t* index; const lock_t* lock;
buf_block_t* block;
const page_t* page;
lock_t* lock;
const rec_t* rec; const rec_t* rec;
ulint nth_lock = 0; ulint nth_lock = 0;
ulint nth_bit = 0; ulint nth_bit = 0;
ulint i; ulint i;
mtr_t mtr;
mem_heap_t* heap = NULL; mem_heap_t* heap = NULL;
ulint offsets_[REC_OFFS_NORMAL_SIZE]; ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets = offsets_; ulint* offsets = offsets_;
rec_offs_init(offsets_); rec_offs_init(offsets_);
ut_ad(!mutex_own(&kernel_mutex)); ut_ad(mutex_own(&kernel_mutex));
ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
mtr_start(&mtr);
ut_ad(zip_size != ULINT_UNDEFINED);
block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, &mtr);
buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
page = block->frame;
lock_mutex_enter_kernel();
loop: loop:
lock = lock_rec_get_first_on_page_addr(space, page_no); lock = lock_rec_get_first_on_page_addr(buf_block_get_space(block),
buf_block_get_page_no(block));
if (!lock) { if (!lock) {
goto function_exit; goto function_exit;
...@@ -4903,7 +4894,7 @@ loop: ...@@ -4903,7 +4894,7 @@ loop:
for (i = 0; i < nth_lock; i++) { for (i = 0; i < nth_lock; i++) {
lock = lock_rec_get_next_on_page(lock); lock = lock_rec_get_next_on_page_const(lock);
if (!lock) { if (!lock) {
goto function_exit; goto function_exit;
...@@ -4926,15 +4917,14 @@ loop: ...@@ -4926,15 +4917,14 @@ loop:
if (i == 1 || lock_rec_get_nth_bit(lock, i)) { if (i == 1 || lock_rec_get_nth_bit(lock, i)) {
index = lock->index; rec = page_find_rec_with_heap_no(block->frame, i);
rec = page_find_rec_with_heap_no(page, i);
ut_a(rec); ut_a(rec);
offsets = rec_get_offsets(rec, index, offsets, offsets = rec_get_offsets(rec, lock->index, offsets,
ULINT_UNDEFINED, &heap); ULINT_UNDEFINED, &heap);
#if 0 #if 0
fprintf(stderr, fprintf(stderr,
"Validating %lu %lu\n", "Validating %u %u\n",
(ulong) space, (ulong) page_no); block->page.space, block->page.offset);
#endif #endif
lock_mutex_exit_kernel(); lock_mutex_exit_kernel();
...@@ -4943,7 +4933,8 @@ loop: ...@@ -4943,7 +4933,8 @@ loop:
check WILL break the latching order and may check WILL break the latching order and may
cause a deadlock of threads. */ cause a deadlock of threads. */
lock_rec_queue_validate(block, rec, index, offsets); lock_rec_queue_validate(block, rec, lock->index,
offsets);
lock_mutex_enter_kernel(); lock_mutex_enter_kernel();
...@@ -4959,16 +4950,32 @@ loop: ...@@ -4959,16 +4950,32 @@ loop:
goto loop; goto loop;
function_exit: function_exit:
lock_mutex_exit_kernel();
mtr_commit(&mtr);
if (UNIV_LIKELY_NULL(heap)) { if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap); mem_heap_free(heap);
} }
return(TRUE); return(TRUE);
} }
#ifdef UNIV_DEBUG_LOCK_VALIDATE
/*********************************************************************//**
Validates the record lock queues on a page.
@return TRUE if ok */
static
ibool
lock_rec_validate_page(
/*===================*/
const buf_block_t* block) /*!< in: buffer block */
{
ibool valid;
lock_mutex_enter_kernel();
valid = lock_rec_validate_page_low(block);
lock_mutex_exit_kernel();
return(valid);
}
#endif /* UNIV_DEBUG_LOCK_VALIDATE */
/*********************************************************************//** /*********************************************************************//**
Validates the lock system. Validates the lock system.
@return TRUE if ok */ @return TRUE if ok */
...@@ -4977,11 +4984,8 @@ ibool ...@@ -4977,11 +4984,8 @@ ibool
lock_validate(void) lock_validate(void)
/*===============*/ /*===============*/
{ {
lock_t* lock; const lock_t* lock;
trx_t* trx; const trx_t* trx;
ib_uint64_t limit;
ulint space;
ulint page_no;
ulint i; ulint i;
lock_mutex_enter_kernel(); lock_mutex_enter_kernel();
...@@ -5006,9 +5010,14 @@ lock_validate(void) ...@@ -5006,9 +5010,14 @@ lock_validate(void)
for (i = 0; i < hash_get_n_cells(lock_sys->rec_hash); i++) { for (i = 0; i < hash_get_n_cells(lock_sys->rec_hash); i++) {
limit = 0; ulint space;
ulint page_no;
ib_uint64_t limit = 0;
for (;;) { for (;;) {
mtr_t mtr;
buf_block_t* block;
lock = HASH_GET_FIRST(lock_sys->rec_hash, i); lock = HASH_GET_FIRST(lock_sys->rec_hash, i);
while (lock) { while (lock) {
...@@ -5032,15 +5041,16 @@ lock_validate(void) ...@@ -5032,15 +5041,16 @@ lock_validate(void)
break; break;
} }
lock_mutex_exit_kernel(); mtr_start(&mtr);
block = buf_page_get(
lock_rec_validate_page(space, space, fil_space_get_zip_size(space),
fil_space_get_zip_size(space), page_no, RW_X_LATCH, &mtr);
page_no); buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
lock_mutex_enter_kernel(); ut_ad(lock_rec_validate_page_low(block));
mtr_commit(&mtr);
limit = ut_ull_create(space, page_no + 1); limit++;
} }
} }
......
...@@ -47,35 +47,6 @@ Created 4/20/1996 Heikki Tuuri ...@@ -47,35 +47,6 @@ Created 4/20/1996 Heikki Tuuri
#include "read0read.h" #include "read0read.h"
#include "ut0mem.h" #include "ut0mem.h"
/*********************************************************************//**
Gets the offset of trx id field, in bytes relative to the origin of
a clustered index record.
@return offset of DATA_TRX_ID */
UNIV_INTERN
ulint
row_get_trx_id_offset(
/*==================*/
const rec_t* rec __attribute__((unused)),
/*!< in: record */
dict_index_t* index, /*!< in: clustered index */
const ulint* offsets)/*!< in: rec_get_offsets(rec, index) */
{
ulint pos;
ulint offset;
ulint len;
ut_ad(dict_index_is_clust(index));
ut_ad(rec_offs_validate(rec, index, offsets));
pos = dict_index_get_sys_col_pos(index, DATA_TRX_ID);
offset = rec_get_nth_field_offs(offsets, pos, &len);
ut_ad(len == DATA_TRX_ID_LEN);
return(offset);
}
/*****************************************************************//** /*****************************************************************//**
When an insert or purge to a table is performed, this function builds When an insert or purge to a table is performed, this function builds
the entry to be inserted into or purged from an index on the table. the entry to be inserted into or purged from an index on the table.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment