1/*****************************************************************************
2
3Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved.
4
5This program is free software; you can redistribute it and/or modify it under
6the terms of the GNU General Public License as published by the Free Software
7Foundation; version 2 of the License.
8
9This program is distributed in the hope that it will be useful, but WITHOUT
10ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
13You should have received a copy of the GNU General Public License along with
14this program; if not, write to the Free Software Foundation, Inc.,
1551 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
16
17*****************************************************************************/
18
19/**************************************************//**
20@file ha/hash0hash.cc
21The simple hash table utility
22
23Created 5/20/1997 Heikki Tuuri
24*******************************************************/
25
26#include "hash0hash.h"
27#include "mem0mem.h"
28#include "sync0sync.h"
29
30/************************************************************//**
31Reserves all the locks of a hash table, in an ascending order. */
32void
33hash_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/************************************************************//**
51Releases all the locks of a hash table, in an ascending order. */
52void
53hash_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/************************************************************//**
70Releases all but passed in lock of a hash table, */
71void
72hash_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/*************************************************************//**
92Creates a hash table with >= n array cells. The actual number of cells is
93chosen to be a prime number slightly bigger than n.
94@return own: created table */
95hash_table_t*
96hash_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/*************************************************************//**
135Frees a hash table. */
136void
137hash_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/*************************************************************//**
148Creates a sync object array to protect a hash table.
149::sync_obj can be mutexes or rw_locks depening on the type of
150hash table. */
151void
152hash_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