MySQL 8.4.2
Source Code Documentation
hash0hash.h
Go to the documentation of this file.
1/*****************************************************************************
2
3Copyright (c) 1997, 2024, Oracle and/or its affiliates.
4
5This program is free software; you can redistribute it and/or modify it under
6the terms of the GNU General Public License, version 2.0, as published by the
7Free Software Foundation.
8
9This program is designed to work with certain software (including
10but not limited to OpenSSL) that is licensed under separate terms,
11as designated in a particular file or component or in included license
12documentation. The authors of MySQL hereby grant you an additional
13permission to link the program and your derivative works with the
14separately licensed software that they have either included with
15the program or referenced in the documentation.
16
17This program is distributed in the hope that it will be useful, but WITHOUT
18ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
20for more details.
21
22You should have received a copy of the GNU General Public License along with
23this program; if not, write to the Free Software Foundation, Inc.,
2451 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25
26*****************************************************************************/
27
28/** @file include/hash0hash.h
29 The simple hash table utility
30
31 Created 5/20/1997 Heikki Tuuri
32 *******************************************************/
33
34#ifndef hash0hash_h
35#define hash0hash_h
36
37#include <stddef.h>
38
39#include "mem0mem.h"
40#include "univ.i"
41#include "ut0rnd.h"
42#ifndef UNIV_HOTBACKUP
43#include "sync0rw.h"
44#endif /* !UNIV_HOTBACKUP */
45
46class hash_table_t;
47struct hash_cell_t;
48
49typedef void *hash_node_t;
50
51/* Different types of hash_table based on the synchronization
52method used for it. */
54 HASH_TABLE_SYNC_NONE = 0, /*!< Don't use any internal
55 synchronization objects for
56 this hash_table. */
57 HASH_TABLE_SYNC_RW_LOCK /*!< Use rw_locks to control
58 access to this hash_table. */
59};
60
62 void *node; /*!< hash chain node, NULL if none */
63};
64
65#ifndef UNIV_HOTBACKUP
66
67/** Creates a sync object array to protect a hash table.
68@param[in] table hash table
69@param[in] id latch ID
70@param[in] n_sync_obj number of sync objects, must be a power of 2 */
72 size_t n_sync_obj);
73#endif /* !UNIV_HOTBACKUP */
74
75/** Calculates the cell index from a hashed value for a specified hash table.
76@param[in] hash_value hashed value
77@param[in] table hash table
78@return cell index for specified hash table*/
79static inline uint64_t hash_calc_cell_id(uint64_t hash_value,
81
82/** Gets the nth cell in a hash table.
83@param[in] table hash table
84@param[in] n cell index
85@return pointer to cell */
87
88/** Inserts a struct to a hash table. */
89
90#define HASH_INSERT(TYPE, NAME, TABLE, HASH_VALUE, DATA) \
91 do { \
92 hash_cell_t *cell3333; \
93 TYPE *struct3333; \
94 const uint64_t hash_value3333 = HASH_VALUE; \
95 \
96 hash_assert_can_modify(TABLE, hash_value3333); \
97 \
98 (DATA)->NAME = NULL; \
99 \
100 cell3333 = \
101 hash_get_nth_cell(TABLE, hash_calc_cell_id(hash_value3333, TABLE)); \
102 \
103 if (cell3333->node == NULL) { \
104 cell3333->node = DATA; \
105 } else { \
106 struct3333 = (TYPE *)cell3333->node; \
107 \
108 while (struct3333->NAME != NULL) { \
109 struct3333 = (TYPE *)struct3333->NAME; \
110 } \
111 \
112 struct3333->NAME = DATA; \
113 } \
114 } while (0)
115
116#ifdef UNIV_HASH_DEBUG
117#define HASH_ASSERT_VALID(DATA) ut_a((void *)(DATA) != (void *)-1)
118#define HASH_INVALIDATE(DATA, NAME) *(void **)(&DATA->NAME) = (void *)-1
119#else
120#define HASH_ASSERT_VALID(DATA) \
121 do { \
122 } while (0)
123#define HASH_INVALIDATE(DATA, NAME) \
124 do { \
125 } while (0)
126#endif
127
128/** Deletes a struct from a hash table. */
129
130#define HASH_DELETE(TYPE, NAME, TABLE, HASH_VALUE, DATA) \
131 do { \
132 hash_cell_t *cell3333; \
133 TYPE *struct3333; \
134 const uint64_t hash_value3333 = HASH_VALUE; \
135 \
136 hash_assert_can_modify(TABLE, hash_value3333); \
137 \
138 cell3333 = \
139 hash_get_nth_cell(TABLE, hash_calc_cell_id(hash_value3333, TABLE)); \
140 \
141 if (cell3333->node == DATA) { \
142 HASH_ASSERT_VALID(DATA->NAME); \
143 cell3333->node = DATA->NAME; \
144 } else { \
145 struct3333 = (TYPE *)cell3333->node; \
146 \
147 while (struct3333->NAME != DATA) { \
148 struct3333 = (TYPE *)struct3333->NAME; \
149 ut_a(struct3333); \
150 } \
151 \
152 struct3333->NAME = DATA->NAME; \
153 } \
154 HASH_INVALIDATE(DATA, NAME); \
155 } while (0)
156
157/** Gets the first struct in a hash chain, NULL if none. */
158
159static inline void *&hash_get_first(hash_table_t *table, size_t cell_id) {
160 return hash_get_nth_cell(table, cell_id)->node;
161}
162
163/** Gets the next struct in a hash chain, NULL if none. */
164
165#define HASH_GET_NEXT(NAME, DATA) ((DATA)->NAME)
166
167/** Looks for a struct in a hash table. */
168#define HASH_SEARCH(NAME, TABLE, HASH_VALUE, TYPE, DATA, ASSERTION, TEST) \
169 { \
170 const uint64_t hash_value3333 = HASH_VALUE; \
171 \
172 hash_assert_can_search(TABLE, hash_value3333); \
173 \
174 (DATA) = \
175 (TYPE)hash_get_first(TABLE, hash_calc_cell_id(hash_value3333, TABLE)); \
176 HASH_ASSERT_VALID(DATA); \
177 \
178 while ((DATA) != NULL) { \
179 ASSERTION; \
180 if (TEST) { \
181 break; \
182 } else { \
183 HASH_ASSERT_VALID(HASH_GET_NEXT(NAME, DATA)); \
184 (DATA) = (TYPE)HASH_GET_NEXT(NAME, DATA); \
185 } \
186 } \
187 }
188
189/** Looks for an item in all hash cells. */
190#define HASH_SEARCH_ALL(NAME, TABLE, TYPE, DATA, ASSERTION, TEST) \
191 do { \
192 size_t i3333; \
193 \
194 for (i3333 = (TABLE)->get_n_cells(); i3333--;) { \
195 (DATA) = (TYPE)hash_get_first(TABLE, i3333); \
196 \
197 while ((DATA) != NULL) { \
198 HASH_ASSERT_VALID(DATA); \
199 ASSERTION; \
200 \
201 if (TEST) { \
202 break; \
203 } \
204 \
205 (DATA) = (TYPE)HASH_GET_NEXT(NAME, DATA); \
206 } \
207 \
208 if ((DATA) != NULL) { \
209 break; \
210 } \
211 } \
212 } while (0)
213
214/** Clears a hash table so that all the cells become empty. */
215static inline void hash_table_clear(
216 hash_table_t *table); /*!< in/out: hash table */
217
218/** Returns the number of cells in a hash table.
219 @return number of cells */
220static inline size_t hash_get_n_cells(hash_table_t *table); /*!< in: table */
221
222/** Deletes a struct which is stored in the heap of the hash table, and compacts
223 the heap. The hash value must be stored in the struct NODE in a field named
224 'hash_value'. */
225#define HASH_DELETE_AND_COMPACT(TYPE, NAME, TABLE, NODE) \
226 do { \
227 TYPE *node111; \
228 TYPE *top_node111; \
229 hash_cell_t *cell111; \
230 uint64_t hash_value111; \
231 \
232 hash_value111 = (NODE)->hash_value; \
233 \
234 HASH_DELETE(TYPE, NAME, TABLE, hash_value111, NODE); \
235 \
236 top_node111 = \
237 (TYPE *)mem_heap_get_top(hash_get_heap(TABLE), sizeof(TYPE)); \
238 \
239 /* If the node to remove is not the top node in the heap, compact the \
240 heap of nodes by moving the top node in the place of NODE. */ \
241 \
242 if (NODE != top_node111) { \
243 /* Copy the top node in place of NODE */ \
244 \
245 *(NODE) = *top_node111; \
246 \
247 cell111 = hash_get_nth_cell( \
248 TABLE, hash_calc_cell_id(top_node111->hash_value, TABLE)); \
249 \
250 /* Look for the pointer to the top node, to update it */ \
251 \
252 if (cell111->node == top_node111) { \
253 /* The top node is the first in the chain */ \
254 \
255 cell111->node = NODE; \
256 } else { \
257 /* We have to look for the predecessor of the top \
258 node */ \
259 node111 = static_cast<TYPE *>(cell111->node); \
260 \
261 while (top_node111 != HASH_GET_NEXT(NAME, node111)) { \
262 node111 = static_cast<TYPE *>(HASH_GET_NEXT(NAME, node111)); \
263 } \
264 \
265 /* Now we have the predecessor node */ \
266 \
267 node111->NAME = NODE; \
268 } \
269 } \
270 \
271 /* Free the space occupied by the top node */ \
272 \
273 mem_heap_free_top(hash_get_heap(TABLE), sizeof(TYPE)); \
274 } while (0)
275
276#ifndef UNIV_HOTBACKUP
277/** Move all hash table entries from OLD_TABLE to NEW_TABLE. */
278
279#define HASH_MIGRATE(OLD_TABLE, NEW_TABLE, NODE_TYPE, PTR_NAME, HASH_FUNC) \
280 do { \
281 size_t i2222; \
282 size_t cell_count2222; \
283 \
284 cell_count2222 = hash_get_n_cells(OLD_TABLE); \
285 \
286 for (i2222 = 0; i2222 < cell_count2222; i2222++) { \
287 NODE_TYPE *node2222 = \
288 static_cast<NODE_TYPE *>(hash_get_first((OLD_TABLE), i2222)); \
289 \
290 while (node2222) { \
291 NODE_TYPE *next2222 = static_cast<NODE_TYPE *>(node2222->PTR_NAME); \
292 uint64_t hash_value2222 = HASH_FUNC(node2222); \
293 \
294 HASH_INSERT(NODE_TYPE, PTR_NAME, (NEW_TABLE), hash_value2222, \
295 node2222); \
296 \
297 node2222 = next2222; \
298 } \
299 } \
300 } while (0)
301
302/** Gets the sync object index for a hash value in a hash table.
303@param[in] table hash table
304@param[in] hash_value hash value
305@return index */
306static inline uint64_t hash_get_sync_obj_index(hash_table_t *table,
307 uint64_t hash_value);
308
309/** Gets the heap for a hash value in a hash table.
310@param[in] table hash table
311@return mem heap */
313
314/** Gets the nth rw_lock in a hash table.
315@param[in] table hash table
316@param[in] i index of the rw_lock
317@return rw_lock */
318static inline rw_lock_t *hash_get_nth_lock(hash_table_t *table, size_t i);
319
320/** Gets the rw_lock for a hash value in a hash table.
321@param[in] table hash table
322@param[in] hash_value hash value
323@return rw_lock */
325 uint64_t hash_value);
326
327/** If not appropriate rw_lock for a hash value in a hash table,
328relock S-lock the another rw_lock until appropriate for a hash value.
329@param[in] hash_lock latched rw_lock to be confirmed
330@param[in] table hash table
331@param[in] hash_value hash value
332@return latched rw_lock */
333static inline rw_lock_t *hash_lock_s_confirm(rw_lock_t *hash_lock,
335 uint64_t hash_value);
336
337/** If not appropriate rw_lock for a hash value in a hash table,
338relock X-lock the another rw_lock until appropriate for a hash value.
339@param[in] hash_lock latched rw_lock to be confirmed
340@param[in] table hash table
341@param[in] hash_value hash value
342@return latched rw_lock */
343static inline rw_lock_t *hash_lock_x_confirm(rw_lock_t *hash_lock,
345 uint64_t hash_value);
346
347#ifdef UNIV_DEBUG
348
349/** Verifies that the current thread holds X-latch on all shards.
350Assumes type==HASH_TABLE_SYNC_RW_LOCK.
351@param[in] table the table in question
352@return true iff the current thread holds X-latch on all shards*/
354
355#endif /* UNIV_DEBUG */
356
357/** Reserves all the locks of a hash table, in an ascending order. */
358void hash_lock_x_all(hash_table_t *table); /*!< in: hash table */
359
360/** Releases all the locks of a hash table, in an ascending order. */
361void hash_unlock_x_all(hash_table_t *table); /*!< in: hash table */
362
363/** Releases all but passed in lock of a hash table,
364@param[in] table Hash table
365@param[in] keep_lock Lock to keep */
367
368#else /* !UNIV_HOTBACKUP */
369#define hash_get_heap(table) ((table)->heap)
370#define hash_lock_x_all(t) ((void)0)
371#define hash_unlock_x_all(t) ((void)0)
372#define hash_unlock_x_all_but(t, l) ((void)0)
373#endif /* !UNIV_HOTBACKUP */
375/* The hash table structure */
377 public:
378 hash_table_t(size_t n) {
379 const auto prime = ut::find_prime(n);
380 cells = ut::make_unique<hash_cell_t[]>(prime);
381 set_n_cells(prime);
382
383 /* Initialize the cell array */
385 }
387
388 /** Returns number of cells in cells[] array.
389 If type==HASH_TABLE_SYNC_RW_LOCK it can be used:
390 - without any latches to peek a value, before hash_lock_[sx]_confirm
391 - when holding S-latch for at least one n_sync_obj to get the "real" value
392 @return value of n_cells
393 */
394 size_t get_n_cells() { return n_cells.load(std::memory_order_relaxed); }
395
396 /** Returns a helper class for calculating fast modulo n_cells.
397 If type==HASH_TABLE_SYNC_RW_LOCK it can be used:
398 - without any latches to peek a value, before hash_lock_[sx]_confirm
399 - when holding S-latch for at least one n_sync_obj to get the "real" value */
401 return n_cells_fast_modulo.load();
402 }
403
404 /** Sets the number of n_cells, to the provided one.
405 If type==HASH_TABLE_SYNC_RW_LOCK it can be used only when holding x-latches on
406 all shards.
407 @param[in] n The new size of cells[] array
408 */
409 void set_n_cells(size_t n) {
410#ifndef UNIV_HOTBACKUP
412#endif
413 n_cells.store(n);
415 }
416
417 public:
418 /** Either:
419 a) HASH_TABLE_SYNC_NONE in which case n_sync_obj is 0 and rw_locks is nullptr
420 or
421 b) HASH_TABLE_SYNC_RW_LOCK in which case n_sync_obj > 0 is the number of
422 rw_locks elements, each of which protects a disjoint fraction of cells.
423 The default type of hash_table is HASH_TABLE_SYNC_NONE i.e.: the caller is
424 responsible for access control to the table. */
426
427#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
428#ifndef UNIV_HOTBACKUP
429 /* true if this is the hash table of the adaptive hash index */
430 bool adaptive = false;
431#endif /* !UNIV_HOTBACKUP */
432#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
433 private:
434 /** The number of cells in the hash table.
435 If type==HASH_TABLE_SYNC_RW_LOCK it is:
436 - modified when holding X-latches on all n_sync_obj
437 - read
438 - without any latches to peek a value, before hash_lock_[sx]_confirm
439 - when holding S-latch for at least one n_sync_obj to get the "real" value
440 */
441 std::atomic<size_t> n_cells;
442 /** Utility to calculate the modulo n_cells fast. It is set together with
443 n_cells. It can be read without latches in parallel to set_n_cells, and as it
444 is a complex object, it is not set atomically. Because of this the
445 multi-threaded version is used. */
447
448 public:
449 /** The pointer to the array of cells.
450 If type==HASH_TABLE_SYNC_RW_LOCK it is:
451 - modified when holding X-latches on all n_sync_obj
452 - read when holding an S-latch for at least one n_sync_obj
453 */
455#ifndef UNIV_HOTBACKUP
456 /** if rw_locks != nullptr, then it's their number (must be a power of two).
457 Otherwise, 0. Is zero iff the type is HASH_TABLE_SYNC_NONE. */
458 size_t n_sync_obj = 0;
459 /** nullptr, or an array of n_sync_obj rw_locks used to protect segments of
460 the hash table. Is nullptr iff the type is HASH_TABLE_SYNC_NONE. */
461 rw_lock_t *rw_locks = nullptr;
463#endif /* !UNIV_HOTBACKUP */
464 mem_heap_t *heap = nullptr;
465#ifdef UNIV_DEBUG
466 static constexpr uint32_t HASH_TABLE_MAGIC_N = 76561114;
467 uint32_t magic_n = HASH_TABLE_MAGIC_N;
468#endif /* UNIV_DEBUG */
469};
470
471#include "hash0hash.ic"
472
473#endif
Definition: hash0hash.h:374
static constexpr uint32_t HASH_TABLE_MAGIC_N
Definition: hash0hash.h:464
hash_table_t(size_t n)
Definition: hash0hash.h:376
size_t n_sync_obj
if rw_locks != nullptr, then it's their number (must be a power of two).
Definition: hash0hash.h:456
uint32_t magic_n
Definition: hash0hash.h:465
void set_n_cells(size_t n)
Sets the number of n_cells, to the provided one.
Definition: hash0hash.h:407
enum hash_table_sync_t type
Either: a) HASH_TABLE_SYNC_NONE in which case n_sync_obj is 0 and rw_locks is nullptr or b) HASH_TABL...
Definition: hash0hash.h:423
rw_lock_t * rw_locks
nullptr, or an array of n_sync_obj rw_locks used to protect segments of the hash table.
Definition: hash0hash.h:459
ut::mt_fast_modulo_t n_cells_fast_modulo
Utility to calculate the modulo n_cells fast.
Definition: hash0hash.h:444
bool adaptive
Definition: hash0hash.h:428
std::atomic< size_t > n_cells
The number of cells in the hash table.
Definition: hash0hash.h:439
const ut::fast_modulo_t get_n_cells_fast_modulo()
Returns a helper class for calculating fast modulo n_cells.
Definition: hash0hash.h:398
~hash_table_t()
Definition: hash0hash.h:384
size_t get_n_cells()
Returns number of cells in cells[] array.
Definition: hash0hash.h:392
ut::unique_ptr< hash_cell_t[]> cells
The pointer to the array of cells.
Definition: hash0hash.h:452
mem_heap_t * heap
Definition: hash0hash.h:462
Allows to execute x % mod for a specified mod in a fast way, without using a slow operation of divisi...
Definition: ut0math.h:145
A class that allows to atomically set new modulo value for fast modulo computations.
Definition: ut0math.h:237
fast_modulo_t load()
Definition: ut0math.h:245
void store(uint64_t new_mod)
Definition: ut0math.h:252
void * hash_node_t
Definition: hash0hash.h:47
static rw_lock_t * hash_lock_s_confirm(rw_lock_t *hash_lock, hash_table_t *table, uint64_t hash_value)
If not appropriate rw_lock for a hash value in a hash table, relock S-lock the another rw_lock until ...
void hash_unlock_x_all_but(hash_table_t *table, rw_lock_t *keep_lock)
Releases all but passed in lock of a hash table,.
Definition: hash0hash.cc:84
static void *& hash_get_first(hash_table_t *table, size_t cell_id)
Gets the first struct in a hash chain, NULL if none.
Definition: hash0hash.h:159
static rw_lock_t * hash_lock_x_confirm(rw_lock_t *hash_lock, hash_table_t *table, uint64_t hash_value)
If not appropriate rw_lock for a hash value in a hash table, relock X-lock the another rw_lock until ...
static uint64_t hash_get_sync_obj_index(hash_table_t *table, uint64_t hash_value)
Gets the sync object index for a hash value in a hash table.
hash_table_sync_t
Definition: hash0hash.h:53
@ HASH_TABLE_SYNC_RW_LOCK
Use rw_locks to control access to this hash_table.
Definition: hash0hash.h:57
@ HASH_TABLE_SYNC_NONE
Don't use any internal synchronization objects for this hash_table.
Definition: hash0hash.h:54
static hash_cell_t * hash_get_nth_cell(hash_table_t *table, size_t n)
Gets the nth cell in a hash table.
void hash_lock_x_all(hash_table_t *table)
Reserves all the locks of a hash table, in an ascending order.
Definition: hash0hash.cc:55
static uint64_t hash_calc_cell_id(uint64_t hash_value, hash_table_t *table)
Calculates the cell index from a hashed value for a specified hash table.
static rw_lock_t * hash_get_lock(hash_table_t *table, uint64_t hash_value)
Gets the rw_lock for a hash value in a hash table.
static mem_heap_t * hash_get_heap(hash_table_t *table)
Gets the heap for a hash value in a hash table.
static rw_lock_t * hash_get_nth_lock(hash_table_t *table, size_t i)
Gets the nth rw_lock in a hash table.
bool hash_lock_has_all_x(const hash_table_t *table)
Verifies that the current thread holds X-latch on all shards.
Definition: hash0hash.cc:43
static void hash_table_clear(hash_table_t *table)
Clears a hash table so that all the cells become empty.
void hash_create_sync_obj(hash_table_t *table, latch_id_t id, size_t n_sync_obj)
Creates a sync object array to protect a hash table.
Definition: hash0hash.cc:104
static size_t hash_get_n_cells(hash_table_t *table)
Returns the number of cells in a hash table.
void hash_unlock_x_all(hash_table_t *table)
Releases all the locks of a hash table, in an ascending order.
Definition: hash0hash.cc:70
The simple hash table utility.
The memory management.
static PFS_engine_table_share_proxy table
Definition: pfs.cc:61
uint64_t find_prime(uint64_t n)
Looks for a prime number slightly greater than the given argument.
Definition: ut0math.cc:36
std::conditional_t< !std::is_array< T >::value, std::unique_ptr< T, detail::Deleter< T > >, std::conditional_t< detail::is_unbounded_array_v< T >, std::unique_ptr< T, detail::Array_deleter< std::remove_extent_t< T > > >, void > > unique_ptr
The following is a common type that is returned by all the ut::make_unique (non-aligned) specializati...
Definition: ut0new.h:2438
Definition: hash0hash.h:61
void * node
hash chain node, NULL if none
Definition: hash0hash.h:62
The info structure stored at the beginning of a heap block.
Definition: mem0mem.h:302
The structure used in the spin lock implementation of a read-write lock.
Definition: sync0rw.h:363
The read-write lock (for threads, not for database transactions)
latch_id_t
Each latch has an ID.
Definition: sync0types.h:343
Version control for database, common definitions, and include files.
#define ut_ad(EXPR)
Debug assertion.
Definition: ut0dbg.h:105
Random numbers and hashing.
int n
Definition: xcom_base.cc:509