Patchwork [BUG:2516,2/3] TOP: cli, rpc/xdr related changes

login
register
Submitter shishir gowda
Date 2011-03-16 09:05:16
Message ID <20110316090516.GA9757@dev.gluster.com>
Download mbox | patch
Permalink /patch/6449/
State Accepted
Headers show

Comments

shishir gowda - 2011-03-16 09:05:16
Signed-off-by: shishir gowda <shishirng@gluster.com>
---
 cli/src/cli-cmd-parser.c          |  133 ++++++++++++++++++++++++
 cli/src/cli-cmd-volume.c          |   49 +++++++++
 cli/src/cli-rpc-ops.c             |  206 ++++++++++++++++++++++++++++++++++++-
 cli/src/cli.h                     |    3 +
 rpc/rpc-lib/src/protocol-common.h |    1 +
 rpc/xdr/src/cli1-xdr.c            |   12 ++
 rpc/xdr/src/cli1-xdr.h            |   19 ++++
 rpc/xdr/src/cli1-xdr.x            |   12 ++
 8 files changed, 434 insertions(+), 1 deletions(-)

Patch

diff --git a/cli/src/cli-cmd-parser.c b/cli/src/cli-cmd-parser.c
index 1dd963b..87792c0 100644
--- a/cli/src/cli-cmd-parser.c
+++ b/cli/src/cli-cmd-parser.c
@@ -1237,3 +1237,136 @@  out:
                 dict_destroy (dict);
         return ret;
 }
+
+int32_t
+cli_cmd_volume_top_parse (const char **words, int wordcount,
+                              dict_t **options)
+{
+        dict_t  *dict           = NULL;
+        char    *volname        = NULL;
+        char    *value          = NULL;
+        char    *key            = NULL;
+        int      ret            = -1;
+        gf1_cli_stats_op op = GF_CLI_STATS_NONE;
+        gf1_cli_top_op    top_op = GF_CLI_TOP_NONE;
+        int32_t  list_cnt       = 0;
+        int      index          = 0;
+        int      perf           = 0;
+        int32_t  blk_size       = 0;
+        int32_t  count          = 0;
+        char    *delimiter      = NULL;
+
+        GF_ASSERT (words);
+        GF_ASSERT (options);
+
+        GF_ASSERT ((strcmp (words[0], "volume")) == 0);
+        GF_ASSERT ((strcmp (words[1], "top")) == 0);
+
+        dict = dict_new ();
+        if (!dict)
+                goto out;
+
+        if (wordcount < 4)
+                goto out;
+
+        volname = (char *)words[2];
+
+        ret = dict_set_str (dict, "volname", volname);
+        if (ret)
+                goto out;
+
+        op = GF_CLI_STATS_TOP;
+        ret = dict_set_int32 (dict, "op", (int32_t)op);
+        if (ret)
+                goto out;
+
+        if (strcmp (words[3], "open") == 0) {
+                top_op = GF_CLI_TOP_OPEN;
+        } else if (strcmp (words[3], "read") == 0) {
+                top_op = GF_CLI_TOP_READ;
+        } else if (strcmp (words[3], "write") == 0) {
+                top_op = GF_CLI_TOP_WRITE;
+        } else if (strcmp (words[3], "opendir") == 0) {
+                top_op = GF_CLI_TOP_OPENDIR;
+        } else if (strcmp (words[3], "readdir") == 0) {
+                top_op = GF_CLI_TOP_READDIR;
+        } else if (strcmp (words[3], "read-perf") == 0) {
+                top_op = GF_CLI_TOP_READ_PERF;
+                perf = 1;
+        } else if (strcmp (words[3], "write-perf") == 0) {
+                top_op = GF_CLI_TOP_WRITE_PERF;
+                perf = 1;
+        } else {
+                ret = -1;
+                goto out;
+        } 
+        ret = dict_set_int32 (dict, "top-op", (int32_t)top_op);
+        if (ret)
+                goto out;
+
+        for (index = 4; index < wordcount; index+=2) {
+
+                key = (char *) words[index];
+                value = (char *) words[index+1];
+
+                if ( key && !value ) {
+                        ret = -1;
+                        goto out;
+                }
+                if (!strcmp (key, "brick")) {
+                        delimiter = strchr (value, ':');
+                        if (!delimiter || delimiter == value 
+                            || *(delimiter+1) != '/') {
+                                cli_out ("wrong brick type: %s, use <HOSTNAME>:"
+                                         "<export-dir-abs-path>", value);
+                                ret = -1;
+                                goto out;
+                        }
+                        ret = dict_set_str (dict, "brick", value);
+
+                } else if (!strcmp (key, "list-cnt")) {
+                        list_cnt = atoi(value);
+                        if (!list_cnt) {
+                                list_cnt = 100;
+                        }
+                        if (list_cnt < 1 || list_cnt > 100) {
+                                cli_out ("list-cnt should be between 1 to 100");
+                                ret = -1;
+                                goto out;
+                        }
+                        ret = dict_set_int32 (dict, "list-cnt", list_cnt);
+                } else if (perf && !strcmp (key, "bs")){
+                        blk_size = atoi (value);
+                        if (blk_size < 0){
+                                cli_out ("block size should be an integer "
+                                         "greater than zero");
+                                ret = -1;
+                                goto out;
+                        }
+                        ret = dict_set_int32 (dict, "blk-size", blk_size);
+                } else if (perf && !strcmp (key, "count")) {
+                        count = atoi(value);
+                        if (count < 0 ){
+                                cli_out ("count should be an integer greater "
+                                         "zero");
+                                ret = -1;
+                                goto out;
+                        }
+                        ret = dict_set_int32 (dict, "blk-cnt", count);
+                } else {
+                        ret = -1;
+                        goto out;
+                }
+                if (ret) {
+                        gf_log ("", GF_LOG_WARNING, "Dict set failed for "
+                                "key %s", key);
+                        goto out;
+                }
+        }
+        *options = dict;
+out:
+        if (ret && dict)
+                dict_destroy (dict);
+        return ret;
+}
+
diff --git a/cli/src/cli-cmd-volume.c b/cli/src/cli-cmd-volume.c
index f7f3330..3bd54a6 100644
--- a/cli/src/cli-cmd-volume.c
+++ b/cli/src/cli-cmd-volume.c
@@ -901,6 +901,49 @@  out:
         return ret;
 }
 
