Introduce libcommon-lgpl for liblttng-ctl
[lttng-tools.git] / src / common / hashtable / hashtable.c
... / ...
CommitLineData
1/*
2 * Copyright (C) 2011 EfficiOS Inc.
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
8#define _LGPL_SOURCE
9#include <assert.h>
10#include <string.h>
11#include <urcu.h>
12#include <urcu/compiler.h>
13
14#include <common/common.h>
15#include <common/defaults.h>
16
17#include "hashtable.h"
18#include "utils.h"
19
20/* seed_lock protects both seed_init and lttng_ht_seed. */
21static pthread_mutex_t seed_lock = PTHREAD_MUTEX_INITIALIZER;
22static bool seed_init;
23
24static unsigned long min_hash_alloc_size = 1;
25static unsigned long max_hash_buckets_size = 0;
26
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
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
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
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
78/*
79 * Return an allocated lttng hashtable.
80 */
81LTTNG_HIDDEN
82struct lttng_ht *lttng_ht_new(unsigned long size, int type)
83{
84 struct lttng_ht *ht;
85
86 /* Test size */
87 if (!size)
88 size = DEFAULT_HT_SIZE;
89
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
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,
104 CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING, NULL);
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;
120 case LTTNG_HT_TYPE_U64:
121 ht->match_fct = match_u64;
122 ht->hash_fct = hash_key_u64;
123 break;
124 case LTTNG_HT_TYPE_TWO_U64:
125 ht->match_fct = match_two_u64;
126 ht->hash_fct = hash_key_two_u64;
127 break;
128 default:
129 ERR("Unknown lttng hashtable type %d", type);
130 lttng_ht_destroy(ht);
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 */
145LTTNG_HIDDEN
146void lttng_ht_destroy(struct lttng_ht *ht)
147{
148 int ret;
149
150 ret = cds_lfht_destroy(ht->ht, NULL);
151 assert(!ret);
152 free(ht);
153}
154
155/*
156 * Init lttng ht node string.
157 */
158LTTNG_HIDDEN
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 */
170LTTNG_HIDDEN
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
180/*
181 * Init lttng ht node uint64_t.
182 */
183LTTNG_HIDDEN
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
193/*
194 * Init lttng ht node with two uint64_t.
195 */
196LTTNG_HIDDEN
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
207/*
208 * Free lttng ht node string.
209 */
210LTTNG_HIDDEN
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 */
220LTTNG_HIDDEN
221void lttng_ht_node_free_ulong(struct lttng_ht_node_ulong *node)
222{
223 assert(node);
224 free(node);
225}
226
227/*
228 * Free lttng ht node uint64_t.
229 */
230LTTNG_HIDDEN
231void lttng_ht_node_free_u64(struct lttng_ht_node_u64 *node)
232{
233 assert(node);
234 free(node);
235}
236
237/*
238 * Free lttng ht node two uint64_t.
239 */
240LTTNG_HIDDEN
241void lttng_ht_node_free_two_u64(struct lttng_ht_node_two_u64 *node)
242{
243 assert(node);
244 free(node);
245}
246
247/*
248 * Lookup function in hashtable.
249 */
250LTTNG_HIDDEN
251void lttng_ht_lookup(struct lttng_ht *ht, const void *key,
252 struct lttng_ht_iter *iter)
253{
254 assert(ht);
255 assert(ht->ht);
256
257 cds_lfht_lookup(ht->ht, ht->hash_fct(key, lttng_ht_seed),
258 ht->match_fct, key, &iter->iter);
259}
260
261/*
262 * Add unique string node to hashtable.
263 */
264LTTNG_HIDDEN
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
273 /* RCU read lock protects from ABA. */
274 rcu_read_lock();
275 node_ptr = cds_lfht_add_unique(ht->ht, ht->hash_fct(node->key, lttng_ht_seed),
276 ht->match_fct, node->key, &node->node);
277 rcu_read_unlock();
278 assert(node_ptr == &node->node);
279}
280
281/*
282 * Add string node to hashtable.
283 */
284LTTNG_HIDDEN
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
292 /* RCU read lock protects from ABA. */
293 rcu_read_lock();
294 cds_lfht_add(ht->ht, ht->hash_fct(node->key, lttng_ht_seed),
295 &node->node);
296 rcu_read_unlock();
297}
298
299/*
300 * Add unsigned long node to hashtable.
301 */
302LTTNG_HIDDEN
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
309 /* RCU read lock protects from ABA. */
310 rcu_read_lock();
311 cds_lfht_add(ht->ht, ht->hash_fct((void *) node->key, lttng_ht_seed),
312 &node->node);
313 rcu_read_unlock();
314}
315
316/*
317 * Add uint64_t node to hashtable.
318 */
319LTTNG_HIDDEN
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
326 /* RCU read lock protects from ABA. */
327 rcu_read_lock();
328 cds_lfht_add(ht->ht, ht->hash_fct(&node->key, lttng_ht_seed),
329 &node->node);
330 rcu_read_unlock();
331}
332
333/*
334 * Add unique unsigned long node to hashtable.
335 */
336LTTNG_HIDDEN
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
345 /* RCU read lock protects from ABA. */
346 rcu_read_lock();
347 node_ptr = cds_lfht_add_unique(ht->ht,
348 ht->hash_fct((void *) node->key, lttng_ht_seed), ht->match_fct,
349 (void *) node->key, &node->node);
350 rcu_read_unlock();
351 assert(node_ptr == &node->node);
352}
353
354/*
355 * Add unique uint64_t node to hashtable.
356 */
357LTTNG_HIDDEN
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
366 /* RCU read lock protects from ABA. */
367 rcu_read_lock();
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);
371 rcu_read_unlock();
372 assert(node_ptr == &node->node);
373}
374
375/*
376 * Add unique two uint64_t node to hashtable.
377 */
378LTTNG_HIDDEN
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
387 /* RCU read lock protects from ABA. */
388 rcu_read_lock();
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);
392 rcu_read_unlock();
393 assert(node_ptr == &node->node);
394}
395
396/*
397 * Add replace unsigned long node to hashtable.
398 */
399LTTNG_HIDDEN
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
408 /* RCU read lock protects from ABA. */
409 rcu_read_lock();
410 node_ptr = cds_lfht_add_replace(ht->ht,
411 ht->hash_fct((void *) node->key, lttng_ht_seed), ht->match_fct,
412 (void *) node->key, &node->node);
413 rcu_read_unlock();
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
422/*
423 * Add replace unsigned long node to hashtable.
424 */
425LTTNG_HIDDEN
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
434 /* RCU read lock protects from ABA. */
435 rcu_read_lock();
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);
439 rcu_read_unlock();
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
448/*
449 * Delete node from hashtable.
450 */
451LTTNG_HIDDEN
452int lttng_ht_del(struct lttng_ht *ht, struct lttng_ht_iter *iter)
453{
454 int ret;
455
456 assert(ht);
457 assert(ht->ht);
458 assert(iter);
459
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;
465}
466
467/*
468 * Get first node in the hashtable.
469 */
470LTTNG_HIDDEN
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 */
483LTTNG_HIDDEN
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 */
496LTTNG_HIDDEN
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
505 /* RCU read lock protects from ABA and allows RCU traversal. */
506 rcu_read_lock();
507 cds_lfht_count_nodes(ht->ht, &scb, &count, &sca);
508 rcu_read_unlock();
509
510 return count;
511}
512
513/*
514 * Return lttng ht string node from iterator.
515 */
516LTTNG_HIDDEN
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 */
533LTTNG_HIDDEN
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}
546
547/*
548 * Return lttng ht unsigned long node from iterator.
549 */
550LTTNG_HIDDEN
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
564/*
565 * Return lttng ht stream and index id node from iterator.
566 */
567LTTNG_HIDDEN
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.023983 seconds and 4 git commands to generate.