Percona-Server-5.5.30-rel30.2.tar.gz

This commit is contained in:
Sergei Golubchik 2013-05-08 09:52:54 +02:00
parent 086b54c281
commit bcfa90b471
43 changed files with 808 additions and 656 deletions

View File

@ -688,7 +688,7 @@ btr_root_fseg_validate(
{
ulint offset = mach_read_from_2(seg_header + FSEG_HDR_OFFSET);
if (UNIV_UNLIKELY(srv_pass_corrupt_table)) {
if (UNIV_UNLIKELY(srv_pass_corrupt_table != 0)) {
return (mach_read_from_4(seg_header + FSEG_HDR_SPACE) == space)
&& (offset >= FIL_PAGE_DATA)
&& (offset <= UNIV_PAGE_SIZE - FIL_PAGE_DATA_END);
@ -723,17 +723,14 @@ btr_root_block_get(
block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH,
index, mtr);
if (srv_pass_corrupt_table && !block) {
return(0);
}
ut_a(block);
SRV_CORRUPT_TABLE_CHECK(block, return(0););
btr_assert_not_corrupted(block, index);
#ifdef UNIV_BTR_DEBUG
if (!dict_index_is_ibuf(index)) {
const page_t* root = buf_block_get_frame(block);
if (UNIV_UNLIKELY(srv_pass_corrupt_table)) {
if (UNIV_UNLIKELY(srv_pass_corrupt_table != 0)) {
if (!btr_root_fseg_validate(FIL_PAGE_DATA
+ PAGE_BTR_SEG_LEAF
+ root, space))
@ -1063,11 +1060,11 @@ btr_get_size(
root = btr_root_get(index, mtr);
if (srv_pass_corrupt_table && !root) {
SRV_CORRUPT_TABLE_CHECK(root,
{
mtr_commit(mtr);
return(0);
}
ut_a(root);
});
if (flag == BTR_N_LEAF_PAGES) {
seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
@ -1525,11 +1522,11 @@ leaf_loop:
root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH,
NULL, &mtr);
if (srv_pass_corrupt_table && !root) {
SRV_CORRUPT_TABLE_CHECK(root,
{
mtr_commit(&mtr);
return;
}
ut_a(root);
});
#ifdef UNIV_BTR_DEBUG
ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF
@ -1555,11 +1552,12 @@ top_loop:
root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH,
NULL, &mtr);
if (srv_pass_corrupt_table && !root) {
SRV_CORRUPT_TABLE_CHECK(root,
{
mtr_commit(&mtr);
return;
}
ut_a(root);
});
#ifdef UNIV_BTR_DEBUG
ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP
+ root, space));
@ -1593,10 +1591,7 @@ btr_free_root(
block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH,
NULL, mtr);
if (srv_pass_corrupt_table && !block) {
return;
}
ut_a(block);
SRV_CORRUPT_TABLE_CHECK(block, return;);
btr_search_drop_page_hash_index(block);
@ -4565,10 +4560,11 @@ btr_validate_index(
root = btr_root_get(index, &mtr);
if (UNIV_UNLIKELY(srv_pass_corrupt_table && !root)) {
SRV_CORRUPT_TABLE_CHECK(root,
{
mtr_commit(&mtr);
return(FALSE);
}
});
n = btr_page_get_level(root, &mtr);

View File

@ -258,10 +258,8 @@ btr_cur_latch_leaves(
get_block = btr_block_get(
space, zip_size, page_no, mode, cursor->index, mtr);
if (srv_pass_corrupt_table && !get_block) {
return;
}
ut_a(get_block);
SRV_CORRUPT_TABLE_CHECK(get_block, return;);
#ifdef UNIV_BTR_DEBUG
ut_a(page_is_comp(get_block->frame) == page_is_comp(page));
#endif /* UNIV_BTR_DEBUG */
@ -283,10 +281,8 @@ btr_cur_latch_leaves(
space, zip_size, left_page_no,
sibling_mode, cursor->index, mtr);
if (srv_pass_corrupt_table && !get_block) {
return;
}
ut_a(get_block);
SRV_CORRUPT_TABLE_CHECK(get_block, return;);
#ifdef UNIV_BTR_DEBUG
ut_a(page_is_comp(get_block->frame)
== page_is_comp(page));
@ -309,10 +305,8 @@ btr_cur_latch_leaves(
space, zip_size, page_no,
mode, cursor->index, mtr);
if (srv_pass_corrupt_table && !get_block) {
return;
}
ut_a(get_block);
SRV_CORRUPT_TABLE_CHECK(get_block, return;);
#ifdef UNIV_BTR_DEBUG
ut_a(page_is_comp(get_block->frame) == page_is_comp(page));
#endif /* UNIV_BTR_DEBUG */
@ -325,10 +319,8 @@ btr_cur_latch_leaves(
space, zip_size, right_page_no,
sibling_mode, cursor->index, mtr);
if (srv_pass_corrupt_table && !get_block) {
return;
}
ut_a(get_block);
SRV_CORRUPT_TABLE_CHECK(get_block, return;);
#ifdef UNIV_BTR_DEBUG
ut_a(page_is_comp(get_block->frame)
== page_is_comp(page));
@ -357,10 +349,8 @@ btr_cur_latch_leaves(
left_page_no, mode, cursor->index, mtr);
cursor->left_block = get_block;
if (srv_pass_corrupt_table && !get_block) {
return;
}
ut_a(get_block);
SRV_CORRUPT_TABLE_CHECK(get_block, return;);
#ifdef UNIV_BTR_DEBUG
ut_a(page_is_comp(get_block->frame)
== page_is_comp(page));
@ -373,10 +363,8 @@ btr_cur_latch_leaves(
get_block = btr_block_get(
space, zip_size, page_no, mode, cursor->index, mtr);
if (srv_pass_corrupt_table && !get_block) {
return;
}
ut_a(get_block);
SRV_CORRUPT_TABLE_CHECK(get_block, return;);
#ifdef UNIV_BTR_DEBUG
ut_a(page_is_comp(get_block->frame) == page_is_comp(page));
#endif /* UNIV_BTR_DEBUG */
@ -652,18 +640,19 @@ retry_page_get:
file, line, mtr);
if (block == NULL) {
if (srv_pass_corrupt_table
&& buf_mode != BUF_GET_IF_IN_POOL
&& buf_mode != BUF_GET_IF_IN_POOL_OR_WATCH) {
page_cursor->block = 0;
page_cursor->rec = 0;
if (estimate) {
cursor->path_arr->nth_rec = ULINT_UNDEFINED;
}
goto func_exit;
}
ut_a(buf_mode == BUF_GET_IF_IN_POOL
|| buf_mode == BUF_GET_IF_IN_POOL_OR_WATCH);
SRV_CORRUPT_TABLE_CHECK(buf_mode == BUF_GET_IF_IN_POOL ||
buf_mode == BUF_GET_IF_IN_POOL_OR_WATCH,
{
page_cursor->block = 0;
page_cursor->rec = 0;
if (estimate) {
cursor->path_arr->nth_rec =
ULINT_UNDEFINED;
}
goto func_exit;
});
/* This must be a search to perform an insert/delete
mark/ delete; try using the insert/delete buffer */
@ -739,15 +728,18 @@ retry_page_get:
block->check_index_page_at_flush = TRUE;
page = buf_block_get_frame(block);
if (srv_pass_corrupt_table && !page) {
SRV_CORRUPT_TABLE_CHECK(page,
{
page_cursor->block = 0;
page_cursor->rec = 0;
if (estimate) {
cursor->path_arr->nth_rec = ULINT_UNDEFINED;
}
goto func_exit;
}
ut_a(page);
});
if (rw_latch != RW_NO_LATCH) {
#ifdef UNIV_ZIP_DEBUG
@ -943,15 +935,19 @@ btr_cur_open_at_index_side_func(
file, line, mtr);
page = buf_block_get_frame(block);
if (srv_pass_corrupt_table && !page) {
SRV_CORRUPT_TABLE_CHECK(page,
{
page_cursor->block = 0;
page_cursor->rec = 0;
if (estimate) {
cursor->path_arr->nth_rec = ULINT_UNDEFINED;
cursor->path_arr->nth_rec =
ULINT_UNDEFINED;
}
break;
}
ut_a(page);
/* Can't use break with the macro */
goto exit_loop;
});
ut_ad(index->id == btr_page_get_index_id(page));
@ -1021,6 +1017,7 @@ btr_cur_open_at_index_side_func(
page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
}
exit_loop:
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
@ -1074,12 +1071,13 @@ btr_cur_open_at_rnd_pos_func(
file, line, mtr);
page = buf_block_get_frame(block);
if (srv_pass_corrupt_table && !page) {
SRV_CORRUPT_TABLE_CHECK(page,
{
page_cursor->block = 0;
page_cursor->rec = 0;
break;
}
ut_a(page);
goto exit_loop;
});
ut_ad(index->id == btr_page_get_index_id(page));
@ -1112,6 +1110,7 @@ btr_cur_open_at_rnd_pos_func(
page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
}
exit_loop:
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
@ -1300,10 +1299,7 @@ btr_cur_optimistic_insert(
block = btr_cur_get_block(cursor);
if (srv_pass_corrupt_table && !block) {
return(DB_CORRUPTION);
}
ut_a(block);
SRV_CORRUPT_TABLE_CHECK(block, return(DB_CORRUPTION););
page = buf_block_get_frame(block);
index = cursor->index;
@ -3149,10 +3145,7 @@ btr_cur_optimistic_delete(
block = btr_cur_get_block(cursor);
if (srv_pass_corrupt_table && !block) {
return(DB_CORRUPTION);
}
ut_a(block);
SRV_CORRUPT_TABLE_CHECK(block, return(DB_CORRUPTION););
ut_ad(page_is_leaf(buf_block_get_frame(block)));
@ -3868,10 +3861,7 @@ btr_estimate_number_of_different_key_vals(
page = btr_cur_get_page(&cursor);
if (srv_pass_corrupt_table && !page) {
break;
}
ut_a(page);
SRV_CORRUPT_TABLE_CHECK(page, goto exit_loop;);
rec = page_rec_get_next(page_get_infimum_rec(page));
@ -3957,6 +3947,7 @@ btr_estimate_number_of_different_key_vals(
mtr_commit(&mtr);
}
exit_loop:
/* If we saw k borders between different key values on
n_sample_pages leaf pages, we can estimate how many
there will be in index->stat_n_leaf_pages */

View File

@ -116,10 +116,7 @@ btr_pcur_store_position(
block = btr_pcur_get_block(cursor);
if (srv_pass_corrupt_table && !block) {
return;
}
ut_a(block);
SRV_CORRUPT_TABLE_CHECK(block, return;);
index = btr_cur_get_index(btr_pcur_get_btr_cur(cursor));
@ -439,14 +436,16 @@ btr_pcur_move_to_next_page(
btr_pcur_get_btr_cur(cursor)->index, mtr);
next_page = buf_block_get_frame(next_block);
if (srv_pass_corrupt_table && !next_page) {
SRV_CORRUPT_TABLE_CHECK(next_page,
{
btr_leaf_page_release(btr_pcur_get_block(cursor),
cursor->latch_mode, mtr);
btr_pcur_get_page_cur(cursor)->block = 0;
btr_pcur_get_page_cur(cursor)->rec = 0;
return;
}
ut_a(next_page);
});
#ifdef UNIV_BTR_DEBUG
ut_a(page_is_comp(next_page) == page_is_comp(page));
ut_a(btr_page_get_prev(next_page, mtr)

View File

@ -649,10 +649,7 @@ btr_search_info_update_slow(
block = btr_cur_get_block(cursor);
if (srv_pass_corrupt_table && !block) {
return;
}
ut_a(block);
SRV_CORRUPT_TABLE_CHECK(block, return;);
/* NOTE that the following two function calls do NOT protect
info or block->n_fields etc. with any semaphore, to save CPU time!

View File

@ -2002,27 +2002,6 @@ lookup:
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
}
if (UNIV_UNLIKELY(bpage->space_was_being_deleted)) {
/* This page is obsoleted, should discard and retry */
rw_lock_s_unlock(&buf_pool->page_hash_latch);
mutex_enter(&buf_pool->LRU_list_mutex);
block_mutex = buf_page_get_mutex_enter(bpage);
if (UNIV_UNLIKELY(!block_mutex)) {
mutex_exit(&buf_pool->LRU_list_mutex);
goto lookup;
}
buf_LRU_free_block(bpage, TRUE, TRUE);
mutex_exit(&buf_pool->LRU_list_mutex);
mutex_exit(block_mutex);
block_mutex = NULL;
goto lookup;
}
if (UNIV_UNLIKELY(!bpage->zip.data)) {
/* There is no compressed page. */
err_exit:
@ -2031,11 +2010,11 @@ err_exit:
return(NULL);
}
if (srv_pass_corrupt_table <= 1) {
if (bpage->is_corrupt) {
rw_lock_s_unlock(&buf_pool->page_hash_latch);
return(NULL);
}
if (UNIV_UNLIKELY(bpage->is_corrupt && srv_pass_corrupt_table <= 1)) {
rw_lock_s_unlock(&buf_pool->page_hash_latch);
return(NULL);
}
block_mutex = buf_page_get_mutex_enter(bpage);
@ -2533,26 +2512,6 @@ loop:
block = (buf_block_t*) buf_page_hash_get_low(
buf_pool, space, offset, fold);
if (block) {
if (UNIV_UNLIKELY(block->page.space_was_being_deleted)) {
/* This page is obsoleted, should discard and retry */
rw_lock_s_unlock(&buf_pool->page_hash_latch);
mutex_enter(&buf_pool->LRU_list_mutex);
block_mutex = buf_page_get_mutex_enter((buf_page_t*)block);
if (UNIV_UNLIKELY(!block_mutex)) {
mutex_exit(&buf_pool->LRU_list_mutex);
goto loop;
}
buf_LRU_free_block((buf_page_t*)block, TRUE, TRUE);
mutex_exit(&buf_pool->LRU_list_mutex);
mutex_exit(block_mutex);
block_mutex = NULL;
goto loop;
}
block_mutex = buf_page_get_mutex_enter((buf_page_t*)block);
ut_a(block_mutex);
@ -2640,11 +2599,12 @@ got_block:
return(NULL);
}
if (srv_pass_corrupt_table <= 1) {
if (block->page.is_corrupt) {
mutex_exit(block_mutex);
return(NULL);
}
if (UNIV_UNLIKELY(block->page.is_corrupt &&
srv_pass_corrupt_table <= 1)) {
mutex_exit(block_mutex);
return(NULL);
}
switch (buf_block_get_state(block)) {
@ -3487,28 +3447,12 @@ buf_page_init_for_read(
fold = buf_page_address_fold(space, offset);
retry:
//buf_pool_mutex_enter(buf_pool);
mutex_enter(&buf_pool->LRU_list_mutex);
rw_lock_x_lock(&buf_pool->page_hash_latch);
watch_page = buf_page_hash_get_low(buf_pool, space, offset, fold);
if (UNIV_UNLIKELY(watch_page && watch_page->space_was_being_deleted)) {
mutex_t* block_mutex = buf_page_get_mutex_enter(watch_page);
/* This page is obsoleted, should discard and retry */
rw_lock_x_unlock(&buf_pool->page_hash_latch);
ut_a(block_mutex);
buf_LRU_free_block(watch_page, TRUE, TRUE);
mutex_exit(&buf_pool->LRU_list_mutex);
mutex_exit(block_mutex);
goto retry;
}
if (watch_page && !buf_pool_watch_is_sentinel(buf_pool, watch_page)) {
/* The page is already in the buffer pool. */
watch_page = NULL;
@ -3637,7 +3581,6 @@ err_exit:
bpage->state = BUF_BLOCK_ZIP_PAGE;
bpage->space = space;
bpage->offset = offset;
bpage->space_was_being_deleted = FALSE;
#ifdef UNIV_DEBUG
bpage->in_page_hash = FALSE;
@ -3722,7 +3665,6 @@ buf_page_create(
fold = buf_page_address_fold(space, offset);
retry:
//buf_pool_mutex_enter(buf_pool);
mutex_enter(&buf_pool->LRU_list_mutex);
rw_lock_x_lock(&buf_pool->page_hash_latch);
@ -3730,21 +3672,6 @@ retry:
block = (buf_block_t*) buf_page_hash_get_low(
buf_pool, space, offset, fold);
if (UNIV_UNLIKELY(block && block->page.space_was_being_deleted)) {
mutex_t* block_mutex = buf_page_get_mutex_enter((buf_page_t*)block);
/* This page is obsoleted, should discard and retry */
rw_lock_x_unlock(&buf_pool->page_hash_latch);
ut_a(block_mutex);
buf_LRU_free_block((buf_page_t*)block, TRUE, TRUE);
mutex_exit(&buf_pool->LRU_list_mutex);
mutex_exit(block_mutex);
goto retry;
}
if (block
&& buf_page_in_file(&block->page)
&& !buf_pool_watch_is_sentinel(buf_pool, &block->page)) {
@ -4001,7 +3928,8 @@ buf_page_io_complete(
(ulong) bpage->offset);
}
if (!srv_pass_corrupt_table || !bpage->is_corrupt) {
if (UNIV_LIKELY(!bpage->is_corrupt ||
!srv_pass_corrupt_table)) {
/* From version 3.23.38 up we store the page checksum
to the 4 first bytes of the page end lsn field */
@ -4086,13 +4014,26 @@ corrupt:
}
if (uncompressed && !recv_no_ibuf_operations) {
buf_block_t* block;
ibool update_ibuf_bitmap;
if (UNIV_UNLIKELY(bpage->is_corrupt &&
srv_pass_corrupt_table)) {
block = NULL;
update_ibuf_bitmap = FALSE;
} else {
block = (buf_block_t *) bpage;
update_ibuf_bitmap = TRUE;
}
ibuf_merge_or_delete_for_page(
/* Delete possible entries, if bpage is_corrupt */
(srv_pass_corrupt_table && bpage->is_corrupt) ? NULL :
(buf_block_t*) bpage, bpage->space,
block, bpage->space,
bpage->offset, buf_page_get_zip_size(bpage),
(srv_pass_corrupt_table && bpage->is_corrupt) ? FALSE :
TRUE);
update_ibuf_bitmap);
}
}

View File

@ -459,7 +459,7 @@ buf_flush_ready_for_replace(
if (UNIV_LIKELY(bpage->in_LRU_list && buf_page_in_file(bpage))) {
return((bpage->oldest_modification == 0 || bpage->space_was_being_deleted)
return(bpage->oldest_modification == 0
&& buf_page_get_io_fix(bpage) == BUF_IO_NONE
&& bpage->buf_fix_count == 0);
}
@ -501,13 +501,6 @@ buf_flush_ready_for_flush(
&& buf_page_get_io_fix(bpage) == BUF_IO_NONE) {
ut_ad(bpage->in_flush_list);
if (bpage->space_was_being_deleted) {
/* should be removed from flush_list here */
/* because buf_flush_try_neighbors() cannot flush without fil_space_get_size(space) */
buf_flush_remove(bpage);
return(FALSE);
}
if (flush_type != BUF_FLUSH_LRU) {
return(TRUE);

View File

@ -884,42 +884,6 @@ buf_LRU_flush_or_remove_pages(
}
}
/******************************************************************//**
*/
UNIV_INTERN
void
buf_LRU_mark_space_was_deleted(
/*===========================*/
ulint id) /*!< in: space id */
{
ulint i;
for (i = 0; i < srv_buf_pool_instances; i++) {
buf_pool_t* buf_pool;
buf_page_t* bpage;
buf_pool = buf_pool_from_array(i);
mutex_enter(&buf_pool->LRU_list_mutex);
bpage = UT_LIST_GET_FIRST(buf_pool->LRU);
while (bpage != NULL) {
if (buf_page_get_space(bpage) == id) {
bpage->space_was_being_deleted = TRUE;
}
bpage = UT_LIST_GET_NEXT(LRU, bpage);
}
mutex_exit(&buf_pool->LRU_list_mutex);
/* The AHI entries for the tablespace being deleted should be
removed by now. */
ut_ad(buf_LRU_drop_page_hash_for_tablespace(buf_pool, id)
== 0);
}
}
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
/********************************************************************//**
Insert a compressed block into buf_pool->zip_clean in the LRU order. */
@ -1891,10 +1855,6 @@ buf_LRU_free_block(
return(FALSE);
}
if (bpage->space_was_being_deleted && bpage->oldest_modification != 0) {
buf_flush_remove(bpage);
}
#ifdef UNIV_IBUF_COUNT_DEBUG
ut_a(ibuf_count_get(bpage->space, bpage->offset) == 0);
#endif /* UNIV_IBUF_COUNT_DEBUG */

View File

@ -245,13 +245,7 @@ not_to_recover:
return(0);
}
if (srv_pass_corrupt_table) {
if (*err != DB_SUCCESS) {
bpage->is_corrupt = TRUE;
}
} else {
ut_a(*err == DB_SUCCESS);
}
SRV_CORRUPT_TABLE_CHECK(*err == DB_SUCCESS, bpage->is_corrupt = TRUE;);
if (sync) {
/* The i/o is already completed when we arrive from

View File

@ -4419,7 +4419,7 @@ dict_reload_statistics(
while (index) {
mtr_t mtr;
if (table->is_corrupt) {
if (UNIV_UNLIKELY(table->is_corrupt)) {
ut_a(srv_pass_corrupt_table);
mem_heap_free(heap);
return(FALSE);
@ -4577,7 +4577,7 @@ dict_store_statistics(
heap = mem_heap_create(1000);
while (index) {
if (table->is_corrupt) {
if (UNIV_UNLIKELY(table->is_corrupt)) {
ut_a(srv_pass_corrupt_table);
mem_heap_free(heap);
return;
@ -4771,7 +4771,7 @@ dict_update_statistics(
mtr_t mtr;
ulint size;
if (table->is_corrupt) {
if (UNIV_UNLIKELY(table->is_corrupt)) {
ut_a(srv_pass_corrupt_table);
dict_table_stats_unlock(table, RW_X_LATCH);
return;

View File

@ -2426,15 +2426,11 @@ try_again:
To deal with potential read requests by checking the
::stop_new_ops flag in fil_io() */
if (srv_lazy_drop_table) {
buf_LRU_mark_space_was_deleted(id);
} else {
buf_LRU_flush_or_remove_pages(
id, evict_all
? BUF_REMOVE_ALL_NO_WRITE
: BUF_REMOVE_FLUSH_NO_WRITE);
}
#endif
/* printf("Deleting tablespace %s id %lu\n", space->name, id); */
@ -5304,22 +5300,6 @@ _fil_io(
srv_data_written+= len;
}
/* if the table space was already deleted, space might not exist already. */
if (message
&& space_id < SRV_LOG_SPACE_FIRST_ID
&& ((buf_page_t*)message)->space_was_being_deleted) {
if (mode == OS_AIO_NORMAL) {
buf_page_io_complete(message);
return(DB_SUCCESS); /*fake*/
}
if (type == OS_FILE_READ) {
return(DB_TABLESPACE_DELETED);
} else {
return(DB_SUCCESS); /*fake*/
}
}
/* Reserve the fil_system mutex and make sure that we can open at
least one file while holding it, if the file is not already open */
@ -5423,35 +5403,38 @@ _fil_io(
ut_a(byte_offset % OS_MIN_LOG_BLOCK_SIZE == 0);
ut_a((len % OS_MIN_LOG_BLOCK_SIZE) == 0);
if (srv_pass_corrupt_table == 1 && space->is_corrupt) {
#ifndef UNIV_HOTBACKUP
if (UNIV_UNLIKELY(space->is_corrupt && srv_pass_corrupt_table)) {
/* should ignore i/o for the crashed space */
mutex_enter(&fil_system->mutex);
fil_node_complete_io(node, fil_system, type);
mutex_exit(&fil_system->mutex);
if (mode == OS_AIO_NORMAL) {
ut_a(space->purpose == FIL_TABLESPACE);
buf_page_io_complete(message);
}
if (type == OS_FILE_READ) {
return(DB_TABLESPACE_DELETED);
} else {
return(DB_SUCCESS);
}
} else {
if (srv_pass_corrupt_table > 1 && space->is_corrupt) {
/* should ignore write i/o for the crashed space */
if (type == OS_FILE_WRITE) {
mutex_enter(&fil_system->mutex);
fil_node_complete_io(node, fil_system, type);
mutex_exit(&fil_system->mutex);
if (mode == OS_AIO_NORMAL) {
ut_a(space->purpose == FIL_TABLESPACE);
buf_page_io_complete(message);
}
return(DB_SUCCESS);
if (srv_pass_corrupt_table == 1 ||
type == OS_FILE_WRITE) {
mutex_enter(&fil_system->mutex);
fil_node_complete_io(node, fil_system, type);
mutex_exit(&fil_system->mutex);
if (mode == OS_AIO_NORMAL) {
ut_a(space->purpose == FIL_TABLESPACE);
buf_page_io_complete(message);
}
}
#ifdef UNIV_HOTBACKUP
if (srv_pass_corrupt_table == 1 && type == OS_FILE_READ) {
return(DB_TABLESPACE_DELETED);
} else if (type == OS_FILE_WRITE) {
return(DB_SUCCESS);
}
} /**/
/* Queue the aio request */
ret = os_aio(type, mode | wake_later, node->name, node->handle, buf,
offset_low, offset_high, len, node, message, space_id,
trx);
#else
/* In ibbackup do normal i/o, not aio */
if (type == OS_FILE_READ) {
ret = os_file_read(node->handle, buf, offset_low, offset_high,
@ -5460,26 +5443,7 @@ _fil_io(
ret = os_file_write(node->name, node->handle, buf,
offset_low, offset_high, len);
}
#else
/* Queue the aio request */
ret = os_aio(type, mode | wake_later, node->name, node->handle, buf,
offset_low, offset_high, len, node, message, space_id, trx);
#endif
} /**/
/* if the table space was already deleted, space might not exist already. */
if (message
&& space_id < SRV_LOG_SPACE_FIRST_ID
&& ((buf_page_t*)message)->space_was_being_deleted) {
if (mode == OS_AIO_SYNC) {
if (type == OS_FILE_READ) {
return(DB_TABLESPACE_DELETED);
} else {
return(DB_SUCCESS); /*fake*/
}
}
}
ut_a(ret);
@ -5603,21 +5567,6 @@ fil_aio_wait(
&message, &type, &space_id);
}
/* if the table space was already deleted, fil_node might not exist already. */
if (message
&& space_id < SRV_LOG_SPACE_FIRST_ID
&& ((buf_page_t*)message)->space_was_being_deleted) {
/* intended not to be uncompress read page */
ut_a(buf_page_get_io_fix_unlocked(message) == BUF_IO_WRITE
|| !buf_page_get_zip_size(message)
|| buf_page_get_state(message) != BUF_BLOCK_FILE_PAGE);
srv_set_io_thread_op_info(segment, "complete io for buf page");
buf_page_io_complete(message);
return;
}
ut_a(ret);
if (UNIV_UNLIKELY(fil_node == NULL)) {
ut_ad(srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS);

View File

@ -317,10 +317,7 @@ fsp_get_space_header(
block = buf_page_get(id, zip_size, 0, RW_X_LATCH, mtr);
if (srv_pass_corrupt_table && !block) {
return(0);
}
ut_a(block);
SRV_CORRUPT_TABLE_CHECK(block, return(0););
header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
@ -731,10 +728,7 @@ xdes_get_descriptor(
block = buf_page_get(space, zip_size, 0, RW_X_LATCH, mtr);
if (srv_pass_corrupt_table && !block) {
return(0);
}
ut_a(block);
SRV_CORRUPT_TABLE_CHECK(block, return(0););
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
@ -1882,10 +1876,7 @@ fsp_seg_inode_page_find_free(
{
fseg_inode_t* inode;
if (srv_pass_corrupt_table && !page) {
return(ULINT_UNDEFINED);
}
ut_a(page);
SRV_CORRUPT_TABLE_CHECK(page, return(ULINT_UNDEFINED););
for (; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
@ -1999,10 +1990,7 @@ fsp_alloc_seg_inode(
page = buf_block_get_frame(block);
if (srv_pass_corrupt_table && !page) {
return(0);
}
ut_a(page);
SRV_CORRUPT_TABLE_CHECK(page, return(0););
n = fsp_seg_inode_page_find_free(page, 0, zip_size, mtr);
@ -2097,10 +2085,7 @@ fseg_inode_try_get(
inode = fut_get_ptr(space, zip_size, inode_addr, RW_X_LATCH, mtr);
if (srv_pass_corrupt_table && !inode) {
return(0);
}
ut_a(inode);
SRV_CORRUPT_TABLE_CHECK(inode, return(0););
if (UNIV_UNLIKELY(!mach_read_from_8(inode + FSEG_ID))) {
@ -2128,7 +2113,7 @@ fseg_inode_get(
{
fseg_inode_t* inode
= fseg_inode_try_get(header, space, zip_size, mtr);
ut_a(srv_pass_corrupt_table || inode);
SRV_CORRUPT_TABLE_CHECK(inode, ; /* do nothing */);
return(inode);
}
@ -3320,12 +3305,12 @@ fseg_free_page_low(
descr = xdes_get_descriptor(space, zip_size, page, mtr);
if (srv_pass_corrupt_table && !descr) {
SRV_CORRUPT_TABLE_CHECK(descr,
{
/* The page may be corrupt. pass it. */
return;
}
});
ut_a(descr);
if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)) {
fputs("InnoDB: Dump of the tablespace extent descriptor: ",
stderr);
@ -3574,15 +3559,15 @@ fseg_free_step(
descr = xdes_get_descriptor(space, zip_size, header_page, mtr);
if (srv_pass_corrupt_table && !descr) {
SRV_CORRUPT_TABLE_CHECK(descr,
{
/* The page may be corrupt. pass it. */
return(TRUE);
}
});
/* Check that the header resides on a page which has not been
freed yet */
ut_a(descr);
ut_a(xdes_get_bit(descr, XDES_FREE_BIT,
header_page % FSP_EXTENT_SIZE, mtr) == FALSE);
inode = fseg_inode_try_get(header, space, zip_size, mtr);
@ -3663,11 +3648,11 @@ fseg_free_step_not_header(
inode = fseg_inode_get(header, space, zip_size, mtr);
if (srv_pass_corrupt_table && !inode) {
SRV_CORRUPT_TABLE_CHECK(inode,
{
/* ignore the corruption */
return(TRUE);
}
ut_a(inode);
});
descr = fseg_get_first_extent(inode, space, zip_size, mtr);

View File

@ -202,6 +202,8 @@ static ulong innobase_sys_stats_root_page = 0;
#endif
static my_bool innobase_buffer_pool_shm_checksum = TRUE;
static uint innobase_buffer_pool_shm_key = 0;
static ulong srv_lazy_drop_table = 0;
static char* internal_innobase_data_file_path = NULL;
@ -1910,7 +1912,7 @@ trx_is_started(
/*===========*/
trx_t* trx) /* in: transaction */
{
return(trx->conc_state != TRX_NOT_STARTED);
return(trx->state != TRX_NOT_STARTED);
}
/*********************************************************************//**
@ -3009,6 +3011,12 @@ innobase_change_buffering_inited_ok:
"InnoDB: innodb_buffer_pool_shm_key was ignored.\n");
}
if (srv_lazy_drop_table) {
fprintf(stderr,
"InnoDB: Warning: "
"innodb_lazy_drop_table is deprecated and ignored.\n");
}
srv_mem_pool_size = (ulint) innobase_additional_mem_pool_size;
srv_n_file_io_threads = (ulint) innobase_file_io_threads;
@ -4599,7 +4607,8 @@ ha_innobase::open(
DBUG_RETURN(1);
}
if (srv_pass_corrupt_table <= 1 && share->ib_table && share->ib_table->is_corrupt) {
if (UNIV_UNLIKELY(share->ib_table && share->ib_table->is_corrupt &&
srv_pass_corrupt_table <= 1)) {
free_share(share);
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
@ -4624,7 +4633,8 @@ retry:
/* Get pointer to a table object in InnoDB dictionary cache */
ib_table = dict_table_get(norm_name, TRUE);
if (srv_pass_corrupt_table <= 1 && ib_table && ib_table->is_corrupt) {
if (UNIV_UNLIKELY(ib_table && ib_table->is_corrupt &&
srv_pass_corrupt_table <= 1)) {
free_share(share);
my_free(upd_buf);
upd_buf = NULL;
@ -6692,7 +6702,8 @@ ha_innobase::index_read(
ha_statistic_increment(&SSV::ha_read_key_count);
if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) {
if (UNIV_UNLIKELY(share->ib_table->is_corrupt &&
srv_pass_corrupt_table <= 1)) {
DBUG_RETURN(HA_ERR_CRASHED);
}
@ -6763,7 +6774,8 @@ ha_innobase::index_read(
ret = DB_UNSUPPORTED;
}
if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) {
if (UNIV_UNLIKELY(share->ib_table->is_corrupt &&
srv_pass_corrupt_table <= 1)) {
DBUG_RETURN(HA_ERR_CRASHED);
}
@ -6881,7 +6893,8 @@ ha_innobase::change_active_index(
{
DBUG_ENTER("change_active_index");
if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) {
if (UNIV_UNLIKELY(share->ib_table->is_corrupt &&
srv_pass_corrupt_table <= 1)) {
DBUG_RETURN(HA_ERR_CRASHED);
}
@ -6998,7 +7011,8 @@ ha_innobase::general_fetch(
DBUG_ENTER("general_fetch");
if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) {
if (UNIV_UNLIKELY(share->ib_table->is_corrupt &&
srv_pass_corrupt_table <= 1)) {
DBUG_RETURN(HA_ERR_CRASHED);
}
@ -7011,7 +7025,8 @@ ha_innobase::general_fetch(
innodb_srv_conc_exit_innodb(prebuilt->trx);
if (srv_pass_corrupt_table <= 1 && share->ib_table->is_corrupt) {
if (UNIV_UNLIKELY(share->ib_table->is_corrupt &&
srv_pass_corrupt_table <= 1)) {
DBUG_RETURN(HA_ERR_CRASHED);
}
@ -9039,7 +9054,7 @@ ha_innobase::info_low(
prebuilt->trx->op_info = "confirming rows of SYS_STATS to store statistics";
ut_a(prebuilt->trx->conc_state == TRX_NOT_STARTED);
ut_a(!trx_is_started(prebuilt->trx));
for (index = dict_table_get_first_index(ib_table);
index != NULL;
@ -9052,7 +9067,7 @@ ha_innobase::info_low(
innobase_commit_low(prebuilt->trx);
}
ut_a(prebuilt->trx->conc_state == TRX_NOT_STARTED);
ut_a(!trx_is_started(prebuilt->trx));
}
prebuilt->trx->op_info = "updating table statistics";
@ -13020,8 +13035,7 @@ static MYSQL_SYSVAR_ENUM(corrupt_table_action, srv_pass_corrupt_table,
static MYSQL_SYSVAR_ULONG(lazy_drop_table, srv_lazy_drop_table,
PLUGIN_VAR_RQCMDARG,
"At deleting tablespace, only miminum needed processes at the time are done. "
"e.g. for http://bugs.mysql.com/51325",
"[Deprecated option] no effect",
NULL, NULL, 0, 0, 1, 0);
static MYSQL_SYSVAR_BOOL(locking_fake_changes, srv_fake_changes_locks,

View File

@ -59,7 +59,7 @@ btr_block_get_func(
block = buf_page_get_gen(space, zip_size, page_no, mode,
NULL, BUF_GET, file, line, mtr);
ut_a(srv_pass_corrupt_table || block);
SRV_CORRUPT_TABLE_CHECK(block, ; /* do nothing */);
if (block && mode != RW_NO_LATCH) {

View File

@ -1587,7 +1587,6 @@ struct buf_page_struct{
0 if the block was never accessed
in the buffer pool. Protected by
block mutex */
ibool space_was_being_deleted;
ibool is_corrupt;
# if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
ibool file_page_was_freed;

View File

@ -430,7 +430,6 @@ buf_block_set_file_page(
buf_block_set_state(block, BUF_BLOCK_FILE_PAGE);
block->page.space = space;
block->page.offset = page_no;
block->page.space_was_being_deleted = FALSE;
}
/*********************************************************************//**
@ -712,13 +711,7 @@ buf_block_get_frame(
/*================*/
const buf_block_t* block) /*!< in: pointer to the control block */
{
ut_a(srv_pass_corrupt_table || block);
if (srv_pass_corrupt_table && !block) {
return(0);
}
ut_ad(block);
SRV_CORRUPT_TABLE_CHECK(block, return(0););
switch (buf_block_get_state(block)) {
case BUF_BLOCK_ZIP_FREE:

View File

@ -70,7 +70,7 @@ buf_flush_note_modification(
ut_ad(!buf_pool_mutex_own(buf_pool));
ut_ad(!buf_flush_list_mutex_own(buf_pool));
ut_ad(log_flush_order_mutex_own());
ut_ad(!mtr->made_dirty || log_flush_order_mutex_own());
ut_ad(mtr->start_lsn != 0);
ut_ad(mtr->modifications);

View File

@ -73,13 +73,6 @@ buf_LRU_flush_or_remove_pages(
enum buf_remove_t buf_remove);/*!< in: remove or flush
strategy */
/******************************************************************//**
*/
UNIV_INTERN
void
buf_LRU_mark_space_was_deleted(
/*===========================*/
ulint id); /*!< in: space id */
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
/********************************************************************//**
Insert a compressed block into buf_pool->zip_clean in the LRU order. */

View File

@ -50,10 +50,7 @@ fut_get_ptr(
block = buf_page_get(space, zip_size, addr.page, rw_latch, mtr);
if (srv_pass_corrupt_table && !block) {
return(0);
}
ut_a(block);
SRV_CORRUPT_TABLE_CHECK(block, return(0););
ptr = buf_block_get_frame(block) + addr.boffset;

View File

@ -122,16 +122,24 @@ UNIV_INLINE
void
log_free_check(void);
/*================*/
/************************************************************//**
Opens the log for log_write_low. The log must be closed with log_close and
released with log_release.
@return start lsn of the log record */
UNIV_INTERN
/**************************************************************************//**
Locks the log mutex and opens the log for log_write_low. The log must be closed
with log_close and released with log_release.
@return start lsn of the log record */
UNIV_INLINE
ib_uint64_t
log_reserve_and_open(
/*=================*/
ulint len); /*!< in: length of data to be catenated */
/************************************************************//**
Opens the log for log_write_low. The log must be closed with log_close.
@return start lsn of the log record */
UNIV_INTERN
ib_uint64_t
log_open(
/*=====*/
ulint len); /*!< in: length of data to be catenated */
/************************************************************//**
Writes to the log the string given. It is assumed that the caller holds the
log mutex. */
UNIV_INTERN

View File

@ -332,10 +332,10 @@ log_reserve_and_write_fast(
if (data_len >= OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE) {
/* The string does not fit within the current log block
or the log block would become full */
mutex_exit(&log_sys->mutex);
/* The string does not fit within the current log block or the
log block would become full. Do not release the log mutex,
because it has to be reacquired immediately for the "slow" write
procedure via log_write_low(). */
return(0);
}
@ -382,6 +382,21 @@ log_reserve_and_write_fast(
return(log_sys->lsn);
}
/**************************************************************************//**
Locks the log mutex and opens the log for log_write_low. The log must be closed
with log_close and released with log_release.
@return start lsn of the log record */
UNIV_INLINE
ib_uint64_t
log_reserve_and_open(
/*=================*/
ulint len) /*!< in: length of data to be catenated */
{
mutex_enter(&(log_sys->mutex));
return log_open(len);
}
/***********************************************************************//**
Releases the log mutex. */
UNIV_INLINE

View File

@ -375,6 +375,8 @@ struct mtr_struct{
ibool modifications;
/* TRUE if the mtr made modifications to
buffer pool pages */
ibool made_dirty;/*!< TRUE if mtr has made at least
one buffer pool page dirty */
ulint n_log_recs;
/* count of how many page initial log records
have been written to the mtr log */

View File

@ -29,6 +29,17 @@ Created 11/26/1995 Heikki Tuuri
#endif /* !UNIV_HOTBACKUP */
#include "mach0data.h"
/***************************************************//**
Checks if a mini-transaction is dirtying a clean page.
@return TRUE if the mtr is dirtying a clean page. */
UNIV_INTERN
ibool
mtr_block_dirtied(
/*==============*/
const buf_block_t* block) /*!< in: block being x-fixed */
__attribute__((nonnull,warn_unused_result));
/***************************************************************//**
Starts a mini-transaction. */
UNIV_INLINE
@ -47,6 +58,7 @@ mtr_start(
mtr->inside_ibuf = FALSE;
mtr->n_log_recs = 0;
mtr->n_freed_pages = 0;
mtr->made_dirty = FALSE;
ut_d(mtr->state = MTR_ACTIVE);
ut_d(mtr->magic_n = MTR_MAGIC_N);
@ -65,6 +77,15 @@ mtr_memo_push(
dyn_array_t* memo;
mtr_memo_slot_t* slot;
/* If this mtr has x-fixed a clean page then we set
the made_dirty flag. This tells us if we need to
grab log_flush_order_mutex at mtr_commit so that we
can insert the dirtied page to the flush list. */
if (type == MTR_MEMO_PAGE_X_FIX && !mtr->made_dirty) {
mtr->made_dirty =
mtr_block_dirtied((const buf_block_t *)object);
}
ut_ad(object);
ut_ad(type >= MTR_MEMO_PAGE_S_FIX);
ut_ad(type <= MTR_MEMO_X_LOCK);

View File

@ -32,6 +32,7 @@ Created 2/16/1997 Heikki Tuuri
#include "ut0byte.h"
#include "ut0lst.h"
#include "trx0trx.h"
#include "trx0sys.h"
#include "read0types.h"
/*********************************************************************//**
@ -44,8 +45,11 @@ read_view_open_now(
/*===============*/
trx_id_t cr_trx_id, /*!< in: trx_id of creating
transaction, or 0 used in purge */
mem_heap_t* heap); /*!< in: memory heap from which
allocated */
read_view_t* view, /*!< in: current read view or NULL if it
doesn't exist yet */
ibool exclude_self); /*!< in: TRUE, if cr_trx_id should be
excluded from the resulting view */
/*********************************************************************//**
Makes a copy of the oldest existing read view, or opens a new. The view
must be closed with ..._close.
@ -56,8 +60,8 @@ read_view_oldest_copy_or_open_new(
/*==============================*/
trx_id_t cr_trx_id, /*!< in: trx_id of creating
transaction, or 0 used in purge */
mem_heap_t* heap); /*!< in: memory heap from which
allocated */
read_view_t* view); /*!< in: pre-allocated view array or
NULL if a new one needs to be created */
/*********************************************************************//**
Closes a read view. */
UNIV_INTERN
@ -66,6 +70,13 @@ read_view_close(
/*============*/
read_view_t* view); /*!< in: read view */
/*********************************************************************//**
Frees memory allocated by a read view. */
UNIV_INTERN
void
read_view_free(
/*===========*/
read_view_t* view); /*< in: read view */
/*********************************************************************//**
Closes a consistent read view for MySQL. This function is called at an SQL
statement end if the trx isolation level is <= TRX_ISO_READ_COMMITTED. */
UNIV_INTERN
@ -143,16 +154,20 @@ struct read_view_struct{
are strictly smaller (<) than this value.
In other words,
this is the "low water mark". */
ulint n_trx_ids;
ulint n_descr;
/*!< Number of cells in the trx_ids array */
trx_id_t* trx_ids;/*!< Additional trx ids which the read should
not see: typically, these are the active
ulint max_descr;
/*!< Maximum number of cells in the trx_ids
array */
trx_id_t* descriptors;
/*!< Array of trx descriptors which the read
should not see: typically, these are the active
transactions at the time when the read is
serialized, except the reading transaction
itself; the trx ids in this array are in a
descending order. These trx_ids should be
between the "low" and "high" water marks,
that is, up_limit_id and low_limit_id. */
between the "low" and "high" water marks, that
is, up_limit_id and low_limit_id. */
trx_id_t creator_trx_id;
/*!< trx id of creating transaction, or
0 used in purge */

View File

@ -25,6 +25,11 @@ Created 2/16/1997 Heikki Tuuri
/*********************************************************************//**
Gets the nth trx id in a read view.
Upstream code stores array of trx_ids in the descending order. Percona Server
keeps it in the ascending order for performance reasons. Let us keep the
semantics.
@return trx id */
UNIV_INLINE
trx_id_t
@ -33,13 +38,17 @@ read_view_get_nth_trx_id(
const read_view_t* view, /*!< in: read view */
ulint n) /*!< in: position */
{
ut_ad(n < view->n_trx_ids);
ut_ad(n < view->n_descr);
return(*(view->trx_ids + n));
return(view->descriptors[view->n_descr - 1 - n]);
}
/*********************************************************************//**
Sets the nth trx id in a read view. */
Sets the nth trx id in a read view.
Upstream code stores array of trx_ids in the descending order. Percona Server
keeps it in the ascending order for performance reasons. Let us keep the
semantics. */
UNIV_INLINE
void
read_view_set_nth_trx_id(
@ -48,9 +57,9 @@ read_view_set_nth_trx_id(
ulint n, /*!< in: position */
trx_id_t trx_id) /*!< in: trx id to set */
{
ut_ad(n < view->n_trx_ids);
ut_ad(n < view->n_descr);
*(view->trx_ids + n) = trx_id;
view->descriptors[view->n_descr - 1 - n] = trx_id;
}
/*********************************************************************//**
@ -63,9 +72,6 @@ read_view_sees_trx_id(
const read_view_t* view, /*!< in: read view */
trx_id_t trx_id) /*!< in: trx id */
{
ulint n_ids;
ulint i;
if (trx_id < view->up_limit_id) {
return(TRUE);
@ -76,21 +82,8 @@ read_view_sees_trx_id(
return(FALSE);
}
/* We go through the trx ids in the array smallest first: this order
may save CPU time, because if there was a very long running
transaction in the trx id array, its trx id is looked at first, and
the first two comparisons may well decide the visibility of trx_id. */
/* Do a binary search over this view's descriptors array */
n_ids = view->n_trx_ids;
for (i = 0; i < n_ids; i++) {
trx_id_t view_trx_id
= read_view_get_nth_trx_id(view, n_ids - i - 1);
if (trx_id <= view_trx_id) {
return(trx_id != view_trx_id);
}
}
return(TRUE);
return(trx_find_descriptor(view->descriptors, view->n_descr,
trx_id) == NULL);
}

View File

@ -266,9 +266,22 @@ extern ulint srv_adaptive_flushing_method;
extern ulint srv_expand_import;
extern ulint srv_pass_corrupt_table;
extern ulint srv_dict_size_limit;
/* Helper macro to support srv_pass_corrupt_table checks. If 'cond' is FALSE,
execute 'code' if srv_pass_corrupt_table is non-zero, or trigger a fatal error
otherwise. The break statement in 'code' will obviously not work as expected. */
extern ulint srv_lazy_drop_table;
#define SRV_CORRUPT_TABLE_CHECK(cond,code) \
do { \
if (UNIV_UNLIKELY(!(cond))) { \
if (srv_pass_corrupt_table) { \
code \
} else { \
ut_error; \
} \
} \
} while(0)
extern ulint srv_dict_size_limit;
/*-------------------------------------------*/
extern ulint srv_n_rows_inserted;

View File

@ -143,6 +143,7 @@ struct trx_purge_struct{
obtaining an s-latch here. */
read_view_t* view; /*!< The purge will not remove undo logs
which are >= this view (purge view) */
read_view_t* prebuilt_view; /*!< Pre-built view array */
ulonglong n_pages_handled;/*!< Approximate number of undo log
pages processed in purge */
ulonglong handle_limit; /*!< Target of how many pages to get

View File

@ -249,6 +249,17 @@ trx_id_t
trx_sys_get_new_trx_id(void);
/*========================*/
/*************************************************************//**
Find a slot for a given trx ID in a descriptors array.
@return: slot pointer */
UNIV_INLINE
trx_id_t*
trx_find_descriptor(
/*================*/
const trx_id_t* descriptors, /*!< in: descriptors array */
ulint n_descr, /*!< in: array size */
trx_id_t trx_id); /*!< in: trx pointer */
#ifdef UNIV_DEBUG
/* Flag to control TRX_RSEG_N_SLOTS behavior debugging. */
extern uint trx_rseg_n_slots_debug;
@ -633,6 +644,8 @@ identifier is added to this 64-bit constant. */
| TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_LOW)
/* @} */
#define TRX_DESCR_ARRAY_INITIAL_SIZE 1000
#ifndef UNIV_HOTBACKUP
/** Doublewrite control struct */
struct trx_doublewrite_struct{
@ -660,16 +673,41 @@ struct trx_sys_struct{
trx_id_t max_trx_id; /*!< The smallest number not yet
assigned as a transaction id or
transaction number */
char pad1[64]; /*!< Ensure max_trx_id does not share
cache line with other fields. */
trx_id_t* descriptors; /*!< Array of trx descriptors */
ulint descr_n_max; /*!< The current size of the descriptors
array. */
char pad2[64]; /*!< Ensure static descriptor fields
do not share cache lines with
descr_n_used */
ulint descr_n_used; /*!< Number of used elements in the
descriptors array. */
char pad3[64]; /*!< Ensure descriptors do not share
cache line with other fields */
UT_LIST_BASE_NODE_T(trx_t) trx_list;
/*!< List of active and committed in
memory transactions, sorted on trx id,
biggest first */
char pad4[64]; /*!< Ensure list base nodes do not
share cache line with other fields */
UT_LIST_BASE_NODE_T(trx_t) mysql_trx_list;
/*!< List of transactions created
for MySQL */
char pad5[64]; /*!< Ensure list base nodes do not
share cache line with other fields */
UT_LIST_BASE_NODE_T(trx_t) trx_serial_list;
/*!< trx->no ordered List of
transactions in either TRX_PREPARED or
TRX_ACTIVE which have already been
assigned a serialization number */
char pad6[64]; /*!< Ensure trx_serial_list does not
share cache line with other fields */
UT_LIST_BASE_NODE_T(trx_rseg_t) rseg_list;
/*!< List of rollback segment
objects */
char pad7[64]; /*!< Ensure list base nodes do not
share cache line with other fields */
trx_rseg_t* latest_rseg; /*!< Latest rollback segment in the
round-robin assignment of rollback
segments to transactions */

View File

@ -367,28 +367,11 @@ trx_is_active(
/*==========*/
trx_id_t trx_id) /*!< in: trx id of the transaction */
{
trx_t* trx;
ut_ad(mutex_own(&(kernel_mutex)));
if (trx_id < trx_list_get_min_trx_id()) {
return(FALSE);
}
if (UNIV_UNLIKELY(trx_id >= trx_sys->max_trx_id)) {
/* There must be corruption: we return TRUE because this
function is only called by lock_clust_rec_some_has_impl()
and row_vers_impl_x_locked_off_kernel() and they have
diagnostic prints in this case */
return(TRUE);
}
trx = trx_get_on_id(trx_id);
if (trx && (trx->conc_state == TRX_ACTIVE
|| trx->conc_state == TRX_PREPARED)) {
if (trx_find_descriptor(trx_sys->descriptors,
trx_sys->descr_n_used,
trx_id)) {
return(TRUE);
}
@ -425,4 +408,27 @@ trx_sys_get_new_trx_id(void)
return(id);
}
/*************************************************************//**
Find a slot for a given trx ID in a descriptors array.
@return: slot pointer */
UNIV_INLINE
trx_id_t*
trx_find_descriptor(
/*================*/
const trx_id_t* descriptors, /*!< in: descriptors array */
ulint n_descr, /*!< in: array size */
trx_id_t trx_id) /*!< in: trx pointer */
{
ut_ad(descriptors != trx_sys->descriptors ||
mutex_own(&kernel_mutex));
if (UNIV_UNLIKELY(n_descr == 0)) {
return(NULL);
}
return((trx_id_t *) bsearch(&trx_id, descriptors, n_descr,
sizeof(trx_id_t), trx_descr_cmp));
}
#endif /* !UNIV_HOTBACKUP */

View File

@ -447,6 +447,23 @@ trx_get_que_state_str(
/*==================*/
const trx_t* trx); /*!< in: transaction */
/*************************************************************//**
Callback function for trx_find_descriptor() to compare trx IDs. */
UNIV_INTERN
int
trx_descr_cmp(
/*==========*/
const void *a, /*!< in: pointer to first comparison argument */
const void *b); /*!< in: pointer to second comparison argument */
/*************************************************************//**
Release a slot for a given trx in the global descriptors array. */
UNIV_INTERN
void
trx_release_descriptor(
/*===================*/
trx_t* trx); /*!< in: trx pointer */
/* Signal to a transaction */
struct trx_sig_struct{
unsigned type:3; /*!< signal type */
@ -477,10 +494,18 @@ struct trx_struct{
const char* op_info; /*!< English text describing the
current operation, or an empty
string */
ulint conc_state; /*!< state of the trx from the point
of view of concurrency control:
TRX_ACTIVE, TRX_COMMITTED_IN_MEMORY,
... */
ulint state; /*!< state of the trx from the point of
view of concurrency control: TRX_ACTIVE,
TRX_COMMITTED_IN_MEMORY, ... This was
called 'conc_state' in the upstream and
has been renamed in Percona Server,
because changing it's value to/from
either TRX_ACTIVE or TRX_PREPARED
requires calling
trx_reserve_descriptor() /
trx_release_descriptor(). Different name
ensures we notice any new code changing
the state. */
/*------------------------------*/
/* MySQL has a transaction coordinator to coordinate two phase
commit between multiple storage engines and the binary log. When
@ -495,6 +520,9 @@ struct trx_struct{
also be set to 1. This is used in the
XA code */
unsigned called_commit_ordered:1;/* 1 if innobase_commit_ordered has run. */
unsigned is_in_trx_serial_list:1;
/* Set when transaction is in the
trx_serial_list */
/*------------------------------*/
ulint isolation_level;/* TRX_ISO_REPEATABLE_READ, ... */
ulint check_foreigns; /* normally TRUE, but if the user
@ -628,6 +656,9 @@ struct trx_struct{
UT_LIST_NODE_T(trx_t)
mysql_trx_list; /*!< list of transactions created for
MySQL */
UT_LIST_NODE_T(trx_t)
trx_serial_list;/*!< list node for
trx_sys->trx_serial_list */
/*------------------------------*/
ulint error_state; /*!< 0 if no error, otherwise error
number; NOTE That ONLY the thread
@ -686,9 +717,6 @@ struct trx_struct{
UT_LIST_BASE_NODE_T(lock_t)
trx_locks; /*!< locks reserved by the transaction */
/*------------------------------*/
mem_heap_t* global_read_view_heap;
/* memory heap for the global read
view */
read_view_t* global_read_view;
/* consistent read view associated
to a transaction or NULL */
@ -698,6 +726,7 @@ struct trx_struct{
associated to a transaction (i.e.
same as global_read_view) or read view
associated to a cursor */
read_view_t* prebuilt_view; /* pre-built view array */
/*------------------------------*/
UT_LIST_BASE_NODE_T(trx_named_savept_t)
trx_savepoints; /*!< savepoints set with SAVEPOINT ...,

View File

@ -31,9 +31,9 @@ trx_start_if_not_started(
/*=====================*/
trx_t* trx) /*!< in: transaction */
{
ut_ad(trx->conc_state != TRX_COMMITTED_IN_MEMORY);
ut_ad(trx->state != TRX_COMMITTED_IN_MEMORY);
if (trx->conc_state == TRX_NOT_STARTED) {
if (trx->state == TRX_NOT_STARTED) {
trx_start(trx, ULINT_UNDEFINED);
}
@ -48,9 +48,9 @@ trx_start_if_not_started_low(
/*=========================*/
trx_t* trx) /*!< in: transaction */
{
ut_ad(trx->conc_state != TRX_COMMITTED_IN_MEMORY);
ut_ad(trx->state != TRX_COMMITTED_IN_MEMORY);
if (trx->conc_state == TRX_NOT_STARTED) {
if (trx->state == TRX_NOT_STARTED) {
trx_start_low(trx, ULINT_UNDEFINED);
}

View File

@ -4652,7 +4652,7 @@ lock_print_info_all_transactions(
trx = UT_LIST_GET_FIRST(trx_sys->mysql_trx_list);
while (trx) {
if (trx->conc_state == TRX_NOT_STARTED) {
if (trx->state == TRX_NOT_STARTED) {
fputs("---", file);
trx_print(file, trx, 600);
}
@ -4820,9 +4820,9 @@ lock_table_queue_validate(
lock = UT_LIST_GET_FIRST(table->locks);
while (lock) {
ut_a(((lock->trx)->conc_state == TRX_ACTIVE)
|| ((lock->trx)->conc_state == TRX_PREPARED)
|| ((lock->trx)->conc_state == TRX_COMMITTED_IN_MEMORY));
ut_a(((lock->trx)->state == TRX_ACTIVE)
|| ((lock->trx)->state == TRX_PREPARED)
|| ((lock->trx)->state == TRX_COMMITTED_IN_MEMORY));
if (!lock_get_wait(lock)) {
@ -4870,7 +4870,7 @@ lock_rec_queue_validate(
lock = lock_rec_get_first(block, heap_no);
while (lock) {
switch(lock->trx->conc_state) {
switch(lock->trx->state) {
case TRX_ACTIVE:
case TRX_PREPARED:
case TRX_COMMITTED_IN_MEMORY:
@ -4957,9 +4957,9 @@ lock_rec_queue_validate(
lock = lock_rec_get_first(block, heap_no);
while (lock) {
ut_a(lock->trx->conc_state == TRX_ACTIVE
|| lock->trx->conc_state == TRX_PREPARED
|| lock->trx->conc_state == TRX_COMMITTED_IN_MEMORY);
ut_a(lock->trx->state == TRX_ACTIVE
|| lock->trx->state == TRX_PREPARED
|| lock->trx->state == TRX_COMMITTED_IN_MEMORY);
ut_a(trx_in_trx_list(lock->trx));
if (index) {
@ -5036,9 +5036,9 @@ loop:
}
ut_a(trx_in_trx_list(lock->trx));
ut_a(lock->trx->conc_state == TRX_ACTIVE
|| lock->trx->conc_state == TRX_PREPARED
|| lock->trx->conc_state == TRX_COMMITTED_IN_MEMORY);
ut_a(lock->trx->state == TRX_ACTIVE
|| lock->trx->state == TRX_PREPARED
|| lock->trx->state == TRX_COMMITTED_IN_MEMORY);
# ifdef UNIV_SYNC_DEBUG
/* Only validate the record queues when this thread is not

View File

@ -263,13 +263,12 @@ log_check_tracking_margin(
}
/************************************************************//**
Opens the log for log_write_low. The log must be closed with log_close and
released with log_release.
Opens the log for log_write_low. The log must be closed with log_close.
@return start lsn of the log record */
UNIV_INTERN
ib_uint64_t
log_reserve_and_open(
/*=================*/
log_open(
/*=====*/
ulint len) /*!< in: length of data to be catenated */
{
log_t* log = log_sys;
@ -282,7 +281,6 @@ log_reserve_and_open(
ut_a(len < log->buf_size / 2);
loop:
mutex_enter(&(log->mutex));
ut_ad(!recv_no_log_write);
/* Calculate an upper limit for the space the string may take in the
@ -303,6 +301,8 @@ loop:
ut_ad(++count < 50);
mutex_enter(&(log->mutex));
goto loop;
}
@ -316,6 +316,8 @@ loop:
os_thread_sleep(10000);
mutex_enter(&(log->mutex));
goto loop;
}
@ -336,6 +338,8 @@ loop:
ut_ad(++count < 50);
mutex_enter(&(log->mutex));
goto loop;
}
}
@ -492,9 +496,12 @@ log_close(void)
if (tracked_lsn_age >= log->log_group_capacity) {
fprintf(stderr, " InnoDB: Error: the age of the "
fprintf(stderr, "InnoDB: Error: the age of the "
"oldest untracked record exceeds the log "
"group capacity!\n");
fprintf(stderr, "InnoDB: Error: stopping the log "
"tracking thread at LSN %llu\n", tracked_lsn);
srv_track_changed_pages = FALSE;
}
}

View File

@ -37,6 +37,25 @@ Created 11/26/1995 Heikki Tuuri
#ifndef UNIV_HOTBACKUP
# include "log0recv.h"
/***************************************************//**
Checks if a mini-transaction is dirtying a clean page.
@return TRUE if the mtr is dirtying a clean page. */
UNIV_INTERN
ibool
mtr_block_dirtied(
/*==============*/
const buf_block_t* block) /*!< in: block being x-fixed */
{
ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
ut_ad(block->page.buf_fix_count > 0);
/* It is OK to read oldest_modification because no
other thread can be performing a write of it and it
is only during write that the value is reset to 0. */
return(block->page.oldest_modification == 0);
}
/*****************************************************************//**
Releases the item in the slot given. */
static
@ -125,7 +144,7 @@ mtr_memo_slot_note_modification(
buf_block_t* block = (buf_block_t*) slot->object;
#ifdef UNIV_DEBUG
ut_ad(log_flush_order_mutex_own());
ut_ad(!mtr->made_dirty || log_flush_order_mutex_own());
#endif /* UNIV_DEBUG */
buf_flush_note_modification(block, mtr);
}
@ -201,12 +220,14 @@ mtr_log_reserve_and_write(
Add pages to flush list and exit */
goto func_exit;
}
} else {
mutex_enter(&log_sys->mutex);
}
data_size = dyn_array_get_data_size(mlog);
/* Open the database log for log_write_low */
mtr->start_lsn = log_reserve_and_open(data_size);
mtr->start_lsn = log_open(data_size);
if (mtr->log_mode == MTR_LOG_ALL) {
@ -225,7 +246,15 @@ mtr_log_reserve_and_write(
mtr->end_lsn = log_close();
func_exit:
log_flush_order_mutex_enter();
/* No need to acquire log_flush_order_mutex if this mtr has
not dirtied a clean page. log_flush_order_mutex is used to
ensure ordered insertions in the flush_list. We need to
insert in the flush_list iff the page in question was clean
before modifications. */
if (mtr->made_dirty) {
log_flush_order_mutex_enter();
}
/* It is now safe to release the log mutex because the
flush_order mutex will ensure that we are the first one
@ -236,7 +265,9 @@ func_exit:
mtr_memo_note_modifications(mtr);
}
log_flush_order_mutex_exit();
if (mtr->made_dirty) {
log_flush_order_mutex_exit();
}
}
#endif /* !UNIV_HOTBACKUP */

View File

@ -145,14 +145,27 @@ read_view_t*
read_view_create_low(
/*=================*/
ulint n, /*!< in: number of cells in the trx_ids array */
mem_heap_t* heap) /*!< in: memory heap from which allocated */
read_view_t* view) /*!< in: pre-allocated view array or NULL if a
new one needs to be created */
{
read_view_t* view;
if (view == NULL) {
view = ut_malloc(sizeof(read_view_t));
view->max_descr = 0;
view->descriptors = NULL;
}
view = mem_heap_alloc(heap, sizeof(read_view_t));
if (UNIV_UNLIKELY(view->max_descr < n)) {
view->n_trx_ids = n;
view->trx_ids = mem_heap_alloc(heap, n * sizeof *view->trx_ids);
/* avoid frequent re-allocations by extending the array to the
desired size + 10% */
view->max_descr = n + n / 10;
view->descriptors = ut_realloc(view->descriptors,
view->max_descr *
sizeof(trx_id_t));
}
view->n_descr = n;
return(view);
}
@ -169,8 +182,8 @@ read_view_oldest_copy_or_open_new(
/*==============================*/
trx_id_t cr_trx_id, /*!< in: trx_id of creating
transaction, or 0 used in purge */
mem_heap_t* heap) /*!< in: memory heap from which
allocated */
read_view_t* view) /*!< in: pre-allocated view array or
NULL if a new one needs to be created */
{
read_view_t* old_view;
read_view_t* view_copy;
@ -185,10 +198,10 @@ read_view_oldest_copy_or_open_new(
if (old_view == NULL) {
return(read_view_open_now(cr_trx_id, heap));
return(read_view_open_now(cr_trx_id, view, TRUE));
}
n = old_view->n_trx_ids;
n = old_view->n_descr;
if (old_view->creator_trx_id) {
n++;
@ -196,7 +209,7 @@ read_view_oldest_copy_or_open_new(
needs_insert = FALSE;
}
view_copy = read_view_create_low(n, heap);
view_copy = read_view_create_low(n, view);
/* Insert the id of the creator in the right place of the descending
array of ids, if needs_insert is TRUE: */
@ -204,7 +217,7 @@ read_view_oldest_copy_or_open_new(
i = 0;
while (i < n) {
if (needs_insert
&& (i >= old_view->n_trx_ids
&& (i >= old_view->n_descr
|| old_view->creator_trx_id
> read_view_get_nth_trx_id(old_view, i))) {
@ -251,16 +264,17 @@ read_view_open_now(
/*===============*/
trx_id_t cr_trx_id, /*!< in: trx_id of creating
transaction, or 0 used in purge */
mem_heap_t* heap) /*!< in: memory heap from which
allocated */
read_view_t* view, /*!< in: current read view or NULL if it
doesn't exist yet */
ibool exclude_self) /*!< in: TRUE, if cr_trx_id should be
excluded from the resulting view */
{
read_view_t* view;
trx_t* trx;
ulint n;
trx_id_t* descr;
ulint i;
ut_ad(mutex_own(&kernel_mutex));
view = read_view_create_low(UT_LIST_GET_LEN(trx_sys->trx_list), heap);
view = read_view_create_low(trx_sys->descr_n_used, view);
view->creator_trx_id = cr_trx_id;
view->type = VIEW_NORMAL;
@ -271,40 +285,58 @@ read_view_open_now(
view->low_limit_no = trx_sys->max_trx_id;
view->low_limit_id = view->low_limit_no;
n = 0;
trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
/* No active transaction should be visible */
/* No active transaction should be visible, except cr_trx */
descr = trx_find_descriptor(trx_sys->descriptors,
trx_sys->descr_n_used,
cr_trx_id);
while (trx) {
if (trx->id != cr_trx_id
&& (trx->conc_state == TRX_ACTIVE
|| trx->conc_state == TRX_PREPARED)) {
if (UNIV_LIKELY(exclude_self && descr != NULL)) {
read_view_set_nth_trx_id(view, n, trx->id);
ut_ad(trx_sys->descr_n_used > 0);
ut_ad(view->n_descr > 0);
n++;
view->n_descr--;
/* NOTE that a transaction whose trx number is <
trx_sys->max_trx_id can still be active, if it is
in the middle of its commit! Note that when a
transaction starts, we initialize trx->no to
IB_ULONGLONG_MAX. */
if (view->low_limit_no > trx->no) {
view->low_limit_no = trx->no;
}
}
trx = UT_LIST_GET_NEXT(trx_list, trx);
i = descr - trx_sys->descriptors;
} else {
i = trx_sys->descr_n_used;
}
view->n_trx_ids = n;
if (UNIV_LIKELY(i > 0)) {
if (n > 0) {
/* Copy the [0; i-1] range */
memcpy(view->descriptors, trx_sys->descriptors,
i * sizeof(trx_id_t));
}
if (UNIV_UNLIKELY(i + 1 < trx_sys->descr_n_used)) {
/* Copy the [i+1; descr_n_used-1] range */
memcpy(view->descriptors + i,
trx_sys->descriptors + i + 1,
(trx_sys->descr_n_used - i - 1) *
sizeof(trx_id_t));
}
/* NOTE that a transaction whose trx number is < trx_sys->max_trx_id can
still be active, if it is in the middle of its commit! Note that when a
transaction starts, we initialize trx->no to IB_ULONGLONG_MAX. */
if (UT_LIST_GET_LEN(trx_sys->trx_serial_list) > 0) {
trx_id_t trx_no;
trx_no = UT_LIST_GET_FIRST(trx_sys->trx_serial_list)->no;
if (trx_no < view->low_limit_no) {
view->low_limit_no = trx_no;
}
}
if (UNIV_LIKELY(view->n_descr > 0)) {
/* The last active transaction has the smallest id: */
view->up_limit_id = read_view_get_nth_trx_id(view, n - 1);
view->up_limit_id = view->descriptors[0];
} else {
view->up_limit_id = view->low_limit_id;
}
@ -328,6 +360,23 @@ read_view_close(
UT_LIST_REMOVE(view_list, trx_sys->view_list, view);
}
/*********************************************************************//**
Frees resource allocated by a read view. */
UNIV_INTERN
void
read_view_free(
/*===========*/
read_view_t* view) /*< in: read view */
{
ut_ad(mutex_own(&kernel_mutex));
if (view->descriptors != NULL) {
ut_free(view->descriptors);
}
ut_free(view);
}
/*********************************************************************//**
Closes a consistent read view for MySQL. This function is called at an SQL
statement end if the trx isolation level is <= TRX_ISO_READ_COMMITTED. */
@ -343,8 +392,6 @@ read_view_close_for_mysql(
read_view_close(trx->global_read_view);
mem_heap_empty(trx->global_read_view_heap);
trx->read_view = NULL;
trx->global_read_view = NULL;
@ -382,7 +429,7 @@ read_view_print(
fprintf(file, "Read view individually stored trx ids:\n");
n_ids = view->n_trx_ids;
n_ids = view->n_descr;
for (i = 0; i < n_ids; i++) {
fprintf(file, "Read view trx id " TRX_ID_FMT "\n",
@ -404,8 +451,6 @@ read_cursor_view_create_for_mysql(
cursor_view_t* curview;
read_view_t* view;
mem_heap_t* heap;
trx_t* trx;
ulint n;
ut_a(cr_trx);
@ -424,61 +469,14 @@ read_cursor_view_create_for_mysql(
mutex_enter(&kernel_mutex);
curview->read_view = read_view_create_low(
UT_LIST_GET_LEN(trx_sys->trx_list), curview->heap);
view = curview->read_view;
view->creator_trx_id = cr_trx->id;
view->type = VIEW_HIGH_GRANULARITY;
view->undo_no = cr_trx->undo_no;
/* No future transactions should be visible in the view */
view->low_limit_no = trx_sys->max_trx_id;
view->low_limit_id = view->low_limit_no;
n = 0;
trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
/* No active transaction should be visible */
while (trx) {
if (trx->conc_state == TRX_ACTIVE
|| trx->conc_state == TRX_PREPARED) {
read_view_set_nth_trx_id(view, n, trx->id);
n++;
/* NOTE that a transaction whose trx number is <
trx_sys->max_trx_id can still be active, if it is
in the middle of its commit! Note that when a
transaction starts, we initialize trx->no to
IB_ULONGLONG_MAX. */
if (view->low_limit_no > trx->no) {
view->low_limit_no = trx->no;
}
}
trx = UT_LIST_GET_NEXT(trx_list, trx);
}
view->n_trx_ids = n;
if (n > 0) {
/* The last active transaction has the smallest id: */
view->up_limit_id = read_view_get_nth_trx_id(view, n - 1);
} else {
view->up_limit_id = view->low_limit_id;
}
UT_LIST_ADD_FIRST(view_list, trx_sys->view_list, view);
curview->read_view = read_view_open_now(cr_trx->id, NULL, FALSE);
mutex_exit(&kernel_mutex);
view = curview->read_view;
view->type = VIEW_HIGH_GRANULARITY;
view->undo_no = cr_trx->undo_no;
return(curview);
}
@ -503,6 +501,8 @@ read_cursor_view_close_for_mysql(
mutex_enter(&kernel_mutex);
read_view_close(curview->read_view);
read_view_free(curview->read_view);
trx->read_view = trx->global_read_view;
mutex_exit(&kernel_mutex);

View File

@ -1346,11 +1346,11 @@ run_again:
const rec_t* rec = btr_pcur_get_rec(&pcur);
const buf_block_t* block = btr_pcur_get_block(&pcur);
if (srv_pass_corrupt_table && !block) {
SRV_CORRUPT_TABLE_CHECK(block,
{
err = DB_CORRUPTION;
break;
}
ut_a(block);
goto exit_loop;
});
if (page_rec_is_infimum(rec)) {
@ -1474,6 +1474,7 @@ run_again:
}
} while (btr_pcur_move_to_next(&pcur, &mtr));
exit_loop:
if (check_ref) {
row_ins_foreign_report_add_err(
trx, foreign, btr_pcur_get_rec(&pcur), entry);

View File

@ -1298,11 +1298,11 @@ row_merge_read_clustered_index(
if (UNIV_LIKELY(has_next)) {
rec = btr_pcur_get_rec(&pcur);
if (srv_pass_corrupt_table && !rec) {
SRV_CORRUPT_TABLE_CHECK(rec,
{
err = DB_CORRUPTION;
goto err_exit;
}
ut_a(rec);
});
offsets = rec_get_offsets(rec, clust_index, NULL,
ULINT_UNDEFINED, &row_heap);

View File

@ -3813,9 +3813,9 @@ release_search_latch_if_needed:
trx->has_search_latch = FALSE;
}
ut_ad(prebuilt->sql_stat_start || trx->conc_state == TRX_ACTIVE);
ut_ad(trx->conc_state == TRX_NOT_STARTED
|| trx->conc_state == TRX_ACTIVE);
ut_ad(prebuilt->sql_stat_start || trx->state == TRX_ACTIVE);
ut_ad(trx->state == TRX_NOT_STARTED
|| trx->state == TRX_ACTIVE);
ut_ad(prebuilt->sql_stat_start
|| prebuilt->select_lock_type != LOCK_NONE
|| trx->read_view);
@ -3997,11 +3997,11 @@ rec_loop:
rec = btr_pcur_get_rec(pcur);
if (srv_pass_corrupt_table && !rec) {
SRV_CORRUPT_TABLE_CHECK(rec,
{
err = DB_CORRUPTION;
goto lock_wait_or_error;
}
ut_a(rec);
});
ut_ad(!!page_rec_is_comp(rec) == comp);
#ifdef UNIV_SEARCH_DEBUG
@ -4138,8 +4138,9 @@ wrong_offs:
offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
if (UNIV_UNLIKELY(srv_force_recovery > 0)
|| (srv_pass_corrupt_table == 2 && index->table->is_corrupt)) {
if (UNIV_UNLIKELY(srv_force_recovery > 0
|| (index->table->is_corrupt &&
srv_pass_corrupt_table == 2))) {
if (!rec_validate(rec, offsets)
|| !btr_index_rec_validate(rec, index, FALSE)) {
fprintf(stderr,
@ -4896,8 +4897,10 @@ row_search_check_if_query_cache_permitted(
if (trx->isolation_level >= TRX_ISO_REPEATABLE_READ
&& !trx->read_view) {
trx->read_view = read_view_open_now(
trx->id, trx->global_read_view_heap);
trx->read_view =
read_view_open_now(trx->id,
NULL, TRUE);
trx->global_read_view = trx->read_view;
}
}

View File

@ -667,9 +667,9 @@ row_vers_build_for_semi_consistent_read(
mutex_enter(&kernel_mutex);
version_trx = trx_get_on_id(version_trx_id);
if (version_trx
&& (version_trx->conc_state == TRX_COMMITTED_IN_MEMORY
|| version_trx->conc_state == TRX_NOT_STARTED)) {
if (version_trx &&
(version_trx->state == TRX_COMMITTED_IN_MEMORY
|| version_trx->state == TRX_NOT_STARTED)) {
version_trx = NULL;
}

View File

@ -430,8 +430,6 @@ UNIV_INTERN ulint srv_expand_import = 0; /* 0:disable 1:enable */
UNIV_INTERN ulint srv_pass_corrupt_table = 0; /* 0:disable 1:enable */
UNIV_INTERN ulint srv_dict_size_limit = 0;
UNIV_INTERN ulint srv_lazy_drop_table = 0;
/*-------------------------------------------*/
UNIV_INTERN ulong srv_n_spin_wait_rounds = 30;
UNIV_INTERN ulong srv_n_free_tickets_to_enter = 500;
@ -2925,7 +2923,7 @@ rescan_idle:
mutex_enter(&kernel_mutex);
trx = UT_LIST_GET_FIRST(trx_sys->mysql_trx_list);
while (trx) {
if (trx->conc_state == TRX_ACTIVE
if (trx->state == TRX_ACTIVE
&& trx->mysql_thd
&& innobase_thd_is_idle(trx->mysql_thd)) {
ib_int64_t start_time = innobase_thd_get_start_time(trx->mysql_thd);

View File

@ -263,8 +263,9 @@ trx_purge_sys_create(
purge_sys->query = trx_purge_graph_build();
purge_sys->view = read_view_oldest_copy_or_open_new(0,
purge_sys->heap);
purge_sys->prebuilt_view =
read_view_oldest_copy_or_open_new(0, NULL);
purge_sys->view = purge_sys->prebuilt_view;
}
/************************************************************************
@ -279,7 +280,12 @@ trx_purge_sys_close(void)
que_graph_free(purge_sys->query);
ut_a(purge_sys->sess->trx->is_purge);
purge_sys->sess->trx->conc_state = TRX_NOT_STARTED;
purge_sys->sess->trx->state = TRX_NOT_STARTED;
mutex_enter(&kernel_mutex);
trx_release_descriptor(purge_sys->sess->trx);
mutex_exit(&kernel_mutex);
sess_close(purge_sys->sess);
purge_sys->sess = NULL;
@ -289,6 +295,8 @@ trx_purge_sys_close(void)
mutex_enter(&kernel_mutex);
read_view_close(purge_sys->view);
read_view_free(purge_sys->prebuilt_view);
purge_sys->prebuilt_view = NULL;
purge_sys->view = NULL;
mutex_exit(&kernel_mutex);
@ -1177,7 +1185,7 @@ trx_purge(
}
purge_sys->view = read_view_oldest_copy_or_open_new(
0, purge_sys->heap);
0, purge_sys->prebuilt_view);
mutex_exit(&kernel_mutex);

View File

@ -132,7 +132,7 @@ trx_rollback_for_mysql(
{
int err;
if (trx->conc_state == TRX_NOT_STARTED) {
if (trx->state == TRX_NOT_STARTED) {
return(DB_SUCCESS);
}
@ -161,7 +161,7 @@ trx_rollback_last_sql_stat_for_mysql(
{
int err;
if (trx->conc_state == TRX_NOT_STARTED) {
if (trx->state == TRX_NOT_STARTED) {
return(DB_SUCCESS);
}
@ -263,7 +263,7 @@ trx_rollback_to_savepoint_for_mysql(
return(DB_NO_SAVEPOINT);
}
if (trx->conc_state == TRX_NOT_STARTED) {
if (trx->state == TRX_NOT_STARTED) {
ut_print_timestamp(stderr);
fputs(" InnoDB: Error: transaction has a savepoint ", stderr);
ut_print_name(stderr, trx, FALSE, savep->name);
@ -560,7 +560,7 @@ loop:
continue;
}
switch (trx->conc_state) {
switch (trx->state) {
case TRX_NOT_STARTED:
case TRX_PREPARED:
continue;

View File

@ -1319,6 +1319,12 @@ trx_sys_init_at_db_start(void)
trx_sys = mem_zalloc(sizeof(*trx_sys));
/* Allocate the trx descriptors array */
trx_sys->descriptors = ut_malloc(sizeof(trx_id_t) *
TRX_DESCR_ARRAY_INITIAL_SIZE);
trx_sys->descr_n_max = TRX_DESCR_ARRAY_INITIAL_SIZE;
trx_sys->descr_n_used = 0;
sys_header = trx_sysf_get(&mtr);
trx_rseg_list_and_array_init(sys_header, ib_bh, &mtr);
@ -1346,7 +1352,7 @@ trx_sys_init_at_db_start(void)
for (;;) {
if (trx->conc_state != TRX_PREPARED) {
if (trx->state != TRX_PREPARED) {
rows_to_undo += trx->undo_no;
}
@ -2028,6 +2034,9 @@ trx_sys_close(void)
ut_a(UT_LIST_GET_LEN(trx_sys->view_list) == 0);
ut_a(UT_LIST_GET_LEN(trx_sys->mysql_trx_list) == 0);
ut_ad(trx_sys->descr_n_used == 0);
ut_free(trx_sys->descriptors);
mem_free(trx_sys);
trx_sys = NULL;

View File

@ -85,6 +85,126 @@ trx_set_detailed_error_from_file(
sizeof(trx->detailed_error));
}
/*************************************************************//**
Callback function for trx_find_descriptor() to compare trx IDs. */
UNIV_INTERN
int
trx_descr_cmp(
/*==========*/
const void *a, /*!< in: pointer to first comparison argument */
const void *b) /*!< in: pointer to second comparison argument */
{
const trx_id_t* da = (const trx_id_t*) a;
const trx_id_t* db = (const trx_id_t*) b;
if (*da < *db) {
return -1;
} else if (*da > *db) {
return 1;
}
return 0;
}
/*************************************************************//**
Reserve a slot for a given trx in the global descriptors array. */
UNIV_INLINE
void
trx_reserve_descriptor(
/*===================*/
const trx_t* trx) /*!< in: trx pointer */
{
ulint n_used;
ulint n_max;
trx_id_t* descr;
ut_ad(mutex_own(&kernel_mutex));
ut_ad(!trx_find_descriptor(trx_sys->descriptors,
trx_sys->descr_n_used,
trx->id));
n_used = trx_sys->descr_n_used + 1;
n_max = trx_sys->descr_n_max;
if (UNIV_UNLIKELY(n_used > n_max)) {
n_max = n_max * 2;
trx_sys->descriptors =
ut_realloc(trx_sys->descriptors,
n_max * sizeof(trx_id_t));
trx_sys->descr_n_max = n_max;
}
descr = trx_sys->descriptors + n_used - 1;
if (UNIV_UNLIKELY(n_used > 1 && trx->id < descr[-1])) {
/* Find the slot where it should be inserted. We could use a
binary search, but in reality linear search should be faster,
because the slot we are looking for is near the array end. */
trx_id_t* tdescr;
for (tdescr = descr - 1;
tdescr >= trx_sys->descriptors && *tdescr > trx->id;
tdescr--) {
}
tdescr++;
ut_memmove(tdescr + 1, tdescr, (descr - tdescr) *
sizeof(trx_id_t));
descr = tdescr;
}
*descr = trx->id;
trx_sys->descr_n_used = n_used;
}
/*************************************************************//**
Release a slot for a given trx in the global descriptors array. */
UNIV_INTERN
void
trx_release_descriptor(
/*===================*/
trx_t* trx) /*!< in: trx pointer */
{
ulint size;
trx_id_t* descr;
ut_ad(mutex_own(&kernel_mutex));
if (UNIV_LIKELY(trx->is_in_trx_serial_list)) {
UT_LIST_REMOVE(trx_serial_list, trx_sys->trx_serial_list,
trx);
trx->is_in_trx_serial_list = 0;
}
descr = trx_find_descriptor(trx_sys->descriptors,
trx_sys->descr_n_used,
trx->id);
if (UNIV_UNLIKELY(descr == NULL)) {
return;
}
size = (trx_sys->descriptors + trx_sys->descr_n_used - 1 - descr) *
sizeof(trx_id_t);
if (UNIV_LIKELY(size > 0)) {
ut_memmove(descr, descr + 1, size);
}
trx_sys->descr_n_used--;
}
/****************************************************************//**
Creates and initializes a transaction object.
@return own: the transaction */
@ -107,7 +227,7 @@ trx_create(
trx->is_purge = 0;
trx->is_recovered = 0;
trx->conc_state = TRX_NOT_STARTED;
trx->state = TRX_NOT_STARTED;
trx->is_registered = 0;
trx->owns_prepare_mutex = 0;
@ -119,6 +239,7 @@ trx_create(
trx->id = 0;
trx->no = IB_ULONGLONG_MAX;
trx->is_in_trx_serial_list = 0;
trx->support_xa = TRUE;
@ -190,9 +311,9 @@ trx_create(
trx->declared_to_be_inside_innodb = FALSE;
trx->n_tickets_to_enter_innodb = 0;
trx->global_read_view_heap = mem_heap_create(256);
trx->global_read_view = NULL;
trx->read_view = NULL;
trx->prebuilt_view = NULL;
trx->io_reads = 0;
trx->io_read = 0;
@ -328,7 +449,7 @@ trx_free(
trx->magic_n = 11112222;
ut_a(trx->conc_state == TRX_NOT_STARTED);
ut_a(trx->state == TRX_NOT_STARTED);
mutex_free(&(trx->undo_mutex));
@ -355,18 +476,18 @@ trx_free(
ut_a(UT_LIST_GET_LEN(trx->trx_locks) == 0);
if (trx->global_read_view_heap) {
mem_heap_free(trx->global_read_view_heap);
if (trx->prebuilt_view != NULL) {
read_view_free(trx->prebuilt_view);
}
trx->global_read_view = NULL;
ut_a(trx->read_view == NULL);
ut_a(ib_vector_is_empty(trx->autoinc_locks));
/* We allocated a dedicated heap for the vector. */
ib_vector_free(trx->autoinc_locks);
trx_release_descriptor(trx);
mem_free(trx);
}
@ -379,7 +500,7 @@ trx_free_prepared(
trx_t* trx) /*!< in, own: trx object */
{
ut_ad(mutex_own(&kernel_mutex));
ut_a(trx->conc_state == TRX_PREPARED);
ut_a(trx->state == TRX_PREPARED);
ut_a(trx->magic_n == TRX_MAGIC_N);
/* Prepared transactions are sort of active; they allow
@ -412,15 +533,19 @@ trx_free_prepared(
mem_heap_free(trx->lock_heap);
}
if (trx->global_read_view_heap) {
mem_heap_free(trx->global_read_view_heap);
}
ut_a(ib_vector_is_empty(trx->autoinc_locks));
ib_vector_free(trx->autoinc_locks);
trx_release_descriptor(trx);
if (trx->prebuilt_view != NULL) {
read_view_free(trx->prebuilt_view);
}
UT_LIST_REMOVE(trx_list, trx_sys->trx_list, trx);
ut_ad(trx_sys->descr_n_used <= UT_LIST_GET_LEN(trx_sys->trx_list));
mem_free(trx);
}
@ -529,6 +654,7 @@ trx_lists_init_at_db_start(void)
ut_ad(mutex_own(&kernel_mutex));
UT_LIST_INIT(trx_sys->trx_list);
UT_LIST_INIT(trx_sys->trx_serial_list);
/* Look from the rollback segments if there exist undo logs for
transactions */
@ -565,7 +691,7 @@ trx_lists_init_at_db_start(void)
if (srv_force_recovery == 0) {
trx->conc_state = TRX_PREPARED;
trx->state = TRX_PREPARED;
trx_n_prepared++;
} else {
fprintf(stderr,
@ -575,11 +701,12 @@ trx_lists_init_at_db_start(void)
" rollback it"
" anyway.\n");
trx->conc_state = TRX_ACTIVE;
trx->state = TRX_ACTIVE;
}
trx_reserve_descriptor(trx);
} else {
trx->conc_state
= TRX_COMMITTED_IN_MEMORY;
trx->state = TRX_COMMITTED_IN_MEMORY;
}
/* We give a dummy value for the trx no;
@ -591,12 +718,15 @@ trx_lists_init_at_db_start(void)
trx->no = trx->id;
} else {
trx->conc_state = TRX_ACTIVE;
trx->state = TRX_ACTIVE;
/* A running transaction always has the number
field inited to IB_ULONGLONG_MAX */
trx->no = IB_ULONGLONG_MAX;
trx_reserve_descriptor(trx);
}
if (undo->dict_operation) {
@ -641,7 +771,7 @@ trx_lists_init_at_db_start(void)
if (srv_force_recovery == 0) {
trx->conc_state
trx->state
= TRX_PREPARED;
trx_n_prepared++;
} else {
@ -652,11 +782,12 @@ trx_lists_init_at_db_start(void)
" rollback it"
" anyway.\n");
trx->conc_state
= TRX_ACTIVE;
trx->state = TRX_ACTIVE;
trx_reserve_descriptor(
trx);
}
} else {
trx->conc_state
trx->state
= TRX_COMMITTED_IN_MEMORY;
}
@ -665,13 +796,14 @@ trx_lists_init_at_db_start(void)
trx->no = trx->id;
} else {
trx->conc_state = TRX_ACTIVE;
trx->state = TRX_ACTIVE;
/* A running transaction always has
the number field inited to
IB_ULONGLONG_MAX */
trx->no = IB_ULONGLONG_MAX;
trx_reserve_descriptor(trx);
}
trx->rseg = rseg;
@ -742,13 +874,15 @@ trx_start_low(
if (trx->is_purge) {
trx->id = 0;
trx->conc_state = TRX_ACTIVE;
/* Don't reserve a descriptor, since this trx is not added to
trx_list. */
trx->state = TRX_ACTIVE;
trx->start_time = time(NULL);
return(TRUE);
}
ut_ad(trx->conc_state != TRX_ACTIVE);
ut_ad(trx->state != TRX_ACTIVE);
ut_a(rseg_id == ULINT_UNDEFINED);
@ -763,7 +897,10 @@ trx_start_low(
trx->rseg = rseg;
trx->conc_state = TRX_ACTIVE;
trx->state = TRX_ACTIVE;
trx_reserve_descriptor(trx);
trx->start_time = time(NULL);
UT_LIST_ADD_FIRST(trx_list, trx_sys->trx_list, trx);
@ -820,6 +957,14 @@ trx_serialisation_number_get(
trx->no = trx_sys_get_new_trx_id();
if (UNIV_LIKELY(trx->is_in_trx_serial_list == 0)) {
UT_LIST_ADD_LAST(trx_serial_list, trx_sys->trx_serial_list,
trx);
trx->is_in_trx_serial_list = 1;
}
/* If the rollack segment is not empty then the
new trx_t::no can't be less than any trx_t::no
already in the rollback segment. User threads only
@ -1001,10 +1146,10 @@ trx_commit_off_kernel(
lsn = 0;
}
ut_ad(trx->conc_state == TRX_ACTIVE || trx->conc_state == TRX_PREPARED);
ut_ad(trx->state == TRX_ACTIVE || trx->state == TRX_PREPARED);
ut_ad(mutex_own(&kernel_mutex));
if (UNIV_UNLIKELY(trx->conc_state == TRX_PREPARED)) {
if (UNIV_UNLIKELY(trx->state == TRX_PREPARED)) {
ut_a(trx_n_prepared > 0);
trx_n_prepared--;
}
@ -1024,7 +1169,9 @@ trx_commit_off_kernel(
committed. */
/*--------------------------------------*/
trx->conc_state = TRX_COMMITTED_IN_MEMORY;
trx->state = TRX_COMMITTED_IN_MEMORY;
/* The following also removes trx from trx_serial_list */
trx_release_descriptor(trx);
/*--------------------------------------*/
/* If we release kernel_mutex below and we are still doing
@ -1045,7 +1192,6 @@ trx_commit_off_kernel(
if (trx->global_read_view) {
read_view_close(trx->global_read_view);
mem_heap_empty(trx->global_read_view_heap);
trx->global_read_view = NULL;
}
@ -1131,7 +1277,7 @@ trx_commit_off_kernel(
/* Free all savepoints */
trx_roll_free_all_savepoints(trx);
trx->conc_state = TRX_NOT_STARTED;
trx->state = TRX_NOT_STARTED;
trx->rseg = NULL;
trx->undo_no = 0;
trx->last_sql_stat_start.least_undo_no = 0;
@ -1141,6 +1287,8 @@ trx_commit_off_kernel(
UT_LIST_REMOVE(trx_list, trx_sys->trx_list, trx);
ut_ad(trx_sys->descr_n_used <= UT_LIST_GET_LEN(trx_sys->trx_list));
trx->error_state = DB_SUCCESS;
}
@ -1159,12 +1307,15 @@ trx_cleanup_at_db_startup(
trx_undo_insert_cleanup(trx);
}
trx->conc_state = TRX_NOT_STARTED;
trx->state = TRX_NOT_STARTED;
trx_release_descriptor(trx);
trx->rseg = NULL;
trx->undo_no = 0;
trx->last_sql_stat_start.least_undo_no = 0;
UT_LIST_REMOVE(trx_list, trx_sys->trx_list, trx);
ut_ad(trx_sys->descr_n_used <= UT_LIST_GET_LEN(trx_sys->trx_list));
}
/********************************************************************//**
@ -1178,7 +1329,7 @@ trx_assign_read_view(
/*=================*/
trx_t* trx) /*!< in: active transaction */
{
ut_ad(trx->conc_state == TRX_ACTIVE);
ut_ad(trx->state == TRX_ACTIVE);
if (trx->read_view) {
return(trx->read_view);
@ -1186,11 +1337,9 @@ trx_assign_read_view(
mutex_enter(&kernel_mutex);
if (!trx->read_view) {
trx->read_view = read_view_open_now(
trx->id, trx->global_read_view_heap);
trx->global_read_view = trx->read_view;
}
trx->read_view = read_view_open_now(trx->id, trx->prebuilt_view, TRUE);
trx->prebuilt_view = trx->read_view;
trx->global_read_view = trx->read_view;
mutex_exit(&kernel_mutex);
@ -1555,7 +1704,7 @@ loop:
return;
}
if (trx->conc_state == TRX_NOT_STARTED) {
if (trx->state == TRX_NOT_STARTED) {
trx_start_low(trx, ULINT_UNDEFINED);
}
@ -1847,7 +1996,7 @@ trx_mark_sql_stat_end(
{
ut_a(trx);
if (trx->conc_state == TRX_NOT_STARTED) {
if (trx->state == TRX_NOT_STARTED) {
trx->undo_no = 0;
}
@ -1870,7 +2019,7 @@ trx_print(
fprintf(f, "TRANSACTION " TRX_ID_FMT, (ullint) trx->id);
switch (trx->conc_state) {
switch (trx->state) {
case TRX_NOT_STARTED:
fputs(", not started", f);
break;
@ -1886,7 +2035,7 @@ trx_print(
fputs(", COMMITTED IN MEMORY", f);
break;
default:
fprintf(f, " state %lu", (ulong) trx->conc_state);
fprintf(f, " state %lu", (ulong) trx->state);
}
if (*trx->op_info) {
@ -2081,7 +2230,11 @@ trx_prepare_off_kernel(
ut_ad(mutex_own(&kernel_mutex));
/*--------------------------------------*/
trx->conc_state = TRX_PREPARED;
if (UNIV_UNLIKELY(trx->state != TRX_ACTIVE)) {
trx_reserve_descriptor(trx);
}
trx->state = TRX_PREPARED;
trx_n_prepared++;
/*--------------------------------------*/
@ -2195,7 +2348,7 @@ trx_recover_for_mysql(
trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
while (trx) {
if (trx->conc_state == TRX_PREPARED) {
if (trx->state == TRX_PREPARED) {
xid_list[count] = trx->xid;
if (count == 0) {
@ -2268,7 +2421,7 @@ trx_get_trx_by_xid(
the same */
if (trx->is_recovered
&& trx->conc_state == TRX_PREPARED
&& trx->state == TRX_PREPARED
&& xid->gtrid_length == trx->xid.gtrid_length
&& xid->bqual_length == trx->xid.bqual_length
&& memcmp(xid->data, trx->xid.data,