Blob Blame History Raw
From 5294c82e0528059b10cbaab7805b20e76ffdd66b Mon Sep 17 00:00:00 2001
From: mohit84 <moagrawa@redhat.com>
Date: Mon, 30 Nov 2020 17:39:53 +0530
Subject: [PATCH 510/511] glusterd[brick_mux]: Optimize friend handshake code
 to avoid call_bail (#1614)

During glusterd handshake glusterd received a volume dictionary
from peer end to compare the own volume dictionary data.If the options
are differ it sets the key to recognize volume options are changed
and call import syntask to delete/start the volume.In brick_mux
environment while number of volumes are high(5k) the dict api in function
glusterd_compare_friend_volume takes time because the function
glusterd_handle_friend_req saves all peer volume data in a single dictionary.
Due to time taken by the function glusterd_handle_friend RPC requests receives
a call_bail from a peer end gluster(CLI) won't be able to show volume status.

Solution: To optimize the code done below changes
1) Populate a new specific dictionary to save the peer end version specific
   data so that function won't take much time to take the decision about the
   peer end has some volume updates.
2) In case of volume has differ version set the key in status_arr instead
   of saving in a dictionary to make the operation is faster.

Note: To validate the changes followed below procedure
1) Setup 5100 distributed volumes 3x1
2) Enable brick_mux
3) Start all the volumes
4) Kill all gluster processes on 3rd node
5) Run a loop to update volume option on a 1st node
   for i in {1..5100}; do gluster v set vol$i performance.open-behind off; done
6) Start the glusterd process on the 3rd node
7) Wait to finish handshake and check there should not be any call_bail message
   in the logs

