nxt_lvlhsh_retrieve().
This commit is contained in:
108
src/nxt_lvlhsh.c
108
src/nxt_lvlhsh.c
@@ -166,6 +166,13 @@ nxt_lvlhsh_set_entry_key(e, n) \
|
|||||||
#define NXT_LVLHSH_BUCKET_DONE ((void *) -1)
|
#define NXT_LVLHSH_BUCKET_DONE ((void *) -1)
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const nxt_lvlhsh_proto_t *proto;
|
||||||
|
void *pool;
|
||||||
|
uint32_t retrieve; /* 1 bit */
|
||||||
|
} nxt_lvlhsh_peek_t;
|
||||||
|
|
||||||
|
|
||||||
static nxt_int_t nxt_lvlhsh_level_find(nxt_lvlhsh_query_t *lhq, void **lvl,
|
static nxt_int_t nxt_lvlhsh_level_find(nxt_lvlhsh_query_t *lhq, void **lvl,
|
||||||
uint32_t key, nxt_uint_t nlvl);
|
uint32_t key, nxt_uint_t nlvl);
|
||||||
static nxt_int_t nxt_lvlhsh_bucket_find(nxt_lvlhsh_query_t *lhq, void **bkt);
|
static nxt_int_t nxt_lvlhsh_bucket_find(nxt_lvlhsh_query_t *lhq, void **bkt);
|
||||||
@@ -188,10 +195,9 @@ static nxt_int_t nxt_lvlhsh_bucket_delete(nxt_lvlhsh_query_t *lhq, void **bkt);
|
|||||||
static void *nxt_lvlhsh_level_each(nxt_lvlhsh_each_t *lhe, void **level,
|
static void *nxt_lvlhsh_level_each(nxt_lvlhsh_each_t *lhe, void **level,
|
||||||
nxt_uint_t nlvl, nxt_uint_t shift);
|
nxt_uint_t nlvl, nxt_uint_t shift);
|
||||||
static void *nxt_lvlhsh_bucket_each(nxt_lvlhsh_each_t *lhe);
|
static void *nxt_lvlhsh_bucket_each(nxt_lvlhsh_each_t *lhe);
|
||||||
static void *nxt_lvlhsh_level_peek(const nxt_lvlhsh_proto_t *proto,
|
static void *nxt_lvlhsh_level_peek(nxt_lvlhsh_peek_t *peek, void **level,
|
||||||
void **level, nxt_uint_t nlvl);
|
nxt_uint_t nlvl);
|
||||||
static void *nxt_lvlhsh_bucket_peek(const nxt_lvlhsh_proto_t *proto,
|
static void *nxt_lvlhsh_bucket_peek(nxt_lvlhsh_peek_t *peek, void **bkt);
|
||||||
void **bkt);
|
|
||||||
|
|
||||||
|
|
||||||
nxt_int_t
|
nxt_int_t
|
||||||
@@ -877,16 +883,20 @@ void *
|
|||||||
nxt_lvlhsh_peek(nxt_lvlhsh_t *lh, const nxt_lvlhsh_proto_t *proto)
|
nxt_lvlhsh_peek(nxt_lvlhsh_t *lh, const nxt_lvlhsh_proto_t *proto)
|
||||||
{
|
{
|
||||||
void **slot;
|
void **slot;
|
||||||
|
nxt_lvlhsh_peek_t peek;
|
||||||
|
|
||||||
slot = lh->slot;
|
slot = lh->slot;
|
||||||
|
|
||||||
if (slot != NULL) {
|
if (slot != NULL) {
|
||||||
|
|
||||||
|
peek.proto = proto;
|
||||||
|
peek.retrieve = 0;
|
||||||
|
|
||||||
if (nxt_lvlhsh_is_bucket(slot)) {
|
if (nxt_lvlhsh_is_bucket(slot)) {
|
||||||
return nxt_lvlhsh_bucket_peek(proto, slot);
|
return nxt_lvlhsh_bucket_peek(&peek, &lh->slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
return nxt_lvlhsh_level_peek(proto, slot, 0);
|
return nxt_lvlhsh_level_peek(&peek, &lh->slot, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -894,32 +904,47 @@ nxt_lvlhsh_peek(nxt_lvlhsh_t *lh, const nxt_lvlhsh_proto_t *proto)
|
|||||||
|
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
nxt_lvlhsh_level_peek(const nxt_lvlhsh_proto_t *proto, void **level,
|
nxt_lvlhsh_level_peek(nxt_lvlhsh_peek_t *peek, void **parent, nxt_uint_t nlvl)
|
||||||
nxt_uint_t nlvl)
|
|
||||||
{
|
{
|
||||||
void **slot;
|
void **slot, **level, *value;
|
||||||
uintptr_t mask;
|
uintptr_t mask;
|
||||||
nxt_uint_t n, shift;
|
nxt_uint_t n, shift;
|
||||||
|
|
||||||
shift = proto->shift[nlvl];
|
shift = peek->proto->shift[nlvl];
|
||||||
mask = ((uintptr_t) 1 << shift) - 1;
|
mask = ((uintptr_t) 1 << shift) - 1;
|
||||||
|
|
||||||
level = nxt_lvlhsh_level(level, mask);
|
level = nxt_lvlhsh_level(*parent, mask);
|
||||||
|
|
||||||
n = 0;
|
n = 0;
|
||||||
|
|
||||||
/* At least one valid level slot must present here. */
|
/* At least one valid level slot must present here. */
|
||||||
|
|
||||||
for ( ;; ) {
|
for ( ;; ) {
|
||||||
slot = level[n];
|
slot = &level[n];
|
||||||
|
|
||||||
if (slot != NULL) {
|
if (*slot != NULL) {
|
||||||
|
|
||||||
if (nxt_lvlhsh_is_bucket(slot)) {
|
if (nxt_lvlhsh_is_bucket(*slot)) {
|
||||||
return nxt_lvlhsh_bucket_peek(proto, slot);
|
value = nxt_lvlhsh_bucket_peek(peek, slot);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
value = nxt_lvlhsh_level_peek(peek, slot, nlvl + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return nxt_lvlhsh_level_peek(proto, slot, nlvl + 1);
|
/*
|
||||||
|
* Checking peek->retrieve is not required here because
|
||||||
|
* there can not be empty slots during peeking.
|
||||||
|
*/
|
||||||
|
if (*slot == NULL) {
|
||||||
|
nxt_lvlhsh_count_dec(*parent);
|
||||||
|
|
||||||
|
if (nxt_lvlhsh_level_entries(*parent, mask) == 0) {
|
||||||
|
*parent = NULL;
|
||||||
|
peek->proto->free(peek->pool, level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
n++;
|
n++;
|
||||||
@@ -927,15 +952,18 @@ nxt_lvlhsh_level_peek(const nxt_lvlhsh_proto_t *proto, void **level,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void *
|
static nxt_noinline void *
|
||||||
nxt_lvlhsh_bucket_peek(const nxt_lvlhsh_proto_t *proto, void **bkt)
|
nxt_lvlhsh_bucket_peek(nxt_lvlhsh_peek_t *peek, void **bkt)
|
||||||
{
|
{
|
||||||
void *value;
|
void *value;
|
||||||
uint32_t *entry;
|
uint32_t *bucket, *entry;
|
||||||
|
const nxt_lvlhsh_proto_t *proto;
|
||||||
|
|
||||||
|
bucket = nxt_lvlhsh_bucket(peek->proto, *bkt);
|
||||||
|
|
||||||
/* At least one valid entry must present here. */
|
/* At least one valid entry must present here. */
|
||||||
|
|
||||||
for (entry = nxt_lvlhsh_bucket(proto, bkt);
|
for (entry = bucket;
|
||||||
nxt_lvlhsh_free_entry(entry);
|
nxt_lvlhsh_free_entry(entry);
|
||||||
entry += NXT_LVLHSH_ENTRY_SIZE)
|
entry += NXT_LVLHSH_ENTRY_SIZE)
|
||||||
{
|
{
|
||||||
@@ -943,10 +971,50 @@ nxt_lvlhsh_bucket_peek(const nxt_lvlhsh_proto_t *proto, void **bkt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
value = nxt_lvlhsh_entry_value(entry);
|
value = nxt_lvlhsh_entry_value(entry);
|
||||||
|
|
||||||
|
if (peek->retrieve) {
|
||||||
|
proto = peek->proto;
|
||||||
|
|
||||||
|
if (nxt_lvlhsh_bucket_entries(proto, *bkt) == 1) {
|
||||||
|
*bkt = *nxt_lvlhsh_next_bucket(proto, bucket);
|
||||||
|
proto->free(peek->pool, bucket);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
nxt_lvlhsh_count_dec(*bkt);
|
||||||
|
nxt_lvlhsh_set_entry_value(entry, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *
|
||||||
|
nxt_lvlhsh_retrieve(nxt_lvlhsh_t *lh, const nxt_lvlhsh_proto_t *proto,
|
||||||
|
void *pool)
|
||||||
|
{
|
||||||
|
void **slot;
|
||||||
|
nxt_lvlhsh_peek_t peek;
|
||||||
|
|
||||||
|
slot = lh->slot;
|
||||||
|
|
||||||
|
if (slot != NULL) {
|
||||||
|
|
||||||
|
peek.proto = proto;
|
||||||
|
peek.pool = pool;
|
||||||
|
peek.retrieve = 1;
|
||||||
|
|
||||||
|
if (nxt_lvlhsh_is_bucket(slot)) {
|
||||||
|
return nxt_lvlhsh_bucket_peek(&peek, &lh->slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nxt_lvlhsh_level_peek(&peek, &lh->slot, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void *
|
void *
|
||||||
nxt_lvlhsh_alloc(void *data, size_t size)
|
nxt_lvlhsh_alloc(void *data, size_t size)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -173,6 +173,15 @@ NXT_EXPORT void *nxt_lvlhsh_each(nxt_lvlhsh_t *lh, nxt_lvlhsh_each_t *le);
|
|||||||
NXT_EXPORT void *nxt_lvlhsh_peek(nxt_lvlhsh_t *lh,
|
NXT_EXPORT void *nxt_lvlhsh_peek(nxt_lvlhsh_t *lh,
|
||||||
const nxt_lvlhsh_proto_t *proto);
|
const nxt_lvlhsh_proto_t *proto);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* nxt_lvlhsh_retrieve() is used to iterate over a lvlhsh during the lvlhsh
|
||||||
|
* destruction. As opposed to nxt_lvlhsh_peek() the returned hash element
|
||||||
|
* is deleted from the lvlhsh. The function returns NULL if there is no
|
||||||
|
* more elements in the lvlhsh.
|
||||||
|
*/
|
||||||
|
NXT_EXPORT void *nxt_lvlhsh_retrieve(nxt_lvlhsh_t *lh,
|
||||||
|
const nxt_lvlhsh_proto_t *proto, void *pool);
|
||||||
|
|
||||||
|
|
||||||
NXT_EXPORT void *nxt_lvlhsh_alloc(void *data, size_t size);
|
NXT_EXPORT void *nxt_lvlhsh_alloc(void *data, size_t size);
|
||||||
NXT_EXPORT void nxt_lvlhsh_free(void *data, void *p);
|
NXT_EXPORT void nxt_lvlhsh_free(void *data, void *p);
|
||||||
|
|||||||
@@ -222,6 +222,43 @@ nxt_lvlhsh_test(nxt_thread_t *thr, nxt_uint_t n, nxt_bool_t use_pool)
|
|||||||
return NXT_ERROR;
|
return NXT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!nxt_lvlhsh_is_empty(&lh)) {
|
||||||
|
nxt_log_error(NXT_LOG_NOTICE, thr->log,
|
||||||
|
"lvlhsh is not empty after deletion");
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
key = 0;
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
key = nxt_murmur_hash2(&key, sizeof(uint32_t));
|
||||||
|
|
||||||
|
if (nxt_lvlhsh_test_add(&lh, proto, mp, key) != NXT_OK) {
|
||||||
|
nxt_log_error(NXT_LOG_NOTICE, thr->log,
|
||||||
|
"lvlhsh add test failed at %ui", i);
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
value = nxt_lvlhsh_retrieve(&lh, proto, mp);
|
||||||
|
|
||||||
|
if (value == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i != n) {
|
||||||
|
nxt_log_error(NXT_LOG_NOTICE, thr->log,
|
||||||
|
"lvlhsh retrieve test failed at %ui of %ui", i, n);
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nxt_lvlhsh_is_empty(&lh)) {
|
||||||
|
nxt_log_error(NXT_LOG_NOTICE, thr->log,
|
||||||
|
"lvlhsh is not empty after retrieving");
|
||||||
|
return NXT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
if (mp != NULL) {
|
if (mp != NULL) {
|
||||||
if (!nxt_mp_is_empty(mp)) {
|
if (!nxt_mp_is_empty(mp)) {
|
||||||
nxt_log_error(NXT_LOG_NOTICE, thr->log, "mem pool is not empty");
|
nxt_log_error(NXT_LOG_NOTICE, thr->log, "mem pool is not empty");
|
||||||
|
|||||||
Reference in New Issue
Block a user