diff options
author | Sergei Golubchik <sergii@pisem.net> | 2013-05-08 09:52:54 +0200 |
---|---|---|
committer | Sergei Golubchik <sergii@pisem.net> | 2013-05-08 09:52:54 +0200 |
commit | bcfa90b471b4a04ba9eb9dccd88a41c8f72cd38a (patch) | |
tree | 936f2f6cb3a07a867bd8e7f51fdc4609abff1f82 | |
parent | 086b54c281eaf5470b0424d926492d7ee25e4916 (diff) | |
download | mariadb-git-bcfa90b471b4a04ba9eb9dccd88a41c8f72cd38a.tar.gz |
Percona-Server-5.5.30-rel30.2.tar.gz
43 files changed, 800 insertions, 648 deletions
diff --git a/btr/btr0btr.c b/btr/btr0btr.c index b0ae888e676..3efd9bc76e0 100644 --- a/btr/btr0btr.c +++ b/btr/btr0btr.c @@ -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); diff --git a/btr/btr0cur.c b/btr/btr0cur.c index d089fb5ad22..488212f087c 100644 --- a/btr/btr0cur.c +++ b/btr/btr0cur.c @@ -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 */ diff --git a/btr/btr0pcur.c b/btr/btr0pcur.c index a1b7affdeb7..7c4ec2dd1ac 100644 --- a/btr/btr0pcur.c +++ b/btr/btr0pcur.c @@ -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) diff --git a/btr/btr0sea.c b/btr/btr0sea.c index 7e9449a6474..d53452bb959 100644 --- a/btr/btr0sea.c +++ b/btr/btr0sea.c @@ -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! diff --git a/buf/buf0buf.c b/buf/buf0buf.c index 5bcfb0f51b9..ae4b2fba98d 100644 --- a/buf/buf0buf.c +++ b/buf/buf0buf.c @@ -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); } } diff --git a/buf/buf0flu.c b/buf/buf0flu.c index 663e2d8f537..9452b53df38 100644 --- a/buf/buf0flu.c +++ b/buf/buf0flu.c @@ -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); diff --git a/buf/buf0lru.c b/buf/buf0lru.c index bbf483c708a..ef747ce470d 100644 --- a/buf/buf0lru.c +++ b/buf/buf0lru.c @@ -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 */ diff --git a/buf/buf0rea.c b/buf/buf0rea.c index cf0a029df92..5edbeadb64e 100644 --- a/buf/buf0rea.c +++ b/buf/buf0rea.c @@ -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 diff --git a/dict/dict0dict.c b/dict/dict0dict.c index 461bdd55ad3..6e883e5048b 100644 --- a/dict/dict0dict.c +++ b/dict/dict0dict.c @@ -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; diff --git a/fil/fil0fil.c b/fil/fil0fil.c index a90f47bda91..1c53c02efb4 100644 --- a/fil/fil0fil.c +++ b/fil/fil0fil.c @@ -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 (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); + } } - if (type == OS_FILE_READ) { + + if (srv_pass_corrupt_table == 1 && type == OS_FILE_READ) { + return(DB_TABLESPACE_DELETED); - } else { + + } else if (type == OS_FILE_WRITE) { + 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); - } - } -#ifdef UNIV_HOTBACKUP + } /**/ + + /* 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); diff --git a/fsp/fsp0fsp.c b/fsp/fsp0fsp.c index cf066404555..24d5183f880 100644 --- a/fsp/fsp0fsp.c +++ b/fsp/fsp0fsp.c @@ -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); diff --git a/handler/ha_innodb.cc b/handler/ha_innodb.cc index ff18ffbecdf..569770602d0 100644 --- a/handler/ha_innodb.cc +++ b/handler/ha_innodb.cc @@ -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, diff --git a/include/btr0btr.ic b/include/btr0btr.ic index 53c8159c448..798107628d7 100644 --- a/include/btr0btr.ic +++ b/include/btr0btr.ic @@ -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) { diff --git a/include/buf0buf.h b/include/buf0buf.h index f4f9cc47ff4..991fdb7ca88 100644 --- a/include/buf0buf.h +++ b/include/buf0buf.h @@ -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; diff --git a/include/buf0buf.ic b/include/buf0buf.ic index 8d5c3edeef8..18c46b6412e 100644 --- a/include/buf0buf.ic +++ b/include/buf0buf.ic @@ -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: diff --git a/include/buf0flu.ic b/include/buf0flu.ic index 30e2cc8efe8..8228c025d23 100644 --- a/include/buf0flu.ic +++ b/include/buf0flu.ic @@ -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); diff --git a/include/buf0lru.h b/include/buf0lru.h index 2ea4f9b1ecf..8bb3aed4059 100644 --- a/include/buf0lru.h +++ b/include/buf0lru.h @@ -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. */ diff --git a/include/fut0fut.ic b/include/fut0fut.ic index 529f2a516d3..63e5736d99e 100644 --- a/include/fut0fut.ic +++ b/include/fut0fut.ic @@ -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; diff --git a/include/log0log.h b/include/log0log.h index ee20f429a2b..e4c19c41137 100644 --- a/include/log0log.h +++ b/include/log0log.h @@ -122,14 +122,22 @@ UNIV_INLINE void log_free_check(void); /*================*/ +/**************************************************************************//** +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 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 */ /************************************************************//** Writes to the log the string given. It is assumed that the caller holds the diff --git a/include/log0log.ic b/include/log0log.ic index 67db6695cab..c39586dbcf9 100644 --- a/include/log0log.ic +++ b/include/log0log.ic @@ -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 diff --git a/include/mtr0mtr.h b/include/mtr0mtr.h index 46f1ff9310c..c51632e0ed5 100644 --- a/include/mtr0mtr.h +++ b/include/mtr0mtr.h @@ -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 */ diff --git a/include/mtr0mtr.ic b/include/mtr0mtr.ic index a03a0271535..7b5d268b70f 100644 --- a/include/mtr0mtr.ic +++ b/include/mtr0mtr.ic @@ -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); diff --git a/include/read0read.h b/include/read0read.h index 0c9468d985e..dd378ecc997 100644 --- a/include/read0read.h +++ b/include/read0read.h @@ -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 */ diff --git a/include/read0read.ic b/include/read0read.ic index 5bb5249b591..ebcdb767406 100644 --- a/include/read0read.ic +++ b/include/read0read.ic @@ -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. */ - - 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); - } - } + /* Do a binary search over this view's descriptors array */ - return(TRUE); + return(trx_find_descriptor(view->descriptors, view->n_descr, + trx_id) == NULL); } diff --git a/include/srv0srv.h b/include/srv0srv.h index 53dbdf8bd8f..c4fb9712b51 100644 --- a/include/srv0srv.h +++ b/include/srv0srv.h @@ -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. */ + +#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_lazy_drop_table; +extern ulint srv_dict_size_limit; /*-------------------------------------------*/ extern ulint srv_n_rows_inserted; diff --git a/include/trx0purge.h b/include/trx0purge.h index 1e8acd65e01..1ddc9068b8e 100644 --- a/include/trx0purge.h +++ b/include/trx0purge.h @@ -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 diff --git a/include/trx0sys.h b/include/trx0sys.h index cba21ae97a9..75a3b0fb4fd 100644 --- a/include/trx0sys.h +++ b/include/trx0sys.h @@ -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 */ diff --git a/include/trx0sys.ic b/include/trx0sys.ic index af05ab2f5ed..3af98cdf98b 100644 --- a/include/trx0sys.ic +++ b/include/trx0sys.ic @@ -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 */ diff --git a/include/trx0trx.h b/include/trx0trx.h index 39b8ccf26ec..fec1d746297 100644 --- a/include/trx0trx.h +++ b/include/trx0trx.h @@ -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 ..., diff --git a/include/trx0trx.ic b/include/trx0trx.ic index 4a1d3bcde0b..1a1fc91eac5 100644 --- a/include/trx0trx.ic +++ b/include/trx0trx.ic @@ -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); } diff --git a/lock/lock0lock.c b/lock/lock0lock.c index 47d082ed49f..f4c991d4fe9 100644 --- a/lock/lock0lock.c +++ b/lock/lock0lock.c @@ -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 diff --git a/log/log0log.c b/log/log0log.c index 8fbf4b80df4..298234050e8 100644 --- a/log/log0log.c +++ b/log/log0log.c @@ -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; } } diff --git a/mtr/mtr0mtr.c b/mtr/mtr0mtr.c index d852ed6f496..f0cd3fb77de 100644 --- a/mtr/mtr0mtr.c +++ b/mtr/mtr0mtr.c @@ -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 */ diff --git a/read/read0read.c b/read/read0read.c index f049dd21e8d..c04dae51ff5 100644 --- a/read/read0read.c +++ b/read/read0read.c @@ -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; + } + + if (UNIV_UNLIKELY(view->max_descr < n)) { - view = mem_heap_alloc(heap, sizeof(read_view_t)); + /* 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_trx_ids = n; - view->trx_ids = mem_heap_alloc(heap, n * sizeof *view->trx_ids); + 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. */ + i = descr - trx_sys->descriptors; + } else { + i = trx_sys->descr_n_used; + } - if (view->low_limit_no > trx->no) { + if (UNIV_LIKELY(i > 0)) { - view->low_limit_no = trx->no; - } - } + /* Copy the [0; i-1] range */ + memcpy(view->descriptors, trx_sys->descriptors, + i * sizeof(trx_id_t)); + } - trx = UT_LIST_GET_NEXT(trx_list, trx); + 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)); } - view->n_trx_ids = 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 (n > 0) { + 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; } @@ -329,6 +361,23 @@ read_view_close( } /*********************************************************************//** +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. */ UNIV_INTERN @@ -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); + curview->read_view = read_view_open_now(cr_trx->id, NULL, FALSE); + + mutex_exit(&kernel_mutex); 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); - - mutex_exit(&kernel_mutex); - 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); diff --git a/row/row0ins.c b/row/row0ins.c index fda0c55b5c7..0002f4410d6 100644 --- a/row/row0ins.c +++ b/row/row0ins.c @@ -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); diff --git a/row/row0merge.c b/row/row0merge.c index 460a44e34b2..ade708f93e7 100644 --- a/row/row0merge.c +++ b/row/row0merge.c @@ -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); diff --git a/row/row0sel.c b/row/row0sel.c index eb60aaa2314..f5b2c0fd014 100644 --- a/row/row0sel.c +++ b/row/row0sel.c @@ -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; } } diff --git a/row/row0vers.c b/row/row0vers.c index 6d83dbaf8ee..3fd13b829a2 100644 --- a/row/row0vers.c +++ b/row/row0vers.c @@ -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; } diff --git a/srv/srv0srv.c b/srv/srv0srv.c index adcc0aa1cc2..9c8abc5dac1 100644 --- a/srv/srv0srv.c +++ b/srv/srv0srv.c @@ -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); diff --git a/trx/trx0purge.c b/trx/trx0purge.c index b048dc66efe..1e119c6828b 100644 --- a/trx/trx0purge.c +++ b/trx/trx0purge.c @@ -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); diff --git a/trx/trx0roll.c b/trx/trx0roll.c index b55471959ce..ae42623a1d9 100644 --- a/trx/trx0roll.c +++ b/trx/trx0roll.c @@ -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; diff --git a/trx/trx0sys.c b/trx/trx0sys.c index 978748642bf..5f589b70343 100644 --- a/trx/trx0sys.c +++ b/trx/trx0sys.c @@ -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; diff --git a/trx/trx0trx.c b/trx/trx0trx.c index c5e26f8d7d1..f061bb4c0b6 100644 --- a/trx/trx0trx.c +++ b/trx/trx0trx.c @@ -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, |