1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: 2 * 3 * Libmemcached library 4 * 5 * Copyright (C) 2011-2013 Data Differential, http://datadifferential.com/ 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are 9 * met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 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 17 * distribution. 18 * 19 * * The names of its contributors may not be used to endorse or 20 * promote products derived from this software without specific prior 21 * written permission. 22 * 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. 34 * 35 */ 36 37 #include <libmemcached/common.h> 38 39 static const char *memcached_stat_keys[] = { 40 "pid", 41 "uptime", 42 "time", 43 "version", 44 "pointer_size", 45 "rusage_user", 46 "rusage_system", 47 "curr_items", 48 "total_items", 49 "bytes", 50 "curr_connections", 51 "total_connections", 52 "connection_structures", 53 "cmd_get", 54 "cmd_set", 55 "get_hits", 56 "get_misses", 57 "evictions", 58 "bytes_read", 59 "bytes_written", 60 "limit_maxbytes", 61 "threads", 62 NULL 63 }; 64 65 struct local_context 66 { 67 memcached_stat_fn func; 68 void *context; 69 const char *args; 70 const size_t args_length; 71 72 local_context(memcached_stat_fn func_arg, 73 void *context_arg, 74 const char *args_arg, 75 const size_t args_length_arg) : 76 func(func_arg), 77 context(context_arg), 78 args(args_arg), 79 args_length(args_length_arg) 80 { } 81 }; 82 83 84 static memcached_return_t set_data(memcached_stat_st *memc_stat, const char *key, const char *value) 85 { 86 87 if (strlen(key) < 1) 88 { 89 WATCHPOINT_STRING(key); 90 return MEMCACHED_UNKNOWN_STAT_KEY; 91 } 92 else if (strcmp("pid", key) == 0) 93 { 94 errno= 0; 95 int64_t temp= strtoll(value, (char **)NULL, 10); 96 if (errno != 0) 97 { 98 return MEMCACHED_FAILURE; 99 } 100 101 if (temp <= INT32_MAX and ( sizeof(pid_t) == sizeof(int32_t) )) 102 { 103 memc_stat->pid= pid_t(temp); 104 } 105 else if (temp > -1) 106 { 107 memc_stat->pid= pid_t(temp); 108 } 109 else 110 { 111 // If we got a value less then -1 then something went wrong in the 112 // protocol 113 } 114 } 115 else if (not strcmp("uptime", key)) 116 { 117 errno= 0; 118 memc_stat->uptime= strtoul(value, (char **)NULL, 10); 119 if (errno != 0) 120 { 121 return MEMCACHED_FAILURE; 122 } 123 } 124 else if (not strcmp("time", key)) 125 { 126 errno= 0; 127 memc_stat->time= strtoul(value, (char **)NULL, 10); 128 if (errno != 0) 129 { 130 return MEMCACHED_FAILURE; 131 } 132 } 133 else if (not strcmp("version", key)) 134 { 135 memcpy(memc_stat->version, value, strlen(value)); 136 memc_stat->version[strlen(value)]= 0; 137 } 138 else if (not strcmp("pointer_size", key)) 139 { 140 errno= 0; 141 memc_stat->pointer_size= strtoul(value, (char **)NULL, 10); 142 if (errno != 0) 143 { 144 return MEMCACHED_FAILURE; 145 } 146 } 147 else if (not strcmp("rusage_user", key)) 148 { 149 char *walk_ptr; 150 for (walk_ptr= (char*)value; (!ispunct(*walk_ptr)); walk_ptr++) {}; 151 *walk_ptr= 0; 152 walk_ptr++; 153 154 errno= 0; 155 memc_stat->rusage_user_seconds= strtoul(value, (char **)NULL, 10); 156 if (errno != 0) 157 { 158 return MEMCACHED_FAILURE; 159 } 160 161 errno= 0; 162 memc_stat->rusage_user_microseconds= strtoul(walk_ptr, (char **)NULL, 10); 163 if (errno != 0) 164 { 165 return MEMCACHED_FAILURE; 166 } 167 } 168 else if (not strcmp("rusage_system", key)) 169 { 170 char *walk_ptr; 171 for (walk_ptr= (char*)value; (!ispunct(*walk_ptr)); walk_ptr++) {}; 172 *walk_ptr= 0; 173 walk_ptr++; 174 175 errno= 0; 176 memc_stat->rusage_system_seconds= strtoul(value, (char **)NULL, 10); 177 if (errno != 0) 178 { 179 return MEMCACHED_FAILURE; 180 } 181 182 errno= 0; 183 memc_stat->rusage_system_microseconds= strtoul(walk_ptr, (char **)NULL, 10); 184 if (errno != 0) 185 { 186 return MEMCACHED_FAILURE; 187 } 188 } 189 else if (not strcmp("curr_items", key)) 190 { 191 errno= 0; 192 memc_stat->curr_items= strtoul(value, (char **)NULL, 10); 193 if (errno != 0) 194 { 195 return MEMCACHED_FAILURE; 196 } 197 } 198 else if (not strcmp("total_items", key)) 199 { 200 errno= 0; 201 memc_stat->total_items= strtoul(value, (char **)NULL, 10); 202 if (errno != 0) 203 { 204 return MEMCACHED_FAILURE; 205 } 206 } 207 else if (not strcmp("bytes_read", key)) 208 { 209 errno= 0; 210 memc_stat->bytes_read= strtoull(value, (char **)NULL, 10); 211 if (errno != 0) 212 { 213 return MEMCACHED_FAILURE; 214 } 215 } 216 else if (not strcmp("bytes_written", key)) 217 { 218 errno= 0; 219 memc_stat->bytes_written= strtoull(value, (char **)NULL, 10); 220 if (errno != 0) 221 { 222 return MEMCACHED_FAILURE; 223 } 224 } 225 else if (not strcmp("bytes", key)) 226 { 227 errno= 0; 228 memc_stat->bytes= strtoull(value, (char **)NULL, 10); 229 if (errno != 0) 230 { 231 return MEMCACHED_FAILURE; 232 } 233 } 234 else if (not strcmp("curr_connections", key)) 235 { 236 errno= 0; 237 memc_stat->curr_connections= strtoull(value, (char **)NULL, 10); 238 if (errno != 0) 239 { 240 return MEMCACHED_FAILURE; 241 } 242 } 243 else if (not strcmp("total_connections", key)) 244 { 245 errno= 0; 246 memc_stat->total_connections= strtoull(value, (char **)NULL, 10); 247 if (errno != 0) 248 { 249 return MEMCACHED_FAILURE; 250 } 251 } 252 else if (not strcmp("connection_structures", key)) 253 { 254 errno= 0; 255 memc_stat->connection_structures= strtoul(value, (char **)NULL, 10); 256 if (errno != 0) 257 { 258 return MEMCACHED_FAILURE; 259 } 260 } 261 else if (not strcmp("cmd_get", key)) 262 { 263 errno= 0; 264 memc_stat->cmd_get= strtoull(value, (char **)NULL, 10); 265 if (errno != 0) 266 { 267 return MEMCACHED_FAILURE; 268 } 269 } 270 else if (not strcmp("cmd_set", key)) 271 { 272 errno= 0; 273 memc_stat->cmd_set= strtoull(value, (char **)NULL, 10); 274 if (errno != 0) 275 { 276 return MEMCACHED_FAILURE; 277 } 278 } 279 else if (not strcmp("get_hits", key)) 280 { 281 errno= 0; 282 memc_stat->get_hits= strtoull(value, (char **)NULL, 10); 283 if (errno != 0) 284 { 285 return MEMCACHED_FAILURE; 286 } 287 } 288 else if (not strcmp("get_misses", key)) 289 { 290 errno= 0; 291 memc_stat->get_misses= strtoull(value, (char **)NULL, 10); 292 if (errno != 0) 293 { 294 return MEMCACHED_FAILURE; 295 } 296 } 297 else if (not strcmp("evictions", key)) 298 { 299 errno= 0; 300 memc_stat->evictions= strtoull(value, (char **)NULL, 10); 301 if (errno != 0) 302 { 303 return MEMCACHED_FAILURE; 304 } 305 } 306 else if (not strcmp("limit_maxbytes", key)) 307 { 308 errno= 0; 309 memc_stat->limit_maxbytes= strtoull(value, (char **)NULL, 10); 310 if (errno != 0) 311 { 312 return MEMCACHED_FAILURE; 313 } 314 } 315 else if (not strcmp("threads", key)) 316 { 317 errno= 0; 318 memc_stat->threads= strtoul(value, (char **)NULL, 10); 319 if (errno != 0) 320 { 321 return MEMCACHED_FAILURE; 322 } 323 } 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) 340 { 341 WATCHPOINT_STRING(key); 342 /* return MEMCACHED_UNKNOWN_STAT_KEY; */ 343 return MEMCACHED_SUCCESS; 344 } 345 346 return MEMCACHED_SUCCESS; 347 } 348 349 char *memcached_stat_get_value(const memcached_st* shell, memcached_stat_st *memc_stat, 350 const char *key, memcached_return_t *error) 351 { 352 memcached_return_t not_used; 353 if (error == NULL) 354 { 355 error= ¬_used; 356 } 357 358 if (memc_stat == NULL) 359 { 360 *error= MEMCACHED_INVALID_ARGUMENTS; 361 return NULL; 362 } 363 364 char buffer[SMALL_STRING_LEN]; 365 int length; 366 367 *error= MEMCACHED_SUCCESS; 368 369 if (memcmp("pid", key, sizeof("pid") -1) == 0) 370 { 371 length= snprintf(buffer, SMALL_STRING_LEN,"%lld", (signed long long)memc_stat->pid); 372 } 373 else if (not memcmp("uptime", key, sizeof("uptime") -1)) 374 { 375 length= snprintf(buffer, SMALL_STRING_LEN,"%lu", memc_stat->uptime); 376 } 377 else if (not memcmp("time", key, sizeof("time") -1)) 378 { 379 length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->time); 380 } 381 else if (not memcmp("version", key, sizeof("version") -1)) 382 { 383 length= snprintf(buffer, SMALL_STRING_LEN,"%s", memc_stat->version); 384 } 385 else if (not memcmp("pointer_size", key, sizeof("pointer_size") -1)) 386 { 387 length= snprintf(buffer, SMALL_STRING_LEN,"%lu", memc_stat->pointer_size); 388 } 389 else if (not memcmp("rusage_user", key, sizeof("rusage_user") -1)) 390 { 391 length= snprintf(buffer, SMALL_STRING_LEN,"%lu.%lu", memc_stat->rusage_user_seconds, memc_stat->rusage_user_microseconds); 392 } 393 else if (not memcmp("rusage_system", key, sizeof("rusage_system") -1)) 394 { 395 length= snprintf(buffer, SMALL_STRING_LEN,"%lu.%lu", memc_stat->rusage_system_seconds, memc_stat->rusage_system_microseconds); 396 } 397 else if (not memcmp("curr_items", key, sizeof("curr_items") -1)) 398 { 399 length= snprintf(buffer, SMALL_STRING_LEN,"%lu", memc_stat->curr_items); 400 } 401 else if (not memcmp("total_items", key, sizeof("total_items") -1)) 402 { 403 length= snprintf(buffer, SMALL_STRING_LEN,"%lu", memc_stat->total_items); 404 } 405 else if (not memcmp("curr_connections", key, sizeof("curr_connections") -1)) 406 { 407 length= snprintf(buffer, SMALL_STRING_LEN,"%lu", memc_stat->curr_connections); 408 } 409 else if (not memcmp("total_connections", key, sizeof("total_connections") -1)) 410 { 411 length= snprintf(buffer, SMALL_STRING_LEN,"%lu", memc_stat->total_connections); 412 } 413 else if (not memcmp("connection_structures", key, sizeof("connection_structures") -1)) 414 { 415 length= snprintf(buffer, SMALL_STRING_LEN,"%lu", memc_stat->connection_structures); 416 } 417 else if (not memcmp("cmd_get", key, sizeof("cmd_get") -1)) 418 { 419 length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->cmd_get); 420 } 421 else if (not memcmp("cmd_set", key, sizeof("cmd_set") -1)) 422 { 423 length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->cmd_set); 424 } 425 else if (not memcmp("get_hits", key, sizeof("get_hits") -1)) 426 { 427 length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->get_hits); 428 } 429 else if (not memcmp("get_misses", key, sizeof("get_misses") -1)) 430 { 431 length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->get_misses); 432 } 433 else if (not memcmp("evictions", key, sizeof("evictions") -1)) 434 { 435 length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->evictions); 436 } 437 else if (not memcmp("bytes_read", key, sizeof("bytes_read") -1)) 438 { 439 length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes_read); 440 } 441 else if (not memcmp("bytes_written", key, sizeof("bytes_written") -1)) 442 { 443 length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes_written); 444 } 445 else if (not memcmp("bytes", key, sizeof("bytes") -1)) 446 { 447 length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->bytes); 448 } 449 else if (not memcmp("limit_maxbytes", key, sizeof("limit_maxbytes") -1)) 450 { 451 length= snprintf(buffer, SMALL_STRING_LEN,"%llu", (unsigned long long)memc_stat->limit_maxbytes); 452 } 453 else if (not memcmp("threads", key, sizeof("threads") -1)) 454 { 455 length= snprintf(buffer, SMALL_STRING_LEN,"%lu", memc_stat->threads); 456 } 457 else 458 { 459 Memcached* memc= (Memcached*)memcached2Memcached(shell); 460 *error= memcached_set_error(*memc, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("Invalid key provided")); 461 return NULL; 462 } 463 464 if (length >= SMALL_STRING_LEN || length < 0) 465 { 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.")); 468 return NULL; 469 } 470 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); 474 ret[length]= '\0'; 475 476 return ret; 477 } 478 479 static memcached_return_t binary_stats_fetch(memcached_stat_st *memc_stat, 480 const char *args, 481 const size_t args_length, 482 memcached_instance_st* instance, 483 struct local_context *check) 484 { 485 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; 486 protocol_binary_request_stats request= {}; // = {.bytes= {0}}; 487 488 initialize_binary_request(instance, request.message.header); 489 490 request.message.header.request.opcode= PROTOCOL_BINARY_CMD_STAT; 491 request.message.header.request.datatype= PROTOCOL_BINARY_RAW_BYTES; 492 493 if (args_length) 494 { 495 request.message.header.request.keylen= htons(uint16_t(args_length)); 496 request.message.header.request.bodylen= htonl(uint32_t( args_length)); 497 498 libmemcached_io_vector_st vector[]= 499 { 500 { request.bytes, sizeof(request.bytes) }, 501 { args, args_length } 502 }; 503 504 if (memcached_vdo(instance, vector, 2, true) != MEMCACHED_SUCCESS) 505 { 506 memcached_io_reset(instance); 507 return MEMCACHED_WRITE_FAILURE; 508 } 509 } 510 else 511 { 512 libmemcached_io_vector_st vector[]= 513 { 514 { request.bytes, sizeof(request.bytes) } 515 }; 516 517 if (memcached_vdo(instance, vector, 1, true) != MEMCACHED_SUCCESS) 518 { 519 memcached_io_reset(instance); 520 return MEMCACHED_WRITE_FAILURE; 521 } 522 } 523 524 memcached_server_response_decrement(instance); 525 while (1) 526 { 527 memcached_return_t rc= memcached_response(instance, buffer, sizeof(buffer), NULL); 528 529 if (rc == MEMCACHED_END) 530 { 531 break; 532 } 533 534 if (rc != MEMCACHED_SUCCESS) 535 { 536 memcached_io_reset(instance); 537 return rc; 538 } 539 540 if (check && check->func) 541 { 542 size_t key_length= strlen(buffer); 543 544 check->func(instance, 545 buffer, key_length, 546 buffer+key_length+1, strlen(buffer+key_length+1), 547 check->context); 548 } 549 550 if (memc_stat) 551 { 552 if ((set_data(memc_stat, buffer, buffer + strlen(buffer) + 1)) == MEMCACHED_UNKNOWN_STAT_KEY) 553 { 554 WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY); 555 WATCHPOINT_ASSERT(0); 556 } 557 } 558 } 559 560 /* 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. 563 * */ 564 instance->cursor_active_= 0; 565 566 return MEMCACHED_SUCCESS; 567 } 568 569 static memcached_return_t ascii_stats_fetch(memcached_stat_st *memc_stat, 570 const char *args, 571 const size_t args_length, 572 memcached_instance_st* instance, 573 struct local_context *check) 574 { 575 libmemcached_io_vector_st vector[]= 576 { 577 { memcached_literal_param("stats ") }, 578 { args, args_length }, 579 { memcached_literal_param("\r\n") } 580 }; 581 582 memcached_return_t rc= memcached_vdo(instance, vector, 3, true); 583 if (memcached_success(rc)) 584 { 585 char buffer[MEMCACHED_DEFAULT_COMMAND_SIZE]; 586 while ((rc= memcached_response(instance, buffer, sizeof(buffer), NULL)) == MEMCACHED_STAT) 587 { 588 char *string_ptr= buffer; 589 string_ptr+= 5; /* Move past STAT */ 590 591 char *end_ptr; 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; 595 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; 600 #if 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); 604 #endif 605 606 if (check and check->func) 607 { 608 check->func(instance, 609 key, strlen(key), 610 value, strlen(value), 611 check->context); 612 } 613 614 if (memc_stat) 615 { 616 if((set_data(memc_stat, key, value)) == MEMCACHED_UNKNOWN_STAT_KEY) 617 { 618 WATCHPOINT_ERROR(MEMCACHED_UNKNOWN_STAT_KEY); 619 WATCHPOINT_ASSERT(0); 620 } 621 } 622 } 623 } 624 625 if (rc == MEMCACHED_ERROR) 626 { 627 return MEMCACHED_INVALID_ARGUMENTS; 628 } 629 630 if (rc == MEMCACHED_END) 631 { 632 return MEMCACHED_SUCCESS; 633 } 634 635 return rc; 636 } 637 638 memcached_stat_st *memcached_stat(memcached_st *shell, char *args, memcached_return_t *error) 639 { 640 Memcached* self= memcached2Memcached(shell); 641 memcached_return_t unused; 642 if (error == NULL) 643 { 644 error= &unused; 645 } 646 647 if (memcached_failed(*error= initialize_query(self, true))) 648 { 649 return NULL; 650 } 651 652 if (memcached_is_udp(self)) 653 { 654 *error= memcached_set_error(*self, MEMCACHED_NOT_SUPPORTED, MEMCACHED_AT); 655 return NULL; 656 } 657 658 memcached_return_t rc; 659 size_t args_length= 0; 660 if (args) 661 { 662 args_length= strlen(args); 663 if (memcached_failed(rc= memcached_key_test(*self, (const char **)&args, &args_length, 1))) 664 { 665 *error= memcached_set_error(*self, rc, MEMCACHED_AT); 666 return NULL; 667 } 668 } 669 670 WATCHPOINT_ASSERT(error); 671 672 memcached_stat_st *stats= libmemcached_xcalloc(self, memcached_server_count(self), memcached_stat_st); 673 if (stats == NULL) 674 { 675 *error= memcached_set_error(*self, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT); 676 return NULL; 677 } 678 679 WATCHPOINT_ASSERT(rc == MEMCACHED_SUCCESS); 680 rc= MEMCACHED_SUCCESS; 681 for (uint32_t x= 0; x < memcached_server_count(self); x++) 682 { 683 memcached_stat_st* stat_instance= stats +x; 684 685 stat_instance->pid= -1; 686 stat_instance->root= self; 687 688 memcached_instance_st* instance= memcached_instance_fetch(self, x); 689 690 memcached_return_t temp_return; 691 if (memcached_is_binary(self)) 692 { 693 temp_return= binary_stats_fetch(stat_instance, args, args_length, instance, NULL); 694 } 695 else 696 { 697 temp_return= ascii_stats_fetch(stat_instance, args, args_length, instance, NULL); 698 } 699 700 // Special case where "args" is invalid 701 if (temp_return == MEMCACHED_INVALID_ARGUMENTS) 702 { 703 rc= MEMCACHED_INVALID_ARGUMENTS; 704 break; 705 } 706 707 if (memcached_failed(temp_return)) 708 { 709 rc= MEMCACHED_SOME_ERRORS; 710 } 711 } 712 713 *error= rc; 714 715 return stats; 716 } 717 718 memcached_return_t memcached_stat_servername(memcached_stat_st *memc_stat, char *args, 719 const char *hostname, in_port_t port) 720 { 721 memcached_st memc; 722 723 memcached_stat_st unused_memc_stat; 724 if (memc_stat == NULL) 725 { 726 memc_stat= &unused_memc_stat; 727 } 728 729 memset(memc_stat, 0, sizeof(memcached_stat_st)); 730 731 memcached_st *memc_ptr= memcached_create(&memc); 732 if (memc_ptr == NULL) 733 { 734 return MEMCACHED_MEMORY_ALLOCATION_FAILURE; 735 } 736 737 memcached_return_t rc; 738 if (memcached_failed(rc= memcached_server_add(&memc, hostname, port))) 739 { 740 memcached_free(&memc); 741 return rc; 742 } 743 744 if (memcached_success(rc= initialize_query(memc_ptr, true))) 745 { 746 size_t args_length= 0; 747 if (args) 748 { 749 args_length= strlen(args); 750 rc= memcached_key_test(*memc_ptr, (const char **)&args, &args_length, 1); 751 } 752 753 if (memcached_success(rc)) 754 { 755 memcached_instance_st* instance= memcached_instance_fetch(memc_ptr, 0); 756 if (memc.flags.binary_protocol) 757 { 758 rc= binary_stats_fetch(memc_stat, args, args_length, instance, NULL); 759 } 760 else 761 { 762 rc= ascii_stats_fetch(memc_stat, args, args_length, instance, NULL); 763 } 764 } 765 } 766 767 memcached_free(&memc); 768 769 return rc; 770 } 771 772 /* 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. 775 */ 776 char ** memcached_stat_get_keys(memcached_st *shell, 777 memcached_stat_st *, 778 memcached_return_t *error) 779 { 780 Memcached* memc= memcached2Memcached(shell); 781 if (memc) 782 { 783 char **list= static_cast<char **>(libmemcached_malloc(memc, sizeof(memcached_stat_keys))); 784 if (list == NULL) 785 { 786 if (error) 787 { 788 *error= memcached_set_error(*memc, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT); 789 } 790 791 return NULL; 792 } 793 794 memcpy(list, memcached_stat_keys, sizeof(memcached_stat_keys)); 795 796 if (error) 797 { 798 *error= MEMCACHED_SUCCESS; 799 } 800 801 return list; 802 } 803 804 return NULL; 805 } 806 807 void memcached_stat_free(const memcached_st *, memcached_stat_st *memc_stat) 808 { 809 WATCHPOINT_ASSERT(memc_stat); // Be polite, but when debugging catch this as an error 810 if (memc_stat) 811 { 812 libmemcached_free(memc_stat->root, memc_stat); 813 } 814 } 815 816 static memcached_return_t call_stat_fn(memcached_st *memc, 817 memcached_instance_st* instance, 818 void *context) 819 { 820 if (memc) 821 { 822 local_context *check= (struct local_context *)context; 823 824 if (memcached_is_binary(memc)) 825 { 826 return binary_stats_fetch(NULL, check->args, check->args_length, instance, check); 827 } 828 else 829 { 830 return ascii_stats_fetch(NULL, check->args, check->args_length, instance, check); 831 } 832 } 833 834 return MEMCACHED_INVALID_ARGUMENTS; 835 } 836 837 memcached_return_t memcached_stat_execute(memcached_st *shell, const char *args, memcached_stat_fn func, void *context) 838 { 839 Memcached* memc= memcached2Memcached(shell); 840 if (memcached_fatal(memcached_version(memc))) 841 { 842 return memcached_last_error(memc); 843 } 844 845 local_context check(func, context, args, args ? strlen(args) : 0); 846 847 return memcached_server_execute(memc, call_stat_fn, (void *)&check); 848 } 849