1
/*****************************************************************************
3
Copyright (C) 1994, 2009, Innobase Oy. All Rights Reserved.
5
This program is free software; you can redistribute it and/or modify it under
6
the terms of the GNU General Public License as published by the Free Software
7
Foundation; version 2 of the License.
9
This program is distributed in the hope that it will be useful, but WITHOUT
10
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
You should have received a copy of the GNU General Public License along with
14
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15
St, Fifth Floor, Boston, MA 02110-1301 USA
17
*****************************************************************************/
19
/********************************************************************//**
21
The hash table with external chains
23
Created 8/22/1994 Heikki Tuuri
24
*************************************************************************/
33
#endif /* UNIV_DEBUG */
35
#include "page0page.h"
37
/*************************************************************//**
38
Creates a hash table with at least n array cells. The actual number
39
of cells is chosen to be a prime number slightly bigger than n.
40
@return own: created table */
45
ulint n, /*!< in: number of array cells */
46
#ifdef UNIV_SYNC_DEBUG
47
ulint mutex_level, /*!< in: level of the mutexes in the latching
48
order: this is used in the debug version */
49
#endif /* UNIV_SYNC_DEBUG */
50
ulint n_mutexes) /*!< in: number of mutexes to protect the
51
hash table: must be a power of 2, or 0 */
54
#ifndef UNIV_HOTBACKUP
56
#endif /* !UNIV_HOTBACKUP */
58
ut_ad(ut_is_2pow(n_mutexes));
59
table = hash_create(n);
61
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
62
# ifndef UNIV_HOTBACKUP
63
table->adaptive = TRUE;
64
# endif /* !UNIV_HOTBACKUP */
65
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
66
/* Creating MEM_HEAP_BTR_SEARCH type heaps can potentially fail,
67
but in practise it never should in this case, hence the asserts. */
70
table->heap = mem_heap_create_in_btr_search(
71
ut_min(4096, MEM_MAX_ALLOC_IN_BUF));
77
#ifndef UNIV_HOTBACKUP
78
hash_create_mutexes(table, n_mutexes, mutex_level);
80
table->heaps = static_cast<mem_block_info_t **>(mem_alloc(n_mutexes * sizeof(mem_block_info_t *)));
82
for (i = 0; i < n_mutexes; i++) {
83
table->heaps[i] = mem_heap_create_in_btr_search(4096);
84
ut_a(table->heaps[i]);
86
#endif /* !UNIV_HOTBACKUP */
91
/*************************************************************//**
92
Empties a hash table and frees the memory heaps. */
97
hash_table_t* table) /*!< in, own: hash table */
103
ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
104
#ifdef UNIV_SYNC_DEBUG
105
ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EXCLUSIVE));
106
#endif /* UNIV_SYNC_DEBUG */
108
#ifndef UNIV_HOTBACKUP
109
/* Free the memory heaps. */
110
n = table->n_mutexes;
112
for (i = 0; i < n; i++) {
113
mem_heap_free(table->heaps[i]);
115
#endif /* !UNIV_HOTBACKUP */
117
/* Clear the hash table. */
118
n = hash_get_n_cells(table);
120
for (i = 0; i < n; i++) {
121
hash_get_nth_cell(table, i)->node = NULL;
125
/*************************************************************//**
126
Inserts an entry into a hash table. If an entry with the same fold number
127
is found, its node is updated to point to the new data, and no new node
128
is inserted. If btr_search_enabled is set to FALSE, we will only allow
129
updating existing nodes, but no new node is allowed to be added.
130
@return TRUE if succeed, FALSE if no more memory could be allocated */
133
ha_insert_for_fold_func(
134
/*====================*/
135
hash_table_t* table, /*!< in: hash table */
136
ulint fold, /*!< in: folded value of data; if a node with
137
the same fold value already exists, it is
138
updated to point to the same data, and no new
140
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
141
buf_block_t* block, /*!< in: buffer block containing the data */
142
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
143
void* data) /*!< in: data, must not be NULL */
147
ha_node_t* prev_node;
152
ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
153
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
154
ut_a(block->frame == page_align(data));
155
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
156
ASSERT_HASH_MUTEX_OWN(table, fold);
158
hash = hash_calc_hash(fold, table);
160
cell = hash_get_nth_cell(table, hash);
162
prev_node = static_cast<ha_node_t *>(cell->node);
164
while (prev_node != NULL) {
165
if (prev_node->fold == fold) {
166
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
167
# ifndef UNIV_HOTBACKUP
168
if (table->adaptive) {
169
buf_block_t* prev_block = prev_node->block;
170
ut_a(prev_block->frame
171
== page_align(prev_node->data));
172
ut_a(prev_block->n_pointers > 0);
173
prev_block->n_pointers--;
176
ut_ad(!btr_search_fully_disabled);
177
# endif /* !UNIV_HOTBACKUP */
179
prev_node->block = block;
180
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
181
prev_node->data = data;
186
prev_node = prev_node->next;
189
/* We are in the process of disabling hash index, do not add
191
if (!btr_search_enabled) {
192
ut_ad(!btr_search_fully_disabled);
196
/* We have to allocate a new chain node */
198
node = static_cast<ha_node_t *>(mem_heap_alloc(hash_get_heap(table, fold), sizeof(ha_node_t)));
201
/* It was a btr search type memory heap and at the moment
202
no more memory could be allocated: return */
204
ut_ad(hash_get_heap(table, fold)->type & MEM_HEAP_BTR_SEARCH);
209
ha_node_set_data(node, block, data);
211
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
212
# ifndef UNIV_HOTBACKUP
213
if (table->adaptive) {
216
# endif /* !UNIV_HOTBACKUP */
217
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
223
prev_node = static_cast<ha_node_t *>(cell->node);
225
if (prev_node == NULL) {
232
while (prev_node->next != NULL) {
234
prev_node = prev_node->next;
237
prev_node->next = node;
242
/***********************************************************//**
243
Deletes a hash node. */
248
hash_table_t* table, /*!< in: hash table */
249
ha_node_t* del_node) /*!< in: node to be deleted */
252
ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
253
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
254
# ifndef UNIV_HOTBACKUP
255
if (table->adaptive) {
256
ut_a(del_node->block->frame = page_align(del_node->data));
257
ut_a(del_node->block->n_pointers > 0);
258
del_node->block->n_pointers--;
260
# endif /* !UNIV_HOTBACKUP */
261
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
263
HASH_DELETE_AND_COMPACT(ha_node_t, next, table, del_node);
266
/*********************************************************//**
267
Looks for an element when we know the pointer to the data, and updates
268
the pointer to data, if found. */
271
ha_search_and_update_if_found_func(
272
/*===============================*/
273
hash_table_t* table, /*!< in/out: hash table */
274
ulint fold, /*!< in: folded value of the searched data */
275
void* data, /*!< in: pointer to the data */
276
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
277
buf_block_t* new_block,/*!< in: block containing new_data */
278
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
279
void* new_data)/*!< in: new pointer to the data */
284
ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
285
ASSERT_HASH_MUTEX_OWN(table, fold);
286
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
287
ut_a(new_block->frame == page_align(new_data));
288
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
290
node = ha_search_with_data(table, fold, data);
293
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
294
# ifndef UNIV_HOTBACKUP
295
if (table->adaptive) {
296
ut_a(node->block->n_pointers > 0);
297
node->block->n_pointers--;
298
new_block->n_pointers++;
300
# endif /* !UNIV_HOTBACKUP */
302
node->block = new_block;
303
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
304
node->data = new_data;
308
#ifndef UNIV_HOTBACKUP
309
/*****************************************************************//**
310
Removes from the chain determined by fold all nodes whose data pointer
311
points to the page given. */
314
ha_remove_all_nodes_to_page(
315
/*========================*/
316
hash_table_t* table, /*!< in: hash table */
317
ulint fold, /*!< in: fold value */
318
const page_t* page) /*!< in: buffer page */
323
ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
324
ASSERT_HASH_MUTEX_OWN(table, fold);
326
node = ha_chain_get_first(table, fold);
329
if (page_align(ha_node_get_data(node)) == page) {
331
/* Remove the hash node */
333
ha_delete_hash_node(table, node);
335
/* Start again from the first node in the chain
336
because the deletion may compact the heap of
337
nodes and move other nodes! */
339
node = ha_chain_get_first(table, fold);
341
node = ha_chain_get_next(node);
345
/* Check that all nodes really got deleted */
347
node = ha_chain_get_first(table, fold);
350
ut_a(page_align(ha_node_get_data(node)) != page);
352
node = ha_chain_get_next(node);
357
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
358
/*************************************************************//**
359
Validates a given range of the cells in hash table.
360
@return TRUE if ok */
365
hash_table_t* table, /*!< in: hash table */
366
ulint start_index, /*!< in: start index */
367
ulint end_index) /*!< in: end index */
375
ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
376
ut_a(start_index <= end_index);
377
ut_a(start_index < hash_get_n_cells(table));
378
ut_a(end_index < hash_get_n_cells(table));
380
for (i = start_index; i <= end_index; i++) {
382
cell = hash_get_nth_cell(table, i);
387
if (hash_calc_hash(node->fold, table) != i) {
388
ut_print_timestamp(stderr);
390
"InnoDB: Error: hash table node"
391
" fold value %lu does not\n"
392
"InnoDB: match the cell number %lu.\n",
393
(ulong) node->fold, (ulong) i);
404
#endif /* defined UNIV_AHI_DEBUG || defined UNIV_DEBUG */
406
/*************************************************************//**
407
Prints info of a hash table. */
412
FILE* file, /*!< in: file where to print */
413
hash_table_t* table) /*!< in: hash table */
416
ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
418
/* Some of the code here is disabled for performance reasons in production
419
builds, see http://bugs.mysql.com/36941 */
420
#define PRINT_USED_CELLS
421
#endif /* UNIV_DEBUG */
423
#ifdef PRINT_USED_CELLS
427
#endif /* PRINT_USED_CELLS */
430
#ifdef PRINT_USED_CELLS
431
for (i = 0; i < hash_get_n_cells(table); i++) {
433
cell = hash_get_nth_cell(table, i);
440
#endif /* PRINT_USED_CELLS */
442
fprintf(file, "Hash table size %lu",
443
(ulong) hash_get_n_cells(table));
445
#ifdef PRINT_USED_CELLS
446
fprintf(file, ", used cells %lu", (ulong) cells);
447
#endif /* PRINT_USED_CELLS */
449
if (table->heaps == NULL && table->heap != NULL) {
451
/* This calculation is intended for the adaptive hash
452
index: how many buffer frames we have reserved? */
454
n_bufs = UT_LIST_GET_LEN(table->heap->base) - 1;
456
if (table->heap->free_block) {
460
fprintf(file, ", node heap has %lu buffer(s)\n",
464
#endif /* !UNIV_HOTBACKUP */