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