summaryrefslogtreecommitdiffstats
path: root/rpc/rpc-lib/src/rpc-clnt-ping.c
diff options
context:
space:
mode:
authorKrishnan Parthasarathi <kparthas@redhat.com>2014-04-07 10:57:45 +0530
committerAnand Avati <avati@redhat.com>2014-04-29 14:23:51 -0700
commitc61bc1f9e5874cb8380ec6398680fc71aea233b4 (patch)
treec02fee67ebcc7c43a6338d34c5700916e672c110 /rpc/rpc-lib/src/rpc-clnt-ping.c
parent91ab65f812ec3b674f53230eacbd0d71964d3d01 (diff)
glusterd: Ping timer implmentation
This patch refactors the existing client ping timer implementation, and makes use of the common code for implementing both client ping timer and the glusterd ping timer. A new gluster rpc program for ping is introduced. The ping timer is only started for peers that have this new program. The deafult glusterd ping timeout is 30 seconds. It is configurable by setting the option 'ping-timeout' in glusterd.vol . Also, this patch introduces changes in the glusterd-handshake path. The client programs for a peer are now set in the callback of dump_versions, for both the older handshake and the newer op-version handshake. This is the only place in the handshake process where we know what programs a peer supports. Change-Id: I035815ac13449ca47080ecc3253c0a9afbe9016a BUG: 1038261 Signed-off-by: Vijaikumar M <vmallika@redhat.com> Signed-off-by: Krishnan Parthasarathi <kparthas@redhat.com> Reviewed-on: http://review.gluster.org/5202 Tested-by: Gluster Build System <jenkins@build.gluster.com> Reviewed-by: Anand Avati <avati@redhat.com>
Diffstat (limited to 'rpc/rpc-lib/src/rpc-clnt-ping.c')
-rw-r--r--rpc/rpc-lib/src/rpc-clnt-ping.c266
1 files changed, 266 insertions, 0 deletions
diff --git a/rpc/rpc-lib/src/rpc-clnt-ping.c b/rpc/rpc-lib/src/rpc-clnt-ping.c
new file mode 100644
index 00000000000..b3bd5e11deb
--- /dev/null
+++ b/rpc/rpc-lib/src/rpc-clnt-ping.c
@@ -0,0 +1,266 @@
+/*
+ Copyright (c) 2014 Red Hat, Inc. <http://www.redhat.com>
+ This file is part of GlusterFS.
+
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+*/
+
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+#include "config.h"
+#endif
+
+#include "rpc-clnt.h"
+#include "rpc-clnt-ping.h"
+#include "byte-order.h"
+#include "xdr-rpcclnt.h"
+#include "rpc-transport.h"
+#include "protocol-common.h"
+#include "mem-pool.h"
+#include "xdr-rpc.h"
+#include "rpc-common-xdr.h"
+
+
+char *clnt_ping_procs[GF_DUMP_MAXVALUE] = {
+ [GF_DUMP_PING] = "NULL",
+};
+struct rpc_clnt_program clnt_ping_prog = {
+ .progname = "GF-DUMP",
+ .prognum = GLUSTER_DUMP_PROGRAM,
+ .progver = GLUSTER_DUMP_VERSION,
+ .procnames = clnt_ping_procs,
+};
+
+void
+rpc_clnt_ping_timer_expired (void *rpc_ptr)
+{
+ struct rpc_clnt *rpc = NULL;
+ rpc_transport_t *trans = NULL;
+ rpc_clnt_connection_t *conn = NULL;
+ int disconnect = 0;
+ int transport_activity = 0;
+ struct timespec timeout = {0, };
+ struct timeval current = {0, };
+
+ rpc = (struct rpc_clnt*) rpc_ptr;
+ conn = &rpc->conn;
+ trans = conn->trans;
+
+ if (!trans) {
+ gf_log ("ping-timer", GF_LOG_WARNING,
+ "transport not initialized");
+ goto out;
+ }
+
+ pthread_mutex_lock (&conn->lock);
+ {
+ if (conn->ping_timer) {
+ gf_timer_call_cancel (rpc->ctx,
+ conn->ping_timer);
+ conn->ping_timer = NULL;
+ rpc_clnt_unref (rpc);
+ }
+ gettimeofday (&current, NULL);
+
+ if (((current.tv_sec - conn->last_received.tv_sec) <
+ conn->ping_timeout)
+ || ((current.tv_sec - conn->last_sent.tv_sec) <
+ conn->ping_timeout)) {
+ transport_activity = 1;
+ }
+
+ if (transport_activity) {
+ gf_log (trans->name, GF_LOG_TRACE,
+ "ping timer expired but transport activity "
+ "detected - not bailing transport");
+ timeout.tv_sec = conn->ping_timeout;
+ timeout.tv_nsec = 0;
+
+ rpc_clnt_ref (rpc);
+ conn->ping_timer =
+ gf_timer_call_after (rpc->ctx, timeout,
+ rpc_clnt_ping_timer_expired,
+ (void *) rpc);
+ if (conn->ping_timer == NULL) {
+ gf_log (trans->name, GF_LOG_WARNING,
+ "unable to setup ping timer");
+ rpc_clnt_unref (rpc);
+ }
+ } else {
+ conn->ping_started = 0;
+ disconnect = 1;
+ }
+ }
+ pthread_mutex_unlock (&conn->lock);
+
+ if (disconnect) {
+ gf_log (trans->name, GF_LOG_CRITICAL,
+ "server %s has not responded in the last %d "
+ "seconds, disconnecting.",
+ trans->peerinfo.identifier,
+ conn->ping_timeout);
+
+ rpc_transport_disconnect (conn->trans);
+ }
+
+out:
+ return;
+}
+
+int
+rpc_clnt_ping_cbk (struct rpc_req *req, struct iovec *iov, int count,
+ void *myframe)
+{
+ struct rpc_clnt *rpc = NULL;
+ xlator_t *this = NULL;
+ rpc_clnt_connection_t *conn = NULL;
+ call_frame_t *frame = NULL;
+
+ if (!myframe) {
+ gf_log (THIS->name, GF_LOG_WARNING,
+ "frame with the request is NULL");
+ goto out;
+ }
+
+ frame = myframe;
+ this = frame->this;
+ rpc = frame->local;
+ frame->local = NULL; /* Prevent STACK_DESTROY from segfaulting */
+ conn = &rpc->conn;
+
+ if (req->rpc_status == -1) {
+ pthread_mutex_lock (&conn->lock);
+ {
+ if (conn->ping_timer != NULL) {
+ gf_log (this->name, GF_LOG_WARNING,
+ "socket or ib related error");
+ gf_timer_call_cancel (rpc->ctx,
+ conn->ping_timer);
+ conn->ping_timer = NULL;
+ rpc_clnt_unref (rpc);
+ } else {
+ /* timer expired and transport bailed out */
+ gf_log (this->name, GF_LOG_WARNING,
+ "timer must have expired");
+ }
+ conn->ping_started = 0;
+ }
+ pthread_mutex_unlock (&conn->lock);
+ }
+out:
+ if (frame)
+ STACK_DESTROY (frame->root);
+ if (rpc)
+ rpc_clnt_unref (rpc);
+ return 0;
+}
+
+int
+rpc_clnt_ping (struct rpc_clnt *rpc)
+{
+ call_frame_t *frame = NULL;
+ int32_t ret = -1;
+
+ frame = create_frame (THIS, THIS->ctx->pool);
+ if (!frame)
+ goto fail;
+
+ frame->local = rpc_clnt_ref (rpc);
+
+ ret = rpc_clnt_submit (rpc, &clnt_ping_prog,
+ GF_DUMP_PING, rpc_clnt_ping_cbk, NULL, 0,
+ NULL, 0, NULL, frame, NULL, 0, NULL, 0, NULL);
+ if (ret) {
+ gf_log (THIS->name, GF_LOG_ERROR,
+ "failed to start ping timer");
+ }
+
+ return ret;
+
+fail:
+ if (frame) {
+ STACK_DESTROY (frame->root);
+ }
+
+ return ret;
+
+}
+
+void
+rpc_clnt_start_ping (void *rpc_ptr)
+{
+ struct rpc_clnt *rpc = NULL;
+ rpc_clnt_connection_t *conn = NULL;
+ struct timespec timeout = {0, };
+ int frame_count = 0;
+
+ rpc = (struct rpc_clnt*) rpc_ptr;
+ conn = &rpc->conn;
+
+ if (conn->ping_timeout == 0) {
+ gf_log (THIS->name, GF_LOG_INFO, "ping timeout is 0, returning");
+ return;
+ }
+
+ pthread_mutex_lock (&conn->lock);
+ {
+ if (conn->ping_started) {
+ pthread_mutex_unlock (&conn->lock);
+ return;
+ }
+
+ if (conn->ping_timer) {
+ gf_timer_call_cancel (rpc->ctx, conn->ping_timer);
+ conn->ping_timer = NULL;
+ rpc_clnt_unref (rpc);
+ }
+
+ if (conn->saved_frames)
+ /* treat the case where conn->saved_frames is NULL
+ as no pending frames */
+ frame_count = conn->saved_frames->count;
+
+ if ((frame_count == 0) || !conn->connected) {
+ gf_log (THIS->name, GF_LOG_DEBUG,
+ "returning as transport is already disconnected"
+ " OR there are no frames (%d || %d)",
+ frame_count, !conn->connected);
+
+ pthread_mutex_unlock (&conn->lock);
+ return;
+ }
+
+ if (frame_count < 0) {
+ gf_log (THIS->name, GF_LOG_WARNING,
+ "saved_frames->count is %"PRId64,
+ conn->saved_frames->count);
+ conn->saved_frames->count = 0;
+ }
+
+ timeout.tv_sec = conn->ping_timeout;
+ timeout.tv_nsec = 0;
+
+ rpc_clnt_ref (rpc);
+ conn->ping_timer =
+ gf_timer_call_after (rpc->ctx, timeout,
+ rpc_clnt_ping_timer_expired,
+ (void *) rpc);
+
+ if (conn->ping_timer == NULL) {
+ gf_log (THIS->name, GF_LOG_WARNING,
+ "unable to setup ping timer");
+ rpc_clnt_unref (rpc);
+ pthread_mutex_unlock (&conn->lock);
+ return;
+ } else {
+ conn->ping_started = 1;
+ }
+ }
+ pthread_mutex_unlock (&conn->lock);
+
+ rpc_clnt_ping(rpc);
+}