|
Packit |
b2c0d9 |
/*
|
|
Packit |
b2c0d9 |
Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
|
|
Packit |
b2c0d9 |
This file is part of GlusterFS.
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
This file is licensed to you under your choice of the GNU Lesser
|
|
Packit |
b2c0d9 |
General Public License, version 3 or any later version (LGPLv3 or
|
|
Packit |
b2c0d9 |
later), or the GNU General Public License, version 2 (GPLv2), in all
|
|
Packit |
b2c0d9 |
cases as published by the Free Software Foundation.
|
|
Packit |
b2c0d9 |
*/
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
#include "glusterfs/rbthash.h"
|
|
Packit |
b2c0d9 |
#include "rb.h"
|
|
Packit |
b2c0d9 |
#include "glusterfs/locking.h"
|
|
Packit |
b2c0d9 |
#include "glusterfs/mem-pool.h"
|
|
Packit |
b2c0d9 |
#include "glusterfs/logging.h"
|
|
Packit |
b2c0d9 |
#include "glusterfs/libglusterfs-messages.h"
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
#include <pthread.h>
|
|
Packit |
b2c0d9 |
#include <string.h>
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
int
|
|
Packit |
b2c0d9 |
rbthash_comparator(void *entry1, void *entry2, void *param)
|
|
Packit |
b2c0d9 |
{
|
|
Packit |
b2c0d9 |
int ret = 0;
|
|
Packit |
b2c0d9 |
rbthash_entry_t *e1 = NULL;
|
|
Packit |
b2c0d9 |
rbthash_entry_t *e2 = NULL;
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
if ((!entry1) || (!entry2) || (!param))
|
|
Packit |
b2c0d9 |
return -1;
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
e1 = (rbthash_entry_t *)entry1;
|
|
Packit |
b2c0d9 |
e2 = (rbthash_entry_t *)entry2;
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
if (e1->keylen != e2->keylen) {
|
|
Packit |
b2c0d9 |
if (e1->keylen < e2->keylen)
|
|
Packit |
b2c0d9 |
ret = -1;
|
|
Packit |
b2c0d9 |
else if (e1->keylen > e2->keylen)
|
|
Packit |
b2c0d9 |
ret = 1;
|
|
Packit |
b2c0d9 |
} else
|
|
Packit |
b2c0d9 |
ret = memcmp(e1->key, e2->key, e1->keylen);
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
return ret;
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
int
|
|
Packit |
b2c0d9 |
__rbthash_init_buckets(rbthash_table_t *tbl, int buckets)
|
|
Packit |
b2c0d9 |
{
|
|
Packit |
b2c0d9 |
int i = 0;
|
|
Packit |
b2c0d9 |
int ret = -1;
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
if (!tbl)
|
|
Packit |
b2c0d9 |
return -1;
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
for (; i < buckets; i++) {
|
|
Packit |
b2c0d9 |
LOCK_INIT(&tbl->buckets[i].bucketlock);
|
|
Packit |
b2c0d9 |
tbl->buckets[i].bucket = rb_create(
|
|
Packit |
b2c0d9 |
(rb_comparison_func *)rbthash_comparator, tbl, NULL);
|
|
Packit |
b2c0d9 |
if (!tbl->buckets[i].bucket) {
|
|
Packit |
b2c0d9 |
gf_msg(GF_RBTHASH, GF_LOG_ERROR, 0, LG_MSG_RB_TABLE_CREATE_FAILED,
|
|
Packit |
b2c0d9 |
"Failed to "
|
|
Packit |
b2c0d9 |
"create rb table bucket");
|
|
Packit |
b2c0d9 |
ret = -1;
|
|
Packit |
b2c0d9 |
goto err;
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
ret = 0;
|
|
Packit |
b2c0d9 |
err:
|
|
Packit |
b2c0d9 |
return ret;
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
/*
|
|
Packit |
b2c0d9 |
* rbthash_table_init - Initialize a RBT based hash table
|
|
Packit |
b2c0d9 |
* @buckets - Number of buckets in the hash table
|
|
Packit |
b2c0d9 |
* @hfunc - hashing function
|
|
Packit |
b2c0d9 |
* @dfunc - destroyer for data in the RBT
|
|
Packit |
b2c0d9 |
* @expected_entries - Number of entries expected in RBT. Mutually exclusive
|
|
Packit |
b2c0d9 |
* with entrypool.
|
|
Packit |
b2c0d9 |
* @entrypool - Memory pool in lieu of expected_entries.
|
|
Packit |
b2c0d9 |
*/
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
rbthash_table_t *
|
|
Packit |
b2c0d9 |
rbthash_table_init(glusterfs_ctx_t *ctx, int buckets, rbt_hasher_t hfunc,
|
|
Packit |
b2c0d9 |
rbt_data_destroyer_t dfunc, unsigned long expected_entries,
|
|
Packit |
b2c0d9 |
struct mem_pool *entrypool)
|
|
Packit |
b2c0d9 |
{
|
|
Packit |
b2c0d9 |
rbthash_table_t *newtab = NULL;
|
|
Packit |
b2c0d9 |
int ret = -1;
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
if (!hfunc) {
|
|
Packit |
b2c0d9 |
gf_msg(GF_RBTHASH, GF_LOG_ERROR, 0, LG_MSG_HASH_FUNC_ERROR,
|
|
Packit |
b2c0d9 |
"Hash function not given");
|
|
Packit |
b2c0d9 |
return NULL;
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
if (!entrypool && !expected_entries) {
|
|
Packit |
b2c0d9 |
gf_msg(GF_RBTHASH, GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY,
|
|
Packit |
b2c0d9 |
"Both mem-pool and expected entries not provided");
|
|
Packit |
b2c0d9 |
return NULL;
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
if (entrypool && expected_entries) {
|
|
Packit |
b2c0d9 |
gf_msg(GF_RBTHASH, GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY,
|
|
Packit |
b2c0d9 |
"Both mem-pool and expected entries are provided");
|
|
Packit |
b2c0d9 |
return NULL;
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
newtab = GF_CALLOC(1, sizeof(*newtab), gf_common_mt_rbthash_table_t);
|
|
Packit |
b2c0d9 |
if (!newtab)
|
|
Packit |
b2c0d9 |
return NULL;
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
newtab->buckets = GF_CALLOC(buckets, sizeof(struct rbthash_bucket),
|
|
Packit |
b2c0d9 |
gf_common_mt_rbthash_bucket);
|
|
Packit |
b2c0d9 |
if (!newtab->buckets) {
|
|
Packit |
b2c0d9 |
goto free_newtab;
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
if (expected_entries) {
|
|
Packit |
b2c0d9 |
newtab->entrypool = mem_pool_new_ctx(ctx, rbthash_entry_t,
|
|
Packit |
b2c0d9 |
expected_entries);
|
|
Packit |
b2c0d9 |
if (!newtab->entrypool) {
|
|
Packit |
b2c0d9 |
goto free_buckets;
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
newtab->pool_alloced = _gf_true;
|
|
Packit |
b2c0d9 |
} else {
|
|
Packit |
b2c0d9 |
newtab->entrypool = entrypool;
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
LOCK_INIT(&newtab->tablelock);
|
|
Packit |
b2c0d9 |
INIT_LIST_HEAD(&newtab->list);
|
|
Packit |
b2c0d9 |
newtab->numbuckets = buckets;
|
|
Packit |
b2c0d9 |
ret = __rbthash_init_buckets(newtab, buckets);
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
if (ret == -1) {
|
|
Packit |
b2c0d9 |
gf_msg(GF_RBTHASH, GF_LOG_ERROR, 0, LG_MSG_RBTHASH_INIT_BUCKET_FAILED,
|
|
Packit |
b2c0d9 |
"Failed to init buckets");
|
|
Packit |
b2c0d9 |
if (newtab->pool_alloced)
|
|
Packit |
b2c0d9 |
mem_pool_destroy(newtab->entrypool);
|
|
Packit |
b2c0d9 |
} else {
|
|
Packit |
b2c0d9 |
gf_msg_trace(GF_RBTHASH, 0,
|
|
Packit |
b2c0d9 |
"Inited hash table: buckets:"
|
|
Packit |
b2c0d9 |
" %d",
|
|
Packit |
b2c0d9 |
buckets);
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
newtab->hashfunc = hfunc;
|
|
Packit |
b2c0d9 |
newtab->dfunc = dfunc;
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
free_buckets:
|
|
Packit |
b2c0d9 |
if (ret == -1)
|
|
Packit |
b2c0d9 |
GF_FREE(newtab->buckets);
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
free_newtab:
|
|
Packit |
b2c0d9 |
if (ret == -1) {
|
|
Packit |
b2c0d9 |
GF_FREE(newtab);
|
|
Packit |
b2c0d9 |
newtab = NULL;
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
return newtab;
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
rbthash_entry_t *
|
|
Packit |
b2c0d9 |
rbthash_init_entry(rbthash_table_t *tbl, void *data, void *key, int keylen)
|
|
Packit |
b2c0d9 |
{
|
|
Packit |
b2c0d9 |
int ret = -1;
|
|
Packit |
b2c0d9 |
rbthash_entry_t *entry = NULL;
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
if ((!tbl) || (!data) || (!key))
|
|
Packit |
b2c0d9 |
return NULL;
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
entry = mem_get(tbl->entrypool);
|
|
Packit |
b2c0d9 |
if (!entry) {
|
|
Packit |
b2c0d9 |
gf_msg(GF_RBTHASH, GF_LOG_ERROR, 0, LG_MSG_RBTHASH_GET_ENTRY_FAILED,
|
|
Packit |
b2c0d9 |
"Failed to get entry from mem-pool");
|
|
Packit |
b2c0d9 |
goto ret;
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
entry->data = data;
|
|
Packit |
b2c0d9 |
entry->key = GF_MALLOC(keylen, gf_common_mt_char);
|
|
Packit |
b2c0d9 |
if (!entry->key) {
|
|
Packit |
b2c0d9 |
goto free_entry;
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
INIT_LIST_HEAD(&entry->list);
|
|
Packit |
b2c0d9 |
memcpy(entry->key, key, keylen);
|
|
Packit |
b2c0d9 |
entry->keylen = keylen;
|
|
Packit |
b2c0d9 |
entry->keyhash = tbl->hashfunc(entry->key, entry->keylen);
|
|
Packit |
b2c0d9 |
gf_msg_trace(GF_RBTHASH, 0, "HASH: %u", entry->keyhash);
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
ret = 0;
|
|
Packit |
b2c0d9 |
free_entry:
|
|
Packit |
b2c0d9 |
if (ret == -1) {
|
|
Packit |
b2c0d9 |
mem_put(entry);
|
|
Packit |
b2c0d9 |
entry = NULL;
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
ret:
|
|
Packit |
b2c0d9 |
return entry;
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
void
|
|
Packit |
b2c0d9 |
rbthash_deinit_entry(rbthash_table_t *tbl, rbthash_entry_t *entry)
|
|
Packit |
b2c0d9 |
{
|
|
Packit |
b2c0d9 |
if (!entry)
|
|
Packit |
b2c0d9 |
return;
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
GF_FREE(entry->key);
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
if (tbl) {
|
|
Packit |
b2c0d9 |
if ((entry->data) && (tbl->dfunc))
|
|
Packit |
b2c0d9 |
tbl->dfunc(entry->data);
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
LOCK(&tbl->tablelock);
|
|
Packit |
b2c0d9 |
{
|
|
Packit |
b2c0d9 |
list_del_init(&entry->list);
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
UNLOCK(&tbl->tablelock);
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
mem_put(entry);
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
return;
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
static struct rbthash_bucket *
|
|
Packit |
b2c0d9 |
rbthash_entry_bucket(rbthash_table_t *tbl, rbthash_entry_t *entry)
|
|
Packit |
b2c0d9 |
{
|
|
Packit |
b2c0d9 |
int nbucket = 0;
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
nbucket = (entry->keyhash % tbl->numbuckets);
|
|
Packit |
b2c0d9 |
gf_msg_trace(GF_RBTHASH, 0, "BUCKET: %d", nbucket);
|
|
Packit |
b2c0d9 |
return &tbl->buckets[nbucket];
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
int
|
|
Packit |
b2c0d9 |
rbthash_insert_entry(rbthash_table_t *tbl, rbthash_entry_t *entry)
|
|
Packit |
b2c0d9 |
{
|
|
Packit |
b2c0d9 |
struct rbthash_bucket *bucket = NULL;
|
|
Packit |
b2c0d9 |
int ret = -1;
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
if ((!tbl) || (!entry))
|
|
Packit |
b2c0d9 |
return -1;
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
bucket = rbthash_entry_bucket(tbl, entry);
|
|
Packit |
b2c0d9 |
if (!bucket) {
|
|
Packit |
b2c0d9 |
gf_msg(GF_RBTHASH, GF_LOG_ERROR, 0, LG_MSG_RBTHASH_GET_BUCKET_FAILED,
|
|
Packit |
b2c0d9 |
"Failed to get bucket");
|
|
Packit |
b2c0d9 |
goto err;
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
ret = 0;
|
|
Packit |
b2c0d9 |
LOCK(&bucket->bucketlock);
|
|
Packit |
b2c0d9 |
{
|
|
Packit |
b2c0d9 |
if (!rb_probe(bucket->bucket, (void *)entry)) {
|
|
Packit |
b2c0d9 |
UNLOCK(&bucket->bucketlock);
|
|
Packit |
b2c0d9 |
gf_msg(GF_RBTHASH, GF_LOG_ERROR, 0, LG_MSG_RBTHASH_INSERT_FAILED,
|
|
Packit |
b2c0d9 |
"Failed to insert entry");
|
|
Packit |
b2c0d9 |
ret = -1;
|
|
Packit |
b2c0d9 |
goto err;
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
UNLOCK(&bucket->bucketlock);
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
err:
|
|
Packit |
b2c0d9 |
return ret;
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
int
|
|
Packit |
b2c0d9 |
rbthash_insert(rbthash_table_t *tbl, void *data, void *key, int keylen)
|
|
Packit |
b2c0d9 |
{
|
|
Packit |
b2c0d9 |
rbthash_entry_t *entry = NULL;
|
|
Packit |
b2c0d9 |
int ret = -1;
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
if ((!tbl) || (!data) || (!key))
|
|
Packit |
b2c0d9 |
return -1;
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
entry = rbthash_init_entry(tbl, data, key, keylen);
|
|
Packit |
b2c0d9 |
if (!entry) {
|
|
Packit |
b2c0d9 |
gf_msg(GF_RBTHASH, GF_LOG_ERROR, 0, LG_MSG_RBTHASH_INIT_ENTRY_FAILED,
|
|
Packit |
b2c0d9 |
"Failed to init entry");
|
|
Packit |
b2c0d9 |
goto err;
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
ret = rbthash_insert_entry(tbl, entry);
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
if (ret == -1) {
|
|
Packit |
b2c0d9 |
gf_msg(GF_RBTHASH, GF_LOG_ERROR, 0, LG_MSG_RBTHASH_INSERT_FAILED,
|
|
Packit |
b2c0d9 |
"Failed to insert entry");
|
|
Packit |
b2c0d9 |
rbthash_deinit_entry(tbl, entry);
|
|
Packit |
b2c0d9 |
goto err;
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
LOCK(&tbl->tablelock);
|
|
Packit |
b2c0d9 |
{
|
|
Packit |
b2c0d9 |
list_add_tail(&entry->list, &tbl->list);
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
UNLOCK(&tbl->tablelock);
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
err:
|
|
Packit |
b2c0d9 |
return ret;
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
static struct rbthash_bucket *
|
|
Packit |
b2c0d9 |
rbthash_key_bucket(rbthash_table_t *tbl, void *key, int keylen)
|
|
Packit |
b2c0d9 |
{
|
|
Packit |
b2c0d9 |
uint32_t keyhash = 0;
|
|
Packit |
b2c0d9 |
int nbucket = 0;
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
if ((!tbl) || (!key))
|
|
Packit |
b2c0d9 |
return NULL;
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
keyhash = tbl->hashfunc(key, keylen);
|
|
Packit |
b2c0d9 |
gf_msg_trace(GF_RBTHASH, 0, "HASH: %u", keyhash);
|
|
Packit |
b2c0d9 |
nbucket = (keyhash % tbl->numbuckets);
|
|
Packit |
b2c0d9 |
gf_msg_trace(GF_RBTHASH, 0, "BUCKET: %u", nbucket);
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
return &tbl->buckets[nbucket];
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
void *
|
|
Packit |
b2c0d9 |
rbthash_get(rbthash_table_t *tbl, void *key, int keylen)
|
|
Packit |
b2c0d9 |
{
|
|
Packit |
b2c0d9 |
struct rbthash_bucket *bucket = NULL;
|
|
Packit |
b2c0d9 |
rbthash_entry_t *entry = NULL;
|
|
Packit |
b2c0d9 |
rbthash_entry_t searchentry = {
|
|
Packit |
b2c0d9 |
0,
|
|
Packit |
b2c0d9 |
};
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
if ((!tbl) || (!key))
|
|
Packit |
b2c0d9 |
return NULL;
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
bucket = rbthash_key_bucket(tbl, key, keylen);
|
|
Packit |
b2c0d9 |
if (!bucket) {
|
|
Packit |
b2c0d9 |
gf_msg(GF_RBTHASH, GF_LOG_ERROR, 0, LG_MSG_GET_BUCKET_FAILED,
|
|
Packit |
b2c0d9 |
"Failed to get bucket");
|
|
Packit |
b2c0d9 |
return NULL;
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
searchentry.key = key;
|
|
Packit |
b2c0d9 |
searchentry.keylen = keylen;
|
|
Packit |
b2c0d9 |
LOCK(&bucket->bucketlock);
|
|
Packit |
b2c0d9 |
{
|
|
Packit |
b2c0d9 |
entry = rb_find(bucket->bucket, &searchentry);
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
UNLOCK(&bucket->bucketlock);
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
if (!entry)
|
|
Packit |
b2c0d9 |
return NULL;
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
return entry->data;
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
void *
|
|
Packit |
b2c0d9 |
rbthash_remove(rbthash_table_t *tbl, void *key, int keylen)
|
|
Packit |
b2c0d9 |
{
|
|
Packit |
b2c0d9 |
struct rbthash_bucket *bucket = NULL;
|
|
Packit |
b2c0d9 |
rbthash_entry_t *entry = NULL;
|
|
Packit |
b2c0d9 |
rbthash_entry_t searchentry = {
|
|
Packit |
b2c0d9 |
0,
|
|
Packit |
b2c0d9 |
};
|
|
Packit |
b2c0d9 |
void *dataref = NULL;
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
if ((!tbl) || (!key))
|
|
Packit |
b2c0d9 |
return NULL;
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
bucket = rbthash_key_bucket(tbl, key, keylen);
|
|
Packit |
b2c0d9 |
if (!bucket) {
|
|
Packit |
b2c0d9 |
gf_msg(GF_RBTHASH, GF_LOG_ERROR, 0, LG_MSG_RBTHASH_GET_BUCKET_FAILED,
|
|
Packit |
b2c0d9 |
"Failed to get bucket");
|
|
Packit |
b2c0d9 |
return NULL;
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
searchentry.key = key;
|
|
Packit |
b2c0d9 |
searchentry.keylen = keylen;
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
LOCK(&bucket->bucketlock);
|
|
Packit |
b2c0d9 |
{
|
|
Packit |
b2c0d9 |
entry = rb_delete(bucket->bucket, &searchentry);
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
UNLOCK(&bucket->bucketlock);
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
if (!entry)
|
|
Packit |
b2c0d9 |
return NULL;
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
GF_FREE(entry->key);
|
|
Packit |
b2c0d9 |
dataref = entry->data;
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
LOCK(&tbl->tablelock);
|
|
Packit |
b2c0d9 |
{
|
|
Packit |
b2c0d9 |
list_del_init(&entry->list);
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
UNLOCK(&tbl->tablelock);
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
mem_put(entry);
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
return dataref;
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
void
|
|
Packit |
b2c0d9 |
rbthash_entry_deiniter(void *entry, void *rbparam)
|
|
Packit |
b2c0d9 |
{
|
|
Packit |
b2c0d9 |
if (!entry)
|
|
Packit |
b2c0d9 |
return;
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
rbthash_deinit_entry(rbparam, entry);
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
void
|
|
Packit |
b2c0d9 |
rbthash_table_destroy_buckets(rbthash_table_t *tbl)
|
|
Packit |
b2c0d9 |
{
|
|
Packit |
b2c0d9 |
int x = 0;
|
|
Packit |
b2c0d9 |
if (!tbl)
|
|
Packit |
b2c0d9 |
return;
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
for (; x < tbl->numbuckets; x++) {
|
|
Packit |
b2c0d9 |
LOCK_DESTROY(&tbl->buckets[x].bucketlock);
|
|
Packit |
b2c0d9 |
rb_destroy(tbl->buckets[x].bucket, rbthash_entry_deiniter);
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
return;
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
void
|
|
Packit |
b2c0d9 |
rbthash_table_destroy(rbthash_table_t *tbl)
|
|
Packit |
b2c0d9 |
{
|
|
Packit |
b2c0d9 |
if (!tbl)
|
|
Packit |
b2c0d9 |
return;
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
rbthash_table_destroy_buckets(tbl);
|
|
Packit |
b2c0d9 |
if (tbl->pool_alloced)
|
|
Packit |
b2c0d9 |
mem_pool_destroy(tbl->entrypool);
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
GF_FREE(tbl->buckets);
|
|
Packit |
b2c0d9 |
GF_FREE(tbl);
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
void
|
|
Packit |
b2c0d9 |
rbthash_table_traverse(rbthash_table_t *tbl, rbt_traverse_t traverse,
|
|
Packit |
b2c0d9 |
void *mydata)
|
|
Packit |
b2c0d9 |
{
|
|
Packit |
b2c0d9 |
rbthash_entry_t *entry = NULL;
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
if ((tbl == NULL) || (traverse == NULL)) {
|
|
Packit |
b2c0d9 |
goto out;
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
LOCK(&tbl->tablelock);
|
|
Packit |
b2c0d9 |
{
|
|
Packit |
b2c0d9 |
list_for_each_entry(entry, &tbl->list, list)
|
|
Packit |
b2c0d9 |
{
|
|
Packit |
b2c0d9 |
traverse(entry->data, mydata);
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
}
|
|
Packit |
b2c0d9 |
UNLOCK(&tbl->tablelock);
|
|
Packit |
b2c0d9 |
|
|
Packit |
b2c0d9 |
out:
|
|
Packit |
b2c0d9 |
return;
|
|
Packit |
b2c0d9 |
}
|