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 | |