> Change-Id: Ibad7c23988539cc369ecc39dea2ea6985470bee1
> Fixes: #1613
> Signed-off-by: Mohit Agrawal <moagrawa@redhat.com>
> (Cherry pick from commit 12545d91eed27ff9abb0505a12c7d4e75b45a53e)
> (Reviewed on upstream link https://github.com/gluster/glusterfs/issues/1613)

Change-Id: Ibad7c23988539cc369ecc39dea2ea6985470bee1
BUG: 1898784
Signed-off-by: Mohit Agrawal <moagrawa@redhat.com>
Reviewed-on: https://code.engineering.redhat.com/gerrit/221193
Tested-by: RHGS Build Bot <nigelb@redhat.com>
Reviewed-by: Sunil Kumar Heggodu Gopala Acharya <sheggodu@redhat.com>
---
 libglusterfs/src/ctx.c                       |   4 +
 libglusterfs/src/dict.c                      | 166 ++++++++++++++++++++++++++-
 libglusterfs/src/globals.c                   |   2 -
 libglusterfs/src/glusterfs/dict.h            |   5 +
 libglusterfs/src/glusterfs/globals.h         |   2 +
 libglusterfs/src/libglusterfs.sym            |   1 +
 xlators/mgmt/glusterd/src/glusterd-handler.c |  39 ++++---
 xlators/mgmt/glusterd/src/glusterd-sm.c      |   6 +-
 xlators/mgmt/glusterd/src/glusterd-sm.h      |   1 +
 xlators/mgmt/glusterd/src/glusterd-utils.c   | 148 ++++++++++++++----------
 xlators/mgmt/glusterd/src/glusterd-utils.h   |   2 +-
 xlators/mgmt/glusterd/src/glusterd.h         |   8 +-
 12 files changed, 301 insertions(+), 83 deletions(-)

diff --git a/libglusterfs/src/ctx.c b/libglusterfs/src/ctx.c
index 4a001c2..ae1a77a 100644
--- a/libglusterfs/src/ctx.c
+++ b/libglusterfs/src/ctx.c
@@ -14,6 +14,7 @@
 #include "glusterfs/glusterfs.h"
 #include "timer-wheel.h"
 
+glusterfs_ctx_t *global_ctx = NULL;
 glusterfs_ctx_t *
 glusterfs_ctx_new()
 {
@@ -51,6 +52,9 @@ glusterfs_ctx_new()
     GF_ATOMIC_INIT(ctx->stats.max_dict_pairs, 0);
     GF_ATOMIC_INIT(ctx->stats.total_pairs_used, 0);
     GF_ATOMIC_INIT(ctx->stats.total_dicts_used, 0);
+
+    if (!global_ctx)
+        global_ctx = ctx;
 out:
     return ctx;
 }
diff --git a/libglusterfs/src/dict.c b/libglusterfs/src/dict.c
index d8cdda4..e5f619c 100644
--- a/libglusterfs/src/dict.c
+++ b/libglusterfs/src/dict.c
@@ -56,7 +56,13 @@ struct dict_cmp {
 static data_t *
 get_new_data()
 {
-    data_t *data = mem_get(THIS->ctx->dict_data_pool);
+    data_t *data = NULL;
+
+    if (global_ctx) {
+        data = mem_get(global_ctx->dict_data_pool);
+    } else {
+        data = mem_get(THIS->ctx->dict_data_pool);
+    }
 
     if (!data)
         return NULL;
@@ -3503,3 +3509,161 @@ unlock:
     UNLOCK(&dict->lock);
     return 0;
 }
+
+/* Popluate specific dictionary on the basis of passed key array at the
+   time of unserialize buffer
+*/
+int32_t
+dict_unserialize_specific_keys(char *orig_buf, int32_t size, dict_t **fill,
+                               char **suffix_key_arr, dict_t **specific_dict,
+                               int totkeycount)
+{
+    char *buf = orig_buf;
+    int ret = -1;
+    int32_t count = 0;
+    int i = 0;
+    int j = 0;
+
+    data_t *value = NULL;
+    char *key = NULL;
+    int32_t keylen = 0;
+    int32_t vallen = 0;
+    int32_t hostord = 0;
+    xlator_t *this = NULL;
+    int32_t keylenarr[totkeycount];
+
+    this = THIS;
+    GF_ASSERT(this);
+
+    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;
+    }
+
+    /* Compute specific key length and save in array */
+    for (i = 0; i < totkeycount; i++) {
+        keylenarr[i] = strlen(suffix_key_arr[i]);
+    }
+
+    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();
+
+        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;
+
+        ret = dict_addn(*fill, key, keylen, value);
+        if (ret < 0) {
+            data_destroy(value);
+            goto out;
+        }
+        for (j = 0; j < totkeycount; j++) {
+            if (keylen > keylenarr[j]) {
+                if (!strcmp(key + keylen - keylenarr[j], suffix_key_arr[j])) {
+                    ret = dict_addn(*specific_dict, key, keylen, value);
+                    break;
+                }
+            }
+        }
+
+        if (ret < 0)
+            goto out;
+    }
+
+    ret = 0;
+out:
+    return ret;
+}
diff --git a/libglusterfs/src/globals.c b/libglusterfs/src/globals.c
index e433ee8..30c15b6 100644
--- a/libglusterfs/src/globals.c
+++ b/libglusterfs/src/globals.c
@@ -96,7 +96,6 @@ const char *gf_upcall_list[GF_UPCALL_FLAGS_MAXVALUE] = {
 /* This global ctx is a bad hack to prevent some of the libgfapi crashes.
  * This should be removed once the patch on resource pool is accepted
  */
-glusterfs_ctx_t *global_ctx = NULL;
 pthread_mutex_t global_ctx_mutex = PTHREAD_MUTEX_INITIALIZER;
 xlator_t global_xlator;
 static int gf_global_mem_acct_enable = 1;
@@ -236,7 +235,6 @@ __glusterfs_this_location()
     if (*this_location == NULL) {
         thread_xlator = &global_xlator;
     }
-
     return this_location;
 }
 
diff --git a/libglusterfs/src/glusterfs/dict.h b/libglusterfs/src/glusterfs/dict.h
index 8239c7a..6e469c7 100644
--- a/libglusterfs/src/glusterfs/dict.h
+++ b/libglusterfs/src/glusterfs/dict.h
@@ -423,4 +423,9 @@ dict_has_key_from_array(dict_t *dict, char **strings, gf_boolean_t *result);
 
 int
 dict_serialized_length_lk(dict_t *this);
