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