Motr  M0
hash.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2013-2020 Seagate Technology LLC and/or its Affiliates
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * For any questions about this software or licensing,
18  * please email opensource@seagate.com or cortx-questions@seagate.com.
19  *
20  */
21 
22 
28 #include "lib/bob.h" /* m0_bob_type */
29 #include "lib/hash.h" /* m0_htable */
30 #include "lib/errno.h" /* Include appropriate errno.h header. */
31 #include "lib/arith.h" /* min64u() */
32 #include "lib/memory.h" /* M0_ALLOC_ARR() */
33 #include "lib/misc.h" /* m0_forall() */
34 
35 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_LIB
36 #include "lib/trace.h"
37 
38 static const struct m0_bob_type htable_bobtype;
40 
41 static const struct m0_bob_type htable_bobtype = {
42  .bt_name = "hashtable",
43  .bt_magix_offset = offsetof(struct m0_htable, h_magic),
44  .bt_magix = M0_LIB_HASHLIST_MAGIC,
45  .bt_check = NULL,
46 };
47 
48 static bool htable_invariant(const struct m0_htable *htable);
49 
50 static void hbucket_init(const struct m0_ht_descr *d,
51  struct m0_hbucket *bucket)
52 {
53  M0_PRE(bucket != NULL);
54  M0_PRE(d != NULL);
55 
56  m0_tlist_init(d->hd_tldescr, &bucket->hb_objects);
57  m0_mutex_init(&bucket->hb_mutex);
58 }
59 
60 static void hbucket_fini(const struct m0_ht_descr *d,
61  struct m0_hbucket *bucket)
62 {
63  M0_PRE(bucket != NULL);
64  M0_PRE(d != NULL);
65 
66  m0_tlist_fini(d->hd_tldescr, &bucket->hb_objects);
67  m0_mutex_fini(&bucket->hb_mutex);
68 }
69 
70 static void *obj_key(const struct m0_ht_descr *hd, void *obj)
71 {
72  return obj + hd->hd_key_offset;
73 }
74 
75 static bool hbucket_invariant(const struct m0_ht_descr *desc,
76  const struct m0_hbucket *bucket,
77  const struct m0_htable *htable)
78 {
79  uint64_t index;
80  void *amb;
81 
82  index = bucket - htable->h_buckets;
83 
84  return
85  bucket != NULL &&
86  desc != NULL &&
87  m0_hbucket_forall_ol(desc->hd_tldescr, amb, bucket,
88  index == desc->hd_hash_func(htable,
89  obj_key(desc, amb)));
90 }
91 
92 static bool htable_invariant(const struct m0_htable *htable)
93 {
94  return
95  m0_htable_bob_check(htable) &&
96  htable->h_bucket_nr > 0 &&
97  htable->h_buckets != NULL &&
98  m0_forall(i, htable->h_bucket_nr,
99  hbucket_invariant(htable->h_descr,
100  &htable->h_buckets[i], htable));
101 }
102 
103 M0_INTERNAL int m0_htable_init(const struct m0_ht_descr *d,
104  struct m0_htable *htable,
105  uint64_t bucket_nr)
106 {
107  uint64_t nr;
108 
109  M0_PRE(htable != NULL);
110  M0_PRE(d != NULL);
111  M0_PRE(bucket_nr > 0);
112 
113  m0_htable_bob_init(htable);
114 
115  htable->h_descr = d;
116  htable->h_bucket_nr = bucket_nr;
117  M0_ALLOC_ARR(htable->h_buckets, htable->h_bucket_nr);
118  if (htable->h_buckets == NULL)
119  return M0_ERR(-ENOMEM);
120 
121  for (nr = 0; nr < htable->h_bucket_nr; ++nr)
122  hbucket_init(d, &htable->h_buckets[nr]);
123  M0_POST_EX(htable_invariant(htable));
124  return 0;
125 }
126 
127 M0_INTERNAL bool m0_htable_is_init(const struct m0_htable *htable)
128 {
129  return htable_invariant(htable);
130 }
131 
132 M0_INTERNAL void m0_htable_add(struct m0_htable *htable,
133  void *amb)
134 {
135  uint64_t bucket_id;
136 
137  M0_PRE_EX(htable_invariant(htable));
138  M0_PRE(amb != NULL);
140 
141  bucket_id = htable->h_descr->hd_hash_func(htable,
142  obj_key(htable->h_descr, amb));
143 
145  &htable->h_buckets[bucket_id].hb_objects, amb);
146  M0_POST_EX(htable_invariant(htable));
148 }
149 
150 M0_INTERNAL void m0_htable_del(struct m0_htable *htable,
151  void *amb)
152 {
153  M0_PRE_EX(htable_invariant(htable));
154  M0_PRE(amb != NULL);
155 
156  m0_tlist_del(htable->h_descr->hd_tldescr, amb);
157 
158  M0_POST_EX(htable_invariant(htable));
160 }
161 
162 M0_INTERNAL void *m0_htable_lookup(const struct m0_htable *htable,
163  const void *key)
164 {
165  void *scan;
166  uint64_t bucket_id;
167 
168  M0_PRE_EX(htable_invariant(htable));
169 
170  bucket_id = htable->h_descr->hd_hash_func(htable, key);
171 
173  &htable->h_buckets[bucket_id].hb_objects, scan) {
174  if (htable->h_descr->hd_key_eq(obj_key(htable->h_descr, scan),
175  key))
176  break;
177  } m0_tlist_endfor;
178 
179  return scan;
180 }
181 
182 M0_INTERNAL void m0_htable_cc_add(struct m0_htable *htable,
183  void *amb)
184 {
185  M0_PRE(amb != NULL);
186 
187  m0_hbucket_lock(htable, obj_key(htable->h_descr, amb));
188  m0_htable_add(htable, amb);
189  m0_hbucket_unlock(htable, obj_key(htable->h_descr, amb));
190 }
191 
192 M0_INTERNAL void m0_htable_cc_del(struct m0_htable *htable,
193  void *amb)
194 {
195  M0_PRE(amb != NULL);
196 
197  m0_hbucket_lock(htable, obj_key(htable->h_descr, amb));
198  m0_htable_del(htable, amb);
199  m0_hbucket_unlock(htable, obj_key(htable->h_descr, amb));
200 }
201 
202 M0_INTERNAL void *m0_htable_cc_lookup(struct m0_htable *htable,
203  const void *key)
204 {
205  void *obj;
206 
207  M0_PRE(key != NULL);
208 
209  m0_hbucket_lock(htable, key);
210  obj = m0_htable_lookup(htable, key);
211  m0_hbucket_unlock(htable, key);
212  return obj;
213 }
214 
215 M0_INTERNAL void m0_hbucket_lock(struct m0_htable *htable,
216  const void *key)
217 {
218  uint64_t bucket_id;
219 
220  M0_PRE_EX(htable_invariant(htable));
221 
222  bucket_id = htable->h_descr->hd_hash_func(htable, key);
223  m0_mutex_lock(&htable->h_buckets[bucket_id].hb_mutex);
224 }
225 
226 M0_INTERNAL void m0_hbucket_unlock(struct m0_htable *htable,
227  const void *key)
228 {
229  uint64_t bucket_id;
230 
231  M0_PRE_EX(htable_invariant(htable));
232 
233  bucket_id = htable->h_descr->hd_hash_func(htable, key);
234  m0_mutex_unlock(&htable->h_buckets[bucket_id].hb_mutex);
235 }
236 
237 M0_INTERNAL void m0_htable_fini(struct m0_htable *htable)
238 {
239  uint64_t nr;
240 
241  M0_PRE_EX(htable_invariant(htable));
242 
243  for (nr = 0; nr < htable->h_bucket_nr; ++nr)
244  hbucket_fini(htable->h_descr, &htable->h_buckets[nr]);
245  m0_free(htable->h_buckets);
246  m0_htable_bob_fini(htable);
247  htable->h_buckets = NULL;
248  htable->h_bucket_nr = 0;
249  htable->h_descr = NULL;
250 }
251 
252 M0_INTERNAL bool m0_htable_is_empty(const struct m0_htable *htable)
253 {
254  uint64_t nr;
255 
256  M0_PRE_EX(htable_invariant(htable));
257 
258  for (nr = 0; nr < htable->h_bucket_nr; ++nr) {
259  if (!m0_tlist_is_empty(htable->h_descr->hd_tldescr,
260  &htable->h_buckets[nr].hb_objects))
261  break;
262  }
263  return nr == htable->h_bucket_nr;
264 }
265 
266 M0_INTERNAL uint64_t m0_htable_size(const struct m0_htable *htable)
267 {
268  uint64_t nr;
269  uint64_t len = 0;
270 
271  M0_PRE_EX(htable_invariant(htable));
272 
273  for (nr = 0; nr < htable->h_bucket_nr; ++nr)
274  len += m0_tlist_length(htable->h_descr->hd_tldescr,
275  &htable->h_buckets[nr].hb_objects);
276  return len;
277 }
278 
279 M0_INTERNAL uint64_t m0_hash(uint64_t x)
280 {
281  uint64_t y;
282 
283  y = x;
284  y <<= 18;
285  x -= y;
286  y <<= 33;
287  x -= y;
288  y <<= 3;
289  x += y;
290  y <<= 3;
291  x -= y;
292  y <<= 4;
293  x += y;
294  y <<= 2;
295 
296  return x + y;
297 }
298 
299 #undef M0_TRACE_SUBSYSTEM
300 
303 /*
304  * Local variables:
305  * c-indentation-style: "K&R"
306  * c-basic-offset: 8
307  * tab-width: 8
308  * fill-column: 80
309  * scroll-step: 1
310  * End:
311  */
static size_t nr
Definition: dump.c:1505
#define M0_PRE(cond)
#define M0_ALLOC_ARR(arr, nr)
Definition: memory.h:84
static bool hbucket_invariant(const struct m0_ht_descr *desc, const struct m0_hbucket *bucket, const struct m0_htable *htable)
Definition: hash.c:75
#define m0_hbucket_forall_ol(descr, var, bucket,...)
Definition: hash.h:508
M0_INTERNAL void m0_mutex_unlock(struct m0_mutex *mutex)
Definition: mutex.c:66
struct m0_mutex hb_mutex
Definition: hash.h:160
M0_INTERNAL void * m0_htable_lookup(const struct m0_htable *htable, const void *key)
Definition: hash.c:162
#define NULL
Definition: misc.h:38
Definition: module.c:324
static bool x
Definition: sm.c:168
static bool htable_invariant(const struct m0_htable *htable)
Definition: hash.c:92
M0_INTERNAL void m0_htable_cc_del(struct m0_htable *htable, void *amb)
Definition: hash.c:192
static struct foo amb[NR]
Definition: tlist.c:69
M0_INTERNAL void m0_tlist_add(const struct m0_tl_descr *d, struct m0_tl *list, void *obj)
Definition: tlist.c:125
M0_INTERNAL bool m0_htable_is_init(const struct m0_htable *htable)
Definition: hash.c:127
M0_INTERNAL void m0_tlist_init(const struct m0_tl_descr *d, struct m0_tl *list)
Definition: tlist.c:46
M0_INTERNAL void m0_tlist_fini(const struct m0_tl_descr *d, struct m0_tl *list)
Definition: tlist.c:53
M0_INTERNAL void m0_mutex_lock(struct m0_mutex *mutex)
Definition: mutex.c:49
M0_BOB_DEFINE(static, &htable_bobtype, m0_htable)
static struct foo * obj
Definition: tlist.c:302
const char * bt_name
Definition: bob.h:73
M0_INTERNAL bool m0_tlist_is_empty(const struct m0_tl_descr *d, const struct m0_tl *list)
Definition: tlist.c:96
M0_INTERNAL void m0_hbucket_unlock(struct m0_htable *htable, const void *key)
Definition: hash.c:226
M0_INTERNAL void m0_tlist_del(const struct m0_tl_descr *d, void *obj)
Definition: tlist.c:157
M0_INTERNAL void m0_hbucket_lock(struct m0_htable *htable, const void *key)
Definition: hash.c:215
int i
Definition: dir.c:1033
return M0_ERR(-EOPNOTSUPP)
struct m0_hbucket * h_buckets
Definition: hash.h:185
static const struct m0_bob_type htable_bobtype
Definition: hash.c:38
M0_INTERNAL int m0_htable_init(const struct m0_ht_descr *d, struct m0_htable *htable, uint64_t bucket_nr)
Definition: hash.c:103
M0_INTERNAL void * m0_htable_cc_lookup(struct m0_htable *htable, const void *key)
Definition: hash.c:202
static void * obj_key(const struct m0_ht_descr *hd, void *obj)
Definition: hash.c:70
M0_INTERNAL void m0_mutex_init(struct m0_mutex *mutex)
Definition: mutex.c:35
M0_INTERNAL size_t m0_tlist_length(const struct m0_tl_descr *d, const struct m0_tl *list)
Definition: tlist.c:117
#define M0_POST(cond)
bool(* hd_key_eq)(const void *key1, const void *key2)
Definition: hash.h:213
M0_INTERNAL void m0_htable_cc_add(struct m0_htable *htable, void *amb)
Definition: hash.c:182
const struct m0_ht_descr * h_descr
Definition: hash.h:188
static void hbucket_init(const struct m0_ht_descr *d, struct m0_hbucket *bucket)
Definition: hash.c:50
M0_INTERNAL bool m0_tlink_is_in(const struct m0_tl_descr *d, const void *obj)
Definition: tlist.c:103
#define m0_forall(var, nr,...)
Definition: misc.h:112
M0_INTERNAL void m0_htable_add(struct m0_htable *htable, void *amb)
Definition: hash.c:132
M0_INTERNAL void m0_htable_fini(struct m0_htable *htable)
Definition: hash.c:237
static void hbucket_fini(const struct m0_ht_descr *d, struct m0_hbucket *bucket)
Definition: hash.c:60
M0_INTERNAL void m0_mutex_fini(struct m0_mutex *mutex)
Definition: mutex.c:42
#define m0_tlist_endfor
Definition: tlist.h:448
M0_INTERNAL void m0_htable_del(struct m0_htable *htable, void *amb)
Definition: hash.c:150
M0_INTERNAL bool m0_htable_is_empty(const struct m0_htable *htable)
Definition: hash.c:252
#define m0_tlist_for(descr, head, obj)
Definition: tlist.h:435
struct m0_tl hb_objects
Definition: hash.h:166
#define M0_PRE_EX(cond)
static int scan(struct scanner *s)
Definition: beck.c:963
void m0_free(void *data)
Definition: memory.c:146
const struct m0_tl_descr * hd_tldescr
Definition: hash.h:199
M0_INTERNAL uint64_t m0_htable_size(const struct m0_htable *htable)
Definition: hash.c:266
uint64_t h_bucket_nr
Definition: hash.h:178
uint64_t(* hd_hash_func)(const struct m0_htable *htable, const void *key)
Definition: hash.h:205
#define M0_POST_EX(cond)
#define offsetof(typ, memb)
Definition: misc.h:29
size_t hd_key_offset
Definition: hash.h:202
Definition: idx_mock.c:47
M0_INTERNAL uint64_t m0_hash(uint64_t x)
Definition: hash.c:279