d1681e
From 8503ed9b94777d47352f19ebfa844e151352b87f Mon Sep 17 00:00:00 2001
d1681e
From: Milind Changire <mchangir@redhat.com>
d1681e
Date: Fri, 2 Mar 2018 15:39:27 +0530
d1681e
Subject: [PATCH 166/180] rpcsvc: scale rpcsvc_request_handler threads
d1681e
d1681e
Scale rpcsvc_request_handler threads to match the scaling of event
d1681e
handler threads.
d1681e
d1681e
Please refer to https://bugzilla.redhat.com/show_bug.cgi?id=1467614#c51
d1681e
for a discussion about why we need multi-threaded rpcsvc request
d1681e
handlers.
d1681e
d1681e
mainline:
d1681e
> Reviewed-on: https://review.gluster.org/19337
d1681e
> Reviewed-by: Raghavendra G <rgowdapp@redhat.com>
d1681e
> Signed-off-by: Milind Changire <mchangir@redhat.com>
d1681e
(cherry picked from commit 7d641313f46789ec0a7ba0cc04f504724c780855)
d1681e
d1681e
Change-Id: Ib6838fb8b928e15602a3d36fd66b7ba08999430b
d1681e
BUG: 1549497
d1681e
Signed-off-by: Milind Changire <mchangir@redhat.com>
d1681e
Reviewed-on: https://code.engineering.redhat.com/gerrit/131596
d1681e
Tested-by: RHGS Build Bot <nigelb@redhat.com>
d1681e
Reviewed-by: Raghavendra Gowdappa <rgowdapp@redhat.com>
d1681e
---
d1681e
 glusterfsd/src/Makefile.am           |   1 +
d1681e
 glusterfsd/src/glusterfsd-mgmt.c     |  16 ++++-
d1681e
 glusterfsd/src/glusterfsd.h          |   2 +-
d1681e
 libglusterfs/src/event-poll.c        |   7 ++
d1681e
 rpc/rpc-lib/src/rpcsvc.c             | 129 +++++++++++++++++++++++++++++++----
d1681e
 rpc/rpc-lib/src/rpcsvc.h             |   8 +++
d1681e
 xlators/protocol/server/src/server.c |  10 ++-
d1681e
 7 files changed, 153 insertions(+), 20 deletions(-)
d1681e
d1681e
diff --git a/glusterfsd/src/Makefile.am b/glusterfsd/src/Makefile.am
d1681e
index 0196204..8ab585c 100644
d1681e
--- a/glusterfsd/src/Makefile.am
d1681e
+++ b/glusterfsd/src/Makefile.am
d1681e
@@ -22,6 +22,7 @@ AM_CPPFLAGS = $(GF_CPPFLAGS) \
d1681e
 	-I$(top_srcdir)/rpc/xdr/src \
d1681e
 	-I$(top_builddir)/rpc/xdr/src \
d1681e
 	-I$(top_srcdir)/xlators/nfs/server/src \
d1681e
+	-I$(top_srcdir)/xlators/protocol/server/src \
d1681e
 	-I$(top_srcdir)/api/src
d1681e
 
d1681e
 AM_CFLAGS = -Wall $(GF_CFLAGS)
d1681e
diff --git a/glusterfsd/src/glusterfsd-mgmt.c b/glusterfsd/src/glusterfsd-mgmt.c
d1681e
index ca706d1..69d93f5 100644
d1681e
--- a/glusterfsd/src/glusterfsd-mgmt.c
d1681e
+++ b/glusterfsd/src/glusterfsd-mgmt.c
d1681e
@@ -33,6 +33,7 @@
d1681e
 #include "syncop.h"
d1681e
 #include "xlator.h"
d1681e
 #include "syscall.h"
d1681e
+#include "server.h"
d1681e
 
d1681e
 static gf_boolean_t is_mgmt_rpc_reconnect = _gf_false;
