14f8ab
From aff18f761ef64d55635daa9a1d2140fe35632820 Mon Sep 17 00:00:00 2001
14f8ab
From: Mohit Agrawal <moagrawal@redhat.com>
14f8ab
Date: Fri, 29 Mar 2019 11:48:32 +0530
14f8ab
Subject: [PATCH 109/124] glusterd: Optimize glusterd handshaking code path
14f8ab
14f8ab
Problem: At the time of handshaking glusterd populate volume
14f8ab
         data in a dictionary.While no. of volumes are configured
14f8ab
         more than 1500 glusterd takes more than 10 min to generated
14f8ab
         the data.Due to taking more time rpc request times out and
14f8ab
         rpc start bailing of call frames.
14f8ab
14f8ab
Solution: To optimize the code done below changes
14f8ab
          1) Spawn multiple threads to populate volumes data in bulk
14f8ab
             in separate dictionary and introduce an option
14f8ab
             glusterd.brick-dict-thread-count to configure no. of threads
14f8ab
             to populate volume data.
14f8ab
          2) Populate tier data only while volume type is tier
14f8ab
          3) Compare snap data only while snap_count is non zero
14f8ab
14f8ab
> Fixes: bz#1699339
14f8ab
> Change-Id: I38dc71970c049217f9d1a06fc0aaf4c26eab18f5
14f8ab
> Signed-off-by: Mohit Agrawal <moagrawal@redhat.com>
14f8ab
> (Cherry picked from commit 26a19d9da3ab5604db02d4ca02ce868fb57193a4)
14f8ab
> (Reviewed on upstream link https://review.gluster.org/#/c/glusterfs/+/22556/)
14f8ab
14f8ab
Bug: 1652461
14f8ab
Change-Id: Ia81671a7e1f173bcb32da9dc439be9e61c18bde1
14f8ab
Signed-off-by: Mohit Agrawal <moagrawal@redhat.com>
14f8ab
Reviewed-on: https://code.engineering.redhat.com/gerrit/167981
14f8ab
Tested-by: Mohit Agrawal <moagrawa@redhat.com>
14f8ab
Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
14f8ab
Tested-by: RHGS Build Bot <nigelb@redhat.com>
14f8ab
---
14f8ab
 libglusterfs/src/glusterfs/globals.h               |   4 +-
14f8ab
 tests/bugs/glusterd/bug-1699339.t                  |  69 ++++++
14f8ab
 xlators/mgmt/glusterd/src/glusterd-op-sm.c         |   1 +
14f8ab
 .../mgmt/glusterd/src/glusterd-snapshot-utils.c    |   3 +
14f8ab
 xlators/mgmt/glusterd/src/glusterd-utils.c         | 269 +++++++++++++++++----
14f8ab
 xlators/mgmt/glusterd/src/glusterd-volume-set.c    |  55 +++++
14f8ab
 xlators/mgmt/glusterd/src/glusterd.h               |  10 +
14f8ab
 7 files changed, 362 insertions(+), 49 deletions(-)
14f8ab
 create mode 100644 tests/bugs/glusterd/bug-1699339.t
14f8ab
14f8ab
diff --git a/libglusterfs/src/glusterfs/globals.h b/libglusterfs/src/glusterfs/globals.h
14f8ab
index 6642ba0..e45db14 100644
14f8ab
--- a/libglusterfs/src/glusterfs/globals.h
14f8ab
+++ b/libglusterfs/src/glusterfs/globals.h
14f8ab
@@ -50,7 +50,7 @@
14f8ab
     1 /* MIN is the fresh start op-version, mostly                             \
14f8ab
          should not change */
14f8ab
 #define GD_OP_VERSION_MAX                                                      \
14f8ab
-    GD_OP_VERSION_6_0 /* MAX VERSION is the maximum                            \
14f8ab
+    GD_OP_VERSION_7_0 /* MAX VERSION is the maximum                            \
14f8ab
                          count in VME table, should                            \
14f8ab
                          keep changing with                                    \
14f8ab
                          introduction of newer                                 \
14f8ab
@@ -134,6 +134,8 @@
14f8ab
 
14f8ab
 #define GD_OP_VERSION_6_0 60000 /* Op-version for GlusterFS 6.0 */
14f8ab
 
14f8ab
+#define GD_OP_VERSION_7_0 70000 /* Op-version for GlusterFS 7.0 */
14f8ab
+
14f8ab
 #include "glusterfs/xlator.h"
14f8ab
 #include "glusterfs/options.h"
14f8ab
 
14f8ab
diff --git a/tests/bugs/glusterd/bug-1699339.t b/tests/bugs/glusterd/bug-1699339.t
14f8ab
new file mode 100644
14f8ab
index 0000000..3e950f4
14f8ab
--- /dev/null
14f8ab
+++ b/tests/bugs/glusterd/bug-1699339.t
14f8ab
@@ -0,0 +1,69 @@
14f8ab
+#!/bin/bash
14f8ab
+
14f8ab
+. $(dirname $0)/../../include.rc
14f8ab
+. $(dirname $0)/../../volume.rc
14f8ab
+. $(dirname $0)/../../cluster.rc
14f8ab
+
14f8ab
+cleanup;
14f8ab
+
14f8ab
+NUM_VOLS=15
14f8ab
+
14f8ab
+
14f8ab
+get_brick_base () {
14f8ab
+	printf "%s/vol%02d" $B0 $1
14f8ab
+}
14f8ab
+
14f8ab
+function count_up_bricks {
14f8ab
+        vol=$1;
14f8ab
+        $CLI_1 --xml volume status $vol | grep '<status>1' | wc -l
14f8ab
+}
14f8ab
+
14f8ab
+create_volume () {
14f8ab
+
14f8ab
+	local vol_name=$(printf "%s-vol%02d" $V0 $1)
14f8ab
+
14f8ab
+        TEST $CLI_1 volume create $vol_name replica 3 $H1:$B1/${vol_name} $H2:$B2/${vol_name} $H3:$B3/${vol_name}
14f8ab
+	TEST $CLI_1 volume start $vol_name
14f8ab
+}
14f8ab
+
14f8ab
+TEST launch_cluster 3
14f8ab
+TEST $CLI_1 volume set all cluster.brick-multiplex on
14f8ab
+
14f8ab
+# The option accepts the value in the range from 5 to 200
14f8ab
+TEST ! $CLI_1 volume set all glusterd.vol_count_per_thread 210
14f8ab
+TEST ! $CLI_1 volume set all glusterd.vol_count_per_thread 4
14f8ab
+
14f8ab
+TEST $CLI_1 volume set all glusterd.vol_count_per_thread 5
14f8ab
+
14f8ab
+TEST $CLI_1 peer probe $H2;
14f8ab
+EXPECT_WITHIN $PROBE_TIMEOUT 1 peer_count
14f8ab
+
14f8ab
+TEST $CLI_1 peer probe $H3;
14f8ab
+EXPECT_WITHIN $PROBE_TIMEOUT 2 peer_count
14f8ab
+
14f8ab
+# Our infrastructure can't handle an arithmetic expression here.  The formula
14f8ab
+# is (NUM_VOLS-1)*5 because it sees each TEST/EXPECT once but needs the other
14f8ab
+# NUM_VOLS-1 and there are 5 such statements in each iteration.
14f8ab
+TESTS_EXPECTED_IN_LOOP=28
14f8ab
+for i in $(seq 1 $NUM_VOLS); do
14f8ab
+        starttime="$(date +%s)";
14f8ab
+	create_volume $i
14f8ab
+done
14f8ab
+
14f8ab
+TEST kill_glusterd 1
14f8ab
+
14f8ab
+vol1=$(printf "%s-vol%02d" $V0 1)
14f8ab
+TEST $CLI_2 volume set $vol1 performance.readdir-ahead on
14f8ab
+vol2=$(printf "%s-vol%02d" $V0 2)
14f8ab
+TEST $CLI_2 volume set $vol2 performance.readdir-ahead on
14f8ab
+
14f8ab
+# Bring back 1st glusterd
14f8ab
+TEST $glusterd_1
14f8ab
+EXPECT_WITHIN $PROBE_TIMEOUT 2 peer_count
14f8ab
+
14f8ab
+EXPECT_WITHIN $PROBE_TIMEOUT "on" volinfo_field_1 $vol1 performance.readdir-ahead
14f8ab
+
14f8ab
+vol_name=$(printf "%s-vol%02d" $V0 2)
14f8ab
+EXPECT_WITHIN $PROBE_TIMEOUT "on" volinfo_field_1 $vol2 performance.readdir-ahead
14f8ab
+
14f8ab
+cleanup
14f8ab
diff --git a/xlators/mgmt/glusterd/src/glusterd-op-sm.c b/xlators/mgmt/glusterd/src/glusterd-op-sm.c
14f8ab
index 95f9707..94a5e1f 100644
14f8ab
--- a/xlators/mgmt/glusterd/src/glusterd-op-sm.c
14f8ab
+++ b/xlators/mgmt/glusterd/src/glusterd-op-sm.c
14f8ab
@@ -87,6 +87,7 @@ glusterd_all_vol_opts valid_all_vol_opts[] = {
14f8ab
      * TBD: Discuss the default value for this. Maybe this should be a
14f8ab
      * dynamic value depending on the memory specifications per node */
14f8ab
     {GLUSTERD_BRICKMUX_LIMIT_KEY, GLUSTERD_BRICKMUX_LIMIT_DFLT_VALUE},
14f8ab
+    {GLUSTERD_VOL_CNT_PER_THRD, GLUSTERD_VOL_CNT_PER_THRD_DEFAULT_VALUE},
14f8ab
     /*{GLUSTERD_LOCALTIME_LOGGING_KEY, "disable"},*/
14f8ab
     {GLUSTERD_DAEMON_LOG_LEVEL_KEY, "INFO"},
14f8ab
     {NULL},
14f8ab
diff --git a/xlators/mgmt/glusterd/src/glusterd-snapshot-utils.c b/xlators/mgmt/glusterd/src/glusterd-snapshot-utils.c
14f8ab
index b3c4158..d225854 100644
14f8ab
--- a/xlators/mgmt/glusterd/src/glusterd-snapshot-utils.c
14f8ab
+++ b/xlators/mgmt/glusterd/src/glusterd-snapshot-utils.c
14f8ab
@@ -2099,6 +2099,9 @@ glusterd_compare_friend_snapshots(dict_t *peer_data, char *peername,
14f8ab
         goto out;
14f8ab
     }
14f8ab
 
14f8ab
+    if (!snap_count)
14f8ab
+        goto out;
14f8ab
+
14f8ab
     for (i = 1; i <= snap_count; i++) {
14f8ab
         /* Compare one snapshot from peer_data at a time */
14f8ab
         ret = glusterd_compare_snap(peer_data, i, peername, peerid);
14f8ab
diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c
14f8ab
index fdd7d91..ff6102b 100644
14f8ab
--- a/xlators/mgmt/glusterd/src/glusterd-utils.c
14f8ab
+++ b/xlators/mgmt/glusterd/src/glusterd-utils.c
14f8ab
@@ -155,6 +155,47 @@ out:
14f8ab
     return ret;
14f8ab
 }
14f8ab
 
14f8ab
+int
14f8ab
+get_gd_vol_thread_limit(int *thread_limit)
14f8ab
+{
14f8ab
+    char *value = NULL;
14f8ab
+    int ret = -1;
14f8ab
+    int vol_per_thread_limit = 0;
14f8ab
+    xlator_t *this = NULL;
14f8ab
+    glusterd_conf_t *priv = NULL;
14f8ab
+
14f8ab
+    this = THIS;
14f8ab
+    GF_VALIDATE_OR_GOTO("glusterd", this, out);
14f8ab
+
14f8ab
+    priv = this->private;
14f8ab
+    GF_VALIDATE_OR_GOTO(this->name, priv, out);
14f8ab
+
14f8ab
+    if (!is_brick_mx_enabled()) {
14f8ab
+        vol_per_thread_limit = 1;
14f8ab
+        ret = 0;
14f8ab
+        goto out;
14f8ab
+    }
14f8ab
+
14f8ab
+    ret = dict_get_strn(priv->opts, GLUSTERD_VOL_CNT_PER_THRD,
14f8ab
+                        SLEN(GLUSTERD_VOL_CNT_PER_THRD), &value);
14f8ab
+    if (ret) {
14f8ab
+        value = GLUSTERD_VOL_CNT_PER_THRD_DEFAULT_VALUE;
14f8ab
+    }
14f8ab
+    ret = gf_string2int(value, &vol_per_thread_limit);
14f8ab
+    if (ret)
14f8ab
+        goto out;
14f8ab
+
14f8ab
+out:
14f8ab
+    *thread_limit = vol_per_thread_limit;
14f8ab
+
14f8ab
+    gf_msg_debug("glusterd", 0,
14f8ab
+                 "Per Thread volume limit set to %d glusterd to populate dict "
14f8ab
+                 "data parallel",
14f8ab
+                 *thread_limit);
14f8ab
+
14f8ab
+    return ret;
14f8ab
+}
14f8ab
+
14f8ab
 extern struct volopt_map_entry glusterd_volopt_map[];
14f8ab
 extern glusterd_all_vol_opts valid_all_vol_opts[];
14f8ab
 
14f8ab
@@ -3070,50 +3111,55 @@ glusterd_add_volume_to_dict(glusterd_volinfo_t *volinfo, dict_t *dict,
14f8ab
 
14f8ab
     /* tiering related variables */
14f8ab
 
14f8ab
-    snprintf(key, sizeof(key), "%s%d.cold_brick_count", prefix, count);
14f8ab
-    ret = dict_set_uint32(dict, key, volinfo->tier_info.cold_brick_count);
14f8ab
-    if (ret)
14f8ab
-        goto out;
14f8ab
+    if (volinfo->type == GF_CLUSTER_TYPE_TIER) {
14f8ab
+        snprintf(key, sizeof(key), "%s%d.cold_brick_count", prefix, count);
14f8ab
+        ret = dict_set_uint32(dict, key, volinfo->tier_info.cold_brick_count);
14f8ab
+        if (ret)
14f8ab
+            goto out;
14f8ab
 
14f8ab
-    snprintf(key, sizeof(key), "%s%d.cold_type", prefix, count);
14f8ab
-    ret = dict_set_uint32(dict, key, volinfo->tier_info.cold_type);
14f8ab
-    if (ret)
14f8ab
-        goto out;
14f8ab
+        snprintf(key, sizeof(key), "%s%d.cold_type", prefix, count);
14f8ab
+        ret = dict_set_uint32(dict, key, volinfo->tier_info.cold_type);
14f8ab
+        if (ret)
14f8ab
+            goto out;
14f8ab
 
14f8ab
-    snprintf(key, sizeof(key), "%s%d.cold_replica_count", prefix, count);
14f8ab
-    ret = dict_set_uint32(dict, key, volinfo->tier_info.cold_replica_count);
14f8ab
-    if (ret)
14f8ab
-        goto out;
14f8ab
+        snprintf(key, sizeof(key), "%s%d.cold_replica_count", prefix, count);
14f8ab
+        ret = dict_set_uint32(dict, key, volinfo->tier_info.cold_replica_count);
14f8ab
+        if (ret)
14f8ab
+            goto out;
14f8ab
 
14f8ab
-    snprintf(key, sizeof(key), "%s%d.cold_disperse_count", prefix, count);
14f8ab
-    ret = dict_set_uint32(dict, key, volinfo->tier_info.cold_disperse_count);
14f8ab
-    if (ret)
14f8ab
-        goto out;
14f8ab
+        snprintf(key, sizeof(key), "%s%d.cold_disperse_count", prefix, count);
14f8ab
+        ret = dict_set_uint32(dict, key,
14f8ab
+                              volinfo->tier_info.cold_disperse_count);
14f8ab
+        if (ret)
14f8ab
+            goto out;
14f8ab
 
14f8ab
-    snprintf(key, sizeof(key), "%s%d.cold_redundancy_count", prefix, count);
14f8ab
-    ret = dict_set_uint32(dict, key, volinfo->tier_info.cold_redundancy_count);
14f8ab
-    if (ret)
14f8ab
-        goto out;
14f8ab
+        snprintf(key, sizeof(key), "%s%d.cold_redundancy_count", prefix, count);
14f8ab
+        ret = dict_set_uint32(dict, key,
14f8ab
+                              volinfo->tier_info.cold_redundancy_count);
14f8ab
+        if (ret)
14f8ab
+            goto out;
14f8ab
 
14f8ab
-    snprintf(key, sizeof(key), "%s%d.cold_dist_count", prefix, count);
14f8ab
-    ret = dict_set_uint32(dict, key, volinfo->tier_info.cold_dist_leaf_count);
14f8ab
-    if (ret)
14f8ab
-        goto out;
14f8ab
+        snprintf(key, sizeof(key), "%s%d.cold_dist_count", prefix, count);
14f8ab
+        ret = dict_set_uint32(dict, key,
14f8ab
+                              volinfo->tier_info.cold_dist_leaf_count);
14f8ab
+        if (ret)
14f8ab
+            goto out;
14f8ab
 
14f8ab
-    snprintf(key, sizeof(key), "%s%d.hot_brick_count", prefix, count);
14f8ab
-    ret = dict_set_uint32(dict, key, volinfo->tier_info.hot_brick_count);
14f8ab
-    if (ret)
14f8ab
-        goto out;
14f8ab
+        snprintf(key, sizeof(key), "%s%d.hot_brick_count", prefix, count);
14f8ab
+        ret = dict_set_uint32(dict, key, volinfo->tier_info.hot_brick_count);
14f8ab
+        if (ret)
14f8ab
+            goto out;
14f8ab
 
14f8ab
-    snprintf(key, sizeof(key), "%s%d.hot_type", prefix, count);
14f8ab
-    ret = dict_set_uint32(dict, key, volinfo->tier_info.hot_type);
14f8ab
-    if (ret)
14f8ab
-        goto out;
14f8ab
+        snprintf(key, sizeof(key), "%s%d.hot_type", prefix, count);
14f8ab
+        ret = dict_set_uint32(dict, key, volinfo->tier_info.hot_type);
14f8ab
+        if (ret)
14f8ab
+            goto out;
14f8ab
 
14f8ab
-    snprintf(key, sizeof(key), "%s%d.hot_replica_count", prefix, count);
14f8ab
-    ret = dict_set_uint32(dict, key, volinfo->tier_info.hot_replica_count);
14f8ab
-    if (ret)
14f8ab
-        goto out;
14f8ab
+        snprintf(key, sizeof(key), "%s%d.hot_replica_count", prefix, count);
14f8ab
+        ret = dict_set_uint32(dict, key, volinfo->tier_info.hot_replica_count);
14f8ab
+        if (ret)
14f8ab
+            goto out;
14f8ab
+    }
14f8ab
 
14f8ab
     snprintf(key, sizeof(key), "%s%d", prefix, count);
14f8ab
     ret = gd_add_vol_snap_details_to_dict(dict, key, volinfo);
14f8ab
@@ -3363,33 +3409,40 @@ out:
14f8ab
     return ret;
14f8ab
 }
14f8ab
 
14f8ab
-int32_t
14f8ab
-glusterd_add_volumes_to_export_dict(dict_t **peer_data)
14f8ab
+void *
14f8ab
+glusterd_add_bulk_volumes_create_thread(void *data)
14f8ab
 {
14f8ab
     int32_t ret = -1;
14f8ab
-    dict_t *dict = NULL;
14f8ab
     glusterd_conf_t *priv = NULL;
14f8ab
     glusterd_volinfo_t *volinfo = NULL;
14f8ab
     int32_t count = 0;
14f8ab
-    glusterd_dict_ctx_t ctx = {0};
14f8ab
     xlator_t *this = NULL;
14f8ab
+    glusterd_add_dict_args_t *arg = NULL;
14f8ab
+    dict_t *dict = NULL;
14f8ab
+    int start = 0;
14f8ab
+    int end = 0;
14f8ab
 
14f8ab
-    this = THIS;
14f8ab
-    GF_ASSERT(this);
14f8ab
+    GF_ASSERT(data);
14f8ab
+
14f8ab
+    arg = data;
14f8ab
+    dict = arg->voldict;
14f8ab
+    start = arg->start;
14f8ab
+    end = arg->end;
14f8ab
+    this = arg->this;
14f8ab
+    THIS = arg->this;
14f8ab
     priv = this->private;
14f8ab
     GF_ASSERT(priv);
14f8ab
 
14f8ab
-    dict = dict_new();
14f8ab
-    if (!dict)
14f8ab
-        goto out;
14f8ab
-
14f8ab
     cds_list_for_each_entry(volinfo, &priv->volumes, vol_list)
14f8ab
     {
14f8ab
         count++;
14f8ab
+        if ((count < start) || (count > end))
14f8ab
+            continue;
14f8ab
+
14f8ab
         ret = glusterd_add_volume_to_dict(volinfo, dict, count, "volume");
14f8ab
         if (ret)
14f8ab
             goto out;
14f8ab
-        if (!glusterd_is_volume_quota_enabled(volinfo))
14f8ab
+        if (!dict_get_sizen(volinfo->dict, VKEY_FEATURES_QUOTA))
14f8ab
             continue;
14f8ab
         ret = glusterd_vol_add_quota_conf_to_dict(volinfo, dict, count,
14f8ab
                                                   "volume");
14f8ab
@@ -3397,7 +3450,122 @@ glusterd_add_volumes_to_export_dict(dict_t **peer_data)
14f8ab
             goto out;
14f8ab
     }
14f8ab
 
14f8ab
-    ret = dict_set_int32n(dict, "count", SLEN("count"), count);
14f8ab
+out:
14f8ab
+    GF_ATOMIC_DEC(priv->thread_count);
14f8ab
+    free(arg);
14f8ab
+    return NULL;
14f8ab
+}
14f8ab
+
14f8ab
+int32_t
14f8ab
+glusterd_add_volumes_to_export_dict(dict_t **peer_data)
14f8ab
+{
14f8ab
+    int32_t ret = -1;
14f8ab
+    dict_t *dict = NULL;
14f8ab
+    dict_t *dict_arr[128] = {
14f8ab
+        0,
14f8ab
+    };
14f8ab
+    glusterd_conf_t *priv = NULL;
14f8ab
+    glusterd_volinfo_t *volinfo = NULL;
14f8ab
+    int32_t count = 0;
14f8ab
+    glusterd_dict_ctx_t ctx = {0};
14f8ab
+    xlator_t *this = NULL;
14f8ab
+    int totthread = 0;
14f8ab
+    int volcnt = 0;
14f8ab
+    int start = 1;
14f8ab
+    int endindex = 0;
14f8ab
+    int vol_per_thread_limit = 0;
14f8ab
+    glusterd_add_dict_args_t *arg = NULL;
14f8ab
+    pthread_t th_id = {
14f8ab
+        0,
14f8ab
+    };
14f8ab
+    int th_ret = 0;
14f8ab
+    int i = 0;
14f8ab
+
14f8ab
+    this = THIS;
14f8ab
+    GF_ASSERT(this);
14f8ab
+    priv = this->private;
14f8ab
+    GF_ASSERT(priv);
14f8ab
+
14f8ab
+    dict = dict_new();
14f8ab
+    if (!dict)
14f8ab
+        goto out;
14f8ab
+
14f8ab
+    /* Count the total number of volumes */
14f8ab
+    cds_list_for_each_entry(volinfo, &priv->volumes, vol_list) volcnt++;
14f8ab
+
14f8ab
+    get_gd_vol_thread_limit(&vol_per_thread_limit);
14f8ab
+
14f8ab
+    if ((vol_per_thread_limit == 1) || (vol_per_thread_limit > 100)) {
14f8ab
+        totthread = 0;
14f8ab
+    } else {
14f8ab
+        totthread = volcnt / vol_per_thread_limit;
14f8ab
+        endindex = volcnt % vol_per_thread_limit;
14f8ab
+        if (endindex)
14f8ab
+            totthread++;
14f8ab
+    }
14f8ab
+
14f8ab
+    if (totthread == 0) {
14f8ab
+        cds_list_for_each_entry(volinfo, &priv->volumes, vol_list)
14f8ab
+        {
14f8ab
+            count++;
14f8ab
+            ret = glusterd_add_volume_to_dict(volinfo, dict, count, "volume");
14f8ab
+            if (ret)
14f8ab
+                goto out;
14f8ab
+
14f8ab
+            if (!dict_get_sizen(volinfo->dict, VKEY_FEATURES_QUOTA))
14f8ab
+                continue;
14f8ab
+
14f8ab
+            ret = glusterd_vol_add_quota_conf_to_dict(volinfo, dict, count,
14f8ab
+                                                      "volume");
14f8ab
+            if (ret)
14f8ab
+                goto out;
14f8ab
+        }
14f8ab
+    } else {
14f8ab
+        for (i = 0; i < totthread; i++) {
14f8ab
+            arg = calloc(1, sizeof(*arg));
14f8ab
+            dict_arr[i] = dict_new();
14f8ab
+            arg->this = this;
14f8ab
+            arg->voldict = dict_arr[i];
14f8ab
+            arg->start = start;
14f8ab
+            if (!endindex) {
14f8ab
+                arg->end = ((i + 1) * vol_per_thread_limit);
14f8ab
+            } else {
14f8ab
+                arg->end = (start + endindex);
14f8ab
+            }
14f8ab
+            th_ret = gf_thread_create_detached(
14f8ab
+                &th_id, glusterd_add_bulk_volumes_create_thread, arg,
14f8ab
+                "bulkvoldict");
14f8ab
+            if (th_ret) {
14f8ab
+                gf_log(this->name, GF_LOG_ERROR,
14f8ab
+                       "glusterd_add_bulk_volume %s"
14f8ab
+                       " thread creation failed",
14f8ab
+                       "bulkvoldict");
14f8ab
+                free(arg);
14f8ab
+                goto out;
14f8ab
+            }
14f8ab
+
14f8ab
+            start = start + vol_per_thread_limit;
14f8ab
+            GF_ATOMIC_INC(priv->thread_count);
14f8ab
+            gf_log(this->name, GF_LOG_INFO,
14f8ab
+                   "Create thread %d to populate dict data for volume"
14f8ab
+                   " start index is %d end index is %d",
14f8ab
+                   (i + 1), arg->start, arg->end);
14f8ab
+        }
14f8ab
+        while (GF_ATOMIC_GET(priv->thread_count)) {
14f8ab
+            sleep(1);
14f8ab
+        }
14f8ab
+
14f8ab
+        gf_log(this->name, GF_LOG_INFO,
14f8ab
+               "Finished dictionary popluation in all threads");
14f8ab
+        for (i = 0; i < totthread; i++) {
14f8ab
+            dict_copy_with_ref(dict_arr[i], dict);
14f8ab
+            dict_unref(dict_arr[i]);
14f8ab
+        }
14f8ab
+        gf_log(this->name, GF_LOG_INFO,
14f8ab
+               "Finished merger of all dictionraies into single one");
14f8ab
+    }
14f8ab
+
14f8ab
+    ret = dict_set_int32n(dict, "count", SLEN("count"), volcnt);
14f8ab
     if (ret)
14f8ab
         goto out;
14f8ab
 
14f8ab
@@ -3499,6 +3667,9 @@ glusterd_compare_friend_volume(dict_t *peer_data, int32_t count,
14f8ab
         goto out;
14f8ab
     }
14f8ab
 
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
     if (ret) {
14f8ab
@@ -3550,6 +3721,8 @@ glusterd_compare_friend_volume(dict_t *peer_data, int32_t count,
14f8ab
             goto out;
14f8ab
         }
14f8ab
     }
14f8ab
+
14f8ab
+skip_quota:
14f8ab
     *status = GLUSTERD_VOL_COMP_SCS;
14f8ab
 
14f8ab
 out:
14f8ab
diff --git a/xlators/mgmt/glusterd/src/glusterd-volume-set.c b/xlators/mgmt/glusterd/src/glusterd-volume-set.c
14f8ab
index 42ca9bb..10aa2ae 100644
14f8ab
--- a/xlators/mgmt/glusterd/src/glusterd-volume-set.c
14f8ab
+++ b/xlators/mgmt/glusterd/src/glusterd-volume-set.c
14f8ab
@@ -1058,6 +1058,51 @@ out:
14f8ab
 }
14f8ab
 
14f8ab
 static int
14f8ab
+validate_volume_per_thread_limit(glusterd_volinfo_t *volinfo, dict_t *dict,
14f8ab
+                                 char *key, char *value, char **op_errstr)
14f8ab
+{
14f8ab
+    xlator_t *this = NULL;
14f8ab
+    uint val = 0;
14f8ab
+    int ret = -1;
14f8ab
+
14f8ab
+    this = THIS;
14f8ab
+    GF_VALIDATE_OR_GOTO("glusterd", this, out);
14f8ab
+
14f8ab
+    if (!is_brick_mx_enabled()) {
14f8ab
+        gf_asprintf(op_errstr,
14f8ab
+                    "Brick-multiplexing is not enabled. "
14f8ab
+                    "Please enable brick multiplexing before trying "
14f8ab
+                    "to set this option.");
14f8ab
+        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_WRONG_OPTS_SETTING, "%s",
14f8ab
+               *op_errstr);
14f8ab
+        goto out;
14f8ab
+    }
14f8ab
+
14f8ab
+    ret = gf_string2uint(value, &val;;
14f8ab
+    if (ret) {
14f8ab
+        gf_asprintf(op_errstr,
14f8ab
+                    "%s is not a valid count. "
14f8ab
+                    "%s expects an unsigned integer.",
14f8ab
+                    value, key);
14f8ab
+        gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_INVALID_ENTRY, "%s",
14f8ab
+               *op_errstr);
14f8ab
+    }
14f8ab
+
14f8ab
+    if ((val < 5) || (val > 200)) {
14f8ab
+        gf_asprintf(
14f8ab
+            op_errstr,
14f8ab
+            "Please set this option to a greater than 5 or less than 200 "
14f8ab
+            "to optimize dict generated while no. of volumes are more");
14f8ab
+        ret = -1;
14f8ab
+        goto out;
14f8ab
+    }
14f8ab
+out:
14f8ab
+    gf_msg_debug("glusterd", 0, "Returning %d", ret);
14f8ab
+
14f8ab
+    return ret;
14f8ab
+}
14f8ab
+
14f8ab
+static int
14f8ab
 validate_boolean(glusterd_volinfo_t *volinfo, dict_t *dict, char *key,
14f8ab
                  char *value, char **op_errstr)
14f8ab
 {
14f8ab
@@ -3520,6 +3565,16 @@ struct volopt_map_entry glusterd_volopt_map[] = {
14f8ab
                     "brick multiplexing. Brick multiplexing ensures that "
14f8ab
                     "compatible brick instances can share one single "
14f8ab
                     "brick process."},
14f8ab
+    {.key = GLUSTERD_VOL_CNT_PER_THRD,
14f8ab
+     .voltype = "mgmt/glusterd",
14f8ab
+     .value = GLUSTERD_VOL_CNT_PER_THRD_DEFAULT_VALUE,
14f8ab
+     .op_version = GD_OP_VERSION_7_0,
14f8ab
+     .validate_fn = validate_volume_per_thread_limit,
14f8ab
+     .type = GLOBAL_NO_DOC,
14f8ab
+     .description =
14f8ab
+         "This option can be used to limit the number of volumes "
14f8ab
+         "handled by per thread to populate peer data.The option accepts "
14f8ab
+         " the value in the range of 5 to 200"},
14f8ab
     {.key = GLUSTERD_BRICKMUX_LIMIT_KEY,
14f8ab
      .voltype = "mgmt/glusterd",
14f8ab
      .value = GLUSTERD_BRICKMUX_LIMIT_DFLT_VALUE,
14f8ab
diff --git a/xlators/mgmt/glusterd/src/glusterd.h b/xlators/mgmt/glusterd/src/glusterd.h
14f8ab
index 0ac6e63..bd9f509 100644
14f8ab
--- a/xlators/mgmt/glusterd/src/glusterd.h
14f8ab
+++ b/xlators/mgmt/glusterd/src/glusterd.h
14f8ab
@@ -57,8 +57,10 @@
14f8ab
 #define GLUSTER_SHARED_STORAGE "gluster_shared_storage"
14f8ab
 #define GLUSTERD_SHARED_STORAGE_KEY "cluster.enable-shared-storage"
14f8ab
 #define GLUSTERD_BRICK_MULTIPLEX_KEY "cluster.brick-multiplex"
14f8ab
+#define GLUSTERD_VOL_CNT_PER_THRD "glusterd.vol_count_per_thread"
14f8ab
 #define GLUSTERD_BRICKMUX_LIMIT_KEY "cluster.max-bricks-per-process"
14f8ab
 #define GLUSTERD_BRICKMUX_LIMIT_DFLT_VALUE "250"
14f8ab
+#define GLUSTERD_VOL_CNT_PER_THRD_DEFAULT_VALUE "100"
14f8ab
 #define GLUSTERD_LOCALTIME_LOGGING_KEY "cluster.localtime-logging"
14f8ab
 #define GLUSTERD_DAEMON_LOG_LEVEL_KEY "cluster.daemon-log-level"
14f8ab
 
14f8ab
@@ -225,8 +227,16 @@ typedef struct {
14f8ab
                                     which might lead the modification of volinfo
14f8ab
                                     list.
14f8ab
                                  */
14f8ab
+    gf_atomic_t thread_count;
14f8ab
 } glusterd_conf_t;
14f8ab
 
14f8ab
+typedef struct glusterd_add_dict_args {
14f8ab
+    xlator_t *this;
14f8ab
+    dict_t *voldict;
14f8ab
+    int start;
14f8ab
+    int end;
14f8ab
+} glusterd_add_dict_args_t;
14f8ab
+
14f8ab
 typedef enum gf_brick_status {
14f8ab
     GF_BRICK_STOPPED,
14f8ab
     GF_BRICK_STARTED,
14f8ab
-- 
14f8ab
1.8.3.1
14f8ab