| 1 | /***************************************************************************** |
| 2 | |
| 3 | Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved. |
| 4 | |
| 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. |
| 8 | |
| 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. |
| 12 | |
| 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 Street, Suite 500, Boston, MA 02110-1335 USA |
| 16 | |
| 17 | *****************************************************************************/ |
| 18 | |
| 19 | /**************************************************//** |
| 20 | @file ha/hash0hash.cc |
| 21 | The simple hash table utility |
| 22 | |
| 23 | Created 5/20/1997 Heikki Tuuri |
| 24 | *******************************************************/ |
| 25 | |
| 26 | #include "hash0hash.h" |
| 27 | #include "mem0mem.h" |
| 28 | #include "sync0sync.h" |
| 29 | |
| 30 | /************************************************************//** |
| 31 | Reserves all the locks of a hash table, in an ascending order. */ |
| 32 | void |
| 33 | hash_lock_x_all( |
| 34 | /*============*/ |
| 35 | hash_table_t* table) /*!< in: hash table */ |
| 36 | { |
| 37 | ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK); |
| 38 | |
| 39 | for (ulint i = 0; i < table->n_sync_obj; i++) { |
| 40 | |
| 41 | rw_lock_t* lock = table->sync_obj.rw_locks + i; |
| 42 | |
| 43 | ut_ad(!rw_lock_own(lock, RW_LOCK_S)); |
| 44 | ut_ad(!rw_lock_own(lock, RW_LOCK_X)); |
| 45 | |
| 46 | rw_lock_x_lock(lock); |
| 47 | } |
| 48 | } |
| 49 | |
| 50 | /************************************************************//** |
| 51 | Releases all the locks of a hash table, in an ascending order. */ |
| 52 | void |
| 53 | hash_unlock_x_all( |
| 54 | /*==============*/ |
| 55 | hash_table_t* table) /*!< in: hash table */ |
| 56 | { |
| 57 | ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK); |
| 58 | |
| 59 | for (ulint i = 0; i < table->n_sync_obj; i++) { |
| 60 | |
| 61 | rw_lock_t* lock = table->sync_obj.rw_locks + i; |
| 62 | |
| 63 | ut_ad(rw_lock_own(lock, RW_LOCK_X)); |
| 64 | |
| 65 | rw_lock_x_unlock(lock); |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | /************************************************************//** |
| 70 | Releases all but passed in lock of a hash table, */ |
| 71 | void |
| 72 | hash_unlock_x_all_but( |
| 73 | /*==================*/ |
| 74 | hash_table_t* table, /*!< in: hash table */ |
| 75 | rw_lock_t* keep_lock) /*!< in: lock to keep */ |
| 76 | { |
| 77 | ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK); |
| 78 | |
| 79 | for (ulint i = 0; i < table->n_sync_obj; i++) { |
| 80 | |
| 81 | rw_lock_t* lock = table->sync_obj.rw_locks + i; |
| 82 | |
| 83 | ut_ad(rw_lock_own(lock, RW_LOCK_X)); |
| 84 | |
| 85 | if (keep_lock != lock) { |
| 86 | rw_lock_x_unlock(lock); |
| 87 | } |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | /*************************************************************//** |
| 92 | Creates a hash table with >= n array cells. The actual number of cells is |
| 93 | chosen to be a prime number slightly bigger than n. |
| 94 | @return own: created table */ |
| 95 | hash_table_t* |
| 96 | hash_create( |
| 97 | /*========*/ |
| 98 | ulint n) /*!< in: number of array cells */ |
| 99 | { |
| 100 | hash_cell_t* array; |
| 101 | ulint prime; |
| 102 | hash_table_t* table; |
| 103 | |
| 104 | prime = ut_find_prime(n); |
| 105 | |
| 106 | table = static_cast<hash_table_t*>( |
| 107 | ut_malloc_nokey(sizeof(hash_table_t))); |
| 108 | |
| 109 | array = static_cast<hash_cell_t*>( |
| 110 | ut_malloc_nokey(sizeof(hash_cell_t) * prime)); |
| 111 | |
| 112 | /* The default type of hash_table is HASH_TABLE_SYNC_NONE i.e.: |
| 113 | the caller is responsible for access control to the table. */ |
| 114 | table->type = HASH_TABLE_SYNC_NONE; |
| 115 | table->array = array; |
| 116 | table->n_cells = prime; |
| 117 | #ifdef BTR_CUR_HASH_ADAPT |
| 118 | # if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG |
| 119 | table->adaptive = FALSE; |
| 120 | # endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ |
| 121 | #endif /* BTR_CUR_HASH_ADAPT */ |
| 122 | table->n_sync_obj = 0; |
| 123 | table->sync_obj.mutexes = NULL; |
| 124 | table->heaps = NULL; |
| 125 | table->heap = NULL; |
| 126 | ut_d(table->magic_n = HASH_TABLE_MAGIC_N); |
| 127 | |
| 128 | /* Initialize the cell array */ |
| 129 | hash_table_clear(table); |
| 130 | |
| 131 | return(table); |
| 132 | } |
| 133 | |
| 134 | /*************************************************************//** |
| 135 | Frees a hash table. */ |
| 136 | void |
| 137 | hash_table_free( |
| 138 | /*============*/ |
| 139 | hash_table_t* table) /*!< in, own: hash table */ |
| 140 | { |
| 141 | ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); |
| 142 | |
| 143 | ut_free(table->array); |
| 144 | ut_free(table); |
| 145 | } |
| 146 | |
| 147 | /*************************************************************//** |
| 148 | Creates a sync object array to protect a hash table. |
| 149 | ::sync_obj can be mutexes or rw_locks depening on the type of |
| 150 | hash table. */ |
| 151 | void |
| 152 | hash_create_sync_obj( |
| 153 | /*=================*/ |
| 154 | hash_table_t* table, /*!< in: hash table */ |
| 155 | enum hash_table_sync_t type, /*!< in: HASH_TABLE_SYNC_MUTEX |
| 156 | or HASH_TABLE_SYNC_RW_LOCK */ |
| 157 | latch_id_t id, /*!< in: latch ID */ |
| 158 | ulint n_sync_obj)/*!< in: number of sync objects, |
| 159 | must be a power of 2 */ |
| 160 | { |
| 161 | ut_a(n_sync_obj > 0); |
| 162 | ut_a(ut_is_2pow(n_sync_obj)); |
| 163 | ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); |
| 164 | |
| 165 | table->type = type; |
| 166 | |
| 167 | switch (table->type) { |
| 168 | case HASH_TABLE_SYNC_MUTEX: |
| 169 | table->sync_obj.mutexes = static_cast<ib_mutex_t*>( |
| 170 | ut_malloc_nokey(n_sync_obj * sizeof(ib_mutex_t))); |
| 171 | |
| 172 | for (ulint i = 0; i < n_sync_obj; i++) { |
| 173 | mutex_create(id, table->sync_obj.mutexes + i); |
| 174 | } |
| 175 | |
| 176 | break; |
| 177 | |
| 178 | case HASH_TABLE_SYNC_RW_LOCK: { |
| 179 | |
| 180 | latch_level_t level = sync_latch_get_level(id); |
| 181 | |
| 182 | ut_a(level != SYNC_UNKNOWN); |
| 183 | |
| 184 | table->sync_obj.rw_locks = static_cast<rw_lock_t*>( |
| 185 | ut_malloc_nokey(n_sync_obj * sizeof(rw_lock_t))); |
| 186 | |
| 187 | for (ulint i = 0; i < n_sync_obj; i++) { |
| 188 | rw_lock_create(hash_table_locks_key, |
| 189 | table->sync_obj.rw_locks + i, level); |
| 190 | } |
| 191 | |
| 192 | break; |
| 193 | } |
| 194 | |
| 195 | case HASH_TABLE_SYNC_NONE: |
| 196 | ut_error; |
| 197 | } |
| 198 | |
| 199 | table->n_sync_obj = n_sync_obj; |
| 200 | } |
| 201 | |