diff options
author | shishir gowda <shishirng@gluster.com> | 2011-03-16 03:35:16 +0000 |
---|---|---|
committer | Vijay Bellur <vijay@dev.gluster.com> | 2011-03-16 02:35:30 -0700 |
commit | 3d1fc9ebe2b0292108dd0737cf8f40d6fcb8cf51 (patch) | |
tree | fa1e4b0454727a74e829a9cb25893394de8381d4 /cli/src | |
parent | f208d7148fefd55b4073bda978816d71831ffefa (diff) |
TOP: cli, rpc/xdr related changes
Signed-off-by: shishir gowda <shishirng@gluster.com>
Signed-off-by: Vijay Bellur <vijay@dev.gluster.com>
BUG: 2516 (Implement gluster volume top command)
URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=2516
Diffstat (limited to 'cli/src')
-rw-r--r-- | cli/src/cli-cmd-parser.c | 133 | ||||
-rw-r--r-- | cli/src/cli-cmd-volume.c | 49 | ||||
-rw-r--r-- | cli/src/cli-rpc-ops.c | 206 | ||||
-rw-r--r-- | cli/src/cli.h | 3 |
4 files changed, 390 insertions, 1 deletions
diff --git a/cli/src/cli-cmd-parser.c b/cli/src/cli-cmd-parser.c index 1dd963b66d8..87792c08c7d 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 f7f333001ee..3bd54a6fb3b 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 7daa7634158..2a7aa17fcb7 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 1db78746a96..33a6fa1879b 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__ */ |