Initial version.
This commit is contained in:
153
src/nxt_lvlhsh_pool.c
Normal file
153
src/nxt_lvlhsh_pool.c
Normal file
@@ -0,0 +1,153 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) NGINX, Inc.
|
||||
*/
|
||||
|
||||
#include <nxt_main.h>
|
||||
|
||||
|
||||
typedef struct nxt_lvlhsh_pool_cache_s nxt_lvlhsh_pool_cache_t;
|
||||
|
||||
struct nxt_lvlhsh_pool_cache_s {
|
||||
uint32_t size;
|
||||
uint32_t nalloc;
|
||||
void *free;
|
||||
nxt_lvlhsh_pool_cache_t *next;
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
nxt_mem_pool_t *mem_pool;
|
||||
void *free;
|
||||
nxt_lvlhsh_pool_cache_t *next;
|
||||
} nxt_lvlhsh_pool_t;
|
||||
|
||||
|
||||
/*
|
||||
* lvlhsh requires allocations aligned to a size of the allocations.
|
||||
* This is not issue for slab-like allocators, but glibc allocator may
|
||||
* waste memory on such aligned allocations. So nxt_lvlhsh_pool_alloc()
|
||||
* allocates memory in chunks specified by the "nalloc" parameter
|
||||
* except the first allocation. The first lvlhsh allocation is a bucket
|
||||
* allocation and it is enough for a small hash or for early stage of
|
||||
* a large hash. By default lvlhsh uses 128-bytes or 64-bytes buckets
|
||||
* and levels on 64-bit and 32-bit platforms respectively.
|
||||
* This allows to search up to 10 entries in one memory access and
|
||||
* up to 160 entries in two memory accesses on 64-bit platform.
|
||||
* And on 32-bit platform up to 7 entries and up to 112 entries
|
||||
* respectively.
|
||||
*
|
||||
* After the bucket has been filled up with 10 64-bit entries
|
||||
* or 7 32-bit entries, lvlhsh expands it to a level and spreads
|
||||
* content of the first bucket to the level's new buckets.
|
||||
* Number of the new allocations may be up to 11 on 64-bit or
|
||||
* 8 on 32-bit platforms. It's better to allocate them together
|
||||
* to eliminate wasting memory and CPU time.
|
||||
*
|
||||
* The "nalloc" should be 16.
|
||||
*/
|
||||
|
||||
|
||||
static void *nxt_lvlhsh_pool_alloc_chunk(nxt_mem_pool_cache_t *cache,
|
||||
size_t size, nxt_uint_t nalloc);
|
||||
|
||||
|
||||
/* Allocation of lvlhsh level or bucket with specified size. */
|
||||
|
||||
void *
|
||||
nxt_lvlhsh_pool_alloc(void *ctx, size_t size, nxt_uint_t nalloc)
|
||||
{
|
||||
void *p, **pp;
|
||||
nxt_mem_pool_t *mp;
|
||||
nxt_mem_pool_cache_t *cache;
|
||||
|
||||
mp = ctx;
|
||||
|
||||
for (cache = mp->cache; cache != NULL; cache = cache->next) {
|
||||
|
||||
if (cache->size == size && cache->nalloc != 0) {
|
||||
|
||||
if (cache->free != NULL) {
|
||||
pp = cache->free;
|
||||
cache->free = *pp;
|
||||
return pp;
|
||||
}
|
||||
|
||||
return nxt_lvlhsh_pool_alloc_chunk(cache, size, nalloc);
|
||||
}
|
||||
}
|
||||
|
||||
cache = nxt_mem_alloc(mp, sizeof(nxt_mem_pool_cache_t));
|
||||
|
||||
if (nxt_fast_path(cache != NULL)) {
|
||||
|
||||
p = nxt_memalign(size, size);
|
||||
|
||||
if (nxt_fast_path(p != NULL)) {
|
||||
cache->size = size;
|
||||
cache->nalloc = nalloc;
|
||||
cache->free = NULL;
|
||||
cache->next = mp->cache;
|
||||
mp->cache = cache;
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
nxt_lvlhsh_pool_alloc_chunk(nxt_mem_pool_cache_t *cache, size_t size,
|
||||
nxt_uint_t nalloc)
|
||||
{
|
||||
char *m, *p, *end;
|
||||
void **pp;
|
||||
size_t n;
|
||||
|
||||
n = (nalloc == 0) ? 1 : nalloc;
|
||||
n *= size;
|
||||
|
||||
m = nxt_memalign(size, n);
|
||||
|
||||
if (nxt_fast_path(m != NULL)) {
|
||||
|
||||
pp = &cache->free;
|
||||
end = m + n;
|
||||
|
||||
for (p = m + size; p < end; p = p + size) {
|
||||
*pp = p;
|
||||
pp = (void **) p;
|
||||
}
|
||||
|
||||
*pp = NULL;
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Deallocation of lvlhsh level or bucket with specified size. */
|
||||
|
||||
void
|
||||
nxt_lvlhsh_pool_free(void *ctx, void *p, size_t size)
|
||||
{
|
||||
void **pp;
|
||||
nxt_mem_pool_t *mp;
|
||||
nxt_mem_pool_cache_t *cache;
|
||||
|
||||
mp = ctx;
|
||||
|
||||
pp = p;
|
||||
|
||||
for (cache = mp->cache; cache != NULL; cache = cache->next) {
|
||||
|
||||
if (cache->size == size && cache->nalloc != 0) {
|
||||
*pp = cache->free;
|
||||
cache->free = p;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user