d1681e
 int need_emancipate = 0;
d1681e
@@ -185,12 +186,15 @@ glusterfs_terminate_response_send (rpcsvc_request_t *req, int op_ret)
d1681e
 }
d1681e
 
d1681e
 void
d1681e
-glusterfs_autoscale_threads (glusterfs_ctx_t *ctx, int incr)
d1681e
+glusterfs_autoscale_threads (glusterfs_ctx_t *ctx, int incr, xlator_t *this)
d1681e
 {
d1681e
         struct event_pool       *pool           = ctx->event_pool;
d1681e
+        server_conf_t           *conf           = this->private;
d1681e
+        int                      thread_count   = pool->eventthreadcount;
d1681e
 
d1681e
         pool->auto_thread_count += incr;
d1681e
-        (void) event_reconfigure_threads (pool, pool->eventthreadcount+incr);
d1681e
+        (void) event_reconfigure_threads (pool, thread_count+incr);
d1681e
+        rpcsvc_ownthread_reconf (conf->rpc, pool->eventthreadcount);
d1681e
 }
d1681e
 
d1681e
 int
d1681e
@@ -839,6 +843,7 @@ glusterfs_handle_attach (rpcsvc_request_t *req)
d1681e
         xlator_t                *nextchild      = NULL;
d1681e
         glusterfs_graph_t       *newgraph       = NULL;
d1681e
         glusterfs_ctx_t         *ctx            = NULL;
d1681e
+        xlator_t                *protocol_server = NULL;
d1681e
 
d1681e
         GF_ASSERT (req);
d1681e
         this = THIS;
d1681e
@@ -876,7 +881,12 @@ glusterfs_handle_attach (rpcsvc_request_t *req)
d1681e
                                                 nextchild->name);
d1681e
                                         goto out;
d1681e
                                 }
d1681e
-                                glusterfs_autoscale_threads (this->ctx, 1);
d1681e
+                                /* we need a protocol/server xlator as
d1681e
+                                 * nextchild
d1681e
+                                 */
d1681e
+                                protocol_server = this->ctx->active->first;
d1681e
+                                glusterfs_autoscale_threads (this->ctx, 1,
d1681e
+                                                             protocol_server);
d1681e
                         }
d1681e
                 } else {
d1681e
                         gf_log (this->name, GF_LOG_WARNING,
d1681e
diff --git a/glusterfsd/src/glusterfsd.h b/glusterfsd/src/glusterfsd.h
d1681e
index 6d1e165..43cef52 100644
d1681e
--- a/glusterfsd/src/glusterfsd.h
d1681e
+++ b/glusterfsd/src/glusterfsd.h
d1681e
@@ -124,7 +124,7 @@ int glusterfs_volume_top_read_perf (uint32_t blk_size, uint32_t blk_count,
d1681e
                                     char *brick_path, double *throughput,
d1681e
                                     double *time);
d1681e
 void
d1681e
-glusterfs_autoscale_threads (glusterfs_ctx_t *ctx, int incr);
d1681e
+glusterfs_autoscale_threads (glusterfs_ctx_t *ctx, int incr, xlator_t *this);
d1681e
 
d1681e
 extern glusterfs_ctx_t *glusterfsd_ctx;
d1681e
 #endif /* __GLUSTERFSD_H__ */
d1681e
diff --git a/libglusterfs/src/event-poll.c b/libglusterfs/src/event-poll.c
d1681e
index 3bffc47..b1aca82 100644
d1681e
--- a/libglusterfs/src/event-poll.c
d1681e
+++ b/libglusterfs/src/event-poll.c
d1681e
@@ -173,6 +173,13 @@ event_pool_new_poll (int count, int eventthreadcount)
d1681e
                         "thread count (%d) ignored", eventthreadcount);
d1681e
         }
d1681e
 