+
+int32_t
+dict_unserialize_specific_keys(char *orig_buf, int32_t size, dict_t **fill,
+                               char **specific_key_arr, dict_t **specific_dict,
+                               int totkeycount);
 #endif
diff --git a/libglusterfs/src/glusterfs/globals.h b/libglusterfs/src/glusterfs/globals.h
index cc145cd..33fb023 100644
--- a/libglusterfs/src/glusterfs/globals.h
+++ b/libglusterfs/src/glusterfs/globals.h
@@ -199,4 +199,6 @@ int
 gf_global_mem_acct_enable_get(void);
 int
 gf_global_mem_acct_enable_set(int val);
+
+extern glusterfs_ctx_t *global_ctx;
 #endif /* !_GLOBALS_H */
diff --git a/libglusterfs/src/libglusterfs.sym b/libglusterfs/src/libglusterfs.sym
index d060292..bc770e2 100644
--- a/libglusterfs/src/libglusterfs.sym
+++ b/libglusterfs/src/libglusterfs.sym
@@ -436,6 +436,7 @@ dict_clear_flag
 dict_check_flag
 dict_unref
 dict_unserialize
+dict_unserialize_specific_keys
 drop_token
 eh_destroy
 eh_dump
diff --git a/xlators/mgmt/glusterd/src/glusterd-handler.c b/xlators/mgmt/glusterd/src/glusterd-handler.c
index b8799ab..908361c 100644
--- a/xlators/mgmt/glusterd/src/glusterd-handler.c
+++ b/xlators/mgmt/glusterd/src/glusterd-handler.c
@@ -86,6 +86,9 @@ glusterd_big_locked_handler(rpcsvc_request_t *req, rpcsvc_actor actor_fn)
     return ret;
 }
 
+static char *specific_key_suffix[] = {".quota-cksum", ".ckusm", ".version",
+                                      ".quota-version", ".name"};
+
 static int
 glusterd_handle_friend_req(rpcsvc_request_t *req, uuid_t uuid, char *hostname,
                            int port, gd1_mgmt_friend_req *friend_req)
