Skip to content

Commit

Permalink
nghttp3_map: Port ngtcp2 changes
Browse files Browse the repository at this point in the history
  • Loading branch information
tatsuhiro-t committed Sep 10, 2024
1 parent 7473d2f commit a0e5fb0
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 77 deletions.
122 changes: 47 additions & 75 deletions lib/nghttp3_map.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@

void nghttp3_map_init(nghttp3_map *map, const nghttp3_mem *mem) {
map->mem = mem;
map->tablelenbits = 0;
map->hashbits = 0;
map->table = NULL;
map->size = 0;
}
Expand All @@ -60,7 +60,7 @@ int nghttp3_map_each(const nghttp3_map *map, int (*func)(void *data, void *ptr),
return 0;
}

tablelen = 1u << map->tablelenbits;
tablelen = 1u << map->hashbits;

for (i = 0; i < tablelen; ++i) {
bkt = &map->table[i];
Expand All @@ -78,38 +78,15 @@ int nghttp3_map_each(const nghttp3_map *map, int (*func)(void *data, void *ptr),
return 0;
}

static uint32_t hash(nghttp3_map_key_type key) {
return (uint32_t)((key * 11400714819323198485llu) >> 32);
static size_t hash(nghttp3_map_key_type key, size_t bits) {
return (size_t)((key * 11400714819323198485llu) >> (64 - bits));
}

static size_t h2idx(uint32_t hash, size_t bits) { return hash >> (32 - bits); }

static void map_bucket_swap(nghttp3_map_bucket *bkt, uint32_t *phash,
uint32_t *ppsl, nghttp3_map_key_type *pkey,
void **pdata) {
uint32_t h = bkt->hash;
uint32_t psl = bkt->psl;
nghttp3_map_key_type key = bkt->key;
void *data = bkt->data;

bkt->hash = *phash;
bkt->psl = *ppsl;
bkt->key = *pkey;
bkt->data = *pdata;

*phash = h;
*ppsl = psl;
*pkey = key;
*pdata = data;
}
static void map_bucket_swap(nghttp3_map_bucket *a, nghttp3_map_bucket *b) {
nghttp3_map_bucket c = *a;

static void map_bucket_set_data(nghttp3_map_bucket *bkt, uint32_t hash,
uint32_t psl, nghttp3_map_key_type key,
void *data) {
bkt->hash = hash;
bkt->psl = psl;
bkt->key = key;
bkt->data = data;
*a = *b;
*b = c;
}

#ifndef WIN32
Expand All @@ -123,7 +100,7 @@ void nghttp3_map_print_distance(const nghttp3_map *map) {
return;
}

tablelen = 1u << map->tablelenbits;
tablelen = 1u << map->hashbits;

for (i = 0; i < tablelen; ++i) {
bkt = &map->table[i];
Expand All @@ -133,30 +110,29 @@ void nghttp3_map_print_distance(const nghttp3_map *map) {
continue;
}

idx = h2idx(bkt->hash, map->tablelenbits);
fprintf(stderr, "@%zu hash=%08x key=%" PRIu64 " base=%zu distance=%u\n", i,
bkt->hash, bkt->key, idx, bkt->psl);
idx = hash(bkt->key, map->hashbits);
fprintf(stderr, "@%zu hash=%zu key=%" PRIu64 " base=%zu distance=%u\n", i,
hash(bkt->key, map->hashbits), bkt->key, idx, bkt->psl);
}
}
#endif /* !WIN32 */

static int insert(nghttp3_map_bucket *table, size_t tablelenbits, uint32_t hash,
static int insert(nghttp3_map_bucket *table, size_t hashbits,
nghttp3_map_key_type key, void *data) {
size_t idx = h2idx(hash, tablelenbits);
uint32_t psl = 0;
nghttp3_map_bucket *bkt;
size_t mask = (1u << tablelenbits) - 1;
size_t idx = hash(key, hashbits);
nghttp3_map_bucket b = {0, key, data}, *bkt;
size_t mask = (1u << hashbits) - 1;

for (;;) {
bkt = &table[idx];

if (bkt->data == NULL) {
map_bucket_set_data(bkt, hash, psl, key, data);
*bkt = b;
return 0;
}

if (psl > bkt->psl) {
map_bucket_swap(bkt, &hash, &psl, &key, &data);
if (b.psl > bkt->psl) {
map_bucket_swap(bkt, &b);
} else if (bkt->key == key) {
/* TODO This check is just a waste after first swap or if this
function is called from map_resize. That said, there is no
Expand All @@ -165,42 +141,42 @@ static int insert(nghttp3_map_bucket *table, size_t tablelenbits, uint32_t hash,
return NGHTTP3_ERR_INVALID_ARGUMENT;
}

++psl;
++b.psl;
idx = (idx + 1) & mask;
}
}

static int map_resize(nghttp3_map *map, size_t new_tablelenbits) {
static int map_resize(nghttp3_map *map, size_t new_hashbits) {
size_t i;
nghttp3_map_bucket *new_table;
nghttp3_map_bucket *bkt;
size_t tablelen;
int rv;
(void)rv;

new_table = nghttp3_mem_calloc(map->mem, 1u << new_tablelenbits,
new_table = nghttp3_mem_calloc(map->mem, 1u << new_hashbits,
sizeof(nghttp3_map_bucket));
if (new_table == NULL) {
return NGHTTP3_ERR_NOMEM;
}

if (map->size) {
tablelen = 1u << map->tablelenbits;
tablelen = 1u << map->hashbits;

for (i = 0; i < tablelen; ++i) {
bkt = &map->table[i];
if (bkt->data == NULL) {
continue;
}

rv = insert(new_table, new_tablelenbits, bkt->hash, bkt->key, bkt->data);
rv = insert(new_table, new_hashbits, bkt->key, bkt->data);

assert(0 == rv);
}
}

nghttp3_mem_free(map->mem, map->table);
map->tablelenbits = new_tablelenbits;
map->hashbits = new_hashbits;
map->table = new_table;

return 0;
Expand All @@ -213,10 +189,10 @@ int nghttp3_map_insert(nghttp3_map *map, nghttp3_map_key_type key, void *data) {

/* Load factor is 0.75 */
/* Under the very initial condition, that is map->size == 0 and
map->tablelenbits == 0, 4 > 3 still holds nicely. */
if ((map->size + 1) * 4 > (1u << map->tablelenbits) * 3) {
if (map->tablelenbits) {
rv = map_resize(map, map->tablelenbits + 1);
map->hashbits == 0, 4 > 3 still holds nicely. */
if ((map->size + 1) * 4 > (1u << map->hashbits) * 3) {
if (map->hashbits) {
rv = map_resize(map, map->hashbits + 1);
if (rv != 0) {
return rv;
}
Expand All @@ -228,7 +204,7 @@ int nghttp3_map_insert(nghttp3_map *map, nghttp3_map_key_type key, void *data) {
}
}

rv = insert(map->table, map->tablelenbits, hash(key), key, data);
rv = insert(map->table, map->hashbits, key, data);
if (rv != 0) {
return rv;
}
Expand All @@ -239,72 +215,68 @@ int nghttp3_map_insert(nghttp3_map *map, nghttp3_map_key_type key, void *data) {
}

void *nghttp3_map_find(const nghttp3_map *map, nghttp3_map_key_type key) {
uint32_t h;
size_t idx;
nghttp3_map_bucket *bkt;
size_t d = 0;
size_t psl = 0;
size_t mask;

if (map->size == 0) {
return NULL;
}

h = hash(key);
idx = h2idx(h, map->tablelenbits);
mask = (1u << map->tablelenbits) - 1;
idx = hash(key, map->hashbits);
mask = (1u << map->hashbits) - 1;

for (;;) {
bkt = &map->table[idx];

if (bkt->data == NULL || d > bkt->psl) {
if (bkt->data == NULL || psl > bkt->psl) {
return NULL;
}

if (bkt->key == key) {
return bkt->data;
}

++d;
++psl;
idx = (idx + 1) & mask;
}
}

int nghttp3_map_remove(nghttp3_map *map, nghttp3_map_key_type key) {
uint32_t h;
size_t idx, didx;
nghttp3_map_bucket *bkt;
size_t d = 0;
size_t idx;
nghttp3_map_bucket *b, *bkt;
size_t psl = 0;
size_t mask;

if (map->size == 0) {
return NGHTTP3_ERR_INVALID_ARGUMENT;
}

h = hash(key);
idx = h2idx(h, map->tablelenbits);
mask = (1u << map->tablelenbits) - 1;
idx = hash(key, map->hashbits);
mask = (1u << map->hashbits) - 1;

for (;;) {
bkt = &map->table[idx];

if (bkt->data == NULL || d > bkt->psl) {
if (bkt->data == NULL || psl > bkt->psl) {
return NGHTTP3_ERR_INVALID_ARGUMENT;
}

if (bkt->key == key) {
didx = idx;
b = bkt;
idx = (idx + 1) & mask;

for (;;) {
bkt = &map->table[idx];
if (bkt->data == NULL || bkt->psl == 0) {
map_bucket_set_data(&map->table[didx], 0, 0, 0, NULL);
b->data = NULL;
break;
}

--bkt->psl;
map->table[didx] = *bkt;
didx = idx;
*b = *bkt;
b = bkt;

idx = (idx + 1) & mask;
}
Expand All @@ -314,7 +286,7 @@ int nghttp3_map_remove(nghttp3_map *map, nghttp3_map_key_type key) {
return 0;
}

++d;
++psl;
idx = (idx + 1) & mask;
}
}
Expand All @@ -324,7 +296,7 @@ void nghttp3_map_clear(nghttp3_map *map) {
return;
}

memset(map->table, 0, sizeof(*map->table) * (1u << map->tablelenbits));
memset(map->table, 0, sizeof(*map->table) * (1u << map->hashbits));
map->size = 0;
}

Expand Down
3 changes: 1 addition & 2 deletions lib/nghttp3_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
typedef uint64_t nghttp3_map_key_type;

typedef struct nghttp3_map_bucket {
uint32_t hash;
uint32_t psl;
nghttp3_map_key_type key;
void *data;
Expand All @@ -50,7 +49,7 @@ typedef struct nghttp3_map {
nghttp3_map_bucket *table;
const nghttp3_mem *mem;
size_t size;
size_t tablelenbits;
size_t hashbits;
} nghttp3_map;

/*
Expand Down

0 comments on commit a0e5fb0

Please sign in to comment.