14f8ab
From 5294c82e0528059b10cbaab7805b20e76ffdd66b Mon Sep 17 00:00:00 2001
14f8ab
From: mohit84 <moagrawa@redhat.com>
14f8ab
Date: Mon, 30 Nov 2020 17:39:53 +0530
14f8ab
Subject: [PATCH 510/511] glusterd[brick_mux]: Optimize friend handshake code
14f8ab
 to avoid call_bail (#1614)
14f8ab
14f8ab
During glusterd handshake glusterd received a volume dictionary
14f8ab
from peer end to compare the own volume dictionary data.If the options
14f8ab
are differ it sets the key to recognize volume options are changed
14f8ab
and call import syntask to delete/start the volume.In brick_mux
14f8ab
environment while number of volumes are high(5k) the dict api in function
14f8ab
glusterd_compare_friend_volume takes time because the function
14f8ab
glusterd_handle_friend_req saves all peer volume data in a single dictionary.
14f8ab
Due to time taken by the function glusterd_handle_friend RPC requests receives
14f8ab
a call_bail from a peer end gluster(CLI) won't be able to show volume status.
14f8ab
14f8ab
Solution: To optimize the code done below changes
14f8ab
1) Populate a new specific dictionary to save the peer end version specific
14f8ab
   data so that function won't take much time to take the decision about the
14f8ab
   peer end has some volume updates.
14f8ab
2) In case of volume has differ version set the key in status_arr instead
14f8ab
   of saving in a dictionary to make the operation is faster.
14f8ab
14f8ab
Note: To validate the changes followed below procedure
14f8ab
1) Setup 5100 distributed volumes 3x1
14f8ab
2) Enable brick_mux
14f8ab
3) Start all the volumes
14f8ab
4) Kill all gluster processes on 3rd node
14f8ab
5) Run a loop to update volume option on a 1st node
14f8ab
   for i in {1..5100}; do gluster v set vol$i performance.open-behind off; done
14f8ab
6) Start the glusterd process on the 3rd node
14f8ab
7) Wait to finish handshake and check there should not be any call_bail message
14f8ab
   in the logs
