summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--storage/xtradb/btr/btr0cur.c51
-rw-r--r--storage/xtradb/btr/btr0sea.c252
-rw-r--r--storage/xtradb/buf/buf0buf.c56
-rw-r--r--storage/xtradb/dict/dict0boot.c8
-rw-r--r--storage/xtradb/dict/dict0dict.c4
-rw-r--r--storage/xtradb/dict/dict0load.c2
-rw-r--r--storage/xtradb/fil/fil0fil.c5
-rw-r--r--storage/xtradb/handler/ha_innodb.cc154
-rw-r--r--storage/xtradb/handler/handler0alter.cc8
-rw-r--r--storage/xtradb/handler/i_s.cc2
-rw-r--r--storage/xtradb/ibuf/ibuf0ibuf.c5
-rw-r--r--storage/xtradb/include/btr0sea.h49
-rw-r--r--storage/xtradb/include/btr0sea.ic76
-rw-r--r--storage/xtradb/include/btr0types.h13
-rw-r--r--storage/xtradb/include/buf0buf.h1
-rw-r--r--storage/xtradb/include/dict0mem.h4
-rw-r--r--storage/xtradb/include/trx0trx.h12
-rw-r--r--storage/xtradb/include/trx0trx.ic13
-rw-r--r--storage/xtradb/lock/lock0lock.c12
-rw-r--r--storage/xtradb/log/log0online.c41
-rw-r--r--storage/xtradb/log/log0recv.c3
-rw-r--r--storage/xtradb/que/que0que.c2
-rw-r--r--storage/xtradb/row/row0ins.c19
-rw-r--r--storage/xtradb/row/row0merge.c19
-rw-r--r--storage/xtradb/row/row0mysql.c28
-rw-r--r--storage/xtradb/row/row0sel.c133
-rw-r--r--storage/xtradb/row/row0uins.c15
-rw-r--r--storage/xtradb/row/row0umod.c46
-rw-r--r--storage/xtradb/row/row0upd.c24
-rw-r--r--storage/xtradb/srv/srv0srv.c106
-rw-r--r--storage/xtradb/trx/trx0trx.c27
31 files changed, 713 insertions, 477 deletions
diff --git a/storage/xtradb/btr/btr0cur.c b/storage/xtradb/btr/btr0cur.c
index a2bbe145355..8904270197a 100644
--- a/storage/xtradb/btr/btr0cur.c
+++ b/storage/xtradb/btr/btr0cur.c
@@ -520,7 +520,8 @@ btr_cur_search_to_nth_level(
#ifdef UNIV_SEARCH_PERF_STAT
info->n_searches++;
#endif
- if (rw_lock_get_writer(btr_search_get_latch(cursor->index->id)) == RW_LOCK_NOT_LOCKED
+ if (rw_lock_get_writer(btr_search_get_latch(cursor->index)) ==
+ RW_LOCK_NOT_LOCKED
&& latch_mode <= BTR_MODIFY_LEAF
&& info->last_hash_succ
&& !estimate
@@ -556,7 +557,7 @@ btr_cur_search_to_nth_level(
if (has_search_latch) {
/* Release possible search latch to obey latching order */
- rw_lock_s_unlock(btr_search_get_latch(cursor->index->id));
+ rw_lock_s_unlock(btr_search_get_latch(cursor->index));
}
/* Store the position of the tree latch we push to mtr so that we
@@ -871,7 +872,7 @@ func_exit:
if (has_search_latch) {
- rw_lock_s_lock(btr_search_get_latch(cursor->index->id));
+ rw_lock_s_lock(btr_search_get_latch(cursor->index));
}
}
@@ -1189,7 +1190,7 @@ btr_cur_ins_lock_and_undo(
rec_t* rec;
roll_ptr_t roll_ptr;
- if (thr && thr_get_trx(thr)->fake_changes) {
+ if (UNIV_UNLIKELY(thr && thr_get_trx(thr)->fake_changes)) {
/* skip LOCK, UNDO */
return(DB_SUCCESS);
}
@@ -1427,7 +1428,7 @@ fail_err:
goto fail_err;
}
- if (thr && thr_get_trx(thr)->fake_changes) {
+ if (UNIV_UNLIKELY(thr && thr_get_trx(thr)->fake_changes)) {
/* skip CHANGE, LOG */
*big_rec = big_rec_vec;
return(err); /* == DB_SUCCESS */
@@ -1641,7 +1642,7 @@ btr_cur_pessimistic_insert(
}
}
- if (thr && thr_get_trx(thr)->fake_changes) {
+ if (UNIV_UNLIKELY(thr && thr_get_trx(thr)->fake_changes)) {
/* skip CHANGE, LOG */
if (n_extents > 0) {
fil_space_release_free_extents(index->space,
@@ -1707,7 +1708,7 @@ btr_cur_upd_lock_and_undo(
ut_ad(cursor && update && thr && roll_ptr);
- if (thr && thr_get_trx(thr)->fake_changes) {
+ if (UNIV_UNLIKELY(thr_get_trx(thr)->fake_changes)) {
/* skip LOCK, UNDO */
return(DB_SUCCESS);
}
@@ -1914,7 +1915,7 @@ btr_cur_update_alloc_zip(
return(FALSE);
}
- if (trx && trx->fake_changes) {
+ if (UNIV_UNLIKELY(trx && trx->fake_changes)) {
/* Don't call page_zip_compress_write_log_no_data as that has
assert which would fail. Assume there won't be a compression
failure. */
@@ -2021,7 +2022,7 @@ btr_cur_update_in_place(
return(err);
}
- if (trx->fake_changes) {
+ if (UNIV_UNLIKELY(trx->fake_changes)) {
/* skip CHANGE, LOG */
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
@@ -2056,13 +2057,13 @@ btr_cur_update_in_place(
btr_search_update_hash_on_delete(cursor);
}
- rw_lock_x_lock(btr_search_get_latch(cursor->index->id));
+ rw_lock_x_lock(btr_search_get_latch(cursor->index));
}
row_upd_rec_in_place(rec, index, offsets, update, page_zip);
if (is_hashed) {
- rw_lock_x_unlock(btr_search_get_latch(cursor->index->id));
+ rw_lock_x_unlock(btr_search_get_latch(cursor->index));
}
if (page_zip && !dict_index_is_clust(index)
@@ -2256,7 +2257,7 @@ any_extern:
goto err_exit;
}
- if (thr && thr_get_trx(thr)->fake_changes) {
+ if (UNIV_UNLIKELY(thr && thr_get_trx(thr)->fake_changes)) {
/* skip CHANGE, LOG */
goto err_exit; /* == DB_SUCCESS */
}
@@ -2494,7 +2495,7 @@ btr_cur_pessimistic_update(
itself. Thus the following call is safe. */
row_upd_index_replace_new_col_vals_index_pos(new_entry, index, update,
FALSE, *heap);
- if (!(flags & BTR_KEEP_SYS_FLAG) && !trx->fake_changes) {
+ if (!(flags & BTR_KEEP_SYS_FLAG) && UNIV_LIKELY(!trx->fake_changes)) {
row_upd_index_entry_sys_field(new_entry, index, DATA_ROLL_PTR,
roll_ptr);
row_upd_index_entry_sys_field(new_entry, index, DATA_TRX_ID,
@@ -2552,7 +2553,7 @@ make_external:
ut_ad(flags & BTR_KEEP_POS_FLAG);
}
- if (trx->fake_changes) {
+ if (UNIV_UNLIKELY(trx->fake_changes)) {
/* skip CHANGE, LOG */
err = DB_SUCCESS;
goto return_after_reservations;
@@ -2888,7 +2889,7 @@ btr_cur_del_mark_set_clust_rec(
ut_ad(dict_index_is_clust(index));
ut_ad(!rec_get_deleted_flag(rec, rec_offs_comp(offsets)));
- if (thr && thr_get_trx(thr)->fake_changes) {
+ if (UNIV_UNLIKELY(thr && thr_get_trx(thr)->fake_changes)) {
/* skip LOCK, UNDO, CHANGE, LOG */
return(DB_SUCCESS);
}
@@ -3027,7 +3028,7 @@ btr_cur_del_mark_set_sec_rec(
rec_t* rec;
ulint err;
- if (thr && thr_get_trx(thr)->fake_changes) {
+ if (UNIV_UNLIKELY(thr && thr_get_trx(thr)->fake_changes)) {
/* skip LOCK, CHANGE, LOG */
return(DB_SUCCESS);
}
@@ -4789,6 +4790,10 @@ next_zip_page:
}
}
}
+
+ DBUG_EXECUTE_IF("btr_store_big_rec_extern",
+ error = DB_OUT_OF_FILE_SPACE;
+ goto func_exit;);
}
func_exit:
@@ -4821,9 +4826,11 @@ func_exit:
field_ref = btr_rec_get_field_ref(rec, offsets, i);
- /* The pointer must not be zero. */
+ /* The pointer must not be zero if the operation
+ succeeded. */
ut_a(0 != memcmp(field_ref, field_ref_zero,
- BTR_EXTERN_FIELD_REF_SIZE));
+ BTR_EXTERN_FIELD_REF_SIZE)
+ || error != DB_SUCCESS);
/* The column must not be disowned by this record. */
ut_a(!(field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_OWNER_FLAG));
}
@@ -4919,10 +4926,10 @@ btr_free_externally_stored_field(
if (UNIV_UNLIKELY(!memcmp(field_ref, field_ref_zero,
BTR_EXTERN_FIELD_REF_SIZE))) {
- /* In the rollback of uncommitted transactions, we may
- encounter a clustered index record whose BLOBs have
- not been written. There is nothing to free then. */
- ut_a(rb_ctx == RB_RECOVERY || rb_ctx == RB_RECOVERY_PURGE_REC);
+ /* In the rollback, we may encounter a clustered index
+ record with some unwritten off-page columns. There is
+ nothing to free then. */
+ ut_a(rb_ctx != RB_NONE);
return;
}
diff --git a/storage/xtradb/btr/btr0sea.c b/storage/xtradb/btr/btr0sea.c
index 83e13e58d70..9fe6fa54b97 100644
--- a/storage/xtradb/btr/btr0sea.c
+++ b/storage/xtradb/btr/btr0sea.c
@@ -69,17 +69,14 @@ hotspots from residing on the same memory
cache line as btr_search_latch */
UNIV_INTERN byte btr_sea_pad1[64];
-/** The latch protecting the adaptive search system: this latch protects the
-(1) positions of records on those pages where a hash index has been built.
-NOTE: It does not protect values of non-ordering fields within a record from
+/** Array of latches protecting individual AHI partitions. The latches
+protect: (1) positions of records on those pages where a hash index from the
+corresponding AHI partition has been built.
+NOTE: They do not protect values of non-ordering fields within a record from
being updated in-place! We can use fact (1) to perform unique searches to
indexes. */
-/* We will allocate the latch from dynamic memory to get it to the
-same DRAM page as other hotspot semaphores */
-//UNIV_INTERN rw_lock_t* btr_search_latch_temp;
-
-UNIV_INTERN rw_lock_t** btr_search_latch_part;
+UNIV_INTERN rw_lock_t* btr_search_latch_arr;
/** padding to prevent other memory update hotspots from residing on
the same memory cache line */
@@ -133,17 +130,17 @@ static
void
btr_search_check_free_space_in_heap(
/*=====================================*/
- index_id_t key)
+ dict_index_t* index)
{
hash_table_t* table;
mem_heap_t* heap;
#ifdef UNIV_SYNC_DEBUG
- ut_ad(!rw_lock_own(btr_search_get_latch(key), RW_LOCK_SHARED));
- ut_ad(!rw_lock_own(btr_search_get_latch(key), RW_LOCK_EX));
+ ut_ad(!rw_lock_own(btr_search_get_latch(index), RW_LOCK_SHARED));
+ ut_ad(!rw_lock_own(btr_search_get_latch(index), RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
- table = btr_search_get_hash_index(key);
+ table = btr_search_get_hash_table(index);
heap = table->heap;
@@ -154,7 +151,7 @@ btr_search_check_free_space_in_heap(
if (heap->free_block == NULL) {
buf_block_t* block = buf_block_alloc(NULL);
- rw_lock_x_lock(btr_search_get_latch(key));
+ rw_lock_x_lock(btr_search_get_latch(index));
if (heap->free_block == NULL) {
heap->free_block = block;
@@ -162,7 +159,7 @@ btr_search_check_free_space_in_heap(
buf_block_free(block);
}
- rw_lock_x_unlock(btr_search_get_latch(key));
+ rw_lock_x_unlock(btr_search_get_latch(index));
}
}
@@ -194,16 +191,19 @@ btr_search_sys_create(
btr_search_sys = mem_alloc(sizeof(btr_search_sys_t));
- /* btr_search_index_num should be <= 32. (bits of trx->has_search_latch) */
- btr_search_latch_part = mem_alloc(sizeof(rw_lock_t*) * btr_search_index_num);
- btr_search_sys->hash_index = mem_alloc(sizeof(hash_table_t*) * btr_search_index_num);
+ /* btr_search_index_num is constrained to machine word size for
+ historical reasons. This limitation can be easily removed later. */
+
+ btr_search_latch_arr = mem_alloc(sizeof(rw_lock_t) *
+ btr_search_index_num);
+ btr_search_sys->hash_tables = mem_alloc(sizeof(hash_table_t *) *
+ btr_search_index_num);
for (i = 0; i < btr_search_index_num; i++) {
- btr_search_latch_part[i] = mem_alloc(sizeof(rw_lock_t));
rw_lock_create(btr_search_latch_key,
- btr_search_latch_part[i], SYNC_SEARCH_SYS);
+ &btr_search_latch_arr[i], SYNC_SEARCH_SYS);
- btr_search_sys->hash_index[i] = ha_create(hash_size, 0, 0);
+ btr_search_sys->hash_tables[i] = ha_create(hash_size, 0, 0);
}
}
@@ -217,15 +217,13 @@ btr_search_sys_free(void)
ulint i;
for (i = 0; i < btr_search_index_num; i++) {
- mem_heap_free(btr_search_sys->hash_index[i]->heap);
- hash_table_free(btr_search_sys->hash_index[i]);
-
- rw_lock_free(btr_search_latch_part[i]);
+ mem_heap_free(btr_search_sys->hash_tables[i]->heap);
+ hash_table_free(btr_search_sys->hash_tables[i]);
- mem_free(btr_search_latch_part[i]);
+ rw_lock_free(&btr_search_latch_arr[i]);
}
- mem_free(btr_search_sys->hash_index);
- mem_free(btr_search_latch_part);
+ mem_free(btr_search_sys->hash_tables);
+ mem_free(btr_search_latch_arr);
//rw_lock_free(&btr_search_latch);
//mem_free(btr_search_latch_temp);
@@ -270,8 +268,8 @@ btr_search_disable(void)
/* Clear the adaptive hash index. */
for (i = 0; i < btr_search_index_num; i++) {
- hash_table_clear(btr_search_sys->hash_index[i]);
- mem_heap_empty(btr_search_sys->hash_index[i]->heap);
+ hash_table_clear(btr_search_sys->hash_tables[i]);
+ mem_heap_empty(btr_search_sys->hash_tables[i]->heap);
}
btr_search_x_unlock_all();
@@ -334,27 +332,27 @@ btr_search_info_create(
/*****************************************************************//**
Returns the value of ref_count. The value is protected by
-btr_search_latch.
+the latch of the AHI partition corresponding to this index.
@return ref_count value. */
UNIV_INTERN
ulint
btr_search_info_get_ref_count(
/*==========================*/
btr_search_t* info, /*!< in: search info. */
- index_id_t key)
+ dict_index_t* index) /*!< in: index */
{
ulint ret;
ut_ad(info);
#ifdef UNIV_SYNC_DEBUG
- ut_ad(!rw_lock_own(btr_search_get_latch(key), RW_LOCK_SHARED));
- ut_ad(!rw_lock_own(btr_search_get_latch(key), RW_LOCK_EX));
+ ut_ad(!rw_lock_own(btr_search_get_latch(index), RW_LOCK_SHARED));
+ ut_ad(!rw_lock_own(btr_search_get_latch(index), RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
- rw_lock_s_lock(btr_search_get_latch(key));
+ rw_lock_s_lock(btr_search_get_latch(index));
ret = info->ref_count;
- rw_lock_s_unlock(btr_search_get_latch(key));
+ rw_lock_s_unlock(btr_search_get_latch(index));
return(ret);
}
@@ -375,8 +373,8 @@ btr_search_info_update_hash(
int cmp;
#ifdef UNIV_SYNC_DEBUG
- ut_ad(!rw_lock_own(btr_search_get_latch(cursor->index->id), RW_LOCK_SHARED));
- ut_ad(!rw_lock_own(btr_search_get_latch(cursor->index->id), RW_LOCK_EX));
+ ut_ad(!rw_lock_own(btr_search_get_latch(cursor->index), RW_LOCK_SHARED));
+ ut_ad(!rw_lock_own(btr_search_get_latch(cursor->index), RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
index = cursor->index;
@@ -494,8 +492,8 @@ btr_search_update_block_hash_info(
/*!< in: cursor */
{
#ifdef UNIV_SYNC_DEBUG
- ut_ad(!rw_lock_own(btr_search_get_latch(cursor->index->id), RW_LOCK_SHARED));
- ut_ad(!rw_lock_own(btr_search_get_latch(cursor->index->id), RW_LOCK_EX));
+ ut_ad(!rw_lock_own(btr_search_get_latch(cursor->index), RW_LOCK_SHARED));
+ ut_ad(!rw_lock_own(btr_search_get_latch(cursor->index), RW_LOCK_EX));
ut_ad(rw_lock_own(&block->lock, RW_LOCK_SHARED)
|| rw_lock_own(&block->lock, RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
@@ -579,7 +577,7 @@ btr_search_update_hash_ref(
ut_ad(cursor->flag == BTR_CUR_HASH_FAIL);
#ifdef UNIV_SYNC_DEBUG
- ut_ad(rw_lock_own(btr_search_get_latch(cursor->index->id), RW_LOCK_EX));
+ ut_ad(rw_lock_own(btr_search_get_latch(cursor->index), RW_LOCK_EX));
ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED)
|| rw_lock_own(&(block->lock), RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
@@ -620,11 +618,12 @@ btr_search_update_hash_ref(
mem_heap_free(heap);
}
#ifdef UNIV_SYNC_DEBUG
- ut_ad(rw_lock_own(btr_search_get_latch(cursor->index->id), RW_LOCK_EX));
+ ut_ad(rw_lock_own(btr_search_get_latch(cursor->index),
+ RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
- ha_insert_for_fold(btr_search_get_hash_index(cursor->index->id), fold,
- block, rec);
+ ha_insert_for_fold(btr_search_get_hash_table(cursor->index),
+ fold, block, rec);
}
}
@@ -643,8 +642,8 @@ btr_search_info_update_slow(
ulint* params2;
#ifdef UNIV_SYNC_DEBUG
- ut_ad(!rw_lock_own(btr_search_get_latch(cursor->index->id), RW_LOCK_SHARED));
- ut_ad(!rw_lock_own(btr_search_get_latch(cursor->index->id), RW_LOCK_EX));
+ ut_ad(!rw_lock_own(btr_search_get_latch(cursor->index), RW_LOCK_SHARED));
+ ut_ad(!rw_lock_own(btr_search_get_latch(cursor->index), RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
block = btr_cur_get_block(cursor);
@@ -662,7 +661,7 @@ btr_search_info_update_slow(
if (build_index || (cursor->flag == BTR_CUR_HASH_FAIL)) {
- btr_search_check_free_space_in_heap(cursor->index->id);
+ btr_search_check_free_space_in_heap(cursor->index);
}
if (cursor->flag == BTR_CUR_HASH_FAIL) {
@@ -672,11 +671,11 @@ btr_search_info_update_slow(
btr_search_n_hash_fail++;
#endif /* UNIV_SEARCH_PERF_STAT */
- rw_lock_x_lock(btr_search_get_latch(cursor->index->id));
+ rw_lock_x_lock(btr_search_get_latch(cursor->index));
btr_search_update_hash_ref(info, block, cursor);
- rw_lock_x_unlock(btr_search_get_latch(cursor->index->id));
+ rw_lock_x_unlock(btr_search_get_latch(cursor->index));
}
if (build_index) {
@@ -921,17 +920,17 @@ btr_search_guess_on_hash(
cursor->flag = BTR_CUR_HASH;
if (UNIV_LIKELY(!has_search_latch)) {
- rw_lock_s_lock(btr_search_get_latch(index_id));
+ rw_lock_s_lock(btr_search_get_latch(index));
if (UNIV_UNLIKELY(!btr_search_enabled)) {
goto failure_unlock;
}
}
- ut_ad(rw_lock_get_writer(btr_search_get_latch(index_id)) != RW_LOCK_EX);
- ut_ad(rw_lock_get_reader_count(btr_search_get_latch(index_id)) > 0);
+ ut_ad(rw_lock_get_writer(btr_search_get_latch(index)) != RW_LOCK_EX);
+ ut_ad(rw_lock_get_reader_count(btr_search_get_latch(index)) > 0);
- rec = ha_search_and_get_data(btr_search_get_hash_index(index_id), fold);
+ rec = ha_search_and_get_data(btr_search_get_hash_table(index), fold);
if (UNIV_UNLIKELY(!rec)) {
goto failure_unlock;
@@ -949,7 +948,7 @@ btr_search_guess_on_hash(
goto failure_unlock;
}
- rw_lock_s_unlock(btr_search_get_latch(index_id));
+ rw_lock_s_unlock(btr_search_get_latch(index));
buf_block_dbg_add_level(block, SYNC_TREE_NODE_FROM_HASH);
}
@@ -1046,7 +1045,7 @@ btr_search_guess_on_hash(
/*-------------------------------------------*/
failure_unlock:
if (UNIV_LIKELY(!has_search_latch)) {
- rw_lock_s_unlock(btr_search_get_latch(index_id));
+ rw_lock_s_unlock(btr_search_get_latch(index));
}
failure:
cursor->flag = BTR_CUR_HASH_FAIL;
@@ -1091,48 +1090,26 @@ btr_search_drop_page_hash_index(
ulint* offsets;
retry:
- if (btr_search_index_num > 1) {
- rw_lock_t* btr_search_latch;
-
- /* FIXME: This may be optimistic implementation still. */
- btr_search_latch = (rw_lock_t*)(block->btr_search_latch);
- if (UNIV_LIKELY(!btr_search_latch)) {
- if (block->index) {
- goto retry;
- }
- return;
- }
- rw_lock_s_lock(btr_search_latch);
- if (UNIV_LIKELY(btr_search_latch != block->btr_search_latch)) {
- rw_lock_s_unlock(btr_search_latch);
- goto retry;
- }
- if (UNIV_LIKELY(!block->index)) {
- rw_lock_s_unlock(btr_search_latch);
- goto retry;
- }
- index = block->index;
- ut_a(btr_search_latch == btr_search_get_latch(index->id));
- } else {
- /* btr_search_index_num == 1 */
- /* btr_search_latch is only one and able to obtain
- before evaluating block->index. */
- rw_lock_s_lock(btr_search_latch_part[0]);
- if (UNIV_LIKELY(!block->index)) {
- rw_lock_s_unlock(btr_search_latch_part[0]);
- return;
- }
- index = block->index;
+ /* Do a dirty check on block->index, return if the block is not in the
+ adaptive hash index. This is to avoid acquiring an AHI latch for
+ performance considerations. */
+
+ index = block->index;
+ if (!index) {
+
+ return;
}
- if (UNIV_LIKELY(!index)) {
+ rw_lock_s_lock(btr_search_get_latch(index));
- rw_lock_s_unlock(btr_search_get_latch(index->id));
+ if (UNIV_UNLIKELY(index != block->index)) {
- return;
+ rw_lock_s_unlock(btr_search_get_latch(index));
+
+ goto retry;
}
- table = btr_search_get_hash_index(index->id);
+ table = btr_search_get_hash_table(index);
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED)
@@ -1149,7 +1126,7 @@ retry:
releasing btr_search_latch, as the index page might only
be s-latched! */
- rw_lock_s_unlock(btr_search_get_latch(index->id));
+ rw_lock_s_unlock(btr_search_get_latch(index));
ut_a(n_fields + n_bytes > 0);
@@ -1200,7 +1177,7 @@ next_rec:
mem_heap_free(heap);
}
- rw_lock_x_lock(btr_search_get_latch(index->id));
+ rw_lock_x_lock(btr_search_get_latch(index));
if (UNIV_UNLIKELY(!block->index)) {
/* Someone else has meanwhile dropped the hash index */
@@ -1216,7 +1193,7 @@ next_rec:
/* Someone else has meanwhile built a new hash index on the
page, with different parameters */
- rw_lock_x_unlock(btr_search_get_latch(index->id));
+ rw_lock_x_unlock(btr_search_get_latch(index));
mem_free(folds);
goto retry;
@@ -1231,7 +1208,6 @@ next_rec:
index->search_info->ref_count--;
block->index = NULL;
- block->btr_search_latch = NULL;
cleanup:
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
@@ -1244,14 +1220,14 @@ cleanup:
"InnoDB: the hash index to a page of %s,"
" still %lu hash nodes remain.\n",
index->name, (ulong) block->n_pointers);
- rw_lock_x_unlock(btr_search_get_latch(index->id));
+ rw_lock_x_unlock(btr_search_get_latch(index));
ut_ad(btr_search_validate());
} else {
- rw_lock_x_unlock(btr_search_get_latch(index->id));
+ rw_lock_x_unlock(btr_search_get_latch(index));
}
#else /* UNIV_AHI_DEBUG || UNIV_DEBUG */
- rw_lock_x_unlock(btr_search_get_latch(index->id));
+ rw_lock_x_unlock(btr_search_get_latch(index));
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
mem_free(folds);
@@ -1283,9 +1259,9 @@ btr_search_drop_page_hash_index_on_index(
ulint* offsets;
ibool released_search_latch;
- rw_lock_s_lock(btr_search_get_latch(index->id));
+ rw_lock_s_lock(btr_search_get_latch(index));
- table = btr_search_get_hash_index(index->id);
+ table = btr_search_get_hash_table(index);
for (j = 0; j < srv_buf_pool_instances; j++) {
buf_pool_t* buf_pool;
@@ -1319,7 +1295,8 @@ retry:
/* keeping latch order */
- rw_lock_s_unlock(btr_search_get_latch(index->id));
+ rw_lock_s_unlock(
+ btr_search_get_latch(index));
released_search_latch = TRUE;
rw_lock_x_lock(&block->lock);
@@ -1371,7 +1348,8 @@ next_rec:
mem_heap_empty(heap);
}
- rw_lock_x_lock(btr_search_get_latch(index->id));
+ rw_lock_x_lock(
+ btr_search_get_latch(index));
if (UNIV_UNLIKELY(!block->index)) {
goto cleanup;
@@ -1381,12 +1359,14 @@ next_rec:
if (UNIV_UNLIKELY(block->curr_n_fields != n_fields)
|| UNIV_UNLIKELY(block->curr_n_bytes != n_bytes)) {
- rw_lock_x_unlock(btr_search_get_latch(index->id));
+ rw_lock_x_unlock(
+ btr_search_get_latch(index));
rw_lock_x_unlock(&block->lock);
mem_free(folds);
- rw_lock_s_lock(btr_search_get_latch(index->id));
+ rw_lock_s_lock(
+ btr_search_get_latch(index));
goto retry;
}
@@ -1399,7 +1379,6 @@ next_rec:
index->search_info->ref_count--;
block->index = NULL;
- block->btr_search_latch = NULL;
cleanup:
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
@@ -1412,18 +1391,20 @@ cleanup:
index->name, (ulong) block->n_pointers);
}
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
- rw_lock_x_unlock(btr_search_get_latch(index->id));
+ rw_lock_x_unlock(
+ btr_search_get_latch(index));
rw_lock_x_unlock(&block->lock);
mem_free(folds);
- rw_lock_s_lock(btr_search_get_latch(index->id));
+ rw_lock_s_lock(
+ btr_search_get_latch(index));
}
}
} while (released_search_latch);
}
- rw_lock_s_unlock(btr_search_get_latch(index->id));
+ rw_lock_s_unlock(btr_search_get_latch(index));
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
@@ -1502,7 +1483,7 @@ btr_search_build_page_hash_index(
ut_ad(index);
ut_a(!dict_index_is_ibuf(index));
- table = btr_search_get_hash_index(index->id);
+ table = btr_search_get_hash_table(index);
page = buf_block_get_frame(block);
#ifdef UNIV_SYNC_DEBUG
@@ -1511,17 +1492,17 @@ btr_search_build_page_hash_index(
|| rw_lock_own(&(block->lock), RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
- rw_lock_s_lock(btr_search_get_latch(index->id));
+ rw_lock_s_lock(btr_search_get_latch(index));
if (block->index && ((block->curr_n_fields != n_fields)
|| (block->curr_n_bytes != n_bytes)
|| (block->curr_left_side != left_side))) {
- rw_lock_s_unlock(btr_search_get_latch(index->id));
+ rw_lock_s_unlock(btr_search_get_latch(index));
btr_search_drop_page_hash_index(block);
} else {
- rw_lock_s_unlock(btr_search_get_latch(index->id));
+ rw_lock_s_unlock(btr_search_get_latch(index));
}
n_recs = page_get_n_recs(page);
@@ -1615,9 +1596,9 @@ btr_search_build_page_hash_index(
fold = next_fold;
}
- btr_search_check_free_space_in_heap(index->id);
+ btr_search_check_free_space_in_heap(index);
- rw_lock_x_lock(btr_search_get_latch(index->id));
+ rw_lock_x_lock(btr_search_get_latch(index));
if (UNIV_UNLIKELY(!btr_search_enabled)) {
goto exit_func;
@@ -1644,7 +1625,6 @@ btr_search_build_page_hash_index(
block->curr_n_bytes = n_bytes;
block->curr_left_side = left_side;
block->index = index;
- block->btr_search_latch = btr_search_get_latch(index->id);
for (i = 0; i < n_cached; i++) {
@@ -1652,7 +1632,7 @@ btr_search_build_page_hash_index(
}
exit_func:
- rw_lock_x_unlock(btr_search_get_latch(index->id));
+ rw_lock_x_unlock(btr_search_get_latch(index));
mem_free(folds);
mem_free(recs);
@@ -1687,7 +1667,7 @@ btr_search_move_or_delete_hash_entries(
ut_ad(rw_lock_own(&(new_block->lock), RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
- rw_lock_s_lock(btr_search_get_latch(index->id));
+ rw_lock_s_lock(btr_search_get_latch(index));
ut_a(!new_block->index || new_block->index == index);
ut_a(!block->index || block->index == index);
@@ -1696,7 +1676,7 @@ btr_search_move_or_delete_hash_entries(
if (new_block->index) {
- rw_lock_s_unlock(btr_search_get_latch(index->id));
+ rw_lock_s_unlock(btr_search_get_latch(index));
btr_search_drop_page_hash_index(block);
@@ -1713,7 +1693,7 @@ btr_search_move_or_delete_hash_entries(
new_block->n_bytes = block->curr_n_bytes;
new_block->left_side = left_side;
- rw_lock_s_unlock(btr_search_get_latch(index->id));
+ rw_lock_s_unlock(btr_search_get_latch(index));
ut_a(n_fields + n_bytes > 0);
@@ -1725,7 +1705,7 @@ btr_search_move_or_delete_hash_entries(
return;
}
- rw_lock_s_unlock(btr_search_get_latch(index->id));
+ rw_lock_s_unlock(btr_search_get_latch(index));
}
/********************************************************************//**
@@ -1764,7 +1744,7 @@ btr_search_update_hash_on_delete(
ut_a(block->curr_n_fields + block->curr_n_bytes > 0);
ut_a(!dict_index_is_ibuf(index));
- table = btr_search_get_hash_index(cursor->index->id);
+ table = btr_search_get_hash_table(cursor->index);
rec = btr_cur_get_rec(cursor);
@@ -1775,7 +1755,7 @@ btr_search_update_hash_on_delete(
mem_heap_free(heap);
}
- rw_lock_x_lock(btr_search_get_latch(cursor->index->id));
+ rw_lock_x_lock(btr_search_get_latch(cursor->index));
if (block->index) {
ut_a(block->index == index);
@@ -1783,7 +1763,7 @@ btr_search_update_hash_on_delete(
ha_search_and_delete_if_found(table, fold, rec);
}
- rw_lock_x_unlock(btr_search_get_latch(cursor->index->id));
+ rw_lock_x_unlock(btr_search_get_latch(cursor->index));
}
/********************************************************************//**
@@ -1820,7 +1800,7 @@ btr_search_update_hash_node_on_insert(
ut_a(cursor->index == index);
ut_a(!dict_index_is_ibuf(index));
- rw_lock_x_lock(btr_search_get_latch(cursor->index->id));
+ rw_lock_x_lock(btr_search_get_latch(cursor->index));
if (!block->index) {
@@ -1834,15 +1814,15 @@ btr_search_update_hash_node_on_insert(
&& (cursor->n_bytes == block->curr_n_bytes)
&& !block->curr_left_side) {
- table = btr_search_get_hash_index(cursor->index->id);
+ table = btr_search_get_hash_table(cursor->index);
ha_search_and_update_if_found(table, cursor->fold, rec,
block, page_rec_get_next(rec));
func_exit:
- rw_lock_x_unlock(btr_search_get_latch(cursor->index->id));
+ rw_lock_x_unlock(btr_search_get_latch(cursor->index));
} else {
- rw_lock_x_unlock(btr_search_get_latch(cursor->index->id));
+ rw_lock_x_unlock(btr_search_get_latch(cursor->index));
btr_search_update_hash_on_insert(cursor);
}
@@ -1877,9 +1857,9 @@ btr_search_update_hash_on_insert(
ulint* offsets = offsets_;
rec_offs_init(offsets_);
- table = btr_search_get_hash_index(cursor->index->id);
+ table = btr_search_get_hash_table(cursor->index);
- btr_search_check_free_space_in_heap(cursor->index->id);
+ btr_search_check_free_space_in_heap(cursor->index);
rec = btr_cur_get_rec(cursor);
@@ -1924,7 +1904,7 @@ btr_search_update_hash_on_insert(
} else {
if (left_side) {
- rw_lock_x_lock(btr_search_get_latch(index->id));
+ rw_lock_x_lock(btr_search_get_latch(index));
locked = TRUE;
@@ -1942,7 +1922,7 @@ btr_search_update_hash_on_insert(
if (!locked) {
- rw_lock_x_lock(btr_search_get_latch(index->id));
+ rw_lock_x_lock(btr_search_get_latch(index));
locked = TRUE;
@@ -1964,7 +1944,7 @@ check_next_rec:
if (!left_side) {
if (!locked) {
- rw_lock_x_lock(btr_search_get_latch(index->id));
+ rw_lock_x_lock(btr_search_get_latch(index));
locked = TRUE;
@@ -1983,7 +1963,7 @@ check_next_rec:
if (!locked) {
- rw_lock_x_lock(btr_search_get_latch(index->id));
+ rw_lock_x_lock(btr_search_get_latch(index));
locked = TRUE;
@@ -2010,7 +1990,7 @@ function_exit:
mem_heap_free(heap);
}
if (locked) {
- rw_lock_x_unlock(btr_search_get_latch(index->id));
+ rw_lock_x_unlock(btr_search_get_latch(index));
}
}
@@ -2043,7 +2023,7 @@ btr_search_validate(void)
for (j = 0; j < btr_search_index_num; j++) {
- cell_count = hash_get_n_cells(btr_search_sys->hash_index[j]);
+ cell_count = hash_get_n_cells(btr_search_sys->hash_tables[j]);
for (i = 0; i < cell_count; i++) {
/* We release btr_search_latch every once in a while to
@@ -2056,7 +2036,7 @@ btr_search_validate(void)
buf_pool_page_hash_x_lock_all();
}
- node = hash_get_nth_cell(btr_search_sys->hash_index[j], i)->node;
+ node = hash_get_nth_cell(btr_search_sys->hash_tables[j], i)->node;
for (; node != NULL; node = node->next) {
const buf_block_t* block
@@ -2171,7 +2151,7 @@ btr_search_validate(void)
buf_pool_page_hash_x_lock_all();
}
- if (!ha_validate(btr_search_sys->hash_index[j], i, end_index)) {
+ if (!ha_validate(btr_search_sys->hash_tables[j], i, end_index)) {
ok = FALSE;
}
}
diff --git a/storage/xtradb/buf/buf0buf.c b/storage/xtradb/buf/buf0buf.c
index dee747b3c9d..f06fd4abfb1 100644
--- a/storage/xtradb/buf/buf0buf.c
+++ b/storage/xtradb/buf/buf0buf.c
@@ -989,7 +989,6 @@ buf_block_init(
block->check_index_page_at_flush = FALSE;
block->index = NULL;
- block->btr_search_latch = NULL;
#ifdef UNIV_DEBUG
block->page.in_page_hash = FALSE;
@@ -1468,7 +1467,7 @@ buf_pool_clear_hash_index(void)
ulint j;
for (j = 0; j < btr_search_index_num; j++) {
- ut_ad(rw_lock_own(btr_search_latch_part[j], RW_LOCK_EX));
+ ut_ad(rw_lock_own(&btr_search_latch_arr[j], RW_LOCK_EX));
}
#endif /* UNIV_SYNC_DEBUG */
ut_ad(!btr_search_enabled);
@@ -2164,7 +2163,6 @@ buf_block_init_low(
{
block->check_index_page_at_flush = FALSE;
block->index = NULL;
- block->btr_search_latch = NULL;
block->n_hash_helps = 0;
block->n_fields = 1;
@@ -2681,6 +2679,11 @@ wait_until_unfixed:
goto loop;
}
+ /* Buffer-fix the block so that it cannot be evicted
+ or relocated while we are attempting to allocate an
+ uncompressed page. */
+ bpage->buf_fix_count++;
+
/* Allocate an uncompressed page. */
//buf_pool_mutex_exit(buf_pool);
//mutex_exit(&buf_pool->zip_mutex);
@@ -2697,49 +2700,22 @@ wait_until_unfixed:
}
rw_lock_x_lock(&buf_pool->page_hash_latch);
- mutex_enter(block_mutex);
-
- {
- buf_page_t* hash_bpage;
-
- hash_bpage = buf_page_hash_get_low(
- buf_pool, space, offset, fold);
-
- if (UNIV_UNLIKELY(bpage != hash_bpage)) {
- /* The buf_pool->page_hash was modified
- while buf_pool->mutex was released.
- Free the block that was allocated. */
-
- buf_LRU_block_free_non_file_page(block, TRUE);
- mutex_exit(block_mutex);
-
- block = (buf_block_t*) hash_bpage;
- if (block) {
- block_mutex = buf_page_get_mutex_enter((buf_page_t*)block);
- ut_a(block_mutex);
- }
- rw_lock_x_unlock(&buf_pool->page_hash_latch);
-
- if (have_LRU_mutex) {
- mutex_exit(&buf_pool->LRU_list_mutex);
- have_LRU_mutex = FALSE;
- }
-
- goto loop2;
- }
- }
-
+ mutex_enter(&block->mutex);
mutex_enter(&buf_pool->zip_mutex);
+ /* Buffer-fixing prevents the page_hash from changing. */
+ ut_ad(bpage == buf_page_hash_get_low(buf_pool,
+ space, offset, fold));
if (UNIV_UNLIKELY
- (bpage->buf_fix_count
+ (--bpage->buf_fix_count
|| buf_page_get_io_fix(bpage) != BUF_IO_NONE)) {
mutex_exit(&buf_pool->zip_mutex);
- /* The block was buffer-fixed or I/O-fixed
- while buf_pool->mutex was not held by this thread.
- Free the block that was allocated and try again.
- This should be extremely unlikely. */
+ /* The block was buffer-fixed or I/O-fixed while
+ buf_pool->mutex was not held by this thread.
+ Free the block that was allocated and retry.
+ This should be extremely unlikely, for example,
+ if buf_page_get_zip() was invoked. */
buf_LRU_block_free_non_file_page(block, TRUE);
//mutex_exit(&block->mutex);
diff --git a/storage/xtradb/dict/dict0boot.c b/storage/xtradb/dict/dict0boot.c
index 6313c8ace8d..692c37cc5a2 100644
--- a/storage/xtradb/dict/dict0boot.c
+++ b/storage/xtradb/dict/dict0boot.c
@@ -31,6 +31,7 @@ Created 4/18/1996 Heikki Tuuri
#include "dict0crea.h"
#include "btr0btr.h"
+#include "btr0sea.h"
#include "dict0load.h"
#include "dict0load.h"
#include "trx0trx.h"
@@ -346,6 +347,7 @@ dict_add_to_cache_xtradb_sys_stats(
dict_mem_index_add_field(index, "KEY_COLS", 0);
index->id = DICT_STATS_ID;
+ btr_search_index_init(index);
root_page_id = mtr_read_ulint(dict_hdr + DICT_HDR_STATS, MLOG_4BYTES,
mtr);
@@ -481,6 +483,7 @@ dict_boot(void)
dict_mem_index_add_field(index, "NAME", 0);
index->id = DICT_TABLES_ID;
+ btr_search_index_init(index);
error = dict_index_add_to_cache(table, index,
mtr_read_ulint(dict_hdr
@@ -495,6 +498,8 @@ dict_boot(void)
dict_mem_index_add_field(index, "ID", 0);
index->id = DICT_TABLE_IDS_ID;
+ btr_search_index_init(index);
+
error = dict_index_add_to_cache(table, index,
mtr_read_ulint(dict_hdr
+ DICT_HDR_TABLE_IDS,
@@ -528,6 +533,7 @@ dict_boot(void)
dict_mem_index_add_field(index, "POS", 0);
index->id = DICT_COLUMNS_ID;
+ btr_search_index_init(index);
error = dict_index_add_to_cache(table, index,
mtr_read_ulint(dict_hdr
+ DICT_HDR_COLUMNS,
@@ -574,6 +580,7 @@ dict_boot(void)
dict_mem_index_add_field(index, "ID", 0);
index->id = DICT_INDEXES_ID;
+ btr_search_index_init(index);
error = dict_index_add_to_cache(table, index,
mtr_read_ulint(dict_hdr
+ DICT_HDR_INDEXES,
@@ -602,6 +609,7 @@ dict_boot(void)
dict_mem_index_add_field(index, "POS", 0);
index->id = DICT_FIELDS_ID;
+ btr_search_index_init(index);
error = dict_index_add_to_cache(table, index,
mtr_read_ulint(dict_hdr
+ DICT_HDR_FIELDS,
diff --git a/storage/xtradb/dict/dict0dict.c b/storage/xtradb/dict/dict0dict.c
index 3dc9367c296..50da1c97beb 100644
--- a/storage/xtradb/dict/dict0dict.c
+++ b/storage/xtradb/dict/dict0dict.c
@@ -1972,7 +1972,7 @@ dict_index_remove_from_cache(
zero. */
for (;;) {
- ulint ref_count = btr_search_info_get_ref_count(info, index->id);
+ ulint ref_count = btr_search_info_get_ref_count(info, index);
if (ref_count == 0) {
break;
}
@@ -2224,6 +2224,7 @@ dict_index_build_internal_clust(
new_index->n_user_defined_cols = index->n_fields;
new_index->id = index->id;
+ btr_search_index_init(new_index);
/* Copy the fields of index */
dict_index_copy(new_index, index, table, 0, index->n_fields);
@@ -2394,6 +2395,7 @@ dict_index_build_internal_non_clust(
new_index->n_user_defined_cols = index->n_fields;
new_index->id = index->id;
+ btr_search_index_init(new_index);
/* Copy fields from index to new_index */
dict_index_copy(new_index, index, table, 0, index->n_fields);
diff --git a/storage/xtradb/dict/dict0load.c b/storage/xtradb/dict/dict0load.c
index d8a9887dde3..0de6698f86c 100644
--- a/storage/xtradb/dict/dict0load.c
+++ b/storage/xtradb/dict/dict0load.c
@@ -33,6 +33,7 @@ Created 4/24/1996 Heikki Tuuri
#include "btr0pcur.h"
#include "btr0btr.h"
+#include "btr0sea.h"
#include "page0page.h"
#include "mach0data.h"
#include "dict0dict.h"
@@ -1431,6 +1432,7 @@ err_len:
(*index)->id = id;
(*index)->page = mach_read_from_4(field);
+ btr_search_index_init(*index);
ut_ad((*index)->page);
return(NULL);
diff --git a/storage/xtradb/fil/fil0fil.c b/storage/xtradb/fil/fil0fil.c
index 74fe1d8fd18..69a151be45f 100644
--- a/storage/xtradb/fil/fil0fil.c
+++ b/storage/xtradb/fil/fil0fil.c
@@ -2266,6 +2266,11 @@ fil_op_log_parse_or_replay(
if (!space_id) {
return(ptr);
+ } else {
+ /* Only replay file ops during recovery. This is a
+ release-build assert to minimize any data loss risk by a
+ misapplied file operation. */
+ ut_a(recv_recovery_is_on());
}
/* Let us try to perform the file operation, if sensible. Note that
diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc
index 92f5b03e663..1946d091993 100644
--- a/storage/xtradb/handler/ha_innodb.cc
+++ b/storage/xtradb/handler/ha_innodb.cc
@@ -99,6 +99,9 @@ extern "C" {
#include "ha_prototypes.h"
#include "ut0mem.h"
#include "ibuf0ibuf.h"
+
+enum_tx_isolation thd_get_trx_isolation(const THD* thd);
+
}
#include "ha_innodb.h"
@@ -467,6 +470,15 @@ innobase_is_fake_change(
whom the transaction is being committed */
+/******************************************************************//**
+Maps a MySQL trx isolation level code to the InnoDB isolation level code
+@return InnoDB isolation level */
+static inline
+ulint
+innobase_map_isolation_level(
+/*=========================*/
+ enum_tx_isolation iso); /*!< in: MySQL isolation level code */
+
static const char innobase_hton_name[]= "InnoDB";
/*************************************************************//**
@@ -1092,7 +1104,7 @@ my_bool
ha_innobase::is_fake_change_enabled(THD* thd)
{
trx_t* trx = thd_to_trx(thd);
- return(trx && trx->fake_changes);
+ return(trx && UNIV_UNLIKELY(trx->fake_changes));
}
/********************************************************************//**
@@ -1119,6 +1131,8 @@ innobase_release_temporary_latches(
trx = thd_to_trx(thd);
if (trx != NULL) {
+
+ /* No-op in XtraDB */
trx_search_latch_release_if_reserved(trx);
}
@@ -1435,7 +1449,8 @@ innobase_convert_from_id(
}
/**********************************************************************
-Converts an identifier from my_charset_filename to UTF-8 charset. */
+Converts an identifier from my_charset_filename to UTF-8 charset.
+@return result string length, as returned by strconvert() */
extern "C"
uint
innobase_convert_to_system_charset(
@@ -3356,7 +3371,7 @@ innobase_is_fake_change(
whom the transaction is being committed */
{
trx_t* trx = check_trx_exists(thd);
- return trx->fake_changes;
+ return UNIV_UNLIKELY(trx->fake_changes);
}
@@ -3440,9 +3455,22 @@ innobase_start_trx_and_assign_read_view(
trx_start_if_not_started(trx);
- /* Assign a read view if the transaction does not have it yet */
+ /* Assign a read view if the transaction does not have it yet.
+ Do this only if transaction is using REPEATABLE READ isolation
+ level. */
+ trx->isolation_level = innobase_map_isolation_level(
+ thd_get_trx_isolation(thd));
- trx_assign_read_view(trx);
+ if (trx->isolation_level == TRX_ISO_REPEATABLE_READ) {
+ trx_assign_read_view(trx);
+ } else {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ HA_ERR_UNSUPPORTED,
+ "InnoDB: WITH CONSISTENT SNAPSHOT "
+ "was ignored because this phrase "
+ "can only be used with "
+ "REPEATABLE READ isolation level.");
+ }
/* Set the MySQL flag to mark that there is an active transaction */
@@ -3578,11 +3606,13 @@ innobase_commit(
/* Since we will reserve the kernel mutex, we have to release
the search system latch first to obey the latching order. */
- if (trx->has_search_latch && !trx_is_active_commit_ordered(trx)) {
- trx_search_latch_release_if_reserved(trx);
- }
+ /* No-op in XtraDB */
+ trx_search_latch_release_if_reserved(trx);
+
+ if (UNIV_UNLIKELY(trx->fake_changes
+ && (all || (!thd_test_options(thd,
+ OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))))) {
- if (trx->fake_changes && (all || (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))) {
innobase_rollback(hton, thd, all); /* rollback implicitly */
thd->stmt_da->reset_diagnostics_area(); /* because debug assertion code complains, if something left */
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
@@ -8355,7 +8385,7 @@ ha_innobase::create(
trx = innobase_trx_allocate(thd);
- if (trx->fake_changes) {
+ if (UNIV_UNLIKELY(trx->fake_changes)) {
innobase_commit_low(trx);
trx_free_for_mysql(trx);
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
@@ -8582,7 +8612,7 @@ ha_innobase::truncate(void)
DBUG_RETURN(HA_ERR_CRASHED);
}
- if (prebuilt->trx->fake_changes) {
+ if (UNIV_UNLIKELY(prebuilt->trx->fake_changes)) {
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
}
@@ -8647,7 +8677,7 @@ ha_innobase::delete_table(
trx = innobase_trx_allocate(thd);
- if (trx->fake_changes) {
+ if (UNIV_UNLIKELY(trx->fake_changes)) {
innobase_commit_low(trx);
trx_free_for_mysql(trx);
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
@@ -8739,13 +8769,13 @@ innobase_drop_database(
trx->mysql_thd = NULL;
#else
trx = innobase_trx_allocate(thd);
- if (trx->fake_changes) {
+#endif
+ if (UNIV_UNLIKELY(trx->fake_changes)) {
my_free(namebuf);
innobase_commit_low(trx);
trx_free_for_mysql(trx);
return; /* ignore */
}
-#endif
row_drop_database_for_mysql(namebuf, trx);
my_free(namebuf);
@@ -8860,7 +8890,7 @@ ha_innobase::rename_table(
trx_search_latch_release_if_reserved(parent_trx);
trx = innobase_trx_allocate(thd);
- if (trx->fake_changes) {
+ if (UNIV_UNLIKELY(trx->fake_changes)) {
innobase_commit_low(trx);
trx_free_for_mysql(trx);
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
@@ -12769,6 +12799,63 @@ innobase_thd_get_thread_id(
return(thd_get_thread_id((const THD*) thd));
}
+#ifdef UNIV_DEBUG
+static my_bool innodb_log_checkpoint_now = TRUE;
+
+/****************************************************************//**
+Force innodb to checkpoint. */
+static
+void
+checkpoint_now_set(
+/*===============*/
+ THD* thd /*!< in: thread handle */
+ __attribute__((unused)),
+ struct st_mysql_sys_var* var /*!< in: pointer to system
+ variable */
+ __attribute__((unused)),
+ void* var_ptr /*!< out: where the formal
+ string goes */
+ __attribute__((unused)),
+ const void* save) /*!< in: immediate result from
+ check function */
+{
+ if (*(my_bool*) save) {
+ while (log_sys->last_checkpoint_lsn < log_sys->lsn) {
+ log_make_checkpoint_at(IB_ULONGLONG_MAX, TRUE);
+ fil_flush_file_spaces(FIL_LOG);
+ }
+ fil_write_flushed_lsn_to_data_files(log_sys->lsn, 0);
+ fil_flush_file_spaces(FIL_TABLESPACE);
+ }
+}
+
+static my_bool innodb_track_redo_log_now = TRUE;
+
+/****************************************************************//**
+Force log tracker to track the log synchronously. */
+static
+void
+track_redo_log_now_set(
+/*===================*/
+ THD* thd /*!< in: thread handle */
+ __attribute__((unused)),
+ struct st_mysql_sys_var* var /*!< in: pointer to system
+ variable */
+ __attribute__((unused)),
+ void* var_ptr /*!< out: where the formal
+ string goes */
+ __attribute__((unused)),
+ const void* save) /*!< in: immediate result from
+ check function */
+{
+ if (*(my_bool*) save && srv_track_changed_pages) {
+
+ log_online_follow_redo_log();
+ }
+}
+
+
+#endif /* UNIV_DEBUG */
static SHOW_VAR innodb_status_variables_export[]= {
{"Innodb", (char*) &show_innodb_vars, SHOW_FUNC},
@@ -13034,6 +13121,8 @@ static MYSQL_SYSVAR_BOOL(adaptive_hash_index, btr_search_enabled,
"Disable with --skip-innodb-adaptive-hash-index.",
NULL, innodb_adaptive_hash_index_update, TRUE);
+/* btr_search_index_num is constrained to machine word size for historical
+reasons. This limitation can be easily removed later. */
static MYSQL_SYSVAR_ULINT(adaptive_hash_index_partitions, btr_search_index_num,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"Number of InnoDB adaptive hash index partitions (default 1: disable partitioning)",
@@ -13239,10 +13328,17 @@ static MYSQL_SYSVAR_ENUM(stats_method, srv_innodb_stats_method,
"NULLS_UNEQUAL and NULLS_IGNORED",
NULL, NULL, SRV_STATS_NULLS_EQUAL, &innodb_stats_method_typelib);
+#ifdef UNIV_DEBUG
+/* Make this variable dynamic for debug builds to
+provide a testcase sync facility */
+#define track_changed_pages_flags PLUGIN_VAR_NOCMDARG
+#else
+#define track_changed_pages_flags PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY
+#endif
static MYSQL_SYSVAR_BOOL(track_changed_pages, srv_track_changed_pages,
- PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
- "Track the redo log for changed pages and output a changed page bitmap",
- NULL, NULL, FALSE);
+ track_changed_pages_flags,
+ "Track the redo log for changed pages and output a changed page bitmap",
+ NULL, NULL, FALSE);
static MYSQL_SYSVAR_ULONGLONG(max_bitmap_file_size, srv_max_bitmap_file_size,
PLUGIN_VAR_RQCMDARG,
@@ -13462,6 +13558,21 @@ static MYSQL_SYSVAR_ULINT(lazy_drop_table, srv_lazy_drop_table,
"[Deprecated option] no effect",
NULL, NULL, 0, 0, 1, 0);
+#ifdef UNIV_DEBUG
+
+static MYSQL_SYSVAR_BOOL(log_checkpoint_now, innodb_log_checkpoint_now,
+ PLUGIN_VAR_OPCMDARG,
+ "Force checkpoint now",
+ NULL, checkpoint_now_set, FALSE);
+
+static MYSQL_SYSVAR_BOOL(track_redo_log_now,
+ innodb_track_redo_log_now,
+ PLUGIN_VAR_OPCMDARG,
+ "Force log tracker to catch up with checkpoint now",
+ NULL, track_redo_log_now_set, FALSE);
+
+#endif /* UNIV_DEBUG */
+
static MYSQL_SYSVAR_BOOL(locking_fake_changes, srv_fake_changes_locks,
PLUGIN_VAR_NOCMDARG,
"###EXPERIMENTAL### if enabled, transactions will get S row locks instead "
@@ -13600,6 +13711,10 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(merge_sort_block_size),
MYSQL_SYSVAR(print_all_deadlocks),
MYSQL_SYSVAR(use_stacktrace),
+#ifdef UNIV_DEBUG
+ MYSQL_SYSVAR(log_checkpoint_now),
+ MYSQL_SYSVAR(track_redo_log_now),
+#endif /* UNIV_DEBUG */
NULL
};
@@ -13788,7 +13903,8 @@ test_innobase_convert_name()
#endif /* UNIV_COMPILE_TEST_FUNCS */
/**********************************************************************
-Converts an identifier from my_charset_filename to UTF-8 charset. */
+Converts an identifier from my_charset_filename to UTF-8 charset.
+@return result string length, as returned by strconvert() */
extern "C"
uint
innobase_convert_to_filename_charset(
diff --git a/storage/xtradb/handler/handler0alter.cc b/storage/xtradb/handler/handler0alter.cc
index a9c010ddbeb..308c90ccd3a 100644
--- a/storage/xtradb/handler/handler0alter.cc
+++ b/storage/xtradb/handler/handler0alter.cc
@@ -698,7 +698,7 @@ ha_innobase::add_index(
possible adaptive hash latch to avoid deadlocks of threads. */
trx_search_latch_release_if_reserved(prebuilt->trx);
- if (prebuilt->trx->fake_changes) {
+ if (UNIV_UNLIKELY(prebuilt->trx->fake_changes)) {
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
}
@@ -744,7 +744,7 @@ ha_innobase::add_index(
/* Create a background transaction for the operations on
the data dictionary tables. */
trx = innobase_trx_allocate(user_thd);
- if (trx->fake_changes) {
+ if (UNIV_UNLIKELY(trx->fake_changes)) {
mem_heap_free(heap);
trx_general_rollback_for_mysql(trx, NULL);
trx_free_for_mysql(trx);
@@ -1118,7 +1118,7 @@ ha_innobase::prepare_drop_index(
trx_search_latch_release_if_reserved(prebuilt->trx);
trx = prebuilt->trx;
- if (trx->fake_changes) {
+ if (UNIV_UNLIKELY(trx->fake_changes)) {
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
}
@@ -1330,7 +1330,7 @@ ha_innobase::final_drop_index(
/* Create a background transaction for the operations on
the data dictionary tables. */
trx = innobase_trx_allocate(user_thd);
- if (trx->fake_changes) {
+ if (UNIV_UNLIKELY(trx->fake_changes)) {
trx_general_rollback_for_mysql(trx, NULL);
trx_free_for_mysql(trx);
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
diff --git a/storage/xtradb/handler/i_s.cc b/storage/xtradb/handler/i_s.cc
index dabae2ba459..71808bcd0e6 100644
--- a/storage/xtradb/handler/i_s.cc
+++ b/storage/xtradb/handler/i_s.cc
@@ -7373,6 +7373,7 @@ i_s_innodb_changed_pages_fill(
}
if (!log_online_bitmap_iterator_init(&i, min_lsn, max_lsn)) {
+ my_error(ER_CANT_FIND_SYSTEM_REC, MYF(0));
DBUG_RETURN(1);
}
@@ -7436,6 +7437,7 @@ i_s_innodb_changed_pages_fill(
if (schema_table_store_record(thd, table))
{
log_online_bitmap_iterator_release(&i);
+ my_error(ER_CANT_FIND_SYSTEM_REC, MYF(0));
DBUG_RETURN(1);
}
diff --git a/storage/xtradb/ibuf/ibuf0ibuf.c b/storage/xtradb/ibuf/ibuf0ibuf.c
index 7be8f0b51c4..65489d13285 100644
--- a/storage/xtradb/ibuf/ibuf0ibuf.c
+++ b/storage/xtradb/ibuf/ibuf0ibuf.c
@@ -48,6 +48,7 @@ Created 7/19/1997 Heikki Tuuri
#include "btr0cur.h"
#include "btr0pcur.h"
#include "btr0btr.h"
+#include "btr0sea.h"
#include "row0upd.h"
#include "sync0sync.h"
#include "dict0boot.h"
@@ -631,6 +632,7 @@ ibuf_init_at_db_start(void)
dict_mem_index_add_field(index, "DUMMY_COLUMN", 0);
index->id = DICT_IBUF_ID_MIN + IBUF_SPACE_ID;
+ btr_search_index_init(index);
error = dict_index_add_to_cache(table, index,
FSP_IBUF_TREE_ROOT_PAGE_NO, FALSE);
@@ -4421,7 +4423,6 @@ ibuf_delete_rec(
BTR_MODIFY_TREE, pcur, mtr)) {
mutex_exit(&ibuf_mutex);
- ut_ad(!ibuf_inside(mtr));
ut_ad(mtr->state == MTR_COMMITTED);
goto func_exit;
}
@@ -4442,7 +4443,6 @@ ibuf_delete_rec(
ibuf_btr_pcur_commit_specify_mtr(pcur, mtr);
func_exit:
- ut_ad(!ibuf_inside(mtr));
ut_ad(mtr->state == MTR_COMMITTED);
btr_pcur_close(pcur);
@@ -4779,7 +4779,6 @@ loop:
BTR_MODIFY_LEAF,
&pcur, &mtr)) {
- ut_ad(!ibuf_inside(&mtr));
ut_ad(mtr.state == MTR_COMMITTED);
mops[op]++;
ibuf_dummy_index_free(dummy_index);
diff --git a/storage/xtradb/include/btr0sea.h b/storage/xtradb/include/btr0sea.h
index dc3bdbd0b0b..6fa7a2d87bf 100644
--- a/storage/xtradb/include/btr0sea.h
+++ b/storage/xtradb/include/btr0sea.h
@@ -79,14 +79,14 @@ btr_search_info_create(
mem_heap_t* heap); /*!< in: heap where created */
/*****************************************************************//**
Returns the value of ref_count. The value is protected by
-btr_search_latch.
+the latch of the AHI partition corresponding to this index.
@return ref_count value. */
UNIV_INTERN
ulint
btr_search_info_get_ref_count(
/*==========================*/
btr_search_t* info, /*!< in: search info. */
- index_id_t key);
+ dict_index_t* index); /*!< in: index */
/*********************************************************************//**
Updates the search info. */
UNIV_INLINE
@@ -204,36 +204,57 @@ btr_search_validate(void);
New functions to control split btr_search_index */
UNIV_INLINE
hash_table_t*
-btr_search_get_hash_index(
+btr_search_get_hash_table(
/*======================*/
- index_id_t key);
+ const dict_index_t* index) /*!< in: index */
+ __attribute__((nonnull,pure,warn_unused_result));
UNIV_INLINE
rw_lock_t*
btr_search_get_latch(
/*=================*/
- index_id_t key);
+ const dict_index_t* index) /*!< in: index */
+ __attribute__((nonnull,pure,warn_unused_result));
+/*********************************************************************//**
+Returns the AHI partition number corresponding to a given index ID. */
UNIV_INLINE
-void
-btr_search_x_lock_all(void);
-/*========================*/
+ulint
+btr_search_get_key(
+/*===============*/
+ index_id_t index_id) /*!< in: index ID */
+ __attribute__((pure,warn_unused_result));
+/*********************************************************************//**
+Initializes AHI-related fields in a newly created index. */
UNIV_INLINE
void
-btr_search_x_unlock_all(void);
-/*==========================*/
+btr_search_index_init(
+/*===============*/
+ dict_index_t* index) /*!< in: index */
+ __attribute__((nonnull));
UNIV_INLINE
void
-btr_search_s_lock_all(void);
+btr_search_x_lock_all(void);
/*========================*/
UNIV_INLINE
void
-btr_search_s_unlock_all(void);
+btr_search_x_unlock_all(void);
/*==========================*/
+#ifdef UNIV_SYNC_DEBUG
+/********************************************************************//**
+Checks if the thread owns any adaptive hash latches in either S or X mode.
+@return TRUE if the thread owns at least one latch in any mode. */
+UNIV_INLINE
+ibool
+btr_search_own_any(void)
+/*=====================*/
+ __attribute__((warn_unused_result));
+#endif
+
/** The search info struct in an index */
struct btr_search_struct{
ulint ref_count; /*!< Number of blocks in this index tree
@@ -294,8 +315,8 @@ typedef struct btr_search_sys_struct btr_search_sys_t;
/** The hash index system */
struct btr_search_sys_struct{
- hash_table_t** hash_index; /*!< the adaptive hash index,
- mapping dtuple_fold values
+ hash_table_t** hash_tables; /*!< the array of adaptive hash index,
+ tables mapping dtuple_fold values
to rec_t pointers on index pages */
};
diff --git a/storage/xtradb/include/btr0sea.ic b/storage/xtradb/include/btr0sea.ic
index d928711a21f..3f0dfdaa511 100644
--- a/storage/xtradb/include/btr0sea.ic
+++ b/storage/xtradb/include/btr0sea.ic
@@ -87,67 +87,99 @@ btr_search_info_update(
New functions to control split btr_search_index */
UNIV_INLINE
hash_table_t*
-btr_search_get_hash_index(
+btr_search_get_hash_table(
/*======================*/
- index_id_t key)
+ const dict_index_t* index) /*!< in: index */
{
- return(btr_search_sys->hash_index[key % btr_search_index_num]);
+ ut_ad(index);
+ ut_ad(index->search_table);
+
+ return(index->search_table);
}
UNIV_INLINE
rw_lock_t*
btr_search_get_latch(
/*=================*/
- index_id_t key)
+ const dict_index_t* index) /*!< in: index */
{
- return(btr_search_latch_part[key % btr_search_index_num]);
+ ut_ad(index);
+ ut_ad(index->search_latch >= btr_search_latch_arr &&
+ index->search_latch < btr_search_latch_arr +
+ btr_search_index_num);
+
+ return(index->search_latch);
}
+/*********************************************************************//**
+Returns the AHI partition number corresponding to a given index ID. */
+UNIV_INLINE
+ulint
+btr_search_get_key(
+/*===============*/
+ index_id_t index_id) /*!< in: index ID */
+{
+ return(index_id % btr_search_index_num);
+}
+
+/*********************************************************************//**
+Initializes AHI-related fields in a newly created index. */
UNIV_INLINE
void
-btr_search_x_lock_all(void)
-/*=======================*/
+btr_search_index_init(
+/*===============*/
+ dict_index_t* index) /*!< in: index */
{
- ulint i;
+ ut_ad(index);
- for (i = 0; i < btr_search_index_num; i++) {
- rw_lock_x_lock(btr_search_latch_part[i]);
- }
+ index->search_latch =
+ &btr_search_latch_arr[btr_search_get_key(index->id)];
+ index->search_table =
+ btr_search_sys->hash_tables[btr_search_get_key(index->id)];
}
UNIV_INLINE
void
-btr_search_x_unlock_all(void)
-/*==========================*/
+btr_search_x_lock_all(void)
+/*=======================*/
{
ulint i;
for (i = 0; i < btr_search_index_num; i++) {
- rw_lock_x_unlock(btr_search_latch_part[i]);
+ rw_lock_x_lock(&btr_search_latch_arr[i]);
}
}
UNIV_INLINE
void
-btr_search_s_lock_all(void)
-/*=======================*/
+btr_search_x_unlock_all(void)
+/*==========================*/
{
ulint i;
for (i = 0; i < btr_search_index_num; i++) {
- rw_lock_s_lock(btr_search_latch_part[i]);
+ rw_lock_x_unlock(&btr_search_latch_arr[i]);
}
}
+#ifdef UNIV_SYNC_DEBUG
+/********************************************************************//**
+Checks if the thread owns any adaptive hash latches in either S or X mode.
+@return TRUE if the thread owns at least one latch in any mode. */
UNIV_INLINE
-void
-btr_search_s_unlock_all(void)
-/*=========================*/
+ibool
+btr_search_own_any(void)
+/*====================*/
{
ulint i;
for (i = 0; i < btr_search_index_num; i++) {
- rw_lock_s_unlock(btr_search_latch_part[i]);
+ if (rw_lock_own(&btr_search_latch_arr[i], RW_LOCK_SHARED) ||
+ rw_lock_own(&btr_search_latch_arr[i], RW_LOCK_EX)) {
+ return(TRUE);
+ }
}
-}
+ return(FALSE);
+}
+#endif
diff --git a/storage/xtradb/include/btr0types.h b/storage/xtradb/include/btr0types.h
index 3865c07e9c4..a7cd64df276 100644
--- a/storage/xtradb/include/btr0types.h
+++ b/storage/xtradb/include/btr0types.h
@@ -41,22 +41,21 @@ typedef struct btr_search_struct btr_search_t;
#ifndef UNIV_HOTBACKUP
-/** @brief The latch protecting the adaptive search system
+/** @brief The array of latches protecting the adaptive search partitions
-This latch protects the
-(1) hash index;
+These latches protect the
+(1) hash index from the corresponding AHI partition;
(2) columns of a record to which we have a pointer in the hash index;
-but does NOT protect:
+but do NOT protect:
(3) next record offset field in a record;
(4) next or previous records on the same page.
-Bear in mind (3) and (4) when using the hash index.
+Bear in mind (3) and (4) when using the hash indexes.
*/
-//extern rw_lock_t* btr_search_latch_temp;
-extern rw_lock_t** btr_search_latch_part;
+extern rw_lock_t* btr_search_latch_arr;
#endif /* UNIV_HOTBACKUP */
diff --git a/storage/xtradb/include/buf0buf.h b/storage/xtradb/include/buf0buf.h
index 233231e4cab..701e820a23f 100644
--- a/storage/xtradb/include/buf0buf.h
+++ b/storage/xtradb/include/buf0buf.h
@@ -1716,7 +1716,6 @@ struct buf_block_struct{
complete, though: there may
have been hash collisions,
record deletions, etc. */
- volatile rw_lock_t* btr_search_latch;
/* @} */
# ifdef UNIV_SYNC_DEBUG
/** @name Debug fields */
diff --git a/storage/xtradb/include/dict0mem.h b/storage/xtradb/include/dict0mem.h
index 4e6713d15c8..717c7532dc9 100644
--- a/storage/xtradb/include/dict0mem.h
+++ b/storage/xtradb/include/dict0mem.h
@@ -365,6 +365,10 @@ struct dict_field_struct{
initialized to 0, NULL or FALSE in dict_mem_index_create(). */
struct dict_index_struct{
index_id_t id; /*!< id of the index */
+ rw_lock_t* search_latch; /*!< latch protecting the AHI partition
+ corresponding to this index */
+ hash_table_t* search_table; /*!< hash table protected by
+ search_latch */
mem_heap_t* heap; /*!< memory heap */
const char* name; /*!< index name */
const char* table_name;/*!< table name */
diff --git a/storage/xtradb/include/trx0trx.h b/storage/xtradb/include/trx0trx.h
index 96a9b180a0b..eac5eb87703 100644
--- a/storage/xtradb/include/trx0trx.h
+++ b/storage/xtradb/include/trx0trx.h
@@ -49,12 +49,14 @@ the kernel mutex */
extern ulint trx_n_prepared;
/********************************************************************//**
-Releases the search latch if trx has reserved it. */
-UNIV_INTERN
+In XtraDB it is impossible for a transaction to own a search latch outside of
+InnoDB code, so there is nothing to release on demand. We keep this function to
+simplify maintenance.*/
+UNIV_INLINE
void
trx_search_latch_release_if_reserved(
/*=================================*/
- trx_t* trx); /*!< in: transaction */
+ trx_t* trx __attribute__((unused))); /*!< in: transaction */
/******************************************************************//**
Set detailed error message for the transaction. */
UNIV_INTERN
@@ -555,8 +557,8 @@ struct trx_struct{
in that case we must flush the log
in trx_commit_complete_for_mysql() */
ulint duplicates; /*!< TRX_DUP_IGNORE | TRX_DUP_REPLACE */
- ulint has_search_latch;
- /* TRUE if this trx has latched the
+ ibool has_search_latch;
+ /* TRUE if this trx has latched any
search system latch in S-mode */
ulint deadlock_mark; /*!< a mark field used in deadlock
checking algorithm. */
diff --git a/storage/xtradb/include/trx0trx.ic b/storage/xtradb/include/trx0trx.ic
index 5f02c021204..97dda69f013 100644
--- a/storage/xtradb/include/trx0trx.ic
+++ b/storage/xtradb/include/trx0trx.ic
@@ -23,6 +23,19 @@ The transaction
Created 3/26/1996 Heikki Tuuri
*******************************************************/
+/********************************************************************//**
+In XtraDB it is impossible for a transaction to own a search latch outside of
+InnoDB code, so there is nothing to release on demand. We keep this function to
+simplify maintenance.*/
+UNIV_INLINE
+void
+trx_search_latch_release_if_reserved(
+/*=================================*/
+ trx_t* trx __attribute__((unused))) /*!< in: transaction */
+{
+ ut_ad(!trx->has_search_latch);
+}
+
/*************************************************************//**
Starts the transaction if it is not yet started. */
UNIV_INLINE
diff --git a/storage/xtradb/lock/lock0lock.c b/storage/xtradb/lock/lock0lock.c
index 495ff787328..547f13828b9 100644
--- a/storage/xtradb/lock/lock0lock.c
+++ b/storage/xtradb/lock/lock0lock.c
@@ -4019,7 +4019,7 @@ lock_table(
trx = thr_get_trx(thr);
- if (trx->fake_changes && mode == LOCK_IX) {
+ if (UNIV_UNLIKELY(trx->fake_changes && mode == LOCK_IX)) {
mode = LOCK_IS;
}
@@ -5268,7 +5268,7 @@ lock_rec_insert_check_and_lock(
trx = thr_get_trx(thr);
- if (trx->fake_changes) {
+ if (UNIV_UNLIKELY(trx->fake_changes)) {
return(DB_SUCCESS);
}
@@ -5453,7 +5453,7 @@ lock_clust_rec_modify_check_and_lock(
return(DB_SUCCESS);
}
- if (thr && thr_get_trx(thr)->fake_changes) {
+ if (UNIV_UNLIKELY(thr_get_trx(thr)->fake_changes)) {
return(DB_SUCCESS);
}
@@ -5515,7 +5515,7 @@ lock_sec_rec_modify_check_and_lock(
return(DB_SUCCESS);
}
- if (thr && thr_get_trx(thr)->fake_changes) {
+ if (UNIV_UNLIKELY(thr_get_trx(thr)->fake_changes)) {
return(DB_SUCCESS);
}
@@ -5606,7 +5606,7 @@ lock_sec_rec_read_check_and_lock(
return(DB_SUCCESS);
}
- if (UNIV_UNLIKELY((thr && thr_get_trx(thr)->fake_changes))) {
+ if (UNIV_UNLIKELY(thr_get_trx(thr)->fake_changes)) {
if (!srv_fake_changes_locks) {
return(DB_SUCCESS);
}
@@ -5691,7 +5691,7 @@ lock_clust_rec_read_check_and_lock(
return(DB_SUCCESS);
}
- if (UNIV_UNLIKELY((thr && thr_get_trx(thr)->fake_changes))) {
+ if (UNIV_UNLIKELY(thr_get_trx(thr)->fake_changes)) {
if (!srv_fake_changes_locks) {
return(DB_SUCCESS);
}
diff --git a/storage/xtradb/log/log0online.c b/storage/xtradb/log/log0online.c
index 6d7cb928d9c..5dfe08a4b65 100644
--- a/storage/xtradb/log/log0online.c
+++ b/storage/xtradb/log/log0online.c
@@ -34,6 +34,14 @@ Online database log parsing for changed page tracking
#include "trx0sys.h"
#include "ut0rbt.h"
+#ifdef __WIN__
+/* error LNK2001: unresolved external symbol _debug_sync_C_callback_ptr */
+# define DEBUG_SYNC_C(dummy) ((void) 0)
+#else
+# include "m_string.h" /* for my_sys.h */
+# include "my_sys.h" /* DEBUG_SYNC_C */
+#endif
+
enum { FOLLOW_SCAN_SIZE = 4 * (UNIV_PAGE_SIZE_MAX) };
#ifdef UNIV_PFS_MUTEX
@@ -1255,6 +1263,24 @@ log_online_follow_redo_log(void)
}
/*********************************************************************//**
+Diagnose a bitmap file range setup failure and free the partially-initialized
+bitmap file range. */
+static
+void
+log_online_diagnose_inconsistent_dir(
+/*=================================*/
+ log_online_bitmap_file_range_t *bitmap_files) /*!<in/out: bitmap file
+ range */
+{
+ fprintf(stderr,
+ "InnoDB: Warning: inconsistent bitmap file "
+ "directory for a "
+ "INFORMATION_SCHEMA.INNODB_CHANGED_PAGES query"
+ "\n");
+ free(bitmap_files->files);
+}
+
+/*********************************************************************//**
List the bitmap files in srv_data_home and setup their range that contains the
specified LSN interval. This range, if non-empty, will start with a file that
has the greatest LSN equal to or less than the start LSN and will include all
@@ -1355,6 +1381,8 @@ log_online_setup_bitmap_file_range(
bitmap_files->count = last_file_seq_num - first_file_seq_num + 1;
+ DEBUG_SYNC_C("setup_bitmap_range_middle");
+
/* 2nd pass: get the file names in the file_seq_num order */
bitmap_dir = os_file_opendir(srv_data_home, FALSE);
@@ -1390,12 +1418,7 @@ log_online_setup_bitmap_file_range(
array_pos = file_seq_num - first_file_seq_num;
if (UNIV_UNLIKELY(array_pos >= bitmap_files->count)) {
- fprintf(stderr,
- "InnoDB: Error: inconsistent bitmap file "
- "directory for a "
- "INFORMATION_SCHEMA.INNODB_CHANGED_PAGES query"
- "\n");
- free(bitmap_files->files);
+ log_online_diagnose_inconsistent_dir(bitmap_files);
return FALSE;
}
@@ -1422,8 +1445,12 @@ log_online_setup_bitmap_file_range(
}
#ifdef UNIV_DEBUG
+ if (!bitmap_files->files[0].seq_num) {
+
+ log_online_diagnose_inconsistent_dir(bitmap_files);
+ return FALSE;
+ }
ut_ad(bitmap_files->files[0].seq_num == first_file_seq_num);
- ut_ad(bitmap_files->files[0].start_lsn == first_file_start_lsn);
{
size_t i;
for (i = 1; i < bitmap_files->count; i++) {
diff --git a/storage/xtradb/log/log0recv.c b/storage/xtradb/log/log0recv.c
index 9fcf1adddad..61239dfb25d 100644
--- a/storage/xtradb/log/log0recv.c
+++ b/storage/xtradb/log/log0recv.c
@@ -1273,7 +1273,8 @@ recv_parse_or_apply_log_rec_body(
break;
case MLOG_FILE_RENAME:
ptr = fil_op_log_parse_or_replay(ptr, end_ptr, type,
- space_id, 0);
+ (recv_recovery_is_on()
+ ? space_id : 0), 0);
break;
case MLOG_FILE_CREATE:
case MLOG_FILE_DELETE:
diff --git a/storage/xtradb/que/que0que.c b/storage/xtradb/que/que0que.c
index 860fcf5f6f5..a9d76ce4706 100644
--- a/storage/xtradb/que/que0que.c
+++ b/storage/xtradb/que/que0que.c
@@ -1417,7 +1417,7 @@ que_eval_sql(
ut_a(trx->error_state == DB_SUCCESS);
- if (trx->fake_changes) {
+ if (UNIV_UNLIKELY(trx->fake_changes)) {
/* fake_changes should not access to system tables */
fprintf(stderr, "InnoDB: ERROR: innodb_fake_changes tried to access to system tables.\n");
return(DB_ERROR);
diff --git a/storage/xtradb/row/row0ins.c b/storage/xtradb/row/row0ins.c
index 87d484c46eb..0d9db2f6d1f 100644
--- a/storage/xtradb/row/row0ins.c
+++ b/storage/xtradb/row/row0ins.c
@@ -1512,7 +1512,7 @@ exit_func:
mem_heap_free(heap);
}
- if (trx->fake_changes) {
+ if (UNIV_UNLIKELY(trx->fake_changes)) {
err = DB_SUCCESS;
}
@@ -2093,11 +2093,11 @@ row_ins_index_entry_low(
transaction. Let us now reposition the cursor and
continue the insertion. */
- btr_cur_search_to_nth_level(index, 0, entry,
- PAGE_CUR_LE,
- thr_get_trx(thr)->fake_changes ? BTR_SEARCH_LEAF : (mode | BTR_INSERT),
- &cursor, 0,
- __FILE__, __LINE__, &mtr);
+ btr_cur_search_to_nth_level(
+ index, 0, entry, PAGE_CUR_LE,
+ (UNIV_UNLIKELY(thr_get_trx(thr)->fake_changes)
+ ? BTR_SEARCH_LEAF : (mode | BTR_INSERT)),
+ &cursor, 0, __FILE__, __LINE__, &mtr);
}
}
@@ -2122,6 +2122,11 @@ row_ins_index_entry_low(
if (big_rec) {
ut_a(err == DB_SUCCESS);
+ if (UNIV_UNLIKELY(thr_get_trx(thr)->
+ fake_changes)) {
+ goto stored_big_rec;
+ }
+
/* Write out the externally stored
columns while still x-latching
index->lock and block->lock. Allocate
@@ -2215,7 +2220,7 @@ function_exit:
rec_t* rec;
ulint* offsets;
- if (thr_get_trx(thr)->fake_changes) {
+ if (UNIV_UNLIKELY(thr_get_trx(thr)->fake_changes)) {
/* skip store extern */
if (modify) {
dtuple_big_rec_free(big_rec);
diff --git a/storage/xtradb/row/row0merge.c b/storage/xtradb/row/row0merge.c
index 449f4767182..752e941af7f 100644
--- a/storage/xtradb/row/row0merge.c
+++ b/storage/xtradb/row/row0merge.c
@@ -63,6 +63,14 @@ Completed by Sunny Bains and Marko Makela
# define posix_fadvise(fd, offset, len, advice) /* nothing */
#endif /* __WIN__ */
+#ifdef __WIN__
+/* error LNK2001: unresolved external symbol _debug_sync_C_callback_ptr */
+# define DEBUG_SYNC_C(dummy) ((void) 0)
+#else
+# include "m_string.h" /* for my_sys.h */
+# include "my_sys.h" /* DEBUG_SYNC_C */
+#endif
+
#ifdef UNIV_DEBUG
/** Set these in order ot enable debug printout. */
/* @{ */
@@ -2593,8 +2601,15 @@ row_merge_rename_tables(
/* The following calls will also rename the .ibd data files if
the tables are stored in a single-table tablespace */
- if (!dict_table_rename_in_cache(old_table, tmp_name, FALSE)
- || !dict_table_rename_in_cache(new_table, old_name, FALSE)) {
+ if (!dict_table_rename_in_cache(old_table, tmp_name, FALSE)) {
+
+ err = DB_ERROR;
+ goto err_exit;
+ }
+
+ DEBUG_SYNC_C("row_merge_rename_tables_between_renames");
+
+ if (!dict_table_rename_in_cache(new_table, old_name, FALSE)) {
err = DB_ERROR;
goto err_exit;
diff --git a/storage/xtradb/row/row0mysql.c b/storage/xtradb/row/row0mysql.c
index 49ee3d91ed4..7028c51babb 100644
--- a/storage/xtradb/row/row0mysql.c
+++ b/storage/xtradb/row/row0mysql.c
@@ -2665,7 +2665,9 @@ row_discard_tablespace_for_mysql(
/* check adaptive hash entries */
index = dict_table_get_first_index(table);
while (index) {
- ulint ref_count = btr_search_info_get_ref_count(index->search_info, index->id);
+ ulint ref_count =
+ btr_search_info_get_ref_count(
+ index->search_info, index);
if (ref_count) {
fprintf(stderr, "InnoDB: Warning:"
" hash index ref_count (%lu) is not zero"
@@ -3026,7 +3028,9 @@ row_truncate_table_for_mysql(
table->space = space;
index = dict_table_get_first_index(table);
do {
- ulint ref_count = btr_search_info_get_ref_count(index->search_info, index->id);
+ ulint ref_count =
+ btr_search_info_get_ref_count(
+ index->search_info, index);
/* check adaptive hash entries */
if (ref_count) {
fprintf(stderr, "InnoDB: Warning:"
@@ -4094,12 +4098,28 @@ row_rename_table_for_mysql(
} else if (!new_is_tmp) {
/* Rename all constraints. */
char new_table_name[MAX_TABLE_NAME_LEN] = "";
+ char old_table_utf8[MAX_TABLE_NAME_LEN] = "";
uint errors = 0;
+ strncpy(old_table_utf8, old_name, MAX_TABLE_NAME_LEN);
+ innobase_convert_to_system_charset(
+ strchr(old_table_utf8, '/') + 1,
+ strchr(old_name, '/') +1,
+ MAX_TABLE_NAME_LEN, &errors);
+
+ if (errors) {
+ /* Table name could not be converted from charset
+ my_charset_filename to UTF-8. This means that the
+ table name is already in UTF-8 (#mysql#50). */
+ strncpy(old_table_utf8, old_name, MAX_TABLE_NAME_LEN);
+ }
+
info = pars_info_create();
pars_info_add_str_literal(info, "new_table_name", new_name);
pars_info_add_str_literal(info, "old_table_name", old_name);
+ pars_info_add_str_literal(info, "old_table_name_utf8",
+ old_table_utf8);
strncpy(new_table_name, new_name, MAX_TABLE_NAME_LEN);
innobase_convert_to_system_charset(
@@ -4136,6 +4156,8 @@ row_rename_table_for_mysql(
"new_db_name := SUBSTR(:new_table_name, 0,\n"
" new_db_name_len);\n"
"old_t_name_len := LENGTH(:old_table_name);\n"
+ "gen_constr_prefix := CONCAT(:old_table_name_utf8,\n"
+ " '_ibfk_');\n"
"WHILE found = 1 LOOP\n"
" SELECT ID INTO foreign_id\n"
" FROM SYS_FOREIGN\n"
@@ -4152,7 +4174,7 @@ row_rename_table_for_mysql(
" id_len := LENGTH(foreign_id);\n"
" IF (INSTR(foreign_id, '/') > 0) THEN\n"
" IF (INSTR(foreign_id,\n"
- " '_ibfk_') > 0)\n"
+ " gen_constr_prefix) > 0)\n"
" THEN\n"
" offset := INSTR(foreign_id, '_ibfk_') - 1;\n"
" new_foreign_id :=\n"
diff --git a/storage/xtradb/row/row0sel.c b/storage/xtradb/row/row0sel.c
index 6e3ed1387f1..a902854d4ca 100644
--- a/storage/xtradb/row/row0sel.c
+++ b/storage/xtradb/row/row0sel.c
@@ -219,7 +219,8 @@ row_sel_sec_rec_is_for_clust_rec(
len = clust_len;
- if (ifield->prefix_len > 0 && len != UNIV_SQL_NULL) {
+ if (ifield->prefix_len > 0 && len != UNIV_SQL_NULL
+ && sec_len != UNIV_SQL_NULL) {
if (rec_offs_nth_extern(clust_offs, clust_pos)) {
len -= BTR_EXTERN_FIELD_REF_SIZE;
@@ -1226,7 +1227,7 @@ row_sel_try_search_shortcut(
ut_ad(plan->unique_search);
ut_ad(!plan->must_get_clust);
#ifdef UNIV_SYNC_DEBUG
- ut_ad(rw_lock_own(btr_search_get_latch(index->id), RW_LOCK_SHARED));
+ ut_ad(rw_lock_own(btr_search_get_latch(index), RW_LOCK_SHARED));
#endif /* UNIV_SYNC_DEBUG */
row_sel_open_pcur(plan, TRUE, mtr);
@@ -1397,10 +1398,11 @@ table_loop:
&& !plan->must_get_clust
&& !plan->table->big_rows) {
if (!search_latch_locked) {
- rw_lock_s_lock(btr_search_get_latch(index->id));
+ rw_lock_s_lock(btr_search_get_latch(index));
search_latch_locked = TRUE;
- } else if (rw_lock_get_writer(btr_search_get_latch(index->id)) == RW_LOCK_WAIT_EX) {
+ } else if (rw_lock_get_writer(btr_search_get_latch(index))
+ == RW_LOCK_WAIT_EX) {
/* There is an x-latch request waiting: release the
s-latch for a moment; as an s-latch here is often
@@ -1409,8 +1411,8 @@ table_loop:
from acquiring an s-latch for a long time, lowering
performance significantly in multiprocessors. */
- rw_lock_s_unlock(btr_search_get_latch(index->id));
- rw_lock_s_lock(btr_search_get_latch(index->id));
+ rw_lock_s_unlock(btr_search_get_latch(index));
+ rw_lock_s_lock(btr_search_get_latch(index));
}
found_flag = row_sel_try_search_shortcut(node, plan, &mtr);
@@ -1433,7 +1435,7 @@ table_loop:
}
if (search_latch_locked) {
- rw_lock_s_unlock(btr_search_get_latch(index->id));
+ rw_lock_s_unlock(btr_search_get_latch(index));
search_latch_locked = FALSE;
}
@@ -2009,7 +2011,7 @@ lock_wait_or_error:
func_exit:
if (search_latch_locked) {
- rw_lock_s_unlock(btr_search_get_latch(index->id));
+ rw_lock_s_unlock(btr_search_get_latch(index));
}
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
@@ -3361,6 +3363,8 @@ row_sel_try_search_shortcut_for_mysql(
ut_ad(!prebuilt->templ_contains_blob);
#ifndef UNIV_SEARCH_DEBUG
+ ut_ad(trx->has_search_latch);
+
btr_pcur_open_with_no_init(index, search_tuple, PAGE_CUR_GE,
BTR_SEARCH_LEAF, pcur,
RW_S_LATCH,
@@ -3538,8 +3542,6 @@ row_search_for_mysql(
/* if the returned record was locked and we did a semi-consistent
read (fetch the newest committed version), then this is set to
TRUE */
- ulint i;
- ulint should_release;
#ifdef UNIV_SEARCH_DEBUG
ulint cnt = 0;
#endif /* UNIV_SEARCH_DEBUG */
@@ -3556,6 +3558,12 @@ row_search_for_mysql(
ut_ad(index && pcur && search_tuple);
+ ut_ad(!trx->has_search_latch);
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!btr_search_own_any());
+ ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
+#endif /* UNIV_SYNC_DEBUG */
+
if (UNIV_UNLIKELY(prebuilt->table->ibd_file_missing)) {
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: Error:\n"
@@ -3571,24 +3579,15 @@ row_search_for_mysql(
"InnoDB: how you can resolve the problem.\n",
prebuilt->table->name);
-#ifdef UNIV_SYNC_DEBUG
- ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
-#endif /* UNIV_SYNC_DEBUG */
return(DB_ERROR);
}
if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
-#ifdef UNIV_SYNC_DEBUG
- ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
-#endif /* UNIV_SYNC_DEBUG */
return(DB_MISSING_HISTORY);
}
if (dict_index_is_corrupted(index)) {
-#ifdef UNIV_SYNC_DEBUG
- ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
-#endif /* UNIV_SYNC_DEBUG */
return(DB_CORRUPTION);
}
@@ -3639,38 +3638,6 @@ row_search_for_mysql(
fprintf(stderr, "N tables locked %lu\n",
(ulong) trx->mysql_n_tables_locked);
#endif
- /*-------------------------------------------------------------*/
- /* PHASE 0: Release a possible s-latch we are holding on the
- adaptive hash index latch if there is someone waiting behind */
-
- should_release = 0;
- for (i = 0; i < btr_search_index_num; i++) {
- /* we should check all latches (fix Bug#791030) */
- if (UNIV_UNLIKELY(rw_lock_get_writer(btr_search_latch_part[i])
- != RW_LOCK_NOT_LOCKED)) {
- should_release |= ((ulint)1 << i);
- }
- }
-
- if (UNIV_UNLIKELY(should_release)) {
-
- /* There is an x-latch request on the adaptive hash index:
- release the s-latch to reduce starvation and wait for
- BTR_SEA_TIMEOUT rounds before trying to keep it again over
- calls from MySQL */
-
- for (i = 0; i < btr_search_index_num; i++) {
- /* we should release all s-latches (fix Bug#791030) */
- if (trx->has_search_latch & ((ulint)1 << i)) {
- rw_lock_s_unlock(btr_search_latch_part[i]);
- trx->has_search_latch &= (~((ulint)1 << i));
- }
- }
-
- if (!trx->has_search_latch) {
- trx->search_latch_timeout = BTR_SEA_TIMEOUT;
- }
- }
/* Reset the new record lock info if srv_locks_unsafe_for_binlog
is set or session is using a READ COMMITED isolation level. Then
@@ -3820,29 +3787,9 @@ row_search_for_mysql(
hash index semaphore! */
#ifndef UNIV_SEARCH_DEBUG
- if (!(trx->has_search_latch
- & ((ulint)1 << (index->id % btr_search_index_num)))) {
- if (trx->has_search_latch
- < ((ulint)1 << (index->id % btr_search_index_num))) {
- rw_lock_s_lock(btr_search_get_latch(index->id));
- trx->has_search_latch |=
- ((ulint)1 << (index->id % btr_search_index_num));
- } else {
- /* should re-lock to obay latch-order */
- for (i = 0; i < btr_search_index_num; i++) {
- if (trx->has_search_latch & ((ulint)1 << i)) {
- rw_lock_s_unlock(btr_search_latch_part[i]);
- }
- }
- trx->has_search_latch |=
- ((ulint)1 << (index->id % btr_search_index_num));
- for (i = 0; i < btr_search_index_num; i++) {
- if (trx->has_search_latch & ((ulint)1 << i)) {
- rw_lock_s_lock(btr_search_latch_part[i]);
- }
- }
- }
- }
+ ut_ad(!trx->has_search_latch);
+ rw_lock_s_lock(btr_search_get_latch(index));
+ trx->has_search_latch = TRUE;
#endif
switch (row_sel_try_search_shortcut_for_mysql(
&rec, prebuilt, &offsets, &heap,
@@ -3901,7 +3848,7 @@ row_search_for_mysql(
srv_n_rows_read++;
err = DB_SUCCESS;
- goto release_search_latch_if_needed;
+ goto release_search_latch;
case SEL_EXHAUSTED:
shortcut_mismatch:
@@ -3911,19 +3858,10 @@ row_search_for_mysql(
fputs(" record not found 2\n", stderr); */
err = DB_RECORD_NOT_FOUND;
-release_search_latch_if_needed:
- if (trx->search_latch_timeout > 0
- && trx->has_search_latch) {
-
- trx->search_latch_timeout--;
-
- for (i = 0; i < btr_search_index_num; i++) {
- if (trx->has_search_latch & ((ulint)1 << i)) {
- rw_lock_s_unlock(btr_search_latch_part[i]);
- }
- }
- trx->has_search_latch = FALSE;
- }
+release_search_latch:
+ rw_lock_s_unlock(
+ btr_search_get_latch(index));
+ trx->has_search_latch = FALSE;
/* NOTE that we do NOT store the cursor
position */
@@ -3938,22 +3876,19 @@ release_search_latch_if_needed:
mtr_commit(&mtr);
mtr_start(&mtr);
+
+ rw_lock_s_unlock(btr_search_get_latch(index));
+ trx->has_search_latch = FALSE;
}
}
/*-------------------------------------------------------------*/
/* PHASE 3: Open or restore index cursor position */
- if (trx->has_search_latch) {
-
- for (i = 0; i < btr_search_index_num; i++) {
- if (trx->has_search_latch & ((ulint)1 << i)) {
- rw_lock_s_unlock(btr_search_latch_part[i]);
- }
- }
- trx->has_search_latch = FALSE;
- }
-
+ ut_ad(!trx->has_search_latch);
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!btr_search_own_any());
+#endif
ut_ad(prebuilt->sql_stat_start || trx->state == TRX_ACTIVE);
ut_ad(trx->state == TRX_NOT_STARTED
|| trx->state == TRX_ACTIVE);
@@ -5047,7 +4982,9 @@ func_exit:
}
}
+ ut_ad(!trx->has_search_latch);
#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!btr_search_own_any());
ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
#endif /* UNIV_SYNC_DEBUG */
return(err);
diff --git a/storage/xtradb/row/row0uins.c b/storage/xtradb/row/row0uins.c
index 396cc6b3390..57c8c512698 100644
--- a/storage/xtradb/row/row0uins.c
+++ b/storage/xtradb/row/row0uins.c
@@ -340,13 +340,14 @@ row_undo_ins(
/* The database must have crashed after
inserting a clustered index record but before
writing all the externally stored columns of
- that record. Because secondary index entries
- are inserted after the clustered index record,
- we may assume that the secondary index record
- does not exist. However, this situation may
- only occur during the rollback of incomplete
- transactions. */
- ut_a(trx_is_recv(node->trx));
+ that record, or a statement is being rolled
+ back because an error occurred while storing
+ off-page columns.
+
+ Because secondary index entries are inserted
+ after the clustered index record, we may
+ assume that the secondary index record does
+ not exist. */
} else {
log_free_check();
err = row_undo_ins_remove_sec(node->index, entry);
diff --git a/storage/xtradb/row/row0umod.c b/storage/xtradb/row/row0umod.c
index fae67c95c43..69831fee8ac 100644
--- a/storage/xtradb/row/row0umod.c
+++ b/storage/xtradb/row/row0umod.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1997, 2012, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1997, 2013, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -128,11 +128,10 @@ row_undo_mod_clust_low(
}
/***********************************************************//**
-Removes a clustered index record after undo if possible.
+Purges a clustered index record after undo if possible.
This is attempted when the record was inserted by updating a
delete-marked record and there no longer exist transactions
-that would see the delete-marked record. In other words, we
-roll back the insert by purging the record.
+that would see the delete-marked record.
@return DB_SUCCESS, DB_FAIL, or error code: we may run out of file space */
static
ulint
@@ -140,11 +139,12 @@ row_undo_mod_remove_clust_low(
/*==========================*/
undo_node_t* node, /*!< in: row undo node */
que_thr_t* thr, /*!< in: query thread */
- mtr_t* mtr, /*!< in: mtr */
+ mtr_t* mtr, /*!< in/out: mini-transaction */
ulint mode) /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */
{
btr_cur_t* btr_cur;
ulint err;
+ ulint trx_id_offset;
ut_ad(node->rec_type == TRX_UNDO_UPD_DEL_REC);
@@ -159,6 +159,42 @@ row_undo_mod_remove_clust_low(
btr_cur = btr_pcur_get_btr_cur(&node->pcur);
+ trx_id_offset = btr_cur_get_index(btr_cur)->trx_id_offset;
+
+ if (!trx_id_offset) {
+ mem_heap_t* heap = NULL;
+ ulint trx_id_col;
+ ulint* offsets;
+ ulint len;
+
+ trx_id_col = dict_index_get_sys_col_pos(
+ btr_cur_get_index(btr_cur), DATA_TRX_ID);
+ ut_ad(trx_id_col > 0);
+ ut_ad(trx_id_col != ULINT_UNDEFINED);
+
+ offsets = rec_get_offsets(
+ btr_cur_get_rec(btr_cur), btr_cur_get_index(btr_cur),
+ NULL, trx_id_col + 1, &heap);
+
+ trx_id_offset = rec_get_nth_field_offs(
+ offsets, trx_id_col, &len);
+ ut_ad(len == DATA_TRX_ID_LEN);
+ mem_heap_free(heap);
+ }
+
+ if (trx_read_trx_id(btr_cur_get_rec(btr_cur) + trx_id_offset)
+ != node->new_trx_id) {
+ /* The record must have been purged and then replaced
+ with a different one. */
+ return(DB_SUCCESS);
+ }
+
+ /* We are about to remove an old, delete-marked version of the
+ record that may have been delete-marked by a different transaction
+ than the rolling-back one. */
+ ut_ad(rec_get_deleted_flag(btr_cur_get_rec(btr_cur),
+ dict_table_is_comp(node->table)));
+
if (mode == BTR_MODIFY_LEAF) {
err = btr_cur_optimistic_delete(btr_cur, mtr)
? DB_SUCCESS
diff --git a/storage/xtradb/row/row0upd.c b/storage/xtradb/row/row0upd.c
index b3307193111..d1b6d098882 100644
--- a/storage/xtradb/row/row0upd.c
+++ b/storage/xtradb/row/row0upd.c
@@ -1607,7 +1607,8 @@ row_upd_sec_index_entry(
}
search_result = row_search_index_entry(index, entry,
- trx->fake_changes ? BTR_SEARCH_LEAF : mode,
+ UNIV_UNLIKELY(trx->fake_changes)
+ ? BTR_SEARCH_LEAF : mode,
&pcur, &mtr);
btr_cur = btr_pcur_get_btr_cur(&pcur);
@@ -1855,7 +1856,7 @@ row_upd_clust_rec_by_insert(
the previous invocation of this function. Mark the
off-page columns in the entry inherited. */
- if (!(trx->fake_changes)) {
+ if (UNIV_LIKELY(!trx->fake_changes)) {
change_ownership = row_upd_clust_rec_by_insert_inherit(
NULL, NULL, entry, node->update);
ut_a(change_ownership);
@@ -1889,7 +1890,8 @@ err_exit:
delete-marked old record, mark them disowned by the
old record and owned by the new entry. */
- if (rec_offs_any_extern(offsets) && !(trx->fake_changes)) {
+ if (rec_offs_any_extern(offsets)
+ && UNIV_LIKELY(!(trx->fake_changes))) {
change_ownership = row_upd_clust_rec_by_insert_inherit(
rec, offsets, entry, node->update);
@@ -2019,9 +2021,10 @@ row_upd_clust_rec(
the same transaction do not modify the record in the meantime.
Therefore we can assert that the restoration of the cursor succeeds. */
- ut_a(btr_pcur_restore_position(thr_get_trx(thr)->fake_changes
- ? BTR_SEARCH_TREE : BTR_MODIFY_TREE,
- pcur, mtr));
+ ut_a(btr_pcur_restore_position(
+ (UNIV_UNLIKELY(thr_get_trx(thr)->fake_changes)
+ ? BTR_SEARCH_TREE : BTR_MODIFY_TREE),
+ pcur, mtr));
ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur),
dict_table_is_comp(index->table)));
@@ -2032,7 +2035,8 @@ row_upd_clust_rec(
node->cmpl_info, thr, mtr);
/* skip store extern for fake_changes */
- if (err == DB_SUCCESS && big_rec && !(thr_get_trx(thr)->fake_changes)) {
+ if (err == DB_SUCCESS && big_rec
+ && UNIV_LIKELY(!(thr_get_trx(thr)->fake_changes))) {
ulint offsets_[REC_OFFS_NORMAL_SIZE];
rec_t* rec;
rec_offs_init(offsets_);
@@ -2192,8 +2196,10 @@ row_upd_clust_step(
ut_a(pcur->rel_pos == BTR_PCUR_ON);
- success = btr_pcur_restore_position(thr_get_trx(thr)->fake_changes ? BTR_SEARCH_LEAF : BTR_MODIFY_LEAF,
- pcur, mtr);
+ success = btr_pcur_restore_position(
+ (UNIV_UNLIKELY(thr_get_trx(thr)->fake_changes)
+ ? BTR_SEARCH_LEAF : BTR_MODIFY_LEAF),
+ pcur, mtr);
if (!success) {
err = DB_RECORD_NOT_FOUND;
diff --git a/storage/xtradb/srv/srv0srv.c b/storage/xtradb/srv/srv0srv.c
index 88abb213dd4..478fc0505bc 100644
--- a/storage/xtradb/srv/srv0srv.c
+++ b/storage/xtradb/srv/srv0srv.c
@@ -1281,8 +1281,10 @@ retry:
os_thread_yield();
goto retry;
}
- if (trx->has_search_latch
- || NULL != UT_LIST_GET_FIRST(trx->trx_locks)) {
+
+ ut_ad(!trx->has_search_latch);
+
+ if (NULL != UT_LIST_GET_FIRST(trx->trx_locks)) {
conc_n_threads = os_atomic_increment_lint(&srv_conc_n_threads, 1);
enter_innodb_with_tickets(trx);
@@ -1325,7 +1327,9 @@ srv_conc_enter_innodb(
ulint sec;
ulint ms;
+ ut_ad(!trx->has_search_latch);
#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!btr_search_own_any());
ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
#endif /* UNIV_SYNC_DEBUG */
@@ -1385,7 +1389,9 @@ retry:
/* If the transaction is not holding resources, let it sleep
for SRV_THREAD_SLEEP_DELAY microseconds, and try again then */
- if (!has_slept && !trx->has_search_latch
+ ut_ad(!trx->has_search_latch);
+
+ if (!has_slept
&& NULL == UT_LIST_GET_FIRST(trx->trx_locks)) {
has_slept = TRUE; /* We let it sleep only once to avoid
@@ -1440,10 +1446,8 @@ retry:
return;
}
- /* Release possible search system latch this thread has */
- if (trx->has_search_latch) {
- trx_search_latch_release_if_reserved(trx);
- }
+ /* No-op for XtraDB. */
+ trx_search_latch_release_if_reserved(trx);
/* Add to the queue */
slot->reserved = TRUE;
@@ -1462,6 +1466,7 @@ retry:
ut_ad(!trx->has_search_latch);
#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!btr_search_own_any());
ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
#endif /* UNIV_SYNC_DEBUG */
@@ -1513,7 +1518,9 @@ srv_conc_force_enter_innodb(
trx_t* trx) /*!< in: transaction object associated with the
thread */
{
+ ut_ad(!trx->has_search_latch);
#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!btr_search_own_any());
ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
#endif /* UNIV_SYNC_DEBUG */
@@ -1604,7 +1611,9 @@ srv_conc_force_exit_innodb(
os_event_set(slot->event);
}
+ ut_ad(!trx->has_search_latch);
#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!btr_search_own_any());
ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
#endif /* UNIV_SYNC_DEBUG */
}
@@ -1618,7 +1627,9 @@ srv_conc_exit_innodb(
trx_t* trx) /*!< in: transaction object associated with the
thread */
{
+ ut_ad(!trx->has_search_latch);
#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!btr_search_own_any());
ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
#endif /* UNIV_SYNC_DEBUG */
@@ -1891,7 +1902,9 @@ srv_suspend_mysql_thread(
os_event_wait(event);
thd_wait_end(trx->mysql_thd);
+ ut_ad(!trx->has_search_latch);
#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!btr_search_own_any());
ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
#endif /* UNIV_SYNC_DEBUG */
@@ -2053,7 +2066,8 @@ srv_printf_innodb_monitor(
ulint n_reserved;
ibool ret;
- ulint btr_search_sys_subtotal;
+ ulong btr_search_sys_constant;
+ ulong btr_search_sys_variable;
ulint lock_sys_subtotal;
ulint recv_sys_subtotal;
@@ -2119,7 +2133,7 @@ srv_printf_innodb_monitor(
ibuf_print(file);
for (i = 0; i < btr_search_index_num; i++) {
- ha_print_info(file, btr_search_get_hash_index((index_id_t)i));
+ ha_print_info(file, btr_search_sys->hash_tables[i]);
}
fprintf(file,
@@ -2147,16 +2161,28 @@ srv_printf_innodb_monitor(
fprintf(file,
"Total memory allocated by read views " ULINTPF "\n",
srv_read_views_memory);
- /* Calcurate reserved memories */
- if (btr_search_sys && btr_search_sys->hash_index[0]->heap) {
- btr_search_sys_subtotal = mem_heap_get_size(btr_search_sys->hash_index[0]->heap);
- } else {
- btr_search_sys_subtotal = 0;
- for (i=0; i < btr_search_sys->hash_index[0]->n_mutexes; i++) {
- btr_search_sys_subtotal += mem_heap_get_size(btr_search_sys->hash_index[0]->heaps[i]);
- }
+
+ /* Calculate AHI constant and variable memory allocations */
+
+ btr_search_sys_constant = 0;
+ btr_search_sys_variable = 0;
+
+ ut_ad(btr_search_sys->hash_tables);
+
+ for (i = 0; i < btr_search_index_num; i++) {
+ hash_table_t* ht = btr_search_sys->hash_tables[i];
+
+ ut_ad(ht);
+ ut_ad(ht->heap);
+
+ /* Multiple mutexes/heaps are currently never used for adaptive
+ hash index tables. */
+ ut_ad(!ht->n_mutexes);
+ ut_ad(!ht->heaps);
+
+ btr_search_sys_variable += mem_heap_get_size(ht->heap);
+ btr_search_sys_constant += ht->n_cells * sizeof(hash_cell_t);
}
- btr_search_sys_subtotal *= btr_search_index_num;
lock_sys_subtotal = 0;
if (trx_sys) {
@@ -2181,12 +2207,9 @@ srv_printf_innodb_monitor(
" Lock system %lu \t(%lu + %lu)\n"
" Recovery system %lu \t(%lu + %lu)\n",
- (ulong) (btr_search_sys
- ? (btr_search_sys->hash_index[0]->n_cells * btr_search_index_num * sizeof(hash_cell_t)) : 0)
- + btr_search_sys_subtotal,
- (ulong) (btr_search_sys
- ? (btr_search_sys->hash_index[0]->n_cells * btr_search_index_num * sizeof(hash_cell_t)) : 0),
- (ulong) btr_search_sys_subtotal,
+ btr_search_sys_constant + btr_search_sys_variable,
+ btr_search_sys_constant,
+ btr_search_sys_variable,
(ulong) (buf_pool_from_array(0)->page_hash->n_cells * sizeof(hash_cell_t)),
@@ -2348,17 +2371,22 @@ srv_export_innodb_status(void)
buf_get_total_list_len(&LRU_len, &free_len, &flush_list_len);
buf_get_total_list_size_in_bytes(&buf_pools_list_size);
- if (btr_search_sys && btr_search_sys->hash_index[0]->heap) {
- mem_adaptive_hash = mem_heap_get_size(btr_search_sys->hash_index[0]->heap);
- } else {
- mem_adaptive_hash = 0;
- for (i=0; i < btr_search_sys->hash_index[0]->n_mutexes; i++) {
- mem_adaptive_hash += mem_heap_get_size(btr_search_sys->hash_index[0]->heaps[i]);
- }
- }
- mem_adaptive_hash *= btr_search_index_num;
- if (btr_search_sys) {
- mem_adaptive_hash += (btr_search_sys->hash_index[0]->n_cells * btr_search_index_num * sizeof(hash_cell_t));
+ mem_adaptive_hash = 0;
+
+ ut_ad(btr_search_sys->hash_tables);
+
+ for (i = 0; i < btr_search_index_num; i++) {
+ hash_table_t* ht = btr_search_sys->hash_tables[i];
+
+ ut_ad(ht);
+ ut_ad(ht->heap);
+ /* Multiple mutexes/heaps are currently never used for adaptive
+ hash index tables. */
+ ut_ad(!ht->n_mutexes);
+ ut_ad(!ht->heaps);
+
+ mem_adaptive_hash += mem_heap_get_size(ht->heap);
+ mem_adaptive_hash += ht->n_cells * sizeof(hash_cell_t);
}
mem_dictionary = (dict_sys ? ((dict_sys->table_hash->n_cells
@@ -2371,7 +2399,7 @@ srv_export_innodb_status(void)
export_vars.innodb_adaptive_hash_cells = 0;
export_vars.innodb_adaptive_hash_heap_buffers = 0;
for (i = 0; i < btr_search_index_num; i++) {
- hash_table_t* table = btr_search_get_hash_index((index_id_t)i);
+ hash_table_t* table = btr_search_sys->hash_tables[i];
export_vars.innodb_adaptive_hash_cells
+= hash_get_n_cells(table);
@@ -3162,6 +3190,12 @@ srv_redo_log_follow_thread(
os_event_wait(srv_checkpoint_completed_event);
os_event_reset(srv_checkpoint_completed_event);
+#ifdef UNIV_DEBUG
+ if (!srv_track_changed_pages) {
+ continue;
+ }
+#endif
+
if (srv_shutdown_state < SRV_SHUTDOWN_LAST_PHASE) {
if (!log_online_follow_redo_log()) {
/* TODO: sync with I_S log tracking status? */
diff --git a/storage/xtradb/trx/trx0trx.c b/storage/xtradb/trx/trx0trx.c
index e316c4005e7..464ce6f3568 100644
--- a/storage/xtradb/trx/trx0trx.c
+++ b/storage/xtradb/trx/trx0trx.c
@@ -385,27 +385,6 @@ trx_allocate_for_background(void)
}
/********************************************************************//**
-Releases the search latch if trx has reserved it. */
-UNIV_INTERN
-void
-trx_search_latch_release_if_reserved(
-/*=================================*/
- trx_t* trx) /*!< in: transaction */
-{
- ulint i;
-
- if (trx->has_search_latch) {
- for (i = 0; i < btr_search_index_num; i++) {
- if (trx->has_search_latch & ((ulint)1 << i)) {
- rw_lock_s_unlock(btr_search_latch_part[i]);
- }
- }
-
- trx->has_search_latch = FALSE;
- }
-}
-
-/********************************************************************//**
Frees a transaction object. */
UNIV_INTERN
void
@@ -467,6 +446,9 @@ trx_free(
ut_a(UT_LIST_GET_LEN(trx->wait_thrs) == 0);
ut_a(!trx->has_search_latch);
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!btr_search_own_any());
+#endif
ut_a(trx->dict_operation_lock_mode == 0);
@@ -526,6 +508,9 @@ trx_free_prepared(
ut_a(UT_LIST_GET_LEN(trx->wait_thrs) == 0);
ut_a(!trx->has_search_latch);
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!btr_search_own_any());
+#endif
ut_a(trx->dict_operation_lock_mode == 0);