*
*/
-#include <config.h>
+#include <mem_config.h>
#include <libtest/test.hpp>
using namespace libtest;
#include <semaphore.h>
-#include <libmemcached/memcached.h>
-#include <libmemcached/util.h>
+#include <libmemcached-1.0/memcached.h>
+#include <libmemcachedutil-1.0/util.h>
+#include <libmemcached/is.h>
#include <tests/pool.h>
+#include <pthread.h>
+#include <poll.h>
+
+#include "libmemcached/instance.hpp"
+
#ifndef __INTEL_COMPILER
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
test_return_t memcached_pool_test(memcached_st *)
{
- memcached_return_t rc;
const char *config_string= "--SERVER=host10.example.com --SERVER=host11.example.com --SERVER=host10.example.com --POOL-MIN=10 --POOL-MAX=32";
char buffer[2048];
- rc= libmemcached_check_configuration(config_string, sizeof(config_string) -1, buffer, sizeof(buffer));
- test_true_got(rc != MEMCACHED_SUCCESS, buffer);
+ test_compare(libmemcached_check_configuration(config_string, sizeof(config_string) -1, buffer, sizeof(buffer)), MEMCACHED_PARSE_ERROR);
memcached_pool_st* pool= memcached_pool(config_string, strlen(config_string));
- test_true_got(pool, strerror(errno));
+ test_true(pool);
+ memcached_return_t rc;
memcached_st *memc= memcached_pool_pop(pool, false, &rc);
- test_true(rc == MEMCACHED_SUCCESS);
+ test_compare(rc, MEMCACHED_SUCCESS);
test_true(memc);
/*
}
};
-static void* connection_release(void *arg)
+static __attribute__((noreturn)) void* connection_release(void *arg)
{
test_pool_context_st *resource= static_cast<test_pool_context_st *>(arg);
- if (resource == NULL)
- {
- fatal_message("resource == NULL");
- }
+ FATAL_IF(resource == NULL);
// Release all of the memc we are holding
resource->rc= memcached_pool_release(resource->pool, resource->mmc);
return TEST_SUCCESS;
}
+
+static memcached_st * create_single_instance_memcached(const memcached_st *original_memc, const char *options)
+{
+ /*
+ If no options are given, copy over at least the binary flag.
+ */
+ char options_buffer[1024]= { 0 };
+ if (options == NULL)
+ {
+ if (memcached_is_binary(original_memc))
+ {
+ snprintf(options_buffer, sizeof(options_buffer), "--BINARY");
+ }
+ }
+
+ /*
+ * I only want to hit _one_ server so I know the number of requests I'm
+ * sending in the pipeline.
+ */
+ const memcached_instance_st * instance= memcached_server_instance_by_position(original_memc, 0);
+
+ char server_string[1024];
+ int server_string_length;
+ if (instance->type == MEMCACHED_CONNECTION_UNIX_SOCKET)
+ {
+ if (options)
+ {
+ server_string_length= snprintf(server_string, sizeof(server_string), "--SOCKET=\"%s\" %s",
+ memcached_server_name(instance), options);
+ }
+ else
+ {
+ server_string_length= snprintf(server_string, sizeof(server_string), "--SOCKET=\"%s\"",
+ memcached_server_name(instance));
+ }
+ }
+ else
+ {
+ if (options)
+ {
+ server_string_length= snprintf(server_string, sizeof(server_string), "--server=%s:%d %s",
+ memcached_server_name(instance), int(memcached_server_port(instance)),
+ options);
+ }
+ else
+ {
+ server_string_length= snprintf(server_string, sizeof(server_string), "--server=%s:%d",
+ memcached_server_name(instance), int(memcached_server_port(instance)));
+ }
+ }
+
+ if (server_string_length <= 0)
+ {
+ return NULL;
+ }
+
+ char errror_buffer[1024];
+ if (memcached_failed(libmemcached_check_configuration(server_string, server_string_length, errror_buffer, sizeof(errror_buffer))))
+ {
+ Error << "Failed to parse (" << server_string << ") " << errror_buffer;
+ return NULL;
+ }
+
+ return memcached(server_string, server_string_length);
+}
+
+pthread_mutex_t mutex= PTHREAD_MUTEX_INITIALIZER;
+static bool _running= false;
+
+static void set_running(const bool arg)
+{
+ int error;
+ FATAL_IF_((error= pthread_mutex_lock(&mutex)) != 0, strerror(error));
+
+ _running= arg;
+
+ FATAL_IF_((error= pthread_mutex_unlock(&mutex)) != 0, strerror(error));
+}
+
+static bool running()
+{
+ int error;
+ bool ret;
+
+ FATAL_IF_((error= pthread_mutex_lock(&mutex)) != 0, strerror(error));
+
+ ret= _running;
+
+ FATAL_IF_((error= pthread_mutex_unlock(&mutex)) != 0, strerror(error));
+
+ return ret;
+}
+
+static void *worker_thread(void *ctx)
+{
+ memcached_pool_st *pool= (memcached_pool_st *)ctx;
+
+ while (running())
+ {
+ memcached_return_t rc;
+ memcached_st *mc= memcached_pool_pop(pool, true, &rc);
+
+ if (mc == NULL)
+ {
+ Error << "failed to fetch a connection from the pool" << memcached_strerror(NULL, rc);
+ dream(1, 0);
+ continue;
+ }
+
+ rc= memcached_set(mc, "test:kv", 7, "value", 5, 600, 0);
+ if (memcached_failed(rc))
+ {
+ Out << "failed memcached_set()";
+ }
+
+ rc= memcached_pool_push(pool, mc);
+ if (memcached_failed(rc))
+ {
+ Error << "failed to release a connection to the pool" << memcached_strerror(NULL, rc);
+ }
+ }
+
+ return NULL;
+}
+
+#define NUM_THREADS 20
+test_return_t regression_bug_962815(memcached_st *memc)
+{
+ pthread_t pid[NUM_THREADS];
+
+ test_false(running());
+
+ memcached_st *master = create_single_instance_memcached(memc, 0);
+ test_true(master);
+
+ memcached_pool_st *pool= memcached_pool_create(master, 5, 10);
+
+ test_true(pool);
+
+ set_running(true);
+
+ for (size_t x=0; x < NUM_THREADS; x++)
+ {
+ test_compare(0, pthread_create(&pid[x], NULL, worker_thread, (void*)pool));
+ }
+
+ {
+ pollfd fds[1];
+ memset(fds, 0, sizeof(pollfd));
+ fds[0].fd= -1; //STDIN_FILENO;
+ fds[0].events= POLLIN;
+ fds[0].revents= 0;
+
+ int active_fd;
+ if ((active_fd= poll(fds, 1, 5000)) == -1)
+ {
+ Error << "poll() failed with:" << strerror(errno);
+ }
+ test_zero(active_fd);
+
+ set_running(false);
+ }
+
+ for (size_t x=0; x < NUM_THREADS; x++)
+ {
+ test_compare(0, pthread_join(pid[x], NULL));
+ }
+
+ memcached_pool_destroy(pool);
+
+ memcached_free(master);
+
+ return TEST_SUCCESS;
+}