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, Fifth Floor, 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
hash_lock_x_all(hash_table_t * table)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
hash_unlock_x_all(hash_table_t * table)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
hash_unlock_x_all_but(hash_table_t * table,rw_lock_t * keep_lock)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*
hash_create(ulint n)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
hash_table_free(hash_table_t * table)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
hash_create_sync_obj(hash_table_t * table,enum hash_table_sync_t type,latch_id_t id,ulint n_sync_obj)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