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 memcached_return_t rc
;
68 const char *config_string
= "--SERVER=host10.example.com --SERVER=host11.example.com --SERVER=host10.example.com --POOL-MIN=10 --POOL-MAX=32";
71 rc
= libmemcached_check_configuration(config_string
, sizeof(config_string
) -1, buffer
, sizeof(buffer
));
73 test_true_got(rc
!= MEMCACHED_SUCCESS
, buffer
);
75 memcached_pool_st
* pool
= memcached_pool(config_string
, strlen(config_string
));
76 test_true_got(pool
, strerror(errno
));
78 memcached_st
*memc
= memcached_pool_pop(pool
, false, &rc
);
80 test_true(rc
== MEMCACHED_SUCCESS
);
84 Release the memc_ptr that was pulled from the pool
86 memcached_pool_push(pool
, memc
);
91 memcached_pool_destroy(pool
);
98 test_return_t
connection_pool_test(memcached_st
*memc
)
100 memcached_pool_st
* pool
= memcached_pool_create(memc
, 5, POOL_SIZE
);
102 memcached_st
*mmc
[POOL_SIZE
];
104 // Fill up our array that we will store the memc that are in the pool
105 for (size_t x
= 0; x
< POOL_SIZE
; ++x
)
107 memcached_return_t rc
;
108 mmc
[x
]= memcached_pool_fetch(pool
, NULL
, &rc
);
109 test_compare(MEMCACHED_SUCCESS
, rc
);
113 // All memc should be gone
115 memcached_return_t rc
;
116 test_null(memcached_pool_fetch(pool
, NULL
, &rc
));
117 test_compare(MEMCACHED_NOTFOUND
, rc
);
121 for (size_t x
= 0; x
< POOL_SIZE
; ++x
)
125 test_compare(MEMCACHED_SUCCESS
, memcached_pool_release(pool
, mmc
[x
]));
128 test_true(memcached_pool_destroy(pool
) == memc
);
133 test_return_t
connection_pool2_test(memcached_st
*memc
)
135 memcached_pool_st
* pool
= memcached_pool_create(memc
, 5, POOL_SIZE
);
137 memcached_st
*mmc
[POOL_SIZE
];
139 // Fill up our array that we will store the memc that are in the pool
140 for (size_t x
= 0; x
< POOL_SIZE
; ++x
)
142 memcached_return_t rc
;
143 mmc
[x
]= memcached_pool_fetch(pool
, NULL
, &rc
);
144 test_compare(MEMCACHED_SUCCESS
, rc
);
148 // All memc should be gone
150 memcached_return_t rc
;
151 test_null(memcached_pool_fetch(pool
, NULL
, &rc
));
152 test_compare(MEMCACHED_NOTFOUND
, rc
);
155 // verify that I can do ops with all connections
156 test_compare(MEMCACHED_SUCCESS
,
157 memcached_set(mmc
[0],
158 test_literal_param("key"),
161 for (uint64_t x
= 0; x
< POOL_SIZE
; ++x
)
163 uint64_t number_value
;
164 test_compare(MEMCACHED_SUCCESS
,
165 memcached_increment(mmc
[x
],
166 test_literal_param("key"),
168 test_compare(number_value
, (x
+1));
172 for (size_t x
= 0; x
< POOL_SIZE
; ++x
)
174 test_compare(MEMCACHED_SUCCESS
, memcached_pool_release(pool
, mmc
[x
]));
178 /* verify that I can set behaviors on the pool when I don't have all
179 * of the connections in the pool. It should however be enabled
180 * when I push the item into the pool
182 mmc
[0]= memcached_pool_fetch(pool
, NULL
, NULL
);
185 test_compare(MEMCACHED_SUCCESS
,
186 memcached_pool_behavior_set(pool
, MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK
, 9999));
189 memcached_return_t rc
;
190 mmc
[1]= memcached_pool_fetch(pool
, NULL
, &rc
);
192 test_compare(MEMCACHED_SUCCESS
, rc
);
195 test_compare(UINT64_C(9999), memcached_behavior_get(mmc
[1], MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK
));
196 test_compare(MEMCACHED_SUCCESS
, memcached_pool_release(pool
, mmc
[1]));
197 test_compare(MEMCACHED_SUCCESS
, memcached_pool_release(pool
, mmc
[0]));
200 memcached_return_t rc
;
201 mmc
[0]= memcached_pool_fetch(pool
, NULL
, &rc
);
203 test_compare(MEMCACHED_SUCCESS
, rc
);
206 test_compare(UINT64_C(9999), memcached_behavior_get(mmc
[0], MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK
));
207 test_compare(MEMCACHED_SUCCESS
, memcached_pool_release(pool
, mmc
[0]));
209 test_true(memcached_pool_destroy(pool
) == memc
);
214 struct test_pool_context_st
{
215 volatile memcached_return_t rc
;
216 memcached_pool_st
* pool
;
220 test_pool_context_st(memcached_pool_st
*pool_arg
, memcached_st
*memc_arg
):
221 rc(MEMCACHED_FAILURE
),
225 sem_init(&_lock
, 0, 0);
238 ~test_pool_context_st()
244 static void* connection_release(void *arg
)
246 test_pool_context_st
*resource
= static_cast<test_pool_context_st
*>(arg
);
247 if (resource
== NULL
)
249 fatal_message("resource == NULL");
252 // Release all of the memc we are holding
253 resource
->rc
= memcached_pool_release(resource
->pool
, resource
->mmc
);
259 test_return_t
connection_pool3_test(memcached_st
*memc
)
265 memcached_pool_st
* pool
= memcached_pool_create(memc
, 1, 1);
268 memcached_st
*pool_memc
;
270 memcached_return_t rc
;
271 pool_memc
= memcached_pool_fetch(pool
, NULL
, &rc
);
272 test_compare(MEMCACHED_SUCCESS
, rc
);
273 test_true(pool_memc
);
277 @note This comment was written to describe what was believed to be the original authors intent.
279 This portion of the test creates a thread that will wait until told to free a memcached_st
280 that will be grabbed by the main thread.
282 It is believed that this tests whether or not we are handling ownership correctly.
285 test_pool_context_st
item(pool
, pool_memc
);
287 test_zero(pthread_create(&tid
, NULL
, connection_release
, &item
));
290 memcached_return_t rc
;
291 memcached_st
*pop_memc
;
292 // We do a hard loop, and try N times
296 struct timespec relative_time
= { 0, 0 };
297 pop_memc
= memcached_pool_fetch(pool
, &relative_time
, &rc
);
299 if (memcached_success(rc
))
304 if (memcached_failed(rc
))
307 test_true(rc
!= MEMCACHED_TIMEOUT
); // As long as relative_time is zero, MEMCACHED_TIMEOUT is invalid
311 if (memcached_failed(rc
)) // Cleanup thread since we will exit once we test.
313 pthread_join(tid
, NULL
);
314 test_compare(MEMCACHED_SUCCESS
, rc
);
318 int pthread_ret
= pthread_join(tid
, NULL
);
319 test_true(pthread_ret
== 0 or pthread_ret
== ESRCH
);
321 test_compare(MEMCACHED_SUCCESS
, rc
);
322 test_true(pool_memc
== pop_memc
);
324 test_true(memcached_pool_destroy(pool
) == memc
);
329 static memcached_st
* create_single_instance_memcached(const memcached_st
*original_memc
, const char *options
)
332 If no options are given, copy over at least the binary flag.
334 char options_buffer
[1024]= { 0 };
337 if (memcached_is_binary(original_memc
))
339 snprintf(options_buffer
, sizeof(options_buffer
), "--BINARY");
344 * I only want to hit _one_ server so I know the number of requests I'm
345 * sending in the pipeline.
347 memcached_server_instance_st instance
= memcached_server_instance_by_position(original_memc
, 0);
349 char server_string
[1024];
350 int server_string_length
;
351 if (instance
->type
== MEMCACHED_CONNECTION_UNIX_SOCKET
)
355 server_string_length
= snprintf(server_string
, sizeof(server_string
), "--SOCKET=\"%s\" %s",
356 memcached_server_name(instance
), options
);
360 server_string_length
= snprintf(server_string
, sizeof(server_string
), "--SOCKET=\"%s\"",
361 memcached_server_name(instance
));
368 server_string_length
= snprintf(server_string
, sizeof(server_string
), "--server=%s:%d %s",
369 memcached_server_name(instance
), int(memcached_server_port(instance
)),
374 server_string_length
= snprintf(server_string
, sizeof(server_string
), "--server=%s:%d",
375 memcached_server_name(instance
), int(memcached_server_port(instance
)));
379 if (server_string_length
<= 0)
384 char errror_buffer
[1024];
385 if (memcached_failed(libmemcached_check_configuration(server_string
, server_string_length
, errror_buffer
, sizeof(errror_buffer
))))
387 Error
<< "Failed to parse (" << server_string
<< ") " << errror_buffer
;
391 return memcached(server_string
, server_string_length
);
394 pthread_mutex_t mutex
= PTHREAD_MUTEX_INITIALIZER
;
395 static bool _running
= false;
397 static void set_running(const bool arg
)
400 if ((error
= pthread_mutex_lock(&mutex
)) != 0)
402 fatal_message(strerror(error
));
407 if ((error
= pthread_mutex_unlock(&mutex
)) != 0)
409 fatal_message(strerror(error
));
413 static bool running()
418 if ((error
= pthread_mutex_lock(&mutex
)) != 0)
420 fatal_message(strerror(error
));
425 if ((error
= pthread_mutex_unlock(&mutex
)) != 0)
427 fatal_message(strerror(error
));
433 static void *worker_thread(void *ctx
)
435 memcached_pool_st
*pool
= (memcached_pool_st
*)ctx
;
439 memcached_return_t rc
;
440 memcached_st
*mc
= memcached_pool_pop(pool
, true, &rc
);
444 Error
<< "failed to fetch a connection from the pool" << memcached_strerror(NULL
, rc
);
449 rc
= memcached_set(mc
, "test:kv", 7, "value", 5, 600, 0);
450 if (memcached_failed(rc
))
452 Out
<< "failed memcached_set()";
455 rc
= memcached_pool_push(pool
, mc
);
456 if (memcached_failed(rc
))
458 Error
<< "failed to release a connection to the pool" << memcached_strerror(NULL
, rc
);
465 #define NUM_THREADS 20
466 test_return_t
regression_bug_962815(memcached_st
*memc
)
468 pthread_t pid
[NUM_THREADS
];
470 test_false(running());
472 memcached_st
*master
= create_single_instance_memcached(memc
, 0);
475 memcached_pool_st
*pool
= memcached_pool_create(master
, 5, 10);
481 for (size_t x
=0; x
< NUM_THREADS
; x
++)
483 test_compare(0, pthread_create(&pid
[x
], NULL
, worker_thread
, (void*)pool
));
488 memset(fds
, 0, sizeof(pollfd
));
489 fds
[0].fd
= -1; //STDIN_FILENO;
490 fds
[0].events
= POLLIN
;
494 if ((active_fd
= poll(fds
, 1, 5000)) == -1)
496 Error
<< "poll() failed with:" << strerror(errno
);
498 test_zero(active_fd
);
503 for (size_t x
=0; x
< NUM_THREADS
; x
++)
505 test_compare(0, pthread_join(pid
[x
], NULL
));
510 memcached_pool_destroy(pool
);
515 memcached_free(master
);