+int
+cli_cmd_volume_top_cbk (struct cli_state *state, struct cli_cmd_word *word,
+                          const char **words, int wordcount)
+{
+
+        int                     ret      = -1;
+        rpc_clnt_procedure_t    *proc    = NULL;
+        call_frame_t            *frame   = NULL;
+        dict_t                  *options = NULL;
+        int                     sent     = 0;
+        int                     parse_error = 0;
+
+        ret = cli_cmd_volume_top_parse (words, wordcount, &options);
+
+        if (ret) {
+                parse_error = 1;
+                cli_usage_out (word->pattern);
+                goto out;
+        }
+
+        proc = &cli_rpc_prog->proctable[GLUSTER_CLI_TOP_VOLUME];
+
+        frame = create_frame (THIS, THIS->ctx->pool);
+        if (!frame)
+                goto out;
+
+        if (proc->fn) {
+                ret = proc->fn (frame, THIS, options);
+        }
+
+out:
+        if (options)
+                dict_unref (options);
+
+        if (ret) {
+                cli_cmd_sent_status_get (&sent);
+                if ((sent == 0) && (parse_error == 0))
+                        cli_out ("Volume top failed");
+        }
+
+        return ret;
+
+}
 
 int
 cli_cmd_log_locate_cbk (struct cli_state *state, struct cli_cmd_word *word,
@@ -1119,6 +1162,12 @@  struct cli_cmd volume_cmds[] = {
           cli_cmd_quota_cbk,
           "quota translator specific operations"},
 
+         { "volume top <VOLNAME> {[open|read|write|opendir|readdir] "
+           "|[read-perf|write-perf bs <size> count <count>]} "
+           " [brick <brick>] [list-cnt <count>]",
+           cli_cmd_volume_top_cbk,
+           "volume profile operations"},
+
         { NULL, NULL, NULL }
 };
 