14f8ab
14f8ab
> Change-Id: Ibad7c23988539cc369ecc39dea2ea6985470bee1
14f8ab
> Fixes: #1613
14f8ab
> Signed-off-by: Mohit Agrawal <moagrawa@redhat.com>
14f8ab
> (Cherry pick from commit 12545d91eed27ff9abb0505a12c7d4e75b45a53e)
14f8ab
> (Reviewed on upstream link https://github.com/gluster/glusterfs/issues/1613)
14f8ab
14f8ab
Change-Id: Ibad7c23988539cc369ecc39dea2ea6985470bee1
14f8ab
BUG: 1898784
14f8ab
Signed-off-by: Mohit Agrawal <moagrawa@redhat.com>
14f8ab
Reviewed-on: https://code.engineering.redhat.com/gerrit/221193
14f8ab
Tested-by: RHGS Build Bot <nigelb@redhat.com>
14f8ab
Reviewed-by: Sunil Kumar Heggodu Gopala Acharya <sheggodu@redhat.com>
14f8ab
---
14f8ab
 libglusterfs/src/ctx.c                       |   4 +
14f8ab
 libglusterfs/src/dict.c                      | 166 ++++++++++++++++++++++++++-
14f8ab
 libglusterfs/src/globals.c                   |   2 -
14f8ab
 libglusterfs/src/glusterfs/dict.h            |   5 +
14f8ab
 libglusterfs/src/glusterfs/globals.h         |   2 +
14f8ab
 libglusterfs/src/libglusterfs.sym            |   1 +
14f8ab
 xlators/mgmt/glusterd/src/glusterd-handler.c |  39 ++++---
14f8ab
 xlators/mgmt/glusterd/src/glusterd-sm.c      |   6 +-
14f8ab
 xlators/mgmt/glusterd/src/glusterd-sm.h      |   1 +
14f8ab
 xlators/mgmt/glusterd/src/glusterd-utils.c   | 148 ++++++++++++++----------
14f8ab
 xlators/mgmt/glusterd/src/glusterd-utils.h   |   2 +-
14f8ab
 xlators/mgmt/glusterd/src/glusterd.h         |   8 +-
14f8ab
 12 files changed, 301 insertions(+), 83 deletions(-)
14f8ab
14f8ab
diff --git a/libglusterfs/src/ctx.c b/libglusterfs/src/ctx.c
14f8ab
index 4a001c2..ae1a77a 100644
14f8ab
--- a/libglusterfs/src/ctx.c
14f8ab
+++ b/libglusterfs/src/ctx.c
14f8ab
@@ -14,6 +14,7 @@
14f8ab
 #include "glusterfs/glusterfs.h"
14f8ab
 #include "timer-wheel.h"
14f8ab
 
14f8ab
+glusterfs_ctx_t *global_ctx = NULL;
14f8ab
 glusterfs_ctx_t *
14f8ab
 glusterfs_ctx_new()
14f8ab
 {
14f8ab
@@ -51,6 +52,9 @@ glusterfs_ctx_new()
14f8ab
     GF_ATOMIC_INIT(ctx->stats.max_dict_pairs, 0);
14f8ab
     GF_ATOMIC_INIT(ctx->stats.total_pairs_used, 0);
14f8ab
     GF_ATOMIC_INIT(ctx->stats.total_dicts_used, 0);
14f8ab
+
14f8ab
+    if (!global_ctx)
14f8ab
+        global_ctx = ctx;
14f8ab
 out:
14f8ab
     return ctx;
14f8ab
 }
14f8ab
diff --git a/libglusterfs/src/dict.c b/libglusterfs/src/dict.c
14f8ab
index d8cdda4..e5f619c 100644
14f8ab
--- a/libglusterfs/src/dict.c
14f8ab
+++ b/libglusterfs/src/dict.c
14f8ab
@@ -56,7 +56,13 @@ struct dict_cmp {
14f8ab
 static data_t *
14f8ab
 get_new_data()
14f8ab
 {
14f8ab
-    data_t *data = mem_get(THIS->ctx->dict_data_pool);
14f8ab
+    data_t *data = NULL;
14f8ab
+
14f8ab
+    if (global_ctx) {
14f8ab
+        data = mem_get(global_ctx->dict_data_pool);
14f8ab
+    } else {
14f8ab
+        data = mem_get(THIS->ctx->dict_data_pool);
14f8ab
+    }
14f8ab
 
14f8ab
     if (!data)
14f8ab
         return NULL;
14f8ab
@@ -3503,3 +3509,161 @@ unlock:
14f8ab
     UNLOCK(&dict->lock);
14f8ab
     return 0;
14f8ab
 }
14f8ab
+
14f8ab
+/* Popluate specific dictionary on the basis of passed key array at the
14f8ab
+   time of unserialize buffer
14f8ab
+*/
14f8ab
+int32_t
14f8ab
+dict_unserialize_specific_keys(char *orig_buf, int32_t size, dict_t **fill,
14f8ab
+                               char **suffix_key_arr, dict_t **specific_dict,
14f8ab
+                               int totkeycount)
14f8ab
+{
14f8ab
+    char *buf = orig_buf;
14f8ab
+    int ret = -1;
14f8ab
+    int32_t count = 0;
14f8ab
+    int i = 0;
14f8ab
+    int j = 0;
14f8ab
+
14f8ab
+    data_t *value = NULL;
14f8ab
+    char *key = NULL;
14f8ab
+    int32_t keylen = 0;
14f8ab
+    int32_t vallen = 0;
14f8ab
+    int32_t hostord = 0;
14f8ab
+    xlator_t *this = NULL;
14f8ab
+    int32_t keylenarr[totkeycount];
14f8ab
+
14f8ab
+    this = THIS;
14f8ab
+    GF_ASSERT(this);
14f8ab
+
14f8ab
+    if (!buf) {
14f8ab
+        gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
14f8ab
+                         "buf is null!");
14f8ab
+        goto out;
14f8ab
+    }
14f8ab
+
14f8ab
+    if (size == 0) {
14f8ab
+        gf_msg_callingfn("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,
14f8ab
+                         "size is 0!");
14f8ab
+        goto out;
14f8ab
+    }
14f8ab
+
14f8ab
+    if (!fill) {
14f8ab
+        gf_msg_callingfn("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,
14f8ab
+                         "fill is null!");
14f8ab
+        goto out;
14f8ab
+    }
14f8ab
+
14f8ab
+    if (!*fill) {
14f8ab
+        gf_msg_callingfn("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,
14f8ab
+                         "*fill is null!");
14f8ab
+        goto out;
14f8ab
+    }
14f8ab
+
14f8ab
+    if ((buf + DICT_HDR_LEN) > (orig_buf + size)) {
14f8ab
+        gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF,
14f8ab
+                         "undersized buffer "
14f8ab
+                         "passed. available (%lu) < required (%lu)",
14f8ab
+                         (long)(orig_buf + size), (long)(buf + DICT_HDR_LEN));
14f8ab
+        goto out;
14f8ab
+    }
14f8ab
+
14f8ab
+    memcpy(&hostord, buf, sizeof(hostord));
14f8ab
+    count = ntoh32(hostord);
14f8ab
+    buf += DICT_HDR_LEN;
14f8ab
+
14f8ab
+    if (count < 0) {
14f8ab
+        gf_smsg("dict", GF_LOG_ERROR, 0, LG_MSG_COUNT_LESS_THAN_ZERO,
14f8ab
+                "count=%d", count, NULL);
14f8ab
+        goto out;
14f8ab
+    }
14f8ab
+
14f8ab
+    /* Compute specific key length and save in array */
14f8ab
+    for (i = 0; i < totkeycount; i++) {
14f8ab
+        keylenarr[i] = strlen(suffix_key_arr[i]);
14f8ab
+    }
14f8ab
+
14f8ab
+    for (i = 0; i < count; i++) {
14f8ab
+        if ((buf + DICT_DATA_HDR_KEY_LEN) > (orig_buf + size)) {
14f8ab
+            gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF,
14f8ab
+                             "undersized "
14f8ab
+                             "buffer passed. available (%lu) < "
14f8ab
+                             "required (%lu)",
14f8ab
+                             (long)(orig_buf + size),
14f8ab
+                             (long)(buf + DICT_DATA_HDR_KEY_LEN));
14f8ab
+            goto out;
14f8ab
+        }
14f8ab
+        memcpy(&hostord, buf, sizeof(hostord));
14f8ab
+        keylen = ntoh32(hostord);
14f8ab
+        buf += DICT_DATA_HDR_KEY_LEN;
14f8ab
+
14f8ab
+        if ((buf + DICT_DATA_HDR_VAL_LEN) > (orig_buf + size)) {
14f8ab
+            gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF,
14f8ab
+                             "undersized "
14f8ab
+                             "buffer passed. available (%lu) < "
14f8ab
+                             "required (%lu)",
14f8ab
+                             (long)(orig_buf + size),
14f8ab
+                             (long)(buf + DICT_DATA_HDR_VAL_LEN));
14f8ab
+            goto out;
14f8ab
+        }
14f8ab
+        memcpy(&hostord, buf, sizeof(hostord));
14f8ab
+        vallen = ntoh32(hostord);
14f8ab
+        buf += DICT_DATA_HDR_VAL_LEN;
14f8ab
+
14f8ab
+        if ((keylen < 0) || (vallen < 0)) {
14f8ab
+            gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF,
14f8ab
+                             "undersized length passed "
14f8ab
+                             "key:%d val:%d",
14f8ab
+                             keylen, vallen);
14f8ab
+            goto out;
14f8ab
+        }
14f8ab
+        if ((buf + keylen) > (orig_buf + size)) {
14f8ab
+            gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF,
14f8ab
+                             "undersized buffer passed. "
14f8ab
+                             "available (%lu) < required (%lu)",
14f8ab
+                             (long)(orig_buf + size), (long)(buf + keylen));
14f8ab
+            goto out;
14f8ab
+        }
14f8ab
+        key = buf;
14f8ab
+        buf += keylen + 1; /* for '\0' */
14f8ab
+
14f8ab
+        if ((buf + vallen) > (orig_buf + size)) {
14f8ab
+            gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF,
14f8ab
+                             "undersized buffer passed. "
14f8ab
+                             "available (%lu) < required (%lu)",
14f8ab
+                             (long)(orig_buf + size), (long)(buf + vallen));
14f8ab
+            goto out;
14f8ab
+        }
14f8ab
+        value = get_new_data();
14f8ab
+
14f8ab
+        if (!value) {
14f8ab
+            ret = -1;
14f8ab
+            goto out;
14f8ab
+        }
14f8ab
+        value->len = vallen;
14f8ab
+        value->data = gf_memdup(buf, vallen);
14f8ab
+        value->data_type = GF_DATA_TYPE_STR_OLD;
14f8ab
+        value->is_static = _gf_false;
14f8ab
+        buf += vallen;
14f8ab
+
14f8ab
+        ret = dict_addn(*fill, key, keylen, value);
14f8ab
+        if (ret < 0) {
14f8ab
+            data_destroy(value);
14f8ab
+            goto out;
14f8ab
+        }
14f8ab
+        for (j = 0; j < totkeycount; j++) {
14f8ab
+            if (keylen > keylenarr[j]) {
14f8ab
+                if (!strcmp(key + keylen - keylenarr[j], suffix_key_arr[j])) {
14f8ab
+                    ret = dict_addn(*specific_dict, key, keylen, value);
14f8ab
+                    break;
14f8ab
+                }
14f8ab
+            }
14f8ab
+        }
14f8ab
+
14f8ab
+        if (ret < 0)
14f8ab
+            goto out;
14f8ab
+    }
14f8ab
+
14f8ab
+    ret = 0;
14f8ab
+out:
14f8ab
+    return ret;
14f8ab
+}
14f8ab
diff --git a/libglusterfs/src/globals.c b/libglusterfs/src/globals.c
14f8ab
index e433ee8..30c15b6 100644
14f8ab
--- a/libglusterfs/src/globals.c
14f8ab
+++ b/libglusterfs/src/globals.c
14f8ab
@@ -96,7 +96,6 @@ const char *gf_upcall_list[GF_UPCALL_FLAGS_MAXVALUE] = {
14f8ab
 /* This global ctx is a bad hack to prevent some of the libgfapi crashes.
14f8ab
  * This should be removed once the patch on resource pool is accepted
14f8ab
  */
14f8ab
-glusterfs_ctx_t *global_ctx = NULL;
14f8ab
 pthread_mutex_t global_ctx_mutex = PTHREAD_MUTEX_INITIALIZER;
14f8ab
 xlator_t global_xlator;
14f8ab
 static int gf_global_mem_acct_enable = 1;
14f8ab
@@ -236,7 +235,6 @@ __glusterfs_this_location()
14f8ab
     if (*this_location == NULL) {
14f8ab
         thread_xlator = &global_xlator;
14f8ab
     }
14f8ab
-
14f8ab
     return this_location;
14f8ab
 }
