From 12a07e58df95bb8dbe167e4157b29c910177ade8 Mon Sep 17 00:00:00 2001 From: Brian Aker Date: Wed, 6 Jul 2011 11:15:01 -0700 Subject: [PATCH 1/1] Merge in pid/ping status. --- libmemcached/util/pid.cc | 41 +++++++++++++------ libmemcached/util/ping.cc | 14 +++++-- libtest/killpid.cc | 5 ++- libtest/memcached.cc | 83 ++++++++++++-------------------------- libtest/server.cc | 69 +++++++++++++++++++++++++++---- libtest/server.h | 56 +++++++++++++++++++------ libtest/test.cc | 10 ++++- tests/cycle.cc | 61 +++++++++++++++++++++++++++- tests/include.am | 3 ++ tests/libmemcached_world.h | 11 +++-- 10 files changed, 250 insertions(+), 103 deletions(-) diff --git a/libmemcached/util/pid.cc b/libmemcached/util/pid.cc index 75edd518..d9ba79c7 100644 --- a/libmemcached/util/pid.cc +++ b/libmemcached/util/pid.cc @@ -46,30 +46,47 @@ pid_t libmemcached_util_getpid(const char *hostname, in_port_t port, memcached_return_t *ret) { - memcached_st *memc_ptr= memcached_create(NULL); - pid_t pid= -1; + memcached_return_t unused; + if (not ret) + ret= &unused; + + memcached_st *memc_ptr= memcached_create(NULL); + if (not memc_ptr) + { + *ret= MEMCACHED_MEMORY_ALLOCATION_FAILURE; + return pid; + } + memcached_return_t rc= memcached_server_add(memc_ptr, hostname, port); if (memcached_success(rc)) { - if (memcached_success(memcached_version(memc_ptr))) + memcached_stat_st *stat= memcached_stat(memc_ptr, NULL, &rc); + if (stat and stat->pid > 0) + { + pid= stat->pid; + } + else if (memcached_failed(rc) and rc == MEMCACHED_SOME_ERRORS) { - memcached_stat_st *stat= memcached_stat(memc_ptr, NULL, &rc); - if (stat and stat->pid > 0) + memcached_server_instance_st instance= + memcached_server_instance_by_position(memc_ptr, 0); + + if (instance and instance->error_messages) { - pid= stat->pid; + rc= memcached_server_error_return(instance); } - - memcached_stat_free(memc_ptr, stat); } + else if (memcached_success(rc)) + { + rc= MEMCACHED_UNKNOWN_STAT_KEY; // Something went wrong if this happens + } + + memcached_stat_free(memc_ptr, stat); } memcached_free(memc_ptr); - if (ret) - { - *ret= rc; - } + *ret= rc; return pid; } diff --git a/libmemcached/util/ping.cc b/libmemcached/util/ping.cc index 52489b95..839810d4 100644 --- a/libmemcached/util/ping.cc +++ b/libmemcached/util/ping.cc @@ -43,7 +43,16 @@ bool libmemcached_util_ping(const char *hostname, in_port_t port, memcached_return_t *ret) { + memcached_return_t unused; + if (not ret) + ret= &unused; + memcached_st *memc_ptr= memcached_create(NULL); + if (not memc_ptr) + { + *ret= MEMCACHED_MEMORY_ALLOCATION_FAILURE; + return false; + } memcached_return_t rc= memcached_server_add(memc_ptr, hostname, port); if (memcached_success(rc)) @@ -63,10 +72,7 @@ bool libmemcached_util_ping(const char *hostname, in_port_t port, memcached_retu } memcached_free(memc_ptr); - if (ret) - { - *ret= rc; - } + *ret= rc; return memcached_success(rc); } diff --git a/libtest/killpid.cc b/libtest/killpid.cc index e963f4a7..ca8a659b 100644 --- a/libtest/killpid.cc +++ b/libtest/killpid.cc @@ -45,7 +45,10 @@ bool kill_pid(pid_t pid_arg) { - if ((kill(pid_arg, SIGTERM) == -1)) + if (pid_arg <= 1) + return false; + + if ((::kill(pid_arg, SIGTERM) == -1)) { switch (errno) { diff --git a/libtest/memcached.cc b/libtest/memcached.cc index e7e87f26..adaa30f6 100644 --- a/libtest/memcached.cc +++ b/libtest/memcached.cc @@ -68,18 +68,21 @@ #define CERR_PREFIX std::endl << __FILE__ << ":" << __LINE__ << " " -static void global_sleep(void) -{ - static struct timespec global_sleep_value= { 0, 50000 }; +#define SOCKET_FILE "/tmp/memcached.socket" -#ifdef WIN32 - sleep(1); -#else - nanosleep(&global_sleep_value, NULL); -#endif +static pid_t __getpid(server_st& server) +{ + memcached_return_t rc; + pid_t pid= libmemcached_util_getpid(server.hostname, server.port(), &rc); + return pid; } -#define SOCKET_FILE "/tmp/memcached.socket" +static bool __ping(server_st& server) +{ + memcached_return_t rc; + bool ret= libmemcached_util_ping(server.hostname, server.port(), &rc); + return ret; +} static bool cycle_server(server_st& server) { @@ -123,6 +126,12 @@ bool server_startup(server_startup_st *construct) } else { + for (uint32_t x= 0; x < construct->count; x++) + { + server_st &server= construct->server[x]; + server.set_methods(__getpid, __ping); + } + std::string server_config_string; uint32_t port_base= 0; @@ -170,34 +179,14 @@ bool server_startup(server_startup_st *construct) snprintf(buffer, sizeof(buffer), "%s -d -t 1 -p %u -U %u", MEMCACHED_BINARY, server.port(), server.port()); } + server.set_command(buffer); - int status= system(buffer); - if (status == -1) + if (not server.start()) { std::cerr << CERR_PREFIX << "Failed system(" << buffer << ")" << std::endl; return false; } - fprintf(stderr, "STARTING SERVER: %s\n", buffer); - - int count= 30; - memcached_return_t rc; - while (not libmemcached_util_ping(server.hostname, server.port(), &rc) and --count) - { - global_sleep(); - } - - if (memcached_failed(rc)) - { - std::cerr << CERR_PREFIX << "libmemcached_util_ping() failed:" << memcached_strerror(NULL, rc) << " Connection:" << server << std::endl; - return false; - } - - server.set_pid(libmemcached_util_getpid(server.hostname, server.port(), &rc)); - if (not server.has_pid()) - { - std::cerr << CERR_PREFIX << "libmemcached_util_getpid() failed" << memcached_strerror(NULL, rc) << " Connection: " << server << std::endl; - return false; - } + std::cerr << "STARTING SERVER: " << buffer << " pid:" << server.pid() << std::endl; } server_config_string+= "--server="; @@ -205,9 +194,9 @@ bool server_startup(server_startup_st *construct) server_config_string+= ":"; server_config_string+= boost::lexical_cast(server.port()); server_config_string+= " "; - fprintf(stderr, " Port %d\n", server.port()); } + // Socket { server_st &server= construct->server[construct->count -1]; @@ -225,7 +214,7 @@ bool server_startup(server_startup_st *construct) { if (not cycle_server(server)) { - std::cerr << CERR_PREFIX << "Found server " << server << ", could not flush it, so trying next port." << std::endl; + std::cerr << CERR_PREFIX << "Found server " << server << ", could not flush it, failing since socket file is not available." << std::endl; return false; } } @@ -239,34 +228,14 @@ bool server_startup(server_startup_st *construct) { char buffer[FILENAME_MAX]; snprintf(buffer, sizeof(buffer), "%s -d -t 1 -s %s", MEMCACHED_BINARY, SOCKET_FILE); + server.set_command(buffer); - int status= system(buffer); - if (status == -1) + if (not server.start()) { std::cerr << CERR_PREFIX << "Failed system(" << buffer << ")" << std::endl; return false; } - fprintf(stderr, "STARTING SERVER: %s\n", buffer); - - int count= 30; - memcached_return_t rc; - while (not libmemcached_util_ping(server.hostname, server.port(), &rc) and --count) - { - global_sleep(); - } - - if (memcached_failed(rc)) - { - std::cerr << CERR_PREFIX << "libmemcached_util_ping() failed:" << memcached_strerror(NULL, rc) << " Connection:" << server << std::endl; - return false; - } - - server.set_pid(libmemcached_util_getpid(server.hostname, server.port(), &rc)); - if (not server.has_pid()) - { - std::cerr << CERR_PREFIX << "libmemcached_util_getpid() failed" << memcached_strerror(NULL, rc) << " Connection: " << server << std::endl; - return false; - } + std::cerr << "STARTING SERVER: " << buffer << " pid:" << server.pid() << std::endl; } { diff --git a/libtest/server.cc b/libtest/server.cc index 78c2a771..d9175dba 100644 --- a/libtest/server.cc +++ b/libtest/server.cc @@ -3,7 +3,6 @@ * Libmemcached library * * Copyright (C) 2011 Data Differential, http://datadifferential.com/ - * Copyright (C) 2006-2009 Brian Aker All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -37,6 +36,8 @@ #include #include +#include +#include #include #include @@ -55,30 +56,77 @@ std::ostream& operator<<(std::ostream& output, const server_st &arg) return output; // for multiple << operators } +static void global_sleep(void) +{ + static struct timespec global_sleep_value= { 0, 50000 }; + +#ifdef WIN32 + sleep(1); +#else + nanosleep(&global_sleep_value, NULL); +#endif +} + server_st::~server_st() { - if (not _used) + if (has_pid()) { kill(); } } +bool server_st::start() +{ + assert(not _command.empty()); + assert(not has_pid()); + + if (has_pid()) + return false; + + if (system(_command.c_str()) == -1) + return false; + + int count= 30; + while (not ping() and --count) + { + global_sleep(); + } + + if (count == 0) + { + return false; + } + + _pid= get_pid(); + + return has_pid(); +} + void server_st::reset_pid() { pid_file[0]= 0; _pid= -1; } -bool server_st::kill() +pid_t server_st::pid() { - if (not has_pid() and pid_file[0] == 0) + if (not has_pid()) { - return true; + _pid= get_pid(); } - - if (has_pid()) + + return _pid; +} + + +bool server_st::kill() +{ + if (is_used()) + return false; + + if ((_pid= get_pid())) { - kill_pid(pid()); + kill_pid(_pid); if (pid_file[0]) { unlink(pid_file); // If this happens we may be dealing with a dead server that left its pid file. @@ -87,6 +135,7 @@ bool server_st::kill() return true; } +#if 0 else if (pid_file[0]) { kill_file(pid_file); @@ -94,6 +143,10 @@ bool server_st::kill() return true; } +#endif return false; } + +server_startup_st::~server_startup_st() +{ } diff --git a/libtest/server.h b/libtest/server.h index c209881e..198e0f6a 100644 --- a/libtest/server.h +++ b/libtest/server.h @@ -17,12 +17,21 @@ #define SERVERS_TO_CREATE 5 +struct server_st; + +typedef pid_t (test_server_getpid)(server_st &); +typedef bool (test_server_ping)(server_st &); + struct server_st { private: bool _used; pid_t _pid; in_port_t _port; char pid_file[FILENAME_MAX]; // Did we start it, or was it just sitting there? + std::string _command; + test_server_getpid *__get_pid; + test_server_ping *__ping; + public: char hostname[NI_MAXHOST]; @@ -30,12 +39,36 @@ public: server_st() : _used(false), _pid(-1), - _port(0) + _port(0), + __get_pid(NULL), + __ping(NULL) { pid_file[0]= 0; strncpy(hostname, "localhost", sizeof(hostname)); } + void set_methods(test_server_getpid *get_pid_arg, test_server_ping *ping_arg) + { + __get_pid= get_pid_arg; + __ping= ping_arg; + } + + bool ping() + { + if (__ping) + return __ping(*this); + + return false; + } + + pid_t get_pid() + { + if (__get_pid) + return _pid= __get_pid(*this); + + return -1; + } + void set_port(in_port_t arg) { _port= arg; @@ -48,23 +81,20 @@ public: bool has_port() const { - return not _port == 0; + return (_port != 0); } - void set_used() + void set_command(const char *arg) { - _used= true; + _command= arg; } - void set_pid(pid_t arg) + void set_used() { - _pid= arg; + _used= true; } - pid_t pid() const - { - return _pid; - } + pid_t pid(); bool is_used() const { @@ -75,7 +105,7 @@ public: bool has_pid() { - return _pid > 0; + return (_pid > 1); } bool is_socket() const @@ -89,6 +119,7 @@ public: } bool kill(); + bool start(); private: void reset_pid(); @@ -108,8 +139,7 @@ struct server_startup_st udp(0) { } - ~server_startup_st() - { } + ~server_startup_st(); }; #ifdef __cplusplus diff --git a/libtest/test.cc b/libtest/test.cc index 49f3893b..29c26ca4 100644 --- a/libtest/test.cc +++ b/libtest/test.cc @@ -138,15 +138,18 @@ static void *sig_thread(void *arg) int error; while ((error= sigwait(set, &sig)) == EINTR) ; - std::cerr << std::endl << "Signal handling thread got signal " << strsignal(sig) << std::endl; switch (sig) { case SIGSEGV: case SIGINT: case SIGABRT: + std::cerr << std::endl << "Signal handling thread got signal " << strsignal(sig) << std::endl; __shutdown= SHUTDOWN_FORCED; + break; default: + std::cerr << std::endl << "Signal handling thread got unexpected signal " << strsignal(sig) << std::endl; + case SIGUSR1: break; } } @@ -163,6 +166,7 @@ static void setup_signals(pthread_t& thread) sigaddset(&set, SIGSEGV); sigaddset(&set, SIGABRT); sigaddset(&set, SIGINT); + sigaddset(&set, SIGUSR1); int error; if ((error= pthread_sigmask(SIG_BLOCK, &set, NULL)) != 0) @@ -372,6 +376,10 @@ cleanup: stats_print(&stats); + void *retval; + pthread_kill(thread, SIGUSR1); + pthread_join(thread, &retval); + delete world; return stats.failed == 0 and __shutdown == SHUTDOWN_GRACEFUL ? EXIT_SUCCESS : EXIT_FAILURE; diff --git a/tests/cycle.cc b/tests/cycle.cc index 3b0aa241..25ca66cc 100644 --- a/tests/cycle.cc +++ b/tests/cycle.cc @@ -42,6 +42,10 @@ #include #include +#include +#include + +#include #include @@ -52,14 +56,57 @@ #pragma GCC diagnostic ignored "-Wstrict-aliasing" #endif -test_st ping[] ={ +static test_return_t alive(memcached_st *memc) +{ + test_true(memc); + test_true(memcached_is_allocated(memc)); + for (uint32_t x= 0; x < memcached_server_count(memc); ++x) + { + memcached_server_instance_st instance= memcached_server_instance_by_position(memc, x); + test_true(instance); + + test_true(libmemcached_util_ping(memcached_server_name(instance), + memcached_server_port(instance), NULL)); + } + + return TEST_SUCCESS; +} + +static test_return_t valid(memcached_st *memc) +{ + test_true(memc); + test_true(memcached_is_allocated(memc)); + + for (uint32_t x= 0; x < memcached_server_count(memc); ++x) + { + memcached_server_instance_st instance= memcached_server_instance_by_position(memc, x); + test_true(instance); + + pid_t pid= libmemcached_util_getpid(memcached_server_name(instance), + memcached_server_port(instance), NULL); + test_true(pid != -1); + } + + return TEST_SUCCESS; +} + +test_st ping_tests[] ={ + {"alive", true, (test_callback_fn*)alive }, + {0, 0, 0} +}; + +test_st getpid_tests[] ={ + {"valid", true, (test_callback_fn*)valid }, {0, 0, 0} }; collection_st collection[] ={ + {"libmemcached_util_ping()", 0, 0, ping_tests}, + {"libmemcached_util_getpid()", 0, 0, getpid_tests}, {0, 0, 0, 0} }; +#if 0 static server_startup_st *world_create(test_return_t *error) { server_startup_st *servers= new server_startup_st(); @@ -78,8 +125,10 @@ static test_return_t world_destroy(server_startup_st *servers) return TEST_SUCCESS; } +#endif +#include "tests/libmemcached_world.h" void get_world(Framework *world) { @@ -87,5 +136,15 @@ void get_world(Framework *world) world->_create= (test_callback_create_fn*)world_create; world->_destroy= (test_callback_fn*)world_destroy; + + world->item._startup= (test_callback_fn*)world_test_startup; + world->item.set_pre((test_callback_fn*)world_pre_run); + world->item.set_post((test_callback_fn*)world_post_run); + world->_on_error= (test_callback_error_fn*)world_on_error; + + world->collection_startup= (test_callback_fn*)world_container_startup; + world->collection_shutdown= (test_callback_fn*)world_container_shutdown; + + world->runner= &defualt_libmemcached_runner; } diff --git a/tests/include.am b/tests/include.am index e2546709..d6d3dab0 100644 --- a/tests/include.am +++ b/tests/include.am @@ -305,6 +305,9 @@ gdb-cycle: tests/cycle gdb-memslap: clients/memslap $(DEBUG_COMMAND) $(MEMSLAP_COMMAND) +valgrind-cycle: tests/cycle + $(VALGRIND_COMMAND) $(CYCLE_COMMAND) + valgrind-mem: tests/testapp $(VALGRIND_COMMAND) $(MEM_COMMAND) diff --git a/tests/libmemcached_world.h b/tests/libmemcached_world.h index a6de23a0..dfdddbef 100644 --- a/tests/libmemcached_world.h +++ b/tests/libmemcached_world.h @@ -40,8 +40,6 @@ test_return_t world_post_run(libmemcached_test_container_st *); test_return_t world_on_error(test_return_t, libmemcached_test_container_st *); test_return_t world_destroy(libmemcached_test_container_st *); -static libmemcached_test_container_st global_container; - /** @note generic shutdown/startup for libmemcached tests. */ @@ -50,9 +48,8 @@ test_return_t world_container_shutdown(libmemcached_test_container_st *container libmemcached_test_container_st *world_create(test_return_t *error) { - global_container.construct.count= SERVERS_TO_CREATE; - global_container.construct.udp= 0; - if (not server_startup(&global_container.construct)) + libmemcached_test_container_st *global_container= new libmemcached_test_container_st(); + if (not server_startup(&global_container->construct)) { *error= TEST_FAILURE; return NULL; @@ -60,7 +57,7 @@ libmemcached_test_container_st *world_create(test_return_t *error) *error= TEST_SUCCESS; - return &global_container; + return global_container; } test_return_t world_container_startup(libmemcached_test_container_st *container) @@ -150,6 +147,8 @@ test_return_t world_destroy(libmemcached_test_container_st *container) sasl_done(); #endif + delete container; + return TEST_SUCCESS; } -- 2.30.2