d1681e
+        /* although, eventhreadcount for poll implementaiton is always
d1681e
+         * going to be 1, eventthreadcount needs to be set to 1 so that
d1681e
+         * rpcsvc_request_handler() thread scaling works flawlessly in
d1681e
+         * both epoll and poll models
d1681e
+         */
d1681e
+        event_pool->eventthreadcount = 1;
d1681e
+
d1681e
         return event_pool;
d1681e
 }
d1681e
 
d1681e
diff --git a/rpc/rpc-lib/src/rpcsvc.c b/rpc/rpc-lib/src/rpcsvc.c
d1681e
index 68e27ab..31b5eb5 100644
d1681e
--- a/rpc/rpc-lib/src/rpcsvc.c
d1681e
+++ b/rpc/rpc-lib/src/rpcsvc.c
d1681e
@@ -1877,39 +1877,105 @@ rpcsvc_request_handler (void *arg)
d1681e
                                 goto unlock;
d1681e
                         }
d1681e
 
d1681e
-                        while (list_empty (&program->request_queue))
d1681e
+                        while (list_empty (&program->request_queue) &&
d1681e
+                               (program->threadcount <=
d1681e
+                                        program->eventthreadcount)) {
d1681e
                                 pthread_cond_wait (&program->queue_cond,
d1681e
                                                    &program->queue_lock);
d1681e
+                        }
d1681e
 
d1681e
-                        req = list_entry (program->request_queue.next,
d1681e
-                                          typeof (*req), request_list);
d1681e
-
d1681e
-                        list_del_init (&req->request_list);
d1681e
+                        if (program->threadcount > program->eventthreadcount) {
d1681e
+                                done = 1;
d1681e
+                                program->threadcount--;
d1681e
+
d1681e
+                                gf_log (GF_RPCSVC, GF_LOG_INFO,
d1681e
+                                        "program '%s' thread terminated; "
d1681e
+                                        "total count:%d",
d1681e
+                                        program->progname,
d1681e
+                                        program->threadcount);
d1681e
+                        } else if (!list_empty (&program->request_queue)) {
d1681e
+                                req = list_entry (program->request_queue.next,
d1681e
+                                                  typeof (*req), request_list);
d1681e
+
d1681e
+                                list_del_init (&req->request_list);
d1681e
+                        }
d1681e
                 }
d1681e
         unlock:
d1681e
                 pthread_mutex_unlock (&program->queue_lock);
d1681e
 
d1681e
+                if (req) {
d1681e
+                        THIS = req->svc->xl;
d1681e
+                        actor = rpcsvc_program_actor (req);
d1681e
+                        ret = actor->actor (req);
d1681e
+
d1681e
+                        if (ret != 0) {
d1681e
+                                rpcsvc_check_and_reply_error (ret, NULL, req);
d1681e
+                        }
d1681e
+                        req = NULL;
d1681e
+                }
d1681e
+
d1681e
                 if (done)
d1681e
                         break;
d1681e
+        }
d1681e
 
d1681e
-                THIS = req->svc->xl;
d1681e
+        return NULL;
d1681e
+}
d1681e
 
