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.
38 #include "mem_config.h"
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.hpp"
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_t(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_t(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 FATAL_IF(resource
== NULL
);
248 // Release all of the memc we are holding
249 resource
->rc
= memcached_pool_release(resource
->pool
, resource
->mmc
);
255 test_return_t
connection_pool3_test(memcached_st
*memc
)
261 memcached_pool_st
* pool
= memcached_pool_create(memc
, 1, 1);
264 memcached_st
*pool_memc
;
266 memcached_return_t rc
;
267 pool_memc
= memcached_pool_fetch(pool
, NULL
, &rc
);
268 test_compare(MEMCACHED_SUCCESS
, rc
);
269 test_true(pool_memc
);
273 @note This comment was written to describe what was believed to be the original authors intent.
275 This portion of the test creates a thread that will wait until told to free a memcached_st
276 that will be grabbed by the main thread.
278 It is believed that this tests whether or not we are handling ownership correctly.
281 test_pool_context_st
item(pool
, pool_memc
);
283 test_zero(pthread_create(&tid
, NULL
, connection_release
, &item
));
286 memcached_return_t rc
;
287 memcached_st
*pop_memc
;
288 // We do a hard loop, and try N times
292 struct timespec relative_time
= { 0, 0 };
293 pop_memc
= memcached_pool_fetch(pool
, &relative_time
, &rc
);
295 if (memcached_success(rc
))
300 if (memcached_failed(rc
))
303 test_true(rc
!= MEMCACHED_TIMEOUT
); // As long as relative_time is zero, MEMCACHED_TIMEOUT is invalid
307 if (memcached_failed(rc
)) // Cleanup thread since we will exit once we test.
309 pthread_join(tid
, NULL
);
310 test_compare(MEMCACHED_SUCCESS
, rc
);
314 int pthread_ret
= pthread_join(tid
, NULL
);
315 test_true(pthread_ret
== 0 or pthread_ret
== ESRCH
);
317 test_compare(MEMCACHED_SUCCESS
, rc
);
318 test_true(pool_memc
== pop_memc
);
320 test_true(memcached_pool_destroy(pool
) == memc
);
325 static memcached_st
* create_single_instance_memcached(const memcached_st
*original_memc
, const char *options
)
328 If no options are given, copy over at least the binary flag.
330 char options_buffer
[1024]= { 0 };
333 if (memcached_is_binary(original_memc
))
335 snprintf(options_buffer
, sizeof(options_buffer
), "--BINARY");
340 * I only want to hit _one_ server so I know the number of requests I'm
341 * sending in the pipeline.
343 const memcached_instance_st
* instance
= memcached_server_instance_by_position(original_memc
, 0);
345 char server_string
[1024];
346 int server_string_length
;
347 if (instance
->type
== MEMCACHED_CONNECTION_UNIX_SOCKET
)
351 server_string_length
= snprintf(server_string
, sizeof(server_string
), "--SOCKET=\"%s\" %s",
352 memcached_server_name(instance
), options
);
356 server_string_length
= snprintf(server_string
, sizeof(server_string
), "--SOCKET=\"%s\"",
357 memcached_server_name(instance
));
364 server_string_length
= snprintf(server_string
, sizeof(server_string
), "--server=%s:%d %s",
365 memcached_server_name(instance
), int(memcached_server_port(instance
)),
370 server_string_length
= snprintf(server_string
, sizeof(server_string
), "--server=%s:%d",
371 memcached_server_name(instance
), int(memcached_server_port(instance
)));
375 if (server_string_length
<= 0)
380 char errror_buffer
[1024];
381 if (memcached_failed(libmemcached_check_configuration(server_string
, server_string_length
, errror_buffer
, sizeof(errror_buffer
))))
383 Error
<< "Failed to parse (" << server_string
<< ") " << errror_buffer
;
387 return memcached(server_string
, server_string_length
);
390 pthread_mutex_t mutex
= PTHREAD_MUTEX_INITIALIZER
;
391 static bool _running
= false;
393 static void set_running(const bool arg
)
396 FATAL_IF_((error
= pthread_mutex_lock(&mutex
)) != 0, strerror(error
));
400 FATAL_IF_((error
= pthread_mutex_unlock(&mutex
)) != 0, strerror(error
));
403 static bool running()
408 FATAL_IF_((error
= pthread_mutex_lock(&mutex
)) != 0, strerror(error
));
412 FATAL_IF_((error
= pthread_mutex_unlock(&mutex
)) != 0, strerror(error
));
417 static void *worker_thread(void *ctx
)
419 memcached_pool_st
*pool
= (memcached_pool_st
*)ctx
;
423 memcached_return_t rc
;
424 memcached_st
*mc
= memcached_pool_pop(pool
, true, &rc
);
428 Error
<< "failed to fetch a connection from the pool" << memcached_strerror(NULL
, rc
);
433 rc
= memcached_set(mc
, "test:kv", 7, "value", 5, 600, 0);
434 if (memcached_failed(rc
))
436 Out
<< "failed memcached_set()";
439 rc
= memcached_pool_push(pool
, mc
);
440 if (memcached_failed(rc
))
442 Error
<< "failed to release a connection to the pool" << memcached_strerror(NULL
, rc
);
449 #define NUM_THREADS 20
450 test_return_t
regression_bug_962815(memcached_st
*memc
)
452 pthread_t pid
[NUM_THREADS
];
454 test_false(running());
456 memcached_st
*master
= create_single_instance_memcached(memc
, 0);
459 memcached_pool_st
*pool
= memcached_pool_create(master
, 5, 10);
465 for (size_t x
=0; x
< NUM_THREADS
; x
++)
467 test_compare(0, pthread_create(&pid
[x
], NULL
, worker_thread
, (void*)pool
));
472 memset(fds
, 0, sizeof(pollfd
));
473 fds
[0].fd
= -1; //STDIN_FILENO;
474 fds
[0].events
= POLLIN
;
478 if ((active_fd
= poll(fds
, 1, 5000)) == -1)
480 Error
<< "poll() failed with:" << strerror(errno
);
482 test_zero(active_fd
);
487 for (size_t x
=0; x
< NUM_THREADS
; x
++)
489 test_compare(0, pthread_join(pid
[x
], NULL
));
492 memcached_pool_destroy(pool
);
494 memcached_free(master
);