X-Git-Url: https://git.m6w6.name/?a=blobdiff_plain;f=clients%2Fmemstat.c;h=0bc365ac8010eabbe6491eb5174cad66e8d5cda3;hb=c79b88bc75d37c933e9d05c83113ccb26ded3683;hp=36ee343e156745baafb45034a4f4271ccb407e76;hpb=7c41f51579dc36df33ec83a743dba8cc1ddc3e3f;p=m6w6%2Flibmemcached diff --git a/clients/memstat.c b/clients/memstat.c index 36ee343e..0bc365ac 100644 --- a/clients/memstat.c +++ b/clients/memstat.c @@ -1,11 +1,26 @@ +/* LibMemcached + * Copyright (C) 2006-2009 Brian Aker + * All rights reserved. + * + * Use and distribution licensed under the BSD license. See + * the COPYING file in the parent directory for full text. + * + * Summary: + * + * Authors: + * Brian Aker + * Toru Maesaka + */ +#include "config.h" + #include #include #include #include -#include #include #include #include +#include #include @@ -16,24 +31,60 @@ #define PROGRAM_DESCRIPTION "Output the state of a memcached cluster." /* Prototypes */ -void options_parse(int argc, char *argv[]); +static void options_parse(int argc, char *argv[]); +static void run_analyzer(memcached_st *memc, memcached_stat_st *memc_stat); +static void print_analysis_report(memcached_st *memc, + memcached_analysis_st *report); static int opt_verbose= 0; static int opt_displayflag= 0; +static int opt_analyze= 0; static char *opt_servers= NULL; +static char *analyze_mode= NULL; + +static struct option long_options[]= +{ + {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION}, + {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP}, + {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE}, + {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG}, + {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS}, + {(OPTIONSTRING)"flag", no_argument, &opt_displayflag, OPT_FLAG}, + {(OPTIONSTRING)"analyze", optional_argument, NULL, OPT_ANALYZE}, + {0, 0, 0, 0}, +}; + + +static memcached_return_t stat_printer(memcached_server_instance_st instance, + const char *key, size_t key_length, + const char *value, size_t value_length, + void *context) +{ + static memcached_server_instance_st last= NULL; + (void)context; + + if (last != instance) + { + printf("Server: %s (%u)\n", memcached_server_name(instance), + (uint32_t)memcached_server_port(instance)); + last= instance; + } + + printf("\t %.*s: %.*s\n", (int)key_length, key, (int)value_length, value); + + return MEMCACHED_SUCCESS; +} int main(int argc, char *argv[]) { - unsigned int x; - memcached_return rc; + memcached_return_t rc; memcached_st *memc; - memcached_stat_st *stat; memcached_server_st *servers; - memcached_server_st *server_list; options_parse(argc, argv); + initialize_sockets(); - if (!opt_servers) + if (! opt_servers) { char *temp; @@ -41,7 +92,8 @@ int main(int argc, char *argv[]) opt_servers= strdup(temp); else { - fprintf(stderr, "No Servers provided\n"); + fprintf(stderr, "No Servers provided\n\n"); + help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, 0); exit(1); } } @@ -49,75 +101,217 @@ int main(int argc, char *argv[]) memc= memcached_create(NULL); servers= memcached_servers_parse(opt_servers); - memcached_server_push(memc, servers); + rc= memcached_server_push(memc, servers); memcached_server_list_free(servers); - stat= memcached_stat(memc, NULL, &rc); - if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_SOME_ERRORS) { printf("Failure to communicate with servers (%s)\n", - memcached_strerror(memc, rc)); + memcached_strerror(memc, rc)); exit(1); } - server_list= memcached_server_list(memc); + if (opt_analyze) + { + memcached_stat_st *memc_stat; + + memc_stat= memcached_stat(memc, NULL, &rc); + + if (! memc_stat) + exit(-1); + + run_analyzer(memc, memc_stat); + + memcached_stat_free(memc, memc_stat); + } + else + { + rc= memcached_stat_execute(memc, NULL, stat_printer, NULL); + } + + free(opt_servers); + + memcached_free(memc); + + return rc == MEMCACHED_SUCCESS ? 0: -1; +} + +static void run_analyzer(memcached_st *memc, memcached_stat_st *memc_stat) +{ + memcached_return_t rc; - printf("Listing %u Server\n\n", memcached_server_count(memc)); - for (x= 0; x < memcached_server_count(memc); x++) + if (analyze_mode == NULL) + { + memcached_analysis_st *report; + report= memcached_analyze(memc, memc_stat, &rc); + if (rc != MEMCACHED_SUCCESS || report == NULL) + { + printf("Failure to analyze servers (%s)\n", + memcached_strerror(memc, rc)); + exit(1); + } + print_analysis_report(memc, report); + free(report); + } + else if (strcmp(analyze_mode, "latency") == 0) { - char **list; - char **ptr; + memcached_st **servers; + uint32_t flags, server_count= memcached_server_count(memc); + uint32_t num_of_tests= 32; + const char *test_key= "libmemcached_test_key"; + + servers= malloc(sizeof(memcached_st*) * server_count); + if (!servers) + { + fprintf(stderr, "Failed to allocate memory\n"); + return; + } + + for (uint32_t x= 0; x < server_count; x++) + { + memcached_server_instance_st instance= + memcached_server_instance_by_position(memc, x); + + if ((servers[x]= memcached_create(NULL)) == NULL) + { + fprintf(stderr, "Failed to memcached_create()\n"); + if (x > 0) + memcached_free(servers[0]); + x--; + for (; x > 0; x--) + memcached_free(servers[x]); - list= memcached_stat_get_keys(memc, &stat[x], &rc); + free(servers); + return; + } + memcached_server_add(servers[x], + memcached_server_name(instance), + memcached_server_port(instance)); + } + + printf("Network Latency Test:\n\n"); + struct timeval start_time, end_time; + uint32_t slowest_server= 0; + long elapsed_time, slowest_time= 0; - printf("Server: %s (%u)\n", memcached_server_name(memc, server_list[x]), - memcached_server_port(memc, server_list[x])); - for (ptr= list; *ptr; ptr++) + for (uint32_t x= 0; x < server_count; x++) { - memcached_return rc; - char *value= memcached_stat_get_value(memc, &stat[x], *ptr, &rc); + memcached_server_instance_st instance= + memcached_server_instance_by_position(memc, x); + gettimeofday(&start_time, NULL); + + for (uint32_t y= 0; y < num_of_tests; y++) + { + size_t vlen; + char *val= memcached_get(servers[x], test_key, strlen(test_key), + &vlen, &flags, &rc); + if (rc != MEMCACHED_NOTFOUND && rc != MEMCACHED_SUCCESS) + break; + free(val); + } + gettimeofday(&end_time, NULL); + + elapsed_time= (long) timedif(end_time, start_time); + elapsed_time /= (long) num_of_tests; - printf("\t %s: %s\n", *ptr, value); - free(value); + if (elapsed_time > slowest_time) + { + slowest_server= x; + slowest_time= elapsed_time; + } + + if (rc != MEMCACHED_NOTFOUND && rc != MEMCACHED_SUCCESS) + { + printf("\t %s (%d) => failed to reach the server\n", + memcached_server_name(instance), + memcached_server_port(instance)); + } + else + { + printf("\t %s (%d) => %ld.%ld seconds\n", + memcached_server_name(instance), + memcached_server_port(instance), + elapsed_time / 1000, elapsed_time % 1000); + } } - free(list); + if (server_count > 1 && slowest_time > 0) + { + memcached_server_instance_st slowest= + memcached_server_instance_by_position(memc, slowest_server); + + printf("---\n"); + printf("Slowest Server: %s (%d) => %ld.%ld seconds\n", + memcached_server_name(slowest), + memcached_server_port(slowest), + slowest_time / 1000, slowest_time % 1000); + } printf("\n"); + + for (uint32_t x= 0; x < server_count; x++) + memcached_free(servers[x]); + + free(servers); + free(analyze_mode); + } + else + { + fprintf(stderr, "Invalid Analyzer Option provided\n"); + free(analyze_mode); } +} - free(stat); - free(opt_servers); +static void print_analysis_report(memcached_st *memc, + memcached_analysis_st *report) + +{ + uint32_t server_count= memcached_server_count(memc); + memcached_server_instance_st most_consumed_server= memcached_server_instance_by_position(memc, report->most_consumed_server); + memcached_server_instance_st least_free_server= memcached_server_instance_by_position(memc, report->least_free_server); + memcached_server_instance_st oldest_server= memcached_server_instance_by_position(memc, report->oldest_server); - memcached_free(memc); + printf("Memcached Cluster Analysis Report\n\n"); - return 0; + printf("\tNumber of Servers Analyzed : %u\n", server_count); + printf("\tAverage Item Size (incl/overhead) : %u bytes\n", + report->average_item_size); + + if (server_count == 1) + { + printf("\nFor a detailed report, you must supply multiple servers.\n"); + return; + } + + printf("\n"); + printf("\tNode with most memory consumption : %s:%u (%llu bytes)\n", + memcached_server_name(most_consumed_server), + (uint32_t)memcached_server_port(most_consumed_server), + (unsigned long long)report->most_used_bytes); + printf("\tNode with least free space : %s:%u (%llu bytes remaining)\n", + memcached_server_name(least_free_server), + (uint32_t)memcached_server_port(least_free_server), + (unsigned long long)report->least_remaining_bytes); + printf("\tNode with longest uptime : %s:%u (%us)\n", + memcached_server_name(oldest_server), + (uint32_t)memcached_server_port(oldest_server), + report->longest_uptime); + printf("\tPool-wide Hit Ratio : %1.f%%\n", report->pool_hit_ratio); + printf("\n"); } -void options_parse(int argc, char *argv[]) +static void options_parse(int argc, char *argv[]) { memcached_programs_help_st help_options[]= { {0}, }; - static struct option long_options[]= - { - {"version", no_argument, NULL, OPT_VERSION}, - {"help", no_argument, NULL, OPT_HELP}, - {"verbose", no_argument, &opt_verbose, OPT_VERBOSE}, - {"debug", no_argument, &opt_verbose, OPT_DEBUG}, - {"servers", required_argument, NULL, OPT_SERVERS}, - {"flag", no_argument, &opt_displayflag, OPT_FLAG}, - {0, 0, 0, 0}, - }; - int option_index= 0; int option_rv; while (1) { - option_rv= getopt_long(argc, argv, "Vhvds:", long_options, &option_index); + option_rv= getopt_long(argc, argv, "Vhvds:a", long_options, &option_index); if (option_rv == -1) break; switch (option_rv) { @@ -138,6 +332,10 @@ void options_parse(int argc, char *argv[]) case OPT_SERVERS: /* --servers or -s */ opt_servers= strdup(optarg); break; + case OPT_ANALYZE: /* --analyze or -a */ + opt_analyze= OPT_ANALYZE; + analyze_mode= (optarg) ? strdup(optarg) : NULL; + break; case '?': /* getopt_long already printed an error message. */ exit(1);