diff options
Diffstat (limited to 'libglusterfs/src/dict.c')
| -rw-r--r-- | libglusterfs/src/dict.c | 4549 |
1 files changed, 2605 insertions, 1944 deletions
diff --git a/libglusterfs/src/dict.c b/libglusterfs/src/dict.c index fd9dd1cd7c6..1d9be9217a6 100644 --- a/libglusterfs/src/dict.c +++ b/libglusterfs/src/dict.c @@ -1,20 +1,11 @@ /* - Copyright (c) 2006-2011 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #include <unistd.h> @@ -23,1318 +14,1474 @@ #include <stdio.h> #include <inttypes.h> #include <limits.h> +#include <fnmatch.h> + +#include "glusterfs/dict.h" +#define XXH_INLINE_ALL +#include "xxhash.h" +#include "glusterfs/compat.h" +#include "glusterfs/compat-errno.h" +#include "glusterfs/byte-order.h" +#include "glusterfs/statedump.h" +#include "glusterfs/libglusterfs-messages.h" + +struct dict_cmp { + dict_t *dict; + gf_boolean_t (*value_ignore)(char *k); +}; + +#define VALIDATE_DATA_AND_LOG(data, type, key, ret_val) \ + do { \ + if (!data || !data->data) { \ + gf_msg_callingfn("dict", GF_LOG_DEBUG, EINVAL, LG_MSG_INVALID_ARG, \ + "data is NULL"); \ + return ret_val; \ + } \ + /* Not of the asked type, or old version */ \ + if ((data->data_type != type) && \ + (data->data_type != GF_DATA_TYPE_STR_OLD)) { \ + gf_msg_callingfn("dict", GF_LOG_DEBUG, EINVAL, LG_MSG_INVALID_ARG, \ + "key %s, %s type asked, has %s type", key, \ + data_type_name[type], \ + data_type_name[data->data_type]); \ + } \ + } while (0) -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include "glusterfs.h" -#include "common-utils.h" -#include "dict.h" -#include "hashfn.h" -#include "logging.h" -#include "compat.h" -#include "byte-order.h" - -data_pair_t * -get_new_data_pair () +static data_t * +get_new_data() { - data_pair_t *data_pair_ptr = NULL; - - data_pair_ptr = (data_pair_t *) GF_CALLOC (1, sizeof (data_pair_t), - gf_common_mt_data_pair_t); - return data_pair_ptr; -} + data_t *data = mem_get(THIS->ctx->dict_data_pool); -data_t * -get_new_data () -{ - data_t *data = NULL; + if (!data) + return NULL; - data = (data_t *) GF_CALLOC (1, sizeof (data_t), gf_common_mt_data_t); - if (!data) { - return NULL; - } + GF_ATOMIC_INIT(data->refcount, 0); + data->is_static = _gf_false; - LOCK_INIT (&data->lock); - return data; + return data; } -dict_t * -get_new_dict_full (int size_hint) +static dict_t * +get_new_dict_full(int size_hint) { - dict_t *dict = GF_CALLOC (1, sizeof (dict_t), gf_common_mt_dict_t); - - if (!dict) { - return NULL; - } - - dict->hash_size = size_hint; - dict->members = GF_CALLOC (size_hint, sizeof (data_pair_t *), - gf_common_mt_data_pair_t); + dict_t *dict = mem_get0(THIS->ctx->dict_pool); + if (!dict) { + return NULL; + } + + dict->hash_size = size_hint; + if (size_hint == 1) { + /* + * This is the only case we ever see currently. If we ever + * need to support resizing the hash table, the resize function + * will have to take into account the possibility that + * "members" is not separately allocated (i.e. don't just call + * realloc() blindly. + */ + dict->members = &dict->members_internal; + } else { + /* + * We actually need to allocate space for size_hint *pointers* + * but we actually allocate space for one *structure*. Since + * a data_pair_t consists of five pointers, we're wasting four + * pointers' worth for N=1, and will overrun what we allocated + * for N>5. If anybody ever starts using size_hint, we'll need + * to fix this. + */ + GF_ASSERT(size_hint <= (sizeof(data_pair_t) / sizeof(data_pair_t *))); + dict->members = mem_get0(THIS->ctx->dict_pair_pool); if (!dict->members) { - GF_FREE (dict); - return NULL; + mem_put(dict); + return NULL; } + } - LOCK_INIT (&dict->lock); + dict->free_pair.key = NULL; + dict->totkvlen = 0; + LOCK_INIT(&dict->lock); - return dict; + return dict; } dict_t * -get_new_dict (void) +dict_new(void) { - return get_new_dict_full (1); + dict_t *dict = get_new_dict_full(1); + + if (dict) + dict_ref(dict); + + return dict; } -dict_t * -dict_new (void) +int32_t +is_data_equal(data_t *one, data_t *two) { - dict_t *dict = NULL; + struct iatt *iatt1, *iatt2; + struct mdata_iatt *mdata_iatt1, *mdata_iatt2; - dict = get_new_dict_full(1); + if (!one || !two || !one->data || !two->data) { + gf_msg_callingfn("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "input arguments are provided " + "with value data_t as NULL"); + return -1; + } - if (dict) - dict_ref (dict); + if (one == two) + return 1; - return dict; -} + if (one->data == two->data) + return 1; + if (one->data_type != two->data_type) { + return 0; + } -int32_t -is_data_equal (data_t *one, - data_t *two) -{ - if (!one || !two || !one->data || !two->data) { - gf_log_callingfn ("dict", GF_LOG_ERROR, - "input arguments are provided " - "with value data_t as NULL"); - return -1; - } + if (one->data_type == GF_DATA_TYPE_IATT) { + if ((one->len < sizeof(struct iatt)) || + (two->len < sizeof(struct iatt))) { + return 0; + } - if (one == two) - return 1; + iatt1 = (struct iatt *)one->data; + iatt2 = (struct iatt *)two->data; - if (one->len != two->len) + /* Two iatt structs are considered equal if main fields are + * equal, even if times differ. + * TODO: maybe when ctime if fully operational we could + * enforce time matching. */ + if (iatt1->ia_ino != iatt2->ia_ino) { + return 0; + } + if (iatt1->ia_type != iatt2->ia_type) { + return 0; + } + if ((iatt1->ia_type == IA_IFBLK) || (iatt1->ia_type == IA_IFCHR)) { + if (iatt1->ia_rdev != iatt2->ia_rdev) { return 0; + } + } + if (gf_uuid_compare(iatt1->ia_gfid, iatt2->ia_gfid) != 0) { + return 0; + } - if (one->data == two->data) - return 1; + /* TODO: ia_uid, ia_gid, ia_prot and ia_size can be changed + * with some commands. Here we don't have enough + * information to decide if they should match or not. */ + /* + if ((iatt1->ia_uid != iatt2->ia_uid) || + (iatt1->ia_gid != iatt2->ia_gid) || + (st_mode_from_ia(iatt1->ia_prot, iatt1->ia_type) != + st_mode_from_ia(iatt2->ia_prot, + iatt2->ia_type))) { return 0; + } + if (iatt1->ia_type == IA_IFREG) { + if (iatt1->ia_size != iatt2->ia_size) { + return 0; + } + } + */ + return 1; + } + if (one->data_type == GF_DATA_TYPE_MDATA) { + if ((one->len < sizeof(struct mdata_iatt)) || + (two->len < sizeof(struct mdata_iatt))) { + return 0; + } + mdata_iatt1 = (struct mdata_iatt *)one->data; + mdata_iatt2 = (struct mdata_iatt *)two->data; + + if (mdata_iatt1->ia_atime != mdata_iatt2->ia_atime || + mdata_iatt1->ia_mtime != mdata_iatt2->ia_mtime || + mdata_iatt1->ia_ctime != mdata_iatt2->ia_ctime || + mdata_iatt1->ia_atime_nsec != mdata_iatt2->ia_atime_nsec || + mdata_iatt1->ia_mtime_nsec != mdata_iatt2->ia_mtime_nsec || + mdata_iatt1->ia_ctime_nsec != mdata_iatt2->ia_ctime_nsec) { + return 0; + } + return 1; + } + + if (one->len != two->len) + return 0; - if (memcmp (one->data, two->data, one->len) == 0) - return 1; + if (memcmp(one->data, two->data, one->len) == 0) + return 1; - return 0; + return 0; +} + +static int +key_value_cmp(dict_t *one, char *key1, data_t *value1, void *data) +{ + struct dict_cmp *cmp = data; + dict_t *two = cmp->dict; + data_t *value2 = dict_get(two, key1); + + if (value2) { + if (cmp->value_ignore && cmp->value_ignore(key1)) + return 0; + + if (is_data_equal(value1, value2) == 1) + return 0; + } + + if (value2 == NULL) { + gf_msg_debug(THIS->name, 0, "'%s' found only on one dict", key1); + } else { + gf_msg_debug(THIS->name, 0, + "'%s' is different in two dicts " + "(%u, %u)", + key1, value1->len, value2->len); + } + + return -1; +} + +/* If both dicts are NULL then equal. If one of the dicts is NULL but the + * other has only ignorable keys then also they are equal. If both dicts are + * non-null then check if for each non-ignorable key, values are same or + * not. value_ignore function is used to skip comparing values for the keys + * which must be present in both the dictionaries but the value could be + * different. + */ +gf_boolean_t +are_dicts_equal(dict_t *one, dict_t *two, + gf_boolean_t (*match)(dict_t *d, char *k, data_t *v, + void *data), + gf_boolean_t (*value_ignore)(char *k)) +{ + int num_matches1 = 0; + int num_matches2 = 0; + struct dict_cmp cmp = {0}; + + if (one == two) + return _gf_true; + + if (!match) + match = dict_match_everything; + + if ((one == NULL) || (two == NULL)) { + num_matches1 = dict_foreach_match(one ? one : two, match, NULL, + dict_null_foreach_fn, NULL); + goto done; + } + + cmp.dict = two; + cmp.value_ignore = value_ignore; + num_matches1 = dict_foreach_match(one, match, NULL, key_value_cmp, &cmp); + + if (num_matches1 == -1) + return _gf_false; + + if ((num_matches1 == one->count) && (one->count == two->count)) + return _gf_true; + + num_matches2 = dict_foreach_match(two, match, NULL, dict_null_foreach_fn, + NULL); +done: + /* If the number of matches is same in 'two' then for all the + * valid-keys that exist in 'one' the value matched and no extra valid + * keys exist in 'two' alone. Otherwise there exists at least one extra + * valid-key in 'two' which doesn't exist in 'one' */ + if (num_matches1 == num_matches2) + return _gf_true; + return _gf_false; } void -data_destroy (data_t *data) +data_destroy(data_t *data) { - if (data) { - LOCK_DESTROY (&data->lock); - - if (!data->is_static) { - if (data->data) { - if (data->is_stdalloc) - free (data->data); - else - GF_FREE (data->data); - } - if (data->vec) - GF_FREE (data->vec); - } + if (data) { + if (!data->is_static) + GF_FREE(data->data); - data->len = 0xbabababa; - if (!data->is_const) - GF_FREE (data); - } + data->len = 0xbabababa; + mem_put(data); + } } data_t * -data_copy (data_t *old) +data_copy(data_t *old) { - if (!old) { - gf_log_callingfn ("dict", GF_LOG_WARNING, - "old is NULL"); - return NULL; - } + if (!old) { + gf_msg_callingfn("dict", GF_LOG_WARNING, 0, LG_MSG_NULL_PTR, + "old is NULL"); + return NULL; + } - data_t *newdata = (data_t *) GF_CALLOC (1, sizeof (*newdata), - gf_common_mt_data_t); + data_t *newdata = mem_get0(THIS->ctx->dict_data_pool); + if (!newdata) { + return NULL; + } - if (!newdata) { - return NULL; - } + newdata->len = old->len; + if (old->data) { + newdata->data = gf_memdup(old->data, old->len); + if (!newdata->data) + goto err_out; + } + newdata->data_type = old->data_type; - if (old) { - newdata->len = old->len; - if (old->data) { - newdata->data = memdup (old->data, old->len); - if (!newdata->data) - goto err_out; - } - if (old->vec) { - newdata->vec = memdup (old->vec, old->len * (sizeof (void *) + - sizeof (size_t))); - if (!newdata->vec) - goto err_out; - } - } - - LOCK_INIT (&newdata->lock); - return newdata; + return newdata; err_out: + mem_put(newdata); - if (newdata->data) - FREE (newdata->data); - if (newdata->vec) - FREE (newdata->vec); - GF_FREE (newdata); - - return NULL; + return NULL; } +/* Always need to be called under lock + * Always this and key variables are not null - + * checked by callers. + */ static data_pair_t * -_dict_lookup (dict_t *this, char *key) +dict_lookup_common(const dict_t *this, const char *key, const uint32_t hash) { - if (!this || !key) { - gf_log_callingfn ("dict", GF_LOG_WARNING, - "!this || !key (%s)", key); - return NULL; - } + int hashval = 0; + data_pair_t *pair; - int hashval = SuperFastHash (key, strlen (key)) % this->hash_size; - data_pair_t *pair; + /* If the divisor is 1, the modulo is always 0, + * in such case avoid hash calculation. + */ + if (this->hash_size != 1) + hashval = hash % this->hash_size; - for (pair = this->members[hashval]; pair != NULL; pair = pair->hash_next) { - if (pair->key && !strcmp (pair->key, key)) - return pair; - } + for (pair = this->members[hashval]; pair != NULL; pair = pair->hash_next) { + if (pair->key && (hash == pair->key_hash) && !strcmp(pair->key, key)) + return pair; + } - return NULL; + return NULL; } int32_t -dict_lookup (dict_t *this, char *key, data_pair_t **data) +dict_lookup(dict_t *this, char *key, data_t **data) { - if (!this || !key || !data) { - gf_log_callingfn ("dict", GF_LOG_WARNING, - "!this || !key || !data"); - return -1; - } + if (!this || !key || !data) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "!this || !key || " + "!data"); + return -1; + } - LOCK (&this->lock); - { - *data = _dict_lookup (this, key); - } - UNLOCK (&this->lock); - if (*data) - return 0; - else - return -1; + data_pair_t *tmp = NULL; -} + uint32_t hash = (uint32_t)XXH64(key, strlen(key), 0); -static int32_t -_dict_set (dict_t *this, - char *key, - data_t *value) -{ - int hashval; - data_pair_t *pair; - char key_free = 0; - int tmp = 0; - int ret = 0; - - if (!key) { - ret = gf_asprintf (&key, "ref:%p", value); - if (-1 == ret) { - gf_log ("dict", GF_LOG_WARNING, "asprintf failed %s", key); - return -1; - } - key_free = 1; - } + LOCK(&this->lock); + { + tmp = dict_lookup_common(this, key, hash); + } + UNLOCK(&this->lock); - tmp = SuperFastHash (key, strlen (key)); - hashval = (tmp % this->hash_size); - pair = _dict_lookup (this, key); + if (!tmp) + return -1; + *data = tmp->value; + return 0; +} + +static int32_t +dict_set_lk(dict_t *this, char *key, const int key_len, data_t *value, + const uint32_t hash, gf_boolean_t replace) +{ + int hashval = 0; + data_pair_t *pair; + int key_free = 0; + uint32_t key_hash; + int keylen; + + if (!key) { + keylen = gf_asprintf(&key, "ref:%p", value); + if (-1 == keylen) { + return -1; + } + key_free = 1; + key_hash = (uint32_t)XXH64(key, keylen, 0); + } else { + keylen = key_len; + key_hash = hash; + } + + /* Search for a existing key if 'replace' is asked for */ + if (replace) { + pair = dict_lookup_common(this, key, key_hash); if (pair) { - data_t *unref_data = pair->value; - pair->value = data_ref (value); - data_unref (unref_data); - if (key_free) - GF_FREE (key); - /* Indicates duplicate key */ - return 0; - } - pair = (data_pair_t *) GF_CALLOC (1, sizeof (*pair), - gf_common_mt_data_pair_t); + data_t *unref_data = pair->value; + pair->value = data_ref(value); + this->totkvlen += (value->len - unref_data->len); + data_unref(unref_data); + if (key_free) + GF_FREE(key); + /* Indicates duplicate key */ + return 0; + } + } + + if (this->free_pair.key) { /* the free_pair is used */ + pair = mem_get(THIS->ctx->dict_pair_pool); if (!pair) { - return -1; - } - - pair->key = (char *) GF_CALLOC (1, strlen (key) + 1, - gf_common_mt_char); + if (key_free) + GF_FREE(key); + return -1; + } + } else { /* assign the pair to the free pair */ + pair = &this->free_pair; + } + + if (key_free) { + /* It's ours. Use it. */ + pair->key = key; + key_free = 0; + } else { + pair->key = (char *)GF_MALLOC(keylen + 1, gf_common_mt_char); if (!pair->key) { - GF_FREE (pair); - - if (key_free) - GF_FREE (key); - return -1; - } - - strcpy (pair->key, key); - pair->value = data_ref (value); - - pair->hash_next = this->members[hashval]; - this->members[hashval] = pair; - - pair->next = this->members_list; - pair->prev = NULL; - if (this->members_list) - this->members_list->prev = pair; - this->members_list = pair; - this->count++; - - if (key_free) - GF_FREE (key); - return 0; + if (pair != &this->free_pair) { + mem_put(pair); + } + return -1; + } + strcpy(pair->key, key); + } + pair->key_hash = key_hash; + pair->value = data_ref(value); + this->totkvlen += (keylen + 1 + value->len); + + /* If the divisor is 1, the modulo is always 0, + * in such case avoid hash calculation. + */ + if (this->hash_size != 1) { + hashval = (key_hash % this->hash_size); + } + pair->hash_next = this->members[hashval]; + this->members[hashval] = pair; + + pair->next = this->members_list; + pair->prev = NULL; + if (this->members_list) + this->members_list->prev = pair; + this->members_list = pair; + this->count++; + + if (key_free) + GF_FREE(key); + + if (this->max_count < this->count) + this->max_count = this->count; + return 0; } int32_t -dict_set (dict_t *this, - char *key, - data_t *value) +dict_set(dict_t *this, char *key, data_t *value) { - int32_t ret; - - if (!this || !value) { - gf_log_callingfn ("dict", GF_LOG_WARNING, - "!this || !value for key=%s", key); - return -1; - } - - LOCK (&this->lock); - - ret = _dict_set (this, key, value); - - UNLOCK (&this->lock); - - return ret; + if (key) + return dict_setn(this, key, strlen(key), value); + else + return dict_setn(this, NULL, 0, value); } - -data_t * -dict_get (dict_t *this, char *key) +int32_t +dict_setn(dict_t *this, char *key, const int keylen, data_t *value) { - data_pair_t *pair; + int32_t ret; + uint32_t key_hash = 0; - if (!this || !key) { - gf_log_callingfn ("dict", GF_LOG_INFO, - "!this || key=%s", (key) ? key : "()"); - return NULL; - } + if (!this || !value) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "!this || !value for " + "key=%s", + key); + return -1; + } - LOCK (&this->lock); + if (key) { + key_hash = (uint32_t)XXH64(key, keylen, 0); + } - pair = _dict_lookup (this, key); + LOCK(&this->lock); - UNLOCK (&this->lock); + ret = dict_set_lk(this, key, keylen, value, key_hash, 1); - if (pair) - return pair->value; + UNLOCK(&this->lock); - return NULL; + return ret; } -void -dict_del (dict_t *this, char *key) +int32_t +dict_add(dict_t *this, char *key, data_t *value) { - if (!this || !key) { - gf_log_callingfn ("dict", GF_LOG_WARNING, - "!this || key=%s", key); - return; - } - - LOCK (&this->lock); - - int hashval = SuperFastHash (key, strlen (key)) % this->hash_size; - data_pair_t *pair = this->members[hashval]; - data_pair_t *prev = NULL; + if (key) + return dict_addn(this, key, strlen(key), value); + else + return dict_addn(this, NULL, 0, value); +} - while (pair) { - if (strcmp (pair->key, key) == 0) { - if (prev) - prev->hash_next = pair->hash_next; - else - this->members[hashval] = pair->hash_next; +int32_t +dict_addn(dict_t *this, char *key, const int keylen, data_t *value) +{ + int32_t ret; + uint32_t key_hash = 0; - data_unref (pair->value); + if (!this || !value) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "!this || !value for key=%s", key); + return -1; + } - if (pair->prev) - pair->prev->next = pair->next; - else - this->members_list = pair->next; + if (key) { + key_hash = (uint32_t)XXH64(key, keylen, 0); + } - if (pair->next) - pair->next->prev = pair->prev; + LOCK(&this->lock); - GF_FREE (pair->key); - GF_FREE (pair); - this->count--; - break; - } + ret = dict_set_lk(this, key, keylen, value, key_hash, 0); - prev = pair; - pair = pair->hash_next; - } + UNLOCK(&this->lock); - UNLOCK (&this->lock); - - return; + return ret; } -void -dict_destroy (dict_t *this) +data_t * +dict_get(dict_t *this, char *key) { - if (!this) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "dict is NULL"); - return; - } - - data_pair_t *pair = this->members_list; - data_pair_t *prev = this->members_list; - - LOCK_DESTROY (&this->lock); - - while (prev) { - pair = pair->next; - data_unref (prev->value); - GF_FREE (prev->key); - GF_FREE (prev); - prev = pair; - } - - GF_FREE (this->members); - - if (this->extra_free) - GF_FREE (this->extra_free); - if (this->extra_stdfree) - free (this->extra_stdfree); - - if (!this->is_static) - GF_FREE (this); + if (!this || !key) { + gf_msg_callingfn("dict", GF_LOG_DEBUG, EINVAL, LG_MSG_INVALID_ARG, + "!this || key=%s", (key) ? key : "()"); + return NULL; + } - return; + return dict_getn(this, key, strlen(key)); } -void -dict_unref (dict_t *this) +data_t * +dict_getn(dict_t *this, char *key, const int keylen) { - int32_t ref; + data_pair_t *pair; + uint32_t hash; - if (!this) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "dict is NULL"); - return; - } + if (!this || !key) { + gf_msg_callingfn("dict", GF_LOG_DEBUG, EINVAL, LG_MSG_INVALID_ARG, + "!this || key=%s", (key) ? key : "()"); + return NULL; + } - LOCK (&this->lock); + hash = (uint32_t)XXH64(key, keylen, 0); - this->refcount--; - ref = this->refcount; + LOCK(&this->lock); + { + pair = dict_lookup_common(this, key, hash); + } + UNLOCK(&this->lock); - UNLOCK (&this->lock); + if (pair) + return pair->value; - if (!ref) - dict_destroy (this); + return NULL; } -dict_t * -dict_ref (dict_t *this) +int +dict_key_count(dict_t *this) { - if (!this) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "dict is NULL"); - return NULL; - } - - LOCK (&this->lock); + int ret = -1; - this->refcount++; + if (!this) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "dict passed is NULL"); + return ret; + } - UNLOCK (&this->lock); + LOCK(&this->lock); + { + ret = this->count; + } + UNLOCK(&this->lock); - return this; + return ret; } void -data_unref (data_t *this) +dict_del(dict_t *this, char *key) { - int32_t ref; - - if (!this) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "dict is NULL"); - return; - } - - LOCK (&this->lock); - - this->refcount--; - ref = this->refcount; - - UNLOCK (&this->lock); + if (!this || !key) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "!this || key=%s", key); + return; + } - if (!ref) - data_destroy (this); + return dict_deln(this, key, strlen(key)); } -data_t * -data_ref (data_t *this) +void +dict_deln(dict_t *this, char *key, const int keylen) { - if (!this) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "dict is NULL"); - return NULL; - } + int hashval = 0; + uint32_t hash; - LOCK (&this->lock); + if (!this || !key) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "!this || key=%s", key); + return; + } - this->refcount++; + hash = (uint32_t)XXH64(key, keylen, 0); - UNLOCK (&this->lock); + LOCK(&this->lock); - return this; -} + /* If the divisor is 1, the modulo is always 0, + * in such case avoid hash calculation. + */ + if (this->hash_size != 1) + hashval = hash % this->hash_size; -/* - Serialization format: - ---- - Count:8 - Key_len:8:Value_len:8 - Key - Value - . - . - . -*/ + data_pair_t *pair = this->members[hashval]; + data_pair_t *prev = NULL; -int32_t -dict_serialized_length_old (dict_t *this) -{ + while (pair) { + if ((hash == pair->key_hash) && strcmp(pair->key, key) == 0) { + if (prev) + prev->hash_next = pair->hash_next; + else + this->members[hashval] = pair->hash_next; - if (!this) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "dict is NULL"); - return -1; - } + this->totkvlen -= pair->value->len; + data_unref(pair->value); - int32_t len = 9; /* count + \n */ - int32_t count = this->count; - data_pair_t *pair = this->members_list; - - while (count) { - len += 18; - len += strlen (pair->key) + 1; - if (pair->value->vec) { - int i; - for (i=0; i<pair->value->len; i++) { - len += pair->value->vec[i].iov_len; - } - } else { - len += pair->value->len; - } - pair = pair->next; - count--; - } + if (pair->prev) + pair->prev->next = pair->next; + else + this->members_list = pair->next; - return len; -} + if (pair->next) + pair->next->prev = pair->prev; -int32_t -dict_serialize_old (dict_t *this, char *buf) -{ - if (!this || !buf) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "dict is NULL"); - return -1; + this->totkvlen -= (strlen(pair->key) + 1); + GF_FREE(pair->key); + if (pair == &this->free_pair) { + this->free_pair.key = NULL; + } else { + mem_put(pair); + } + this->count--; + break; } - data_pair_t *pair = this->members_list; - int32_t count = this->count; - uint64_t dcount = this->count; - - // FIXME: magic numbers - - sprintf (buf, "%08"PRIx64"\n", dcount); - buf += 9; - while (count) { - uint64_t keylen = strlen (pair->key) + 1; - uint64_t vallen = pair->value->len; - - sprintf (buf, "%08"PRIx64":%08"PRIx64"\n", keylen, vallen); - buf += 18; - memcpy (buf, pair->key, keylen); - buf += keylen; - memcpy (buf, pair->value->data, pair->value->len); - buf += pair->value->len; - pair = pair->next; - count--; - } - return (0); -} + prev = pair; + pair = pair->hash_next; + } + UNLOCK(&this->lock); -dict_t * -dict_unserialize_old (char *buf, int32_t size, dict_t **fill) -{ - int32_t ret = 0; - int32_t cnt = 0; + return; +} - if (!buf || !fill || !(*fill)) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "buf is NULL"); - return NULL; - } +void +dict_destroy(dict_t *this) +{ + if (!this) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "dict is NULL"); + return; + } - uint64_t count; - ret = sscanf (buf, "%"SCNx64"\n", &count); - (*fill)->count = 0; + data_pair_t *pair = this->members_list; + data_pair_t *prev = this->members_list; + glusterfs_ctx_t *ctx = NULL; + uint64_t current_max = 0; + uint32_t total_pairs = 0; - if (!ret){ - gf_log ("dict", GF_LOG_ERROR, "sscanf on buf failed"); - goto err; - } - buf += 9; + LOCK_DESTROY(&this->lock); - if (count == 0) { - gf_log ("dict", GF_LOG_ERROR, "count == 0"); - goto err; + while (prev) { + pair = pair->next; + data_unref(prev->value); + GF_FREE(prev->key); + if (prev != &this->free_pair) { + mem_put(prev); + } else { + this->free_pair.key = NULL; } + total_pairs++; + prev = pair; + } - for (cnt = 0; cnt < count; cnt++) { - data_t *value = NULL; - char *key = NULL; - uint64_t key_len, value_len; - - ret = sscanf (buf, "%"SCNx64":%"SCNx64"\n", &key_len, &value_len); - if (ret != 2) { - gf_log ("dict", GF_LOG_ERROR, - "sscanf for key_len and value_len failed"); - goto err; - } - buf += 18; + this->totkvlen = 0; + if (this->members != &this->members_internal) { + mem_put(this->members); + } - key = buf; - buf += key_len; + free(this->extra_stdfree); - value = get_new_data (); - value->len = value_len; - value->data = buf; - value->is_static = 1; - buf += value_len; + /* update 'ctx->stats.dict.details' using max_count */ + ctx = THIS->ctx; - dict_set (*fill, key, value); - } + /* NOTE: below logic is not totaly race proof */ + /* thread0 and thread1 gets current_max as 10 */ + /* thread0 has 'this->max_count as 11 */ + /* thread1 has 'this->max_count as 20 */ + /* thread1 goes ahead and sets the max_dict_pairs to 20 */ + /* thread0 then goes and sets it to 11 */ + /* As it is for information purpose only, no functionality will be + broken by this, but a point to consider about ATOMIC macros. */ + current_max = GF_ATOMIC_GET(ctx->stats.max_dict_pairs); + if (current_max < this->max_count) + GF_ATOMIC_INIT(ctx->stats.max_dict_pairs, this->max_count); - goto ret; + GF_ATOMIC_ADD(ctx->stats.total_pairs_used, total_pairs); + GF_ATOMIC_INC(ctx->stats.total_dicts_used); -err: - GF_FREE (*fill); - *fill = NULL; + mem_put(this); -ret: - return *fill; + return; } - -int32_t -dict_iovec_len (dict_t *this) +void +dict_unref(dict_t *this) { - if (!this) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "dict is NULL"); - return -1; - } - - int32_t len = 0; - data_pair_t *pair = this->members_list; + uint64_t ref = 0; - len++; /* initial header */ - while (pair) { - len++; /* pair header */ - len++; /* key */ + if (!this) { + gf_msg_callingfn("dict", GF_LOG_DEBUG, EINVAL, LG_MSG_INVALID_ARG, + "dict is NULL"); + return; + } - if (pair->value->vec) - len += pair->value->len; - else - len++; - pair = pair->next; - } + ref = GF_ATOMIC_DEC(this->refcount); - return len; + if (!ref) + dict_destroy(this); } -int32_t -dict_to_iovec (dict_t *this, - struct iovec *vec, - int32_t count) +dict_t * +dict_ref(dict_t *this) { - if (!this || !vec) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "dict is NULL"); - return -1; - } - - int32_t i = 0; - data_pair_t *pair = this->members_list; - - vec[0].iov_len = 9; - if (vec[0].iov_base) - sprintf (vec[0].iov_base, - "%08"PRIx64"\n", - (int64_t)this->count); - i++; - - while (pair) { - int64_t keylen = strlen (pair->key) + 1; - int64_t vallen = 0; + if (!this) { + gf_msg_callingfn("dict", GF_LOG_DEBUG, EINVAL, LG_MSG_INVALID_ARG, + "dict is NULL"); + return NULL; + } - if (pair->value->vec) { - int i; + GF_ATOMIC_INC(this->refcount); + return this; +} - for (i=0; i<pair->value->len; i++) { - vallen += pair->value->vec[i].iov_len; - } - } else { - vallen = pair->value->len; - } +void +data_unref(data_t *this) +{ + uint64_t ref; - vec[i].iov_len = 18; - if (vec[i].iov_base) - sprintf (vec[i].iov_base, - "%08"PRIx64":%08"PRIx64"\n", - keylen, - vallen); - i++; - - vec[i].iov_len = keylen; - vec[i].iov_base = pair->key; - i++; - - if (pair->value->vec) { - int k; - - for (k=0; k<pair->value->len; k++) { - vec[i].iov_len = pair->value->vec[k].iov_len; - vec[i].iov_base = pair->value->vec[k].iov_base; - i++; - } - } else { - vec[i].iov_len = pair->value->len; - vec[i].iov_base = pair->value->data; - i++; - } + if (!this) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "data is NULL"); + return; + } - pair = pair->next; - } + ref = GF_ATOMIC_DEC(this->refcount); - return 0; + if (!ref) + data_destroy(this); } data_t * -int_to_data (int64_t value) +data_ref(data_t *this) { - int ret = 0; - data_t *data = get_new_data (); - - if (!data) { - return NULL; - } + if (!this) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "data is NULL"); + return NULL; + } - ret = gf_asprintf (&data->data, "%"PRId64, value); - if (-1 == ret) { - gf_log ("dict", GF_LOG_DEBUG, "asprintf failed"); - return NULL; - } - data->len = strlen (data->data) + 1; + GF_ATOMIC_INC(this->refcount); - return data; + return this; } data_t * -data_from_int64 (int64_t value) +int_to_data(int64_t value) { - int ret = 0; - data_t *data = get_new_data (); + data_t *data = get_new_data(); - if (!data) { - return NULL; - } - ret = gf_asprintf (&data->data, "%"PRId64, value); - if (-1 == ret) { - gf_log ("dict", GF_LOG_DEBUG, "asprintf failed"); - return NULL; - } - data->len = strlen (data->data) + 1; + if (!data) { + return NULL; + } - return data; + data->len = gf_asprintf(&data->data, "%" PRId64, value); + if (-1 == data->len) { + gf_msg_debug("dict", 0, "asprintf failed"); + data_destroy(data); + return NULL; + } + data->len++; /* account for terminating NULL */ + data->data_type = GF_DATA_TYPE_INT; + + return data; } data_t * -data_from_int32 (int32_t value) +data_from_int64(int64_t value) { - int ret = 0; - data_t *data = get_new_data (); - - if (!data) { - return NULL; - } - ret = gf_asprintf (&data->data, "%"PRId32, value); - if (-1 == ret) { - gf_log ("dict", GF_LOG_DEBUG, "asprintf failed"); - return NULL; - } + data_t *data = get_new_data(); - data->len = strlen (data->data) + 1; + if (!data) { + return NULL; + } + data->len = gf_asprintf(&data->data, "%" PRId64, value); + if (-1 == data->len) { + gf_msg_debug("dict", 0, "asprintf failed"); + data_destroy(data); + return NULL; + } + data->len++; /* account for terminating NULL */ + data->data_type = GF_DATA_TYPE_INT; - return data; + return data; } data_t * -data_from_int16 (int16_t value) +data_from_int32(int32_t value) { - int ret = 0; - data_t *data = get_new_data (); + data_t *data = get_new_data(); - if (!data) { - return NULL; - } - ret = gf_asprintf (&data->data, "%"PRId16, value); - if (-1 == ret) { - gf_log ("dict", GF_LOG_DEBUG, "asprintf failed"); - return NULL; - } + if (!data) { + return NULL; + } + data->len = gf_asprintf(&data->data, "%" PRId32, value); + if (-1 == data->len) { + gf_msg_debug("dict", 0, "asprintf failed"); + data_destroy(data); + return NULL; + } - data->len = strlen (data->data) + 1; + data->len++; /* account for terminating NULL */ + data->data_type = GF_DATA_TYPE_INT; - return data; + return data; } data_t * -data_from_int8 (int8_t value) +data_from_int16(int16_t value) { - int ret = 0; - data_t *data = get_new_data (); + data_t *data = get_new_data(); - if (!data) { - return NULL; - } - ret = gf_asprintf (&data->data, "%d", value); - if (-1 == ret) { - gf_log ("dict", GF_LOG_DEBUG, "asprintf failed"); - return NULL; - } + if (!data) { + return NULL; + } + data->len = gf_asprintf(&data->data, "%" PRId16, value); + if (-1 == data->len) { + gf_msg_debug("dict", 0, "asprintf failed"); + data_destroy(data); + return NULL; + } - data->len = strlen (data->data) + 1; + data->len++; /* account for terminating NULL */ + data->data_type = GF_DATA_TYPE_INT; - return data; + return data; } data_t * -data_from_uint64 (uint64_t value) +data_from_int8(int8_t value) { - int ret = 0; - data_t *data = get_new_data (); + data_t *data = get_new_data(); - if (!data) { - return NULL; - } - ret = gf_asprintf (&data->data, "%"PRIu64, value); - if (-1 == ret) { - gf_log ("dict", GF_LOG_DEBUG, "asprintf failed"); - return NULL; - } + if (!data) { + return NULL; + } + data->len = gf_asprintf(&data->data, "%d", value); + if (-1 == data->len) { + gf_msg_debug("dict", 0, "asprintf failed"); + data_destroy(data); + return NULL; + } - data->len = strlen (data->data) + 1; + data->len++; /* account for terminating NULL */ + data->data_type = GF_DATA_TYPE_INT; - return data; + return data; } -static data_t * -data_from_double (double value) +data_t * +data_from_uint64(uint64_t value) { - data_t *data = NULL; - int ret = 0; - - data = get_new_data (); + data_t *data = get_new_data(); - if (!data) { - return NULL; - } + if (!data) { + return NULL; + } + data->len = gf_asprintf(&data->data, "%" PRIu64, value); + if (-1 == data->len) { + gf_msg_debug("dict", 0, "asprintf failed"); + data_destroy(data); + return NULL; + } - ret = gf_asprintf (&data->data, "%f", value); - if (ret == -1) { - return NULL; - } - data->len = strlen (data->data) + 1; + data->len++; /* account for terminating NULL */ + data->data_type = GF_DATA_TYPE_UINT; - return data; + return data; } - data_t * -data_from_uint32 (uint32_t value) +data_from_double(double value) { - int ret = 0; - data_t *data = get_new_data (); + data_t *data = get_new_data(); - if (!data) { - return NULL; - } - ret = gf_asprintf (&data->data, "%"PRIu32, value); - if (-1 == ret) { - gf_log ("dict", GF_LOG_DEBUG, "asprintf failed"); - return NULL; - } + if (!data) { + return NULL; + } - data->len = strlen (data->data) + 1; + data->len = gf_asprintf(&data->data, "%f", value); + if (data->len == -1) { + gf_msg_debug("dict", 0, "asprintf failed"); + data_destroy(data); + return NULL; + } + data->len++; /* account for terminating NULL */ + data->data_type = GF_DATA_TYPE_DOUBLE; - return data; + return data; } - data_t * -data_from_uint16 (uint16_t value) +data_from_uint32(uint32_t value) { - int ret = 0; - data_t *data = get_new_data (); + data_t *data = get_new_data(); - if (!data) { - return NULL; - } - ret = gf_asprintf (&data->data, "%"PRIu16, value); - if (-1 == ret) { - return NULL; - } + if (!data) { + return NULL; + } + data->len = gf_asprintf(&data->data, "%" PRIu32, value); + if (-1 == data->len) { + gf_msg_debug("dict", 0, "asprintf failed"); + data_destroy(data); + return NULL; + } - data->len = strlen (data->data) + 1; + data->len++; /* account for terminating NULL */ + data->data_type = GF_DATA_TYPE_UINT; - return data; + return data; } - data_t * -data_from_ptr (void *value) +data_from_uint16(uint16_t value) { - if (!value) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "value is NULL"); - return NULL; - } + data_t *data = get_new_data(); - data_t *data = get_new_data (); + if (!data) { + return NULL; + } + data->len = gf_asprintf(&data->data, "%" PRIu16, value); + if (-1 == data->len) { + gf_msg_debug("dict", 0, "asprintf failed"); + data_destroy(data); + return NULL; + } - if (!data) { - return NULL; - } + data->len++; /* account for terminating NULL */ + data->data_type = GF_DATA_TYPE_UINT; - data->data = value; - return data; + return data; } -data_t * -data_from_static_ptr (void *value) +static data_t * +data_from_ptr_common(void *value, gf_boolean_t is_static) { -/* - this is valid to set 0 as value.. - - if (!value) { - gf_log ("dict", GF_LOG_CRITICAL, - "@value=%p", value); - return NULL; - } -*/ - data_t *data = get_new_data (); + /* it is valid to set 0/NULL as a value, no need to check *value */ - if (!data) { - return NULL; - } + data_t *data = get_new_data(); + if (!data) { + return NULL; + } - data->is_static = 1; - data->data = value; + data->data = value; + data->len = 0; + data->is_static = is_static; - return data; + data->data_type = GF_DATA_TYPE_PTR; + return data; } data_t * -str_to_data (char *value) +str_to_data(char *value) { - if (!value) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "value is NULL"); - return NULL; - } - data_t *data = get_new_data (); - - if (!data) { - return NULL; - } - data->len = strlen (value) + 1; - - data->data = value; - data->is_static = 1; + if (!value) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "value is NULL"); + return NULL; + } - return data; + return strn_to_data(value, strlen(value)); } data_t * -data_from_dynstr (char *value) +strn_to_data(char *value, const int vallen) { - if (!value) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "value is NULL"); - return NULL; - } + if (!value) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "value is NULL"); + return NULL; + } + data_t *data = get_new_data(); - data_t *data = get_new_data (); + if (!data) { + return NULL; + } + data->len = vallen + 1; + data->data_type = GF_DATA_TYPE_STR; - data->len = strlen (value) + 1; - data->data = value; + data->data = value; + data->is_static = _gf_true; - return data; + return data; } -data_t * -data_from_dynmstr (char *value) +static data_t * +data_from_dynstr(char *value) { - if (!value) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "value is NULL"); - return NULL; - } + if (!value) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "value is NULL"); + return NULL; + } - data_t *data = get_new_data (); + data_t *data = get_new_data(); - data->len = strlen (value) + 1; - data->data = value; - data->is_stdalloc = 1; + if (!data) + return NULL; + data->len = strlen(value) + 1; + data->data = value; + data->data_type = GF_DATA_TYPE_STR; - return data; + return data; } data_t * -data_from_dynptr (void *value, int32_t len) +data_from_dynptr(void *value, int32_t len) { - data_t *data = get_new_data (); + data_t *data = get_new_data(); - if (!data) - return NULL; + if (!data) + return NULL; - data->len = len; - data->data = value; + data->len = len; + data->data = value; + data->data_type = GF_DATA_TYPE_PTR; - return data; + return data; } data_t * -bin_to_data (void *value, int32_t len) +bin_to_data(void *value, int32_t len) { - if (!value) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "value is NULL"); - return NULL; - } + if (!value) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "value is NULL"); + return NULL; + } - data_t *data = get_new_data (); + data_t *data = get_new_data(); - if (!data) - return NULL; + if (!data) + return NULL; - data->is_static = 1; - data->len = len; - data->data = value; + data->is_static = _gf_true; + data->len = len; + data->data = value; - return data; + return data; } -int64_t -data_to_int64 (data_t *data) -{ - if (!data) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "data is NULL"); - return -1; - } - - char *str = alloca (data->len + 1); - if (!str) - return -1; +static char *data_type_name[GF_DATA_TYPE_MAX] = { + [GF_DATA_TYPE_UNKNOWN] = "unknown", + [GF_DATA_TYPE_STR_OLD] = "string-old-version", + [GF_DATA_TYPE_INT] = "integer", + [GF_DATA_TYPE_UINT] = "unsigned integer", + [GF_DATA_TYPE_DOUBLE] = "float", + [GF_DATA_TYPE_STR] = "string", + [GF_DATA_TYPE_PTR] = "pointer", + [GF_DATA_TYPE_GFUUID] = "gf-uuid", + [GF_DATA_TYPE_IATT] = "iatt", + [GF_DATA_TYPE_MDATA] = "mdata", +}; - memcpy (str, data->data, data->len); - str[data->len] = '\0'; - return (int64_t) strtoull (str, NULL, 0); -} +int64_t +data_to_int64(data_t *data) +{ + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, "null", -1); + + char *endptr = NULL; + int64_t value = 0; + + errno = 0; + value = strtoll(data->data, &endptr, 0); + + if (endptr && *endptr != '\0') + /* Unrecognized characters at the end of string. */ + errno = EINVAL; + if (errno) { + gf_msg_callingfn("dict", GF_LOG_WARNING, errno, + LG_MSG_DATA_CONVERSION_ERROR, + "Error in data conversion: '%s' can't " + "be represented as int64_t", + data->data); + return -1; + } + return value; +} + +/* Like above but implies signed range check. */ + +#define DATA_TO_RANGED_SIGNED(endptr, value, data, type, min, max) \ + do { \ + errno = 0; \ + value = strtoll(data->data, &endptr, 0); \ + if (endptr && *endptr != '\0') \ + errno = EINVAL; \ + if (errno || value > max || value < min) { \ + gf_msg_callingfn("dict", GF_LOG_WARNING, errno, \ + LG_MSG_DATA_CONVERSION_ERROR, \ + "Error in data conversion: '%s' can't " \ + "be represented as " #type, \ + data->data); \ + return -1; \ + } \ + return (type)value; \ + } while (0) int32_t -data_to_int32 (data_t *data) +data_to_int32(data_t *data) { - if (!data) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "data is NULL"); - return -1; - } + char *endptr = NULL; + int64_t value = 0; - char *str = alloca (data->len + 1); - if (!str) - return -1; - - memcpy (str, data->data, data->len); - str[data->len] = '\0'; - - return strtoul (str, NULL, 0); + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, "null", -1); + DATA_TO_RANGED_SIGNED(endptr, value, data, int32_t, INT_MIN, INT_MAX); } int16_t -data_to_int16 (data_t *data) +data_to_int16(data_t *data) { - if (!data) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "data is NULL"); - return -1; - } + char *endptr = NULL; + int64_t value = 0; - char *str = alloca (data->len + 1); - if (!str) - return -1; - - memcpy (str, data->data, data->len); - str[data->len] = '\0'; - - return strtol (str, NULL, 0); + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, "null", -1); + DATA_TO_RANGED_SIGNED(endptr, value, data, int16_t, SHRT_MIN, SHRT_MAX); } - int8_t -data_to_int8 (data_t *data) +data_to_int8(data_t *data) { - int32_t value = 0; + char *endptr = NULL; + int64_t value = 0; - if (!data) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "data is NULL"); - return -1; - } - - char *str = alloca (data->len + 1); - if (!str) - return -1; - - memcpy (str, data->data, data->len); - str[data->len] = '\0'; + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, "null", -1); + DATA_TO_RANGED_SIGNED(endptr, value, data, int8_t, CHAR_MIN, CHAR_MAX); +} - errno = 0; - value = strtol (str, NULL, 0); +uint64_t +data_to_uint64(data_t *data) +{ + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_UINT, "null", -1); + + char *endptr = NULL; + uint64_t value = 0; + + errno = 0; + value = strtoull(data->data, &endptr, 0); + + if (endptr && *endptr != '\0') + errno = EINVAL; + if (errno) { + gf_msg_callingfn("dict", GF_LOG_WARNING, errno, + LG_MSG_DATA_CONVERSION_ERROR, + "Error in data conversion: '%s' can't " + "be represented as uint64_t", + data->data); + return -1; + } + return value; +} + +/* Like above but implies unsigned range check. */ + +#define DATA_TO_RANGED_UNSIGNED(endptr, value, data, type, max) \ + do { \ + errno = 0; \ + value = strtoull(data->data, &endptr, 0); \ + if (endptr && *endptr != '\0') \ + errno = EINVAL; \ + if (errno || value > max) { \ + gf_msg_callingfn("dict", GF_LOG_WARNING, errno, \ + LG_MSG_DATA_CONVERSION_ERROR, \ + "Error in data conversion: '%s' can't " \ + "be represented as " #type, \ + data->data); \ + return -1; \ + } \ + return (type)value; \ + } while (0) - if ((SCHAR_MAX > value) || (SCHAR_MIN < value)) { - errno = ERANGE; - gf_log_callingfn ("dict", GF_LOG_WARNING, - "Error in data conversion: detected overflow"); - return -1; - } +uint32_t +data_to_uint32(data_t *data) +{ + char *endptr = NULL; + uint64_t value = 0; - return (int8_t)value; + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_UINT, "null", -1); + DATA_TO_RANGED_UNSIGNED(endptr, value, data, uint32_t, UINT_MAX); } - -uint64_t -data_to_uint64 (data_t *data) +uint16_t +data_to_uint16(data_t *data) { - if (!data) - return -1; - char *str = alloca (data->len + 1); - if (!str) - return -1; - - memcpy (str, data->data, data->len); - str[data->len] = '\0'; + char *endptr = NULL; + uint64_t value = 0; - return strtoll (str, NULL, 0); + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_UINT, "null", -1); + DATA_TO_RANGED_UNSIGNED(endptr, value, data, uint16_t, USHRT_MAX); } -uint32_t -data_to_uint32 (data_t *data) +uint8_t +data_to_uint8(data_t *data) { - if (!data) - return -1; + char *endptr = NULL; + uint64_t value = 0; - char *str = alloca (data->len + 1); - if (!str) - return -1; + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_UINT, "null", -1); + DATA_TO_RANGED_UNSIGNED(endptr, value, data, uint8_t, UCHAR_MAX); +} - memcpy (str, data->data, data->len); - str[data->len] = '\0'; +char * +data_to_str(data_t *data) +{ + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_STR, "null", NULL); + return data->data; +} - return strtol (str, NULL, 0); +void * +data_to_ptr(data_t *data) +{ + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_PTR, "null", NULL); + return data->data; } -uint16_t -data_to_uint16 (data_t *data) +void * +data_to_bin(data_t *data) { - if (!data) - return -1; + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_PTR, "null", NULL); + return data->data; +} - char *str = alloca (data->len + 1); - if (!str) - return -1; +struct iatt * +data_to_iatt(data_t *data, char *key) +{ + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_IATT, key, NULL); - memcpy (str, data->data, data->len); - str[data->len] = '\0'; + /* We only check for smaller size. If it's bigger we simply ignore + * the extra data. This way it's easy to do changes in the future that + * pass more data but are backward compatible (if the initial contents + * of the struct are maintained, of course). */ + if (data->len < sizeof(struct iatt)) { + gf_smsg("glusterfs", GF_LOG_ERROR, ENOBUFS, LG_MSG_UNDERSIZED_BUF, + "key=%s", key, NULL); + return NULL; + } - return strtol (str, NULL, 0); + return (struct iatt *)data->data; } -uint8_t -data_to_uint8 (data_t *data) +int +dict_null_foreach_fn(dict_t *d, char *k, data_t *v, void *tmp) { - uint32_t value = 0; + return 0; +} - if (!data) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "data is NULL"); - return -1; - } +int +dict_remove_foreach_fn(dict_t *d, char *k, data_t *v, void *_tmp) +{ + if (!d || !k) { + gf_smsg("glusterfs", GF_LOG_WARNING, EINVAL, LG_MSG_KEY_OR_VALUE_NULL, + "d=%s", d ? "key" : "dictionary", NULL); + return -1; + } - char *str = alloca (data->len + 1); - if (!str) - return -1; + dict_del(d, k); + return 0; +} - memcpy (str, data->data, data->len); - str[data->len] = '\0'; +gf_boolean_t +dict_match_everything(dict_t *d, char *k, data_t *v, void *data) +{ + return _gf_true; +} - errno = 0; - value = strtol (str, NULL, 0); +int +dict_foreach(dict_t *dict, + int (*fn)(dict_t *this, char *key, data_t *value, void *data), + void *data) +{ + int ret = dict_foreach_match(dict, dict_match_everything, NULL, fn, data); - if ((UCHAR_MAX - value) < 0) { - errno = ERANGE; - gf_log_callingfn ("dict", GF_LOG_WARNING, - "data conversion overflow detected (%s)", - strerror(errno)); - return -1; - } + if (ret > 0) + ret = 0; - return (uint8_t) value; + return ret; } -char * -data_to_str (data_t *data) +/* return values: + -1 = failure, + 0 = no matches found, + +n = n number of matches +*/ +int +dict_foreach_match(dict_t *dict, + gf_boolean_t (*match)(dict_t *this, char *key, data_t *value, + void *mdata), + void *match_data, + int (*action)(dict_t *this, char *key, data_t *value, + void *adata), + void *action_data) +{ + if (!dict || !match || !action) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "dict|match|action is " + "NULL"); + return -1; + } + + int ret = -1; + int count = 0; + data_pair_t *pairs = dict->members_list; + data_pair_t *next = NULL; + + while (pairs) { + next = pairs->next; + if (match(dict, pairs->key, pairs->value, match_data)) { + ret = action(dict, pairs->key, pairs->value, action_data); + if (ret < 0) + return ret; + count++; + } + pairs = next; + } + + return count; +} + +static gf_boolean_t +dict_fnmatch(dict_t *d, char *k, data_t *val, void *match_data) +{ + return (fnmatch(match_data, k, 0) == 0); +} +/* return values: + -1 = failure, + 0 = no matches found, + +n = n number of matches +*/ +int +dict_foreach_fnmatch(dict_t *dict, char *pattern, + int (*fn)(dict_t *this, char *key, data_t *value, + void *data), + void *data) { - if (!data) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "data is NULL"); - return NULL; - } - return data->data; + return dict_foreach_match(dict, dict_fnmatch, pattern, fn, data); } -void * -data_to_ptr (data_t *data) -{ - if (!data) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "data is NULL"); - return NULL; - } - return data->data; -} +/** + * dict_keys_join - pack the keys of the dictionary in a buffer. + * + * @value : buffer in which the keys will be packed (can be NULL) + * @size : size of the buffer which is sent (can be 0, in which case buffer + * is not packed but only length is returned) + * @dict : dictionary of which all the keys will be packed + * @filter_fn : keys matched in filter_fn() is counted. + * + * @return : @length of string after joining keys. + * + */ -void * -data_to_bin (data_t *data) +int +dict_keys_join(void *value, int size, dict_t *dict, int (*filter_fn)(char *k)) { - if (!data) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "data is NULL"); - return NULL; - } - return data->data; -} + int len = 0; + data_pair_t *pairs = dict->members_list; + data_pair_t *next = NULL; -void -dict_foreach (dict_t *dict, - void (*fn)(dict_t *this, - char *key, - data_t *value, - void *data), - void *data) -{ - if (!dict) { - gf_log_callingfn ("dict", GF_LOG_WARNING, - "dict is NULL"); - return; + while (pairs) { + next = pairs->next; + + if (filter_fn && filter_fn(pairs->key)) { + pairs = next; + continue; } - data_pair_t *pairs = dict->members_list; - data_pair_t *next = NULL; + if (value && (size > len)) + strncpy(value + len, pairs->key, size - len); - while (pairs) { - next = pairs->next; - fn (dict, pairs->key, pairs->value, data); - pairs = next; - } -} + len += (strlen(pairs->key) + 1); + pairs = next; + } -static void -_copy (dict_t *unused, - char *key, - data_t *value, - void *newdict) -{ - dict_set ((dict_t *)newdict, key, (value)); + return len; } -static void -_remove (dict_t *dict, - char *key, - data_t *value, - void *unused) +static int +dict_copy_one(dict_t *unused, char *key, data_t *value, void *newdict) { - dict_del ((dict_t *)dict, key); + return dict_set((dict_t *)newdict, key, (value)); } - dict_t * -dict_copy (dict_t *dict, - dict_t *new) +dict_copy(dict_t *dict, dict_t *new) { - if (!dict) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "dict is NULL"); - return NULL; - } + if (!dict) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "dict is NULL"); + return NULL; + } - if (!new) - new = get_new_dict_full (dict->hash_size); + if (!new) + new = get_new_dict_full(dict->hash_size); - dict_foreach (dict, _copy, new); + dict_foreach(dict, dict_copy_one, new); - return new; + return new; } int -dict_reset (dict_t *dict) -{ - int32_t ret = -1; - if (!dict) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "dict is NULL"); - goto out; - } - dict_foreach (dict, _remove, NULL); - ret = 0; +dict_reset(dict_t *dict) +{ + int32_t ret = -1; + if (!dict) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "dict is NULL"); + goto out; + } + dict_foreach(dict, dict_remove_foreach_fn, NULL); + ret = 0; out: - return ret; + return ret; } dict_t * -dict_copy_with_ref (dict_t *dict, - dict_t *new) +dict_copy_with_ref(dict_t *dict, dict_t *new) { - dict_t *local_new = NULL; + dict_t *local_new = NULL; - GF_VALIDATE_OR_GOTO("dict", dict, fail); + GF_VALIDATE_OR_GOTO("dict", dict, fail); - if (new == NULL) { - local_new = dict_new (); - GF_VALIDATE_OR_GOTO("dict", local_new, fail); - new = local_new; - } + if (new == NULL) { + local_new = dict_new(); + GF_VALIDATE_OR_GOTO("dict", local_new, fail); + new = local_new; + } - dict_foreach (dict, _copy, new); + dict_foreach(dict, dict_copy_one, new); fail: - return new; + return new; } /* @@ -1348,900 +1495,1292 @@ fail: * -val error, val = errno */ - static int -dict_get_with_ref (dict_t *this, char *key, data_t **data) +dict_get_with_refn(dict_t *this, char *key, const int keylen, data_t **data) { - data_pair_t * pair = NULL; - int ret = -ENOENT; + data_pair_t *pair = NULL; + int ret = -ENOENT; + uint32_t hash; - if (!this || !key || !data) { - gf_log_callingfn ("dict", GF_LOG_WARNING, - "dict OR key (%s) is NULL", key); - ret = -EINVAL; - goto err; - } + hash = (uint32_t)XXH64(key, keylen, 0); - LOCK (&this->lock); - { - pair = _dict_lookup (this, key); - } - UNLOCK (&this->lock); + LOCK(&this->lock); + { + pair = dict_lookup_common(this, key, hash); if (pair) { - ret = 0; - *data = data_ref (pair->value); + ret = 0; + *data = data_ref(pair->value); } + } + UNLOCK(&this->lock); -err: - return ret; + return ret; +} + +int +dict_get_with_ref(dict_t *this, char *key, data_t **data) +{ + if (!this || !key || !data) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "dict OR key (%s) is NULL", key); + return -EINVAL; + } + + return dict_get_with_refn(this, key, strlen(key), data); } static int -_data_to_ptr (data_t *data, void **val) +data_to_ptr_common(data_t *data, void **val) { - int ret = 0; + int ret = 0; - if (!data) { - ret = -EINVAL; - goto err; - } + if (!data) { + ret = -EINVAL; + goto err; + } - *val = data->data; + *val = data->data; err: - return ret; + return ret; } - static int -_data_to_int8 (data_t *data, int8_t *val) +data_to_int8_ptr(data_t *data, int8_t *val) { - int ret = 0; - char * str = NULL; + int ret = 0; - if (!data || !val) { - ret = -EINVAL; - goto err; - } + if (!data || !val) { + ret = -EINVAL; + goto err; + } - str = alloca (data->len + 1); - if (!str) { - ret = -ENOMEM; - goto err; - } - memcpy (str, data->data, data->len); - str[data->len] = '\0'; - - errno = 0; - *val = strtol (str, NULL, 0); - if (errno != 0) - ret = -errno; + errno = 0; + *val = strtol(data->data, NULL, 0); + if (errno != 0) + ret = -errno; err: - return ret; + return ret; } static int -_data_to_int16 (data_t *data, int16_t *val) +data_to_int16_ptr(data_t *data, int16_t *val) { - int ret = 0; - char * str = NULL; + int ret = 0; - if (!data || !val) { - ret = -EINVAL; - goto err; - } - - str = alloca (data->len + 1); - if (!str) { - ret = -ENOMEM; - goto err; - } - memcpy (str, data->data, data->len); - str[data->len] = '\0'; + if (!data || !val) { + ret = -EINVAL; + goto err; + } - errno = 0; - *val = strtol (str, NULL, 0); - if (errno != 0) - ret = -errno; + errno = 0; + *val = strtol(data->data, NULL, 0); + if (errno != 0) + ret = -errno; err: - return ret; + return ret; } static int -_data_to_int32 (data_t *data, int32_t *val) +data_to_int32_ptr(data_t *data, int32_t *val) { - int ret = 0; - char * str = NULL; - - if (!data || !val) { - ret = -EINVAL; - goto err; - } + int ret = 0; - str = alloca (data->len + 1); - if (!str) { - ret = -ENOMEM; - goto err; - } - memcpy (str, data->data, data->len); - str[data->len] = '\0'; + if (!data || !val) { + ret = -EINVAL; + goto err; + } - errno = 0; - *val = strtol (str, NULL, 0); - if (errno != 0) - ret = -errno; + errno = 0; + *val = strtol(data->data, NULL, 0); + if (errno != 0) + ret = -errno; err: - return ret; + return ret; } static int -_data_to_int64 (data_t *data, int64_t *val) +data_to_int64_ptr(data_t *data, int64_t *val) { - int ret = 0; - char * str = NULL; - - if (!data || !val) { - ret = -EINVAL; - goto err; - } + int ret = 0; - str = alloca (data->len + 1); - if (!str) { - ret = -ENOMEM; - goto err; - } - memcpy (str, data->data, data->len); - str[data->len] = '\0'; + if (!data || !val) { + ret = -EINVAL; + goto err; + } - errno = 0; - *val = strtoll (str, NULL, 0); - if (errno != 0) - ret = -errno; + errno = 0; + *val = strtoll(data->data, NULL, 0); + if (errno != 0) + ret = -errno; err: - return ret; + return ret; } static int -_data_to_uint16 (data_t *data, uint16_t *val) +data_to_uint16_ptr(data_t *data, uint16_t *val) { - int ret = 0; - char * str = NULL; - - if (!data || !val) { - ret = -EINVAL; - goto err; - } + int ret = 0; - str = alloca (data->len + 1); - if (!str) { - ret = -ENOMEM; - goto err; - } - memcpy (str, data->data, data->len); - str[data->len] = '\0'; + if (!data || !val) { + ret = -EINVAL; + goto err; + } - errno = 0; - *val = strtoul (str, NULL, 0); - if (errno != 0) - ret = -errno; + errno = 0; + *val = strtoul(data->data, NULL, 0); + if (errno != 0) + ret = -errno; err: - return ret; + return ret; } static int -_data_to_uint32 (data_t *data, uint32_t *val) +data_to_uint32_ptr(data_t *data, uint32_t *val) { - int ret = 0; - char * str = NULL; + int ret = 0; - if (!data || !val) { - ret = -EINVAL; - goto err; - } + if (!data || !val) { + ret = -EINVAL; + goto err; + } - str = alloca (data->len + 1); - if (!str) { - ret = -ENOMEM; - goto err; - } - memcpy (str, data->data, data->len); - str[data->len] = '\0'; - - errno = 0; - *val = strtoul (str, NULL, 0); - if (errno != 0) - ret = -errno; + errno = 0; + *val = strtoul(data->data, NULL, 0); + if (errno != 0) + ret = -errno; err: - return ret; + return ret; } static int -_data_to_uint64 (data_t *data, uint64_t *val) +data_to_uint64_ptr(data_t *data, uint64_t *val) { - int ret = 0; - char * str = NULL; + int ret = 0; - if (!data || !val) { - ret = -EINVAL; - goto err; - } + if (!data || !val) { + ret = -EINVAL; + goto err; + } - str = alloca (data->len + 1); - if (!str) { - ret = -ENOMEM; - goto err; - } - memcpy (str, data->data, data->len); - str[data->len] = '\0'; - - errno = 0; - *val = strtoull (str, NULL, 0); - if (errno != 0) - ret = -errno; + errno = 0; + *val = strtoull(data->data, NULL, 0); + if (errno != 0) + ret = -errno; err: - return ret; + return ret; } static int -_data_to_double (data_t *data, double *val) +data_to_double_ptr(data_t *data, double *val) { - int ret = 0; - char * str = NULL; - - if (!data || !val) { - ret = -EINVAL; - goto err; - } + int ret = 0; - str = alloca (data->len + 1); - if (!str) { - ret = -ENOMEM; - goto err; - } - memcpy (str, data->data, data->len); - str[data->len] = '\0'; + if (!data || !val) { + ret = -EINVAL; + goto err; + } - errno = 0; - *val = strtod (str, NULL); - if (errno != 0) - ret = -errno; + errno = 0; + *val = strtod(data->data, NULL); + if (errno != 0) + ret = -errno; err: - return ret; + return ret; } int -dict_get_int8 (dict_t *this, char *key, int8_t *val) +dict_get_int8(dict_t *this, char *key, int8_t *val) { - data_t * data = NULL; - int ret = 0; + data_t *data = NULL; + int ret = 0; - if (!this || !key || !val) { - ret = -EINVAL; - goto err; - } + if (!val) { + ret = -EINVAL; + goto err; + } - ret = dict_get_with_ref (this, key, &data); - if (ret != 0) { - goto err; - } + ret = dict_get_with_ref(this, key, &data); + if (ret != 0) { + goto err; + } - ret = _data_to_int8 (data, val); + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, key, -EINVAL); + + ret = data_to_int8_ptr(data, val); err: - if (data) - data_unref (data); - return ret; + if (data) + data_unref(data); + return ret; } - int -dict_set_int8 (dict_t *this, char *key, int8_t val) +dict_set_int8(dict_t *this, char *key, int8_t val) { - data_t * data = NULL; - int ret = 0; + data_t *data = NULL; + int ret = 0; - data = data_from_int8 (val); - if (!data) { - ret = -EINVAL; - goto err; - } + data = data_from_int8(val); + if (!data) { + ret = -EINVAL; + goto err; + } - ret = dict_set (this, key, data); + ret = dict_set(this, key, data); + if (ret < 0) + data_destroy(data); err: - return ret; + return ret; } int -dict_get_int16 (dict_t *this, char *key, int16_t *val) +dict_get_int16(dict_t *this, char *key, int16_t *val) { - data_t * data = NULL; - int ret = 0; + data_t *data = NULL; + int ret = 0; - if (!this || !key || !val) { - ret = -EINVAL; - goto err; - } + if (!val) { + ret = -EINVAL; + goto err; + } - ret = dict_get_with_ref (this, key, &data); - if (ret != 0) { - goto err; - } + ret = dict_get_with_ref(this, key, &data); + if (ret != 0) { + goto err; + } - ret = _data_to_int16 (data, val); + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, key, -EINVAL); + + ret = data_to_int16_ptr(data, val); err: - if (data) - data_unref (data); - return ret; + if (data) + data_unref(data); + return ret; } +int +dict_set_int16(dict_t *this, char *key, int16_t val) +{ + data_t *data = NULL; + int ret = 0; + + data = data_from_int16(val); + if (!data) { + ret = -EINVAL; + goto err; + } + + ret = dict_set(this, key, data); + if (ret < 0) + data_destroy(data); + +err: + return ret; +} int -dict_set_int16 (dict_t *this, char *key, int16_t val) +dict_get_int32n(dict_t *this, char *key, const int keylen, int32_t *val) { - data_t * data = NULL; - int ret = 0; + data_t *data = NULL; + int ret = 0; - data = data_from_int16 (val); - if (!data) { - ret = -EINVAL; - goto err; - } + if (!this || !key || !val) { + ret = -EINVAL; + goto err; + } + + ret = dict_get_with_refn(this, key, keylen, &data); + if (ret != 0) { + goto err; + } - ret = dict_set (this, key, data); + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, key, -EINVAL); + + ret = data_to_int32_ptr(data, val); err: - return ret; + if (data) + data_unref(data); + return ret; } int -dict_get_int32 (dict_t *this, char *key, int32_t *val) +dict_get_int32(dict_t *this, char *key, int32_t *val) { - data_t * data = NULL; - int ret = 0; + data_t *data = NULL; + int ret = 0; - if (!this || !key || !val) { - ret = -EINVAL; - goto err; - } + if (!val) { + ret = -EINVAL; + goto err; + } - ret = dict_get_with_ref (this, key, &data); - if (ret != 0) { - goto err; - } + ret = dict_get_with_ref(this, key, &data); + if (ret != 0) { + goto err; + } + + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, key, -EINVAL); - ret = _data_to_int32 (data, val); + ret = data_to_int32_ptr(data, val); err: - if (data) - data_unref (data); - return ret; + if (data) + data_unref(data); + return ret; } +int +dict_set_int32n(dict_t *this, char *key, const int keylen, int32_t val) +{ + data_t *data = NULL; + int ret = 0; + + data = data_from_int32(val); + if (!data) { + ret = -EINVAL; + goto err; + } + + ret = dict_setn(this, key, keylen, data); + if (ret < 0) + data_destroy(data); + +err: + return ret; +} int -dict_set_int32 (dict_t *this, char *key, int32_t val) +dict_set_int32(dict_t *this, char *key, int32_t val) { - data_t * data = NULL; - int ret = 0; + data_t *data = data_from_int32(val); + int ret = 0; - data = data_from_int32 (val); - if (!data) { - ret = -EINVAL; - goto err; - } + if (!data) { + ret = -EINVAL; + goto err; + } - ret = dict_set (this, key, data); + ret = dict_set(this, key, data); + if (ret < 0) + data_destroy(data); err: - return ret; + return ret; } int -dict_get_int64 (dict_t *this, char *key, int64_t *val) +dict_get_int64(dict_t *this, char *key, int64_t *val) { - data_t * data = NULL; - int ret = 0; + data_t *data = NULL; + int ret = 0; - if (!this || !key || !val) { - ret = -EINVAL; - goto err; - } + if (!val) { + ret = -EINVAL; + goto err; + } - ret = dict_get_with_ref (this, key, &data); - if (ret != 0) { - goto err; - } + ret = dict_get_with_ref(this, key, &data); + if (ret != 0) { + goto err; + } - ret = _data_to_int64 (data, val); + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, key, -EINVAL); + + ret = data_to_int64_ptr(data, val); err: - if (data) - data_unref (data); - return ret; + if (data) + data_unref(data); + return ret; } - int -dict_set_int64 (dict_t *this, char *key, int64_t val) +dict_set_int64(dict_t *this, char *key, int64_t val) { - data_t * data = NULL; - int ret = 0; + data_t *data = data_from_int64(val); + int ret = 0; - data = data_from_int64 (val); - if (!data) { - ret = -EINVAL; - goto err; - } + if (!data) { + ret = -EINVAL; + goto err; + } - ret = dict_set (this, key, data); + ret = dict_set(this, key, data); + if (ret < 0) + data_destroy(data); err: - return ret; + return ret; } int -dict_get_uint16 (dict_t *this, char *key, uint16_t *val) +dict_get_uint16(dict_t *this, char *key, uint16_t *val) { - data_t * data = NULL; - int ret = 0; + data_t *data = NULL; + int ret = 0; - if (!this || !key || !val) { - ret = -EINVAL; - goto err; - } + if (!val) { + ret = -EINVAL; + goto err; + } - ret = dict_get_with_ref (this, key, &data); - if (ret != 0) { - goto err; - } + ret = dict_get_with_ref(this, key, &data); + if (ret != 0) { + goto err; + } - ret = _data_to_uint16 (data, val); + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_UINT, key, -EINVAL); + + ret = data_to_uint16_ptr(data, val); err: - if (data) - data_unref (data); - return ret; + if (data) + data_unref(data); + return ret; } - int -dict_set_uint16 (dict_t *this, char *key, uint16_t val) +dict_set_uint16(dict_t *this, char *key, uint16_t val) { - data_t * data = NULL; - int ret = 0; + data_t *data = data_from_uint16(val); + int ret = 0; - data = data_from_uint16 (val); - if (!data) { - ret = -EINVAL; - goto err; - } + if (!data) { + ret = -EINVAL; + goto err; + } - ret = dict_set (this, key, data); + ret = dict_set(this, key, data); + if (ret < 0) + data_destroy(data); err: - return ret; + return ret; } int -dict_get_uint32 (dict_t *this, char *key, uint32_t *val) +dict_get_uint32(dict_t *this, char *key, uint32_t *val) { - data_t * data = NULL; - int ret = 0; + data_t *data = NULL; + int ret = 0; - if (!this || !key || !val) { - ret = -EINVAL; - goto err; - } + if (!val) { + ret = -EINVAL; + goto err; + } - ret = dict_get_with_ref (this, key, &data); - if (ret != 0) { - goto err; - } + ret = dict_get_with_ref(this, key, &data); + if (ret != 0) { + goto err; + } - ret = _data_to_uint32 (data, val); + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_UINT, key, -EINVAL); + + ret = data_to_uint32_ptr(data, val); err: - if (data) - data_unref (data); - return ret; + if (data) + data_unref(data); + return ret; } - - int -dict_set_uint32 (dict_t *this, char *key, uint32_t val) +dict_set_uint32(dict_t *this, char *key, uint32_t val) { - data_t * data = NULL; - int ret = 0; + data_t *data = data_from_uint32(val); + int ret = 0; - data = data_from_uint32 (val); - if (!data) { - ret = -EINVAL; - goto err; - } + if (!data) { + ret = -EINVAL; + goto err; + } - ret = dict_set (this, key, data); + ret = dict_set(this, key, data); + if (ret < 0) + data_destroy(data); err: - return ret; + return ret; } int -dict_get_uint64 (dict_t *this, char *key, uint64_t *val) +dict_get_uint64(dict_t *this, char *key, uint64_t *val) { - data_t * data = NULL; - int ret = 0; + data_t *data = NULL; + int ret = 0; - if (!this || !key || !val) { - ret = -EINVAL; - goto err; - } + if (!val) { + ret = -EINVAL; + goto err; + } - ret = dict_get_with_ref (this, key, &data); - if (ret != 0) { - goto err; - } + ret = dict_get_with_ref(this, key, &data); + if (ret != 0) { + goto err; + } + + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_UINT, key, -EINVAL); - ret = _data_to_uint64 (data, val); + ret = data_to_uint64_ptr(data, val); err: - if (data) - data_unref (data); - return ret; + if (data) + data_unref(data); + return ret; } - int -dict_set_uint64 (dict_t *this, char *key, uint64_t val) +dict_set_uint64(dict_t *this, char *key, uint64_t val) { - data_t * data = NULL; - int ret = 0; + data_t *data = data_from_uint64(val); + int ret = 0; - data = data_from_uint64 (val); - if (!data) { - ret = -EINVAL; - goto err; - } + if (!data) { + ret = -EINVAL; + goto err; + } - ret = dict_set (this, key, data); + ret = dict_set(this, key, data); + if (ret < 0) + data_destroy(data); err: - return ret; + return ret; } +/* + * dict_check_flag can be used to check a one bit flag in an array of flags + * The flag argument indicates the bit position (within the array of bits). + * Currently limited to max of 256 flags for a key. + * return value, + * 1 : flag is set + * 0 : flag is not set + * <0: Error + */ int -dict_get_double (dict_t *this, char *key, double *val) +dict_check_flag(dict_t *this, char *key, int flag) { - data_t *data = NULL; - int ret = 0; + data_t *data = NULL; + int ret = -ENOENT; + + ret = dict_get_with_ref(this, key, &data); + if (ret < 0) { + return ret; + } + + if (BIT_VALUE((unsigned char *)(data->data), flag)) + ret = 1; + else + ret = 0; - if (!this || !key || !val) { - ret = -EINVAL; + data_unref(data); + return ret; +} + +/* + * _dict_modify_flag can be used to set/clear a bit flag in an array of flags + * flag: indicates the bit position. limited to max of DICT_MAX_FLAGS. + * op: Indicates operation DICT_FLAG_SET / DICT_FLAG_CLEAR + */ +static int +_dict_modify_flag(dict_t *this, char *key, int flag, int op) +{ + data_t *data = NULL; + int ret = 0; + data_pair_t *pair = NULL; + char *ptr = NULL; + int hashval = 0; + uint32_t hash; + + if (!this || !key) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "dict OR key (%s) is NULL", key); + ret = -EINVAL; + goto err; + } + + /* + * Using a size of 32 bytes to support max of 256 + * flags in a single key. This should be suffcient. + */ + GF_ASSERT(flag >= 0 && flag < DICT_MAX_FLAGS); + + hash = (uint32_t)XXH64(key, strlen(key), 0); + LOCK(&this->lock); + { + pair = dict_lookup_common(this, key, hash); + + if (pair) { + data = pair->value; + if (op == DICT_FLAG_SET) + BIT_SET((unsigned char *)(data->data), flag); + else + BIT_CLEAR((unsigned char *)(data->data), flag); + } else { + ptr = GF_CALLOC(1, DICT_MAX_FLAGS / 8, gf_common_mt_char); + if (!ptr) { + gf_smsg("dict", GF_LOG_ERROR, ENOMEM, LG_MSG_NO_MEMORY, + "flag bit array", NULL); + ret = -ENOMEM; goto err; - } + } + + data = data_from_dynptr(ptr, DICT_MAX_FLAGS / 8); + + if (!data) { + gf_smsg("dict", GF_LOG_ERROR, ENOMEM, LG_MSG_NO_MEMORY, "data", + NULL); + GF_FREE(ptr); + ret = -ENOMEM; + goto err; + } - ret = dict_get_with_ref (this, key, &data); - if (ret != 0) { + if (op == DICT_FLAG_SET) + BIT_SET((unsigned char *)(data->data), flag); + else + BIT_CLEAR((unsigned char *)(data->data), flag); + + if (this->free_pair.key) { /* the free pair is in use */ + pair = mem_get0(THIS->ctx->dict_pair_pool); + if (!pair) { + gf_smsg("dict", GF_LOG_ERROR, ENOMEM, LG_MSG_NO_MEMORY, + "dict pair", NULL); + ret = -ENOMEM; + goto err; + } + } else { /* use the free pair */ + pair = &this->free_pair; + } + + pair->key = (char *)GF_MALLOC(strlen(key) + 1, gf_common_mt_char); + if (!pair->key) { + gf_smsg("dict", GF_LOG_ERROR, ENOMEM, LG_MSG_NO_MEMORY, + "dict pair", NULL); + ret = -ENOMEM; goto err; + } + strcpy(pair->key, key); + pair->key_hash = hash; + pair->value = data_ref(data); + this->totkvlen += (strlen(key) + 1 + data->len); + hashval = hash % this->hash_size; + pair->hash_next = this->members[hashval]; + this->members[hashval] = pair; + + pair->next = this->members_list; + pair->prev = NULL; + if (this->members_list) + this->members_list->prev = pair; + this->members_list = pair; + this->count++; + + if (this->max_count < this->count) + this->max_count = this->count; } + } - ret = _data_to_double (data, val); + UNLOCK(&this->lock); + return 0; err: - if (data) - data_unref (data); - return ret; + if (key && this) + UNLOCK(&this->lock); + + if (pair) { + if (pair->key) { + GF_FREE(pair->key); + pair->key = NULL; + } + if (pair != &this->free_pair) { + mem_put(pair); + } + } + + if (data) + data_destroy(data); + + gf_smsg("dict", GF_LOG_ERROR, EINVAL, LG_MSG_DICT_SET_FAILED, "key=%s", key, + NULL); + + return ret; } +/* + * Todo: + * Add below primitives as needed: + * dict_check_flags(this, key, flag...): variadic function to check + * multiple flags at a time. + * dict_set_flags(this, key, flag...): set multiple flags + * dict_clear_flags(this, key, flag...): reset multiple flags + */ + int -dict_set_double (dict_t *this, char *key, double val) +dict_set_flag(dict_t *this, char *key, int flag) { - data_t * data = NULL; - int ret = 0; + return _dict_modify_flag(this, key, flag, DICT_FLAG_SET); +} - data = data_from_double (val); - if (!data) { - ret = -EINVAL; - goto err; - } +int +dict_clear_flag(dict_t *this, char *key, int flag) +{ + return _dict_modify_flag(this, key, flag, DICT_FLAG_CLEAR); +} + +int +dict_get_double(dict_t *this, char *key, double *val) +{ + data_t *data = NULL; + int ret = 0; + + if (!val) { + ret = -EINVAL; + goto err; + } + + ret = dict_get_with_ref(this, key, &data); + if (ret != 0) { + goto err; + } - ret = dict_set (this, key, data); + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_DOUBLE, key, -EINVAL); + + ret = data_to_double_ptr(data, val); err: - return ret; + if (data) + data_unref(data); + return ret; } int -dict_set_static_ptr (dict_t *this, char *key, void *ptr) +dict_set_double(dict_t *this, char *key, double val) { - data_t * data = NULL; - int ret = 0; + data_t *data = data_from_double(val); + int ret = 0; - data = data_from_static_ptr (ptr); - if (!data) { - ret = -EINVAL; - goto err; - } + if (!data) { + ret = -EINVAL; + goto err; + } - ret = dict_set (this, key, data); + ret = dict_set(this, key, data); + if (ret < 0) + data_destroy(data); err: - return ret; + return ret; } int -dict_set_dynptr (dict_t *this, char *key, void *ptr, size_t len) +dict_set_static_ptr(dict_t *this, char *key, void *ptr) { - data_t * data = NULL; - int ret = 0; + data_t *data = data_from_ptr_common(ptr, _gf_true); + int ret = 0; - data = data_from_dynptr (ptr, len); - if (!data) { - ret = -EINVAL; - goto err; - } + if (!data) { + ret = -EINVAL; + goto err; + } - ret = dict_set (this, key, data); + ret = dict_set(this, key, data); + if (ret < 0) + data_destroy(data); err: - return ret; + return ret; } int -dict_get_ptr (dict_t *this, char *key, void **ptr) +dict_set_dynptr(dict_t *this, char *key, void *ptr, size_t len) { - data_t * data = NULL; - int ret = 0; + data_t *data = data_from_dynptr(ptr, len); + int ret = 0; - if (!this || !key || !ptr) { - ret = -EINVAL; - goto err; - } + if (!data) { + ret = -EINVAL; + goto err; + } - ret = dict_get_with_ref (this, key, &data); - if (ret != 0) { - goto err; - } + ret = dict_set(this, key, data); + if (ret < 0) + data_destroy(data); - ret = _data_to_ptr (data, ptr); - if (ret != 0) { - goto err; - } +err: + return ret; +} + +int +dict_get_ptr(dict_t *this, char *key, void **ptr) +{ + data_t *data = NULL; + int ret = 0; + + if (!ptr) { + ret = -EINVAL; + goto err; + } + + ret = dict_get_with_ref(this, key, &data); + if (ret != 0) { + goto err; + } + + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_PTR, key, -EINVAL); + + ret = data_to_ptr_common(data, ptr); + if (ret != 0) { + goto err; + } err: - if (data) - data_unref (data); + if (data) + data_unref(data); - return ret; + return ret; } int -dict_get_ptr_and_len (dict_t *this, char *key, void **ptr, int *len) +dict_get_ptr_and_len(dict_t *this, char *key, void **ptr, int *len) { - data_t * data = NULL; - int ret = 0; + data_t *data = NULL; + int ret = 0; - if (!this || !key || !ptr) { - ret = -EINVAL; - goto err; - } + if (!ptr) { + ret = -EINVAL; + goto err; + } - ret = dict_get_with_ref (this, key, &data); - if (ret != 0) { - goto err; - } + ret = dict_get_with_ref(this, key, &data); + if (ret != 0) { + goto err; + } - *len = data->len; + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_PTR, key, -EINVAL); - ret = _data_to_ptr (data, ptr); - if (ret != 0) { - goto err; - } + *len = data->len; + + ret = data_to_ptr_common(data, ptr); + if (ret != 0) { + goto err; + } err: - if (data) - data_unref (data); + if (data) + data_unref(data); - return ret; + return ret; } +/* Get string - with known key length */ int -dict_set_ptr (dict_t *this, char *key, void *ptr) +dict_get_strn(dict_t *this, char *key, const int keylen, char **str) { - data_t * data = NULL; - int ret = 0; + data_t *data = NULL; + int ret = -EINVAL; - data = data_from_ptr (ptr); - if (!data) { - ret = -EINVAL; - goto err; - } + if (!this || !key || !str) { + goto err; + } + ret = dict_get_with_refn(this, key, keylen, &data); + if (ret < 0) { + goto err; + } + + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_STR, key, -EINVAL); - ret = dict_set (this, key, data); + *str = data->data; err: - return ret; -} + if (data) + data_unref(data); + return ret; +} int -dict_get_str (dict_t *this, char *key, char **str) +dict_get_str(dict_t *this, char *key, char **str) { - data_t * data = NULL; - int ret = -EINVAL; + data_t *data = NULL; + int ret = -EINVAL; - if (!this || !key || !str) { - goto err; - } + if (!str) { + goto err; + } + ret = dict_get_with_ref(this, key, &data); + if (ret < 0) { + goto err; + } - ret = dict_get_with_ref (this, key, &data); - if (ret < 0) { - goto err; - } + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_STR, key, -EINVAL); - if (!data || !data->data) { - goto err; - } - *str = data->data; + *str = data->data; err: - if (data) - data_unref (data); + if (data) + data_unref(data); - return ret; + return ret; } int -dict_set_str (dict_t *this, char *key, char *str) +dict_set_str(dict_t *this, char *key, char *str) { - data_t * data = NULL; - int ret = 0; + data_t *data = str_to_data(str); + int ret = 0; - data = str_to_data (str); - if (!data) { - ret = -EINVAL; - goto err; - } + if (!data) { + ret = -EINVAL; + goto err; + } - ret = dict_set (this, key, data); + ret = dict_set(this, key, data); + if (ret < 0) + data_destroy(data); err: - return ret; + return ret; } +/* Set string - with known key length */ int -dict_set_dynstr (dict_t *this, char *key, char *str) +dict_set_strn(dict_t *this, char *key, const int keylen, char *str) { - data_t * data = NULL; - int ret = 0; + data_t *data = NULL; + int ret = 0; - data = data_from_dynstr (str); - if (!data) { - ret = -EINVAL; - goto err; - } + data = str_to_data(str); + if (!data) { + ret = -EINVAL; + goto err; + } - ret = dict_set (this, key, data); + ret = dict_setn(this, key, keylen, data); + if (ret < 0) + data_destroy(data); err: - return ret; + return ret; } -/* - for malloced strings we should do a free instead of GF_FREE -*/ +/* Set string - with known key length and known value length */ int -dict_set_dynmstr (dict_t *this, char *key, char *str) +dict_set_nstrn(dict_t *this, char *key, const int keylen, char *str, + const int vallen) { - data_t * data = NULL; - int ret = 0; + data_t *data = strn_to_data(str, vallen); + int ret = 0; - data = data_from_dynmstr (str); - if (!data) { - ret = -EINVAL; - goto err; - } + if (!data) { + ret = -EINVAL; + goto err; + } - ret = dict_set (this, key, data); + ret = dict_setn(this, key, keylen, data); + if (ret < 0) + data_destroy(data); err: - return ret; + return ret; } +int +dict_set_dynstr_with_alloc(dict_t *this, char *key, const char *str) +{ + char *alloc_str = gf_strdup(str); + int ret = -1; + + if (!alloc_str) + return ret; + + ret = dict_set_dynstr(this, key, alloc_str); + if (ret == -EINVAL) + GF_FREE(alloc_str); + + return ret; +} int -dict_get_bin (dict_t *this, char *key, void **bin) +dict_set_dynstr(dict_t *this, char *key, char *str) { - data_t * data = NULL; - int ret = -EINVAL; + const int keylen = strlen(key); + return dict_set_dynstrn(this, key, keylen, str); +} - if (!this || !key || !bin) { - goto err; - } +int +dict_set_dynstrn(dict_t *this, char *key, const int keylen, char *str) +{ + data_t *data = data_from_dynstr(str); + int ret = 0; - ret = dict_get_with_ref (this, key, &data); - if (ret < 0) { - goto err; - } + if (!data) { + ret = -EINVAL; + goto err; + } - if (!data || !data->data) { - goto err; - } - *bin = data->data; + ret = dict_setn(this, key, keylen, data); + if (ret < 0) + data_destroy(data); err: - if (data) - data_unref (data); + return ret; +} - return ret; +/* This function is called only by the volgen for now. + Check how else you can handle it */ +int +dict_set_option(dict_t *this, char *key, char *str) +{ + data_t *data = data_from_dynstr(str); + int ret = 0; + + if (!data) { + ret = -EINVAL; + goto err; + } + + data->data_type = GF_DATA_TYPE_STR_OLD; + ret = dict_set(this, key, data); + if (ret < 0) + data_destroy(data); +err: + return ret; } +int +dict_add_dynstr_with_alloc(dict_t *this, char *key, char *str) +{ + data_t *data = NULL; + int ret = 0; + char *alloc_str = gf_strdup(str); + + if (!alloc_str) + goto out; + + data = data_from_dynstr(alloc_str); + if (!data) { + GF_FREE(alloc_str); + ret = -EINVAL; + goto out; + } + + ret = dict_add(this, key, data); + if (ret < 0) + data_destroy(data); + +out: + return ret; +} int -dict_set_bin (dict_t *this, char *key, void *ptr, size_t size) +dict_get_bin(dict_t *this, char *key, void **bin) { - data_t * data = NULL; - int ret = 0; + data_t *data = NULL; + int ret = -EINVAL; - if (!ptr || (size < 0)) { - ret = -EINVAL; - goto err; - } + if (!bin) { + goto err; + } - data = bin_to_data (ptr, size); - if (!data) { - ret = -EINVAL; - goto err; - } + ret = dict_get_with_ref(this, key, &data); + if (ret < 0) { + goto err; + } - data->data = ptr; - data->len = size; - data->is_static = 0; + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_PTR, key, ret); - ret = dict_set (this, key, data); + *bin = data->data; err: - return ret; + if (data) + data_unref(data); + + return ret; } +/******************************************************************** + * + * dict_set_bin_common: + * This is the common function to set key and its value in + * dictionary. Flag(is_static) should be set appropriately based + * on the type of memory type used for value(*ptr). If flag is set + * to false value(*ptr) will be freed using GF_FREE() on destroy. + * + *******************************************************************/ +static int +dict_set_bin_common(dict_t *this, char *key, void *ptr, size_t size, + gf_boolean_t is_static, gf_dict_data_type_t type) +{ + data_t *data = NULL; + int ret = 0; + + if (!ptr || (size > DICT_KEY_VALUE_MAX_SIZE)) { + ret = -EINVAL; + goto err; + } + + data = bin_to_data(ptr, size); + if (!data) { + ret = -EINVAL; + goto err; + } + + data->is_static = is_static; + data->data_type = type; + + ret = dict_set(this, key, data); + if (ret < 0) { + /* don't free data->data, let callers handle it */ + data->data = NULL; + data_destroy(data); + } + +err: + return ret; +} +/******************************************************************** + * + * dict_set_bin: + * Set key and its value in the dictionary. This function should + * be called if the value is stored in dynamic memory. + * + *******************************************************************/ int -dict_set_static_bin (dict_t *this, char *key, void *ptr, size_t size) +dict_set_bin(dict_t *this, char *key, void *ptr, size_t size) { - data_t * data = NULL; - int ret = 0; + return dict_set_bin_common(this, key, ptr, size, _gf_false, + GF_DATA_TYPE_PTR); +} - if (!ptr || (size < 0)) { - ret = -EINVAL; - goto err; - } +/******************************************************************** + * + * dict_set_static_bin: + * Set key and its value in the dictionary. This function should + * be called if the value is stored in static memory. + * + *******************************************************************/ +int +dict_set_static_bin(dict_t *this, char *key, void *ptr, size_t size) +{ + return dict_set_bin_common(this, key, ptr, size, _gf_true, + GF_DATA_TYPE_PTR); +} - data = bin_to_data (ptr, size); - if (!data) { - ret = -EINVAL; - goto err; - } +/* */ +int +dict_set_gfuuid(dict_t *this, char *key, uuid_t gfid, bool is_static) +{ + return dict_set_bin_common(this, key, gfid, sizeof(uuid_t), is_static, + GF_DATA_TYPE_GFUUID); +} - data->data = ptr; - data->len = size; - data->is_static = 1; +int +dict_get_gfuuid(dict_t *this, char *key, uuid_t *gfid) +{ + data_t *data = NULL; + int ret = -EINVAL; - ret = dict_set (this, key, data); + if (!gfid) { + goto err; + } + ret = dict_get_with_ref(this, key, &data); + if (ret < 0) { + goto err; + } + + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_GFUUID, key, -EINVAL); + + memcpy(*gfid, data->data, min(data->len, sizeof(uuid_t))); err: - return ret; + if (data) + data_unref(data); + + return ret; +} + +int +dict_set_mdata(dict_t *this, char *key, struct mdata_iatt *mdata, + bool is_static) +{ + return dict_set_bin_common(this, key, mdata, sizeof(struct mdata_iatt), + is_static, GF_DATA_TYPE_MDATA); +} + +int +dict_get_mdata(dict_t *this, char *key, struct mdata_iatt *mdata) +{ + data_t *data = NULL; + int ret = -EINVAL; + + if (!mdata) { + goto err; + } + ret = dict_get_with_ref(this, key, &data); + if (ret < 0) { + goto err; + } + + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_MDATA, key, -EINVAL); + if (data->len < sizeof(struct mdata_iatt)) { + gf_smsg("glusterfs", GF_LOG_ERROR, ENOBUFS, LG_MSG_UNDERSIZED_BUF, + "key=%s", key, NULL); + ret = -ENOBUFS; + goto err; + } + + memcpy(mdata, data->data, min(data->len, sizeof(struct mdata_iatt))); + +err: + if (data) + data_unref(data); + + return ret; +} + +int +dict_set_iatt(dict_t *this, char *key, struct iatt *iatt, bool is_static) +{ + return dict_set_bin_common(this, key, iatt, sizeof(struct iatt), is_static, + GF_DATA_TYPE_IATT); } +int +dict_get_iatt(dict_t *this, char *key, struct iatt *iatt) +{ + data_t *data = NULL; + int ret = -EINVAL; + + if (!iatt) { + goto err; + } + ret = dict_get_with_ref(this, key, &data); + if (ret < 0) { + goto err; + } + + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_IATT, key, -EINVAL); + + memcpy(iatt, data->data, min(data->len, sizeof(struct iatt))); + +err: + if (data) + data_unref(data); + + return ret; +} /** * dict_get_str_boolean - get a boolean value based on string representation. @@ -2267,41 +2806,77 @@ err: */ int -dict_get_str_boolean (dict_t *this, char *key, int default_val) +dict_get_str_boolean(dict_t *this, char *key, int default_val) { - data_t *data = NULL; - gf_boolean_t boo = _gf_false; - int ret = 0; + data_t *data = NULL; + gf_boolean_t boo = _gf_false; + int ret = 0; - ret = dict_get_with_ref (this, key, &data); - if (ret < 0) { - if (ret == -ENOENT) - ret = default_val; - else - ret = -1; - goto err; - } + ret = dict_get_with_ref(this, key, &data); + if (ret < 0) { + if (ret == -ENOENT) + ret = default_val; + else + ret = -1; + goto err; + } - GF_ASSERT (data); + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, key, -EINVAL); - if (!data->data) { - ret = -1; - goto err; - } - - ret = gf_string2boolean (data->data, &boo); - if (ret == -1) - goto err; + ret = gf_strn2boolean(data->data, data->len - 1, &boo); + if (ret == -1) + goto err; - ret = boo; + ret = boo; err: - if (data) - data_unref (data); + if (data) + data_unref(data); - return ret; + return ret; } +int +dict_rename_key(dict_t *this, char *key, char *replace_key) +{ + data_pair_t *pair = NULL; + int ret = -EINVAL; + uint32_t hash; + uint32_t replacekey_hash; + int replacekey_len; + + /* replacing a key by itself is a NO-OP */ + if (strcmp(key, replace_key) == 0) + return 0; + + if (!this) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "dict is NULL"); + return ret; + } + + hash = (uint32_t)XXH64(key, strlen(key), 0); + replacekey_len = strlen(replace_key); + replacekey_hash = (uint32_t)XXH64(replace_key, replacekey_len, 0); + + LOCK(&this->lock); + { + /* no need to data_ref(pair->value), dict_set_lk() does it */ + pair = dict_lookup_common(this, key, hash); + if (!pair) + ret = -ENODATA; + else + ret = dict_set_lk(this, replace_key, replacekey_len, pair->value, + replacekey_hash, 1); + } + UNLOCK(&this->lock); + + if (!ret) + /* only delete the key on success */ + dict_del(this, key); + + return ret; +} /** * Serialization format: @@ -2311,13 +2886,9 @@ err: * 4 4 4 <key len> <value len> */ -#define DICT_HDR_LEN 4 -#define DICT_DATA_HDR_KEY_LEN 4 -#define DICT_DATA_HDR_VAL_LEN 4 - /** - * _dict_serialized_length - return the length of serialized dict. This - * procedure has to be called with this->lock held. + * dict_serialized_length_lk - return the length of serialized dict. This + * procedure has to be called with this->lock held. * * @this : dict to be serialized * @return: success: len @@ -2325,169 +2896,103 @@ err: */ int -_dict_serialized_length (dict_t *this) +dict_serialized_length_lk(dict_t *this) { - int ret = -EINVAL; - int count = 0; - int len = 0; - int i = 0; - data_pair_t * pair = NULL; - - len = DICT_HDR_LEN; - count = this->count; - - if (count < 0) { - gf_log ("dict", GF_LOG_ERROR, "count (%d) < 0!", count); - goto out; - } - - pair = this->members_list; - - while (count) { - if (!pair) { - gf_log ("dict", GF_LOG_ERROR, - "less than count data pairs found!"); - goto out; - } - - len += DICT_DATA_HDR_KEY_LEN + DICT_DATA_HDR_VAL_LEN; - - if (!pair->key) { - gf_log ("dict", GF_LOG_ERROR, "pair->key is null!"); - goto out; - } - - len += strlen (pair->key) + 1 /* for '\0' */; + int ret = -EINVAL; + int count = this->count; + const int keyhdrlen = DICT_DATA_HDR_KEY_LEN + DICT_DATA_HDR_VAL_LEN; - if (!pair->value) { - gf_log ("dict", GF_LOG_ERROR, - "pair->value is null!"); - goto out; - } - - if (pair->value->vec) { - for (i = 0; i < pair->value->len; i++) { - if (pair->value->vec[i].iov_len < 0) { - gf_log ("dict", GF_LOG_ERROR, - "iov_len (%"GF_PRI_SIZET") < 0!", - pair->value->vec[i].iov_len); - goto out; - } + if (count < 0) { + gf_smsg("dict", GF_LOG_ERROR, EINVAL, LG_MSG_COUNT_LESS_THAN_ZERO, + "count=%d", count, NULL); + goto out; + } - len += pair->value->vec[i].iov_len; - } - } else { - if (pair->value->len < 0) { - gf_log ("dict", GF_LOG_ERROR, - "value->len (%d) < 0", - pair->value->len); - goto out; - } - - len += pair->value->len; - } - - pair = pair->next; - count--; - } - - ret = len; + ret = DICT_HDR_LEN + this->totkvlen + (count * keyhdrlen); out: - return ret; + return ret; } /** - * _dict_serialize - serialize a dictionary into a buffer. This procedure has - * to be called with this->lock held. + * dict_serialize_lk - serialize a dictionary into a buffer. This procedure has + * to be called with this->lock held. * * @this: dict to serialize * @buf: buffer to serialize into. This must be - * atleast dict_serialized_length (this) large + * at least dict_serialized_length (this) large * * @return: success: 0 * failure: -errno */ -int -_dict_serialize (dict_t *this, char *buf) -{ - int ret = -1; - data_pair_t * pair = NULL; - int32_t count = 0; - int32_t keylen = 0; - int32_t vallen = 0; - int32_t netword = 0; - - - if (!buf) { - gf_log ("dict", GF_LOG_ERROR, - "buf is null!"); - goto out; +static int +dict_serialize_lk(dict_t *this, char *buf) +{ + int ret = -1; + data_pair_t *pair = this->members_list; + int32_t count = this->count; + int32_t keylen = 0; + int32_t netword = 0; + + if (!buf) { + gf_smsg("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, NULL); + goto out; + } + + if (count < 0) { + gf_smsg("dict", GF_LOG_ERROR, 0, LG_MSG_COUNT_LESS_THAN_ZERO, + "count=%d", count, NULL); + goto out; + } + + netword = hton32(count); + memcpy(buf, &netword, sizeof(netword)); + buf += DICT_HDR_LEN; + + while (count) { + if (!pair) { + gf_smsg("dict", GF_LOG_ERROR, 0, LG_MSG_PAIRS_LESS_THAN_COUNT, + NULL); + goto out; } - - count = this->count; - if (count < 0) { - gf_log ("dict", GF_LOG_ERROR, "count (%d) < 0!", count); - goto out; + if (!pair->key) { + gf_smsg("dict", GF_LOG_ERROR, 0, LG_MSG_NULL_PTR, NULL); + goto out; } - netword = hton32 (count); - memcpy (buf, &netword, sizeof(netword)); - buf += DICT_HDR_LEN; - pair = this->members_list; - - while (count) { - if (!pair) { - gf_log ("dict", GF_LOG_ERROR, - "less than count data pairs found!"); - goto out; - } - - if (!pair->key) { - gf_log ("dict", GF_LOG_ERROR, - "pair->key is null!"); - goto out; - } - - keylen = strlen (pair->key); - netword = hton32 (keylen); - memcpy (buf, &netword, sizeof(netword)); - buf += DICT_DATA_HDR_KEY_LEN; - - if (!pair->value) { - gf_log ("dict", GF_LOG_ERROR, - "pair->value is null!"); - goto out; - } + keylen = strlen(pair->key); + netword = hton32(keylen); + memcpy(buf, &netword, sizeof(netword)); + buf += DICT_DATA_HDR_KEY_LEN; - vallen = pair->value->len; - netword = hton32 (vallen); - memcpy (buf, &netword, sizeof(netword)); - buf += DICT_DATA_HDR_VAL_LEN; + if (!pair->value) { + gf_smsg("dict", GF_LOG_ERROR, 0, LG_MSG_NULL_PTR, NULL); + goto out; + } - memcpy (buf, pair->key, keylen); - buf += keylen; - *buf++ = '\0'; + netword = hton32(pair->value->len); + memcpy(buf, &netword, sizeof(netword)); + buf += DICT_DATA_HDR_VAL_LEN; - if (!pair->value->data) { - gf_log ("dict", GF_LOG_ERROR, - "pair->value->data is null!"); - goto out; - } - memcpy (buf, pair->value->data, vallen); - buf += vallen; + memcpy(buf, pair->key, keylen); + buf += keylen; + *buf++ = '\0'; - pair = pair->next; - count--; + if (pair->value->data) { + memcpy(buf, pair->value->data, pair->value->len); + buf += pair->value->len; } - ret = 0; + pair = pair->next; + count--; + } + + ret = 0; out: - return ret; + return ret; } - /** * dict_serialized_length - return the length of serialized dict * @@ -2497,23 +3002,24 @@ out: */ int -dict_serialized_length (dict_t *this) +dict_serialized_length(dict_t *this) { - int ret = -EINVAL; + int ret = -EINVAL; - if (!this) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "dict is null!"); - goto out; - } + if (!this) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "dict is null!"); + goto out; + } - LOCK (&this->lock); - { - ret = _dict_serialized_length (this); - } - UNLOCK (&this->lock); + LOCK(&this->lock); + { + ret = dict_serialized_length_lk(this); + } + UNLOCK(&this->lock); out: - return ret; + return ret; } /** @@ -2521,32 +3027,32 @@ out: * * @this: dict to serialize * @buf: buffer to serialize into. This must be - * atleast dict_serialized_length (this) large + * at least dict_serialized_length (this) large * * @return: success: 0 * failure: -errno */ int -dict_serialize (dict_t *this, char *buf) +dict_serialize(dict_t *this, char *buf) { - int ret = -1; + int ret = -1; - if (!this || !buf) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "dict is null!"); - goto out; - } + if (!this || !buf) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "dict is null!"); + goto out; + } - LOCK (&this->lock); - { - ret = _dict_serialize (this, buf); - } - UNLOCK (&this->lock); + LOCK(&this->lock); + { + ret = dict_serialize_lk(this, buf); + } + UNLOCK(&this->lock); out: - return ret; + return ret; } - /** * dict_unserialize - unserialize a buffer into a dict * @@ -2559,124 +3065,137 @@ out: */ int32_t -dict_unserialize (char *orig_buf, int32_t size, dict_t **fill) -{ - char *buf = NULL; - int ret = -1; - int32_t count = 0; - int i = 0; - - data_t * value = NULL; - char * key = NULL; - int32_t keylen = 0; - int32_t vallen = 0; - int32_t hostord = 0; - - buf = orig_buf; - - if (!buf) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "buf is null!"); - goto out; - } - - if (size == 0) { - gf_log_callingfn ("dict", GF_LOG_ERROR, - "size is 0!"); - goto out; - } - - if (!fill) { - gf_log_callingfn ("dict", GF_LOG_ERROR, - "fill is null!"); - goto out; - } - - if (!*fill) { - gf_log_callingfn ("dict", GF_LOG_ERROR, - "*fill is null!"); - goto out; - } - - if ((buf + DICT_HDR_LEN) > (orig_buf + size)) { - gf_log_callingfn ("dict", GF_LOG_ERROR, - "undersized buffer passed. " - "available (%lu) < required (%lu)", - (long)(orig_buf + size), - (long)(buf + DICT_HDR_LEN)); - goto out; - } +dict_unserialize(char *orig_buf, int32_t size, dict_t **fill) +{ + char *buf = orig_buf; + int ret = -1; + int32_t count = 0; + int i = 0; + + data_t *value = NULL; + char *key = NULL; + int32_t keylen = 0; + int32_t vallen = 0; + int32_t hostord = 0; + + if (!buf) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "buf is null!"); + goto out; + } + + if (size == 0) { + gf_msg_callingfn("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "size is 0!"); + goto out; + } + + if (!fill) { + gf_msg_callingfn("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "fill is null!"); + goto out; + } + + if (!*fill) { + gf_msg_callingfn("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "*fill is null!"); + goto out; + } + + if ((buf + DICT_HDR_LEN) > (orig_buf + size)) { + gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF, + "undersized buffer " + "passed. available (%lu) < required (%lu)", + (long)(orig_buf + size), (long)(buf + DICT_HDR_LEN)); + goto out; + } + + memcpy(&hostord, buf, sizeof(hostord)); + count = ntoh32(hostord); + buf += DICT_HDR_LEN; + + if (count < 0) { + gf_smsg("dict", GF_LOG_ERROR, 0, LG_MSG_COUNT_LESS_THAN_ZERO, + "count=%d", count, NULL); + goto out; + } + + /* count will be set by the dict_set's below */ + (*fill)->count = 0; + + for (i = 0; i < count; i++) { + if ((buf + DICT_DATA_HDR_KEY_LEN) > (orig_buf + size)) { + gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF, + "undersized " + "buffer passed. available (%lu) < " + "required (%lu)", + (long)(orig_buf + size), + (long)(buf + DICT_DATA_HDR_KEY_LEN)); + goto out; + } + memcpy(&hostord, buf, sizeof(hostord)); + keylen = ntoh32(hostord); + buf += DICT_DATA_HDR_KEY_LEN; + + if ((buf + DICT_DATA_HDR_VAL_LEN) > (orig_buf + size)) { + gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF, + "undersized " + "buffer passed. available (%lu) < " + "required (%lu)", + (long)(orig_buf + size), + (long)(buf + DICT_DATA_HDR_VAL_LEN)); + goto out; + } + memcpy(&hostord, buf, sizeof(hostord)); + vallen = ntoh32(hostord); + buf += DICT_DATA_HDR_VAL_LEN; + + if ((keylen < 0) || (vallen < 0)) { + gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF, + "undersized length passed " + "key:%d val:%d", + keylen, vallen); + goto out; + } + if ((buf + keylen) > (orig_buf + size)) { + gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF, + "undersized buffer passed. " + "available (%lu) < required (%lu)", + (long)(orig_buf + size), (long)(buf + keylen)); + goto out; + } + key = buf; + buf += keylen + 1; /* for '\0' */ + + if ((buf + vallen) > (orig_buf + size)) { + gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF, + "undersized buffer passed. " + "available (%lu) < required (%lu)", + (long)(orig_buf + size), (long)(buf + vallen)); + goto out; + } + value = get_new_data(); - memcpy (&hostord, buf, sizeof(hostord)); - count = ntoh32 (hostord); - buf += DICT_HDR_LEN; - - if (count < 0) { - gf_log ("dict", GF_LOG_ERROR, - "count (%d) <= 0", count); - goto out; + if (!value) { + ret = -1; + goto out; } + value->len = vallen; + value->data = gf_memdup(buf, vallen); + value->data_type = GF_DATA_TYPE_STR_OLD; + value->is_static = _gf_false; + buf += vallen; - /* count will be set by the dict_set's below */ - (*fill)->count = 0; - - for (i = 0; i < count; i++) { - if ((buf + DICT_DATA_HDR_KEY_LEN) > (orig_buf + size)) { - gf_log_callingfn ("dict", GF_LOG_ERROR, - "undersized buffer passed. " - "available (%lu) < required (%lu)", - (long)(orig_buf + size), - (long)(buf + DICT_DATA_HDR_KEY_LEN)); - goto out; - } - memcpy (&hostord, buf, sizeof(hostord)); - keylen = ntoh32 (hostord); - buf += DICT_DATA_HDR_KEY_LEN; - - if ((buf + DICT_DATA_HDR_VAL_LEN) > (orig_buf + size)) { - gf_log_callingfn ("dict", GF_LOG_ERROR, - "undersized buffer passed. " - "available (%lu) < required (%lu)", - (long)(orig_buf + size), - (long)(buf + DICT_DATA_HDR_VAL_LEN)); - goto out; - } - memcpy (&hostord, buf, sizeof(hostord)); - vallen = ntoh32 (hostord); - buf += DICT_DATA_HDR_VAL_LEN; - - if ((buf + keylen) > (orig_buf + size)) { - gf_log_callingfn ("dict", GF_LOG_ERROR, - "undersized buffer passed. " - "available (%lu) < required (%lu)", - (long)(orig_buf + size), - (long)(buf + keylen)); - goto out; - } - key = buf; - buf += keylen + 1; /* for '\0' */ - - if ((buf + vallen) > (orig_buf + size)) { - gf_log_callingfn ("dict", GF_LOG_ERROR, - "undersized buffer passed. " - "available (%lu) < required (%lu)", - (long)(orig_buf + size), - (long)(buf + vallen)); - } - value = get_new_data (); - value->len = vallen; - value->data = memdup (buf, vallen); - value->is_static = 0; - buf += vallen; + ret = dict_addn(*fill, key, keylen, value); + if (ret < 0) + goto out; + } - dict_set (*fill, key, value); - } - - ret = 0; + ret = 0; out: - return ret; + return ret; } - /** * dict_allocate_and_serialize - serialize a dictionary into an allocated buffer * @@ -2689,50 +3208,49 @@ out: */ int32_t -dict_allocate_and_serialize (dict_t *this, char **buf, size_t *length) +dict_allocate_and_serialize(dict_t *this, char **buf, u_int *length) { - int ret = -EINVAL; - ssize_t len = 0; + int ret = -EINVAL; + ssize_t len = 0; - if (!this || !buf) { - gf_log_callingfn ("dict", GF_LOG_DEBUG, - "dict OR buf is NULL"); - goto out; - } + if (!this || !buf) { + gf_msg_debug("dict", 0, "dict OR buf is NULL"); + goto out; + } - LOCK (&this->lock); - { - len = _dict_serialized_length (this); - if (len < 0) { - ret = len; - goto unlock; - } + LOCK(&this->lock); + { + len = dict_serialized_length_lk(this); + if (len < 0) { + ret = len; + goto unlock; + } - *buf = GF_CALLOC (1, len, gf_common_mt_char); - if (*buf == NULL) { - ret = -ENOMEM; - goto unlock; - } + *buf = GF_MALLOC(len, gf_common_mt_char); + if (*buf == NULL) { + ret = -ENOMEM; + goto unlock; + } - ret = _dict_serialize (this, *buf); - if (ret < 0) { - GF_FREE (*buf); - *buf = NULL; - goto unlock; - } + ret = dict_serialize_lk(this, *buf); + if (ret < 0) { + GF_FREE(*buf); + *buf = NULL; + goto unlock; + } - if (length != NULL) { - *length = len; - } + if (length != NULL) { + *length = len; } + } unlock: - UNLOCK (&this->lock); + UNLOCK(&this->lock); out: - return ret; + return ret; } /** - * _dict_serialize_value_with_delim: serialize the values in the dictionary + * dict_serialize_value_with_delim_lk: serialize the values in the dictionary * into a buffer separated by delimiter (except the last) * * @this : dictionary to serialize @@ -2741,88 +3259,231 @@ out: * @delimiter : the delimiter to separate the values * * @return : 0 -> success - * : -errno -> faliure + * : -errno -> failure */ int -_dict_serialize_value_with_delim (dict_t *this, char *buf, int32_t *serz_len, - char delimiter) -{ - int ret = -1; - int32_t count = 0; - int32_t vallen = 0; - int32_t total_len = 0; - data_pair_t *pair = NULL; - - if (!buf) { - gf_log ("dict", GF_LOG_ERROR, "buf is null"); - goto out; +dict_serialize_value_with_delim_lk(dict_t *this, char *buf, int32_t *serz_len, + char delimiter) +{ + int ret = -1; + int32_t count = this->count; + int32_t vallen = 0; + int32_t total_len = 0; + data_pair_t *pair = this->members_list; + + if (!buf) { + gf_smsg("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, NULL); + goto out; + } + + if (count < 0) { + gf_smsg("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, "count=%d", + count, NULL); + goto out; + } + + while (count) { + if (!pair) { + gf_smsg("dict", GF_LOG_ERROR, 0, LG_MSG_PAIRS_LESS_THAN_COUNT, + NULL); + goto out; } - count = this->count; - if (count < 0) { - gf_log ("dict", GF_LOG_ERROR, "count (%d) < 0", count); - goto out; + if (!pair->key || !pair->value) { + gf_smsg("dict", GF_LOG_ERROR, 0, LG_MSG_KEY_OR_VALUE_NULL, NULL); + goto out; } - pair = this->members_list; + if (!pair->value->data) { + gf_smsg("dict", GF_LOG_ERROR, 0, LG_MSG_NULL_VALUE_IN_DICT, NULL); + goto out; + } - while (count) { - if (!pair) { - gf_log ("dict", GF_LOG_ERROR, - "less than count data pairs found"); - goto out; - } + vallen = pair->value->len - 1; // length includes \0 + memcpy(buf, pair->value->data, vallen); + buf += vallen; + *buf++ = delimiter; - if (!pair->key || !pair->value) { - gf_log ("dict", GF_LOG_ERROR, - "key or value is null"); - goto out; - } + total_len += (vallen + 1); - if (!pair->value->data) { - gf_log ("dict", GF_LOG_ERROR, - "null value found in dict"); - goto out; - } + pair = pair->next; + count--; + } - vallen = pair->value->len - 1; // length includes \0 - memcpy (buf, pair->value->data, vallen); - buf += vallen; - *buf++ = delimiter; + *--buf = '\0'; // remove the last delimiter + total_len--; // adjust the length + ret = 0; - total_len += (vallen + 1); + if (serz_len) + *serz_len = total_len; - pair = pair->next; - count--; - } +out: + return ret; +} - *--buf = '\0'; // remove the last delimiter - total_len--; // adjust the length - ret = 0; +int +dict_serialize_value_with_delim(dict_t *this, char *buf, int32_t *serz_len, + char delimiter) +{ + int ret = -1; + + if (!this || !buf) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "dict is null!"); + goto out; + } + + LOCK(&this->lock); + { + ret = dict_serialize_value_with_delim_lk(this, buf, serz_len, + delimiter); + } + UNLOCK(&this->lock); +out: + return ret; +} - if (serz_len) - *serz_len = total_len; +int +dict_dump_to_str(dict_t *dict, char *dump, int dumpsize, char *format) +{ + int ret = 0; + int dumplen = 0; + data_pair_t *trav = NULL; - out: - return ret; + if (!dict) + return 0; + + for (trav = dict->members_list; trav; trav = trav->next) { + ret = snprintf(&dump[dumplen], dumpsize - dumplen, format, trav->key, + trav->value->data); + if ((ret == -1) || !ret) + return ret; + + dumplen += ret; + } + return 0; } +void +dict_dump_to_log(dict_t *dict) +{ + int ret = -1; + char *dump = NULL; + const int dump_size = 64 * 1024; + char *format = "(%s:%s)"; + + if (!dict) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "dict is NULL"); + goto out; + } + + dump = GF_MALLOC(dump_size, gf_common_mt_char); + if (!dump) { + gf_msg_callingfn("dict", GF_LOG_WARNING, ENOMEM, LG_MSG_NO_MEMORY, + "dump buffer is NULL"); + goto out; + } + + ret = dict_dump_to_str(dict, dump, dump_size, format); + if (ret) { + gf_smsg("dict", GF_LOG_WARNING, 0, LG_MSG_FAILED_TO_LOG_DICT, NULL); + goto out; + } + gf_smsg("dict", GF_LOG_INFO, 0, LG_MSG_DICT_ERROR, "dict=%p", dict, + "dump=%s", dump, NULL); +out: + GF_FREE(dump); + + return; +} + +void +dict_dump_to_statedump(dict_t *dict, char *dict_name, char *domain) +{ + int ret = -1; + char *dump = NULL; + const int dump_size = 64 * 1024; + char key[4096] = { + 0, + }; + char *format = "\n\t%s:%s"; + + if (!dict) { + gf_msg_callingfn(domain, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "dict is NULL"); + goto out; + } + + dump = GF_MALLOC(dump_size, gf_common_mt_char); + if (!dump) { + gf_msg_callingfn(domain, GF_LOG_WARNING, ENOMEM, LG_MSG_NO_MEMORY, + "dump buffer is NULL"); + goto out; + } + + ret = dict_dump_to_str(dict, dump, dump_size, format); + if (ret) { + gf_smsg(domain, GF_LOG_WARNING, 0, LG_MSG_FAILED_TO_LOG_DICT, "name=%s", + dict_name, NULL); + goto out; + } + gf_proc_dump_build_key(key, domain, "%s", dict_name); + gf_proc_dump_write(key, "%s", dump); + +out: + GF_FREE(dump); + + return; +} + +dict_t * +dict_for_key_value(const char *name, const char *value, size_t size, + gf_boolean_t is_static) +{ + dict_t *xattr = dict_new(); + int ret = 0; + + if (!xattr) + return NULL; + + if (is_static) + ret = dict_set_static_bin(xattr, (char *)name, (void *)value, size); + else + ret = dict_set_bin(xattr, (char *)name, (void *)value, size); + + if (ret) { + dict_destroy(xattr); + xattr = NULL; + } + + return xattr; +} + +/* + * "strings" should be NULL terminated strings array. + */ int -dict_serialize_value_with_delim (dict_t *this, char *buf, int32_t *serz_len, - char delimiter) +dict_has_key_from_array(dict_t *dict, char **strings, gf_boolean_t *result) { - int ret = -1; + int i = 0; + uint32_t hash = 0; - if (!this || !buf) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "dict is null!"); - goto out; - } + if (!dict || !strings || !result) + return -EINVAL; - LOCK (&this->lock); - { - ret = _dict_serialize_value_with_delim (this, buf, serz_len, delimiter); + LOCK(&dict->lock); + { + for (i = 0; strings[i]; i++) { + hash = (uint32_t)XXH64(strings[i], strlen(strings[i]), 0); + if (dict_lookup_common(dict, strings[i], hash)) { + *result = _gf_true; + goto unlock; + } } - UNLOCK (&this->lock); -out: - return ret; + *result = _gf_false; + } +unlock: + UNLOCK(&dict->lock); + return 0; } |
