Merge from Trond
[m6w6/libmemcached] / clients / memstat.c
1 #include "libmemcached/common.h"
2 #include <stdio.h>
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <sys/types.h>
6 #include <sys/mman.h>
7 #include <fcntl.h>
8 #include <string.h>
9 #include <getopt.h>
10 #include <sys/time.h>
11
12 #include <libmemcached/memcached.h>
13
14 #include "client_options.h"
15 #include "utilities.h"
16
17 #define PROGRAM_NAME "memstat"
18 #define PROGRAM_DESCRIPTION "Output the state of a memcached cluster."
19
20 /* Prototypes */
21 static void options_parse(int argc, char *argv[]);
22 static void run_analyzer(memcached_st *memc, memcached_stat_st *memc_stat,
23 memcached_server_st *server_list);
24 static void print_server_listing(memcached_st *memc, memcached_stat_st *memc_stat,
25 memcached_server_st *server_list);
26 static void print_analysis_report(memcached_st *memc,
27 memcached_analysis_st *report,
28 memcached_server_st *server_list);
29
30 static int opt_verbose= 0;
31 static int opt_displayflag= 0;
32 static int opt_analyze= 0;
33 static char *opt_servers= NULL;
34 static char *analyze_mode= NULL;
35
36 static struct option long_options[]=
37 {
38 {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
39 {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
40 {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
41 {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
42 {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
43 {(OPTIONSTRING)"flag", no_argument, &opt_displayflag, OPT_FLAG},
44 {(OPTIONSTRING)"analyze", optional_argument, NULL, OPT_ANALYZE},
45 {0, 0, 0, 0},
46 };
47
48 int main(int argc, char *argv[])
49 {
50 memcached_return rc;
51 memcached_st *memc;
52 memcached_stat_st *memc_stat;
53 memcached_server_st *servers;
54 memcached_server_st *server_list;
55
56 options_parse(argc, argv);
57
58 if (!opt_servers)
59 {
60 char *temp;
61
62 if ((temp= getenv("MEMCACHED_SERVERS")))
63 opt_servers= strdup(temp);
64 else
65 {
66 fprintf(stderr, "No Servers provided\n\n");
67 help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, 0);
68 exit(1);
69 }
70 }
71
72 memc= memcached_create(NULL);
73
74 servers= memcached_servers_parse(opt_servers);
75 memcached_server_push(memc, servers);
76 memcached_server_list_free(servers);
77
78 memc_stat= memcached_stat(memc, NULL, &rc);
79
80 if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_SOME_ERRORS)
81 {
82 printf("Failure to communicate with servers (%s)\n",
83 memcached_strerror(memc, rc));
84 exit(1);
85 }
86
87 server_list= memcached_server_list(memc);
88
89 if (opt_analyze)
90 run_analyzer(memc, memc_stat, server_list);
91 else
92 print_server_listing(memc, memc_stat, server_list);
93
94 free(memc_stat);
95 free(opt_servers);
96
97 memcached_free(memc);
98
99 return 0;
100 }
101
102 static void run_analyzer(memcached_st *memc, memcached_stat_st *memc_stat,
103 memcached_server_st *server_list)
104 {
105 memcached_return rc;
106
107 if (analyze_mode == NULL)
108 {
109 memcached_analysis_st *report;
110 report= memcached_analyze(memc, memc_stat, &rc);
111 if (rc != MEMCACHED_SUCCESS || report == NULL)
112 {
113 printf("Failure to analyze servers (%s)\n",
114 memcached_strerror(memc, rc));
115 exit(1);
116 }
117 print_analysis_report(memc, report, server_list);
118 free(report);
119 }
120 else if (strcmp(analyze_mode, "latency") == 0)
121 {
122 memcached_st **servers;
123 uint32_t x, y, flags, server_count= memcached_server_count(memc);
124 uint32_t num_of_tests= 32;
125 const char *test_key= "libmemcached_test_key";
126
127 servers= malloc(sizeof(memcached_st*) * server_count);
128 if (!servers)
129 {
130 fprintf(stderr, "Failed to allocate memory\n");
131 return;
132 }
133
134 for (x= 0; x < server_count; x++)
135 {
136 if((servers[x]= memcached_create(NULL)) == NULL)
137 {
138 fprintf(stderr, "Failed to memcached_create()\n");
139 if (x > 0)
140 memcached_free(servers[0]);
141 x--;
142 for (; x > 0; x--)
143 memcached_free(servers[x]);
144
145 free(servers);
146 return;
147 }
148 memcached_server_add(servers[x],
149 memcached_server_name(memc, server_list[x]),
150 memcached_server_port(memc, server_list[x]));
151 }
152
153 printf("Network Latency Test:\n\n");
154 struct timeval start_time, end_time;
155 long elapsed_time, slowest_time= 0, slowest_server= 0;
156
157 for (x= 0; x < server_count; x++)
158 {
159 gettimeofday(&start_time, NULL);
160 for (y= 0; y < num_of_tests; y++)
161 {
162 size_t vlen;
163 char *val= memcached_get(servers[x], test_key, strlen(test_key),
164 &vlen, &flags, &rc);
165 if (rc != MEMCACHED_NOTFOUND && rc != MEMCACHED_SUCCESS)
166 break;
167 free(val);
168 }
169 gettimeofday(&end_time, NULL);
170
171 elapsed_time= (long) timedif(end_time, start_time);
172 elapsed_time /= (long) num_of_tests;
173
174 if (elapsed_time > slowest_time)
175 {
176 slowest_server= (long)x;
177 slowest_time= elapsed_time;
178 }
179
180 if (rc != MEMCACHED_NOTFOUND && rc != MEMCACHED_SUCCESS)
181 {
182 printf("\t %s (%d) => failed to reach the server\n",
183 memcached_server_name(memc, server_list[x]),
184 memcached_server_port(memc, server_list[x]));
185 }
186 else
187 {
188 printf("\t %s (%d) => %ld.%ld seconds\n",
189 memcached_server_name(memc, server_list[x]),
190 memcached_server_port(memc, server_list[x]),
191 elapsed_time / 1000, elapsed_time % 1000);
192 }
193 }
194
195 if (server_count > 1 && slowest_time > 0)
196 {
197 printf("---\n");
198 printf("Slowest Server: %s (%d) => %ld.%ld seconds\n",
199 memcached_server_name(memc, server_list[slowest_server]),
200 memcached_server_port(memc, server_list[slowest_server]),
201 slowest_time / 1000, slowest_time % 1000);
202 }
203 printf("\n");
204
205 for (x= 0; x < server_count; x++)
206 memcached_free(servers[x]);
207
208 free(servers);
209 free(analyze_mode);
210 }
211 else
212 {
213 fprintf(stderr, "Invalid Analyzer Option provided\n");
214 free(analyze_mode);
215 }
216 }
217
218 static void print_server_listing(memcached_st *memc, memcached_stat_st *memc_stat,
219 memcached_server_st *server_list)
220 {
221 unsigned int x;
222 memcached_return rc;
223
224 printf("Listing %u Server\n\n", memcached_server_count(memc));
225 for (x= 0; x < memcached_server_count(memc); x++)
226 {
227 char **list;
228 char **ptr;
229
230 list= memcached_stat_get_keys(memc, &memc_stat[x], &rc);
231
232 printf("Server: %s (%u)\n", memcached_server_name(memc, server_list[x]),
233 memcached_server_port(memc, server_list[x]));
234 for (ptr= list; *ptr; ptr++)
235 {
236 char *value= memcached_stat_get_value(memc, &memc_stat[x], *ptr, &rc);
237
238 printf("\t %s: %s\n", *ptr, value);
239 free(value);
240 }
241
242 free(list);
243 printf("\n");
244 }
245 }
246
247 static void print_analysis_report(memcached_st *memc,
248 memcached_analysis_st *report,
249 memcached_server_st *server_list)
250 {
251 uint32_t server_count= memcached_server_count(memc);
252
253 printf("Memcached Cluster Analysis Report\n\n");
254
255 printf("\tNumber of Servers Analyzed : %d\n", server_count);
256 printf("\tAverage Item Size (incl/overhead) : %u bytes\n",
257 report->average_item_size);
258
259 if (server_count == 1)
260 {
261 printf("\nFor a detailed report, you must supply multiple servers.\n");
262 return;
263 }
264
265 printf("\n");
266 printf("\tNode with most memory consumption : %s:%u (%llu bytes)\n",
267 memcached_server_name(memc, server_list[report->most_consumed_server]),
268 memcached_server_port(memc, server_list[report->most_consumed_server]),
269 (unsigned long long)report->most_used_bytes);
270 printf("\tNode with least free space : %s:%u (%llu bytes remaining)\n",
271 memcached_server_name(memc, server_list[report->least_free_server]),
272 memcached_server_port(memc, server_list[report->least_free_server]),
273 (unsigned long long)report->least_remaining_bytes);
274 printf("\tNode with longest uptime : %s:%u (%us)\n",
275 memcached_server_name(memc, server_list[report->oldest_server]),
276 memcached_server_port(memc, server_list[report->oldest_server]),
277 report->longest_uptime);
278 printf("\tPool-wide Hit Ratio : %1.f%%\n", report->pool_hit_ratio);
279 printf("\n");
280 }
281
282 static void options_parse(int argc, char *argv[])
283 {
284 memcached_programs_help_st help_options[]=
285 {
286 {0},
287 };
288
289 int option_index= 0;
290 int option_rv;
291
292 while (1)
293 {
294 option_rv= getopt_long(argc, argv, "Vhvds:a", long_options, &option_index);
295 if (option_rv == -1) break;
296 switch (option_rv)
297 {
298 case 0:
299 break;
300 case OPT_VERBOSE: /* --verbose or -v */
301 opt_verbose = OPT_VERBOSE;
302 break;
303 case OPT_DEBUG: /* --debug or -d */
304 opt_verbose = OPT_DEBUG;
305 break;
306 case OPT_VERSION: /* --version or -V */
307 version_command(PROGRAM_NAME);
308 break;
309 case OPT_HELP: /* --help or -h */
310 help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
311 break;
312 case OPT_SERVERS: /* --servers or -s */
313 opt_servers= strdup(optarg);
314 break;
315 case OPT_ANALYZE: /* --analyze or -a */
316 opt_analyze= OPT_ANALYZE;
317 analyze_mode= (optarg) ? strdup(optarg) : NULL;
318 break;
319 case '?':
320 /* getopt_long already printed an error message. */
321 exit(1);
322 default:
323 abort();
324 }
325 }
326 }