From 3d1fc9ebe2b0292108dd0737cf8f40d6fcb8cf51 Mon Sep 17 00:00:00 2001 From: shishir gowda Date: Wed, 16 Mar 2011 03:35:16 +0000 Subject: TOP: cli, rpc/xdr related changes Signed-off-by: shishir gowda Signed-off-by: Vijay Bellur BUG: 2516 (Implement gluster volume top command) URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=2516 --- 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 deletion(-) diff --git a/cli/src/cli-cmd-parser.c b/cli/src/cli-cmd-parser.c index 1dd963b66..87792c08c 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 :" + "", 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 f7f333001..3bd54a6fb 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 {[open|read|write|opendir|readdir] " + "|[read-perf|write-perf bs count ]} " + " [brick ] [list-cnt ]", + 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 7daa76341..2a7aa17fc 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 1db78746a..33a6fa187 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 30434d0d9..8483fbcf4 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 c51546a8e..fa24ad90b 100644 --- a/rpc/xdr/src/cli1-xdr.c +++ b/rpc/xdr/src/cli1-xdr.c @@ -107,6 +107,15 @@ xdr_gf1_cli_stats_op (XDR *xdrs, gf1_cli_stats_op *objp) return TRUE; } +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 865eb793a..dba583492 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 f352b6f36..035927f89 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 { -- cgit