lsquic_hash.c revision 229fce07
1229fce07SDmitri Tikhonov/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc.  See LICENSE. */
250aadb33SDmitri Tikhonov/*
350aadb33SDmitri Tikhonov * lsquic_hash.c
450aadb33SDmitri Tikhonov */
550aadb33SDmitri Tikhonov
650aadb33SDmitri Tikhonov#include <assert.h>
750aadb33SDmitri Tikhonov#include <stdint.h>
850aadb33SDmitri Tikhonov#include <stdlib.h>
950aadb33SDmitri Tikhonov#include <string.h>
1050aadb33SDmitri Tikhonov#include <sys/queue.h>
11461e84d8SAmol Deshpande#ifdef WIN32
12461e84d8SAmol Deshpande#include <vc_compat.h>
13461e84d8SAmol Deshpande#endif
1450aadb33SDmitri Tikhonov
1550aadb33SDmitri Tikhonov#include "lsquic_malo.h"
1650aadb33SDmitri Tikhonov#include "lsquic_hash.h"
1750aadb33SDmitri Tikhonov#include "lsquic_xxhash.h"
1850aadb33SDmitri Tikhonov
1950aadb33SDmitri Tikhonovstruct lsquic_hash_elem
2050aadb33SDmitri Tikhonov{
2150aadb33SDmitri Tikhonov    TAILQ_ENTRY(lsquic_hash_elem)
2250aadb33SDmitri Tikhonov                    qhe_next_bucket,
2350aadb33SDmitri Tikhonov                    qhe_next_all;
2450aadb33SDmitri Tikhonov    const void     *qhe_key_data;
2550aadb33SDmitri Tikhonov    unsigned        qhe_key_len;
2650aadb33SDmitri Tikhonov    void           *qhe_value;
2750aadb33SDmitri Tikhonov    unsigned        qhe_hash_val;
2850aadb33SDmitri Tikhonov};
2950aadb33SDmitri Tikhonov
3050aadb33SDmitri TikhonovTAILQ_HEAD(hels_head, lsquic_hash_elem);
3150aadb33SDmitri Tikhonov
3250aadb33SDmitri Tikhonov#define N_BUCKETS(n_bits) (1U << (n_bits))
3350aadb33SDmitri Tikhonov#define BUCKNO(n_bits, hash) ((hash) & (N_BUCKETS(n_bits) - 1))
3450aadb33SDmitri Tikhonov
3550aadb33SDmitri Tikhonovstruct lsquic_hash
3650aadb33SDmitri Tikhonov{
3750aadb33SDmitri Tikhonov    struct hels_head        *qh_buckets,
3850aadb33SDmitri Tikhonov                             qh_all;
3950aadb33SDmitri Tikhonov    struct malo             *qh_malo_els;
4050aadb33SDmitri Tikhonov    struct lsquic_hash_elem *qh_iter_next;
4150aadb33SDmitri Tikhonov    unsigned                 qh_count;
4250aadb33SDmitri Tikhonov    unsigned                 qh_nbits;
4350aadb33SDmitri Tikhonov};
4450aadb33SDmitri Tikhonov
4550aadb33SDmitri Tikhonov
4650aadb33SDmitri Tikhonovstruct lsquic_hash *
4750aadb33SDmitri Tikhonovlsquic_hash_create (void)
4850aadb33SDmitri Tikhonov{
4950aadb33SDmitri Tikhonov    struct hels_head *buckets;
5050aadb33SDmitri Tikhonov    struct lsquic_hash *hash;
5150aadb33SDmitri Tikhonov    struct malo *malo;
5250aadb33SDmitri Tikhonov    unsigned nbits = 2;
5350aadb33SDmitri Tikhonov    unsigned i;
5450aadb33SDmitri Tikhonov
5550aadb33SDmitri Tikhonov    buckets = malloc(sizeof(buckets[0]) * N_BUCKETS(nbits));
5650aadb33SDmitri Tikhonov    if (!buckets)
5750aadb33SDmitri Tikhonov        return NULL;
5850aadb33SDmitri Tikhonov
5950aadb33SDmitri Tikhonov    hash = malloc(sizeof(*hash));
6050aadb33SDmitri Tikhonov    if (!hash)
6150aadb33SDmitri Tikhonov    {
6250aadb33SDmitri Tikhonov        free(buckets);
6350aadb33SDmitri Tikhonov        return NULL;
6450aadb33SDmitri Tikhonov    }
6550aadb33SDmitri Tikhonov
6650aadb33SDmitri Tikhonov    malo = lsquic_malo_create(sizeof(struct lsquic_hash_elem));
6750aadb33SDmitri Tikhonov    if (!malo)
6850aadb33SDmitri Tikhonov    {
6950aadb33SDmitri Tikhonov        free(hash);
7050aadb33SDmitri Tikhonov        free(buckets);
7150aadb33SDmitri Tikhonov        return NULL;
7250aadb33SDmitri Tikhonov    }
7350aadb33SDmitri Tikhonov
7450aadb33SDmitri Tikhonov    for (i = 0; i < N_BUCKETS(nbits); ++i)
7550aadb33SDmitri Tikhonov        TAILQ_INIT(&buckets[i]);
7650aadb33SDmitri Tikhonov
7750aadb33SDmitri Tikhonov    TAILQ_INIT(&hash->qh_all);
7850aadb33SDmitri Tikhonov    hash->qh_buckets   = buckets;
7950aadb33SDmitri Tikhonov    hash->qh_nbits     = nbits;
8050aadb33SDmitri Tikhonov    hash->qh_malo_els  = malo;
8150aadb33SDmitri Tikhonov    hash->qh_iter_next = NULL;
8250aadb33SDmitri Tikhonov    hash->qh_count     = 0;
8350aadb33SDmitri Tikhonov    return hash;
8450aadb33SDmitri Tikhonov}
8550aadb33SDmitri Tikhonov
8650aadb33SDmitri Tikhonov
8750aadb33SDmitri Tikhonovvoid
8850aadb33SDmitri Tikhonovlsquic_hash_destroy (struct lsquic_hash *hash)
8950aadb33SDmitri Tikhonov{
9050aadb33SDmitri Tikhonov    lsquic_malo_destroy(hash->qh_malo_els);
9150aadb33SDmitri Tikhonov    free(hash->qh_buckets);
9250aadb33SDmitri Tikhonov    free(hash);
9350aadb33SDmitri Tikhonov}
9450aadb33SDmitri Tikhonov
9550aadb33SDmitri Tikhonov
9650aadb33SDmitri Tikhonovstatic int
9750aadb33SDmitri Tikhonovlsquic_hash_grow (struct lsquic_hash *hash)
9850aadb33SDmitri Tikhonov{
9950aadb33SDmitri Tikhonov    struct hels_head *new_buckets, *new[2];
10050aadb33SDmitri Tikhonov    struct lsquic_hash_elem *el;
10150aadb33SDmitri Tikhonov    unsigned n, old_nbits;
10250aadb33SDmitri Tikhonov    int idx;
10350aadb33SDmitri Tikhonov
10450aadb33SDmitri Tikhonov    old_nbits = hash->qh_nbits;
10550aadb33SDmitri Tikhonov    new_buckets = malloc(sizeof(hash->qh_buckets[0])
10650aadb33SDmitri Tikhonov                                                * N_BUCKETS(old_nbits + 1));
10750aadb33SDmitri Tikhonov    if (!new_buckets)
10850aadb33SDmitri Tikhonov        return -1;
10950aadb33SDmitri Tikhonov
11050aadb33SDmitri Tikhonov    for (n = 0; n < N_BUCKETS(old_nbits); ++n)
11150aadb33SDmitri Tikhonov    {
11250aadb33SDmitri Tikhonov        new[0] = &new_buckets[n];
11350aadb33SDmitri Tikhonov        new[1] = &new_buckets[n + N_BUCKETS(old_nbits)];
11450aadb33SDmitri Tikhonov        TAILQ_INIT(new[0]);
11550aadb33SDmitri Tikhonov        TAILQ_INIT(new[1]);
11650aadb33SDmitri Tikhonov        while ((el = TAILQ_FIRST(&hash->qh_buckets[n])))
11750aadb33SDmitri Tikhonov        {
11850aadb33SDmitri Tikhonov            TAILQ_REMOVE(&hash->qh_buckets[n], el, qhe_next_bucket);
11950aadb33SDmitri Tikhonov            idx = (BUCKNO(old_nbits + 1, el->qhe_hash_val) >> old_nbits) & 1;
12050aadb33SDmitri Tikhonov            TAILQ_INSERT_TAIL(new[idx], el, qhe_next_bucket);
12150aadb33SDmitri Tikhonov        }
12250aadb33SDmitri Tikhonov    }
12350aadb33SDmitri Tikhonov    free(hash->qh_buckets);
12450aadb33SDmitri Tikhonov    hash->qh_nbits   = old_nbits + 1;
12550aadb33SDmitri Tikhonov    hash->qh_buckets = new_buckets;
12650aadb33SDmitri Tikhonov    return 0;
12750aadb33SDmitri Tikhonov}
12850aadb33SDmitri Tikhonov
12950aadb33SDmitri Tikhonov
13050aadb33SDmitri Tikhonovstruct lsquic_hash_elem *
13150aadb33SDmitri Tikhonovlsquic_hash_insert (struct lsquic_hash *hash, const void *key,
13250aadb33SDmitri Tikhonov                                            unsigned key_sz, void *data)
13350aadb33SDmitri Tikhonov{
13450aadb33SDmitri Tikhonov    unsigned buckno, hash_val;
13550aadb33SDmitri Tikhonov    struct lsquic_hash_elem *el;
13650aadb33SDmitri Tikhonov
13750aadb33SDmitri Tikhonov    el = lsquic_malo_get(hash->qh_malo_els);
13850aadb33SDmitri Tikhonov    if (!el)
13950aadb33SDmitri Tikhonov        return NULL;
14050aadb33SDmitri Tikhonov
14150aadb33SDmitri Tikhonov    if (hash->qh_count >= N_BUCKETS(hash->qh_nbits) / 2 &&
14250aadb33SDmitri Tikhonov                                            0 != lsquic_hash_grow(hash))
14350aadb33SDmitri Tikhonov    {
14450aadb33SDmitri Tikhonov        lsquic_malo_put(el);
14550aadb33SDmitri Tikhonov        return NULL;
14650aadb33SDmitri Tikhonov    }
14750aadb33SDmitri Tikhonov
14850aadb33SDmitri Tikhonov    hash_val = XXH64(key, key_sz, (uintptr_t) hash);
14950aadb33SDmitri Tikhonov    buckno = BUCKNO(hash->qh_nbits, hash_val);
15050aadb33SDmitri Tikhonov    TAILQ_INSERT_TAIL(&hash->qh_all, el, qhe_next_all);
15150aadb33SDmitri Tikhonov    TAILQ_INSERT_TAIL(&hash->qh_buckets[buckno], el, qhe_next_bucket);
15250aadb33SDmitri Tikhonov    el->qhe_key_data = key;
15350aadb33SDmitri Tikhonov    el->qhe_key_len  = key_sz;
15450aadb33SDmitri Tikhonov    el->qhe_value    = data;
15550aadb33SDmitri Tikhonov    el->qhe_hash_val = hash_val;
15650aadb33SDmitri Tikhonov    ++hash->qh_count;
15750aadb33SDmitri Tikhonov    return el;
15850aadb33SDmitri Tikhonov}
15950aadb33SDmitri Tikhonov
16050aadb33SDmitri Tikhonov
16150aadb33SDmitri Tikhonovstruct lsquic_hash_elem *
16250aadb33SDmitri Tikhonovlsquic_hash_find (struct lsquic_hash *hash, const void *key, unsigned key_sz)
16350aadb33SDmitri Tikhonov{
16450aadb33SDmitri Tikhonov    unsigned buckno, hash_val;
16550aadb33SDmitri Tikhonov    struct lsquic_hash_elem *el;
16650aadb33SDmitri Tikhonov
16750aadb33SDmitri Tikhonov    hash_val = XXH64(key, key_sz, (uintptr_t) hash);
16850aadb33SDmitri Tikhonov    buckno = BUCKNO(hash->qh_nbits, hash_val);
16950aadb33SDmitri Tikhonov    TAILQ_FOREACH(el, &hash->qh_buckets[buckno], qhe_next_bucket)
17050aadb33SDmitri Tikhonov        if (hash_val == el->qhe_hash_val &&
17150aadb33SDmitri Tikhonov            key_sz   == el->qhe_key_len &&
17250aadb33SDmitri Tikhonov            0 == memcmp(key, el->qhe_key_data, key_sz))
17350aadb33SDmitri Tikhonov        {
17450aadb33SDmitri Tikhonov            return el;
17550aadb33SDmitri Tikhonov        }
17650aadb33SDmitri Tikhonov
17750aadb33SDmitri Tikhonov    return NULL;
17850aadb33SDmitri Tikhonov}
17950aadb33SDmitri Tikhonov
18050aadb33SDmitri Tikhonov
18150aadb33SDmitri Tikhonovvoid *
18250aadb33SDmitri Tikhonovlsquic_hashelem_getdata (const struct lsquic_hash_elem *el)
18350aadb33SDmitri Tikhonov{
18450aadb33SDmitri Tikhonov    return el->qhe_value;
18550aadb33SDmitri Tikhonov}
18650aadb33SDmitri Tikhonov
18750aadb33SDmitri Tikhonov
18850aadb33SDmitri Tikhonovvoid
18950aadb33SDmitri Tikhonovlsquic_hash_erase (struct lsquic_hash *hash, struct lsquic_hash_elem *el)
19050aadb33SDmitri Tikhonov{
19150aadb33SDmitri Tikhonov    unsigned buckno;
19250aadb33SDmitri Tikhonov
19350aadb33SDmitri Tikhonov    buckno = BUCKNO(hash->qh_nbits, el->qhe_hash_val);
19450aadb33SDmitri Tikhonov    TAILQ_REMOVE(&hash->qh_buckets[buckno], el, qhe_next_bucket);
19550aadb33SDmitri Tikhonov    TAILQ_REMOVE(&hash->qh_all, el, qhe_next_all);
19650aadb33SDmitri Tikhonov    lsquic_malo_put(el);
19750aadb33SDmitri Tikhonov    --hash->qh_count;
19850aadb33SDmitri Tikhonov}
19950aadb33SDmitri Tikhonov
20050aadb33SDmitri Tikhonov
20150aadb33SDmitri Tikhonovvoid
20250aadb33SDmitri Tikhonovlsquic_hash_reset_iter (struct lsquic_hash *hash)
20350aadb33SDmitri Tikhonov{
20450aadb33SDmitri Tikhonov    hash->qh_iter_next = TAILQ_FIRST(&hash->qh_all);
20550aadb33SDmitri Tikhonov}
20650aadb33SDmitri Tikhonov
20750aadb33SDmitri Tikhonov
20850aadb33SDmitri Tikhonovstruct lsquic_hash_elem *
20950aadb33SDmitri Tikhonovlsquic_hash_first (struct lsquic_hash *hash)
21050aadb33SDmitri Tikhonov{
21150aadb33SDmitri Tikhonov    lsquic_hash_reset_iter(hash);
21250aadb33SDmitri Tikhonov    return lsquic_hash_next(hash);
21350aadb33SDmitri Tikhonov}
21450aadb33SDmitri Tikhonov
21550aadb33SDmitri Tikhonov
21650aadb33SDmitri Tikhonovstruct lsquic_hash_elem *
21750aadb33SDmitri Tikhonovlsquic_hash_next (struct lsquic_hash *hash)
21850aadb33SDmitri Tikhonov{
21950aadb33SDmitri Tikhonov    struct lsquic_hash_elem *el;
22050aadb33SDmitri Tikhonov    el = hash->qh_iter_next;
22150aadb33SDmitri Tikhonov    if (el)
22250aadb33SDmitri Tikhonov        hash->qh_iter_next = TAILQ_NEXT(el, qhe_next_all);
22350aadb33SDmitri Tikhonov    return el;
22450aadb33SDmitri Tikhonov}
22550aadb33SDmitri Tikhonov
22650aadb33SDmitri Tikhonov
22750aadb33SDmitri Tikhonovunsigned
22850aadb33SDmitri Tikhonovlsquic_hash_count (struct lsquic_hash *hash)
22950aadb33SDmitri Tikhonov{
23050aadb33SDmitri Tikhonov    return hash->qh_count;
23150aadb33SDmitri Tikhonov}
232c51ce338SDmitri Tikhonov
233c51ce338SDmitri Tikhonov
234c51ce338SDmitri Tikhonovsize_t
235c51ce338SDmitri Tikhonovlsquic_hash_mem_used (const struct lsquic_hash *hash)
236c51ce338SDmitri Tikhonov{
237c51ce338SDmitri Tikhonov    return sizeof(*hash)
238c51ce338SDmitri Tikhonov         + N_BUCKETS(hash->qh_nbits) * sizeof(hash->qh_buckets[0])
239c51ce338SDmitri Tikhonov         + lsquic_malo_mem_used(hash->qh_malo_els);
240c51ce338SDmitri Tikhonov}
241