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>
58 #include "libmemcached/instance.h"
60 #ifndef __INTEL_COMPILER
61 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
65 test_return_t
memcached_pool_test(memcached_st
*)
67 const char *config_string
= "--SERVER=host10.example.com --SERVER=host11.example.com --SERVER=host10.example.com --POOL-MIN=10 --POOL-MAX=32";
71 test_compare(libmemcached_check_configuration(config_string
, sizeof(config_string
) -1, buffer
, sizeof(buffer
)), MEMCACHED_PARSE_ERROR
);
73 memcached_pool_st
* pool
= memcached_pool(config_string
, strlen(config_string
));
76 memcached_return_t rc
;
77 memcached_st
*memc
= memcached_pool_pop(pool
, false, &rc
);
79 test_compare(rc
, MEMCACHED_SUCCESS
);
83 Release the memc_ptr that was pulled from the pool
85 memcached_pool_push(pool
, memc
);
90 memcached_pool_destroy(pool
);
97 test_return_t
connection_pool_test(memcached_st
*memc
)
99 memcached_pool_st
* pool
= memcached_pool_create(memc
, 5, POOL_SIZE
);
101 memcached_st
*mmc
[POOL_SIZE
];
103 // Fill up our array that we will store the memc that are in the pool
104 for (size_t x
= 0; x
< POOL_SIZE
; ++x
)
106 memcached_return_t rc
;
107 mmc
[x
]= memcached_pool_fetch(pool
, NULL
, &rc
);
108 test_compare(MEMCACHED_SUCCESS
, rc
);
112 // All memc should be gone
114 memcached_return_t rc
;
115 test_null(memcached_pool_fetch(pool
, NULL
, &rc
));
116 test_compare(MEMCACHED_NOTFOUND
, rc
);
120 for (size_t x
= 0; x
< POOL_SIZE
; ++x
)
124 test_compare(MEMCACHED_SUCCESS
, memcached_pool_release(pool
, mmc
[x
]));
127 test_true(memcached_pool_destroy(pool
) == memc
);
132 test_return_t
connection_pool2_test(memcached_st
*memc
)
134 memcached_pool_st
* pool
= memcached_pool_create(memc
, 5, POOL_SIZE
);
136 memcached_st
*mmc
[POOL_SIZE
];
138 // Fill up our array that we will store the memc that are in the pool
139 for (size_t x
= 0; x
< POOL_SIZE
; ++x
)
141 memcached_return_t rc
;
142 mmc
[x
]= memcached_pool_fetch(pool
, NULL
, &rc
);
143 test_compare(MEMCACHED_SUCCESS
, rc
);
147 // All memc should be gone
149 memcached_return_t rc
;
150 test_null(memcached_pool_fetch(pool
, NULL
, &rc
));
151 test_compare(MEMCACHED_NOTFOUND
, rc
);
154 // verify that I can do ops with all connections
155 test_compare(MEMCACHED_SUCCESS
,
156 memcached_set(mmc
[0],
157 test_literal_param("key"),
160 for (uint64_t x
= 0; x
< POOL_SIZE
; ++x
)
162 uint64_t number_value
;
163 test_compare(MEMCACHED_SUCCESS
,
164 memcached_increment(mmc
[x
],
165 test_literal_param("key"),
167 test_compare(number_value
, (x
+1));
171 for (size_t x
= 0; x
< POOL_SIZE
; ++x
)
173 test_compare(MEMCACHED_SUCCESS
, memcached_pool_release(pool
, mmc
[x
]));
177 /* verify that I can set behaviors on the pool when I don't have all
178 * of the connections in the pool. It should however be enabled
179 * when I push the item into the pool
181 mmc
[0]= memcached_pool_fetch(pool
, NULL
, NULL
);
184 test_compare(MEMCACHED_SUCCESS
,
185 memcached_pool_behavior_set(pool
, MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK
, 9999));
188 memcached_return_t rc
;
189 mmc
[1]= memcached_pool_fetch(pool
, NULL
, &rc
);
191 test_compare(MEMCACHED_SUCCESS
, rc
);
194 test_compare(UINT64_C(9999), memcached_behavior_get(mmc
[1], MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK
));
195 test_compare(MEMCACHED_SUCCESS
, memcached_pool_release(pool
, mmc
[1]));
196 test_compare(MEMCACHED_SUCCESS
, memcached_pool_release(pool
, mmc
[0]));
199 memcached_return_t rc
;
200 mmc
[0]= memcached_pool_fetch(pool
, NULL
, &rc
);
202 test_compare(MEMCACHED_SUCCESS
, rc
);
205 test_compare(UINT64_C(9999), memcached_behavior_get(mmc
[0], MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK
));
206 test_compare(MEMCACHED_SUCCESS
, memcached_pool_release(pool
, mmc
[0]));
208 test_true(memcached_pool_destroy(pool
) == memc
);
213 struct test_pool_context_st
{
214 volatile memcached_return_t rc
;
215 memcached_pool_st
* pool
;
219 test_pool_context_st(memcached_pool_st
*pool_arg
, memcached_st
*memc_arg
):
220 rc(MEMCACHED_FAILURE
),
224 sem_init(&_lock
, 0, 0);
237 ~test_pool_context_st()
243 static __attribute__((noreturn
)) void* connection_release(void *arg
)
245 test_pool_context_st
*resource
= static_cast<test_pool_context_st
*>(arg
);
246 if (resource
== NULL
)
248 fatal_message("resource == NULL");
251 // Release all of the memc we are holding
252 resource
->rc
= memcached_pool_release(resource
->pool
, resource
->mmc
);
258 test_return_t
connection_pool3_test(memcached_st
*memc
)
264 memcached_pool_st
* pool
= memcached_pool_create(memc
, 1, 1);
267 memcached_st
*pool_memc
;
269 memcached_return_t rc
;
270 pool_memc
= memcached_pool_fetch(pool
, NULL
, &rc
);
271 test_compare(MEMCACHED_SUCCESS
, rc
);
272 test_true(pool_memc
);
276 @note This comment was written to describe what was believed to be the original authors intent.
278 This portion of the test creates a thread that will wait until told to free a memcached_st
279 that will be grabbed by the main thread.
281 It is believed that this tests whether or not we are handling ownership correctly.
284 test_pool_context_st
item(pool
, pool_memc
);
286 test_zero(pthread_create(&tid
, NULL
, connection_release
, &item
));
289 memcached_return_t rc
;
290 memcached_st
*pop_memc
;
291 // We do a hard loop, and try N times
295 struct timespec relative_time
= { 0, 0 };
296 pop_memc
= memcached_pool_fetch(pool
, &relative_time
, &rc
);
298 if (memcached_success(rc
))
303 if (memcached_failed(rc
))
306 test_true(rc
!= MEMCACHED_TIMEOUT
); // As long as relative_time is zero, MEMCACHED_TIMEOUT is invalid
310 if (memcached_failed(rc
)) // Cleanup thread since we will exit once we test.
312 pthread_join(tid
, NULL
);
313 test_compare(MEMCACHED_SUCCESS
, rc
);
317 int pthread_ret
= pthread_join(tid
, NULL
);
318 test_true(pthread_ret
== 0 or pthread_ret
== ESRCH
);
320 test_compare(MEMCACHED_SUCCESS
, rc
);
321 test_true(pool_memc
== pop_memc
);
323 test_true(memcached_pool_destroy(pool
) == memc
);
328 static memcached_st
* create_single_instance_memcached(const memcached_st
*original_memc
, const char *options
)
331 If no options are given, copy over at least the binary flag.
333 char options_buffer
[1024]= { 0 };
336 if (memcached_is_binary(original_memc
))
338 snprintf(options_buffer
, sizeof(options_buffer
), "--BINARY");
343 * I only want to hit _one_ server so I know the number of requests I'm
344 * sending in the pipeline.
346 memcached_server_instance_st instance
= memcached_server_instance_by_position(original_memc
, 0);
348 char server_string
[1024];
349 int server_string_length
;
350 if (instance
->type
== MEMCACHED_CONNECTION_UNIX_SOCKET
)
354 server_string_length
= snprintf(server_string
, sizeof(server_string
), "--SOCKET=\"%s\" %s",
355 memcached_server_name(instance
), options
);
359 server_string_length
= snprintf(server_string
, sizeof(server_string
), "--SOCKET=\"%s\"",
360 memcached_server_name(instance
));
367 server_string_length
= snprintf(server_string
, sizeof(server_string
), "--server=%s:%d %s",
368 memcached_server_name(instance
), int(memcached_server_port(instance
)),
373 server_string_length
= snprintf(server_string
, sizeof(server_string
), "--server=%s:%d",
374 memcached_server_name(instance
), int(memcached_server_port(instance
)));
378 if (server_string_length
<= 0)
383 char errror_buffer
[1024];
384 if (memcached_failed(libmemcached_check_configuration(server_string
, server_string_length
, errror_buffer
, sizeof(errror_buffer
))))
386 Error
<< "Failed to parse (" << server_string
<< ") " << errror_buffer
;
390 return memcached(server_string
, server_string_length
);
393 pthread_mutex_t mutex
= PTHREAD_MUTEX_INITIALIZER
;
394 static bool _running
= false;
396 static void set_running(const bool arg
)
399 if ((error
= pthread_mutex_lock(&mutex
)) != 0)
401 fatal_message(strerror(error
));
406 if ((error
= pthread_mutex_unlock(&mutex
)) != 0)
408 fatal_message(strerror(error
));
412 static bool running()
417 if ((error
= pthread_mutex_lock(&mutex
)) != 0)
419 fatal_message(strerror(error
));
424 if ((error
= pthread_mutex_unlock(&mutex
)) != 0)
426 fatal_message(strerror(error
));
432 static void *worker_thread(void *ctx
)
434 memcached_pool_st
*pool
= (memcached_pool_st
*)ctx
;
438 memcached_return_t rc
;
439 memcached_st
*mc
= memcached_pool_pop(pool
, true, &rc
);
443 Error
<< "failed to fetch a connection from the pool" << memcached_strerror(NULL
, rc
);
448 rc
= memcached_set(mc
, "test:kv", 7, "value", 5, 600, 0);
449 if (memcached_failed(rc
))
451 Out
<< "failed memcached_set()";
454 rc
= memcached_pool_push(pool
, mc
);
455 if (memcached_failed(rc
))
457 Error
<< "failed to release a connection to the pool" << memcached_strerror(NULL
, rc
);
464 #define NUM_THREADS 20
465 test_return_t
regression_bug_962815(memcached_st
*memc
)
467 pthread_t pid
[NUM_THREADS
];
469 test_false(running());
471 memcached_st
*master
= create_single_instance_memcached(memc
, 0);
474 memcached_pool_st
*pool
= memcached_pool_create(master
, 5, 10);
480 for (size_t x
=0; x
< NUM_THREADS
; x
++)
482 test_compare(0, pthread_create(&pid
[x
], NULL
, worker_thread
, (void*)pool
));
487 memset(fds
, 0, sizeof(pollfd
));
488 fds
[0].fd
= -1; //STDIN_FILENO;
489 fds
[0].events
= POLLIN
;
493 if ((active_fd
= poll(fds
, 1, 5000)) == -1)
495 Error
<< "poll() failed with:" << strerror(errno
);
497 test_zero(active_fd
);
502 for (size_t x
=0; x
< NUM_THREADS
; x
++)
504 test_compare(0, pthread_join(pid
[x
], NULL
));
509 memcached_pool_destroy(pool
);
514 memcached_free(master
);