1a74702c6SGeorge Wang/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc.  See LICENSE. */
25392f7a3SLiteSpeed Tech/*
35392f7a3SLiteSpeed Tech * lsquic_stock_shi.c
45392f7a3SLiteSpeed Tech */
55392f7a3SLiteSpeed Tech
65392f7a3SLiteSpeed Tech#include <errno.h>
75392f7a3SLiteSpeed Tech#include <stdlib.h>
85392f7a3SLiteSpeed Tech#include <string.h>
95392f7a3SLiteSpeed Tech#include <sys/queue.h>
105392f7a3SLiteSpeed Tech#include <time.h>
115392f7a3SLiteSpeed Tech
125392f7a3SLiteSpeed Tech#include "lsquic.h"
135392f7a3SLiteSpeed Tech#include "lsquic_stock_shi.h"
145392f7a3SLiteSpeed Tech#include "lsquic_malo.h"
155392f7a3SLiteSpeed Tech#include "lsquic_hash.h"
165392f7a3SLiteSpeed Tech
175392f7a3SLiteSpeed Techstruct stock_shared_hash
185392f7a3SLiteSpeed Tech{
195392f7a3SLiteSpeed Tech    TAILQ_HEAD(, hash_elem)     lru_elems;
205392f7a3SLiteSpeed Tech    struct lsquic_hash         *lhash;
215392f7a3SLiteSpeed Tech    struct malo                *malo;
225392f7a3SLiteSpeed Tech};
235392f7a3SLiteSpeed Tech
245392f7a3SLiteSpeed Tech
255392f7a3SLiteSpeed Techstruct key
265392f7a3SLiteSpeed Tech{
275392f7a3SLiteSpeed Tech    void         *buf;
285392f7a3SLiteSpeed Tech    unsigned      sz;
295392f7a3SLiteSpeed Tech};
305392f7a3SLiteSpeed Tech
315392f7a3SLiteSpeed Tech
325392f7a3SLiteSpeed Techstruct hash_elem
335392f7a3SLiteSpeed Tech{
345392f7a3SLiteSpeed Tech    TAILQ_ENTRY(hash_elem)  next_lru_he;
355392f7a3SLiteSpeed Tech    struct lsquic_hash_elem lhash_elem;
365392f7a3SLiteSpeed Tech    void                   *data;
375392f7a3SLiteSpeed Tech    time_t                  expiry;         /* If not 0, the element is on LRU list */
385392f7a3SLiteSpeed Tech    struct key              key;
395392f7a3SLiteSpeed Tech    unsigned                data_sz;
405392f7a3SLiteSpeed Tech};
415392f7a3SLiteSpeed Tech
425392f7a3SLiteSpeed Tech
435392f7a3SLiteSpeed Techstatic void
445392f7a3SLiteSpeed Techfree_key_data (struct hash_elem *he)
455392f7a3SLiteSpeed Tech{
465392f7a3SLiteSpeed Tech    if (he->data_sz)
475392f7a3SLiteSpeed Tech        free(he->data);
485392f7a3SLiteSpeed Tech    free(he->key.buf);
495392f7a3SLiteSpeed Tech}
505392f7a3SLiteSpeed Tech
515392f7a3SLiteSpeed Tech
525392f7a3SLiteSpeed Techstatic void
535392f7a3SLiteSpeed Techdelete_expired_elements (struct stock_shared_hash *hash)
545392f7a3SLiteSpeed Tech{
555392f7a3SLiteSpeed Tech    struct hash_elem *he;
565392f7a3SLiteSpeed Tech    time_t now = time(NULL);
575392f7a3SLiteSpeed Tech    while ((he = TAILQ_FIRST(&hash->lru_elems)))
585392f7a3SLiteSpeed Tech    {
595392f7a3SLiteSpeed Tech        if (he->expiry < now)
605392f7a3SLiteSpeed Tech        {
615392f7a3SLiteSpeed Tech            lsquic_hash_erase(hash->lhash, &he->lhash_elem);
625392f7a3SLiteSpeed Tech            if (he->expiry)
635392f7a3SLiteSpeed Tech                TAILQ_REMOVE(&hash->lru_elems, he, next_lru_he);
645392f7a3SLiteSpeed Tech            free_key_data(he);
655392f7a3SLiteSpeed Tech            lsquic_malo_put(he);
665392f7a3SLiteSpeed Tech        }
675392f7a3SLiteSpeed Tech        else
685392f7a3SLiteSpeed Tech            break;
695392f7a3SLiteSpeed Tech    }
705392f7a3SLiteSpeed Tech}
715392f7a3SLiteSpeed Tech
725392f7a3SLiteSpeed Tech
735392f7a3SLiteSpeed Techstatic int
745392f7a3SLiteSpeed Techstock_shi_insert (void *hash_ctx, void *key, unsigned key_sz,
755392f7a3SLiteSpeed Tech                  void *data, unsigned data_sz, time_t expiry)
765392f7a3SLiteSpeed Tech{
775392f7a3SLiteSpeed Tech    struct stock_shared_hash *const hash = hash_ctx;
785392f7a3SLiteSpeed Tech    struct hash_elem *he;
795392f7a3SLiteSpeed Tech
805392f7a3SLiteSpeed Tech    /* Potential optimization: do not exire on every insert.  Use case:
815392f7a3SLiteSpeed Tech     * if many insert occur in a row, it is not efficient to perform
825392f7a3SLiteSpeed Tech     * this check every time.  Can add a counter in hash.
835392f7a3SLiteSpeed Tech     */
845392f7a3SLiteSpeed Tech    if (!TAILQ_EMPTY(&hash->lru_elems))
855392f7a3SLiteSpeed Tech        delete_expired_elements(hash);
865392f7a3SLiteSpeed Tech
875392f7a3SLiteSpeed Tech    he = lsquic_malo_get(hash->malo);
885392f7a3SLiteSpeed Tech    if (!he)
895392f7a3SLiteSpeed Tech        return -1;
905392f7a3SLiteSpeed Tech    he->key.buf = key;
915392f7a3SLiteSpeed Tech    he->key.sz  = key_sz;
925392f7a3SLiteSpeed Tech    he->data    = data;
935392f7a3SLiteSpeed Tech    he->data_sz = data_sz;
945392f7a3SLiteSpeed Tech    he->expiry = expiry;
955392f7a3SLiteSpeed Tech    memset(&he->lhash_elem, 0, sizeof(he->lhash_elem));
965392f7a3SLiteSpeed Tech    if (lsquic_hash_insert(hash->lhash, he->key.buf,
975392f7a3SLiteSpeed Tech                                            he->key.sz, he, &he->lhash_elem))
985392f7a3SLiteSpeed Tech    {
995392f7a3SLiteSpeed Tech        if (expiry)
1005392f7a3SLiteSpeed Tech            TAILQ_INSERT_TAIL(&hash->lru_elems, he, next_lru_he);
1015392f7a3SLiteSpeed Tech        return 0;
1025392f7a3SLiteSpeed Tech    }
1035392f7a3SLiteSpeed Tech    else
1045392f7a3SLiteSpeed Tech    {
1055392f7a3SLiteSpeed Tech        lsquic_malo_put(he);
1065392f7a3SLiteSpeed Tech        return -1;
1075392f7a3SLiteSpeed Tech    }
1085392f7a3SLiteSpeed Tech}
1095392f7a3SLiteSpeed Tech
1105392f7a3SLiteSpeed Tech
1115392f7a3SLiteSpeed Techstatic int
1125392f7a3SLiteSpeed Techstock_shi_lookup (void *hash_ctx, const void *key, unsigned key_sz,
1135392f7a3SLiteSpeed Tech                                  void     **data, unsigned *data_sz)
1145392f7a3SLiteSpeed Tech{
1155392f7a3SLiteSpeed Tech    struct stock_shared_hash *const hash = hash_ctx;
1165392f7a3SLiteSpeed Tech    struct hash_elem *he;
1175392f7a3SLiteSpeed Tech    struct lsquic_hash_elem *el;
1185392f7a3SLiteSpeed Tech
1195392f7a3SLiteSpeed Tech    if (!TAILQ_EMPTY(&hash->lru_elems))
1205392f7a3SLiteSpeed Tech        delete_expired_elements(hash);
1215392f7a3SLiteSpeed Tech
1225392f7a3SLiteSpeed Tech    el = lsquic_hash_find(hash->lhash, key, key_sz);
1235392f7a3SLiteSpeed Tech    if (!el)
1245392f7a3SLiteSpeed Tech        return 0;                                   /* 0: not found */
1255392f7a3SLiteSpeed Tech    he = lsquic_hashelem_getdata(el);
1265392f7a3SLiteSpeed Tech    *data    = he->data;
1275392f7a3SLiteSpeed Tech    *data_sz = he->data_sz;
1285392f7a3SLiteSpeed Tech    return 1;                                       /* 1: found */
1295392f7a3SLiteSpeed Tech}
1305392f7a3SLiteSpeed Tech
1315392f7a3SLiteSpeed Tech
1325392f7a3SLiteSpeed Techstatic int
1335392f7a3SLiteSpeed Techstock_shi_delete (void *hash_ctx, const void *key, unsigned key_sz)
1345392f7a3SLiteSpeed Tech{
1355392f7a3SLiteSpeed Tech    struct stock_shared_hash *const hash = hash_ctx;
1365392f7a3SLiteSpeed Tech    struct lsquic_hash_elem *el;
1375392f7a3SLiteSpeed Tech    struct hash_elem *he;
1385392f7a3SLiteSpeed Tech
1395392f7a3SLiteSpeed Tech    if (!TAILQ_EMPTY(&hash->lru_elems))
1405392f7a3SLiteSpeed Tech        delete_expired_elements(hash);
1415392f7a3SLiteSpeed Tech
1425392f7a3SLiteSpeed Tech    el = lsquic_hash_find(hash->lhash, key, key_sz);
1435392f7a3SLiteSpeed Tech    if (!el)
1445392f7a3SLiteSpeed Tech        return -1;
1455392f7a3SLiteSpeed Tech
1465392f7a3SLiteSpeed Tech    he = lsquic_hashelem_getdata(el);
1475392f7a3SLiteSpeed Tech    lsquic_hash_erase(hash->lhash, el);
1485392f7a3SLiteSpeed Tech    if (he->expiry)
1495392f7a3SLiteSpeed Tech        TAILQ_REMOVE(&hash->lru_elems, he, next_lru_he);
1505392f7a3SLiteSpeed Tech
1515392f7a3SLiteSpeed Tech    free_key_data(he);
1525392f7a3SLiteSpeed Tech    lsquic_malo_put(he);
1535392f7a3SLiteSpeed Tech    return 0;
1545392f7a3SLiteSpeed Tech}
1555392f7a3SLiteSpeed Tech
1565392f7a3SLiteSpeed Tech
1575392f7a3SLiteSpeed Techstruct stock_shared_hash *
158a5fa05f9SDmitri Tikhonovlsquic_stock_shared_hash_new (void)
1595392f7a3SLiteSpeed Tech{
1605392f7a3SLiteSpeed Tech    struct malo *malo;
1615392f7a3SLiteSpeed Tech    struct stock_shared_hash *hash;
1625392f7a3SLiteSpeed Tech
1635392f7a3SLiteSpeed Tech    malo = lsquic_malo_create(sizeof(struct hash_elem));
1645392f7a3SLiteSpeed Tech    if (!malo)
1655392f7a3SLiteSpeed Tech        return NULL;
1665392f7a3SLiteSpeed Tech
1675392f7a3SLiteSpeed Tech    hash = lsquic_malo_get(malo);
1685392f7a3SLiteSpeed Tech    if (!hash)
1695392f7a3SLiteSpeed Tech    {   /* This would be really odd, but let's check this for completeness. */
1705392f7a3SLiteSpeed Tech        lsquic_malo_destroy(malo);
1715392f7a3SLiteSpeed Tech        return NULL;
1725392f7a3SLiteSpeed Tech    }
1735392f7a3SLiteSpeed Tech
1745392f7a3SLiteSpeed Tech    hash->malo = malo;
1755392f7a3SLiteSpeed Tech    hash->lhash = lsquic_hash_create();
1765392f7a3SLiteSpeed Tech    TAILQ_INIT(&hash->lru_elems);
1775392f7a3SLiteSpeed Tech    return hash;
1785392f7a3SLiteSpeed Tech}
1795392f7a3SLiteSpeed Tech
1805392f7a3SLiteSpeed Tech
1815392f7a3SLiteSpeed Techvoid
182a5fa05f9SDmitri Tikhonovlsquic_stock_shared_hash_destroy (struct stock_shared_hash *hash)
1835392f7a3SLiteSpeed Tech{
1845392f7a3SLiteSpeed Tech    struct hash_elem *he;
1855392f7a3SLiteSpeed Tech    struct lsquic_hash_elem *el;
1865392f7a3SLiteSpeed Tech    for (el = lsquic_hash_first(hash->lhash); el;
1875392f7a3SLiteSpeed Tech                                        el = lsquic_hash_next(hash->lhash))
1885392f7a3SLiteSpeed Tech    {
1895392f7a3SLiteSpeed Tech        he = lsquic_hashelem_getdata(el);
1905392f7a3SLiteSpeed Tech        free_key_data(he);
1915392f7a3SLiteSpeed Tech        /* No need to lsquic_malo_put(he) here */
1925392f7a3SLiteSpeed Tech    }
1935392f7a3SLiteSpeed Tech    lsquic_hash_destroy(hash->lhash);
1945392f7a3SLiteSpeed Tech    lsquic_malo_destroy(hash->malo);
1955392f7a3SLiteSpeed Tech}
1965392f7a3SLiteSpeed Tech
1975392f7a3SLiteSpeed Tech
1985392f7a3SLiteSpeed Techconst struct lsquic_shared_hash_if stock_shi =
1995392f7a3SLiteSpeed Tech{
2005392f7a3SLiteSpeed Tech    .shi_insert = stock_shi_insert,
2015392f7a3SLiteSpeed Tech    .shi_delete = stock_shi_delete,
2025392f7a3SLiteSpeed Tech    .shi_lookup = stock_shi_lookup,
2035392f7a3SLiteSpeed Tech};
2045392f7a3SLiteSpeed Tech
2055392f7a3SLiteSpeed Tech
2065392f7a3SLiteSpeed Tech/* Need this to save one malloc using malo: */
2075392f7a3SLiteSpeed Techtypedef char hash_not_larger_than_hash_elem [
208fb3e20e0SDmitri Tikhonov            (sizeof(struct stock_shared_hash) <= sizeof(struct hash_elem)) ? 1 : -1];
209