diff options
Diffstat (limited to 'libglusterfs/src/dict.c')
| -rw-r--r-- | libglusterfs/src/dict.c | 612 |
1 files changed, 252 insertions, 360 deletions
diff --git a/libglusterfs/src/dict.c b/libglusterfs/src/dict.c index ed89f236a..3b7ddce5e 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,6 +14,7 @@ #include <stdio.h> #include <inttypes.h> #include <limits.h> +#include <fnmatch.h> #ifndef _CONFIG_H #define _CONFIG_H @@ -38,16 +30,6 @@ #include "byte-order.h" #include "globals.h" -data_pair_t * -get_new_data_pair () -{ - data_pair_t *data_pair_ptr = NULL; - - data_pair_ptr = mem_get0 (THIS->ctx->dict_pair_pool); - - return data_pair_ptr; -} - data_t * get_new_data () { @@ -72,11 +54,32 @@ get_new_dict_full (int size_hint) } dict->hash_size = size_hint; - dict->members = mem_get0 (THIS->ctx->dict_pair_pool); - - if (!dict->members) { - mem_put (dict); - return NULL; + 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) { + mem_put (dict); + return NULL; + } } LOCK_INIT (&dict->lock); @@ -143,8 +146,6 @@ data_destroy (data_t *data) else GF_FREE (data->data); } - if (data->vec) - GF_FREE (data->vec); } data->len = 0xbabababa; @@ -174,12 +175,6 @@ data_copy (data_t *old) 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); @@ -187,10 +182,7 @@ data_copy (data_t *old) err_out: - if (newdata->data) - FREE (newdata->data); - if (newdata->vec) - FREE (newdata->vec); + FREE (newdata->data); mem_put (newdata); return NULL; @@ -217,7 +209,7 @@ _dict_lookup (dict_t *this, char *key) } 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, @@ -225,22 +217,22 @@ dict_lookup (dict_t *this, char *key, data_pair_t **data) return -1; } + data_pair_t *tmp = NULL; LOCK (&this->lock); { - *data = _dict_lookup (this, key); + tmp = _dict_lookup (this, key); } UNLOCK (&this->lock); - if (*data) - return 0; - else + + if (!tmp) return -1; + *data = tmp->value; + return 0; } static int32_t -_dict_set (dict_t *this, - char *key, - data_t *value) +_dict_set (dict_t *this, char *key, data_t *value, gf_boolean_t replace) { int hashval; data_pair_t *pair; @@ -259,33 +251,54 @@ _dict_set (dict_t *this, tmp = SuperFastHash (key, strlen (key)); hashval = (tmp % this->hash_size); - pair = _dict_lookup (this, key); - 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 = mem_get0 (THIS->ctx->dict_pair_pool); - if (!pair) { - return -1; - } + /* Search for a existing key if 'replace' is asked for */ + if (replace) { + pair = _dict_lookup (this, key); - pair->key = (char *) GF_CALLOC (1, strlen (key) + 1, - gf_common_mt_char); - if (!pair->key) { - mem_put (pair); + 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; + } + } - if (key_free) - GF_FREE (key); - return -1; + if (this->free_pair_in_use) { + pair = mem_get0 (THIS->ctx->dict_pair_pool); + if (!pair) { + if (key_free) + GF_FREE (key); + return -1; + } + } + else { + pair = &this->free_pair; + this->free_pair_in_use = _gf_true; } - strcpy (pair->key, key); + if (key_free) { + /* It's ours. Use it. */ + pair->key = key; + key_free = 0; + } + else { + pair->key = (char *) GF_CALLOC (1, strlen (key) + 1, + gf_common_mt_char); + if (!pair->key) { + if (pair == &this->free_pair) { + this->free_pair_in_use = _gf_false; + } + else { + mem_put (pair); + } + return -1; + } + strcpy (pair->key, key); + } pair->value = data_ref (value); pair->hash_next = this->members[hashval]; @@ -318,7 +331,28 @@ dict_set (dict_t *this, LOCK (&this->lock); - ret = _dict_set (this, key, value); + ret = _dict_set (this, key, value, 1); + + UNLOCK (&this->lock); + + return ret; +} + + +int32_t +dict_add (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, 0); UNLOCK (&this->lock); @@ -382,7 +416,12 @@ dict_del (dict_t *this, char *key) pair->next->prev = pair->prev; GF_FREE (pair->key); - mem_put (pair); + if (pair == &this->free_pair) { + this->free_pair_in_use = _gf_false; + } + else { + mem_put (pair); + } this->count--; break; } @@ -413,16 +452,18 @@ dict_destroy (dict_t *this) pair = pair->next; data_unref (prev->value); GF_FREE (prev->key); - mem_put (prev); + if (prev != &this->free_pair) { + mem_put (prev); + } prev = pair; } - mem_put (this->members); + if (this->members != &this->members_internal) { + mem_put (this->members); + } - if (this->extra_free) - GF_FREE (this->extra_free); - if (this->extra_stdfree) - free (this->extra_stdfree); + GF_FREE (this->extra_free); + free (this->extra_stdfree); if (!this->is_static) mem_put (this); @@ -506,236 +547,6 @@ data_ref (data_t *this) return this; } -/* - Serialization format: - ---- - Count:8 - Key_len:8:Value_len:8 - Key - Value - . - . - . -*/ - -int32_t -dict_serialized_length_old (dict_t *this) -{ - - if (!this) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "dict is NULL"); - return -1; - } - - 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--; - } - - return len; -} - -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; - } - - 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); -} - - -dict_t * -dict_unserialize_old (char *buf, int32_t size, dict_t **fill) -{ - int32_t ret = 0; - int32_t cnt = 0; - - if (!buf || !fill || !(*fill)) { - gf_log_callingfn ("dict", GF_LOG_WARNING, "buf is NULL"); - return NULL; - } - - uint64_t count; - ret = sscanf (buf, "%"SCNx64"\n", &count); - (*fill)->count = 0; - - if (!ret){ - gf_log ("dict", GF_LOG_ERROR, "sscanf on buf failed"); - goto err; - } - buf += 9; - - if (count == 0) { - gf_log ("dict", GF_LOG_ERROR, "count == 0"); - goto err; - } - - 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; - - key = buf; - buf += key_len; - - value = get_new_data (); - value->len = value_len; - value->data = buf; - value->is_static = 1; - buf += value_len; - - dict_set (*fill, key, value); - } - - goto ret; - -err: - GF_FREE (*fill); - *fill = NULL; - -ret: - return *fill; -} - - -int32_t -dict_iovec_len (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; - - len++; /* initial header */ - while (pair) { - len++; /* pair header */ - len++; /* key */ - - if (pair->value->vec) - len += pair->value->len; - else - len++; - pair = pair->next; - } - - return len; -} - -int32_t -dict_to_iovec (dict_t *this, - struct iovec *vec, - int32_t count) -{ - 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 (pair->value->vec) { - int i; - - for (i=0; i<pair->value->len; i++) { - vallen += pair->value->vec[i].iov_len; - } - } else { - vallen = pair->value->len; - } - - 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++; - } - - pair = pair->next; - } - - return 0; -} - data_t * int_to_data (int64_t value) { @@ -1085,7 +896,7 @@ data_to_int32 (data_t *data) int16_t data_to_int16 (data_t *data) { - int16_t value = 0; + int16_t value = 0; if (!data) { gf_log_callingfn ("dict", GF_LOG_WARNING, "data is NULL"); @@ -1099,16 +910,16 @@ data_to_int16 (data_t *data) memcpy (str, data->data, data->len); str[data->len] = '\0'; - errno = 0; - value = strtol (str, NULL, 0); + errno = 0; + value = strtol (str, NULL, 0); - if ((SHRT_MAX > value) || (SHRT_MIN < value)) { - errno = ERANGE; + if ((value > SHRT_MAX) || (value < SHRT_MIN)) { + errno = ERANGE; gf_log_callingfn ("dict", GF_LOG_WARNING, - "Error in data conversion: " - "detected overflow"); + "Error in data conversion: " + "detected overflow"); return -1; - } + } return (int16_t)value; } @@ -1117,7 +928,7 @@ data_to_int16 (data_t *data) int8_t data_to_int8 (data_t *data) { - int32_t value = 0; + int8_t value = 0; if (!data) { gf_log_callingfn ("dict", GF_LOG_WARNING, "data is NULL"); @@ -1131,16 +942,16 @@ data_to_int8 (data_t *data) memcpy (str, data->data, data->len); str[data->len] = '\0'; - errno = 0; - value = strtol (str, NULL, 0); + errno = 0; + value = strtol (str, NULL, 0); - if ((SCHAR_MAX > value) || (SCHAR_MIN < value)) { - errno = ERANGE; + if ((value > SCHAR_MAX) || (value < SCHAR_MIN)) { + errno = ERANGE; gf_log_callingfn ("dict", GF_LOG_WARNING, - "Error in data conversion: " - "detected overflow"); + "Error in data conversion: " + "detected overflow"); return -1; - } + } return (int8_t)value; } @@ -1267,47 +1078,141 @@ data_to_bin (data_t *data) return data->data; } -void +int +dict_null_foreach_fn (dict_t *d, char *k, + data_t *v, void *tmp) +{ + return 0; +} + +int dict_foreach (dict_t *dict, - void (*fn)(dict_t *this, - char *key, - data_t *value, - void *data), + int (*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; + return -1; } - data_pair_t *pairs = dict->members_list; - data_pair_t *next = NULL; + int ret = -1; + data_pair_t *pairs = NULL; + data_pair_t *next = NULL; + pairs = dict->members_list; while (pairs) { next = pairs->next; - fn (dict, pairs->key, pairs->value, data); + ret = fn (dict, pairs->key, pairs->value, data); + if (ret == -1) + return -1; pairs = next; } + + return 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 (!dict) { + gf_log_callingfn ("dict", GF_LOG_WARNING, + "dict is NULL"); + return 0; + } -static void + int ret = -1; + int count = 0; + data_pair_t *pairs = NULL; + data_pair_t *next = NULL; + + pairs = dict->members_list; + while (pairs) { + next = pairs->next; + if (!fnmatch (pattern, pairs->key, 0)) { + ret = fn (dict, pairs->key, pairs->value, data); + if (ret == -1) + return -1; + count++; + } + pairs = next; + } + + return count; +} + + +/** + * 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. + * + */ + +int +dict_keys_join (void *value, int size, dict_t *dict, + int (*filter_fn)(char *k)) +{ + int len = 0; + data_pair_t *pairs = NULL; + data_pair_t *next = NULL; + + pairs = dict->members_list; + while (pairs) { + next = pairs->next; + + if (filter_fn && filter_fn (pairs->key)){ + pairs = next; + continue; + } + + if (value && (size > len)) + strncpy (value + len, pairs->key, size - len); + + len += (strlen (pairs->key) + 1); + + pairs = next; + } + + return len; +} + +static int _copy (dict_t *unused, char *key, data_t *value, void *newdict) { - dict_set ((dict_t *)newdict, key, (value)); + return dict_set ((dict_t *)newdict, key, (value)); } -static void +static int _remove (dict_t *dict, char *key, data_t *value, void *unused) { dict_del ((dict_t *)dict, key); + return 0; } @@ -2354,7 +2259,6 @@ _dict_serialized_length (dict_t *this) int ret = -EINVAL; int count = 0; int len = 0; - int i = 0; data_pair_t * pair = NULL; len = DICT_HDR_LEN; @@ -2389,28 +2293,15 @@ _dict_serialized_length (dict_t *this) 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; - } - - 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; + 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--; } @@ -2685,6 +2576,7 @@ dict_unserialize (char *orig_buf, int32_t size, dict_t **fill) "available (%lu) < required (%lu)", (long)(orig_buf + size), (long)(buf + vallen)); + goto out; } value = get_new_data (); value->len = vallen; @@ -2692,7 +2584,7 @@ dict_unserialize (char *orig_buf, int32_t size, dict_t **fill) value->is_static = 0; buf += vallen; - dict_set (*fill, key, value); + dict_add (*fill, key, value); } ret = 0; @@ -2713,7 +2605,7 @@ 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; |
