src/libmemcached: apply clang-format
[m6w6/libmemcached] / src / libmemcached / stats.cc
1 /*
2 +--------------------------------------------------------------------+
3 | libmemcached - C/C++ Client Library for memcached |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted under the terms of the BSD license. |
7 | You should have received a copy of the license in a bundled file |
8 | named LICENSE; in case you did not receive a copy you can review |
9 | the terms online at: https://opensource.org/licenses/BSD-3-Clause |
10 +--------------------------------------------------------------------+
11 | Copyright (c) 2006-2014 Brian Aker https://datadifferential.com/ |
12 | Copyright (c) 2020 Michael Wallner <mike@php.net> |
13 +--------------------------------------------------------------------+
14 */
15
16 #include "libmemcached/common.h"
17
18 static const char *memcached_stat_keys[] = {"pid",
19 "uptime",
20 "time",
21 "version",
22 "pointer_size",
23 "rusage_user",
24 "rusage_system",
25 "curr_items",
26 "total_items",
27 "bytes",
28 "curr_connections",
29 "total_connections",
30 "connection_structures",
31 "cmd_get",
32 "cmd_set",
33 "get_hits",
34 "get_misses",
35 "evictions",
36 "bytes_read",
37 "bytes_written",
38 "limit_maxbytes",
39 "threads",
40 NULL};
41
42 struct local_context {
43 memcached_stat_fn func;
44 void *context;
45 const char *args;
46 const size_t args_length;
47
48 local_context(memcached_stat_fn func_arg, void *context_arg, const char *args_arg,
49 const size_t args_length_arg)
50 : func(func_arg)
51 , context(context_arg)
52 , args(args_arg)
53 , args_length(args_length_arg) {}
54 };
55
56 static memcached_return_t set_data(memcached_stat_st *memc_stat, const char *key,
57 const char *value) {
58 if (strlen(key) < 1) {
59 WATCHPOINT_STRING(key);
60 return MEMCACHED_UNKNOWN_STAT_KEY;
61 } else if (strcmp("pid", key) == 0) {
62 errno = 0;
63 int64_t temp = strtoll(value, (char **) NULL, 10);
64 if (errno != 0) {
65 return MEMCACHED_FAILURE;
66 }
67
68 if (temp <= INT32_MAX and (sizeof(pid_t) == sizeof(int32_t))) {
69 memc_stat->pid = pid_t(temp);
70 } else if (temp > -1) {
71 memc_stat->pid = pid_t(temp);
72 } else {
73 // If we got a value less then -1 then something went wrong in the
74 // protocol
75 }
76 } else if (not strcmp("uptime", key)) {
77 errno = 0;
78 memc_stat->uptime = strtoul(value, (char **) NULL, 10);
79 if (errno != 0) {
80 return MEMCACHED_FAILURE;
81 }
82 } else if (not strcmp("time", key)) {
83 errno = 0;
84 memc_stat->time = strtoul(value, (char **) NULL, 10);
85 if (errno != 0) {
86 return MEMCACHED_FAILURE;
87 }
88 } else if (not strcmp("version", key)) {
89 memcpy(memc_stat->version, value, strlen(value));
90 memc_stat->version[strlen(value)] = 0;
91 } else if (not strcmp("pointer_size", key)) {
92 errno = 0;
93 memc_stat->pointer_size = strtoul(value, (char **) NULL, 10);
94 if (errno != 0) {
95 return MEMCACHED_FAILURE;
96 }
97 } else if (not strcmp("rusage_user", key)) {
98 char *walk_ptr;
99 for (walk_ptr = (char *) value; (!ispunct(*walk_ptr)); walk_ptr++) {
100 };
101 *walk_ptr = 0;
102 walk_ptr++;
103
104 errno = 0;
105 memc_stat->rusage_user_seconds = strtoul(value, (char **) NULL, 10);
106 if (errno != 0) {
107 return MEMCACHED_FAILURE;
108 }
109
110 errno = 0;
111 memc_stat->rusage_user_microseconds = strtoul(walk_ptr, (char **) NULL, 10);
112 if (errno != 0) {
113 return MEMCACHED_FAILURE;
114 }
115 } else if (not strcmp("rusage_system", key)) {
116 char *walk_ptr;
117 for (walk_ptr = (char *) value; (!ispunct(*walk_ptr)); walk_ptr++) {
118 };
119 *walk_ptr = 0;
120 walk_ptr++;
121
122 errno = 0;
123 memc_stat->rusage_system_seconds = strtoul(value, (char **) NULL, 10);
124 if (errno != 0) {
125 return MEMCACHED_FAILURE;
126 }
127
128 errno = 0;
129 memc_stat->rusage_system_microseconds = strtoul(walk_ptr, (char **) NULL, 10);
130 if (errno != 0) {
131 return MEMCACHED_FAILURE;
132 }
133 } else if (not strcmp("curr_items", key)) {
134 errno = 0;
135 memc_stat->curr_items = strtoul(value, (char **) NULL, 10);
136 if (errno != 0) {
137 return MEMCACHED_FAILURE;
138 }
139 } else if (not strcmp("total_items", key)) {
140 errno = 0;
141 memc_stat->total_items = strtoul(value, (char **) NULL, 10);
142 if (errno != 0) {
143 return MEMCACHED_FAILURE;
144 }
145 } else if (not strcmp("bytes_read", key)) {
146 errno = 0;
147 memc_stat->bytes_read = strtoull(value, (char **) NULL, 10);
148 if (errno != 0) {
149 return MEMCACHED_FAILURE;
150 }
151 } else if (not strcmp("bytes_written", key)) {
152 errno = 0;
153 memc_stat->bytes_written = strtoull(value, (char **) NULL, 10);
154 if (errno != 0) {
155 return MEMCACHED_FAILURE;
156 }
157 } else if (not strcmp("bytes", key)) {
158 errno = 0;
159 memc_stat->bytes = strtoull(value, (char **) NULL, 10);
160 if (errno != 0) {
161 return MEMCACHED_FAILURE;
162 }
163 } else if (not strcmp("curr_connections", key)) {
164 errno = 0;
165 memc_stat->curr_connections = strtoull(value, (char **) NULL, 10);
166 if (errno != 0) {
167 return MEMCACHED_FAILURE;
168 }
169 } else if (not strcmp("total_connections", key)) {
170 errno = 0;
171 memc_stat->total_connections = strtoull(value, (char **) NULL, 10);
172 if (errno != 0) {
173 return MEMCACHED_FAILURE;
174 }
175 } else if (not strcmp("connection_structures", key)) {
176 errno = 0;
177 memc_stat->connection_structures = strtoul(value, (char **) NULL, 10);
178 if (errno != 0) {
179 return MEMCACHED_FAILURE;
180 }
181 } else if (not strcmp("cmd_get", key)) {
182 errno = 0;
183 memc_stat->cmd_get = strtoull(value, (char **) NULL, 10);
184 if (errno != 0) {
185 return MEMCACHED_FAILURE;
186 }
187 } else if (not strcmp("cmd_set", key)) {
188 errno = 0;
189 memc_stat->cmd_set = strtoull(value, (char **) NULL, 10);
190 if (errno != 0) {
191 return MEMCACHED_FAILURE;
192 }
193 } else if (not strcmp("get_hits", key)) {
194 errno = 0;
195 memc_stat->get_hits = strtoull(value, (char **) NULL, 10);
196 if (errno != 0) {
197 return MEMCACHED_FAILURE;
198 }
199 } else if (not strcmp("get_misses", key)) {
200 errno = 0;
201 memc_stat->get_misses = strtoull(value, (char **) NULL, 10);
202 if (errno != 0) {
203 return MEMCACHED_FAILURE;
204 }
205 } else if (not strcmp("evictions", key)) {
206 errno = 0;
207 memc_stat->evictions = strtoull(value, (char **) NULL, 10);
208 if (errno != 0) {
209 return MEMCACHED_FAILURE;
210 }
211 } else if (not strcmp("limit_maxbytes", key)) {
212 errno = 0;
213 memc_stat->limit_maxbytes = strtoull(value, (char **) NULL, 10);
214 if (errno != 0) {
215 return MEMCACHED_FAILURE;
216 }
217 } else if (not strcmp("threads", key)) {
218 errno = 0;
219 memc_stat->threads = strtoul(value, (char **) NULL, 10);
220 if (errno != 0) {
221 return MEMCACHED_FAILURE;
222 }
223 } else if ((strcmp("delete_misses", key) == 0 or /* New stats in the 1.3 beta */
224 strcmp("delete_hits", key) == 0 or /* Just swallow them for now.. */
225 strcmp("incr_misses", key) == 0 or strcmp("incr_hits", key) == 0
226 or strcmp("decr_misses", key) == 0 or strcmp("decr_hits", key) == 0
227 or strcmp("cas_misses", key) == 0 or strcmp("cas_hits", key) == 0
228 or strcmp("cas_badval", key) == 0 or strcmp("cmd_flush", key) == 0
229 or strcmp("accepting_conns", key) == 0 or strcmp("listen_disabled_num", key) == 0
230 or strcmp("conn_yields", key) == 0 or strcmp("auth_cmds", key) == 0
231 or strcmp("auth_errors", key) == 0 or strcmp("reclaimed", key) == 0)
232 == 0)
233 {
234 WATCHPOINT_STRING(key);
235 /* return MEMCACHED_UNKNOWN_STAT_KEY; */
236 return MEMCACHED_SUCCESS;
237 }
238
239 return MEMCACHED_SUCCESS;
240 }
241
242 char *memcached_stat_get_value(const memcached_st *shell, memcached_stat_st *memc_stat,
243 const char *key, memcached_return_t *error) {
244 memcached_return_t not_used;
245 if (error == NULL) {
246 error = &not_used;
247 }
248
249 if (memc_stat == NULL) {
250 *error = MEMCACHED_INVALID_ARGUMENTS;
251 return NULL;
252 }
253
254 char buffer[SMALL_STRING_LEN];
255 int length;
256
257 *error = MEMCACHED_SUCCESS;
258
259 if (!strcmp(key, "pid")) {
260 length = snprintf(buffer, SMALL_STRING_LEN, "%lld", (signed long long) memc_stat->pid);
261 } else if (!strcmp(key, "uptime")) {
262 length = snprintf(buffer, SMALL_STRING_LEN, "%lu", memc_stat->uptime);
263 } else if (!strcmp(key, "time")) {
264 length = snprintf(buffer, SMALL_STRING_LEN, "%llu", (unsigned long long) memc_stat->time);
265 } else if (!strcmp(key, "version")) {
266 length = snprintf(buffer, SMALL_STRING_LEN, "%s", memc_stat->version);
267 } else if (!strcmp(key, "pointer_size")) {
268 length = snprintf(buffer, SMALL_STRING_LEN, "%lu", memc_stat->pointer_size);
269 } else if (!strcmp(key, "rusage_user")) {
270 length = snprintf(buffer, SMALL_STRING_LEN, "%lu.%lu", memc_stat->rusage_user_seconds,
271 memc_stat->rusage_user_microseconds);
272 } else if (!strcmp(key, "rusage_system")) {
273 length = snprintf(buffer, SMALL_STRING_LEN, "%lu.%lu", memc_stat->rusage_system_seconds,
274 memc_stat->rusage_system_microseconds);
275 } else if (!strcmp(key, "curr_items")) {
276 length = snprintf(buffer, SMALL_STRING_LEN, "%lu", memc_stat->curr_items);
277 } else if (!strcmp(key, "total_items")) {
278 length = snprintf(buffer, SMALL_STRING_LEN, "%lu", memc_stat->total_items);
279 } else if (!strcmp(key, "curr_connections")) {
280 length = snprintf(buffer, SMALL_STRING_LEN, "%lu", memc_stat->curr_connections);
281 } else if (!strcmp(key, "total_connections")) {
282 length = snprintf(buffer, SMALL_STRING_LEN, "%lu", memc_stat->total_connections);
283 } else if (!strcmp(key, "connection_structures")) {
284 length = snprintf(buffer, SMALL_STRING_LEN, "%lu", memc_stat->connection_structures);
285 } else if (!strcmp(key, "cmd_get")) {
286 length = snprintf(buffer, SMALL_STRING_LEN, "%llu", (unsigned long long) memc_stat->cmd_get);
287 } else if (!strcmp(key, "cmd_set")) {
288 length = snprintf(buffer, SMALL_STRING_LEN, "%llu", (unsigned long long) memc_stat->cmd_set);
289 } else if (!strcmp(key, "get_hits")) {
290 length = snprintf(buffer, SMALL_STRING_LEN, "%llu", (unsigned long long) memc_stat->get_hits);
291 } else if (!strcmp(key, "get_misses")) {
292 length = snprintf(buffer, SMALL_STRING_LEN, "%llu", (unsigned long long) memc_stat->get_misses);
293 } else if (!strcmp(key, "evictions")) {
294 length = snprintf(buffer, SMALL_STRING_LEN, "%llu", (unsigned long long) memc_stat->evictions);
295 } else if (!strcmp(key, "bytes_read")) {
296 length = snprintf(buffer, SMALL_STRING_LEN, "%llu", (unsigned long long) memc_stat->bytes_read);
297 } else if (!strcmp(key, "bytes_written")) {
298 length =
299 snprintf(buffer, SMALL_STRING_LEN, "%llu", (unsigned long long) memc_stat->bytes_written);
300 } else if (!strcmp(key, "bytes")) {
301 length = snprintf(buffer, SMALL_STRING_LEN, "%llu", (unsigned long long) memc_stat->bytes);
302 } else if (!strcmp(key, "limit_maxbytes")) {
303 length =
304 snprintf(buffer, SMALL_STRING_LEN, "%llu", (unsigned long long) memc_stat->limit_maxbytes);
305 } else if (!strcmp(key, "threads")) {
306 length = snprintf(buffer, SMALL_STRING_LEN, "%lu", memc_stat->threads);
307 } else {
308 Memcached *memc = (Memcached *) memcached2Memcached(shell);
309 *error = memcached_set_error(*memc, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
310 memcached_literal_param("Invalid key provided"));
311 return NULL;
312 }
313
314 if (length >= SMALL_STRING_LEN || length < 0) {
315 Memcached *memc = (Memcached *) memcached2Memcached(shell);
316 *error = memcached_set_error(
317 *memc, MEMCACHED_FAILURE, MEMCACHED_AT,
318 memcached_literal_param("Internal failure occured with buffer, please report this bug."));
319 return NULL;
320 }
321
322 // User is responsible for free() memory, so use malloc()
323 char *ret = static_cast<char *>(malloc(size_t(length + 1)));
324 memcpy(ret, buffer, (size_t) length);
325 ret[length] = '\0';
326
327 return ret;
328 }
329
330 static memcached_return_t binary_stats_fetch(memcached_stat_st *memc_stat, const char *args,
331 const size_t args_length,
332 memcached_instance_st *instance,
333 struct local_context *check) {
334 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
335 protocol_binary_request_stats request = {}; // = {.bytes= {0}};
336 memcached_return_t rc;
337
338 initialize_binary_request(instance, request.message.header);
339
340 request.message.header.request.opcode = PROTOCOL_BINARY_CMD_STAT;
341 request.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
342
343 if (args_length) {
344 request.message.header.request.keylen = htons(uint16_t(args_length));
345 request.message.header.request.bodylen = htonl(uint32_t(args_length));
346
347 libmemcached_io_vector_st vector[] = {{request.bytes, sizeof(request.bytes)},
348 {args, args_length}};
349
350 if (memcached_failed(rc = memcached_vdo(instance, vector, 2, true))) {
351 return rc;
352 }
353 } else {
354 libmemcached_io_vector_st vector[] = {{request.bytes, sizeof(request.bytes)}};
355
356 if (memcached_failed(rc = memcached_vdo(instance, vector, 1, true))) {
357 return rc;
358 }
359 }
360
361 memcached_server_response_decrement(instance);
362 while (1) {
363 rc = memcached_response(instance, buffer, sizeof(buffer), NULL);
364
365 if (rc == MEMCACHED_END) {
366 break;
367 }
368
369 if (rc != MEMCACHED_SUCCESS) {
370 return rc;
371 }
372
373 if (check && check->func) {
374 size_t key_length = strlen(buffer);
375
376 check->func(instance, buffer, key_length, buffer + key_length + 1,
377 strlen(buffer + key_length + 1), check->context);
378 }
379
380 if (memc_stat) {
381 if ((set_data(memc_stat, buffer, buffer + strlen(buffer) + 1)) == MEMCACHED_UNKNOWN_STAT_KEY)
382 {
383 WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY);
384 WATCHPOINT_ASSERT(0);
385 }
386 }
387 }
388
389 /*
390 * memcached_response will decrement the counter, so I need to reset it..
391 * todo: look at this and try to find a better solution.
392 * */
393 instance->cursor_active_ = 0;
394
395 return MEMCACHED_SUCCESS;
396 }
397
398 static memcached_return_t ascii_stats_fetch(memcached_stat_st *memc_stat, const char *args,
399 const size_t args_length,
400 memcached_instance_st *instance,
401 struct local_context *check) {
402 libmemcached_io_vector_st vector[] = {
403 {memcached_literal_param("stats ")}, {args, args_length}, {memcached_literal_param("\r\n")}};
404
405 memcached_return_t rc = memcached_vdo(instance, vector, 3, true);
406 if (memcached_success(rc)) {
407 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE];
408 while ((rc = memcached_response(instance, buffer, sizeof(buffer), NULL)) == MEMCACHED_STAT) {
409 char *string_ptr = buffer;
410 string_ptr += 5; /* Move past STAT */
411
412 char *end_ptr;
413 for (end_ptr = string_ptr; isgraph(*end_ptr); end_ptr++) {
414 };
415 char *key = string_ptr;
416 key[size_t(end_ptr - string_ptr)] = 0;
417
418 string_ptr = end_ptr + 1;
419 for (end_ptr = string_ptr; !(isspace(*end_ptr)); end_ptr++) {
420 };
421 char *value = string_ptr;
422 value[(size_t)(end_ptr - string_ptr)] = 0;
423 #if 0
424 bool check_bool= bool(check);
425 bool check_func_bool= bool(check) ? bool(check->func) : false;
426 fprintf(stderr, "%s:%d %s %s %d:%d\n", __FILE__, __LINE__, key, value, check_bool, check_func_bool);
427 #endif
428
429 if (check and check->func) {
430 check->func(instance, key, strlen(key), value, strlen(value), check->context);
431 }
432
433 if (memc_stat) {
434 if ((set_data(memc_stat, key, value)) == MEMCACHED_UNKNOWN_STAT_KEY) {
435 WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY);
436 WATCHPOINT_ASSERT(0);
437 }
438 }
439 }
440 }
441
442 if (rc == MEMCACHED_ERROR) {
443 return MEMCACHED_INVALID_ARGUMENTS;
444 }
445
446 if (rc == MEMCACHED_END) {
447 return MEMCACHED_SUCCESS;
448 }
449
450 return rc;
451 }
452
453 memcached_stat_st *memcached_stat(memcached_st *shell, char *args, memcached_return_t *error) {
454 Memcached *self = memcached2Memcached(shell);
455 memcached_return_t unused;
456 if (error == NULL) {
457 error = &unused;
458 }
459
460 if (memcached_failed(*error = initialize_query(self, true))) {
461 return NULL;
462 }
463
464 if (memcached_is_udp(self)) {
465 *error = memcached_set_error(*self, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT);
466 return NULL;
467 }
468
469 memcached_return_t rc = MEMCACHED_SUCCESS;
470 size_t args_length = 0;
471 if (args) {
472 args_length = strlen(args);
473 if (memcached_failed(rc = memcached_key_test(*self, (const char **) &args, &args_length, 1))) {
474 *error = memcached_set_error(*self, rc, MEMCACHED_AT);
475 return NULL;
476 }
477 }
478
479 WATCHPOINT_ASSERT(error);
480
481 memcached_stat_st *stats =
482 libmemcached_xcalloc(self, memcached_server_count(self), memcached_stat_st);
483 if (stats == NULL) {
484 *error = memcached_set_error(*self, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
485 return NULL;
486 }
487
488 WATCHPOINT_ASSERT(rc == MEMCACHED_SUCCESS);
489 rc = MEMCACHED_SUCCESS;
490 for (uint32_t x = 0; x < memcached_server_count(self); x++) {
491 memcached_stat_st *stat_instance = stats + x;
492
493 stat_instance->pid = -1;
494 stat_instance->root = self;
495
496 memcached_instance_st *instance = memcached_instance_fetch(self, x);
497
498 memcached_return_t temp_return;
499 if (memcached_is_binary(self)) {
500 temp_return = binary_stats_fetch(stat_instance, args, args_length, instance, NULL);
501 } else {
502 temp_return = ascii_stats_fetch(stat_instance, args, args_length, instance, NULL);
503 }
504
505 // Special case where "args" is invalid
506 if (temp_return == MEMCACHED_INVALID_ARGUMENTS) {
507 rc = MEMCACHED_INVALID_ARGUMENTS;
508 break;
509 }
510
511 if (memcached_failed(temp_return)) {
512 rc = MEMCACHED_SOME_ERRORS;
513 }
514 }
515
516 *error = rc;
517
518 return stats;
519 }
520
521 memcached_return_t memcached_stat_servername(memcached_stat_st *memc_stat, char *args,
522 const char *hostname, in_port_t port) {
523 memcached_st memc;
524
525 memcached_stat_st unused_memc_stat;
526 if (memc_stat == NULL) {
527 memc_stat = &unused_memc_stat;
528 }
529
530 memset(memc_stat, 0, sizeof(memcached_stat_st));
531
532 memcached_st *memc_ptr = memcached_create(&memc);
533 if (memc_ptr == NULL) {
534 return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
535 }
536
537 memcached_return_t rc;
538 if (memcached_failed(rc = memcached_server_add(&memc, hostname, port))) {
539 memcached_free(&memc);
540 return rc;
541 }
542
543 if (memcached_success(rc = initialize_query(memc_ptr, true))) {
544 size_t args_length = 0;
545 if (args) {
546 args_length = strlen(args);
547 rc = memcached_key_test(*memc_ptr, (const char **) &args, &args_length, 1);
548 }
549
550 if (memcached_success(rc)) {
551 memcached_instance_st *instance = memcached_instance_fetch(memc_ptr, 0);
552 if (memc.flags.binary_protocol) {
553 rc = binary_stats_fetch(memc_stat, args, args_length, instance, NULL);
554 } else {
555 rc = ascii_stats_fetch(memc_stat, args, args_length, instance, NULL);
556 }
557 }
558 }
559
560 memcached_free(&memc);
561
562 return rc;
563 }
564
565 /*
566 We make a copy of the keys since at some point in the not so distant future
567 we will add support for "found" keys.
568 */
569 char **memcached_stat_get_keys(memcached_st *shell, memcached_stat_st *,
570 memcached_return_t *error) {
571 Memcached *memc = memcached2Memcached(shell);
572 if (memc) {
573 char **list = static_cast<char **>(libmemcached_malloc(memc, sizeof(memcached_stat_keys)));
574 if (list == NULL) {
575 if (error) {
576 *error = memcached_set_error(*memc, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
577 }
578
579 return NULL;
580 }
581
582 memcpy(list, memcached_stat_keys, sizeof(memcached_stat_keys));
583
584 if (error) {
585 *error = MEMCACHED_SUCCESS;
586 }
587
588 return list;
589 }
590
591 return NULL;
592 }
593
594 void memcached_stat_free(const memcached_st *, memcached_stat_st *memc_stat) {
595 WATCHPOINT_ASSERT(memc_stat); // Be polite, but when debugging catch this as an error
596 if (memc_stat) {
597 libmemcached_free(memc_stat->root, memc_stat);
598 }
599 }
600
601 static memcached_return_t call_stat_fn(memcached_st *memc, memcached_instance_st *instance,
602 void *context) {
603 if (memc) {
604 local_context *check = (struct local_context *) context;
605
606 if (memcached_is_binary(memc)) {
607 return binary_stats_fetch(NULL, check->args, check->args_length, instance, check);
608 } else {
609 return ascii_stats_fetch(NULL, check->args, check->args_length, instance, check);
610 }
611 }
612
613 return MEMCACHED_INVALID_ARGUMENTS;
614 }
615
616 memcached_return_t memcached_stat_execute(memcached_st *shell, const char *args,
617 memcached_stat_fn func, void *context) {
618 Memcached *memc = memcached2Memcached(shell);
619 if (memcached_fatal(memcached_version(memc))) {
620 return memcached_last_error(memc);
621 }
622
623 local_context check(func, context, args, args ? strlen(args) : 0);
624
625 return memcached_server_execute(memc, call_stat_fn, (void *) &check);
626 }