14f8ab
 
14f8ab
diff --git a/libglusterfs/src/glusterfs/dict.h b/libglusterfs/src/glusterfs/dict.h
14f8ab
index 8239c7a..6e469c7 100644
14f8ab
--- a/libglusterfs/src/glusterfs/dict.h
14f8ab
+++ b/libglusterfs/src/glusterfs/dict.h
14f8ab
@@ -423,4 +423,9 @@ dict_has_key_from_array(dict_t *dict, char **strings, gf_boolean_t *result);
14f8ab
 
14f8ab
 int
14f8ab
 dict_serialized_length_lk(dict_t *this);
14f8ab
+
14f8ab
+int32_t
14f8ab
+dict_unserialize_specific_keys(char *orig_buf, int32_t size, dict_t **fill,
14f8ab
+                               char **specific_key_arr, dict_t **specific_dict,
14f8ab
+                               int totkeycount);
14f8ab
 #endif
14f8ab
diff --git a/libglusterfs/src/glusterfs/globals.h b/libglusterfs/src/glusterfs/globals.h
14f8ab
index cc145cd..33fb023 100644
14f8ab
--- a/libglusterfs/src/glusterfs/globals.h
14f8ab
+++ b/libglusterfs/src/glusterfs/globals.h
14f8ab
@@ -199,4 +199,6 @@ int
14f8ab
 gf_global_mem_acct_enable_get(void);
