1 /*****************************************************************************
3 Copyright (c) 1994, 2011, Oracle and/or its affiliates. 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.,
15 51 Franklin 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
= mem_alloc(n_mutexes
* sizeof(void*));
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 Inserts an entry into a hash table. If an entry with the same fold number
93 is found, its node is updated to point to the new data, and no new node
94 is inserted. If btr_search_enabled is set to FALSE, we will only allow
95 updating existing nodes, but no new node is allowed to be added.
96 @return TRUE if succeed, FALSE if no more memory could be allocated */
99 ha_insert_for_fold_func(
100 /*====================*/
101 hash_table_t
* table
, /*!< in: hash table */
102 ulint fold
, /*!< in: folded value of data; if a node with
103 the same fold value already exists, it is
104 updated to point to the same data, and no new
106 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
107 buf_block_t
* block
, /*!< in: buffer block containing the data */
108 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
109 const rec_t
* data
) /*!< in: data, must not be NULL */
113 ha_node_t
* prev_node
;
118 ut_ad(table
->magic_n
== HASH_TABLE_MAGIC_N
);
119 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
120 ut_a(block
->frame
== page_align(data
));
121 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
122 #ifdef UNIV_SYNC_DEBUG
123 ut_ad(rw_lock_own(&btr_search_latch
, RW_LOCK_EX
));
124 #endif /* UNIV_SYNC_DEBUG */
125 ASSERT_HASH_MUTEX_OWN(table
, fold
);
126 ut_ad(btr_search_enabled
);
128 hash
= hash_calc_hash(fold
, table
);
130 cell
= hash_get_nth_cell(table
, hash
);
132 prev_node
= cell
->node
;
134 while (prev_node
!= NULL
) {
135 if (prev_node
->fold
== fold
) {
136 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
137 # ifndef UNIV_HOTBACKUP
138 if (table
->adaptive
) {
139 buf_block_t
* prev_block
= prev_node
->block
;
140 ut_a(prev_block
->frame
141 == page_align(prev_node
->data
));
142 ut_a(prev_block
->n_pointers
> 0);
143 prev_block
->n_pointers
--;
146 # endif /* !UNIV_HOTBACKUP */
148 prev_node
->block
= block
;
149 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
150 prev_node
->data
= data
;
155 prev_node
= prev_node
->next
;
158 /* We have to allocate a new chain node */
160 node
= mem_heap_alloc(hash_get_heap(table
, fold
), sizeof(ha_node_t
));
163 /* It was a btr search type memory heap and at the moment
164 no more memory could be allocated: return */
166 ut_ad(hash_get_heap(table
, fold
)->type
& MEM_HEAP_BTR_SEARCH
);
171 ha_node_set_data(node
, block
, data
);
173 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
174 # ifndef UNIV_HOTBACKUP
175 if (table
->adaptive
) {
178 # endif /* !UNIV_HOTBACKUP */
179 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
185 prev_node
= cell
->node
;
187 if (prev_node
== NULL
) {
194 while (prev_node
->next
!= NULL
) {
196 prev_node
= prev_node
->next
;
199 prev_node
->next
= node
;
204 /***********************************************************//**
205 Deletes a hash node. */
210 hash_table_t
* table
, /*!< in: hash table */
211 ha_node_t
* del_node
) /*!< in: node to be deleted */
214 ut_ad(table
->magic_n
== HASH_TABLE_MAGIC_N
);
215 #ifdef UNIV_SYNC_DEBUG
216 ut_ad(rw_lock_own(&btr_search_latch
, RW_LOCK_EX
));
217 #endif /* UNIV_SYNC_DEBUG */
218 ut_ad(btr_search_enabled
);
219 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
220 # ifndef UNIV_HOTBACKUP
221 if (table
->adaptive
) {
222 ut_a(del_node
->block
->frame
= page_align(del_node
->data
));
223 ut_a(del_node
->block
->n_pointers
> 0);
224 del_node
->block
->n_pointers
--;
226 # endif /* !UNIV_HOTBACKUP */
227 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
229 HASH_DELETE_AND_COMPACT(ha_node_t
, next
, table
, del_node
);
232 /*********************************************************//**
233 Looks for an element when we know the pointer to the data, and updates
234 the pointer to data, if found. */
237 ha_search_and_update_if_found_func(
238 /*===============================*/
239 hash_table_t
* table
, /*!< in/out: hash table */
240 ulint fold
, /*!< in: folded value of the searched data */
241 const rec_t
* data
, /*!< in: pointer to the data */
242 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
243 buf_block_t
* new_block
,/*!< in: block containing new_data */
244 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
245 const rec_t
* new_data
)/*!< in: new pointer to the data */
250 ut_ad(table
->magic_n
== HASH_TABLE_MAGIC_N
);
251 ASSERT_HASH_MUTEX_OWN(table
, fold
);
252 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
253 ut_a(new_block
->frame
== page_align(new_data
));
254 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
255 #ifdef UNIV_SYNC_DEBUG
256 ut_ad(rw_lock_own(&btr_search_latch
, RW_LOCK_EX
));
257 #endif /* UNIV_SYNC_DEBUG */
259 if (!btr_search_enabled
) {
263 node
= ha_search_with_data(table
, fold
, data
);
266 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
267 # ifndef UNIV_HOTBACKUP
268 if (table
->adaptive
) {
269 ut_a(node
->block
->n_pointers
> 0);
270 node
->block
->n_pointers
--;
271 new_block
->n_pointers
++;
273 # endif /* !UNIV_HOTBACKUP */
275 node
->block
= new_block
;
276 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
277 node
->data
= new_data
;
281 #ifndef UNIV_HOTBACKUP
282 /*****************************************************************//**
283 Removes from the chain determined by fold all nodes whose data pointer
284 points to the page given. */
287 ha_remove_all_nodes_to_page(
288 /*========================*/
289 hash_table_t
* table
, /*!< in: hash table */
290 ulint fold
, /*!< in: fold value */
291 const page_t
* page
) /*!< in: buffer page */
296 ut_ad(table
->magic_n
== HASH_TABLE_MAGIC_N
);
297 ASSERT_HASH_MUTEX_OWN(table
, fold
);
298 #ifdef UNIV_SYNC_DEBUG
299 ut_ad(rw_lock_own(&btr_search_latch
, RW_LOCK_EX
));
300 #endif /* UNIV_SYNC_DEBUG */
301 ut_ad(btr_search_enabled
);
303 node
= ha_chain_get_first(table
, fold
);
306 if (page_align(ha_node_get_data(node
)) == page
) {
308 /* Remove the hash node */
310 ha_delete_hash_node(table
, node
);
312 /* Start again from the first node in the chain
313 because the deletion may compact the heap of
314 nodes and move other nodes! */
316 node
= ha_chain_get_first(table
, fold
);
318 node
= ha_chain_get_next(node
);
322 /* Check that all nodes really got deleted */
324 node
= ha_chain_get_first(table
, fold
);
327 ut_a(page_align(ha_node_get_data(node
)) != page
);
329 node
= ha_chain_get_next(node
);
334 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
335 /*************************************************************//**
336 Validates a given range of the cells in hash table.
337 @return TRUE if ok */
342 hash_table_t
* table
, /*!< in: hash table */
343 ulint start_index
, /*!< in: start index */
344 ulint end_index
) /*!< in: end index */
352 ut_ad(table
->magic_n
== HASH_TABLE_MAGIC_N
);
353 ut_a(start_index
<= end_index
);
354 ut_a(start_index
< hash_get_n_cells(table
));
355 ut_a(end_index
< hash_get_n_cells(table
));
357 for (i
= start_index
; i
<= end_index
; i
++) {
359 cell
= hash_get_nth_cell(table
, i
);
364 if (hash_calc_hash(node
->fold
, table
) != i
) {
365 ut_print_timestamp(stderr
);
367 "InnoDB: Error: hash table node"
368 " fold value %lu does not\n"
369 "InnoDB: match the cell number %lu.\n",
370 (ulong
) node
->fold
, (ulong
) i
);
381 #endif /* defined UNIV_AHI_DEBUG || defined UNIV_DEBUG */
383 /*************************************************************//**
384 Prints info of a hash table. */
389 FILE* file
, /*!< in: file where to print */
390 hash_table_t
* table
) /*!< in: hash table */
393 /* Some of the code here is disabled for performance reasons in production
394 builds, see http://bugs.mysql.com/36941 */
395 #define PRINT_USED_CELLS
396 #endif /* UNIV_DEBUG */
398 #ifdef PRINT_USED_CELLS
402 #endif /* PRINT_USED_CELLS */
406 ut_ad(table
->magic_n
== HASH_TABLE_MAGIC_N
);
407 #ifdef PRINT_USED_CELLS
408 for (i
= 0; i
< hash_get_n_cells(table
); i
++) {
410 cell
= hash_get_nth_cell(table
, i
);
417 #endif /* PRINT_USED_CELLS */
419 fprintf(file
, "Hash table size %lu",
420 (ulong
) hash_get_n_cells(table
));
422 #ifdef PRINT_USED_CELLS
423 fprintf(file
, ", used cells %lu", (ulong
) cells
);
424 #endif /* PRINT_USED_CELLS */
426 if (table
->heaps
== NULL
&& table
->heap
!= NULL
) {
428 /* This calculation is intended for the adaptive hash
429 index: how many buffer frames we have reserved? */
431 n_bufs
= UT_LIST_GET_LEN(table
->heap
->base
) - 1;
433 if (table
->heap
->free_block
) {
437 fprintf(file
, ", node heap has %lu buffer(s)\n",
441 #endif /* !UNIV_HOTBACKUP */