1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
5 * Copyright (C) 2011-2013 Data Differential, http://datadifferential.com/
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following disclaimer
16 * in the documentation and/or other materials provided with the
19 * * The names of its contributors may not be used to endorse or
20 * promote products derived from this software without specific prior
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 #include <libmemcached/common.h>
39 static const char *memcached_stat_keys
[] = {
52 "connection_structures",
67 memcached_stat_fn func
;
70 const size_t args_length
;
72 local_context(memcached_stat_fn func_arg
,
75 const size_t args_length_arg
) :
79 args_length(args_length_arg
)
84 static memcached_return_t
set_data(memcached_stat_st
*memc_stat
, const char *key
, const char *value
)
89 WATCHPOINT_STRING(key
);
90 return MEMCACHED_UNKNOWN_STAT_KEY
;
92 else if (strcmp("pid", key
) == 0)
95 int64_t temp
= strtoll(value
, (char **)NULL
, 10);
98 return MEMCACHED_FAILURE
;
101 if (temp
<= INT32_MAX
and ( sizeof(pid_t
) == sizeof(int32_t) ))
103 memc_stat
->pid
= pid_t(temp
);
107 memc_stat
->pid
= pid_t(temp
);
111 // If we got a value less then -1 then something went wrong in the
115 else if (not strcmp("uptime", key
))
118 memc_stat
->uptime
= strtoul(value
, (char **)NULL
, 10);
121 return MEMCACHED_FAILURE
;
124 else if (not strcmp("time", key
))
127 memc_stat
->time
= strtoul(value
, (char **)NULL
, 10);
130 return MEMCACHED_FAILURE
;
133 else if (not strcmp("version", key
))
135 memcpy(memc_stat
->version
, value
, strlen(value
));
136 memc_stat
->version
[strlen(value
)]= 0;
138 else if (not strcmp("pointer_size", key
))
141 memc_stat
->pointer_size
= strtoul(value
, (char **)NULL
, 10);
144 return MEMCACHED_FAILURE
;
147 else if (not strcmp("rusage_user", key
))
150 for (walk_ptr
= (char*)value
; (!ispunct(*walk_ptr
)); walk_ptr
++) {};
155 memc_stat
->rusage_user_seconds
= strtoul(value
, (char **)NULL
, 10);
158 return MEMCACHED_FAILURE
;
162 memc_stat
->rusage_user_microseconds
= strtoul(walk_ptr
, (char **)NULL
, 10);
165 return MEMCACHED_FAILURE
;
168 else if (not strcmp("rusage_system", key
))
171 for (walk_ptr
= (char*)value
; (!ispunct(*walk_ptr
)); walk_ptr
++) {};
176 memc_stat
->rusage_system_seconds
= strtoul(value
, (char **)NULL
, 10);
179 return MEMCACHED_FAILURE
;
183 memc_stat
->rusage_system_microseconds
= strtoul(walk_ptr
, (char **)NULL
, 10);
186 return MEMCACHED_FAILURE
;
189 else if (not strcmp("curr_items", key
))
192 memc_stat
->curr_items
= strtoul(value
, (char **)NULL
, 10);
195 return MEMCACHED_FAILURE
;
198 else if (not strcmp("total_items", key
))
201 memc_stat
->total_items
= strtoul(value
, (char **)NULL
, 10);
204 return MEMCACHED_FAILURE
;
207 else if (not strcmp("bytes_read", key
))
210 memc_stat
->bytes_read
= strtoull(value
, (char **)NULL
, 10);
213 return MEMCACHED_FAILURE
;
216 else if (not strcmp("bytes_written", key
))
219 memc_stat
->bytes_written
= strtoull(value
, (char **)NULL
, 10);
222 return MEMCACHED_FAILURE
;
225 else if (not strcmp("bytes", key
))
228 memc_stat
->bytes
= strtoull(value
, (char **)NULL
, 10);
231 return MEMCACHED_FAILURE
;
234 else if (not strcmp("curr_connections", key
))
237 memc_stat
->curr_connections
= strtoull(value
, (char **)NULL
, 10);
240 return MEMCACHED_FAILURE
;
243 else if (not strcmp("total_connections", key
))
246 memc_stat
->total_connections
= strtoull(value
, (char **)NULL
, 10);
249 return MEMCACHED_FAILURE
;
252 else if (not strcmp("connection_structures", key
))
255 memc_stat
->connection_structures
= strtoul(value
, (char **)NULL
, 10);
258 return MEMCACHED_FAILURE
;
261 else if (not strcmp("cmd_get", key
))
264 memc_stat
->cmd_get
= strtoull(value
, (char **)NULL
, 10);
267 return MEMCACHED_FAILURE
;
270 else if (not strcmp("cmd_set", key
))
273 memc_stat
->cmd_set
= strtoull(value
, (char **)NULL
, 10);
276 return MEMCACHED_FAILURE
;
279 else if (not strcmp("get_hits", key
))
282 memc_stat
->get_hits
= strtoull(value
, (char **)NULL
, 10);
285 return MEMCACHED_FAILURE
;
288 else if (not strcmp("get_misses", key
))
291 memc_stat
->get_misses
= strtoull(value
, (char **)NULL
, 10);
294 return MEMCACHED_FAILURE
;
297 else if (not strcmp("evictions", key
))
300 memc_stat
->evictions
= strtoull(value
, (char **)NULL
, 10);
303 return MEMCACHED_FAILURE
;
306 else if (not strcmp("limit_maxbytes", key
))
309 memc_stat
->limit_maxbytes
= strtoull(value
, (char **)NULL
, 10);
312 return MEMCACHED_FAILURE
;
315 else if (not strcmp("threads", key
))
318 memc_stat
->threads
= strtoul(value
, (char **)NULL
, 10);
321 return MEMCACHED_FAILURE
;
324 else if ((strcmp("delete_misses", key
) == 0 or /* New stats in the 1.3 beta */
325 strcmp("delete_hits", key
) == 0 or /* Just swallow them for now.. */
326 strcmp("incr_misses", key
) == 0 or
327 strcmp("incr_hits", key
) == 0 or
328 strcmp("decr_misses", key
) == 0 or
329 strcmp("decr_hits", key
) == 0 or
330 strcmp("cas_misses", key
) == 0 or
331 strcmp("cas_hits", key
) == 0 or
332 strcmp("cas_badval", key
) == 0 or
333 strcmp("cmd_flush", key
) == 0 or
334 strcmp("accepting_conns", key
) == 0 or
335 strcmp("listen_disabled_num", key
) == 0 or
336 strcmp("conn_yields", key
) == 0 or
337 strcmp("auth_cmds", key
) == 0 or
338 strcmp("auth_errors", key
) == 0 or
339 strcmp("reclaimed", key
) == 0) == 0)
341 WATCHPOINT_STRING(key
);
342 /* return MEMCACHED_UNKNOWN_STAT_KEY; */
343 return MEMCACHED_SUCCESS
;
346 return MEMCACHED_SUCCESS
;
349 char *memcached_stat_get_value(const memcached_st
* shell
, memcached_stat_st
*memc_stat
,
350 const char *key
, memcached_return_t
*error
)
352 memcached_return_t not_used
;
358 if (memc_stat
== NULL
)
360 *error
= MEMCACHED_INVALID_ARGUMENTS
;
364 char buffer
[SMALL_STRING_LEN
];
367 *error
= MEMCACHED_SUCCESS
;
369 if (memcmp("pid", key
, sizeof("pid") -1) == 0)
371 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%lld", (signed long long)memc_stat
->pid
);
373 else if (not memcmp("uptime", key
, sizeof("uptime") -1))
375 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%lu", memc_stat
->uptime
);
377 else if (not memcmp("time", key
, sizeof("time") -1))
379 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%llu", (unsigned long long)memc_stat
->time
);
381 else if (not memcmp("version", key
, sizeof("version") -1))
383 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%s", memc_stat
->version
);
385 else if (not memcmp("pointer_size", key
, sizeof("pointer_size") -1))
387 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%lu", memc_stat
->pointer_size
);
389 else if (not memcmp("rusage_user", key
, sizeof("rusage_user") -1))
391 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%lu.%lu", memc_stat
->rusage_user_seconds
, memc_stat
->rusage_user_microseconds
);
393 else if (not memcmp("rusage_system", key
, sizeof("rusage_system") -1))
395 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%lu.%lu", memc_stat
->rusage_system_seconds
, memc_stat
->rusage_system_microseconds
);
397 else if (not memcmp("curr_items", key
, sizeof("curr_items") -1))
399 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%lu", memc_stat
->curr_items
);
401 else if (not memcmp("total_items", key
, sizeof("total_items") -1))
403 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%lu", memc_stat
->total_items
);
405 else if (not memcmp("curr_connections", key
, sizeof("curr_connections") -1))
407 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%lu", memc_stat
->curr_connections
);
409 else if (not memcmp("total_connections", key
, sizeof("total_connections") -1))
411 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%lu", memc_stat
->total_connections
);
413 else if (not memcmp("connection_structures", key
, sizeof("connection_structures") -1))
415 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%lu", memc_stat
->connection_structures
);
417 else if (not memcmp("cmd_get", key
, sizeof("cmd_get") -1))
419 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%llu", (unsigned long long)memc_stat
->cmd_get
);
421 else if (not memcmp("cmd_set", key
, sizeof("cmd_set") -1))
423 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%llu", (unsigned long long)memc_stat
->cmd_set
);
425 else if (not memcmp("get_hits", key
, sizeof("get_hits") -1))
427 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%llu", (unsigned long long)memc_stat
->get_hits
);
429 else if (not memcmp("get_misses", key
, sizeof("get_misses") -1))
431 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%llu", (unsigned long long)memc_stat
->get_misses
);
433 else if (not memcmp("evictions", key
, sizeof("evictions") -1))
435 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%llu", (unsigned long long)memc_stat
->evictions
);
437 else if (not memcmp("bytes_read", key
, sizeof("bytes_read") -1))
439 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%llu", (unsigned long long)memc_stat
->bytes_read
);
441 else if (not memcmp("bytes_written", key
, sizeof("bytes_written") -1))
443 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%llu", (unsigned long long)memc_stat
->bytes_written
);
445 else if (not memcmp("bytes", key
, sizeof("bytes") -1))
447 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%llu", (unsigned long long)memc_stat
->bytes
);
449 else if (not memcmp("limit_maxbytes", key
, sizeof("limit_maxbytes") -1))
451 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%llu", (unsigned long long)memc_stat
->limit_maxbytes
);
453 else if (not memcmp("threads", key
, sizeof("threads") -1))
455 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%lu", memc_stat
->threads
);
459 Memcached
* memc
= (Memcached
*)memcached2Memcached(shell
);
460 *error
= memcached_set_error(*memc
, MEMCACHED_INVALID_ARGUMENTS
, MEMCACHED_AT
, memcached_literal_param("Invalid key provided"));
464 if (length
>= SMALL_STRING_LEN
|| length
< 0)
466 Memcached
* memc
= (Memcached
*)memcached2Memcached(shell
);
467 *error
= memcached_set_error(*memc
, MEMCACHED_FAILURE
, MEMCACHED_AT
, memcached_literal_param("Internal failure occured with buffer, please report this bug."));
471 // User is responsible for free() memory, so use malloc()
472 char *ret
= static_cast<char *>(malloc(size_t(length
+1)));
473 memcpy(ret
, buffer
, (size_t) length
);
479 static memcached_return_t
binary_stats_fetch(memcached_stat_st
*memc_stat
,
481 const size_t args_length
,
482 memcached_instance_st
* instance
,
483 struct local_context
*check
)
485 char buffer
[MEMCACHED_DEFAULT_COMMAND_SIZE
];
486 protocol_binary_request_stats request
= {}; // = {.bytes= {0}};
488 initialize_binary_request(instance
, request
.message
.header
);
490 request
.message
.header
.request
.opcode
= PROTOCOL_BINARY_CMD_STAT
;
491 request
.message
.header
.request
.datatype
= PROTOCOL_BINARY_RAW_BYTES
;
495 request
.message
.header
.request
.keylen
= htons(uint16_t(args_length
));
496 request
.message
.header
.request
.bodylen
= htonl(uint32_t( args_length
));
498 libmemcached_io_vector_st vector
[]=
500 { request
.bytes
, sizeof(request
.bytes
) },
501 { args
, args_length
}
504 if (memcached_vdo(instance
, vector
, 2, true) != MEMCACHED_SUCCESS
)
506 memcached_io_reset(instance
);
507 return MEMCACHED_WRITE_FAILURE
;
512 libmemcached_io_vector_st vector
[]=
514 { request
.bytes
, sizeof(request
.bytes
) }
517 if (memcached_vdo(instance
, vector
, 1, true) != MEMCACHED_SUCCESS
)
519 memcached_io_reset(instance
);
520 return MEMCACHED_WRITE_FAILURE
;
524 memcached_server_response_decrement(instance
);
527 memcached_return_t rc
= memcached_response(instance
, buffer
, sizeof(buffer
), NULL
);
529 if (rc
== MEMCACHED_END
)
534 if (rc
!= MEMCACHED_SUCCESS
)
536 memcached_io_reset(instance
);
540 if (check
&& check
->func
)
542 size_t key_length
= strlen(buffer
);
544 check
->func(instance
,
546 buffer
+key_length
+1, strlen(buffer
+key_length
+1),
552 if ((set_data(memc_stat
, buffer
, buffer
+ strlen(buffer
) + 1)) == MEMCACHED_UNKNOWN_STAT_KEY
)
554 WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY
);
555 WATCHPOINT_ASSERT(0);
561 * memcached_response will decrement the counter, so I need to reset it..
562 * todo: look at this and try to find a better solution.
564 instance
->cursor_active_
= 0;
566 return MEMCACHED_SUCCESS
;
569 static memcached_return_t
ascii_stats_fetch(memcached_stat_st
*memc_stat
,
571 const size_t args_length
,
572 memcached_instance_st
* instance
,
573 struct local_context
*check
)
575 libmemcached_io_vector_st vector
[]=
577 { memcached_literal_param("stats ") },
578 { args
, args_length
},
579 { memcached_literal_param("\r\n") }
582 memcached_return_t rc
= memcached_vdo(instance
, vector
, 3, true);
583 if (memcached_success(rc
))
585 char buffer
[MEMCACHED_DEFAULT_COMMAND_SIZE
];
586 while ((rc
= memcached_response(instance
, buffer
, sizeof(buffer
), NULL
)) == MEMCACHED_STAT
)
588 char *string_ptr
= buffer
;
589 string_ptr
+= 5; /* Move past STAT */
592 for (end_ptr
= string_ptr
; isgraph(*end_ptr
); end_ptr
++) {};
593 char *key
= string_ptr
;
594 key
[size_t(end_ptr
-string_ptr
)]= 0;
596 string_ptr
= end_ptr
+ 1;
597 for (end_ptr
= string_ptr
; !(isspace(*end_ptr
)); end_ptr
++) {};
598 char *value
= string_ptr
;
599 value
[(size_t)(end_ptr
-string_ptr
)]= 0;
601 bool check_bool
= bool(check
);
602 bool check_func_bool
= bool(check
) ? bool(check
->func
) : false;
603 fprintf(stderr
, "%s:%d %s %s %d:%d\n", __FILE__
, __LINE__
, key
, value
, check_bool
, check_func_bool
);
606 if (check
and check
->func
)
608 check
->func(instance
,
610 value
, strlen(value
),
616 if((set_data(memc_stat
, key
, value
)) == MEMCACHED_UNKNOWN_STAT_KEY
)
618 WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY
);
619 WATCHPOINT_ASSERT(0);
625 if (rc
== MEMCACHED_ERROR
)
627 return MEMCACHED_INVALID_ARGUMENTS
;
630 if (rc
== MEMCACHED_END
)
632 return MEMCACHED_SUCCESS
;
638 memcached_stat_st
*memcached_stat(memcached_st
*shell
, char *args
, memcached_return_t
*error
)
640 Memcached
* self
= memcached2Memcached(shell
);
641 memcached_return_t unused
;
647 if (memcached_failed(*error
= initialize_query(self
, true)))
652 if (memcached_is_udp(self
))
654 *error
= memcached_set_error(*self
, MEMCACHED_NOT_SUPPORTED
, MEMCACHED_AT
);
658 memcached_return_t rc
;
659 size_t args_length
= 0;
662 args_length
= strlen(args
);
663 if (memcached_failed(rc
= memcached_key_test(*self
, (const char **)&args
, &args_length
, 1)))
665 *error
= memcached_set_error(*self
, rc
, MEMCACHED_AT
);
670 WATCHPOINT_ASSERT(error
);
672 memcached_stat_st
*stats
= libmemcached_xcalloc(self
, memcached_server_count(self
), memcached_stat_st
);
675 *error
= memcached_set_error(*self
, MEMCACHED_MEMORY_ALLOCATION_FAILURE
, MEMCACHED_AT
);
679 WATCHPOINT_ASSERT(rc
== MEMCACHED_SUCCESS
);
680 rc
= MEMCACHED_SUCCESS
;
681 for (uint32_t x
= 0; x
< memcached_server_count(self
); x
++)
683 memcached_stat_st
* stat_instance
= stats
+x
;
685 stat_instance
->pid
= -1;
686 stat_instance
->root
= self
;
688 memcached_instance_st
* instance
= memcached_instance_fetch(self
, x
);
690 memcached_return_t temp_return
;
691 if (memcached_is_binary(self
))
693 temp_return
= binary_stats_fetch(stat_instance
, args
, args_length
, instance
, NULL
);
697 temp_return
= ascii_stats_fetch(stat_instance
, args
, args_length
, instance
, NULL
);
700 // Special case where "args" is invalid
701 if (temp_return
== MEMCACHED_INVALID_ARGUMENTS
)
703 rc
= MEMCACHED_INVALID_ARGUMENTS
;
707 if (memcached_failed(temp_return
))
709 rc
= MEMCACHED_SOME_ERRORS
;
718 memcached_return_t
memcached_stat_servername(memcached_stat_st
*memc_stat
, char *args
,
719 const char *hostname
, in_port_t port
)
723 memcached_stat_st unused_memc_stat
;
724 if (memc_stat
== NULL
)
726 memc_stat
= &unused_memc_stat
;
729 memset(memc_stat
, 0, sizeof(memcached_stat_st
));
731 memcached_st
*memc_ptr
= memcached_create(&memc
);
732 if (memc_ptr
== NULL
)
734 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
737 memcached_return_t rc
;
738 if (memcached_failed(rc
= memcached_server_add(&memc
, hostname
, port
)))
740 memcached_free(&memc
);
744 if (memcached_success(rc
= initialize_query(memc_ptr
, true)))
746 size_t args_length
= 0;
749 args_length
= strlen(args
);
750 rc
= memcached_key_test(*memc_ptr
, (const char **)&args
, &args_length
, 1);
753 if (memcached_success(rc
))
755 memcached_instance_st
* instance
= memcached_instance_fetch(memc_ptr
, 0);
756 if (memc
.flags
.binary_protocol
)
758 rc
= binary_stats_fetch(memc_stat
, args
, args_length
, instance
, NULL
);
762 rc
= ascii_stats_fetch(memc_stat
, args
, args_length
, instance
, NULL
);
767 memcached_free(&memc
);
773 We make a copy of the keys since at some point in the not so distant future
774 we will add support for "found" keys.
776 char ** memcached_stat_get_keys(memcached_st
*shell
,
778 memcached_return_t
*error
)
780 Memcached
* memc
= memcached2Memcached(shell
);
783 char **list
= static_cast<char **>(libmemcached_malloc(memc
, sizeof(memcached_stat_keys
)));
788 *error
= memcached_set_error(*memc
, MEMCACHED_MEMORY_ALLOCATION_FAILURE
, MEMCACHED_AT
);
794 memcpy(list
, memcached_stat_keys
, sizeof(memcached_stat_keys
));
798 *error
= MEMCACHED_SUCCESS
;
807 void memcached_stat_free(const memcached_st
*, memcached_stat_st
*memc_stat
)
809 WATCHPOINT_ASSERT(memc_stat
); // Be polite, but when debugging catch this as an error
812 libmemcached_free(memc_stat
->root
, memc_stat
);
816 static memcached_return_t
call_stat_fn(memcached_st
*memc
,
817 memcached_instance_st
* instance
,
822 local_context
*check
= (struct local_context
*)context
;
824 if (memcached_is_binary(memc
))
826 return binary_stats_fetch(NULL
, check
->args
, check
->args_length
, instance
, check
);
830 return ascii_stats_fetch(NULL
, check
->args
, check
->args_length
, instance
, check
);
834 return MEMCACHED_INVALID_ARGUMENTS
;
837 memcached_return_t
memcached_stat_execute(memcached_st
*shell
, const char *args
, memcached_stat_fn func
, void *context
)
839 Memcached
* memc
= memcached2Memcached(shell
);
840 if (memcached_fatal(memcached_version(memc
)))
842 return memcached_last_error(memc
);
845 local_context
check(func
, context
, args
, args
? strlen(args
) : 0);
847 return memcached_server_execute(memc
, call_stat_fn
, (void *)&check
);