1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
5 * Copyright (C) 2011 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
;
71 local_context(memcached_stat_fn func_arg
,
73 const char *args_arg
) :
81 static memcached_return_t
set_data(memcached_stat_st
*memc_stat
, char *key
, char *value
)
86 WATCHPOINT_STRING(key
);
87 return MEMCACHED_UNKNOWN_STAT_KEY
;
89 else if (strcmp("pid", key
) == 0)
91 int64_t temp
= strtoll(value
, (char **)NULL
, 10);
93 if (temp
<= INT32_MAX
and ( sizeof(pid_t
) == sizeof(int32_t) ))
103 // If we got a value less then -1 then something went wrong in the
107 else if (not strcmp("uptime", key
))
109 memc_stat
->uptime
= strtoul(value
, (char **)NULL
, 10);
111 else if (not strcmp("time", key
))
113 memc_stat
->time
= strtoul(value
, (char **)NULL
, 10);
115 else if (not strcmp("version", key
))
117 memcpy(memc_stat
->version
, value
, strlen(value
));
118 memc_stat
->version
[strlen(value
)]= 0;
120 else if (not strcmp("pointer_size", key
))
122 memc_stat
->pointer_size
= strtoul(value
, (char **)NULL
, 10);
124 else if (not strcmp("rusage_user", key
))
127 for (walk_ptr
= value
; (!ispunct(*walk_ptr
)); walk_ptr
++) {};
130 memc_stat
->rusage_user_seconds
= strtoul(value
, (char **)NULL
, 10);
131 memc_stat
->rusage_user_microseconds
= strtoul(walk_ptr
, (char **)NULL
, 10);
133 else if (not strcmp("rusage_system", key
))
136 for (walk_ptr
= value
; (!ispunct(*walk_ptr
)); walk_ptr
++) {};
139 memc_stat
->rusage_system_seconds
= strtoul(value
, (char **)NULL
, 10);
140 memc_stat
->rusage_system_microseconds
= strtoul(walk_ptr
, (char **)NULL
, 10);
142 else if (not strcmp("curr_items", key
))
144 memc_stat
->curr_items
= strtoul(value
, (char **)NULL
, 10);
146 else if (not strcmp("total_items", key
))
148 memc_stat
->total_items
= strtoul(value
, (char **)NULL
, 10);
150 else if (not strcmp("bytes_read", key
))
152 memc_stat
->bytes_read
= strtoull(value
, (char **)NULL
, 10);
154 else if (not strcmp("bytes_written", key
))
156 memc_stat
->bytes_written
= strtoull(value
, (char **)NULL
, 10);
158 else if (not strcmp("bytes", key
))
160 memc_stat
->bytes
= strtoull(value
, (char **)NULL
, 10);
162 else if (not strcmp("curr_connections", key
))
164 memc_stat
->curr_connections
= strtoull(value
, (char **)NULL
, 10);
166 else if (not strcmp("total_connections", key
))
168 memc_stat
->total_connections
= strtoull(value
, (char **)NULL
, 10);
170 else if (not strcmp("connection_structures", key
))
172 memc_stat
->connection_structures
= strtoul(value
, (char **)NULL
, 10);
174 else if (not strcmp("cmd_get", key
))
176 memc_stat
->cmd_get
= strtoull(value
, (char **)NULL
, 10);
178 else if (not strcmp("cmd_set", key
))
180 memc_stat
->cmd_set
= strtoull(value
, (char **)NULL
, 10);
182 else if (not strcmp("get_hits", key
))
184 memc_stat
->get_hits
= strtoull(value
, (char **)NULL
, 10);
186 else if (not strcmp("get_misses", key
))
188 memc_stat
->get_misses
= strtoull(value
, (char **)NULL
, 10);
190 else if (not strcmp("evictions", key
))
192 memc_stat
->evictions
= strtoull(value
, (char **)NULL
, 10);
194 else if (not strcmp("limit_maxbytes", key
))
196 memc_stat
->limit_maxbytes
= strtoull(value
, (char **)NULL
, 10);
198 else if (not strcmp("threads", key
))
200 memc_stat
->threads
= strtoul(value
, (char **)NULL
, 10);
202 else if (not (strcmp("delete_misses", key
) == 0 or /* New stats in the 1.3 beta */
203 strcmp("delete_hits", key
) == 0 or /* Just swallow them for now.. */
204 strcmp("incr_misses", key
) == 0 or
205 strcmp("incr_hits", key
) == 0 or
206 strcmp("decr_misses", key
) == 0 or
207 strcmp("decr_hits", key
) == 0 or
208 strcmp("cas_misses", key
) == 0 or
209 strcmp("cas_hits", key
) == 0 or
210 strcmp("cas_badval", key
) == 0 or
211 strcmp("cmd_flush", key
) == 0 or
212 strcmp("accepting_conns", key
) == 0 or
213 strcmp("listen_disabled_num", key
) == 0 or
214 strcmp("conn_yields", key
) == 0 or
215 strcmp("auth_cmds", key
) == 0 or
216 strcmp("auth_errors", key
) == 0 or
217 strcmp("reclaimed", key
) == 0))
219 WATCHPOINT_STRING(key
);
220 /* return MEMCACHED_UNKNOWN_STAT_KEY; */
221 return MEMCACHED_SUCCESS
;
224 return MEMCACHED_SUCCESS
;
227 char *memcached_stat_get_value(const memcached_st
*ptr
, memcached_stat_st
*memc_stat
,
228 const char *key
, memcached_return_t
*error
)
230 char buffer
[SMALL_STRING_LEN
];
234 *error
= MEMCACHED_SUCCESS
;
236 if (not memcmp("pid", key
, sizeof("pid") -1))
238 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%lld", (signed long long)memc_stat
->pid
);
240 else if (not memcmp("uptime", key
, sizeof("uptime") -1))
242 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%lu", memc_stat
->uptime
);
244 else if (not memcmp("time", key
, sizeof("time") -1))
246 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%llu", (unsigned long long)memc_stat
->time
);
248 else if (not memcmp("version", key
, sizeof("version") -1))
250 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%s", memc_stat
->version
);
252 else if (not memcmp("pointer_size", key
, sizeof("pointer_size") -1))
254 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%lu", memc_stat
->pointer_size
);
256 else if (not memcmp("rusage_user", key
, sizeof("rusage_user") -1))
258 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%lu.%lu", memc_stat
->rusage_user_seconds
, memc_stat
->rusage_user_microseconds
);
260 else if (not memcmp("rusage_system", key
, sizeof("rusage_system") -1))
262 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%lu.%lu", memc_stat
->rusage_system_seconds
, memc_stat
->rusage_system_microseconds
);
264 else if (not memcmp("curr_items", key
, sizeof("curr_items") -1))
266 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%lu", memc_stat
->curr_items
);
268 else if (not memcmp("total_items", key
, sizeof("total_items") -1))
270 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%lu", memc_stat
->total_items
);
272 else if (not memcmp("curr_connections", key
, sizeof("curr_connections") -1))
274 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%lu", memc_stat
->curr_connections
);
276 else if (not memcmp("total_connections", key
, sizeof("total_connections") -1))
278 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%lu", memc_stat
->total_connections
);
280 else if (not memcmp("connection_structures", key
, sizeof("connection_structures") -1))
282 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%lu", memc_stat
->connection_structures
);
284 else if (not memcmp("cmd_get", key
, sizeof("cmd_get") -1))
286 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%llu", (unsigned long long)memc_stat
->cmd_get
);
288 else if (not memcmp("cmd_set", key
, sizeof("cmd_set") -1))
290 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%llu", (unsigned long long)memc_stat
->cmd_set
);
292 else if (not memcmp("get_hits", key
, sizeof("get_hits") -1))
294 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%llu", (unsigned long long)memc_stat
->get_hits
);
296 else if (not memcmp("get_misses", key
, sizeof("get_misses") -1))
298 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%llu", (unsigned long long)memc_stat
->get_misses
);
300 else if (not memcmp("evictions", key
, sizeof("evictions") -1))
302 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%llu", (unsigned long long)memc_stat
->evictions
);
304 else if (not memcmp("bytes_read", key
, sizeof("bytes_read") -1))
306 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%llu", (unsigned long long)memc_stat
->bytes_read
);
308 else if (not memcmp("bytes_written", key
, sizeof("bytes_written") -1))
310 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%llu", (unsigned long long)memc_stat
->bytes_written
);
312 else if (not memcmp("bytes", key
, sizeof("bytes") -1))
314 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%llu", (unsigned long long)memc_stat
->bytes
);
316 else if (not memcmp("limit_maxbytes", key
, sizeof("limit_maxbytes") -1))
318 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%llu", (unsigned long long)memc_stat
->limit_maxbytes
);
320 else if (not memcmp("threads", key
, sizeof("threads") -1))
322 length
= snprintf(buffer
, SMALL_STRING_LEN
,"%lu", memc_stat
->threads
);
326 *error
= MEMCACHED_NOTFOUND
;
330 if (length
>= SMALL_STRING_LEN
|| length
< 0)
332 *error
= MEMCACHED_FAILURE
;
336 ret
= static_cast<char *>(libmemcached_malloc(ptr
, (size_t) (length
+ 1)));
337 memcpy(ret
, buffer
, (size_t) length
);
343 static memcached_return_t
binary_stats_fetch(memcached_stat_st
*memc_stat
,
345 memcached_server_write_instance_st instance
,
346 struct local_context
*check
)
348 char buffer
[MEMCACHED_DEFAULT_COMMAND_SIZE
];
349 protocol_binary_request_stats request
= {}; // = {.bytes= {0}};
350 request
.message
.header
.request
.magic
= PROTOCOL_BINARY_REQ
;
351 request
.message
.header
.request
.opcode
= PROTOCOL_BINARY_CMD_STAT
;
352 request
.message
.header
.request
.datatype
= PROTOCOL_BINARY_RAW_BYTES
;
356 size_t len
= strlen(args
);
358 memcached_return_t rc
= memcached_validate_key_length(len
, true);
359 if (rc
!= MEMCACHED_SUCCESS
)
364 request
.message
.header
.request
.keylen
= htons((uint16_t)len
);
365 request
.message
.header
.request
.bodylen
= htonl((uint32_t) len
);
367 struct libmemcached_io_vector_st vector
[]=
369 { request
.bytes
, sizeof(request
.bytes
) },
373 if (memcached_vdo(instance
, vector
, 2, true) != MEMCACHED_SUCCESS
)
375 memcached_io_reset(instance
);
376 return MEMCACHED_WRITE_FAILURE
;
381 if (memcached_do(instance
, request
.bytes
,
382 sizeof(request
.bytes
), true) != MEMCACHED_SUCCESS
)
384 memcached_io_reset(instance
);
385 return MEMCACHED_WRITE_FAILURE
;
389 memcached_server_response_decrement(instance
);
392 memcached_return_t rc
= memcached_response(instance
, buffer
, sizeof(buffer
), NULL
);
394 if (rc
== MEMCACHED_END
)
397 unlikely (rc
!= MEMCACHED_SUCCESS
)
399 memcached_io_reset(instance
);
405 unlikely((set_data(memc_stat
, buffer
, buffer
+ strlen(buffer
) + 1)) == MEMCACHED_UNKNOWN_STAT_KEY
)
407 WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY
);
408 WATCHPOINT_ASSERT(0);
412 if (check
&& check
->func
)
414 size_t key_length
= strlen(buffer
);
416 check
->func(instance
,
418 buffer
+key_length
+1, strlen(buffer
+key_length
+1),
423 /* shit... memcached_response will decrement the counter, so I need to
424 ** reset it.. todo: look at this and try to find a better solution.
426 instance
->cursor_active
= 0;
428 return MEMCACHED_SUCCESS
;
431 static memcached_return_t
ascii_stats_fetch(memcached_stat_st
*memc_stat
,
433 memcached_server_write_instance_st instance
,
434 struct local_context
*check
)
439 send_length
= strlen(args
);
442 struct libmemcached_io_vector_st vector
[]=
444 { memcached_literal_param("stats ") },
445 { args
, send_length
},
446 { memcached_literal_param("\r\n") }
449 memcached_return_t rc
= memcached_vdo(instance
, vector
, 3, true);
450 if (memcached_success(rc
))
452 char buffer
[MEMCACHED_DEFAULT_COMMAND_SIZE
];
453 while ((rc
= memcached_response(instance
, buffer
, MEMCACHED_DEFAULT_COMMAND_SIZE
, NULL
)) == MEMCACHED_STAT
)
455 char *string_ptr
, *end_ptr
;
459 string_ptr
+= 5; /* Move past STAT */
460 for (end_ptr
= string_ptr
; isgraph(*end_ptr
); end_ptr
++) {};
462 key
[(size_t)(end_ptr
-string_ptr
)]= 0;
464 string_ptr
= end_ptr
+ 1;
465 for (end_ptr
= string_ptr
; !(isspace(*end_ptr
)); end_ptr
++) {};
467 value
[(size_t)(end_ptr
-string_ptr
)]= 0;
470 unlikely((set_data(memc_stat
, key
, value
)) == MEMCACHED_UNKNOWN_STAT_KEY
)
472 WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY
);
473 WATCHPOINT_ASSERT(0);
477 if (check
&& check
->func
)
479 check
->func(instance
,
481 value
, strlen(value
),
487 if (rc
== MEMCACHED_END
)
489 return MEMCACHED_SUCCESS
;
495 memcached_stat_st
*memcached_stat(memcached_st
*self
, char *args
, memcached_return_t
*error
)
497 memcached_return_t unused
;
503 memcached_return_t rc
;
504 if (memcached_failed(rc
= initialize_query(self
)))
511 WATCHPOINT_ASSERT(error
);
513 if (self
->flags
.use_udp
)
515 *error
= memcached_set_error(*self
, MEMCACHED_NOT_SUPPORTED
, MEMCACHED_AT
);
520 memcached_stat_st
*stats
= libmemcached_xcalloc(self
, memcached_server_count(self
), memcached_stat_st
);
524 *error
= MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
529 WATCHPOINT_ASSERT(rc
== MEMCACHED_SUCCESS
);
530 rc
= MEMCACHED_SUCCESS
;
531 for (uint32_t x
= 0; x
< memcached_server_count(self
); x
++)
533 memcached_return_t temp_return
;
534 memcached_server_write_instance_st instance
;
535 memcached_stat_st
*stat_instance
;
537 stat_instance
= stats
+x
;
539 stat_instance
->pid
= -1;
540 stat_instance
->root
= self
;
542 instance
= memcached_server_instance_fetch(self
, x
);
544 if (self
->flags
.binary_protocol
)
546 temp_return
= binary_stats_fetch(stat_instance
, args
, instance
, NULL
);
550 temp_return
= ascii_stats_fetch(stat_instance
, args
, instance
, NULL
);
553 if (memcached_failed(temp_return
))
555 rc
= MEMCACHED_SOME_ERRORS
;
564 memcached_return_t
memcached_stat_servername(memcached_stat_st
*memc_stat
, char *args
,
565 const char *hostname
, in_port_t port
)
568 memcached_server_write_instance_st instance
;
570 memset(memc_stat
, 0, sizeof(memcached_stat_st
));
572 memcached_st
*memc_ptr
= memcached_create(&memc
);
574 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
576 memcached_server_add(&memc
, hostname
, port
);
578 memcached_return_t rc
;
579 if ((rc
= initialize_query(memc_ptr
)) != MEMCACHED_SUCCESS
)
584 instance
= memcached_server_instance_fetch(memc_ptr
, 0);
586 if (memc
.flags
.binary_protocol
)
588 rc
= binary_stats_fetch(memc_stat
, args
, instance
, NULL
);
592 rc
= ascii_stats_fetch(memc_stat
, args
, instance
, NULL
);
595 memcached_free(&memc
);
601 We make a copy of the keys since at some point in the not so distant future
602 we will add support for "found" keys.
604 char ** memcached_stat_get_keys(memcached_st
*ptr
,
606 memcached_return_t
*error
)
611 char **list
= static_cast<char **>(libmemcached_malloc(ptr
, sizeof(memcached_stat_keys
)));
614 *error
= memcached_set_error(*ptr
, MEMCACHED_MEMORY_ALLOCATION_FAILURE
, MEMCACHED_AT
);
618 memcpy(list
, memcached_stat_keys
, sizeof(memcached_stat_keys
));
620 *error
= MEMCACHED_SUCCESS
;
625 void memcached_stat_free(const memcached_st
*, memcached_stat_st
*memc_stat
)
627 WATCHPOINT_ASSERT(memc_stat
); // Be polite, but when debugging catch this as an error
628 if (memc_stat
== NULL
)
635 libmemcached_free(memc_stat
->root
, memc_stat
);
639 libmemcached_free(NULL
, memc_stat
);
642 static memcached_return_t
call_stat_fn(memcached_st
*ptr
,
643 memcached_server_write_instance_st instance
,
646 memcached_return_t rc
;
647 struct local_context
*check
= (struct local_context
*)context
;
649 if (ptr
->flags
.binary_protocol
)
651 rc
= binary_stats_fetch(NULL
, check
->args
, instance
, check
);
655 rc
= ascii_stats_fetch(NULL
, check
->args
, instance
, check
);
661 memcached_return_t
memcached_stat_execute(memcached_st
*memc
, const char *args
, memcached_stat_fn func
, void *context
)
663 memcached_version(memc
);
665 struct local_context
check(func
, context
, args
);
667 return memcached_server_execute(memc
, call_stat_fn
, (void *)&check
);