1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3 * Libmemcached Client and Server
5 * Copyright (C) 2011 Data Differential, http://datadifferential.com/
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following disclaimer
17 * in the documentation and/or other materials provided with the
20 * * The names of its contributors may not be used to endorse or
21 * promote products derived from this software without specific prior
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 #include <libtest/test.hpp>
41 using namespace libtest
;
48 #include <semaphore.h>
50 #include <libmemcached-1.0/memcached.h>
51 #include <libmemcachedutil-1.0/util.h>
52 #include <libmemcached/is.h>
53 #include <tests/pool.h>
57 #ifndef __INTEL_COMPILER
58 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
62 test_return_t
memcached_pool_test(memcached_st
*)
64 memcached_return_t rc
;
65 const char *config_string
= "--SERVER=host10.example.com --SERVER=host11.example.com --SERVER=host10.example.com --POOL-MIN=10 --POOL-MAX=32";
68 rc
= libmemcached_check_configuration(config_string
, sizeof(config_string
) -1, buffer
, sizeof(buffer
));
70 test_true_got(rc
!= MEMCACHED_SUCCESS
, buffer
);
72 memcached_pool_st
* pool
= memcached_pool(config_string
, strlen(config_string
));
73 test_true_got(pool
, strerror(errno
));
75 memcached_st
*memc
= memcached_pool_pop(pool
, false, &rc
);
77 test_true(rc
== MEMCACHED_SUCCESS
);
81 Release the memc_ptr that was pulled from the pool
83 memcached_pool_push(pool
, memc
);
88 memcached_pool_destroy(pool
);
95 test_return_t
connection_pool_test(memcached_st
*memc
)
97 memcached_pool_st
* pool
= memcached_pool_create(memc
, 5, POOL_SIZE
);
99 memcached_st
*mmc
[POOL_SIZE
];
101 // Fill up our array that we will store the memc that are in the pool
102 for (size_t x
= 0; x
< POOL_SIZE
; ++x
)
104 memcached_return_t rc
;
105 mmc
[x
]= memcached_pool_fetch(pool
, NULL
, &rc
);
106 test_compare(MEMCACHED_SUCCESS
, rc
);
110 // All memc should be gone
112 memcached_return_t rc
;
113 test_null(memcached_pool_fetch(pool
, NULL
, &rc
));
114 test_compare(MEMCACHED_NOTFOUND
, rc
);
118 for (size_t x
= 0; x
< POOL_SIZE
; ++x
)
122 test_compare(MEMCACHED_SUCCESS
, memcached_pool_release(pool
, mmc
[x
]));
125 test_true(memcached_pool_destroy(pool
) == memc
);
130 test_return_t
connection_pool2_test(memcached_st
*memc
)
132 memcached_pool_st
* pool
= memcached_pool_create(memc
, 5, POOL_SIZE
);
134 memcached_st
*mmc
[POOL_SIZE
];
136 // Fill up our array that we will store the memc that are in the pool
137 for (size_t x
= 0; x
< POOL_SIZE
; ++x
)
139 memcached_return_t rc
;
140 mmc
[x
]= memcached_pool_fetch(pool
, NULL
, &rc
);
141 test_compare(MEMCACHED_SUCCESS
, rc
);
145 // All memc should be gone
147 memcached_return_t rc
;
148 test_null(memcached_pool_fetch(pool
, NULL
, &rc
));
149 test_compare(MEMCACHED_NOTFOUND
, rc
);
152 // verify that I can do ops with all connections
153 test_compare(MEMCACHED_SUCCESS
,
154 memcached_set(mmc
[0],
155 test_literal_param("key"),
158 for (uint64_t x
= 0; x
< POOL_SIZE
; ++x
)
160 uint64_t number_value
;
161 test_compare(MEMCACHED_SUCCESS
,
162 memcached_increment(mmc
[x
],
163 test_literal_param("key"),
165 test_compare(number_value
, (x
+1));
169 for (size_t x
= 0; x
< POOL_SIZE
; ++x
)
171 test_compare(MEMCACHED_SUCCESS
, memcached_pool_release(pool
, mmc
[x
]));
175 /* verify that I can set behaviors on the pool when I don't have all
176 * of the connections in the pool. It should however be enabled
177 * when I push the item into the pool
179 mmc
[0]= memcached_pool_fetch(pool
, NULL
, NULL
);
182 test_compare(MEMCACHED_SUCCESS
,
183 memcached_pool_behavior_set(pool
, MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK
, 9999));
186 memcached_return_t rc
;
187 mmc
[1]= memcached_pool_fetch(pool
, NULL
, &rc
);
189 test_compare(MEMCACHED_SUCCESS
, rc
);
192 test_compare(UINT64_C(9999), memcached_behavior_get(mmc
[1], MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK
));
193 test_compare(MEMCACHED_SUCCESS
, memcached_pool_release(pool
, mmc
[1]));
194 test_compare(MEMCACHED_SUCCESS
, memcached_pool_release(pool
, mmc
[0]));
197 memcached_return_t rc
;
198 mmc
[0]= memcached_pool_fetch(pool
, NULL
, &rc
);
200 test_compare(MEMCACHED_SUCCESS
, rc
);
203 test_compare(UINT64_C(9999), memcached_behavior_get(mmc
[0], MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK
));
204 test_compare(MEMCACHED_SUCCESS
, memcached_pool_release(pool
, mmc
[0]));
206 test_true(memcached_pool_destroy(pool
) == memc
);
211 struct test_pool_context_st
{
212 volatile memcached_return_t rc
;
213 memcached_pool_st
* pool
;
217 test_pool_context_st(memcached_pool_st
*pool_arg
, memcached_st
*memc_arg
):
218 rc(MEMCACHED_FAILURE
),
222 sem_init(&_lock
, 0, 0);
235 ~test_pool_context_st()
241 static void* connection_release(void *arg
)
243 test_pool_context_st
*resource
= static_cast<test_pool_context_st
*>(arg
);
244 if (resource
== NULL
)
246 fatal_message("resource == NULL");
249 // Release all of the memc we are holding
250 resource
->rc
= memcached_pool_release(resource
->pool
, resource
->mmc
);
256 test_return_t
connection_pool3_test(memcached_st
*memc
)
262 memcached_pool_st
* pool
= memcached_pool_create(memc
, 1, 1);
265 memcached_st
*pool_memc
;
267 memcached_return_t rc
;
268 pool_memc
= memcached_pool_fetch(pool
, NULL
, &rc
);
269 test_compare(MEMCACHED_SUCCESS
, rc
);
270 test_true(pool_memc
);
274 @note This comment was written to describe what was believed to be the original authors intent.
276 This portion of the test creates a thread that will wait until told to free a memcached_st
277 that will be grabbed by the main thread.
279 It is believed that this tests whether or not we are handling ownership correctly.
282 test_pool_context_st
item(pool
, pool_memc
);
284 test_zero(pthread_create(&tid
, NULL
, connection_release
, &item
));
287 memcached_return_t rc
;
288 memcached_st
*pop_memc
;
289 // We do a hard loop, and try N times
293 struct timespec relative_time
= { 0, 0 };
294 pop_memc
= memcached_pool_fetch(pool
, &relative_time
, &rc
);
296 if (memcached_success(rc
))
301 if (memcached_failed(rc
))
304 test_true(rc
!= MEMCACHED_TIMEOUT
); // As long as relative_time is zero, MEMCACHED_TIMEOUT is invalid
308 if (memcached_failed(rc
)) // Cleanup thread since we will exit once we test.
310 pthread_join(tid
, NULL
);
311 test_compare(MEMCACHED_SUCCESS
, rc
);
315 int pthread_ret
= pthread_join(tid
, NULL
);
316 test_true(pthread_ret
== 0 or pthread_ret
== ESRCH
);
318 test_compare(MEMCACHED_SUCCESS
, rc
);
319 test_true(pool_memc
== pop_memc
);
321 test_true(memcached_pool_destroy(pool
) == memc
);
326 static memcached_st
* create_single_instance_memcached(const memcached_st
*original_memc
, const char *options
)
329 If no options are given, copy over at least the binary flag.
331 char options_buffer
[1024]= { 0 };
334 if (memcached_is_binary(original_memc
))
336 snprintf(options_buffer
, sizeof(options_buffer
), "--BINARY");
341 * I only want to hit _one_ server so I know the number of requests I'm
342 * sending in the pipeline.
344 memcached_server_instance_st instance
= memcached_server_instance_by_position(original_memc
, 0);
346 char server_string
[1024];
347 int server_string_length
;
348 if (instance
->type
== MEMCACHED_CONNECTION_UNIX_SOCKET
)
352 server_string_length
= snprintf(server_string
, sizeof(server_string
), "--SOCKET=\"%s\" %s",
353 memcached_server_name(instance
), options
);
357 server_string_length
= snprintf(server_string
, sizeof(server_string
), "--SOCKET=\"%s\"",
358 memcached_server_name(instance
));
365 server_string_length
= snprintf(server_string
, sizeof(server_string
), "--server=%s:%d %s",
366 memcached_server_name(instance
), int(memcached_server_port(instance
)),
371 server_string_length
= snprintf(server_string
, sizeof(server_string
), "--server=%s:%d",
372 memcached_server_name(instance
), int(memcached_server_port(instance
)));
376 if (server_string_length
<= 0)
381 char errror_buffer
[1024];
382 if (memcached_failed(libmemcached_check_configuration(server_string
, server_string_length
, errror_buffer
, sizeof(errror_buffer
))))
384 Error
<< "Failed to parse (" << server_string
<< ") " << errror_buffer
;
388 return memcached(server_string
, server_string_length
);
391 pthread_mutex_t mutex
= PTHREAD_MUTEX_INITIALIZER
;
392 static bool _running
= false;
394 static void set_running(const bool arg
)
397 if ((error
= pthread_mutex_lock(&mutex
)) != 0)
399 fatal_message(strerror(error
));
404 if ((error
= pthread_mutex_unlock(&mutex
)) != 0)
406 fatal_message(strerror(error
));
410 static bool running()
415 if ((error
= pthread_mutex_lock(&mutex
)) != 0)
417 fatal_message(strerror(error
));
422 if ((error
= pthread_mutex_unlock(&mutex
)) != 0)
424 fatal_message(strerror(error
));
430 static void *worker_thread(void *ctx
)
432 memcached_pool_st
*pool
= (memcached_pool_st
*)ctx
;
436 memcached_return_t rc
;
437 memcached_st
*mc
= memcached_pool_pop(pool
, true, &rc
);
441 Error
<< "failed to fetch a connection from the pool" << memcached_strerror(NULL
, rc
);
446 rc
= memcached_set(mc
, "test:kv", 7, "value", 5, 600, 0);
447 if (memcached_failed(rc
))
449 Out
<< "failed memcached_set()";
452 rc
= memcached_pool_push(pool
, mc
);
453 if (memcached_failed(rc
))
455 Error
<< "failed to release a connection to the pool" << memcached_strerror(NULL
, rc
);
462 static void sig_handler(int sig
)
473 Error
<< __func__
<< " caught unknown signal";
478 #define NUM_THREADS 20
479 test_return_t
regression_bug_962815(memcached_st
*memc
)
481 test_skip_valgrind();
483 pthread_t pid
[NUM_THREADS
];
485 test_false(running());
487 memcached_st
*master
= create_single_instance_memcached(memc
, 0);
490 memcached_pool_st
*pool
= memcached_pool_create(master
, 5, 10);
496 struct itimerval new_value
;
497 struct itimerval old_value
;
498 memset(&new_value
, 0, sizeof(itimerval
));
499 memset(&old_value
, 0, sizeof(itimerval
));
501 new_value
.it_interval
.tv_sec
=0;
502 new_value
.it_interval
.tv_usec
=10*1000;
503 new_value
.it_value
.tv_sec
=0;
504 new_value
.it_value
.tv_usec
=10*1000;
506 test_true(signal(SIGPROF
, sig_handler
) != SIG_ERR
);
507 test_compare(0, setitimer(ITIMER_PROF
, &new_value
, &old_value
));
509 for (size_t x
=0; x
< NUM_THREADS
; x
++)
511 test_compare(0, pthread_create(&pid
[x
], NULL
, worker_thread
, (void*)pool
));
514 for (size_t x
=0; x
< NUM_THREADS
; x
++)
516 test_compare(0, pthread_join(pid
[x
], NULL
));
521 memcached_pool_destroy(pool
);
526 memcached_free(master
);
528 test_true(signal(SIGPROF
, SIG_DFL
) != SIG_ERR
);
529 test_compare(0, setitimer(ITIMER_PROF
, &old_value
, NULL
));