diff --git a/cli/src/cli-rpc-ops.c b/cli/src/cli-rpc-ops.c
index 7daa763..2a7aa17 100644
--- a/cli/src/cli-rpc-ops.c
+++ b/cli/src/cli-rpc-ops.c
@@ -3145,6 +3145,210 @@  out:
         return ret;
 }
 
+int32_t
+gf_cli3_1_top_volume_cbk (struct rpc_req *req, struct iovec *iov,
+                              int count, void *myframe)
+{
+        gf1_cli_stats_volume_rsp        rsp   = {0,};
+        int                               ret   = -1;
+        dict_t                            *dict = NULL;
+        gf1_cli_stats_op                op = GF_CLI_STATS_NONE;
+        char                              key[256] = {0};
+        int                               i = 1;
+        int32_t                           brick_count = 0;
+        char                              brick[1024];
+        int32_t                           members = 0;
+        char                              *filename;
+        char                              *bricks;
+        uint64_t                           value = 0;
+        int32_t                           j = 0;
+        gf1_cli_top_op                    top_op = GF_CLI_TOP_NONE;
+        uint64_t                          nr_open = 0;
+        uint64_t                          max_nr_open = 0;
+        double                            throughput = 0;
+        double                            time = 0;
+        long int                          time_sec = 0;
+        long int                           time_usec = 0;
+        struct tm                         *tm = NULL;
+        char                              timestr[256] = {0, };
+
+        if (-1 == req->rpc_status) {
+                goto out;
+        }
+
+        gf_log ("cli", GF_LOG_DEBUG, "Received resp to top");
+        ret = gf_xdr_to_cli_stats_volume_rsp (*iov, &rsp);
+        if (ret < 0) {
+                gf_log ("", GF_LOG_ERROR, "error");
+                goto out;
+        }
+
+        if (rsp.op_ret && strcmp (rsp.op_errstr, "")) {
+                cli_out (rsp.op_errstr);
+        } else {
+                cli_out ("volume top %s ",
+                         (rsp.op_ret) ? "unsuccessful": "successful");
+        }
+
+        if (rsp.op_ret) {
+                ret = rsp.op_ret;
+                goto out;
+        }
+
+        dict = dict_new ();
+
+        if (!dict) {
+                ret = -1;
+                goto out;
+        }
+
+        ret = dict_unserialize (rsp.stats_info.stats_info_val,
+                                rsp.stats_info.stats_info_len,
+                                &dict);
+
+        if (ret) {
+                gf_log ("", GF_LOG_ERROR,
+                                "Unable to allocate memory");
+                goto out;
+        }
+
+        ret = dict_get_int32 (dict, "op", (int32_t*)&op);
+
+        if (op != GF_CLI_STATS_TOP) {
+                ret = 0;
+                goto out;
+        }
+        ret = dict_get_int32 (dict, "count", &brick_count);
+        if (ret)
+                goto out;
+        snprintf (key, sizeof (key), "%d-top-op", i);
+        ret = dict_get_int32 (dict, key, (int32_t*)&top_op);
+        if (ret)
+                goto out;
+        while (i <= brick_count) {
+                snprintf (brick, sizeof (brick), "%d-brick", i);
+                ret = dict_get_str (dict, brick, &bricks);
+                if (ret)
+                        goto out;
+                cli_out ("Brick: %s", bricks);
+                switch (top_op) {
+                case GF_CLI_TOP_OPEN:
+                        snprintf (key, sizeof (key), "%d-current-open", i);
+                        ret = dict_get_uint64 (dict, key, &nr_open);
+                        if (ret)
+                                break;
+                        snprintf (key, sizeof (key), "%d-max-open", i);
+                        ret = dict_get_uint64 (dict, key, &max_nr_open);
+                        if (ret)
+                                goto out;
+                        cli_out ("Current open fd's: %"PRIu64", Max open"
+                                " fd's: %"PRIu64, nr_open, max_nr_open);
+                case GF_CLI_TOP_READ:
+                case GF_CLI_TOP_WRITE:
+                case GF_CLI_TOP_OPENDIR:
+                case GF_CLI_TOP_READDIR:
+                        cli_out ("Count\t\tfilename\n=======================");
+                        break;
+                case GF_CLI_TOP_READ_PERF:
+                case GF_CLI_TOP_WRITE_PERF:
+                        snprintf (key, sizeof (key), "%d-throughput", i);
+                        ret = dict_get_double (dict, key, &throughput);
+                        if (!ret) {
+                                snprintf (key, sizeof (key), "%d-time", i);
+                                ret = dict_get_double (dict, key, &time);
+                        }
+                        if (!ret)
+                                cli_out ("Throughput %.2f MBps time %.4f secs", throughput,
+                                          time / 1e6);
+
+                        cli_out ("MBps\t\tfilename\t\t time\n========================");
+                        break;
+                default:
+                        goto out;
+                }
+                snprintf(key, sizeof (key), "%d-members", i);
+                ret = dict_get_int32 (dict, key, &members);
+                for (j = 1; j <= members; j++) {
+                        snprintf (key, sizeof (key), "%d-filename-%d", i, j);
+                        ret = dict_get_str (dict, key, &filename);
+                        if (ret)
+                                break;
+                        snprintf (key, sizeof (key), "%d-value-%d", i, j);
+                        ret = dict_get_uint64 (dict, key, &value);
+                        if (ret)
+                                goto out;
+                        if ( top_op == GF_CLI_TOP_READ_PERF ||
+                                top_op == GF_CLI_TOP_WRITE_PERF) {
+                                snprintf (key, sizeof (key), "%d-time-sec-%d", i, j);
+                                ret = dict_get_int32 (dict, key, (int32_t *)&time_sec);
+                                if (ret)
+                                        goto out;
+                                snprintf (key, sizeof (key), "%d-time-usec-%d", i, j);
+                                ret = dict_get_int32 (dict, key, (int32_t *)&time_usec);
+                                if (ret)
+                                        goto out;
+                                tm    = localtime (&time_sec);
+                                if (!tm)
+                                        goto out;
+                                strftime (timestr, 256, "%Y-%m-%d %H:%M:%S", tm);
+                                snprintf (timestr + strlen (timestr), 256 - strlen (timestr),
+                                  ".%"GF_PRI_SUSECONDS, time_usec);
+
+                                cli_out ("%"PRIu64"\t\t%s\t\t%s", value, filename, timestr);
+                        } else {
+                                cli_out ("%"PRIu64"\t\t%s", value, filename);
+                        }
+                }
+                i++;
+        }
+        ret = rsp.op_ret;
+
+out:
+        cli_cmd_broadcast_response (ret);
+
+        if (dict)
+                dict_unref (dict);
+
+        if (rsp.stats_info.stats_info_val)
+                free (rsp.stats_info.stats_info_val);
+        return ret;
+}
+
+int32_t
+gf_cli3_1_top_volume (call_frame_t *frame, xlator_t *this, void *data)
+{
+        int                        ret   = -1;
+        gf1_cli_stats_volume_req   req   = {0,};
+        dict_t                     *dict = NULL;
+
+        GF_ASSERT (frame);
+        GF_ASSERT (this);
+        GF_ASSERT (data);
+
+        if (!frame || !this || !data)
+                goto out;
+        dict = data;
+        ret = dict_get_str (dict, "volname", &req.volname);
+        if (ret)
+                goto out;
+
+        ret = dict_get_int32 (dict, "op", (int32_t*)&req.op);
+        if (ret)
+                goto out;
+
+        ret = dict_allocate_and_serialize (dict,
+                                           &req.dict_req.dict_req_val,
+                                           (size_t *)&req.dict_req.dict_req_len);
+
+        ret = cli_cmd_submit (&req, frame, cli_rpc_prog,
+                              GLUSTER_CLI_PROFILE_VOLUME, NULL,
+                              gf_xdr_from_cli_stats_volume_req,
+                              this, gf_cli3_1_top_volume_cbk);
+
+out:
+        gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret);
+        return ret;
+}
 
 struct rpc_clnt_procedure gluster_cli_actors[GLUSTER_CLI_MAXVALUE] = {
         [GLUSTER_CLI_NULL]             = {"NULL", NULL },
@@ -3174,7 +3378,7 @@  struct rpc_clnt_procedure gluster_cli_actors[GLUSTER_CLI_MAXVALUE] = {
         [GLUSTER_CLI_GSYNC_SET]        = {"GSYNC_SET", gf_cli3_1_gsync_set},
         [GLUSTER_CLI_PROFILE_VOLUME]   = {"PROFILE_VOLUME", gf_cli3_1_profile_volume},
         [GLUSTER_CLI_QUOTA]            = {"QUOTA", gf_cli3_1_quota},
-
+        [GLUSTER_CLI_TOP_VOLUME]       = {"TOP_VOLUME", gf_cli3_1_top_volume}
 };
 
 struct rpc_clnt_program cli_prog = {
diff --git a/cli/src/cli.h b/cli/src/cli.h
index 1db7874..33a6fa1 100644
--- a/cli/src/cli.h
+++ b/cli/src/cli.h
@@ -223,4 +223,7 @@  cli_path_strip_trailing_slashes (char *path);
 int32_t
 cli_cmd_volume_profile_parse (const char **words, int wordcount,
                               dict_t **options);
+int32_t
+cli_cmd_volume_top_parse (const char **words, int wordcount,
+                              dict_t **options);
 #endif /* __CLI_H__ */
diff --git a/rpc/rpc-lib/src/protocol-common.h b/rpc/rpc-lib/src/protocol-common.h
index 30434d0..8483fbc 100644
--- a/rpc/rpc-lib/src/protocol-common.h
+++ b/rpc/rpc-lib/src/protocol-common.h
@@ -197,6 +197,7 @@  enum gluster_cli_procnum {
         GLUSTER_CLI_GSYNC_SET,
         GLUSTER_CLI_PROFILE_VOLUME,
         GLUSTER_CLI_QUOTA,
+        GLUSTER_CLI_TOP_VOLUME,
         GLUSTER_CLI_MAXVALUE,
 };
 
diff --git a/rpc/xdr/src/cli1-xdr.c b/rpc/xdr/src/cli1-xdr.c
index c51546a..fa24ad9 100644
--- a/rpc/xdr/src/cli1-xdr.c
+++ b/rpc/xdr/src/cli1-xdr.c
@@ -108,6 +108,15 @@  xdr_gf1_cli_stats_op (XDR *xdrs, gf1_cli_stats_op *objp)
 }
 
 bool_t
+xdr_gf1_cli_top_op (XDR *xdrs, gf1_cli_top_op *objp)
+{
+
+         if (!xdr_enum (xdrs, (enum_t *) objp))
+                 return FALSE;
+        return TRUE;
+}
+
+bool_t
 xdr_gf1_cli_probe_req (XDR *xdrs, gf1_cli_probe_req *objp)
 {
 
@@ -764,6 +773,9 @@  xdr_gf1_cli_stats_volume_req (XDR *xdrs, gf1_cli_stats_volume_req *objp)
 		 return FALSE;
 	 if (!xdr_gf1_cli_stats_op (xdrs, &objp->op))
 		 return FALSE;
+	 if (!xdr_bytes (xdrs, (char **)&objp->dict_req.dict_req_val, (u_int *) &objp->dict_req.dict_req_len, ~0))
+		 return FALSE;
+
 	return TRUE;
 }
 
diff --git a/rpc/xdr/src/cli1-xdr.h b/rpc/xdr/src/cli1-xdr.h
index 865eb79..dba5834 100644
--- a/rpc/xdr/src/cli1-xdr.h
+++ b/rpc/xdr/src/cli1-xdr.h
@@ -100,9 +100,22 @@  enum gf1_cli_stats_op {
 	GF_CLI_STATS_START = 1,
 	GF_CLI_STATS_STOP = 2,
 	GF_CLI_STATS_INFO = 3,
+        GF_CLI_STATS_TOP = 4,
 };
 typedef enum gf1_cli_stats_op gf1_cli_stats_op;
 
+enum gf1_cli_top_op {
+        GF_CLI_TOP_NONE = 0,
+        GF_CLI_TOP_OPEN = 0 + 1,
+        GF_CLI_TOP_READ = 0 + 2,
+        GF_CLI_TOP_WRITE = 0 + 3,
+        GF_CLI_TOP_OPENDIR = 0 + 4,
+        GF_CLI_TOP_READDIR = 0 + 5,
+        GF_CLI_TOP_READ_PERF = 0 + 6,
+        GF_CLI_TOP_WRITE_PERF = 0 + 7,
+};
+typedef enum gf1_cli_top_op gf1_cli_top_op;
+
 struct gf1_cli_probe_req {
 	char *hostname;
 	int port;
@@ -475,6 +488,10 @@  typedef struct gf1_cli_gsync_set_rsp gf1_cli_gsync_set_rsp;
 struct gf1_cli_stats_volume_req {
 	char *volname;
 	gf1_cli_stats_op op;
+	struct {
+		u_int dict_req_len;
+		char* dict_req_val;
+	} dict_req;
 };
 typedef struct gf1_cli_stats_volume_req gf1_cli_stats_volume_req;
 
@@ -499,6 +516,7 @@  extern  bool_t xdr_gf1_cli_get_volume (XDR *, gf1_cli_get_volume*);
 extern  bool_t xdr_gf1_cli_sync_volume (XDR *, gf1_cli_sync_volume*);
 extern  bool_t xdr_gf1_cli_op_flags (XDR *, gf1_cli_op_flags*);
 extern  bool_t xdr_gf1_cli_gsync_set (XDR *, gf1_cli_gsync_set*);
+extern  bool_t xdr_gf1_cli_top_op (XDR *, gf1_cli_top_op*);
 extern  bool_t xdr_gf1_cli_stats_op (XDR *, gf1_cli_stats_op*);
 extern  bool_t xdr_gf_quota_type (XDR *, gf_quota_type*);
 extern  bool_t xdr_gf1_cli_probe_req (XDR *, gf1_cli_probe_req*);
@@ -558,6 +576,7 @@  extern bool_t xdr_gf1_cli_sync_volume ();
 extern bool_t xdr_gf1_cli_op_flags ();
 extern bool_t xdr_gf1_cli_gsync_set ();
 extern bool_t xdr_gf1_cli_stats_op ();
+extern bool_t xdr_gf1_cli_top_op ();
 extern bool_t xdr_gf_quota_type ();
 extern bool_t xdr_gf1_cli_probe_req ();
 extern bool_t xdr_gf1_cli_probe_rsp ();
diff --git a/rpc/xdr/src/cli1-xdr.x b/rpc/xdr/src/cli1-xdr.x
index f352b6f..035927f 100644
--- a/rpc/xdr/src/cli1-xdr.x
+++ b/rpc/xdr/src/cli1-xdr.x
@@ -58,6 +58,18 @@  enum gf1_cli_stats_op {
         GF_CLI_STATS_START = 1,
         GF_CLI_STATS_STOP  = 2,
         GF_CLI_STATS_INFO  = 3
+        GF_CLI_STATS_TOP = 4
+};
+
+enum gf1_cli_top_op {
+        GF_CLI_TOP_NONE = 0,
+        GF_CLI_TOP_OPEN,
+        GF_CLI_TOP_READ,
+        GF_CLI_TOP_WRITE,
+        GF_CLI_TOP_OPENDIR,
+        GF_CLI_TOP_READDIR,
+        GF_CLI_TOP_READ_PERF,
+        GF_CLI_TOP_WRITE_PERF
 };
 
  struct gf1_cli_probe_req {