1 | /***************************************************************************** |
2 | |
3 | Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved. |
4 | Copyright (c) 2018, MariaDB Corporation. |
5 | |
6 | This program is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free Software |
8 | Foundation; version 2 of the License. |
9 | |
10 | This program is distributed in the hope that it will be useful, but WITHOUT |
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
12 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU General Public License along with |
15 | this program; if not, write to the Free Software Foundation, Inc., |
16 | 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA |
17 | |
18 | *****************************************************************************/ |
19 | |
20 | /**************************************************//** |
21 | @file include/hash0hash.h |
22 | The simple hash table utility |
23 | |
24 | Created 5/20/1997 Heikki Tuuri |
25 | *******************************************************/ |
26 | |
27 | #ifndef hash0hash_h |
28 | #define hash0hash_h |
29 | |
30 | #include "univ.i" |
31 | #include "mem0mem.h" |
32 | #include "sync0rw.h" |
33 | |
34 | struct hash_table_t; |
35 | struct hash_cell_t; |
36 | |
37 | typedef void* hash_node_t; |
38 | |
39 | /* Fix Bug #13859: symbol collision between imap/mysql */ |
40 | #define hash_create hash0_create |
41 | |
42 | /* Differnt types of hash_table based on the synchronization |
43 | method used for it. */ |
44 | enum hash_table_sync_t { |
45 | HASH_TABLE_SYNC_NONE = 0, /*!< Don't use any internal |
46 | synchronization objects for |
47 | this hash_table. */ |
48 | HASH_TABLE_SYNC_MUTEX, /*!< Use mutexes to control |
49 | access to this hash_table. */ |
50 | HASH_TABLE_SYNC_RW_LOCK /*!< Use rw_locks to control |
51 | access to this hash_table. */ |
52 | }; |
53 | |
54 | /*************************************************************//** |
55 | Creates a hash table with >= n array cells. The actual number |
56 | of cells is chosen to be a prime number slightly bigger than n. |
57 | @return own: created table */ |
58 | hash_table_t* |
59 | hash_create( |
60 | /*========*/ |
61 | ulint n); /*!< in: number of array cells */ |
62 | |
63 | /*************************************************************//** |
64 | Creates a sync object array array to protect a hash table. |
65 | ::sync_obj can be mutexes or rw_locks depening on the type of |
66 | hash table. */ |
67 | void |
68 | hash_create_sync_obj( |
69 | /*=================*/ |
70 | hash_table_t* table, /*!< in: hash table */ |
71 | hash_table_sync_t type, /*!< in: HASH_TABLE_SYNC_MUTEX |
72 | or HASH_TABLE_SYNC_RW_LOCK */ |
73 | latch_id_t id, /*!< in: mutex/rw_lock ID */ |
74 | ulint n_sync_obj);/*!< in: number of sync objects, |
75 | must be a power of 2 */ |
76 | |
77 | /*************************************************************//** |
78 | Frees a hash table. */ |
79 | void |
80 | hash_table_free( |
81 | /*============*/ |
82 | hash_table_t* table); /*!< in, own: hash table */ |
83 | /**************************************************************//** |
84 | Calculates the hash value from a folded value. |
85 | @return hashed value */ |
86 | UNIV_INLINE |
87 | ulint |
88 | hash_calc_hash( |
89 | /*===========*/ |
90 | ulint fold, /*!< in: folded value */ |
91 | hash_table_t* table); /*!< in: hash table */ |
92 | /********************************************************************//** |
93 | Assert that the mutex for the table is held */ |
94 | #define HASH_ASSERT_OWN(TABLE, FOLD) \ |
95 | ut_ad((TABLE)->type != HASH_TABLE_SYNC_MUTEX \ |
96 | || (mutex_own(hash_get_mutex((TABLE), FOLD)))); |
97 | |
98 | /*******************************************************************//** |
99 | Inserts a struct to a hash table. */ |
100 | |
101 | #define HASH_INSERT(TYPE, NAME, TABLE, FOLD, DATA)\ |
102 | do {\ |
103 | hash_cell_t* cell3333;\ |
104 | TYPE* struct3333;\ |
105 | \ |
106 | HASH_ASSERT_OWN(TABLE, FOLD)\ |
107 | \ |
108 | (DATA)->NAME = NULL;\ |
109 | \ |
110 | cell3333 = hash_get_nth_cell(TABLE, hash_calc_hash(FOLD, TABLE));\ |
111 | \ |
112 | if (cell3333->node == NULL) {\ |
113 | cell3333->node = DATA;\ |
114 | } else {\ |
115 | struct3333 = (TYPE*) cell3333->node;\ |
116 | \ |
117 | while (struct3333->NAME != NULL) {\ |
118 | \ |
119 | struct3333 = (TYPE*) struct3333->NAME;\ |
120 | }\ |
121 | \ |
122 | struct3333->NAME = DATA;\ |
123 | }\ |
124 | } while (0) |
125 | |
126 | /*******************************************************************//** |
127 | Inserts a struct to the head of hash table. */ |
128 | |
129 | #define HASH_PREPEND(TYPE, NAME, TABLE, FOLD, DATA) \ |
130 | do { \ |
131 | hash_cell_t* cell3333; \ |
132 | TYPE* struct3333; \ |
133 | \ |
134 | HASH_ASSERT_OWN(TABLE, FOLD) \ |
135 | \ |
136 | (DATA)->NAME = NULL; \ |
137 | \ |
138 | cell3333 = hash_get_nth_cell(TABLE, hash_calc_hash(FOLD, TABLE));\ |
139 | \ |
140 | if (cell3333->node == NULL) { \ |
141 | cell3333->node = DATA; \ |
142 | DATA->NAME = NULL; \ |
143 | } else { \ |
144 | struct3333 = (TYPE*) cell3333->node; \ |
145 | \ |
146 | DATA->NAME = struct3333; \ |
147 | \ |
148 | cell3333->node = DATA; \ |
149 | } \ |
150 | } while (0) |
151 | #ifdef UNIV_HASH_DEBUG |
152 | # define HASH_ASSERT_VALID(DATA) ut_a((void*) (DATA) != (void*) -1) |
153 | # define HASH_INVALIDATE(DATA, NAME) *(void**) (&DATA->NAME) = (void*) -1 |
154 | #else |
155 | # define HASH_ASSERT_VALID(DATA) do {} while (0) |
156 | # define HASH_INVALIDATE(DATA, NAME) do {} while (0) |
157 | #endif |
158 | |
159 | /*******************************************************************//** |
160 | Deletes a struct from a hash table. */ |
161 | |
162 | #define HASH_DELETE(TYPE, NAME, TABLE, FOLD, DATA)\ |
163 | do {\ |
164 | hash_cell_t* cell3333;\ |
165 | TYPE* struct3333;\ |
166 | \ |
167 | HASH_ASSERT_OWN(TABLE, FOLD)\ |
168 | \ |
169 | cell3333 = hash_get_nth_cell(TABLE, hash_calc_hash(FOLD, TABLE));\ |
170 | \ |
171 | if (cell3333->node == DATA) {\ |
172 | HASH_ASSERT_VALID(DATA->NAME);\ |
173 | cell3333->node = DATA->NAME;\ |
174 | } else {\ |
175 | struct3333 = (TYPE*) cell3333->node;\ |
176 | \ |
177 | while (struct3333->NAME != DATA) {\ |
178 | \ |
179 | struct3333 = (TYPE*) struct3333->NAME;\ |
180 | ut_a(struct3333);\ |
181 | }\ |
182 | \ |
183 | struct3333->NAME = DATA->NAME;\ |
184 | }\ |
185 | HASH_INVALIDATE(DATA, NAME);\ |
186 | } while (0) |
187 | |
188 | /*******************************************************************//** |
189 | Gets the first struct in a hash chain, NULL if none. */ |
190 | |
191 | #define HASH_GET_FIRST(TABLE, HASH_VAL)\ |
192 | (hash_get_nth_cell(TABLE, HASH_VAL)->node) |
193 | |
194 | /*******************************************************************//** |
195 | Gets the next struct in a hash chain, NULL if none. */ |
196 | |
197 | #define HASH_GET_NEXT(NAME, DATA) ((DATA)->NAME) |
198 | |
199 | /********************************************************************//** |
200 | Looks for a struct in a hash table. */ |
201 | #define HASH_SEARCH(NAME, TABLE, FOLD, TYPE, DATA, ASSERTION, TEST)\ |
202 | {\ |
203 | \ |
204 | HASH_ASSERT_OWN(TABLE, FOLD)\ |
205 | \ |
206 | (DATA) = (TYPE) HASH_GET_FIRST(TABLE, hash_calc_hash(FOLD, TABLE));\ |
207 | HASH_ASSERT_VALID(DATA);\ |
208 | \ |
209 | while ((DATA) != NULL) {\ |
210 | ASSERTION;\ |
211 | if (TEST) {\ |
212 | break;\ |
213 | } else {\ |
214 | HASH_ASSERT_VALID(HASH_GET_NEXT(NAME, DATA));\ |
215 | (DATA) = (TYPE) HASH_GET_NEXT(NAME, DATA);\ |
216 | }\ |
217 | }\ |
218 | } |
219 | |
220 | /********************************************************************//** |
221 | Looks for an item in all hash buckets. */ |
222 | #define HASH_SEARCH_ALL(NAME, TABLE, TYPE, DATA, ASSERTION, TEST) \ |
223 | do { \ |
224 | ulint i3333; \ |
225 | \ |
226 | for (i3333 = (TABLE)->n_cells; i3333--; ) { \ |
227 | (DATA) = (TYPE) HASH_GET_FIRST(TABLE, i3333); \ |
228 | \ |
229 | while ((DATA) != NULL) { \ |
230 | HASH_ASSERT_VALID(DATA); \ |
231 | ASSERTION; \ |
232 | \ |
233 | if (TEST) { \ |
234 | break; \ |
235 | } \ |
236 | \ |
237 | (DATA) = (TYPE) HASH_GET_NEXT(NAME, DATA); \ |
238 | } \ |
239 | \ |
240 | if ((DATA) != NULL) { \ |
241 | break; \ |
242 | } \ |
243 | } \ |
244 | } while (0) |
245 | |
246 | /************************************************************//** |
247 | Gets the nth cell in a hash table. |
248 | @return pointer to cell */ |
249 | UNIV_INLINE |
250 | hash_cell_t* |
251 | hash_get_nth_cell( |
252 | /*==============*/ |
253 | hash_table_t* table, /*!< in: hash table */ |
254 | ulint n); /*!< in: cell index */ |
255 | |
256 | /*************************************************************//** |
257 | Clears a hash table so that all the cells become empty. */ |
258 | UNIV_INLINE |
259 | void |
260 | hash_table_clear( |
261 | /*=============*/ |
262 | hash_table_t* table); /*!< in/out: hash table */ |
263 | |
264 | /*************************************************************//** |
265 | Returns the number of cells in a hash table. |
266 | @return number of cells */ |
267 | UNIV_INLINE |
268 | ulint |
269 | hash_get_n_cells( |
270 | /*=============*/ |
271 | hash_table_t* table); /*!< in: table */ |
272 | /*******************************************************************//** |
273 | Deletes a struct which is stored in the heap of the hash table, and compacts |
274 | the heap. The fold value must be stored in the struct NODE in a field named |
275 | 'fold'. */ |
276 | |
277 | #define HASH_DELETE_AND_COMPACT(TYPE, NAME, TABLE, NODE)\ |
278 | do {\ |
279 | TYPE* node111;\ |
280 | TYPE* top_node111;\ |
281 | hash_cell_t* cell111;\ |
282 | ulint fold111;\ |
283 | \ |
284 | fold111 = (NODE)->fold;\ |
285 | \ |
286 | HASH_DELETE(TYPE, NAME, TABLE, fold111, NODE);\ |
287 | \ |
288 | top_node111 = (TYPE*) mem_heap_get_top(\ |
289 | hash_get_heap(TABLE, fold111),\ |
290 | sizeof(TYPE));\ |
291 | \ |
292 | /* If the node to remove is not the top node in the heap, compact the\ |
293 | heap of nodes by moving the top node in the place of NODE. */\ |
294 | \ |
295 | if (NODE != top_node111) {\ |
296 | \ |
297 | /* Copy the top node in place of NODE */\ |
298 | \ |
299 | *(NODE) = *top_node111;\ |
300 | \ |
301 | cell111 = hash_get_nth_cell(TABLE,\ |
302 | hash_calc_hash(top_node111->fold, TABLE));\ |
303 | \ |
304 | /* Look for the pointer to the top node, to update it */\ |
305 | \ |
306 | if (cell111->node == top_node111) {\ |
307 | /* The top node is the first in the chain */\ |
308 | \ |
309 | cell111->node = NODE;\ |
310 | } else {\ |
311 | /* We have to look for the predecessor of the top\ |
312 | node */\ |
313 | node111 = static_cast<TYPE*>(cell111->node);\ |
314 | \ |
315 | while (top_node111 != HASH_GET_NEXT(NAME, node111)) {\ |
316 | \ |
317 | node111 = static_cast<TYPE*>(\ |
318 | HASH_GET_NEXT(NAME, node111));\ |
319 | }\ |
320 | \ |
321 | /* Now we have the predecessor node */\ |
322 | \ |
323 | node111->NAME = NODE;\ |
324 | }\ |
325 | }\ |
326 | \ |
327 | /* Free the space occupied by the top node */\ |
328 | \ |
329 | mem_heap_free_top(hash_get_heap(TABLE, fold111), sizeof(TYPE));\ |
330 | } while (0) |
331 | |
332 | /****************************************************************//** |
333 | Move all hash table entries from OLD_TABLE to NEW_TABLE. */ |
334 | |
335 | #define HASH_MIGRATE(OLD_TABLE, NEW_TABLE, NODE_TYPE, PTR_NAME, FOLD_FUNC) \ |
336 | do {\ |
337 | ulint i2222;\ |
338 | ulint cell_count2222;\ |
339 | \ |
340 | cell_count2222 = hash_get_n_cells(OLD_TABLE);\ |
341 | \ |
342 | for (i2222 = 0; i2222 < cell_count2222; i2222++) {\ |
343 | NODE_TYPE* node2222 = static_cast<NODE_TYPE*>(\ |
344 | HASH_GET_FIRST((OLD_TABLE), i2222));\ |
345 | \ |
346 | while (node2222) {\ |
347 | NODE_TYPE* next2222 = static_cast<NODE_TYPE*>(\ |
348 | node2222->PTR_NAME);\ |
349 | ulint fold2222 = FOLD_FUNC(node2222);\ |
350 | \ |
351 | HASH_INSERT(NODE_TYPE, PTR_NAME, (NEW_TABLE),\ |
352 | fold2222, node2222);\ |
353 | \ |
354 | node2222 = next2222;\ |
355 | }\ |
356 | }\ |
357 | } while (0) |
358 | |
359 | /************************************************************//** |
360 | Gets the sync object index for a fold value in a hash table. |
361 | @return index */ |
362 | UNIV_INLINE |
363 | ulint |
364 | hash_get_sync_obj_index( |
365 | /*====================*/ |
366 | hash_table_t* table, /*!< in: hash table */ |
367 | ulint fold); /*!< in: fold */ |
368 | /************************************************************//** |
369 | Gets the nth heap in a hash table. |
370 | @return mem heap */ |
371 | UNIV_INLINE |
372 | mem_heap_t* |
373 | hash_get_nth_heap( |
374 | /*==============*/ |
375 | hash_table_t* table, /*!< in: hash table */ |
376 | ulint i); /*!< in: index of the heap */ |
377 | /************************************************************//** |
378 | Gets the heap for a fold value in a hash table. |
379 | @return mem heap */ |
380 | UNIV_INLINE |
381 | mem_heap_t* |
382 | hash_get_heap( |
383 | /*==========*/ |
384 | hash_table_t* table, /*!< in: hash table */ |
385 | ulint fold); /*!< in: fold */ |
386 | /************************************************************//** |
387 | Gets the nth mutex in a hash table. |
388 | @return mutex */ |
389 | UNIV_INLINE |
390 | ib_mutex_t* |
391 | hash_get_nth_mutex( |
392 | /*===============*/ |
393 | hash_table_t* table, /*!< in: hash table */ |
394 | ulint i); /*!< in: index of the mutex */ |
395 | /************************************************************//** |
396 | Gets the nth rw_lock in a hash table. |
397 | @return rw_lock */ |
398 | UNIV_INLINE |
399 | rw_lock_t* |
400 | hash_get_nth_lock( |
401 | /*==============*/ |
402 | hash_table_t* table, /*!< in: hash table */ |
403 | ulint i); /*!< in: index of the rw_lock */ |
404 | /************************************************************//** |
405 | Gets the mutex for a fold value in a hash table. |
406 | @return mutex */ |
407 | UNIV_INLINE |
408 | ib_mutex_t* |
409 | hash_get_mutex( |
410 | /*===========*/ |
411 | hash_table_t* table, /*!< in: hash table */ |
412 | ulint fold); /*!< in: fold */ |
413 | /************************************************************//** |
414 | Gets the rw_lock for a fold value in a hash table. |
415 | @return rw_lock */ |
416 | UNIV_INLINE |
417 | rw_lock_t* |
418 | hash_get_lock( |
419 | /*==========*/ |
420 | hash_table_t* table, /*!< in: hash table */ |
421 | ulint fold); /*!< in: fold */ |
422 | |
423 | /** If not appropriate rw_lock for a fold value in a hash table, |
424 | relock S-lock the another rw_lock until appropriate for a fold value. |
425 | @param[in] hash_lock latched rw_lock to be confirmed |
426 | @param[in] table hash table |
427 | @param[in] fold fold value |
428 | @return latched rw_lock */ |
429 | UNIV_INLINE |
430 | rw_lock_t* |
431 | hash_lock_s_confirm( |
432 | rw_lock_t* hash_lock, |
433 | hash_table_t* table, |
434 | ulint fold); |
435 | |
436 | /** If not appropriate rw_lock for a fold value in a hash table, |
437 | relock X-lock the another rw_lock until appropriate for a fold value. |
438 | @param[in] hash_lock latched rw_lock to be confirmed |
439 | @param[in] table hash table |
440 | @param[in] fold fold value |
441 | @return latched rw_lock */ |
442 | UNIV_INLINE |
443 | rw_lock_t* |
444 | hash_lock_x_confirm( |
445 | rw_lock_t* hash_lock, |
446 | hash_table_t* table, |
447 | ulint fold); |
448 | |
449 | /************************************************************//** |
450 | Reserves all the locks of a hash table, in an ascending order. */ |
451 | void |
452 | hash_lock_x_all( |
453 | /*============*/ |
454 | hash_table_t* table); /*!< in: hash table */ |
455 | /************************************************************//** |
456 | Releases all the locks of a hash table, in an ascending order. */ |
457 | void |
458 | hash_unlock_x_all( |
459 | /*==============*/ |
460 | hash_table_t* table); /*!< in: hash table */ |
461 | /************************************************************//** |
462 | Releases all but passed in lock of a hash table, */ |
463 | void |
464 | hash_unlock_x_all_but( |
465 | /*==================*/ |
466 | hash_table_t* table, /*!< in: hash table */ |
467 | rw_lock_t* keep_lock); /*!< in: lock to keep */ |
468 | |
469 | struct hash_cell_t{ |
470 | void* node; /*!< hash chain node, NULL if none */ |
471 | }; |
472 | |
473 | /* The hash table structure */ |
474 | struct hash_table_t { |
475 | enum hash_table_sync_t type; /*<! type of hash_table. */ |
476 | #ifdef BTR_CUR_HASH_ADAPT |
477 | # if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG |
478 | ibool adaptive;/* TRUE if this is the hash |
479 | table of the adaptive hash |
480 | index */ |
481 | # endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ |
482 | #endif /* BTR_CUR_HASH_ADAPT */ |
483 | ulint n_cells;/* number of cells in the hash table */ |
484 | hash_cell_t* array; /*!< pointer to cell array */ |
485 | |
486 | ulint n_sync_obj;/* if sync_objs != NULL, then |
487 | the number of either the number |
488 | of mutexes or the number of |
489 | rw_locks depending on the type. |
490 | Must be a power of 2 */ |
491 | union { |
492 | ib_mutex_t* mutexes;/* NULL, or an array of mutexes |
493 | used to protect segments of the |
494 | hash table */ |
495 | rw_lock_t* rw_locks;/* NULL, or an array of rw_lcoks |
496 | used to protect segments of the |
497 | hash table */ |
498 | } sync_obj; |
499 | |
500 | mem_heap_t** heaps; /*!< if this is non-NULL, hash |
501 | chain nodes for external chaining |
502 | can be allocated from these memory |
503 | heaps; there are then n_mutexes |
504 | many of these heaps */ |
505 | mem_heap_t* heap; |
506 | #ifdef UNIV_DEBUG |
507 | ulint magic_n; |
508 | # define HASH_TABLE_MAGIC_N 76561114 |
509 | #endif /* UNIV_DEBUG */ |
510 | }; |
511 | |
512 | #include "hash0hash.ic" |
513 | |
514 | #endif |
515 | |