diff options
Diffstat (limited to 'storage/xtradb/btr/btr0sea.c')
-rw-r--r-- | storage/xtradb/btr/btr0sea.c | 165 |
1 files changed, 106 insertions, 59 deletions
diff --git a/storage/xtradb/btr/btr0sea.c b/storage/xtradb/btr/btr0sea.c index c78f791480c..3b38e2799c2 100644 --- a/storage/xtradb/btr/btr0sea.c +++ b/storage/xtradb/btr/btr0sea.c @@ -141,7 +141,7 @@ btr_search_check_free_space_in_heap(void) be enough free space in the hash table. */ if (heap->free_block == NULL) { - buf_block_t* block = buf_block_alloc(0); + buf_block_t* block = buf_block_alloc(); rw_lock_x_lock(&btr_search_latch); @@ -1186,7 +1186,7 @@ btr_search_drop_page_hash_index_on_index( /*=====================================*/ dict_index_t* index) /* in: record descriptor */ { - buf_page_t* bpage; + hash_table_t* table; buf_block_t* block; ulint n_fields; @@ -1202,96 +1202,143 @@ btr_search_drop_page_hash_index_on_index( ulint i; mem_heap_t* heap = NULL; ulint* offsets; + ibool released_search_latch; - rw_lock_x_lock(&btr_search_latch); - mutex_enter(&LRU_list_mutex); + rw_lock_s_lock(&btr_search_latch); table = btr_search_sys->hash_index; - bpage = UT_LIST_GET_LAST(buf_pool->LRU); + do { + buf_chunk_t* chunks = buf_pool->chunks; + buf_chunk_t* chunk = chunks + buf_pool->n_chunks; + + released_search_latch = FALSE; + + while (--chunk >= chunks) { + block = chunk->blocks; + i = chunk->size; + +retry: + for (; i--; block++) { + if (buf_block_get_state(block) + != BUF_BLOCK_FILE_PAGE + || block->index != index + || !block->is_hashed) { + continue; + } + + page = block->frame; + + /* from btr_search_drop_page_hash_index() */ + n_fields = block->curr_n_fields; + n_bytes = block->curr_n_bytes; + - while (bpage != NULL) { - block = (buf_block_t*) bpage; - if (block->index == index && block->is_hashed) { - page = block->frame; + /* keeping latch order */ + rw_lock_s_unlock(&btr_search_latch); + released_search_latch = TRUE; + rw_lock_x_lock(&block->lock); - /* from btr_search_drop_page_hash_index() */ - n_fields = block->curr_n_fields; - n_bytes = block->curr_n_bytes; - ut_a(n_fields + n_bytes > 0); + ut_a(n_fields + n_bytes > 0); - n_recs = page_get_n_recs(page); + n_recs = page_get_n_recs(page); - /* Calculate and cache fold values into an array for fast deletion - from the hash index */ + /* Calculate and cache fold values into an array for fast deletion + from the hash index */ - folds = mem_alloc(n_recs * sizeof(ulint)); + folds = mem_alloc(n_recs * sizeof(ulint)); - n_cached = 0; + n_cached = 0; - rec = page_get_infimum_rec(page); - rec = page_rec_get_next_low(rec, page_is_comp(page)); + rec = page_get_infimum_rec(page); + rec = page_rec_get_next_low(rec, page_is_comp(page)); - index_id = btr_page_get_index_id(page); + index_id = btr_page_get_index_id(page); - ut_a(0 == ut_dulint_cmp(index_id, index->id)); + ut_a(0 == ut_dulint_cmp(index_id, index->id)); - prev_fold = 0; + prev_fold = 0; - offsets = NULL; + offsets = NULL; - while (!page_rec_is_supremum(rec)) { - offsets = rec_get_offsets(rec, index, offsets, - n_fields + (n_bytes > 0), &heap); - ut_a(rec_offs_n_fields(offsets) == n_fields + (n_bytes > 0)); - fold = rec_fold(rec, offsets, n_fields, n_bytes, index_id); + while (!page_rec_is_supremum(rec)) { + offsets = rec_get_offsets(rec, index, offsets, + n_fields + (n_bytes > 0), &heap); + ut_a(rec_offs_n_fields(offsets) == n_fields + (n_bytes > 0)); + fold = rec_fold(rec, offsets, n_fields, n_bytes, index_id); - if (fold == prev_fold && prev_fold != 0) { + if (fold == prev_fold && prev_fold != 0) { - goto next_rec; - } + goto next_rec; + } - /* Remove all hash nodes pointing to this page from the - hash chain */ + /* Remove all hash nodes pointing to this page from the + hash chain */ - folds[n_cached] = fold; - n_cached++; + folds[n_cached] = fold; + n_cached++; next_rec: - rec = page_rec_get_next_low(rec, page_rec_is_comp(rec)); - prev_fold = fold; - } + rec = page_rec_get_next_low(rec, page_rec_is_comp(rec)); + prev_fold = fold; + } - for (i = 0; i < n_cached; i++) { + if (UNIV_LIKELY_NULL(heap)) { + mem_heap_empty(heap); + } - ha_remove_all_nodes_to_page(table, folds[i], page); - } + rw_lock_x_lock(&btr_search_latch); - ut_a(index->search_info->ref_count > 0); - index->search_info->ref_count--; + if (UNIV_UNLIKELY(!block->is_hashed)) { + goto cleanup; + } - block->is_hashed = FALSE; - block->index = NULL; - + ut_a(block->index == index); + + if (UNIV_UNLIKELY(block->curr_n_fields != n_fields) + || UNIV_UNLIKELY(block->curr_n_bytes != n_bytes)) { + rw_lock_x_unlock(&btr_search_latch); + rw_lock_x_unlock(&block->lock); + + mem_free(folds); + + rw_lock_s_lock(&btr_search_latch); + goto retry; + } + + for (i = 0; i < n_cached; i++) { + + ha_remove_all_nodes_to_page(table, folds[i], page); + } + + ut_a(index->search_info->ref_count > 0); + index->search_info->ref_count--; + + block->is_hashed = FALSE; + block->index = NULL; + +cleanup: #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG - if (UNIV_UNLIKELY(block->n_pointers)) { - /* Corruption */ - ut_print_timestamp(stderr); - fprintf(stderr, + if (UNIV_UNLIKELY(block->n_pointers)) { + /* Corruption */ + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB: Corruption of adaptive hash index. After dropping\n" "InnoDB: the hash index to a page of %s, still %lu hash nodes remain.\n", - index->name, (ulong) block->n_pointers); - } + index->name, (ulong) block->n_pointers); + } #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ + rw_lock_x_unlock(&btr_search_latch); + rw_lock_x_unlock(&block->lock); - mem_free(folds); - } + mem_free(folds); - bpage = UT_LIST_GET_PREV(LRU, bpage); - } + rw_lock_s_lock(&btr_search_latch); + } + } + } while (released_search_latch); - mutex_exit(&LRU_list_mutex); - rw_lock_x_unlock(&btr_search_latch); + rw_lock_s_unlock(&btr_search_latch); if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); |