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