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