summaryrefslogtreecommitdiff
path: root/0149-glusterd-Optimize-code-to-copy-dictionary-in-handsha.patch
diff options
context:
space:
mode:
Diffstat (limited to '0149-glusterd-Optimize-code-to-copy-dictionary-in-handsha.patch')
-rw-r--r--0149-glusterd-Optimize-code-to-copy-dictionary-in-handsha.patch452
1 files changed, 452 insertions, 0 deletions
diff --git a/0149-glusterd-Optimize-code-to-copy-dictionary-in-handsha.patch b/0149-glusterd-Optimize-code-to-copy-dictionary-in-handsha.patch
new file mode 100644
index 0000000..5caf3d4
--- /dev/null
+++ b/0149-glusterd-Optimize-code-to-copy-dictionary-in-handsha.patch
@@ -0,0 +1,452 @@
+From 86eee7e829bb33cac9b611da511ecbd2f03fab25 Mon Sep 17 00:00:00 2001
+From: Mohit Agrawal <moagrawal@redhat.com>
+Date: Fri, 17 May 2019 19:26:48 +0530
+Subject: [PATCH 149/169] glusterd: Optimize code to copy dictionary in
+ handshake code path
+
+Problem: While high no. of volumes are configured around 2000
+ glusterd has bottleneck during handshake at the time
+ of copying dictionary
+
+Solution: To avoid the bottleneck serialize a dictionary instead
+ of copying key-value pair one by one
+
+> Change-Id: I9fb332f432e4f915bc3af8dcab38bed26bda2b9a
+> fixes: bz#1711297
+> Cherry picked from commit f8f09178bb890924a8050b466cc2e7a0a30e35a7
+> (Reviewed on upstream link https://review.gluster.org/#/c/glusterfs/+/22742/)
+
+BUG: 1711296
+Change-Id: I9fb332f432e4f915bc3af8dcab38bed26bda2b9a
+Signed-off-by: Mohit Agrawal <moagrawal@redhat.com>
+Reviewed-on: https://code.engineering.redhat.com/gerrit/172255
+Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
+Tested-by: RHGS Build Bot <nigelb@redhat.com>
+---
+ libglusterfs/src/dict.c | 6 +-
+ libglusterfs/src/glusterfs/dict.h | 6 +
+ libglusterfs/src/libglusterfs.sym | 1 +
+ xlators/mgmt/glusterd/src/glusterd-rpc-ops.c | 27 ++--
+ xlators/mgmt/glusterd/src/glusterd-utils.c | 187 +++++++++++++++++++++++----
+ xlators/mgmt/glusterd/src/glusterd-utils.h | 3 +-
+ xlators/mgmt/glusterd/src/glusterd.h | 5 +
+ 7 files changed, 194 insertions(+), 41 deletions(-)
+
+diff --git a/libglusterfs/src/dict.c b/libglusterfs/src/dict.c
+index 4cd1fcf..6917df9 100644
+--- a/libglusterfs/src/dict.c
++++ b/libglusterfs/src/dict.c
+@@ -2799,10 +2799,6 @@ dict_rename_key(dict_t *this, char *key, char *replace_key)
+ * 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_lk - return the length of serialized dict. This
+ * procedure has to be called with this->lock held.
+@@ -2812,7 +2808,7 @@ dict_rename_key(dict_t *this, char *key, char *replace_key)
+ * : failure: -errno
+ */
+
+-static int
++int
+ dict_serialized_length_lk(dict_t *this)
+ {
+ int ret = -EINVAL;
+diff --git a/libglusterfs/src/glusterfs/dict.h b/libglusterfs/src/glusterfs/dict.h
+index 52b833f..022f564 100644
+--- a/libglusterfs/src/glusterfs/dict.h
++++ b/libglusterfs/src/glusterfs/dict.h
+@@ -91,6 +91,9 @@ typedef struct _data_pair data_pair_t;
+ #define DICT_MAX_FLAGS 256
+ #define DICT_FLAG_SET 1
+ #define DICT_FLAG_CLEAR 0
++#define DICT_HDR_LEN 4
++#define DICT_DATA_HDR_KEY_LEN 4
++#define DICT_DATA_HDR_VAL_LEN 4
+
+ struct _data {
+ char *data;
+@@ -412,4 +415,7 @@ are_dicts_equal(dict_t *one, dict_t *two,
+ gf_boolean_t (*value_ignore)(char *k));
+ int
+ dict_has_key_from_array(dict_t *dict, char **strings, gf_boolean_t *result);
++
++int
++dict_serialized_length_lk(dict_t *this);
+ #endif
+diff --git a/libglusterfs/src/libglusterfs.sym b/libglusterfs/src/libglusterfs.sym
+index cf5757c..ec474e7 100644
+--- a/libglusterfs/src/libglusterfs.sym
++++ b/libglusterfs/src/libglusterfs.sym
+@@ -405,6 +405,7 @@ dict_rename_key
+ dict_reset
+ dict_serialize
+ dict_serialized_length
++dict_serialized_length_lk
+ dict_serialize_value_with_delim
+ dict_set
+ dict_setn
+diff --git a/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c b/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c
+index 4ec9700..45f8f17 100644
+--- a/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c
++++ b/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c
+@@ -1528,11 +1528,9 @@ glusterd_rpc_friend_add(call_frame_t *frame, xlator_t *this, void *data)
+
+ RCU_READ_UNLOCK;
+
+- ret = glusterd_add_volumes_to_export_dict(&peer_data);
+- if (ret) {
+- gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
+- "Unable to add list of volumes "
+- "in the peer_data dict for handshake");
++ peer_data = dict_new();
++ if (!peer_data) {
++ errno = ENOMEM;
+ goto out;
+ }
+
+@@ -1563,10 +1561,23 @@ glusterd_rpc_friend_add(call_frame_t *frame, xlator_t *this, void *data)
+ }
+ }
+
+- ret = dict_allocate_and_serialize(peer_data, &req.vols.vols_val,
+- &req.vols.vols_len);
+- if (ret)
++ /* Don't add any key-value in peer_data dictionary after call this function
++ */
++ ret = glusterd_add_volumes_to_export_dict(peer_data, &req.vols.vols_val,
++ &req.vols.vols_len);
++ if (ret) {
++ gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
++ "Unable to add list of volumes "
++ "in the peer_data dict for handshake");
+ goto out;
++ }
++
++ if (!req.vols.vols_len) {
++ ret = dict_allocate_and_serialize(peer_data, &req.vols.vols_val,
++ &req.vols.vols_len);
++ if (ret)
++ goto out;
++ }
+
+ ret = glusterd_submit_request(
+ peerinfo->rpc, &req, frame, peerinfo->peer, GLUSTERD_FRIEND_ADD, NULL,
+diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c
+index 8f1525e..2bc4836 100644
+--- a/xlators/mgmt/glusterd/src/glusterd-utils.c
++++ b/xlators/mgmt/glusterd/src/glusterd-utils.c
+@@ -3466,11 +3466,118 @@ out:
+ return NULL;
+ }
+
++int
++glusterd_dict_searialize(dict_t *dict_arr[], int count, int totcount, char *buf)
++{
++ int i = 0;
++ int32_t keylen = 0;
++ int64_t netword = 0;
++ data_pair_t *pair = NULL;
++ int dict_count = 0;
++ int ret = 0;
++
++ netword = hton32(totcount);
++ memcpy(buf, &netword, sizeof(netword));
++ buf += DICT_HDR_LEN;
++
++ for (i = 0; i < count; i++) {
++ if (dict_arr[i]) {
++ dict_count = dict_arr[i]->count;
++ pair = dict_arr[i]->members_list;
++ while (dict_count) {
++ if (!pair) {
++ gf_msg("glusterd", GF_LOG_ERROR, 0,
++ LG_MSG_PAIRS_LESS_THAN_COUNT,
++ "less than count data pairs found!");
++ ret = -1;
++ goto out;
++ }
++
++ if (!pair->key) {
++ gf_msg("glusterd", GF_LOG_ERROR, 0, LG_MSG_NULL_PTR,
++ "pair->key is null!");
++ ret = -1;
++ goto out;
++ }
++
++ keylen = strlen(pair->key);
++ netword = hton32(keylen);
++ memcpy(buf, &netword, sizeof(netword));
++ buf += DICT_DATA_HDR_KEY_LEN;
++ if (!pair->value) {
++ gf_msg("glusterd", GF_LOG_ERROR, 0, LG_MSG_NULL_PTR,
++ "pair->value is null!");
++ ret = -1;
++ goto out;
++ }
++
++ netword = hton32(pair->value->len);
++ memcpy(buf, &netword, sizeof(netword));
++ buf += DICT_DATA_HDR_VAL_LEN;
++
++ memcpy(buf, pair->key, keylen);
++ buf += keylen;
++ *buf++ = '\0';
++
++ if (pair->value->data) {
++ memcpy(buf, pair->value->data, pair->value->len);
++ buf += pair->value->len;
++ }
++
++ pair = pair->next;
++ dict_count--;
++ }
++ }
++ }
++
++out:
++ for (i = 0; i < count; i++) {
++ if (dict_arr[i])
++ dict_unref(dict_arr[i]);
++ }
++ return ret;
++}
++
++int
++glusterd_dict_arr_serialize(dict_t *dict_arr[], int count, char **buf,
++ u_int *length)
++{
++ ssize_t len = 0;
++ int i = 0;
++ int totcount = 0;
++ int ret = 0;
++
++ for (i = 0; i < count; i++) {
++ if (dict_arr[i]) {
++ len += dict_serialized_length_lk(dict_arr[i]);
++ totcount += dict_arr[i]->count;
++ }
++ }
++
++ // Subtract HDR_LEN except one dictionary
++ len = len - ((count - 1) * DICT_HDR_LEN);
++
++ *buf = GF_MALLOC(len, gf_common_mt_char);
++ if (*buf == NULL) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ if (length != NULL) {
++ *length = len;
++ }
++
++ ret = glusterd_dict_searialize(dict_arr, count, totcount, *buf);
++
++out:
++ return ret;
++}
++
+ int32_t
+-glusterd_add_volumes_to_export_dict(dict_t **peer_data)
++glusterd_add_volumes_to_export_dict(dict_t *peer_data, char **buf,
++ u_int *length)
+ {
+ int32_t ret = -1;
+- dict_t *dict = NULL;
+ dict_t *dict_arr[128] = {
+ 0,
+ };
+@@ -3496,10 +3603,6 @@ glusterd_add_volumes_to_export_dict(dict_t **peer_data)
+ priv = this->private;
+ GF_ASSERT(priv);
+
+- dict = dict_new();
+- if (!dict)
+- goto out;
+-
+ /* Count the total number of volumes */
+ cds_list_for_each_entry(volinfo, &priv->volumes, vol_list) volcnt++;
+
+@@ -3520,14 +3623,15 @@ glusterd_add_volumes_to_export_dict(dict_t **peer_data)
+ cds_list_for_each_entry(volinfo, &priv->volumes, vol_list)
+ {
+ count++;
+- ret = glusterd_add_volume_to_dict(volinfo, dict, count, "volume");
++ ret = glusterd_add_volume_to_dict(volinfo, peer_data, count,
++ "volume");
+ if (ret)
+ goto out;
+
+ if (!dict_get_sizen(volinfo->dict, VKEY_FEATURES_QUOTA))
+ continue;
+
+- ret = glusterd_vol_add_quota_conf_to_dict(volinfo, dict, count,
++ ret = glusterd_vol_add_quota_conf_to_dict(volinfo, peer_data, count,
+ "volume");
+ if (ret)
+ goto out;
+@@ -3569,34 +3673,34 @@ glusterd_add_volumes_to_export_dict(dict_t **peer_data)
+
+ gf_log(this->name, GF_LOG_INFO,
+ "Finished dictionary popluation in all threads");
+- for (i = 0; i < totthread; i++) {
+- dict_copy_with_ref(dict_arr[i], dict);
+- dict_unref(dict_arr[i]);
+- }
+- gf_log(this->name, GF_LOG_INFO,
+- "Finished merger of all dictionraies into single one");
+ }
+
+- ret = dict_set_int32n(dict, "count", SLEN("count"), volcnt);
++ ret = dict_set_int32n(peer_data, "count", SLEN("count"), volcnt);
+ if (ret)
+ goto out;
+
+- ctx.dict = dict;
++ ctx.dict = peer_data;
+ ctx.prefix = "global";
+ ctx.opt_count = 1;
+ ctx.key_name = "key";
+ ctx.val_name = "val";
+ dict_foreach(priv->opts, _add_dict_to_prdict, &ctx);
+ ctx.opt_count--;
+- ret = dict_set_int32n(dict, "global-opt-count", SLEN("global-opt-count"),
+- ctx.opt_count);
++ ret = dict_set_int32n(peer_data, "global-opt-count",
++ SLEN("global-opt-count"), ctx.opt_count);
+ if (ret)
+ goto out;
+
+- *peer_data = dict;
++ if (totthread) {
++ gf_log(this->name, GF_LOG_INFO,
++ "Finished merger of all dictionraies into single one");
++ dict_arr[totthread++] = peer_data;
++ ret = glusterd_dict_arr_serialize(dict_arr, totthread, buf, length);
++ gf_log(this->name, GF_LOG_INFO,
++ "Serialize dictionary data return is %d", ret);
++ }
++
+ out:
+- if (ret)
+- dict_unref(dict);
+
+ gf_msg_trace(this->name, 0, "Returning %d", ret);
+ return ret;
+@@ -4940,6 +5044,7 @@ glusterd_import_friend_volumes_synctask(void *opaque)
+ xlator_t *this = NULL;
+ glusterd_conf_t *conf = NULL;
+ dict_t *peer_data = NULL;
++ glusterd_friend_synctask_args_t *arg = NULL;
+
+ this = THIS;
+ GF_ASSERT(this);
+@@ -4947,8 +5052,20 @@ glusterd_import_friend_volumes_synctask(void *opaque)
+ conf = this->private;
+ GF_ASSERT(conf);
+
+- peer_data = (dict_t *)opaque;
+- GF_ASSERT(peer_data);
++ arg = opaque;
++ if (!arg)
++ goto out;
++
++ peer_data = dict_new();
++ if (!peer_data) {
++ goto out;
++ }
++
++ ret = dict_unserialize(arg->dict_buf, arg->dictlen, &peer_data);
++ if (ret) {
++ errno = ENOMEM;
++ goto out;
++ }
+
+ ret = dict_get_int32n(peer_data, "count", SLEN("count"), &count);
+ if (ret)
+@@ -4980,6 +5097,11 @@ glusterd_import_friend_volumes_synctask(void *opaque)
+ out:
+ if (peer_data)
+ dict_unref(peer_data);
++ if (arg) {
++ if (arg->dict_buf)
++ GF_FREE(arg->dict_buf);
++ GF_FREE(arg);
++ }
+
+ gf_msg_debug("glusterd", 0, "Returning with %d", ret);
+ return ret;
+@@ -5146,7 +5268,7 @@ glusterd_compare_friend_data(dict_t *peer_data, int32_t *status, char *hostname)
+ gf_boolean_t update = _gf_false;
+ xlator_t *this = NULL;
+ glusterd_conf_t *priv = NULL;
+- dict_t *peer_data_copy = NULL;
++ glusterd_friend_synctask_args_t *arg = NULL;
+
+ this = THIS;
+ GF_ASSERT(this);
+@@ -5188,12 +5310,23 @@ glusterd_compare_friend_data(dict_t *peer_data, int32_t *status, char *hostname)
+ * first brick to come up before attaching the subsequent bricks
+ * in case brick multiplexing is enabled
+ */
+- peer_data_copy = dict_copy_with_ref(peer_data, NULL);
+- glusterd_launch_synctask(glusterd_import_friend_volumes_synctask,
+- peer_data_copy);
++ arg = GF_CALLOC(1, sizeof(*arg), gf_common_mt_char);
++ ret = dict_allocate_and_serialize(peer_data, &arg->dict_buf,
++ &arg->dictlen);
++ if (ret < 0) {
++ gf_log(this->name, GF_LOG_ERROR,
++ "dict_serialize failed while handling "
++ " import friend volume request");
++ goto out;
++ }
++
++ glusterd_launch_synctask(glusterd_import_friend_volumes_synctask, arg);
+ }
+
+ out:
++ if (ret && arg) {
++ GF_FREE(arg);
++ }
+ gf_msg_debug(this->name, 0, "Returning with ret: %d, status: %d", ret,
+ *status);
+ return ret;
+diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.h b/xlators/mgmt/glusterd/src/glusterd-utils.h
+index 3647c34..6ad8062 100644
+--- a/xlators/mgmt/glusterd/src/glusterd-utils.h
++++ b/xlators/mgmt/glusterd/src/glusterd-utils.h
+@@ -227,7 +227,8 @@ glusterd_volume_brickinfo_get_by_brick(char *brick, glusterd_volinfo_t *volinfo,
+ gf_boolean_t construct_real_path);
+
+ int32_t
+-glusterd_add_volumes_to_export_dict(dict_t **peer_data);
++glusterd_add_volumes_to_export_dict(dict_t *peer_data, char **buf,
++ u_int *length);
+
+ int32_t
+ glusterd_compare_friend_data(dict_t *peer_data, int32_t *status,
+diff --git a/xlators/mgmt/glusterd/src/glusterd.h b/xlators/mgmt/glusterd/src/glusterd.h
+index 2ea8560..f96bca3 100644
+--- a/xlators/mgmt/glusterd/src/glusterd.h
++++ b/xlators/mgmt/glusterd/src/glusterd.h
+@@ -240,6 +240,11 @@ typedef struct glusterd_add_dict_args {
+ int end;
+ } glusterd_add_dict_args_t;
+
++typedef struct glusterd_friend_synctask_args {
++ char *dict_buf;
++ u_int dictlen;
++} glusterd_friend_synctask_args_t;
++
+ typedef enum gf_brick_status {
+ GF_BRICK_STOPPED,
+ GF_BRICK_STARTED,
+--
+1.8.3.1
+