d1681e
-                actor = rpcsvc_program_actor (req);
d1681e
+int
d1681e
+rpcsvc_spawn_threads (rpcsvc_t *svc, rpcsvc_program_t *program)
d1681e
+{
d1681e
+        int                ret  = 0, delta = 0, creates = 0;
d1681e
 
d1681e
-                ret = actor->actor (req);
d1681e
+        if (!program || !svc)
d1681e
+                goto out;
d1681e
 
d1681e
-                if (ret != 0) {
d1681e
-                        rpcsvc_check_and_reply_error (ret, NULL, req);
d1681e
+        pthread_mutex_lock (&program->queue_lock);
d1681e
+        {
d1681e
+                delta = program->eventthreadcount - program->threadcount;
d1681e
+
d1681e
+                if (delta >= 0) {
d1681e
+                        while (delta--) {
d1681e
+                                ret = gf_thread_create (&program->thread, NULL,
d1681e
+                                                        rpcsvc_request_handler,
d1681e
+                                                        program, "rpcrqhnd");
d1681e
+                                if (!ret) {
d1681e
+                                        program->threadcount++;
d1681e
+                                        creates++;
d1681e
+                                }
d1681e
+                        }
d1681e
+
d1681e
+                        if (creates) {
d1681e
+                                gf_log (GF_RPCSVC, GF_LOG_INFO,
d1681e
+                                        "spawned %d threads for program '%s'; "
d1681e
+                                        "total count:%d",
d1681e
+                                        creates,
d1681e
+                                        program->progname,
d1681e
+                                        program->threadcount);
d1681e
+                        }
d1681e
+                } else {
d1681e
+                        gf_log (GF_RPCSVC, GF_LOG_INFO,
d1681e
+                                "terminating %d threads for program '%s'",
d1681e
+                                -delta, program->progname);
d1681e
+
d1681e
+                        /* this signal is to just wake up the threads so they
d1681e
+                         * test for the change in eventthreadcount and kill
d1681e
+                         * themselves until the program thread count becomes
d1681e
+                         * equal to the event thread count
d1681e
+                         */
d1681e
+                        pthread_cond_broadcast (&program->queue_cond);
d1681e
                 }
d1681e
         }
d1681e
+        pthread_mutex_unlock (&program->queue_lock);
d1681e
 
d1681e
-        return NULL;
d1681e
+out:
d1681e
+        return creates;
d1681e
 }
d1681e
 
d1681e
 int
d1681e
 rpcsvc_program_register (rpcsvc_t *svc, rpcsvc_program_t *program)
d1681e
 {
d1681e
         int               ret                = -1;
d1681e
+        int               creates            = -1;
d1681e
         rpcsvc_program_t *newprog            = NULL;
d1681e
         char              already_registered = 0;
d1681e
 
d1681e
@@ -1957,9 +2023,12 @@ rpcsvc_program_register (rpcsvc_t *svc, rpcsvc_program_t *program)
d1681e
                 newprog->ownthread = _gf_false;
d1681e
 
d1681e
         if (newprog->ownthread) {
d1681e
-                gf_thread_create (&newprog->thread, NULL,
d1681e
-                                  rpcsvc_request_handler,
d1681e
-                                  newprog, "rpcsvcrh");
d1681e
+                newprog->eventthreadcount = 1;
d1681e
+                creates = rpcsvc_spawn_threads (svc, newprog);
d1681e
+
d1681e
+                if (creates < 1) {
d1681e
+                        goto out;
d1681e
+                }
d1681e
         }
d1681e
 
d1681e
         pthread_mutex_lock (&svc->rpclock);
d1681e
@@ -2816,6 +2885,38 @@ out:
d1681e
         return ret;
d1681e
 }
d1681e
 
d1681e
+/* During reconfigure, Make sure to call this function after event-threads are
d1681e
+ * reconfigured as programs' threadcount will be made equal to event threads.
d1681e
+ */
d1681e
+
d1681e
+int
d1681e
+rpcsvc_ownthread_reconf (rpcsvc_t *svc, int new_eventthreadcount)
d1681e
+{
d1681e
+        int ret = -1;
d1681e
+        rpcsvc_program_t *program = NULL;
d1681e
+
d1681e
+        if (!svc) {
d1681e
+                ret = 0;
d1681e
+                goto out;
d1681e
+        }
d1681e
+
d1681e
+        pthread_rwlock_wrlock (&svc->rpclock);
d1681e
+        {
d1681e
+                list_for_each_entry (program, &svc->programs, program) {
d1681e
+                        if (program->ownthread) {
d1681e
+                                program->eventthreadcount =
d1681e
+                                        new_eventthreadcount;
d1681e
+                                rpcsvc_spawn_threads (svc, program);
d1681e
+                        }
d1681e
+                }
d1681e
+        }
d1681e
+        pthread_rwlock_unlock (&svc->rpclock);
d1681e
+
d1681e
+        ret = 0;
d1681e
+out:
d1681e
+        return ret;
d1681e
+}
d1681e
+
d1681e
 
d1681e
 rpcsvc_actor_t gluster_dump_actors[GF_DUMP_MAXVALUE] = {
d1681e
         [GF_DUMP_NULL]      = {"NULL",     GF_DUMP_NULL,     NULL,        NULL, 0, DRC_NA},
d1681e
diff --git a/rpc/rpc-lib/src/rpcsvc.h b/rpc/rpc-lib/src/rpcsvc.h
d1681e
index 73507b6..4ae2350 100644
d1681e
--- a/rpc/rpc-lib/src/rpcsvc.h
d1681e
+++ b/rpc/rpc-lib/src/rpcsvc.h
d1681e
@@ -412,6 +412,12 @@ struct rpcsvc_program {
d1681e
         pthread_mutex_t         queue_lock;
d1681e
         pthread_cond_t          queue_cond;
d1681e
         pthread_t               thread;
d1681e
+        int                     threadcount;
d1681e
+        /* eventthreadcount is just a readonly copy of the actual value
d1681e
+         * owned by the event sub-system
d1681e
+         * It is used to control the scaling of rpcsvc_request_handler threads
d1681e
+         */
d1681e
+        int                     eventthreadcount;
d1681e
 };
d1681e
 
d1681e
 typedef struct rpcsvc_cbk_program {
d1681e
@@ -623,4 +629,6 @@ rpcsvc_auth_array (rpcsvc_t *svc, char *volname, int *autharr, int arrlen);
d1681e
 rpcsvc_vector_sizer
d1681e
 rpcsvc_get_program_vector_sizer (rpcsvc_t *svc, uint32_t prognum,
d1681e
                                  uint32_t progver, int procnum);
d1681e
+extern int
d1681e
+rpcsvc_ownthread_reconf (rpcsvc_t *svc, int new_eventthreadcount);
d1681e
 #endif
d1681e
diff --git a/xlators/protocol/server/src/server.c b/xlators/protocol/server/src/server.c
d1681e
index 6dc9d0f..4627ea0 100644
d1681e
--- a/xlators/protocol/server/src/server.c
d1681e
+++ b/xlators/protocol/server/src/server.c
d1681e
@@ -990,6 +990,12 @@ do_rpc:
d1681e
 
d1681e
         ret = server_init_grace_timer (this, options, conf);
d1681e
 
d1681e
+        /* rpcsvc thread reconfigure should be after events thread
d1681e
+         * reconfigure
d1681e
+         */
d1681e
+        new_nthread =
d1681e
+        ((struct event_pool *)(this->ctx->event_pool))->eventthreadcount;
d1681e
+        ret = rpcsvc_ownthread_reconf (rpc_conf, new_nthread);
d1681e
 out:
d1681e
         THIS = oldTHIS;
d1681e
         gf_msg_debug ("", 0, "returning %d", ret);
d1681e
@@ -1569,9 +1575,9 @@ notify (xlator_t *this, int32_t event, void *data, ...)
d1681e
                                 (*trav_p) = (*trav_p)->next;
d1681e
                         glusterfs_mgmt_pmap_signout (ctx,
d1681e
                                                      victim->name);
d1681e
-                        glusterfs_autoscale_threads (THIS->ctx, -1);
d1681e
+                        /* we need the protocol/server xlator here as 'this' */
d1681e
+                        glusterfs_autoscale_threads (ctx, -1, this);
d1681e
                         default_notify (victim, GF_EVENT_CLEANUP, data);
d1681e
-
d1681e
                 }
d1681e
                 break;
d1681e
 
d1681e
-- 
d1681e
1.8.3.1
d1681e