Introduce libcommon-lgpl for liblttng-ctl
[lttng-tools.git] / src / common / hashtable / hashtable.c
CommitLineData
bec39940 1/*
a4eb26f0 2 * Copyright (C) 2011 EfficiOS Inc.
bec39940 3 *
ab5be9fa 4 * SPDX-License-Identifier: GPL-2.0-only
bec39940 5 *
bec39940
DG
6 */
7
6c1c0768 8#define _LGPL_SOURCE
bec39940
DG
9#include <assert.h>
10#include <string.h>
11#include <urcu.h>
12#include <urcu/compiler.h>
13
990570ed
DG
14#include <common/common.h>
15#include <common/defaults.h>
bec39940 16
10a8a223 17#include "hashtable.h"
bec39940
DG
18#include "utils.h"
19
6dcd74cf
JG
20/* seed_lock protects both seed_init and lttng_ht_seed. */
21static pthread_mutex_t seed_lock = PTHREAD_MUTEX_INITIALIZER;
22static bool seed_init;
bec39940
DG
23
24static unsigned long min_hash_alloc_size = 1;
13fe1164 25static unsigned long max_hash_buckets_size = 0;
bec39940 26
42ce408e
MD
27/*
28 * Getter/lookup functions need to be called with RCU read-side lock
29 * held. However, modification functions (add, add_unique, replace, del)
30 * take the RCU lock internally, so it does not matter whether the
31 * caller hold the RCU lock or not.
32 */
33
bec39940
DG
34/*
35 * Match function for string node.
36 */
37static int match_str(struct cds_lfht_node *node, const void *key)
38{
39 struct lttng_ht_node_str *match_node =
40 caa_container_of(node, struct lttng_ht_node_str, node);
41
42 return hash_match_key_str(match_node->key, (void *) key);
43}
44
45/*
46 * Match function for ulong node.
47 */
48static int match_ulong(struct cds_lfht_node *node, const void *key)
49{
50 struct lttng_ht_node_ulong *match_node =
51 caa_container_of(node, struct lttng_ht_node_ulong, node);
52
53 return hash_match_key_ulong((void *) match_node->key, (void *) key);
54}
55
d88aee68
DG
56/*
57 * Match function for u64 node.
58 */
59static int match_u64(struct cds_lfht_node *node, const void *key)
60{
61 struct lttng_ht_node_u64 *match_node =
62 caa_container_of(node, struct lttng_ht_node_u64, node);
63
64 return hash_match_key_u64(&match_node->key, (void *) key);
65}
66
3c4599b9
JD
67/*
68 * Match function for two uint64_t node.
69 */
70static int match_two_u64(struct cds_lfht_node *node, const void *key)
71{
72 struct lttng_ht_node_two_u64 *match_node =
73 caa_container_of(node, struct lttng_ht_node_two_u64, node);
74
75 return hash_match_key_two_u64((void *) &match_node->key, (void *) key);
76}
77
bec39940
DG
78/*
79 * Return an allocated lttng hashtable.
80 */
d604af56 81LTTNG_HIDDEN
bec39940
DG
82struct lttng_ht *lttng_ht_new(unsigned long size, int type)
83{
84 struct lttng_ht *ht;
85
86 /* Test size */
dc78d159
MD
87 if (!size)
88 size = DEFAULT_HT_SIZE;
bec39940 89
6dcd74cf
JG
90 pthread_mutex_lock(&seed_lock);
91 if (!seed_init) {
92 lttng_ht_seed = (unsigned long) time(NULL);
93 seed_init = true;
94 }
95 pthread_mutex_unlock(&seed_lock);
96
bec39940
DG
97 ht = zmalloc(sizeof(*ht));
98 if (ht == NULL) {
99 PERROR("zmalloc lttng_ht");
100 goto error;
101 }
102
103 ht->ht = cds_lfht_new(size, min_hash_alloc_size, max_hash_buckets_size,
13fe1164 104 CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING, NULL);
bec39940
DG
105 /*
106 * There is already an assert in the RCU hashtable code so if the ht is
107 * NULL here there is a *huge* problem.
108 */
109 assert(ht->ht);
110
111 switch (type) {
112 case LTTNG_HT_TYPE_STRING:
113 ht->match_fct = match_str;
114 ht->hash_fct = hash_key_str;
115 break;
116 case LTTNG_HT_TYPE_ULONG:
117 ht->match_fct = match_ulong;
118 ht->hash_fct = hash_key_ulong;
119 break;
d88aee68
DG
120 case LTTNG_HT_TYPE_U64:
121 ht->match_fct = match_u64;
122 ht->hash_fct = hash_key_u64;
123 break;
3c4599b9
JD
124 case LTTNG_HT_TYPE_TWO_U64:
125 ht->match_fct = match_two_u64;
126 ht->hash_fct = hash_key_two_u64;
127 break;
bec39940
DG
128 default:
129 ERR("Unknown lttng hashtable type %d", type);
42305b36 130 lttng_ht_destroy(ht);
bec39940
DG
131 goto error;
132 }
133
134 DBG3("Created hashtable size %lu at %p of type %d", size, ht->ht, type);
135
136 return ht;
137
138error:
139 return NULL;
140}
141
142/*
143 * Free a lttng hashtable.
144 */
d604af56 145LTTNG_HIDDEN
bec39940
DG
146void lttng_ht_destroy(struct lttng_ht *ht)
147{
148 int ret;
149
150 ret = cds_lfht_destroy(ht->ht, NULL);
151 assert(!ret);
cf5280ea 152 free(ht);
bec39940
DG
153}
154
155/*
156 * Init lttng ht node string.
157 */
d604af56 158LTTNG_HIDDEN
bec39940
DG
159void lttng_ht_node_init_str(struct lttng_ht_node_str *node, char *key)
160{
161 assert(node);
162
163 node->key = key;
164 cds_lfht_node_init(&node->node);
165}
166
167/*
168 * Init lttng ht node unsigned long.
169 */
d604af56 170LTTNG_HIDDEN
bec39940
DG
171void lttng_ht_node_init_ulong(struct lttng_ht_node_ulong *node,
172 unsigned long key)
173{
174 assert(node);
175
176 node->key = key;
177 cds_lfht_node_init(&node->node);
178}
179
d88aee68
DG
180/*
181 * Init lttng ht node uint64_t.
182 */
d604af56 183LTTNG_HIDDEN
d88aee68
DG
184void lttng_ht_node_init_u64(struct lttng_ht_node_u64 *node,
185 uint64_t key)
186{
187 assert(node);
188
189 node->key = key;
190 cds_lfht_node_init(&node->node);
191}
192
3c4599b9
JD
193/*
194 * Init lttng ht node with two uint64_t.
195 */
d604af56 196LTTNG_HIDDEN
3c4599b9
JD
197void lttng_ht_node_init_two_u64(struct lttng_ht_node_two_u64 *node,
198 uint64_t key1, uint64_t key2)
199{
200 assert(node);
201
202 node->key.key1 = key1;
203 node->key.key2 = key2;
204 cds_lfht_node_init(&node->node);
205}
206
bec39940
DG
207/*
208 * Free lttng ht node string.
209 */
d604af56 210LTTNG_HIDDEN
bec39940
DG
211void lttng_ht_node_free_str(struct lttng_ht_node_str *node)
212{
213 assert(node);
214 free(node);
215}
216
217/*
218 * Free lttng ht node unsigned long.
219 */
d604af56 220LTTNG_HIDDEN
bec39940
DG
221void lttng_ht_node_free_ulong(struct lttng_ht_node_ulong *node)
222{
223 assert(node);
224 free(node);
225}
226
d88aee68
DG
227/*
228 * Free lttng ht node uint64_t.
229 */
d604af56 230LTTNG_HIDDEN
7972aab2 231void lttng_ht_node_free_u64(struct lttng_ht_node_u64 *node)
d88aee68
DG
232{
233 assert(node);
234 free(node);
235}
236
3c4599b9
JD
237/*
238 * Free lttng ht node two uint64_t.
239 */
d604af56 240LTTNG_HIDDEN
3c4599b9
JD
241void lttng_ht_node_free_two_u64(struct lttng_ht_node_two_u64 *node)
242{
243 assert(node);
244 free(node);
245}
246
bec39940
DG
247/*
248 * Lookup function in hashtable.
249 */
d604af56 250LTTNG_HIDDEN
fb9a95c4 251void lttng_ht_lookup(struct lttng_ht *ht, const void *key,
bec39940
DG
252 struct lttng_ht_iter *iter)
253{
254 assert(ht);
255 assert(ht->ht);
bec39940 256
b6314938 257 cds_lfht_lookup(ht->ht, ht->hash_fct(key, lttng_ht_seed),
bec39940
DG
258 ht->match_fct, key, &iter->iter);
259}
260
261/*
262 * Add unique string node to hashtable.
263 */
d604af56 264LTTNG_HIDDEN
bec39940
DG
265void lttng_ht_add_unique_str(struct lttng_ht *ht,
266 struct lttng_ht_node_str *node)
267{
268 struct cds_lfht_node *node_ptr;
269 assert(ht);
270 assert(ht->ht);
271 assert(node);
272
42ce408e
MD
273 /* RCU read lock protects from ABA. */
274 rcu_read_lock();
b6314938 275 node_ptr = cds_lfht_add_unique(ht->ht, ht->hash_fct(node->key, lttng_ht_seed),
bec39940 276 ht->match_fct, node->key, &node->node);
42ce408e 277 rcu_read_unlock();
bec39940
DG
278 assert(node_ptr == &node->node);
279}
280
efa116c6
JD
281/*
282 * Add string node to hashtable.
283 */
d604af56 284LTTNG_HIDDEN
efa116c6
JD
285void lttng_ht_add_str(struct lttng_ht *ht,
286 struct lttng_ht_node_str *node)
287{
288 assert(ht);
289 assert(ht->ht);
290 assert(node);
291
42ce408e
MD
292 /* RCU read lock protects from ABA. */
293 rcu_read_lock();
efa116c6
JD
294 cds_lfht_add(ht->ht, ht->hash_fct(node->key, lttng_ht_seed),
295 &node->node);
42ce408e 296 rcu_read_unlock();
efa116c6
JD
297}
298
aefea3b7
DG
299/*
300 * Add unsigned long node to hashtable.
301 */
d604af56 302LTTNG_HIDDEN
aefea3b7
DG
303void lttng_ht_add_ulong(struct lttng_ht *ht, struct lttng_ht_node_ulong *node)
304{
305 assert(ht);
306 assert(ht->ht);
307 assert(node);
308
42ce408e
MD
309 /* RCU read lock protects from ABA. */
310 rcu_read_lock();
b6314938 311 cds_lfht_add(ht->ht, ht->hash_fct((void *) node->key, lttng_ht_seed),
aefea3b7 312 &node->node);
42ce408e 313 rcu_read_unlock();
aefea3b7
DG
314}
315
d88aee68
DG
316/*
317 * Add uint64_t node to hashtable.
d88aee68 318 */
d604af56 319LTTNG_HIDDEN
d88aee68
DG
320void lttng_ht_add_u64(struct lttng_ht *ht, struct lttng_ht_node_u64 *node)
321{
322 assert(ht);
323 assert(ht->ht);
324 assert(node);
325
42ce408e
MD
326 /* RCU read lock protects from ABA. */
327 rcu_read_lock();
d88aee68
DG
328 cds_lfht_add(ht->ht, ht->hash_fct(&node->key, lttng_ht_seed),
329 &node->node);
42ce408e 330 rcu_read_unlock();
d88aee68
DG
331}
332
bec39940
DG
333/*
334 * Add unique unsigned long node to hashtable.
335 */
d604af56 336LTTNG_HIDDEN
bec39940
DG
337void lttng_ht_add_unique_ulong(struct lttng_ht *ht,
338 struct lttng_ht_node_ulong *node)
339{
340 struct cds_lfht_node *node_ptr;
341 assert(ht);
342 assert(ht->ht);
343 assert(node);
344
42ce408e
MD
345 /* RCU read lock protects from ABA. */
346 rcu_read_lock();
bec39940 347 node_ptr = cds_lfht_add_unique(ht->ht,
b6314938 348 ht->hash_fct((void *) node->key, lttng_ht_seed), ht->match_fct,
bec39940 349 (void *) node->key, &node->node);
42ce408e 350 rcu_read_unlock();
bec39940
DG
351 assert(node_ptr == &node->node);
352}
353
d88aee68
DG
354/*
355 * Add unique uint64_t node to hashtable.
356 */
d604af56 357LTTNG_HIDDEN
d88aee68
DG
358void lttng_ht_add_unique_u64(struct lttng_ht *ht,
359 struct lttng_ht_node_u64 *node)
360{
361 struct cds_lfht_node *node_ptr;
362 assert(ht);
363 assert(ht->ht);
364 assert(node);
365
42ce408e
MD
366 /* RCU read lock protects from ABA. */
367 rcu_read_lock();
d88aee68
DG
368 node_ptr = cds_lfht_add_unique(ht->ht,
369 ht->hash_fct(&node->key, lttng_ht_seed), ht->match_fct,
370 &node->key, &node->node);
42ce408e 371 rcu_read_unlock();
d88aee68
DG
372 assert(node_ptr == &node->node);
373}
374
3c4599b9
JD
375/*
376 * Add unique two uint64_t node to hashtable.
377 */
d604af56 378LTTNG_HIDDEN
3c4599b9
JD
379void lttng_ht_add_unique_two_u64(struct lttng_ht *ht,
380 struct lttng_ht_node_two_u64 *node)
381{
382 struct cds_lfht_node *node_ptr;
383 assert(ht);
384 assert(ht->ht);
385 assert(node);
386
42ce408e
MD
387 /* RCU read lock protects from ABA. */
388 rcu_read_lock();
3c4599b9
JD
389 node_ptr = cds_lfht_add_unique(ht->ht,
390 ht->hash_fct((void *) &node->key, lttng_ht_seed), ht->match_fct,
391 (void *) &node->key, &node->node);
42ce408e 392 rcu_read_unlock();
3c4599b9
JD
393 assert(node_ptr == &node->node);
394}
395
702b1ea4
MD
396/*
397 * Add replace unsigned long node to hashtable.
398 */
d604af56 399LTTNG_HIDDEN
702b1ea4
MD
400struct lttng_ht_node_ulong *lttng_ht_add_replace_ulong(struct lttng_ht *ht,
401 struct lttng_ht_node_ulong *node)
402{
403 struct cds_lfht_node *node_ptr;
404 assert(ht);
405 assert(ht->ht);
406 assert(node);
407
42ce408e
MD
408 /* RCU read lock protects from ABA. */
409 rcu_read_lock();
702b1ea4 410 node_ptr = cds_lfht_add_replace(ht->ht,
b6314938 411 ht->hash_fct((void *) node->key, lttng_ht_seed), ht->match_fct,
702b1ea4 412 (void *) node->key, &node->node);
42ce408e 413 rcu_read_unlock();
702b1ea4
MD
414 if (!node_ptr) {
415 return NULL;
416 } else {
417 return caa_container_of(node_ptr, struct lttng_ht_node_ulong, node);
418 }
419 assert(node_ptr == &node->node);
420}
421
d88aee68
DG
422/*
423 * Add replace unsigned long node to hashtable.
424 */
d604af56 425LTTNG_HIDDEN
d88aee68
DG
426struct lttng_ht_node_u64 *lttng_ht_add_replace_u64(struct lttng_ht *ht,
427 struct lttng_ht_node_u64 *node)
428{
429 struct cds_lfht_node *node_ptr;
430 assert(ht);
431 assert(ht->ht);
432 assert(node);
433
42ce408e
MD
434 /* RCU read lock protects from ABA. */
435 rcu_read_lock();
d88aee68
DG
436 node_ptr = cds_lfht_add_replace(ht->ht,
437 ht->hash_fct(&node->key, lttng_ht_seed), ht->match_fct,
438 &node->key, &node->node);
42ce408e 439 rcu_read_unlock();
d88aee68
DG
440 if (!node_ptr) {
441 return NULL;
442 } else {
443 return caa_container_of(node_ptr, struct lttng_ht_node_u64, node);
444 }
445 assert(node_ptr == &node->node);
446}
447
bec39940
DG
448/*
449 * Delete node from hashtable.
450 */
d604af56 451LTTNG_HIDDEN
bec39940
DG
452int lttng_ht_del(struct lttng_ht *ht, struct lttng_ht_iter *iter)
453{
42ce408e
MD
454 int ret;
455
bec39940
DG
456 assert(ht);
457 assert(ht->ht);
458 assert(iter);
459
42ce408e
MD
460 /* RCU read lock protects from ABA. */
461 rcu_read_lock();
462 ret = cds_lfht_del(ht->ht, iter->iter.node);
463 rcu_read_unlock();
464 return ret;
bec39940
DG
465}
466
467/*
468 * Get first node in the hashtable.
469 */
d604af56 470LTTNG_HIDDEN
bec39940
DG
471void lttng_ht_get_first(struct lttng_ht *ht, struct lttng_ht_iter *iter)
472{
473 assert(ht);
474 assert(ht->ht);
475 assert(iter);
476
477 cds_lfht_first(ht->ht, &iter->iter);
478}
479
480/*
481 * Get next node in the hashtable.
482 */
d604af56 483LTTNG_HIDDEN
bec39940
DG
484void lttng_ht_get_next(struct lttng_ht *ht, struct lttng_ht_iter *iter)
485{
486 assert(ht);
487 assert(ht->ht);
488 assert(iter);
489
490 cds_lfht_next(ht->ht, &iter->iter);
491}
492
493/*
494 * Return the number of nodes in the hashtable.
495 */
d604af56 496LTTNG_HIDDEN
bec39940
DG
497unsigned long lttng_ht_get_count(struct lttng_ht *ht)
498{
499 long scb, sca;
500 unsigned long count;
501
502 assert(ht);
503 assert(ht->ht);
504
42ce408e
MD
505 /* RCU read lock protects from ABA and allows RCU traversal. */
506 rcu_read_lock();
bec39940 507 cds_lfht_count_nodes(ht->ht, &scb, &count, &sca);
42ce408e 508 rcu_read_unlock();
bec39940
DG
509
510 return count;
511}
512
513/*
514 * Return lttng ht string node from iterator.
515 */
d604af56 516LTTNG_HIDDEN
bec39940
DG
517struct lttng_ht_node_str *lttng_ht_iter_get_node_str(
518 struct lttng_ht_iter *iter)
519{
520 struct cds_lfht_node *node;
521
522 assert(iter);
523 node = cds_lfht_iter_get_node(&iter->iter);
524 if (!node) {
525 return NULL;
526 }
527 return caa_container_of(node, struct lttng_ht_node_str, node);
528}
529
530/*
531 * Return lttng ht unsigned long node from iterator.
532 */
d604af56 533LTTNG_HIDDEN
bec39940
DG
534struct lttng_ht_node_ulong *lttng_ht_iter_get_node_ulong(
535 struct lttng_ht_iter *iter)
536{
537 struct cds_lfht_node *node;
538
539 assert(iter);
540 node = cds_lfht_iter_get_node(&iter->iter);
541 if (!node) {
542 return NULL;
543 }
544 return caa_container_of(node, struct lttng_ht_node_ulong, node);
545}
b6314938 546
d88aee68
DG
547/*
548 * Return lttng ht unsigned long node from iterator.
549 */
d604af56 550LTTNG_HIDDEN
d88aee68
DG
551struct lttng_ht_node_u64 *lttng_ht_iter_get_node_u64(
552 struct lttng_ht_iter *iter)
553{
554 struct cds_lfht_node *node;
555
556 assert(iter);
557 node = cds_lfht_iter_get_node(&iter->iter);
558 if (!node) {
559 return NULL;
560 }
561 return caa_container_of(node, struct lttng_ht_node_u64, node);
562}
563
3c4599b9
JD
564/*
565 * Return lttng ht stream and index id node from iterator.
566 */
d604af56 567LTTNG_HIDDEN
3c4599b9
JD
568struct lttng_ht_node_two_u64 *lttng_ht_iter_get_node_two_u64(
569 struct lttng_ht_iter *iter)
570{
571 struct cds_lfht_node *node;
572
573 assert(iter);
574 node = cds_lfht_iter_get_node(&iter->iter);
575 if (!node) {
576 return NULL;
577 }
578 return caa_container_of(node, struct lttng_ht_node_two_u64, node);
579}
This page took 0.103194 seconds and 5 git commands to generate.