2 * Copyright (C) 2011 EfficiOS Inc.
4 * SPDX-License-Identifier: GPL-2.0-only
9 #include "hashtable.hpp"
12 #include <common/common.hpp>
13 #include <common/defaults.hpp>
17 #include <urcu/compiler.h>
19 /* seed_lock protects both seed_init and lttng_ht_seed. */
20 static pthread_mutex_t seed_lock
= PTHREAD_MUTEX_INITIALIZER
;
21 static bool seed_init
;
23 static unsigned long min_hash_alloc_size
= 1;
24 static unsigned long max_hash_buckets_size
= 0;
27 * Getter/lookup functions need to be called with RCU read-side lock
28 * held. However, modification functions (add, add_unique, replace, del)
29 * take the RCU lock internally, so it does not matter whether the
30 * caller hold the RCU lock or not.
34 * Match function for string node.
36 static int match_str(struct cds_lfht_node
*node
, const void *key
)
38 struct lttng_ht_node_str
*match_node
=
39 lttng::utils::container_of(node
, <tng_ht_node_str::node
);
41 return hash_match_key_str(match_node
->key
, (void *) key
);
45 * Match function for ulong node.
47 static int match_ulong(struct cds_lfht_node
*node
, const void *key
)
49 struct lttng_ht_node_ulong
*match_node
=
50 lttng::utils::container_of(node
, <tng_ht_node_ulong::node
);
52 return hash_match_key_ulong((void *) match_node
->key
, (void *) key
);
56 * Match function for u64 node.
58 static int match_u64(struct cds_lfht_node
*node
, const void *key
)
60 struct lttng_ht_node_u64
*match_node
=
61 lttng::utils::container_of(node
, <tng_ht_node_u64::node
);
63 return hash_match_key_u64(&match_node
->key
, (void *) key
);
67 * Match function for two uint64_t node.
69 static int match_two_u64(struct cds_lfht_node
*node
, const void *key
)
71 struct lttng_ht_node_two_u64
*match_node
=
72 lttng::utils::container_of(node
, <tng_ht_node_two_u64::node
);
74 return hash_match_key_two_u64((void *) &match_node
->key
, (void *) key
);
77 static inline const char *lttng_ht_type_str(enum lttng_ht_type type
)
80 case LTTNG_HT_TYPE_STRING
:
82 case LTTNG_HT_TYPE_ULONG
:
84 case LTTNG_HT_TYPE_U64
:
86 case LTTNG_HT_TYPE_TWO_U64
:
89 ERR("Unknown lttng hashtable type %d", type
);
95 * Return an allocated lttng hashtable.
97 struct lttng_ht
*lttng_ht_new(unsigned long size
, lttng_ht_type type
)
103 size
= DEFAULT_HT_SIZE
;
105 pthread_mutex_lock(&seed_lock
);
107 lttng_ht_seed
= (unsigned long) time(nullptr);
110 pthread_mutex_unlock(&seed_lock
);
112 ht
= zmalloc
<lttng_ht
>();
114 PERROR("zmalloc lttng_ht");
118 ht
->ht
= cds_lfht_new(size
,
120 max_hash_buckets_size
,
121 CDS_LFHT_AUTO_RESIZE
| CDS_LFHT_ACCOUNTING
,
124 * There is already an assert in the RCU hashtable code so if the ht is
125 * NULL here there is a *huge* problem.
127 LTTNG_ASSERT(ht
->ht
);
130 case LTTNG_HT_TYPE_STRING
:
131 ht
->match_fct
= match_str
;
132 ht
->hash_fct
= hash_key_str
;
134 case LTTNG_HT_TYPE_ULONG
:
135 ht
->match_fct
= match_ulong
;
136 ht
->hash_fct
= hash_key_ulong
;
138 case LTTNG_HT_TYPE_U64
:
139 ht
->match_fct
= match_u64
;
140 ht
->hash_fct
= hash_key_u64
;
142 case LTTNG_HT_TYPE_TWO_U64
:
143 ht
->match_fct
= match_two_u64
;
144 ht
->hash_fct
= hash_key_two_u64
;
147 ERR("Unknown lttng hashtable type %d", type
);
148 lttng_ht_destroy(ht
);
152 DBG3("Created hashtable size %lu at %p of type %s", size
, ht
->ht
, lttng_ht_type_str(type
));
161 * Free a lttng hashtable.
163 void lttng_ht_destroy(struct lttng_ht
*ht
)
167 ret
= cds_lfht_destroy(ht
->ht
, nullptr);
173 * Init lttng ht node string.
175 void lttng_ht_node_init_str(struct lttng_ht_node_str
*node
, char *key
)
180 cds_lfht_node_init(&node
->node
);
184 * Init lttng ht node unsigned long.
186 void lttng_ht_node_init_ulong(struct lttng_ht_node_ulong
*node
, unsigned long key
)
191 cds_lfht_node_init(&node
->node
);
195 * Init lttng ht node uint64_t.
197 void lttng_ht_node_init_u64(struct lttng_ht_node_u64
*node
, uint64_t key
)
202 cds_lfht_node_init(&node
->node
);
206 * Init lttng ht node with two uint64_t.
208 void lttng_ht_node_init_two_u64(struct lttng_ht_node_two_u64
*node
, uint64_t key1
, uint64_t key2
)
212 node
->key
.key1
= key1
;
213 node
->key
.key2
= key2
;
214 cds_lfht_node_init(&node
->node
);
218 * Free lttng ht node string.
220 void lttng_ht_node_free_str(struct lttng_ht_node_str
*node
)
227 * Free lttng ht node unsigned long.
229 void lttng_ht_node_free_ulong(struct lttng_ht_node_ulong
*node
)
236 * Free lttng ht node uint64_t.
238 void lttng_ht_node_free_u64(struct lttng_ht_node_u64
*node
)
245 * Free lttng ht node two uint64_t.
247 void lttng_ht_node_free_two_u64(struct lttng_ht_node_two_u64
*node
)
254 * Lookup function in hashtable.
256 void lttng_ht_lookup(struct lttng_ht
*ht
, const void *key
, struct lttng_ht_iter
*iter
)
259 LTTNG_ASSERT(ht
->ht
);
261 cds_lfht_lookup(ht
->ht
, ht
->hash_fct(key
, lttng_ht_seed
), ht
->match_fct
, key
, &iter
->iter
);
265 * Add unique string node to hashtable.
267 void lttng_ht_add_unique_str(struct lttng_ht
*ht
, struct lttng_ht_node_str
*node
)
269 struct cds_lfht_node
*node_ptr
;
271 LTTNG_ASSERT(ht
->ht
);
274 /* RCU read lock protects from ABA. */
276 node_ptr
= cds_lfht_add_unique(ht
->ht
,
277 ht
->hash_fct(node
->key
, lttng_ht_seed
),
282 LTTNG_ASSERT(node_ptr
== &node
->node
);
286 * Add string node to hashtable.
288 void lttng_ht_add_str(struct lttng_ht
*ht
, struct lttng_ht_node_str
*node
)
291 LTTNG_ASSERT(ht
->ht
);
294 /* RCU read lock protects from ABA. */
296 cds_lfht_add(ht
->ht
, ht
->hash_fct(node
->key
, lttng_ht_seed
), &node
->node
);
301 * Add unsigned long node to hashtable.
303 void lttng_ht_add_ulong(struct lttng_ht
*ht
, struct lttng_ht_node_ulong
*node
)
306 LTTNG_ASSERT(ht
->ht
);
309 /* RCU read lock protects from ABA. */
311 cds_lfht_add(ht
->ht
, ht
->hash_fct((void *) node
->key
, lttng_ht_seed
), &node
->node
);
316 * Add uint64_t node to hashtable.
318 void lttng_ht_add_u64(struct lttng_ht
*ht
, struct lttng_ht_node_u64
*node
)
321 LTTNG_ASSERT(ht
->ht
);
324 /* RCU read lock protects from ABA. */
326 cds_lfht_add(ht
->ht
, ht
->hash_fct(&node
->key
, lttng_ht_seed
), &node
->node
);
331 * Add unique unsigned long node to hashtable.
333 void lttng_ht_add_unique_ulong(struct lttng_ht
*ht
, struct lttng_ht_node_ulong
*node
)
335 struct cds_lfht_node
*node_ptr
;
337 LTTNG_ASSERT(ht
->ht
);
340 /* RCU read lock protects from ABA. */
342 node_ptr
= cds_lfht_add_unique(ht
->ht
,
343 ht
->hash_fct((void *) node
->key
, lttng_ht_seed
),
348 LTTNG_ASSERT(node_ptr
== &node
->node
);
352 * Add unique uint64_t node to hashtable.
354 void lttng_ht_add_unique_u64(struct lttng_ht
*ht
, struct lttng_ht_node_u64
*node
)
356 struct cds_lfht_node
*node_ptr
;
358 LTTNG_ASSERT(ht
->ht
);
361 /* RCU read lock protects from ABA. */
363 node_ptr
= cds_lfht_add_unique(ht
->ht
,
364 ht
->hash_fct(&node
->key
, lttng_ht_seed
),
369 LTTNG_ASSERT(node_ptr
== &node
->node
);
373 * Add unique two uint64_t node to hashtable.
375 void lttng_ht_add_unique_two_u64(struct lttng_ht
*ht
, struct lttng_ht_node_two_u64
*node
)
377 struct cds_lfht_node
*node_ptr
;
379 LTTNG_ASSERT(ht
->ht
);
382 /* RCU read lock protects from ABA. */
384 node_ptr
= cds_lfht_add_unique(ht
->ht
,
385 ht
->hash_fct((void *) &node
->key
, lttng_ht_seed
),
390 LTTNG_ASSERT(node_ptr
== &node
->node
);
394 * Add replace unsigned long node to hashtable.
396 struct lttng_ht_node_ulong
*lttng_ht_add_replace_ulong(struct lttng_ht
*ht
,
397 struct lttng_ht_node_ulong
*node
)
399 struct cds_lfht_node
*node_ptr
;
401 LTTNG_ASSERT(ht
->ht
);
404 /* RCU read lock protects from ABA. */
406 node_ptr
= cds_lfht_add_replace(ht
->ht
,
407 ht
->hash_fct((void *) node
->key
, lttng_ht_seed
),
415 return lttng::utils::container_of(node_ptr
, <tng_ht_node_ulong::node
);
417 LTTNG_ASSERT(node_ptr
== &node
->node
);
421 * Add replace unsigned long node to hashtable.
423 struct lttng_ht_node_u64
*lttng_ht_add_replace_u64(struct lttng_ht
*ht
,
424 struct lttng_ht_node_u64
*node
)
426 struct cds_lfht_node
*node_ptr
;
428 LTTNG_ASSERT(ht
->ht
);
431 /* RCU read lock protects from ABA. */
433 node_ptr
= cds_lfht_add_replace(ht
->ht
,
434 ht
->hash_fct(&node
->key
, lttng_ht_seed
),
442 return lttng::utils::container_of(node_ptr
, <tng_ht_node_u64::node
);
444 LTTNG_ASSERT(node_ptr
== &node
->node
);
448 * Delete node from hashtable.
450 int lttng_ht_del(struct lttng_ht
*ht
, struct lttng_ht_iter
*iter
)
455 LTTNG_ASSERT(ht
->ht
);
458 /* RCU read lock protects from ABA. */
460 ret
= cds_lfht_del(ht
->ht
, iter
->iter
.node
);
466 * Get first node in the hashtable.
468 void lttng_ht_get_first(struct lttng_ht
*ht
, struct lttng_ht_iter
*iter
)
471 LTTNG_ASSERT(ht
->ht
);
474 cds_lfht_first(ht
->ht
, &iter
->iter
);
478 * Get next node in the hashtable.
480 void lttng_ht_get_next(struct lttng_ht
*ht
, struct lttng_ht_iter
*iter
)
483 LTTNG_ASSERT(ht
->ht
);
486 cds_lfht_next(ht
->ht
, &iter
->iter
);
490 * Return the number of nodes in the hashtable.
492 unsigned long lttng_ht_get_count(struct lttng_ht
*ht
)
498 LTTNG_ASSERT(ht
->ht
);
500 /* RCU read lock protects from ABA and allows RCU traversal. */
502 cds_lfht_count_nodes(ht
->ht
, &scb
, &count
, &sca
);
509 * Return lttng ht string node from iterator.
511 struct lttng_ht_node_str
*lttng_ht_iter_get_node_str(struct lttng_ht_iter
*iter
)
513 struct cds_lfht_node
*node
;
516 node
= cds_lfht_iter_get_node(&iter
->iter
);
520 return lttng::utils::container_of(node
, <tng_ht_node_str::node
);
524 * Return lttng ht unsigned long node from iterator.
526 struct lttng_ht_node_ulong
*lttng_ht_iter_get_node_ulong(struct lttng_ht_iter
*iter
)
528 struct cds_lfht_node
*node
;
531 node
= cds_lfht_iter_get_node(&iter
->iter
);
535 return lttng::utils::container_of(node
, <tng_ht_node_ulong::node
);
539 * Return lttng ht unsigned long node from iterator.
541 struct lttng_ht_node_u64
*lttng_ht_iter_get_node_u64(struct lttng_ht_iter
*iter
)
543 struct cds_lfht_node
*node
;
546 node
= cds_lfht_iter_get_node(&iter
->iter
);
550 return lttng::utils::container_of(node
, <tng_ht_node_u64::node
);
554 * Return lttng ht stream and index id node from iterator.
556 struct lttng_ht_node_two_u64
*lttng_ht_iter_get_node_two_u64(struct lttng_ht_iter
*iter
)
558 struct cds_lfht_node
*node
;
561 node
= cds_lfht_iter_get_node(&iter
->iter
);
565 return lttng::utils::container_of(node
, <tng_ht_node_two_u64::node
);