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;
}
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))
}
memcached_free(memc_ptr);
- if (ret)
- {
- *ret= rc;
- }
+ *ret= rc;
return memcached_success(rc);
}
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)
{
#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)
{
}
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;
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=";
server_config_string+= ":";
server_config_string+= boost::lexical_cast<std::string>(server.port());
server_config_string+= " ";
- fprintf(stderr, " Port %d\n", server.port());
}
+ // Socket
{
server_st &server= construct->server[construct->count -1];
{
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;
}
}
{
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;
}
{
* 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
#include <config.h>
#include <iostream>
+#include <cstdlib>
+#include <cassert>
#include <libtest/server.h>
#include <libtest/killpid.h>
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.
return true;
}
+#if 0
else if (pid_file[0])
{
kill_file(pid_file);
return true;
}
+#endif
return false;
}
+
+server_startup_st::~server_startup_st()
+{ }
#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];
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;
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
{
bool has_pid()
{
- return _pid > 0;
+ return (_pid > 1);
}
bool is_socket() const
}
bool kill();
+ bool start();
private:
void reset_pid();
udp(0)
{ }
- ~server_startup_st()
- { }
+ ~server_startup_st();
};
#ifdef __cplusplus
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;
}
}
sigaddset(&set, SIGSEGV);
sigaddset(&set, SIGABRT);
sigaddset(&set, SIGINT);
+ sigaddset(&set, SIGUSR1);
int error;
if ((error= pthread_sigmask(SIG_BLOCK, &set, NULL)) != 0)
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;
#include <libtest/common.h>
#include <libmemcached/common.h>
+#include <libmemcached/is.h>
+#include <libmemcached/util.h>
+
+#include <iostream>
#include <libtest/server.h>
#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();
return TEST_SUCCESS;
}
+#endif
+#include "tests/libmemcached_world.h"
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;
}
gdb-memslap: clients/memslap
$(DEBUG_COMMAND) $(MEMSLAP_COMMAND)
+valgrind-cycle: tests/cycle
+ $(VALGRIND_COMMAND) $(CYCLE_COMMAND)
+
valgrind-mem: tests/testapp
$(VALGRIND_COMMAND) $(MEM_COMMAND)
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.
*/
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;
*error= TEST_SUCCESS;
- return &global_container;
+ return global_container;
}
test_return_t world_container_startup(libmemcached_test_container_st *container)
sasl_done();
#endif
+ delete container;
+
return TEST_SUCCESS;
}