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., 59 Temple
15
Place, Suite 330, Boston, MA 02111-1307 USA
17
*****************************************************************************/
19
/************************************************************************
20
The hash table with external chains
22
Created 8/22/1994 Heikki Tuuri
23
*************************************************************************/
32
#endif /* UNIV_DEBUG */
33
#ifdef UNIV_SYNC_DEBUG
35
#endif /* UNIV_SYNC_DEBUG */
36
#include "page0page.h"
38
/*****************************************************************
39
Creates a hash table with >= n array cells. The actual number of cells is
40
chosen to be a prime number slightly bigger than n. */
45
/* out, own: created table */
46
ulint n, /* in: number of array cells */
47
#ifdef UNIV_SYNC_DEBUG
48
ulint mutex_level, /* in: level of the mutexes in the latching
49
order: this is used in the debug version */
50
#endif /* UNIV_SYNC_DEBUG */
51
ulint n_mutexes) /* in: number of mutexes to protect the
52
hash table: must be a power of 2, or 0 */
57
table = hash_create(n);
59
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
60
table->adaptive = TRUE;
61
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
62
/* Creating MEM_HEAP_BTR_SEARCH type heaps can potentially fail,
63
but in practise it never should in this case, hence the asserts. */
66
table->heap = mem_heap_create_in_btr_search(
67
ut_min(4096, MEM_MAX_ALLOC_IN_BUF));
73
hash_create_mutexes(table, n_mutexes, mutex_level);
75
table->heaps = mem_alloc(n_mutexes * sizeof(void*));
77
for (i = 0; i < n_mutexes; i++) {
78
table->heaps[i] = mem_heap_create_in_btr_search(4096);
79
ut_a(table->heaps[i]);
85
/*****************************************************************
86
Empties a hash table and frees the memory heaps. */
91
hash_table_t* table) /* in, own: hash table */
96
#ifdef UNIV_SYNC_DEBUG
97
ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EXCLUSIVE));
98
#endif /* UNIV_SYNC_DEBUG */
100
/* Free the memory heaps. */
101
n = table->n_mutexes;
103
for (i = 0; i < n; i++) {
104
mem_heap_free(table->heaps[i]);
107
/* Clear the hash table. */
108
n = hash_get_n_cells(table);
110
for (i = 0; i < n; i++) {
111
hash_get_nth_cell(table, i)->node = NULL;
115
/*****************************************************************
116
Inserts an entry into a hash table. If an entry with the same fold number
117
is found, its node is updated to point to the new data, and no new node
121
ha_insert_for_fold_func(
122
/*====================*/
123
/* out: TRUE if succeed, FALSE if no more
124
memory could be allocated */
125
hash_table_t* table, /* in: hash table */
126
ulint fold, /* in: folded value of data; if a node with
127
the same fold value already exists, it is
128
updated to point to the same data, and no new
130
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
131
buf_block_t* block, /* in: buffer block containing the data */
132
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
133
void* data) /* in: data, must not be NULL */
137
ha_node_t* prev_node;
140
ut_ad(table && data);
141
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
142
ut_a(block->frame == page_align(data));
143
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
144
ut_ad(!table->mutexes || mutex_own(hash_get_mutex(table, fold)));
146
hash = hash_calc_hash(fold, table);
148
cell = hash_get_nth_cell(table, hash);
150
prev_node = cell->node;
152
while (prev_node != NULL) {
153
if (prev_node->fold == fold) {
154
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
155
if (table->adaptive) {
156
buf_block_t* prev_block = prev_node->block;
157
ut_a(prev_block->frame
158
== page_align(prev_node->data));
159
ut_a(prev_block->n_pointers > 0);
160
prev_block->n_pointers--;
164
prev_node->block = block;
165
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
166
prev_node->data = data;
171
prev_node = prev_node->next;
174
/* We have to allocate a new chain node */
176
node = mem_heap_alloc(hash_get_heap(table, fold), sizeof(ha_node_t));
179
/* It was a btr search type memory heap and at the moment
180
no more memory could be allocated: return */
182
ut_ad(hash_get_heap(table, fold)->type & MEM_HEAP_BTR_SEARCH);
187
ha_node_set_data(node, block, data);
189
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
190
if (table->adaptive) {
193
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
198
prev_node = cell->node;
200
if (prev_node == NULL) {
207
while (prev_node->next != NULL) {
209
prev_node = prev_node->next;
212
prev_node->next = node;
217
/***************************************************************
218
Deletes a hash node. */
223
hash_table_t* table, /* in: hash table */
224
ha_node_t* del_node) /* in: node to be deleted */
226
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
227
if (table->adaptive) {
228
ut_a(del_node->block->frame = page_align(del_node->data));
229
ut_a(del_node->block->n_pointers > 0);
230
del_node->block->n_pointers--;
232
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
233
HASH_DELETE_AND_COMPACT(ha_node_t, next, table, del_node);
236
/*****************************************************************
237
Deletes an entry from a hash table. */
242
hash_table_t* table, /* in: hash table */
243
ulint fold, /* in: folded value of data */
244
void* data) /* in: data, must not be NULL and must exist
249
ut_ad(!table->mutexes || mutex_own(hash_get_mutex(table, fold)));
251
node = ha_search_with_data(table, fold, data);
255
ha_delete_hash_node(table, node);
258
/*************************************************************
259
Looks for an element when we know the pointer to the data, and updates
260
the pointer to data, if found. */
263
ha_search_and_update_if_found_func(
264
/*===============================*/
265
hash_table_t* table, /* in: hash table */
266
ulint fold, /* in: folded value of the searched data */
267
void* data, /* in: pointer to the data */
268
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
269
buf_block_t* new_block,/* in: block containing new_data */
270
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
271
void* new_data)/* in: new pointer to the data */
275
ut_ad(!table->mutexes || mutex_own(hash_get_mutex(table, fold)));
276
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
277
ut_a(new_block->frame == page_align(new_data));
278
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
280
node = ha_search_with_data(table, fold, data);
283
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
284
if (table->adaptive) {
285
ut_a(node->block->n_pointers > 0);
286
node->block->n_pointers--;
287
new_block->n_pointers++;
290
node->block = new_block;
291
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
292
node->data = new_data;
296
/*********************************************************************
297
Removes from the chain determined by fold all nodes whose data pointer
298
points to the page given. */
301
ha_remove_all_nodes_to_page(
302
/*========================*/
303
hash_table_t* table, /* in: hash table */
304
ulint fold, /* in: fold value */
305
const page_t* page) /* in: buffer page */
309
ut_ad(!table->mutexes || mutex_own(hash_get_mutex(table, fold)));
311
node = ha_chain_get_first(table, fold);
314
if (page_align(ha_node_get_data(node)) == page) {
316
/* Remove the hash node */
318
ha_delete_hash_node(table, node);
320
/* Start again from the first node in the chain
321
because the deletion may compact the heap of
322
nodes and move other nodes! */
324
node = ha_chain_get_first(table, fold);
326
node = ha_chain_get_next(node);
330
/* Check that all nodes really got deleted */
332
node = ha_chain_get_first(table, fold);
335
ut_a(page_align(ha_node_get_data(node)) != page);
337
node = ha_chain_get_next(node);
342
/*****************************************************************
343
Validates a given range of the cells in hash table. */
348
/* out: TRUE if ok */
349
hash_table_t* table, /* in: hash table */
350
ulint start_index, /* in: start index */
351
ulint end_index) /* in: end index */
358
ut_a(start_index <= end_index);
359
ut_a(start_index < hash_get_n_cells(table));
360
ut_a(end_index < hash_get_n_cells(table));
362
for (i = start_index; i <= end_index; i++) {
364
cell = hash_get_nth_cell(table, i);
369
if (hash_calc_hash(node->fold, table) != i) {
370
ut_print_timestamp(stderr);
372
"InnoDB: Error: hash table node"
373
" fold value %lu does not\n"
374
"InnoDB: match the cell number %lu.\n",
375
(ulong) node->fold, (ulong) i);
387
/*****************************************************************
388
Prints info of a hash table. */
393
FILE* file, /* in: file where to print */
394
hash_table_t* table) /* in: hash table */
397
/* Some of the code here is disabled for performance reasons in production
398
builds, see http://bugs.mysql.com/36941 */
399
#define PRINT_USED_CELLS
400
#endif /* UNIV_DEBUG */
402
#ifdef PRINT_USED_CELLS
406
#endif /* PRINT_USED_CELLS */
409
#ifdef PRINT_USED_CELLS
410
for (i = 0; i < hash_get_n_cells(table); i++) {
412
cell = hash_get_nth_cell(table, i);
419
#endif /* PRINT_USED_CELLS */
421
fprintf(file, "Hash table size %lu",
422
(ulong) hash_get_n_cells(table));
424
#ifdef PRINT_USED_CELLS
425
fprintf(file, ", used cells %lu", (ulong) cells);
426
#endif /* PRINT_USED_CELLS */
428
if (table->heaps == NULL && table->heap != NULL) {
430
/* This calculation is intended for the adaptive hash
431
index: how many buffer frames we have reserved? */
433
n_bufs = UT_LIST_GET_LEN(table->heap->base) - 1;
435
if (table->heap->free_block) {
439
fprintf(file, ", node heap has %lu buffer(s)\n",