diff options
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); |