14f8ab
 int
14f8ab
 gf_global_mem_acct_enable_set(int val);
14f8ab
+
14f8ab
+extern glusterfs_ctx_t *global_ctx;
14f8ab
 #endif /* !_GLOBALS_H */
14f8ab
diff --git a/libglusterfs/src/libglusterfs.sym b/libglusterfs/src/libglusterfs.sym
14f8ab
index d060292..bc770e2 100644
14f8ab
--- a/libglusterfs/src/libglusterfs.sym
14f8ab
+++ b/libglusterfs/src/libglusterfs.sym
14f8ab
@@ -436,6 +436,7 @@ dict_clear_flag
14f8ab
 dict_check_flag
14f8ab
 dict_unref
14f8ab
 dict_unserialize
14f8ab
+dict_unserialize_specific_keys
14f8ab
 drop_token
14f8ab
 eh_destroy
14f8ab
 eh_dump
14f8ab
diff --git a/xlators/mgmt/glusterd/src/glusterd-handler.c b/xlators/mgmt/glusterd/src/glusterd-handler.c
14f8ab
index b8799ab..908361c 100644
14f8ab
--- a/xlators/mgmt/glusterd/src/glusterd-handler.c
14f8ab
+++ b/xlators/mgmt/glusterd/src/glusterd-handler.c
14f8ab
@@ -86,6 +86,9 @@ glusterd_big_locked_handler(rpcsvc_request_t *req, rpcsvc_actor actor_fn)
14f8ab
     return ret;
14f8ab
 }
14f8ab
 
14f8ab
+static char *specific_key_suffix[] = {".quota-cksum", ".ckusm", ".version",
14f8ab
+                                      ".quota-version", ".name"};
14f8ab
+
14f8ab
 static int
14f8ab
 glusterd_handle_friend_req(rpcsvc_request_t *req, uuid_t uuid, char *hostname,
14f8ab
                            int port, gd1_mgmt_friend_req *friend_req)