@@ -97,6 +100,8 @@ glusterd_handle_friend_req(rpcsvc_request_t *req, uuid_t uuid, char *hostname,
     char rhost[UNIX_PATH_MAX + 1] = {0};
     uuid_t friend_uuid = {0};
     dict_t *dict = NULL;
+    dict_t *peer_ver = NULL;
+    int totcount = sizeof(specific_key_suffix) / sizeof(specific_key_suffix[0]);
 
     gf_uuid_parse(uuid_utoa(uuid), friend_uuid);
     if (!port)
@@ -104,8 +109,19 @@ glusterd_handle_friend_req(rpcsvc_request_t *req, uuid_t uuid, char *hostname,
 
     ret = glusterd_remote_hostname_get(req, rhost, sizeof(rhost));
 
+    ctx = GF_CALLOC(1, sizeof(*ctx), gf_gld_mt_friend_req_ctx_t);
+    dict = dict_new();
+    peer_ver = dict_new();
+
     RCU_READ_LOCK;
 
+    if (!ctx || !dict || !peer_ver) {
+        gf_msg("glusterd", GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
+               "Unable to allocate memory");
+        ret = -1;
+        goto out;
+    }
+
     peerinfo = glusterd_peerinfo_find(uuid, rhost);
 
     if (peerinfo == NULL) {
@@ -130,28 +146,14 @@ glusterd_handle_friend_req(rpcsvc_request_t *req, uuid_t uuid, char *hostname,
     event->peername = gf_strdup(peerinfo->hostname);
     gf_uuid_copy(event->peerid, peerinfo->uuid);
 
-    ctx = GF_CALLOC(1, sizeof(*ctx), gf_gld_mt_friend_req_ctx_t);
-
-    if (!ctx) {
-        gf_msg("glusterd", GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
-               "Unable to allocate memory");
-        ret = -1;
-        goto out;
-    }
-
     gf_uuid_copy(ctx->uuid, uuid);
     if (hostname)
         ctx->hostname = gf_strdup(hostname);
     ctx->req = req;
 
-    dict = dict_new();
-    if (!dict) {
-        ret = -1;
-        goto out;
-    }
-
-    ret = dict_unserialize(friend_req->vols.vols_val, friend_req->vols.vols_len,
-                           &dict);
+    ret = dict_unserialize_specific_keys(
+        friend_req->vols.vols_val, friend_req->vols.vols_len, &dict,
+        specific_key_suffix, &peer_ver, totcount);
 
     if (ret)
         goto out;
@@ -159,6 +161,7 @@ glusterd_handle_friend_req(rpcsvc_request_t *req, uuid_t uuid, char *hostname,
         dict->extra_stdfree = friend_req->vols.vols_val;
 
     ctx->vols = dict;
+    ctx->peer_ver = peer_ver;
     event->ctx = ctx;
 
     ret = glusterd_friend_sm_inject_event(event);
@@ -188,6 +191,8 @@ out:
         } else {
             free(friend_req->vols.vols_val);
         }
+        if (peer_ver)
+            dict_unref(peer_ver);
         if (event)
             GF_FREE(event->peername);
         GF_FREE(event);
diff --git a/xlators/mgmt/glusterd/src/glusterd-sm.c b/xlators/mgmt/glusterd/src/glusterd-sm.c
index 044da3d..d10a792 100644
--- a/xlators/mgmt/glusterd/src/glusterd-sm.c
+++ b/xlators/mgmt/glusterd/src/glusterd-sm.c
@@ -106,6 +106,8 @@ glusterd_destroy_friend_req_ctx(glusterd_friend_req_ctx_t *ctx)
 
     if (ctx->vols)
         dict_unref(ctx->vols);
+    if (ctx->peer_ver)
+        dict_unref(ctx->peer_ver);
     GF_FREE(ctx->hostname);
     GF_FREE(ctx);
 }
@@ -936,8 +938,8 @@ glusterd_ac_handle_friend_add_req(glusterd_friend_sm_event_t *event, void *ctx)
     // Build comparison logic here.
     pthread_mutex_lock(&conf->import_volumes);
     {
-        ret = glusterd_compare_friend_data(ev_ctx->vols, &status,
-                                           event->peername);
+        ret = glusterd_compare_friend_data(ev_ctx->vols, ev_ctx->peer_ver,
+                                           &status, event->peername);
         if (ret) {
             pthread_mutex_unlock(&conf->import_volumes);
             goto out;
diff --git a/xlators/mgmt/glusterd/src/glusterd-sm.h b/xlators/mgmt/glusterd/src/glusterd-sm.h
index ce008ac..efdf68e 100644
--- a/xlators/mgmt/glusterd/src/glusterd-sm.h
+++ b/xlators/mgmt/glusterd/src/glusterd-sm.h
@@ -174,6 +174,7 @@ typedef struct glusterd_friend_req_ctx_ {
     rpcsvc_request_t *req;
     int port;
     dict_t *vols;
+    dict_t *peer_ver;  // Dictionary to save peer ver data
 } glusterd_friend_req_ctx_t;
 
 typedef struct glusterd_friend_update_ctx_ {
diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c
index f7030fb..cf32bd9 100644
--- a/xlators/mgmt/glusterd/src/glusterd-utils.c
+++ b/xlators/mgmt/glusterd/src/glusterd-utils.c
@@ -3709,12 +3709,14 @@ out:
     return ret;
 }
 
-int32_t
-glusterd_compare_friend_volume(dict_t *peer_data, int32_t count,
-                               int32_t *status, char *hostname)
+static int32_t
+glusterd_compare_friend_volume(dict_t *peer_data,
+                               glusterd_friend_synctask_args_t *arg,
+                               int32_t count, int32_t *status, char *hostname)
 {
     int32_t ret = -1;
     char key[64] = "";
+    char key_prefix[32];
     int keylen;
     glusterd_volinfo_t *volinfo = NULL;
     char *volname = NULL;
@@ -3726,15 +3728,20 @@ glusterd_compare_friend_volume(dict_t *peer_data, int32_t count,
     xlator_t *this = NULL;
 
     GF_ASSERT(peer_data);
+    GF_ASSERT(arg);
     GF_ASSERT(status);
 
     this = THIS;
     GF_ASSERT(this);
 
-    keylen = snprintf(key, sizeof(key), "volume%d.name", count);
-    ret = dict_get_strn(peer_data, key, keylen, &volname);
-    if (ret)
+    snprintf(key_prefix, sizeof(key_prefix), "volume%d", count);
+    keylen = snprintf(key, sizeof(key), "%s.name", key_prefix);
+    ret = dict_get_strn(arg->peer_ver_data, key, keylen, &volname);
+    if (ret) {
+        gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_GET_FAILED,
+                "Key=%s is NULL in peer_ver_data", key, NULL);
         goto out;
+    }
 
     ret = glusterd_volinfo_find(volname, &volinfo);
     if (ret) {
@@ -3750,10 +3757,13 @@ glusterd_compare_friend_volume(dict_t *peer_data, int32_t count,
         goto out;
     }
 
-    keylen = snprintf(key, sizeof(key), "volume%d.version", count);
-    ret = dict_get_int32n(peer_data, key, keylen, &version);
-    if (ret)
+    keylen = snprintf(key, sizeof(key), "%s.version", key_prefix);
+    ret = dict_get_int32n(arg->peer_ver_data, key, keylen, &version);
+    if (ret) {
+        gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_GET_FAILED,
+                "Key=%s is NULL in peer_ver_data", key, NULL);
         goto out;
+    }
 
     if (version > volinfo->version) {
         // Mismatch detected
@@ -3772,10 +3782,13 @@ glusterd_compare_friend_volume(dict_t *peer_data, int32_t count,
 
     // Now, versions are same, compare cksums.
     //
-    snprintf(key, sizeof(key), "volume%d.ckusm", count);
-    ret = dict_get_uint32(peer_data, key, &cksum);
-    if (ret)
+    snprintf(key, sizeof(key), "%s.ckusm", key_prefix);
+    ret = dict_get_uint32(arg->peer_ver_data, key, &cksum);
+    if (ret) {
+        gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_GET_FAILED,
+                "Key=%s is NULL in peer_ver_data", key, NULL);
         goto out;
+    }
 
     if (cksum != volinfo->cksum) {
         ret = 0;
@@ -3790,8 +3803,8 @@ glusterd_compare_friend_volume(dict_t *peer_data, int32_t count,
     if (!dict_get_sizen(volinfo->dict, VKEY_FEATURES_QUOTA))
         goto skip_quota;
 
-    snprintf(key, sizeof(key), "volume%d.quota-version", count);
-    ret = dict_get_uint32(peer_data, key, &quota_version);
+    snprintf(key, sizeof(key), "%s.quota-version", key_prefix);
+    ret = dict_get_uint32(arg->peer_ver_data, key, &quota_version);
     if (ret) {
         gf_msg_debug(this->name, 0,
                      "quota-version key absent for"
@@ -3809,6 +3822,7 @@ glusterd_compare_friend_volume(dict_t *peer_data, int32_t count,
                    "%d on peer %s",
                    volinfo->volname, volinfo->quota_conf_version, quota_version,
                    hostname);
+            GF_ATOMIC_INIT(volinfo->volpeerupdate, 1);
             *status = GLUSTERD_VOL_COMP_UPDATE_REQ;
             goto out;
         } else if (quota_version < volinfo->quota_conf_version) {
@@ -3819,8 +3833,8 @@ glusterd_compare_friend_volume(dict_t *peer_data, int32_t count,
 
     // Now, versions are same, compare cksums.
     //
-    snprintf(key, sizeof(key), "volume%d.quota-cksum", count);
-    ret = dict_get_uint32(peer_data, key, &quota_cksum);
+    snprintf(key, sizeof(key), "%s.quota-cksum", key_prefix);
+    ret = dict_get_uint32(arg->peer_ver_data, key, &quota_cksum);
     if (ret) {
         gf_msg_debug(this->name, 0,
                      "quota checksum absent for "
@@ -3846,13 +3860,12 @@ skip_quota:
     *status = GLUSTERD_VOL_COMP_SCS;
 
 out:
-    keylen = snprintf(key, sizeof(key), "volume%d.update", count);
-
     if (*status == GLUSTERD_VOL_COMP_UPDATE_REQ) {
-        ret = dict_set_int32n(peer_data, key, keylen, 1);
-    } else {
-        ret = dict_set_int32n(peer_data, key, keylen, 0);
+        /*Set the status to ensure volume is updated on the peer
+         */
+        arg->status_arr[(count / 64)] ^= 1UL << (count % 64);
     }
+
     if (*status == GLUSTERD_VOL_COMP_RJT) {
         gf_event(EVENT_COMPARE_FRIEND_VOLUME_FAILED, "volume=%s",
                  volinfo->volname);
@@ -4935,8 +4948,9 @@ out:
     return ret;
 }
 
-int32_t
-glusterd_import_friend_volume(dict_t *peer_data, int count)
+static int32_t
+glusterd_import_friend_volume(dict_t *peer_data, int count,
+                              glusterd_friend_synctask_args_t *arg)
 {
     int32_t ret = -1;
     glusterd_conf_t *priv = NULL;
@@ -4954,10 +4968,27 @@ glusterd_import_friend_volume(dict_t *peer_data, int count)
     priv = this->private;
     GF_ASSERT(priv);
 
-    ret = snprintf(key, sizeof(key), "volume%d.update", count);
-    ret = dict_get_int32n(peer_data, key, ret, &update);
-    if (ret || !update) {
+    if (arg) {
+        /*Check if the volume options are updated on the other peers
+         */
+        update = (1UL & (arg->status_arr[(count / 64)] >> (count % 64)));
+    } else {
+        ret = snprintf(key, sizeof(key), "volume%d.update", count);
+        ret = dict_get_int32n(peer_data, key, ret, &update);
+        if (ret) {
+            gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_GET_FAILED,
+                    "Key=%s", key, NULL);
+            goto out;
+        }
+    }
+
+    if (!update) {
         /* if update is 0 that means the volume is not imported */
+        gf_log(this->name, GF_LOG_DEBUG,
+               "The volume%d does"
+               " not have any peer change",
+               count);
+        ret = 0;
         goto out;
     }
 
@@ -5045,6 +5076,8 @@ glusterd_import_friend_volumes_synctask(void *opaque)
     glusterd_conf_t *conf = NULL;
     dict_t *peer_data = NULL;
     glusterd_friend_synctask_args_t *arg = NULL;
+    uint64_t bm = 0;
+    uint64_t mask = 0;
 
     this = THIS;
     GF_ASSERT(this);
@@ -5056,17 +5089,7 @@ glusterd_import_friend_volumes_synctask(void *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;
-    }
-
+    peer_data = arg->peer_data;
     ret = dict_get_int32n(peer_data, "count", SLEN("count"), &count);
     if (ret)
         goto out;
@@ -5083,11 +5106,18 @@ glusterd_import_friend_volumes_synctask(void *opaque)
     conf->restart_bricks = _gf_true;
 
     while (i <= count) {
-        ret = glusterd_import_friend_volume(peer_data, i);
-        if (ret) {
-            break;
+        bm = arg->status_arr[i / 64];
+        while (bm != 0) {
+            /* mask will contain the lowest bit set from bm. */
+            mask = bm & (-bm);
+            bm ^= mask;
+            ret = glusterd_import_friend_volume(peer_data, i + ffsll(mask) - 2,
+                                                arg);
+            if (ret < 0) {
+                break;
+            }
         }
-        i++;
+        i += 64;
     }
     if (i > count) {
         glusterd_svcs_manager(NULL);
@@ -5095,11 +5125,9 @@ glusterd_import_friend_volumes_synctask(void *opaque)
     conf->restart_bricks = _gf_false;
     synccond_broadcast(&conf->cond_restart_bricks);
 out:
-    if (peer_data)
-        dict_unref(peer_data);
     if (arg) {
-        if (arg->dict_buf)
-            GF_FREE(arg->dict_buf);
+        dict_unref(arg->peer_data);
+        dict_unref(arg->peer_ver_data);
         GF_FREE(arg);
     }
 
@@ -5121,7 +5149,7 @@ glusterd_import_friend_volumes(dict_t *peer_data)
         goto out;
 
     while (i <= count) {
-        ret = glusterd_import_friend_volume(peer_data, i);
+        ret = glusterd_import_friend_volume(peer_data, i, NULL);
         if (ret)
             goto out;
         i++;
@@ -5260,7 +5288,8 @@ out:
 }
 
 int32_t
-glusterd_compare_friend_data(dict_t *peer_data, int32_t *status, char *hostname)
+glusterd_compare_friend_data(dict_t *peer_data, dict_t *cmp, int32_t *status,
+                             char *hostname)
 {
     int32_t ret = -1;
     int32_t count = 0;
@@ -5289,8 +5318,19 @@ glusterd_compare_friend_data(dict_t *peer_data, int32_t *status, char *hostname)
     if (ret)
         goto out;
 
+    arg = GF_CALLOC(1, sizeof(*arg) + sizeof(uint64_t) * (count / 64),
+                    gf_common_mt_char);
+    if (!arg) {
+        ret = -1;
+        gf_msg("glusterd", GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
+               "Out Of Memory");
+        goto out;
+    }
+    arg->peer_data = dict_ref(peer_data);
+    arg->peer_ver_data = dict_ref(cmp);
     while (i <= count) {
-        ret = glusterd_compare_friend_volume(peer_data, i, status, hostname);
+        ret = glusterd_compare_friend_volume(peer_data, arg, i, status,
+                                             hostname);
         if (ret)
             goto out;
 
@@ -5310,21 +5350,13 @@ 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
          */
-        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) {
+        dict_unref(arg->peer_data);
+        dict_unref(arg->peer_ver_data);
         GF_FREE(arg);
     }
     gf_msg_debug(this->name, 0, "Returning with ret: %d, status: %d", ret,
diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.h b/xlators/mgmt/glusterd/src/glusterd-utils.h
index 5f5de82..02d85d2 100644
--- a/xlators/mgmt/glusterd/src/glusterd-utils.h
+++ b/xlators/mgmt/glusterd/src/glusterd-utils.h
@@ -231,7 +231,7 @@ 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,
+glusterd_compare_friend_data(dict_t *peer_data, dict_t *cmp, int32_t *status,
                              char *hostname);
 
 int
diff --git a/xlators/mgmt/glusterd/src/glusterd.h b/xlators/mgmt/glusterd/src/glusterd.h
index f739b5d..efe4d0e 100644
--- a/xlators/mgmt/glusterd/src/glusterd.h
+++ b/xlators/mgmt/glusterd/src/glusterd.h
@@ -234,8 +234,12 @@ typedef struct glusterd_add_dict_args {
 } glusterd_add_dict_args_t;
 
 typedef struct glusterd_friend_synctask_args {
-    char *dict_buf;
-    u_int dictlen;
+    dict_t *peer_data;
+    dict_t *peer_ver_data;  // Dictionary to save peer version data
+    /* This status_arr[1] is not a real size, real size of the array
+       is dynamically allocated
+    */
+    uint64_t status_arr[1];
 } glusterd_friend_synctask_args_t;
 
 typedef enum gf_brick_status {
-- 
1.8.3.1