/*************************************************************//** Empties a hash table and frees the memory heaps. */ UNIV_INTERN void ha_clear( /*=====*/ hash_table_t* table) /*!< in, own: hash table */ { ulint i; ulint n; ut_ad(table); ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); #ifdef UNIV_SYNC_DEBUG ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EXCLUSIVE)); #endif /* UNIV_SYNC_DEBUG */ #ifndef UNIV_HOTBACKUP /* Free the memory heaps. */ n = table->n_mutexes; for (i = 0; i < n; i++) { mem_heap_free(table->heaps[i]); } #endif /* !UNIV_HOTBACKUP */ /* Clear the hash table. */ n = hash_get_n_cells(table); for (i = 0; i < n; i++) { hash_get_nth_cell(table, i)->node = NULL; } }
/*************************************************************//** Prints info of a hash table. */ UNIV_INTERN void ha_print_info( /*==========*/ FILE* file, /*!< in: file where to print */ hash_table_t* table) /*!< in: hash table */ { #ifdef UNIV_DEBUG /* Some of the code here is disabled for performance reasons in production builds, see http://bugs.mysql.com/36941 */ #define PRINT_USED_CELLS #endif /* UNIV_DEBUG */ #ifdef PRINT_USED_CELLS hash_cell_t* cell; ulint cells = 0; ulint i; #endif /* PRINT_USED_CELLS */ ulint n_bufs; ut_ad(table); ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); #ifdef PRINT_USED_CELLS for (i = 0; i < hash_get_n_cells(table); i++) { cell = hash_get_nth_cell(table, i); if (cell->node) { cells++; } } #endif /* PRINT_USED_CELLS */ fprintf(file, "Hash table size %lu", (ulong) hash_get_n_cells(table)); #ifdef PRINT_USED_CELLS fprintf(file, ", used cells %lu", (ulong) cells); #endif /* PRINT_USED_CELLS */ if (table->heaps == NULL && table->heap != NULL) { /* This calculation is intended for the adaptive hash index: how many buffer frames we have reserved? */ n_bufs = UT_LIST_GET_LEN(table->heap->base) - 1; if (table->heap->free_block) { n_bufs++; } fprintf(file, ", node heap has %lu buffer(s)\n", (ulong) n_bufs); } }
/*************************************************************//** Validates a given range of the cells in hash table. @return TRUE if ok */ UNIV_INTERN ibool ha_validate( /*========*/ hash_table_t* table, /*!< in: hash table */ ulint start_index, /*!< in: start index */ ulint end_index) /*!< in: end index */ { hash_cell_t* cell; ha_node_t* node; ibool ok = TRUE; ulint i; ut_ad(table); ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); ut_a(start_index <= end_index); ut_a(start_index < hash_get_n_cells(table)); ut_a(end_index < hash_get_n_cells(table)); for (i = start_index; i <= end_index; i++) { cell = hash_get_nth_cell(table, i); node = cell->node; while (node) { if (hash_calc_hash(node->fold, table) != i) { ut_print_timestamp(stderr); fprintf(stderr, "InnoDB: Error: hash table node" " fold value %lu does not\n" "InnoDB: match the cell number %lu.\n", (ulong) node->fold, (ulong) i); ok = FALSE; } node = node->next; } } return(ok); }
hash_table_t* hash_create( /*========*/ /* out, own: created table */ ulint n) /* in: number of array cells */ { hash_cell_t* array; ulint prime; hash_table_t* table; ulint i; hash_cell_t* cell; prime = ut_find_prime(n); table = mem_alloc(sizeof(hash_table_t)); array = ut_malloc(sizeof(hash_cell_t) * prime); table->array = array; table->n_cells = prime; table->n_mutexes = 0; table->mutexes = NULL; table->heaps = NULL; table->heap = NULL; table->magic_n = HASH_TABLE_MAGIC_N; /* Initialize the cell array */ for (i = 0; i < prime; i++) { cell = hash_get_nth_cell(table, i); cell->node = NULL; } return(table); }
/*************************************************************//** Inserts an entry into a hash table. If an entry with the same fold number is found, its node is updated to point to the new data, and no new node is inserted. If btr_search_enabled is set to FALSE, we will only allow updating existing nodes, but no new node is allowed to be added. @return TRUE if succeed, FALSE if no more memory could be allocated */ UNIV_INTERN ibool ha_insert_for_fold_func( /*====================*/ hash_table_t* table, /*!< in: hash table */ ulint fold, /*!< in: folded value of data; if a node with the same fold value already exists, it is updated to point to the same data, and no new node is created! */ #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG buf_block_t* block, /*!< in: buffer block containing the data */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ const rec_t* data) /*!< in: data, must not be NULL */ { hash_cell_t* cell; ha_node_t* node; ha_node_t* prev_node; ulint hash; ut_ad(data); ut_ad(table); ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG ut_a(block->frame == page_align(data)); #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ #ifdef UNIV_SYNC_DEBUG ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ ASSERT_HASH_MUTEX_OWN(table, fold); ut_ad(btr_search_enabled); hash = hash_calc_hash(fold, table); cell = hash_get_nth_cell(table, hash); prev_node = cell->node; while (prev_node != NULL) { if (prev_node->fold == fold) { #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG # ifndef UNIV_HOTBACKUP if (table->adaptive) { buf_block_t* prev_block = prev_node->block; ut_a(prev_block->frame == page_align(prev_node->data)); ut_a(prev_block->n_pointers > 0); prev_block->n_pointers--; block->n_pointers++; } # endif /* !UNIV_HOTBACKUP */ prev_node->block = block; #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ prev_node->data = data; return(TRUE); } prev_node = prev_node->next; } /* We have to allocate a new chain node */ node = mem_heap_alloc(hash_get_heap(table, fold), sizeof(ha_node_t)); if (node == NULL) { /* It was a btr search type memory heap and at the moment no more memory could be allocated: return */ ut_ad(hash_get_heap(table, fold)->type & MEM_HEAP_BTR_SEARCH); return(FALSE); } ha_node_set_data(node, block, data); #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG # ifndef UNIV_HOTBACKUP if (table->adaptive) { block->n_pointers++; } # endif /* !UNIV_HOTBACKUP */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ node->fold = fold; node->next = NULL; prev_node = cell->node; if (prev_node == NULL) { cell->node = node; return(TRUE); } while (prev_node->next != NULL) { prev_node = prev_node->next; } prev_node->next = node; return(TRUE); }