summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2013-05-08 09:52:54 +0200
committerSergei Golubchik <sergii@pisem.net>2013-05-08 09:52:54 +0200
commitbcfa90b471b4a04ba9eb9dccd88a41c8f72cd38a (patch)
tree936f2f6cb3a07a867bd8e7f51fdc4609abff1f82
parent086b54c281eaf5470b0424d926492d7ee25e4916 (diff)
downloadmariadb-git-bcfa90b471b4a04ba9eb9dccd88a41c8f72cd38a.tar.gz
Percona-Server-5.5.30-rel30.2.tar.gz
-rw-r--r--btr/btr0btr.c38
-rw-r--r--btr/btr0cur.c111
-rw-r--r--btr/btr0pcur.c13
-rw-r--r--btr/btr0sea.c5
-rw-r--r--buf/buf0buf.c121
-rw-r--r--buf/buf0flu.c9
-rw-r--r--buf/buf0lru.c40
-rw-r--r--buf/buf0rea.c8
-rw-r--r--dict/dict0dict.c6
-rw-r--r--fil/fil0fil.c105
-rw-r--r--fsp/fsp0fsp.c45
-rw-r--r--handler/ha_innodb.cc38
-rw-r--r--include/btr0btr.ic2
-rw-r--r--include/buf0buf.h1
-rw-r--r--include/buf0buf.ic9
-rw-r--r--include/buf0flu.ic2
-rw-r--r--include/buf0lru.h7
-rw-r--r--include/fut0fut.ic5
-rw-r--r--include/log0log.h16
-rw-r--r--include/log0log.ic23
-rw-r--r--include/mtr0mtr.h2
-rw-r--r--include/mtr0mtr.ic21
-rw-r--r--include/read0read.h33
-rw-r--r--include/read0read.ic41
-rw-r--r--include/srv0srv.h17
-rw-r--r--include/trx0purge.h1
-rw-r--r--include/trx0sys.h38
-rw-r--r--include/trx0sys.ic46
-rw-r--r--include/trx0trx.h43
-rw-r--r--include/trx0trx.ic8
-rw-r--r--lock/lock0lock.c22
-rw-r--r--log/log0log.c19
-rw-r--r--mtr/mtr0mtr.c39
-rw-r--r--read/read0read.c188
-rw-r--r--row/row0ins.c9
-rw-r--r--row/row0merge.c6
-rw-r--r--row/row0sel.c23
-rw-r--r--row/row0vers.c6
-rw-r--r--srv/srv0srv.c4
-rw-r--r--trx/trx0purge.c16
-rw-r--r--trx/trx0roll.c8
-rw-r--r--trx/trx0sys.c11
-rw-r--r--trx/trx0trx.c243
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,