summaryrefslogtreecommitdiffstats
path: root/libglusterfs/src/dict.c
diff options
context:
space:
mode:
authorSanoj Unnikrishnan <sunnikri@redhat.com>2018-02-23 15:26:20 +0530
committerRaghavendra G <rgowdapp@redhat.com>2018-03-28 04:07:12 +0000
commit04ede2e1635d664ea18e266544bffc569ae69bb8 (patch)
tree32a8846a0614421f40c22ddc9af88c638a2cb2bb /libglusterfs/src/dict.c
parent7d95a6ff7182e67be8a49f59dbedb892da4a6ae8 (diff)
Quota: heal directory on newly added bricks when quota limit is reached
Problem: if a lookup is done on a newly added brick for a path on which limit has been reached, the lookup fails to heal the directory tree due to quota. Solution: Tag the lookup as an internal fop and ignore it in quota. Since marking internal fop does not usually give enough contextual information. Introducing new flags to pass the contextual info. Adding dict_check_flag and dict_set_flag to aid flag operations. A flag is a single bit in a bit array (currently limited to 256 bits). Change-Id: Ifb6a68bcaffedd425dd0f01f7db24edd5394c095 fixes: bz#1505355 BUG: 1505355 Signed-off-by: Sanoj Unnikrishnan <sunnikri@redhat.com>
Diffstat (limited to 'libglusterfs/src/dict.c')
-rw-r--r--libglusterfs/src/dict.c190
1 files changed, 190 insertions, 0 deletions
diff --git a/libglusterfs/src/dict.c b/libglusterfs/src/dict.c
index d1a64c4a3a2..0f9632160cc 100644
--- a/libglusterfs/src/dict.c
+++ b/libglusterfs/src/dict.c
@@ -2022,6 +2022,196 @@ err:
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_check_flag (dict_t *this, char *key, int flag)
+{
+ 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;
+
+ 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;
+ uint32_t hash = 0;
+ data_pair_t *pair = NULL;
+ char *ptr = NULL;
+ int hashval = 0;
+
+ 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 = SuperFastHash (key, strlen (key));
+ 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);
+ ret = 0;
+ } else {
+ ptr = GF_CALLOC(1, DICT_MAX_FLAGS / 8,
+ gf_common_mt_char);
+ if (!ptr) {
+ gf_msg("dict", GF_LOG_ERROR, ENOMEM,
+ LG_MSG_NO_MEMORY,
+ "unable to allocate flag bit array");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ data = data_from_dynptr(ptr, DICT_MAX_FLAGS / 8);
+
+ if (!data) {
+ gf_msg("dict", GF_LOG_ERROR, ENOMEM,
+ LG_MSG_NO_MEMORY,
+ "unable to allocate data");
+ GF_FREE(ptr);
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ if (op == DICT_FLAG_SET)
+ BIT_SET((unsigned char *)(data->data), flag);
+ else
+ BIT_CLEAR((unsigned char *)(data->data), flag);
+
+ if (this->free_pair_in_use) {
+ pair = mem_get0 (THIS->ctx->dict_pair_pool);
+ if (!pair) {
+ gf_msg("dict", GF_LOG_ERROR, ENOMEM,
+ LG_MSG_NO_MEMORY,
+ "unable to allocate dict pair");
+ ret = -ENOMEM;
+ goto err;
+ }
+ } else {
+ pair = &this->free_pair;
+ this->free_pair_in_use = _gf_true;
+ }
+
+ pair->key = (char *)GF_CALLOC(1, strlen (key) + 1,
+ gf_common_mt_char);
+ if (!pair->key) {
+ gf_msg("dict", GF_LOG_ERROR, ENOMEM,
+ LG_MSG_NO_MEMORY,
+ "unable to allocate dict pair");
+ ret = -ENOMEM;
+ goto err;
+ }
+ strcpy (pair->key, key);
+ pair->key_hash = hash;
+ pair->value = data_ref (data);
+
+ 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;
+ }
+ }
+
+ UNLOCK (&this->lock);
+ return 0;
+
+err:
+ UNLOCK (&this->lock);
+ if (pair) {
+ if (pair->key)
+ free(pair->key);
+
+ if (pair == &this->free_pair) {
+ this->free_pair_in_use = _gf_false;
+ } else {
+ mem_put (pair);
+ }
+ }
+
+ if (data)
+ data_destroy(data);
+
+
+ gf_msg("dict", GF_LOG_ERROR, EINVAL,
+ LG_MSG_DICT_SET_FAILED,
+ "unable to set key (%s) in dict ", key);
+
+ 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_flag (dict_t *this, char *key, int flag)
+{
+ return _dict_modify_flag (this, key, flag, DICT_FLAG_SET);
+}
+
+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)
{