From a0aafa365dd355864d24232bd6d7f399ef38f9ef Mon Sep 17 00:00:00 2001 From: Pranith K Date: Thu, 10 Mar 2011 02:20:39 +0000 Subject: cli: gluster profile CLI Signed-off-by: Pranith Kumar K Signed-off-by: Vijay Bellur BUG: 1965 (need a cmd to get io-stat details) URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=1965 --- cli/src/cli-cmd-parser.c | 326 ++++++++++++++++++++++------------------------- cli/src/cli-cmd-volume.c | 48 +++++++ cli/src/cli-cmd.h | 9 ++ cli/src/cli-rpc-ops.c | 319 ++++++++++++++++++++++++++++++++++++++++++++++ cli/src/cli.c | 9 +- cli/src/cli.h | 3 + 6 files changed, 534 insertions(+), 180 deletions(-) (limited to 'cli/src') diff --git a/cli/src/cli-cmd-parser.c b/cli/src/cli-cmd-parser.c index 8cfdc808a..b38cf24fa 100644 --- a/cli/src/cli-cmd-parser.c +++ b/cli/src/cli-cmd-parser.c @@ -36,29 +36,116 @@ #include "protocol-common.h" #include "cli1-xdr.h" +int32_t +cli_cmd_bricks_parse (const char **words, int wordcount, int brick_index, + char **bricks, int *brick_count) +{ + int ret = 0; + char *tmp_list = NULL; + char brick_list[120000] = {0,}; + char *space = " "; + char *delimiter = NULL; + char *host_name = NULL; + char *tmp = NULL; + char *free_list_ptr = NULL; + char *tmpptr = NULL; + int j = 0; + int brick_list_len = 0; + + GF_ASSERT (words); + GF_ASSERT (wordcount); + GF_ASSERT (bricks); + GF_ASSERT (brick_index > 0); + GF_ASSERT (brick_index < wordcount); + + strncpy (brick_list, space, strlen (space)); + brick_list_len++; + while (brick_index < wordcount) { + delimiter = strchr (words[brick_index], ':'); + if (!delimiter || delimiter == words[brick_index] + || *(delimiter+1) != '/') { + cli_out ("wrong brick type: %s, use :" + "", words[brick_index]); + ret = -1; + goto out; + } else { + cli_path_strip_trailing_slashes (delimiter + 1); + } + + if ((brick_list_len + strlen (words[brick_index]) + 1) > sizeof (brick_list)) { + gf_log ("cli", GF_LOG_ERROR, + "total brick list is larger than a request " + "can take (brick_count %d)", *brick_count); + ret = -1; + goto out; + } + + host_name = gf_strdup (words[brick_index]); + if (!host_name) { + ret = -1; + gf_log("cli",GF_LOG_ERROR, "Unable to allocate " + "memory"); + goto out; + } + + strtok_r (host_name, ":", &tmp); + if (!(strcmp (host_name, "localhost") && + strcmp (host_name, "127.0.0.1"))) { + cli_out ("Please provide a valid hostname/ip other " + "than localhost or 127.0.0.1"); + ret = -1; + GF_FREE (host_name); + goto out; + } + GF_FREE (host_name); + tmp_list = gf_strdup (brick_list + 1); + if (free_list_ptr) { + GF_FREE (free_list_ptr); + free_list_ptr = NULL; + } + free_list_ptr = tmp_list; + j = 0; + while(j < *brick_count) { + strtok_r (tmp_list, " ", &tmpptr); + if (!(strcmp (tmp_list, words[brick_index]))) { + ret = -1; + cli_out ("Found duplicate" + " exports %s",words[brick_index]); + goto out; + } + tmp_list = tmpptr; + j++; + } + strcat (brick_list, words[brick_index]); + strcat (brick_list, " "); + brick_list_len += (strlen (words[brick_index]) + 1); + ++(*brick_count); + ++brick_index; + } + + *bricks = gf_strdup (brick_list); + if (!*bricks) + ret = -1; +out: + if (free_list_ptr) + GF_FREE (free_list_ptr); + return ret; +} + int32_t cli_cmd_volume_create_parse (const char **words, int wordcount, dict_t **options) { dict_t *dict = NULL; char *volname = NULL; - char *delimiter = NULL; int ret = -1; gf1_cluster_type type = GF_CLUSTER_TYPE_NONE; int count = 1; - int brick_count = 0, brick_index = 0; - int brick_list_size = 1; - char brick_list[120000] = {0,}; + int brick_index = 0; int i = 0; - char *tmp_list = NULL; - char *tmpptr = NULL; - int j = 0; - char *host_name = NULL; - char *tmp = NULL; - char *freeptr = NULL; char *trans_type = NULL; int32_t index = 0; - char *free_list_ptr = NULL; char *bricks = NULL; + int32_t brick_count = 0; GF_ASSERT (words); GF_ASSERT (options); @@ -187,77 +274,10 @@ cli_cmd_volume_create_parse (const char **words, int wordcount, dict_t **options if (ret) goto out; - strcpy (brick_list, " "); - while (brick_index < wordcount) { - delimiter = strchr (words[brick_index], ':'); - if (!delimiter || delimiter == words[brick_index] - || *(delimiter+1) != '/') { - cli_out ("wrong brick type: %s, use :" - "", words[brick_index]); - ret = -1; - goto out; - } else { - cli_path_strip_trailing_slashes (delimiter + 1); - } - if ((brick_list_size + strlen (words[brick_index]) + 1) > 120000) { - gf_log ("cli", GF_LOG_ERROR, - "total brick list is larger than a request " - "can take (brick_count %d)", brick_count); - ret = -1; - goto out; - } - - host_name = gf_strdup(words[brick_index]); - if (!host_name) { - ret = -1; - gf_log("cli",GF_LOG_ERROR, "Unable to allocate " - "memory"); - goto out; - } - freeptr = host_name; - - strtok_r(host_name, ":", &tmp); - if (!(strcmp(host_name, "localhost") && - strcmp (host_name, "127.0.0.1"))) { - cli_out ("Please provide a valid hostname/ip other " - "than localhost or 127.0.0.1"); - ret = -1; - GF_FREE(freeptr); - goto out; - } - GF_FREE (freeptr); - tmp_list = strdup(brick_list+1); - free_list_ptr = tmp_list; - j = 0; - while(( brick_count != 0) && (j < brick_count)) { - strtok_r (tmp_list, " ", &tmpptr); - if (!(strcmp (tmp_list, words[brick_index]))) { - ret = -1; - cli_out ("Found duplicate" - " exports %s",words[brick_index]); - if (free_list_ptr) - free (free_list_ptr); - goto out; - } - tmp_list = tmpptr; - j++; - } - strcat (brick_list, words[brick_index]); - strcat (brick_list, " "); - brick_list_size += (strlen (words[brick_index]) + 1); - ++brick_count; - ++brick_index; - /* - char key[50]; - snprintf (key, 50, "brick%d", ++brick_count); - ret = dict_set_str (dict, key, (char *)words[brick_index++]); - - if (ret) - goto out; - */ - if (free_list_ptr) - free (free_list_ptr); - } + ret = cli_cmd_bricks_parse (words, wordcount, brick_index, &bricks, + &brick_count); + if (ret) + goto out; /* If brick-count is not valid when replica or stripe is given, exit here */ @@ -278,12 +298,6 @@ cli_cmd_volume_create_parse (const char **words, int wordcount, dict_t **options goto out; } - bricks = gf_strdup (brick_list); - if (!bricks) { - ret = -1; - goto out; - } - ret = dict_set_dynstr (dict, "bricks", bricks); if (ret) goto out; @@ -429,18 +443,8 @@ cli_cmd_volume_add_brick_parse (const char **words, int wordcount, { dict_t *dict = NULL; char *volname = NULL; - char *delimiter = NULL; int ret = -1; int brick_count = 0, brick_index = 0; - int brick_list_size = 1; - char brick_list[120000] = {0,}; - int j = 0; - char *tmp_list = NULL; - char *tmpptr = NULL; - char *host_name = NULL; - char *tmp = NULL; - char *freeptr = NULL; - char *free_list_ptr = NULL; char *bricks = NULL; GF_ASSERT (words); @@ -472,85 +476,10 @@ cli_cmd_volume_add_brick_parse (const char **words, int wordcount, } brick_index = 3; - strcpy (brick_list, " "); - while (brick_index < wordcount) { - delimiter = strchr (words[brick_index], ':'); - if (!delimiter || delimiter == words[brick_index] - || *(delimiter+1) != '/') { - cli_out ("wrong brick type: %s, use :" - "", words[brick_index]); - ret = -1; - goto out; - } else { - cli_path_strip_trailing_slashes (delimiter + 1); - } - - if ((brick_list_size + strlen (words[brick_index]) + 1) > 120000) { - gf_log ("cli", GF_LOG_ERROR, - "total brick list is larger than a request " - "can take (brick_count %d)", brick_count); - ret = -1; - goto out; - } - - host_name = gf_strdup(words[brick_index]); - if (!host_name) { - ret = -1; - gf_log ("cli", GF_LOG_ERROR, "unable to allocate " - "memory"); - goto out; - } - freeptr = host_name; - strtok_r(host_name, ":", &tmp); - if (!(strcmp(host_name, "localhost") && - strcmp (host_name, "127.0.0.1"))) { - cli_out ("Please provide a valid hostname/ip other " - "localhost or 127.0.0.1"); - ret = -1; - GF_FREE (freeptr); - goto out; - } - GF_FREE (freeptr); - - tmp_list = strdup(brick_list+1); - free_list_ptr = tmp_list; - j = 0; - while(( brick_count != 0) && (j < brick_count)) { - strtok_r (tmp_list, " ", &tmpptr); - if (!(strcmp (tmp_list, words[brick_index]))) { - ret = -1; - cli_out ("Found duplicate" - " exports %s",words[brick_index]); - if (free_list_ptr) - free (free_list_ptr); - goto out; - } - tmp_list = tmpptr; - j++; - } - - strcat (brick_list, words[brick_index]); - strcat (brick_list, " "); - brick_list_size += (strlen (words[brick_index]) + 1); - ++brick_count; - ++brick_index; - /* - char key[50]; - snprintf (key, 50, "brick%d", ++brick_count); - ret = dict_set_str (dict, key, (char *)words[brick_index++]); - - if (ret) - goto out; - */ - if (free_list_ptr) - free (free_list_ptr); - } - - bricks = gf_strdup (brick_list); - if (!bricks) { - ret = -1; + ret = cli_cmd_bricks_parse (words, wordcount, brick_index, &bricks, + &brick_count); + if (ret) goto out; - } ret = dict_set_dynstr (dict, "bricks", bricks); if (ret) @@ -1097,3 +1026,48 @@ out: return ret; } +int32_t +cli_cmd_volume_profile_parse (const char **words, int wordcount, + dict_t **options) +{ + dict_t *dict = NULL; + char *volname = NULL; + int ret = -1; + gf1_cli_stats_op op = GF_CLI_STATS_NONE; + + GF_ASSERT (words); + GF_ASSERT (options); + + GF_ASSERT ((strcmp (words[0], "volume")) == 0); + GF_ASSERT ((strcmp (words[1], "profile")) == 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; + + if (strcmp (words[3], "start") == 0) { + op = GF_CLI_STATS_START; + } else if (strcmp (words[3], "stop") == 0) { + op = GF_CLI_STATS_STOP; + } else if (strcmp (words[3], "info") == 0) { + op = GF_CLI_STATS_INFO; + } else { + ret = -1; + goto out; + } + ret = dict_set_int32 (dict, "op", (int32_t)op); + *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 8414a50b6..f53db3d80 100644 --- a/cli/src/cli-cmd-volume.c +++ b/cli/src/cli-cmd-volume.c @@ -570,6 +570,49 @@ out: } +int +cli_cmd_volume_profile_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) +{ + int sent = 0; + int parse_error = 0; + + int ret = -1; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + dict_t *options = NULL; + + ret = cli_cmd_volume_profile_parse (words, wordcount, &options); + + if (ret) { + cli_usage_out (word->pattern); + parse_error = 1; + goto out; + } + + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_PROFILE_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 profile failed"); + } + + return ret; + +} int cli_cmd_volume_set_cbk (struct cli_state *state, struct cli_cmd_word *word, @@ -1024,6 +1067,11 @@ struct cli_cmd volume_cmds[] = { cli_cmd_volume_gsync_set_cbk, "Geo-sync operations"}, #endif + + { "volume profile {start|info|stop}", + cli_cmd_volume_profile_cbk, + "volume profile operations"}, + { NULL, NULL, NULL } }; diff --git a/cli/src/cli-cmd.h b/cli/src/cli-cmd.h index 4daf7fae3..ee784f0e9 100644 --- a/cli/src/cli-cmd.h +++ b/cli/src/cli-cmd.h @@ -43,6 +43,15 @@ struct cli_cmd_volume_get_ctx_ { int flags; }; +typedef struct cli_profile_info_ { + uint64_t fop_hits; + double min_latency; + double max_latency; + double avg_latency; + char *fop_name; + double percentage_avg_latency; +} cli_profile_info_t; + typedef struct cli_cmd_volume_get_ctx_ cli_cmd_volume_get_ctx_t; int cli_cmd_volume_register (struct cli_state *state); diff --git a/cli/src/cli-rpc-ops.c b/cli/src/cli-rpc-ops.c index 1082a908f..31adfb332 100644 --- a/cli/src/cli-rpc-ops.c +++ b/cli/src/cli-rpc-ops.c @@ -2646,6 +2646,324 @@ out: return ret; } +void* +cli_profile_info_elem (void *a, int index) +{ + return ((cli_profile_info_t *)a) + index; +} + +int +cli_profile_info_percentage_cmp (void *a, void *b) +{ + cli_profile_info_t *ia = NULL; + cli_profile_info_t *ib = NULL; + int ret = 0; + + ia = a; + ib = b; + if (ia->percentage_avg_latency < ib->percentage_avg_latency) + ret = -1; + else if (ia->percentage_avg_latency > ib->percentage_avg_latency) + ret = 1; + else + ret = 0; + return ret; +} + +void +cli_profile_info_swap (void *a, void *b) +{ + cli_profile_info_t *ia = NULL; + cli_profile_info_t *ib = NULL; + cli_profile_info_t tmp = {0}; + + ia = a; + ib = b; + tmp = *ia; + *ia = *ib; + *ib = tmp; +} + +void +cmd_profile_volume_brick_out (dict_t *dict, int count, int interval) +{ + char key[256] = {0}; + int i = 0; + uint64_t sec = 0; + uint64_t r_count = 0; + uint64_t w_count = 0; + char *brick = NULL; + uint64_t rb_counts[32] = {0}; + uint64_t wb_counts[32] = {0}; + cli_profile_info_t profile_info[GF_FOP_MAXVALUE] = {{0}}; + char output[128] = {0}; + int per_line = 0; + char read_blocks[128] = {0}; + char write_blocks[128] = {0}; + int index = 0; + int is_header_printed = 0; + int ret = 0; + uint64_t total_fop_hits = 0; + double total_avg_latency = 0; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-brick", count); + ret = dict_get_str (dict, key, &brick); + for (i = 0; i < 32; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-%d-read-%d", count, + interval, (1 << i)); + ret = dict_get_uint64 (dict, key, &rb_counts[i]); + } + + for (i = 0; i < 32; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-%d-write-%d", count, interval, + (1<rpc_status) { + goto out; + } + + gf_log ("cli", GF_LOG_DEBUG, "Received resp to profile"); + 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 profile %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_INFO) { + ret = 0; + goto out; + } + + ret = dict_get_int32 (dict, "count", &brick_count); + if (ret) + goto out; + while (i <= brick_count) { + snprintf (key, sizeof (key), "%d-cumulative", i); + ret = dict_get_int32 (dict, key, &interval); + if (ret == 0) { + cmd_profile_volume_brick_out (dict, i, interval); + } + snprintf (key, sizeof (key), "%d-interval", i); + ret = dict_get_int32 (dict, key, &interval); + if (ret == 0) { + cmd_profile_volume_brick_out (dict, i, interval); + } + i++; + } + ret = rsp.op_ret; + +out: + cli_cmd_broadcast_response (ret); + return ret; +} + +int32_t +gf_cli3_1_profile_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 = cli_cmd_submit (&req, frame, cli_rpc_prog, + GLUSTER_CLI_PROFILE_VOLUME, NULL, + gf_xdr_from_cli_stats_volume_req, + this, gf_cli3_1_profile_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 }, @@ -2673,6 +2991,7 @@ struct rpc_clnt_procedure gluster_cli_actors[GLUSTER_CLI_MAXVALUE] = { [GLUSTER_CLI_RESET_VOLUME] = {"RESET_VOLUME", gf_cli3_1_reset_volume}, [GLUSTER_CLI_FSM_LOG] = {"FSM_LOG", gf_cli3_1_fsm_log}, [GLUSTER_CLI_GSYNC_SET] = {"GSYNC_SET", gf_cli3_1_gsync_set}, + [GLUSTER_CLI_PROFILE_VOLUME] = {"PROFILE_VOLUME", gf_cli3_1_profile_volume} }; struct rpc_clnt_program cli_prog = { diff --git a/cli/src/cli.c b/cli/src/cli.c index 00faffe42..ef88d0420 100644 --- a/cli/src/cli.c +++ b/cli/src/cli.c @@ -491,7 +491,6 @@ struct rpc_clnt * cli_rpc_init (struct cli_state *state) { struct rpc_clnt *rpc = NULL; - struct rpc_clnt_config rpc_cfg = {0,}; dict_t *options = NULL; int ret = -1; int port = CLI_GLUSTERD_PORT; @@ -511,9 +510,6 @@ cli_rpc_init (struct cli_state *state) if (state->remote_port) port = state->remote_port; - rpc_cfg.remote_host = state->remote_host; - rpc_cfg.remote_port = port; - ret = dict_set_int32 (options, "remote-port", port); if (ret) goto out; @@ -535,6 +531,11 @@ cli_rpc_init (struct cli_state *state) rpc_clnt_start (rpc); out: + if (ret) { + if (rpc) + rpc_clnt_unref (rpc); + rpc = NULL; + } return rpc; } diff --git a/cli/src/cli.h b/cli/src/cli.h index 77bc249d9..acfd5b539 100644 --- a/cli/src/cli.h +++ b/cli/src/cli.h @@ -217,4 +217,7 @@ cli_rpc_notify (struct rpc_clnt *rpc, void *mydata, rpc_clnt_event_t event, void *data); void cli_path_strip_trailing_slashes (char *path); +int32_t +cli_cmd_volume_profile_parse (const char **words, int wordcount, + dict_t **options); #endif /* __CLI_H__ */ -- cgit