14f8ab
@@ -97,6 +100,8 @@ glusterd_handle_friend_req(rpcsvc_request_t *req, uuid_t uuid, char *hostname,
14f8ab
     char rhost[UNIX_PATH_MAX + 1] = {0};
14f8ab
     uuid_t friend_uuid = {0};
14f8ab
     dict_t *dict = NULL;
14f8ab
+    dict_t *peer_ver = NULL;
14f8ab
+    int totcount = sizeof(specific_key_suffix) / sizeof(specific_key_suffix[0]);
14f8ab
 
14f8ab
     gf_uuid_parse(uuid_utoa(uuid), friend_uuid);
14f8ab
     if (!port)
14f8ab
@@ -104,8 +109,19 @@ glusterd_handle_friend_req(rpcsvc_request_t *req, uuid_t uuid, char *hostname,
14f8ab
 
14f8ab
     ret = glusterd_remote_hostname_get(req, rhost, sizeof(rhost));
14f8ab
 
14f8ab
+    ctx = GF_CALLOC(1, sizeof(*ctx), gf_gld_mt_friend_req_ctx_t);
14f8ab
+    dict = dict_new();
14f8ab
+    peer_ver = dict_new();
14f8ab
+
14f8ab
     RCU_READ_LOCK;
14f8ab
 
14f8ab
+    if (!ctx || !dict || !peer_ver) {
14f8ab
+        gf_msg("glusterd", GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
14f8ab
+               "Unable to allocate memory");
14f8ab
+        ret = -1;
14f8ab
+        goto out;
14f8ab
+    }
14f8ab
+
14f8ab
     peerinfo = glusterd_peerinfo_find(uuid, rhost);
14f8ab
 
14f8ab
     if (peerinfo == NULL) {
14f8ab
@@ -130,28 +146,14 @@ glusterd_handle_friend_req(rpcsvc_request_t *req, uuid_t uuid, char *hostname,
14f8ab
     event->peername = gf_strdup(peerinfo->hostname);
14f8ab
     gf_uuid_copy(event->peerid, peerinfo->uuid);
14f8ab
 
14f8ab
-    ctx = GF_CALLOC(1, sizeof(*ctx), gf_gld_mt_friend_req_ctx_t);
14f8ab
-
14f8ab
-    if (!ctx) {
14f8ab
-        gf_msg("glusterd", GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
14f8ab
-               "Unable to allocate memory");
14f8ab
-        ret = -1;
14f8ab
-        goto out;
14f8ab
-    }
14f8ab
-
14f8ab
     gf_uuid_copy(ctx->uuid, uuid);
14f8ab
     if (hostname)
14f8ab
         ctx->hostname = gf_strdup(hostname);
14f8ab
     ctx->req = req;
14f8ab
 
14f8ab
-    dict = dict_new();
14f8ab
-    if (!dict) {
14f8ab
-        ret = -1;
14f8ab
-        goto out;
14f8ab
-    }
14f8ab
-
14f8ab
-    ret = dict_unserialize(friend_req->vols.vols_val, friend_req->vols.vols_len,
14f8ab
-                           &dict);
14f8ab
+    ret = dict_unserialize_specific_keys(
14f8ab
+        friend_req->vols.vols_val, friend_req->vols.vols_len, &dict,
14f8ab
+        specific_key_suffix, &peer_ver, totcount);
14f8ab
 
14f8ab
     if (ret)
14f8ab
         goto out;
14f8ab
@@ -159,6 +161,7 @@ glusterd_handle_friend_req(rpcsvc_request_t *req, uuid_t uuid, char *hostname,
14f8ab
         dict->extra_stdfree = friend_req->vols.vols_val;
14f8ab
 
14f8ab
     ctx->vols = dict;
14f8ab
+    ctx->peer_ver = peer_ver;
14f8ab
     event->ctx = ctx;
14f8ab
 
14f8ab
     ret = glusterd_friend_sm_inject_event(event);
14f8ab
@@ -188,6 +191,8 @@ out:
14f8ab
         } else {
14f8ab
             free(friend_req->vols.vols_val);
14f8ab
         }
14f8ab
+        if (peer_ver)
14f8ab
+            dict_unref(peer_ver);
14f8ab
         if (event)
14f8ab
             GF_FREE(event->peername);
14f8ab
         GF_FREE(event);
14f8ab
diff --git a/xlators/mgmt/glusterd/src/glusterd-sm.c b/xlators/mgmt/glusterd/src/glusterd-sm.c
14f8ab
index 044da3d..d10a792 100644
14f8ab
--- a/xlators/mgmt/glusterd/src/glusterd-sm.c
14f8ab
+++ b/xlators/mgmt/glusterd/src/glusterd-sm.c
14f8ab
@@ -106,6 +106,8 @@ glusterd_destroy_friend_req_ctx(glusterd_friend_req_ctx_t *ctx)
14f8ab
 
14f8ab
     if (ctx->vols)
14f8ab
         dict_unref(ctx->vols);
14f8ab
+    if (ctx->peer_ver)
14f8ab
+        dict_unref(ctx->peer_ver);
14f8ab
     GF_FREE(ctx->hostname);
14f8ab
     GF_FREE(ctx);
14f8ab
 }
14f8ab
@@ -936,8 +938,8 @@ glusterd_ac_handle_friend_add_req(glusterd_friend_sm_event_t *event, void *ctx)
14f8ab
     // Build comparison logic here.
14f8ab
     pthread_mutex_lock(&conf->import_volumes);
14f8ab
     {
14f8ab
-        ret = glusterd_compare_friend_data(ev_ctx->vols, &status,
14f8ab
-                                           event->peername);
14f8ab
+        ret = glusterd_compare_friend_data(ev_ctx->vols, ev_ctx->peer_ver,
14f8ab
+                                           &status, event->peername);
14f8ab
         if (ret) {
14f8ab
             pthread_mutex_unlock(&conf->import_volumes);
14f8ab
             goto out;
14f8ab
diff --git a/xlators/mgmt/glusterd/src/glusterd-sm.h b/xlators/mgmt/glusterd/src/glusterd-sm.h
14f8ab
index ce008ac..efdf68e 100644
14f8ab
--- a/xlators/mgmt/glusterd/src/glusterd-sm.h
14f8ab
+++ b/xlators/mgmt/glusterd/src/glusterd-sm.h
14f8ab
@@ -174,6 +174,7 @@ typedef struct glusterd_friend_req_ctx_ {
14f8ab
     rpcsvc_request_t *req;
14f8ab
     int port;
14f8ab
     dict_t *vols;
14f8ab
+    dict_t *peer_ver;  // Dictionary to save peer ver data
14f8ab
 } glusterd_friend_req_ctx_t;
14f8ab
 
14f8ab
 typedef struct glusterd_friend_update_ctx_ {
14f8ab
diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c
14f8ab
index f7030fb..cf32bd9 100644
14f8ab
--- a/xlators/mgmt/glusterd/src/glusterd-utils.c
14f8ab
+++ b/xlators/mgmt/glusterd/src/glusterd-utils.c
14f8ab
@@ -3709,12 +3709,14 @@ out:
14f8ab
     return ret;
14f8ab
 }
14f8ab
 
14f8ab
-int32_t
14f8ab
-glusterd_compare_friend_volume(dict_t *peer_data, int32_t count,
14f8ab
-                               int32_t *status, char *hostname)
14f8ab
+static int32_t
14f8ab
+glusterd_compare_friend_volume(dict_t *peer_data,
14f8ab
+                               glusterd_friend_synctask_args_t *arg,
14f8ab
+                               int32_t count, int32_t *status, char *hostname)
14f8ab
 {
14f8ab
     int32_t ret = -1;
14f8ab
     char key[64] = "";
14f8ab
+    char key_prefix[32];
14f8ab
     int keylen;
14f8ab
     glusterd_volinfo_t *volinfo = NULL;
14f8ab
     char *volname = NULL;
14f8ab
@@ -3726,15 +3728,20 @@ glusterd_compare_friend_volume(dict_t *peer_data, int32_t count,
14f8ab
     xlator_t *this = NULL;
14f8ab
 
14f8ab
     GF_ASSERT(peer_data);
14f8ab
+    GF_ASSERT(arg);
14f8ab
     GF_ASSERT(status);
14f8ab
 
14f8ab
     this = THIS;
14f8ab
     GF_ASSERT(this);
14f8ab
 
14f8ab
-    keylen = snprintf(key, sizeof(key), "volume%d.name", count);
14f8ab
-    ret = dict_get_strn(peer_data, key, keylen, &volname);
14f8ab
-    if (ret)
14f8ab
+    snprintf(key_prefix, sizeof(key_prefix), "volume%d", count);
14f8ab
+    keylen = snprintf(key, sizeof(key), "%s.name", key_prefix);
14f8ab
+    ret = dict_get_strn(arg->peer_ver_data, key, keylen, &volname);
14f8ab
+    if (ret) {
14f8ab
+        gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_GET_FAILED,
14f8ab
+                "Key=%s is NULL in peer_ver_data", key, NULL);
14f8ab
         goto out;
14f8ab
+    }
14f8ab
 
14f8ab
     ret = glusterd_volinfo_find(volname, &volinfo);
14f8ab
     if (ret) {
14f8ab
@@ -3750,10 +3757,13 @@ glusterd_compare_friend_volume(dict_t *peer_data, int32_t count,
14f8ab
         goto out;
14f8ab
     }
14f8ab
 
14f8ab
-    keylen = snprintf(key, sizeof(key), "volume%d.version", count);
14f8ab
-    ret = dict_get_int32n(peer_data, key, keylen, &version);
14f8ab
-    if (ret)
14f8ab
+    keylen = snprintf(key, sizeof(key), "%s.version", key_prefix);
14f8ab
+    ret = dict_get_int32n(arg->peer_ver_data, key, keylen, &version);
14f8ab
+    if (ret) {
14f8ab
+        gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_GET_FAILED,
14f8ab
+                "Key=%s is NULL in peer_ver_data", key, NULL);
14f8ab
         goto out;
14f8ab
+    }
14f8ab
 
14f8ab
     if (version > volinfo->version) {
14f8ab
         // Mismatch detected
14f8ab
@@ -3772,10 +3782,13 @@ glusterd_compare_friend_volume(dict_t *peer_data, int32_t count,
14f8ab
 
14f8ab
     // Now, versions are same, compare cksums.
14f8ab
     //
14f8ab
-    snprintf(key, sizeof(key), "volume%d.ckusm", count);
14f8ab
-    ret = dict_get_uint32(peer_data, key, &cksum);
14f8ab
-    if (ret)
14f8ab
+    snprintf(key, sizeof(key), "%s.ckusm", key_prefix);
14f8ab
+    ret = dict_get_uint32(arg->peer_ver_data, key, &cksum);
14f8ab
+    if (ret) {
14f8ab
+        gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_GET_FAILED,
14f8ab
+                "Key=%s is NULL in peer_ver_data", key, NULL);
14f8ab
         goto out;
14f8ab
+    }
14f8ab
 
14f8ab
     if (cksum != volinfo->cksum) {
14f8ab
         ret = 0;
14f8ab
@@ -3790,8 +3803,8 @@ glusterd_compare_friend_volume(dict_t *peer_data, int32_t count,
14f8ab
     if (!dict_get_sizen(volinfo->dict, VKEY_FEATURES_QUOTA))
14f8ab
         goto skip_quota;
14f8ab
 
14f8ab
-    snprintf(key, sizeof(key), "volume%d.quota-version", count);
14f8ab
-    ret = dict_get_uint32(peer_data, key, &quota_version);
14f8ab
+    snprintf(key, sizeof(key), "%s.quota-version", key_prefix);
14f8ab
+    ret = dict_get_uint32(arg->peer_ver_data, key, &quota_version);
14f8ab
     if (ret) {
14f8ab
         gf_msg_debug(this->name, 0,
14f8ab
                      "quota-version key absent for"
14f8ab
@@ -3809,6 +3822,7 @@ glusterd_compare_friend_volume(dict_t *peer_data, int32_t count,
14f8ab
                    "%d on peer %s",
14f8ab
                    volinfo->volname, volinfo->quota_conf_version, quota_version,
14f8ab
                    hostname);
14f8ab
+            GF_ATOMIC_INIT(volinfo->volpeerupdate, 1);
14f8ab
             *status = GLUSTERD_VOL_COMP_UPDATE_REQ;
14f8ab
             goto out;
14f8ab
         } else if (quota_version < volinfo->quota_conf_version) {
14f8ab
@@ -3819,8 +3833,8 @@ glusterd_compare_friend_volume(dict_t *peer_data, int32_t count,
14f8ab
 
14f8ab
     // Now, versions are same, compare cksums.
14f8ab
     //
14f8ab
-    snprintf(key, sizeof(key), "volume%d.quota-cksum", count);
14f8ab
-    ret = dict_get_uint32(peer_data, key, &quota_cksum);
14f8ab
+    snprintf(key, sizeof(key), "%s.quota-cksum", key_prefix);
14f8ab
+    ret = dict_get_uint32(arg->peer_ver_data, key, &quota_cksum);
14f8ab
     if (ret) {
14f8ab
         gf_msg_debug(this->name, 0,
14f8ab
                      "quota checksum absent for "
14f8ab
@@ -3846,13 +3860,12 @@ skip_quota:
14f8ab
     *status = GLUSTERD_VOL_COMP_SCS;
14f8ab
 
14f8ab
 out:
14f8ab
-    keylen = snprintf(key, sizeof(key), "volume%d.update", count);
14f8ab
-
14f8ab
     if (*status == GLUSTERD_VOL_COMP_UPDATE_REQ) {
14f8ab
-        ret = dict_set_int32n(peer_data, key, keylen, 1);
14f8ab
-    } else {
14f8ab
-        ret = dict_set_int32n(peer_data, key, keylen, 0);
14f8ab
+        /*Set the status to ensure volume is updated on the peer
14f8ab
+         */
14f8ab
+        arg->status_arr[(count / 64)] ^= 1UL << (count % 64);
14f8ab
     }
14f8ab
+
14f8ab
     if (*status == GLUSTERD_VOL_COMP_RJT) {
14f8ab
         gf_event(EVENT_COMPARE_FRIEND_VOLUME_FAILED, "volume=%s",
14f8ab
                  volinfo->volname);
14f8ab
@@ -4935,8 +4948,9 @@ out:
14f8ab
     return ret;
14f8ab
 }
14f8ab
 
14f8ab
-int32_t
14f8ab
-glusterd_import_friend_volume(dict_t *peer_data, int count)
14f8ab
+static int32_t
14f8ab
+glusterd_import_friend_volume(dict_t *peer_data, int count,
14f8ab
+                              glusterd_friend_synctask_args_t *arg)
14f8ab
 {
14f8ab
     int32_t ret = -1;
14f8ab
     glusterd_conf_t *priv = NULL;
14f8ab
@@ -4954,10 +4968,27 @@ glusterd_import_friend_volume(dict_t *peer_data, int count)
14f8ab
     priv = this->private;
14f8ab
     GF_ASSERT(priv);
14f8ab
 
14f8ab
-    ret = snprintf(key, sizeof(key), "volume%d.update", count);
14f8ab
-    ret = dict_get_int32n(peer_data, key, ret, &update);
14f8ab
-    if (ret || !update) {
14f8ab
+    if (arg) {
14f8ab
+        /*Check if the volume options are updated on the other peers
14f8ab
+         */
14f8ab
+        update = (1UL & (arg->status_arr[(count / 64)] >> (count % 64)));
14f8ab
+    } else {
14f8ab
+        ret = snprintf(key, sizeof(key), "volume%d.update", count);
14f8ab
+        ret = dict_get_int32n(peer_data, key, ret, &update);
14f8ab
+        if (ret) {
14f8ab
+            gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_GET_FAILED,
14f8ab
+                    "Key=%s", key, NULL);
14f8ab
+            goto out;
14f8ab
+        }
14f8ab
+    }
14f8ab
+
14f8ab
+    if (!update) {
14f8ab
         /* if update is 0 that means the volume is not imported */
14f8ab
+        gf_log(this->name, GF_LOG_DEBUG,
14f8ab
+               "The volume%d does"
14f8ab
+               " not have any peer change",
14f8ab
+               count);
14f8ab
+        ret = 0;
14f8ab
         goto out;
14f8ab
     }
14f8ab
 
14f8ab
@@ -5045,6 +5076,8 @@ glusterd_import_friend_volumes_synctask(void *opaque)
14f8ab
     glusterd_conf_t *conf = NULL;
14f8ab
     dict_t *peer_data = NULL;
14f8ab
     glusterd_friend_synctask_args_t *arg = NULL;
14f8ab
+    uint64_t bm = 0;
14f8ab
+    uint64_t mask = 0;
14f8ab
 
14f8ab
     this = THIS;
14f8ab
     GF_ASSERT(this);
14f8ab
@@ -5056,17 +5089,7 @@ glusterd_import_friend_volumes_synctask(void *opaque)
14f8ab
     if (!arg)
14f8ab
         goto out;
14f8ab
 
14f8ab
-    peer_data = dict_new();
14f8ab
-    if (!peer_data) {
14f8ab
-        goto out;
14f8ab
-    }
14f8ab
-
14f8ab
-    ret = dict_unserialize(arg->dict_buf, arg->dictlen, &peer_data);
14f8ab
-    if (ret) {
14f8ab
-        errno = ENOMEM;
14f8ab
-        goto out;
14f8ab
-    }
14f8ab
-
14f8ab
+    peer_data = arg->peer_data;
14f8ab
     ret = dict_get_int32n(peer_data, "count", SLEN("count"), &count);
14f8ab
     if (ret)
14f8ab
         goto out;
14f8ab
@@ -5083,11 +5106,18 @@ glusterd_import_friend_volumes_synctask(void *opaque)
14f8ab
     conf->restart_bricks = _gf_true;
14f8ab
 
14f8ab
     while (i <= count) {
14f8ab
-        ret = glusterd_import_friend_volume(peer_data, i);
14f8ab
-        if (ret) {
14f8ab
-            break;
14f8ab
+        bm = arg->status_arr[i / 64];
14f8ab
+        while (bm != 0) {
14f8ab
+            /* mask will contain the lowest bit set from bm. */
14f8ab
+            mask = bm & (-bm);
14f8ab
+            bm ^= mask;
14f8ab
+            ret = glusterd_import_friend_volume(peer_data, i + ffsll(mask) - 2,
14f8ab
+                                                arg);
14f8ab
+            if (ret < 0) {
14f8ab
+                break;
14f8ab
+            }
14f8ab
         }
14f8ab
-        i++;
14f8ab
+        i += 64;
14f8ab
     }
14f8ab
     if (i > count) {
14f8ab
         glusterd_svcs_manager(NULL);
14f8ab
@@ -5095,11 +5125,9 @@ glusterd_import_friend_volumes_synctask(void *opaque)
14f8ab
     conf->restart_bricks = _gf_false;
14f8ab
     synccond_broadcast(&conf->cond_restart_bricks);
14f8ab
 out:
14f8ab
-    if (peer_data)
14f8ab
-        dict_unref(peer_data);
14f8ab
     if (arg) {
14f8ab
-        if (arg->dict_buf)
14f8ab
-            GF_FREE(arg->dict_buf);
14f8ab
+        dict_unref(arg->peer_data);
14f8ab
+        dict_unref(arg->peer_ver_data);
14f8ab
         GF_FREE(arg);
14f8ab
     }
14f8ab
 
14f8ab
@@ -5121,7 +5149,7 @@ glusterd_import_friend_volumes(dict_t *peer_data)
14f8ab
         goto out;
14f8ab
 
14f8ab
     while (i <= count) {
14f8ab
-        ret = glusterd_import_friend_volume(peer_data, i);
14f8ab
+        ret = glusterd_import_friend_volume(peer_data, i, NULL);
14f8ab
         if (ret)
14f8ab
             goto out;
14f8ab
         i++;
14f8ab
@@ -5260,7 +5288,8 @@ out:
14f8ab
 }
14f8ab
 
14f8ab
 int32_t
14f8ab
-glusterd_compare_friend_data(dict_t *peer_data, int32_t *status, char *hostname)
14f8ab
+glusterd_compare_friend_data(dict_t *peer_data, dict_t *cmp, int32_t *status,
14f8ab
+                             char *hostname)
14f8ab
 {
14f8ab
     int32_t ret = -1;
14f8ab
     int32_t count = 0;
14f8ab
@@ -5289,8 +5318,19 @@ glusterd_compare_friend_data(dict_t *peer_data, int32_t *status, char *hostname)
14f8ab
     if (ret)
14f8ab
         goto out;
14f8ab
 
14f8ab
+    arg = GF_CALLOC(1, sizeof(*arg) + sizeof(uint64_t) * (count / 64),
14f8ab
+                    gf_common_mt_char);
14f8ab
+    if (!arg) {
14f8ab
+        ret = -1;
14f8ab
+        gf_msg("glusterd", GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
14f8ab
+               "Out Of Memory");
14f8ab
+        goto out;
14f8ab
+    }
14f8ab
+    arg->peer_data = dict_ref(peer_data);
14f8ab
+    arg->peer_ver_data = dict_ref(cmp);
14f8ab
     while (i <= count) {
14f8ab
-        ret = glusterd_compare_friend_volume(peer_data, i, status, hostname);
14f8ab
+        ret = glusterd_compare_friend_volume(peer_data, arg, i, status,
14f8ab
+                                             hostname);
14f8ab
         if (ret)
14f8ab
             goto out;
14f8ab
 
14f8ab
@@ -5310,21 +5350,13 @@ glusterd_compare_friend_data(dict_t *peer_data, int32_t *status, char *hostname)
14f8ab
          * first brick to come up before attaching the subsequent bricks
14f8ab
          * in case brick multiplexing is enabled
14f8ab
          */
14f8ab
-        arg = GF_CALLOC(1, sizeof(*arg), gf_common_mt_char);
14f8ab
-        ret = dict_allocate_and_serialize(peer_data, &arg->dict_buf,
14f8ab
-                                          &arg->dictlen);
14f8ab
-        if (ret < 0) {
14f8ab
-            gf_log(this->name, GF_LOG_ERROR,
14f8ab
-                   "dict_serialize failed while handling "
14f8ab
-                   " import friend volume request");
14f8ab
-            goto out;
14f8ab
-        }
14f8ab
-
14f8ab
         glusterd_launch_synctask(glusterd_import_friend_volumes_synctask, arg);
14f8ab
     }
14f8ab
 
14f8ab
 out:
14f8ab
     if (ret && arg) {
14f8ab
+        dict_unref(arg->peer_data);
14f8ab
+        dict_unref(arg->peer_ver_data);
14f8ab
         GF_FREE(arg);
14f8ab
     }
14f8ab
     gf_msg_debug(this->name, 0, "Returning with ret: %d, status: %d", ret,
14f8ab
diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.h b/xlators/mgmt/glusterd/src/glusterd-utils.h
14f8ab
index 5f5de82..02d85d2 100644
14f8ab
--- a/xlators/mgmt/glusterd/src/glusterd-utils.h
14f8ab
+++ b/xlators/mgmt/glusterd/src/glusterd-utils.h
14f8ab
@@ -231,7 +231,7 @@ glusterd_add_volumes_to_export_dict(dict_t *peer_data, char **buf,
14f8ab
                                     u_int *length);
14f8ab
 
14f8ab
 int32_t
14f8ab
-glusterd_compare_friend_data(dict_t *peer_data, int32_t *status,
14f8ab
+glusterd_compare_friend_data(dict_t *peer_data, dict_t *cmp, int32_t *status,
14f8ab
                              char *hostname);
14f8ab
 
14f8ab
 int
14f8ab
diff --git a/xlators/mgmt/glusterd/src/glusterd.h b/xlators/mgmt/glusterd/src/glusterd.h
14f8ab
index f739b5d..efe4d0e 100644
14f8ab
--- a/xlators/mgmt/glusterd/src/glusterd.h
14f8ab
+++ b/xlators/mgmt/glusterd/src/glusterd.h
14f8ab
@@ -234,8 +234,12 @@ typedef struct glusterd_add_dict_args {
14f8ab
 } glusterd_add_dict_args_t;
14f8ab
 
14f8ab
 typedef struct glusterd_friend_synctask_args {
14f8ab
-    char *dict_buf;
14f8ab
-    u_int dictlen;
14f8ab
+    dict_t *peer_data;
14f8ab
+    dict_t *peer_ver_data;  // Dictionary to save peer version data
14f8ab
+    /* This status_arr[1] is not a real size, real size of the array
14f8ab
+       is dynamically allocated
14f8ab
+    */
14f8ab
+    uint64_t status_arr[1];
14f8ab
 } glusterd_friend_synctask_args_t;
14f8ab
 
14f8ab
 typedef enum gf_brick_status {
14f8ab
-- 
14f8ab
1.8.3.1
14f8ab