MySQL 9.1.0
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,
80 hash_table_t const *table);
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(
221 hash_table_t const *table); /*!< in: table */
222
223/** Deletes a struct which is stored in the heap of the hash table, and compacts
224 the heap. The hash value must be stored in the struct NODE in a field named
225 'hash_value'. */
226#define HASH_DELETE_AND_COMPACT(TYPE, NAME, TABLE, NODE) \
227 do { \
228 TYPE *node111; \
229 TYPE *top_node111; \
230 hash_cell_t *cell111; \
231 uint64_t hash_value111; \
232 \
233 hash_value111 = (NODE)->hash_value; \
234 \
235 HASH_DELETE(TYPE, NAME, TABLE, hash_value111, NODE); \
236 \
237 top_node111 = \
238 (TYPE *)mem_heap_get_top(hash_get_heap(TABLE), sizeof(TYPE)); \
239 \
240 /* If the node to remove is not the top node in the heap, compact the \
241 heap of nodes by moving the top node in the place of NODE. */ \
242 \
243 if (NODE != top_node111) { \
244 /* Copy the top node in place of NODE */ \
245 \
246 *(NODE) = *top_node111; \
247 \
248 cell111 = hash_get_nth_cell( \
249 TABLE, hash_calc_cell_id(top_node111->hash_value, TABLE)); \
250 \
251 /* Look for the pointer to the top node, to update it */ \
252 \
253 if (cell111->node == top_node111) { \
254 /* The top node is the first in the chain */ \
255 \
256 cell111->node = NODE; \
257 } else { \
258 /* We have to look for the predecessor of the top \
259 node */ \
260 node111 = static_cast<TYPE *>(cell111->node); \
261 \
262 while (top_node111 != HASH_GET_NEXT(NAME, node111)) { \
263 node111 = static_cast<TYPE *>(HASH_GET_NEXT(NAME, node111)); \
264 } \
265 \
266 /* Now we have the predecessor node */ \
267 \
268 node111->NAME = NODE; \
269 } \
270 } \
271 \
272 /* Free the space occupied by the top node */ \
273 \
274 mem_heap_free_top(hash_get_heap(TABLE), sizeof(TYPE)); \
275 } while (0)
276
277#ifndef UNIV_HOTBACKUP
278/** Move all hash table entries from OLD_TABLE to NEW_TABLE. */
279
280#define HASH_MIGRATE(OLD_TABLE, NEW_TABLE, NODE_TYPE, PTR_NAME, HASH_FUNC) \
281 do { \
282 size_t i2222; \
283 size_t cell_count2222; \
284 \
285 cell_count2222 = hash_get_n_cells(OLD_TABLE); \
286 \
287 for (i2222 = 0; i2222 < cell_count2222; i2222++) { \
288 NODE_TYPE *node2222 = \
289 static_cast<NODE_TYPE *>(hash_get_first((OLD_TABLE), i2222)); \
290 \
291 while (node2222) { \
292 NODE_TYPE *next2222 = static_cast<NODE_TYPE *>(node2222->PTR_NAME); \
293 uint64_t hash_value2222 = HASH_FUNC(node2222); \
294 \
295 HASH_INSERT(NODE_TYPE, PTR_NAME, (NEW_TABLE), hash_value2222, \
296 node2222); \
297 \
298 node2222 = next2222; \
299 } \
300 } \
301 } while (0)
302
303/** Gets the sync object index for a hash value in a hash table.
304@param[in] table hash table
305@param[in] hash_value hash value
306@return index */
307static inline uint64_t hash_get_sync_obj_index(hash_table_t *table,
308 uint64_t hash_value);
309
310/** Gets the heap for a hash value in a hash table.
311@param[in] table hash table
312@return mem heap */
314
315/** Gets the nth rw_lock in a hash table.
316@param[in] table hash table
317@param[in] i index of the rw_lock
318@return rw_lock */
319static inline rw_lock_t *hash_get_nth_lock(hash_table_t *table, size_t i);
320
321/** Gets the rw_lock for a hash value in a hash table.
322@param[in] table hash table
323@param[in] hash_value hash value
324@return rw_lock */
326 uint64_t hash_value);
327
328/** If not appropriate rw_lock for a hash value in a hash table,
329relock S-lock the another rw_lock until appropriate for a hash value.
330@param[in] hash_lock latched rw_lock to be confirmed
331@param[in] table hash table
332@param[in] hash_value hash value
333@return latched rw_lock */
334static inline rw_lock_t *hash_lock_s_confirm(rw_lock_t *hash_lock,
336 uint64_t hash_value);
337
338/** If not appropriate rw_lock for a hash value in a hash table,
339relock X-lock the another rw_lock until appropriate for a hash value.
340@param[in] hash_lock latched rw_lock to be confirmed
341@param[in] table hash table
342@param[in] hash_value hash value
343@return latched rw_lock */
344static inline rw_lock_t *hash_lock_x_confirm(rw_lock_t *hash_lock,
346 uint64_t hash_value);
347
348#ifdef UNIV_DEBUG
349
350/** Verifies that the current thread holds X-latch on all shards.
351Assumes type==HASH_TABLE_SYNC_RW_LOCK.
352@param[in] table the table in question
353@return true iff the current thread holds X-latch on all shards*/
355
356#endif /* UNIV_DEBUG */
357
358/** Reserves all the locks of a hash table, in an ascending order. */
359void hash_lock_x_all(hash_table_t *table); /*!< in: hash table */
360
361/** Releases all the locks of a hash table, in an ascending order. */
362void hash_unlock_x_all(hash_table_t *table); /*!< in: hash table */
363
364/** Releases all but passed in lock of a hash table,
365@param[in] table Hash table
366@param[in] keep_lock Lock to keep */
368
369#else /* !UNIV_HOTBACKUP */
370#define hash_get_heap(table) ((table)->heap)
371#define hash_lock_x_all(t) ((void)0)
372#define hash_unlock_x_all(t) ((void)0)
373#define hash_unlock_x_all_but(t, l) ((void)0)
374#endif /* !UNIV_HOTBACKUP */
376/* The hash table structure */
378 public:
379 hash_table_t(size_t n) {
380 const auto prime = ut::find_prime(n);
381 cells = ut::make_unique<hash_cell_t[]>(prime);
382 set_n_cells(prime);
383
384 /* Initialize the cell array */
386 }
388
389 /** Returns number of cells in cells[] array.
390 If type==HASH_TABLE_SYNC_RW_LOCK it can be used:
391 - without any latches to peek a value, before hash_lock_[sx]_confirm
392 - when holding S-latch for at least one n_sync_obj to get the "real" value
393 @return value of n_cells
394 */
395 size_t get_n_cells() const { return n_cells.load(std::memory_order_relaxed); }
396
397 /** Returns a helper class for calculating fast modulo n_cells.
398 If type==HASH_TABLE_SYNC_RW_LOCK it can be used:
399 - without any latches to peek a value, before hash_lock_[sx]_confirm
400 - when holding S-latch for at least one n_sync_obj to get the "real" value */
402 return n_cells_fast_modulo.load();
403 }
404
405 /** Sets the number of n_cells, to the provided one.
406 If type==HASH_TABLE_SYNC_RW_LOCK it can be used only when holding x-latches on
407 all shards.
408 @param[in] n The new size of cells[] array
409 */
410 void set_n_cells(size_t n) {
411#ifndef UNIV_HOTBACKUP
413#endif
414 n_cells.store(n);
416 }
417
418 public:
419 /** Either:
420 a) HASH_TABLE_SYNC_NONE in which case n_sync_obj is 0 and rw_locks is nullptr
421 or
422 b) HASH_TABLE_SYNC_RW_LOCK in which case n_sync_obj > 0 is the number of
423 rw_locks elements, each of which protects a disjoint fraction of cells.
424 The default type of hash_table is HASH_TABLE_SYNC_NONE i.e.: the caller is
425 responsible for access control to the table. */
427
428#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
429#ifndef UNIV_HOTBACKUP
430 /* true if this is the hash table of the adaptive hash index */
431 bool adaptive = false;
432#endif /* !UNIV_HOTBACKUP */
433#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
434 private:
435 /** The number of cells in the hash table.
436 If type==HASH_TABLE_SYNC_RW_LOCK it is:
437 - modified when holding X-latches on all n_sync_obj
438 - read
439 - without any latches to peek a value, before hash_lock_[sx]_confirm
440 - when holding S-latch for at least one n_sync_obj to get the "real" value
441 */
442 std::atomic<size_t> n_cells;
443 /** Utility to calculate the modulo n_cells fast. It is set together with
444 n_cells. It can be read without latches in parallel to set_n_cells, and as it
445 is a complex object, it is not set atomically. Because of this the
446 multi-threaded version is used. */
448
449 public:
450 /** The pointer to the array of cells.
451 If type==HASH_TABLE_SYNC_RW_LOCK it is:
452 - modified when holding X-latches on all n_sync_obj
453 - read when holding an S-latch for at least one n_sync_obj
454 */
456#ifndef UNIV_HOTBACKUP
457 /** if rw_locks != nullptr, then it's their number (must be a power of two).
458 Otherwise, 0. Is zero iff the type is HASH_TABLE_SYNC_NONE. */
459 size_t n_sync_obj = 0;
460 /** nullptr, or an array of n_sync_obj rw_locks used to protect segments of
461 the hash table. Is nullptr iff the type is HASH_TABLE_SYNC_NONE. */
462 rw_lock_t *rw_locks = nullptr;
464#endif /* !UNIV_HOTBACKUP */
465 mem_heap_t *heap = nullptr;
466#ifdef UNIV_DEBUG
467 static constexpr uint32_t HASH_TABLE_MAGIC_N = 76561114;
468 uint32_t magic_n = HASH_TABLE_MAGIC_N;
469#endif /* UNIV_DEBUG */
470};
471
472#include "hash0hash.ic"
473
474#endif
Definition: hash0hash.h:375
static constexpr uint32_t HASH_TABLE_MAGIC_N
Definition: hash0hash.h:465
hash_table_t(size_t n)
Definition: hash0hash.h:377
size_t get_n_cells() const
Returns number of cells in cells[] array.
Definition: hash0hash.h:393
size_t n_sync_obj
if rw_locks != nullptr, then it's their number (must be a power of two).
Definition: hash0hash.h:457
uint32_t magic_n
Definition: hash0hash.h:466
void set_n_cells(size_t n)
Sets the number of n_cells, to the provided one.
Definition: hash0hash.h:408
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:424
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:460
ut::mt_fast_modulo_t n_cells_fast_modulo
Utility to calculate the modulo n_cells fast.
Definition: hash0hash.h:445
bool adaptive
Definition: hash0hash.h:429
std::atomic< size_t > n_cells
The number of cells in the hash table.
Definition: hash0hash.h:440
const ut::fast_modulo_t get_n_cells_fast_modulo() const
Returns a helper class for calculating fast modulo n_cells.
Definition: hash0hash.h:399
~hash_table_t()
Definition: hash0hash.h:385
ut::unique_ptr< hash_cell_t[]> cells
The pointer to the array of cells.
Definition: hash0hash.h:453
mem_heap_t * heap
Definition: hash0hash.h:463
Allows to execute x % mod for a specified mod in a fast way, without using a slow operation of divisi...
Definition: ut0math.h:165
A class that allows to atomically set new modulo value for fast modulo computations.
Definition: ut0math.h:257
void store(uint64_t new_mod)
Definition: ut0math.h:272
fast_modulo_t load() const
Definition: ut0math.h:265
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 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.
static uint64_t hash_calc_cell_id(uint64_t hash_value, hash_table_t const *table)
Calculates the cell index from a hashed value for a specified 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 const *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:2440
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:345
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