Merge in build trunk.
[awesomized/libmemcached] / tests / libmemcached-1.0 / pool.cc
1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * Libmemcached Client and Server
4 *
5 * Copyright (C) 2011 Data Differential, http://datadifferential.com/
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
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
18 * distribution.
19 *
20 * * The names of its contributors may not be used to endorse or
21 * promote products derived from this software without specific prior
22 * written permission.
23 *
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.
35 *
36 */
37
38 #include <config.h>
39 #include <libtest/test.hpp>
40
41 using namespace libtest;
42
43 #include <vector>
44 #include <iostream>
45 #include <string>
46 #include <cerrno>
47
48 #include <semaphore.h>
49
50 #include <libmemcached/memcached.h>
51 #include <libmemcached/util.h>
52 #include <tests/pool.h>
53
54 #ifndef __INTEL_COMPILER
55 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
56 #endif
57
58
59 test_return_t memcached_pool_test(memcached_st *)
60 {
61 memcached_return_t rc;
62 const char *config_string= "--SERVER=host10.example.com --SERVER=host11.example.com --SERVER=host10.example.com --POOL-MIN=10 --POOL-MAX=32";
63
64 char buffer[2048];
65 rc= libmemcached_check_configuration(config_string, sizeof(config_string) -1, buffer, sizeof(buffer));
66
67 test_true_got(rc != MEMCACHED_SUCCESS, buffer);
68
69 memcached_pool_st* pool= memcached_pool(config_string, strlen(config_string));
70 test_true_got(pool, strerror(errno));
71
72 memcached_st *memc= memcached_pool_pop(pool, false, &rc);
73
74 test_true(rc == MEMCACHED_SUCCESS);
75 test_true(memc);
76
77 /*
78 Release the memc_ptr that was pulled from the pool
79 */
80 memcached_pool_push(pool, memc);
81
82 /*
83 Destroy the pool.
84 */
85 memcached_pool_destroy(pool);
86
87 return TEST_SUCCESS;
88 }
89
90
91 #define POOL_SIZE 10
92 test_return_t connection_pool_test(memcached_st *memc)
93 {
94 memcached_pool_st* pool= memcached_pool_create(memc, 5, POOL_SIZE);
95 test_true(pool);
96 memcached_st *mmc[POOL_SIZE];
97
98 // Fill up our array that we will store the memc that are in the pool
99 for (size_t x= 0; x < POOL_SIZE; ++x)
100 {
101 memcached_return_t rc;
102 mmc[x]= memcached_pool_fetch(pool, NULL, &rc);
103 test_compare(MEMCACHED_SUCCESS, rc);
104 test_true(mmc[x]);
105 }
106
107 // All memc should be gone
108 {
109 memcached_return_t rc;
110 test_null(memcached_pool_fetch(pool, NULL, &rc));
111 test_compare(MEMCACHED_NOTFOUND, rc);
112 }
113
114 // Release them..
115 for (size_t x= 0; x < POOL_SIZE; ++x)
116 {
117 if (mmc[x])
118 {
119 test_compare(MEMCACHED_SUCCESS, memcached_pool_release(pool, mmc[x]));
120 }
121 }
122 test_true(memcached_pool_destroy(pool) == memc);
123
124 return TEST_SUCCESS;
125 }
126
127 test_return_t connection_pool2_test(memcached_st *memc)
128 {
129 memcached_pool_st* pool= memcached_pool_create(memc, 5, POOL_SIZE);
130 test_true(pool);
131 memcached_st *mmc[POOL_SIZE];
132
133 // Fill up our array that we will store the memc that are in the pool
134 for (size_t x= 0; x < POOL_SIZE; ++x)
135 {
136 memcached_return_t rc;
137 mmc[x]= memcached_pool_fetch(pool, NULL, &rc);
138 test_compare(MEMCACHED_SUCCESS, rc);
139 test_true(mmc[x]);
140 }
141
142 // All memc should be gone
143 {
144 memcached_return_t rc;
145 test_null(memcached_pool_fetch(pool, NULL, &rc));
146 test_compare(MEMCACHED_NOTFOUND, rc);
147 }
148
149 // verify that I can do ops with all connections
150 test_compare(MEMCACHED_SUCCESS,
151 memcached_set(mmc[0],
152 test_literal_param("key"),
153 "0", 1, 0, 0));
154
155 for (uint64_t x= 0; x < POOL_SIZE; ++x)
156 {
157 uint64_t number_value;
158 test_compare(MEMCACHED_SUCCESS,
159 memcached_increment(mmc[x],
160 test_literal_param("key"),
161 1, &number_value));
162 test_compare(number_value, (x+1));
163 }
164
165 // Release them..
166 for (size_t x= 0; x < POOL_SIZE; ++x)
167 {
168 test_compare(MEMCACHED_SUCCESS, memcached_pool_release(pool, mmc[x]));
169 }
170
171
172 /* verify that I can set behaviors on the pool when I don't have all
173 * of the connections in the pool. It should however be enabled
174 * when I push the item into the pool
175 */
176 mmc[0]= memcached_pool_fetch(pool, NULL, NULL);
177 test_true(mmc[0]);
178
179 test_compare(MEMCACHED_SUCCESS,
180 memcached_pool_behavior_set(pool, MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK, 9999));
181
182 {
183 memcached_return_t rc;
184 mmc[1]= memcached_pool_fetch(pool, NULL, &rc);
185 test_true(mmc[1]);
186 test_compare(MEMCACHED_SUCCESS, rc);
187 }
188
189 test_compare(UINT64_C(9999), memcached_behavior_get(mmc[1], MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK));
190 test_compare(MEMCACHED_SUCCESS, memcached_pool_release(pool, mmc[1]));
191 test_compare(MEMCACHED_SUCCESS, memcached_pool_release(pool, mmc[0]));
192
193 {
194 memcached_return_t rc;
195 mmc[0]= memcached_pool_fetch(pool, NULL, &rc);
196 test_true(mmc[0]);
197 test_compare(MEMCACHED_SUCCESS, rc);
198 }
199
200 test_compare(UINT64_C(9999), memcached_behavior_get(mmc[0], MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK));
201 test_compare(MEMCACHED_SUCCESS, memcached_pool_release(pool, mmc[0]));
202
203 test_true(memcached_pool_destroy(pool) == memc);
204
205 return TEST_SUCCESS;
206 }
207
208 struct test_pool_context_st {
209 volatile memcached_return_t rc;
210 memcached_pool_st* pool;
211 memcached_st* mmc;
212 sem_t _lock;
213
214 test_pool_context_st(memcached_pool_st *pool_arg, memcached_st *memc_arg):
215 rc(MEMCACHED_FAILURE),
216 pool(pool_arg),
217 mmc(memc_arg)
218 {
219 sem_init(&_lock, 0, 0);
220 }
221
222 void wait()
223 {
224 sem_wait(&_lock);
225 }
226
227 void release()
228 {
229 sem_post(&_lock);
230 }
231
232 ~test_pool_context_st()
233 {
234 sem_destroy(&_lock);
235 }
236 };
237
238 static void* connection_release(void *arg)
239 {
240 test_pool_context_st *resource= static_cast<test_pool_context_st *>(arg);
241 if (resource == NULL)
242 {
243 fatal_message("resource == NULL");
244 }
245
246 // Release all of the memc we are holding
247 resource->rc= memcached_pool_release(resource->pool, resource->mmc);
248 resource->release();
249
250 pthread_exit(arg);
251 }
252
253 test_return_t connection_pool3_test(memcached_st *memc)
254 {
255 #ifdef __APPLE__
256 return TEST_SKIPPED;
257 #endif
258
259 memcached_pool_st* pool= memcached_pool_create(memc, 1, 1);
260 test_true(pool);
261
262 memcached_st *pool_memc;
263 {
264 memcached_return_t rc;
265 pool_memc= memcached_pool_fetch(pool, NULL, &rc);
266 test_compare(MEMCACHED_SUCCESS, rc);
267 test_true(pool_memc);
268 }
269
270 /*
271 @note This comment was written to describe what was believed to be the original authors intent.
272
273 This portion of the test creates a thread that will wait until told to free a memcached_st
274 that will be grabbed by the main thread.
275
276 It is believed that this tests whether or not we are handling ownership correctly.
277 */
278 pthread_t tid;
279 test_pool_context_st item(pool, pool_memc);
280
281 test_zero(pthread_create(&tid, NULL, connection_release, &item));
282 item.wait();
283
284 memcached_return_t rc;
285 memcached_st *pop_memc;
286 // We do a hard loop, and try N times
287 int counter= 5;
288 do
289 {
290 struct timespec relative_time= { 0, 0 };
291 pop_memc= memcached_pool_fetch(pool, &relative_time, &rc);
292
293 if (memcached_success(rc))
294 {
295 break;
296 }
297
298 if (memcached_failed(rc))
299 {
300 test_null(pop_memc);
301 test_true(rc != MEMCACHED_TIMEOUT); // As long as relative_time is zero, MEMCACHED_TIMEOUT is invalid
302 }
303 } while (--counter);
304
305 if (memcached_failed(rc)) // Cleanup thread since we will exit once we test.
306 {
307 pthread_join(tid, NULL);
308 test_compare(MEMCACHED_SUCCESS, rc);
309 }
310
311 {
312 int pthread_ret= pthread_join(tid, NULL);
313 test_true(pthread_ret == 0 or pthread_ret == ESRCH);
314 }
315 test_compare(MEMCACHED_SUCCESS, rc);
316 test_true(pool_memc == pop_memc);
317
318 test_true(memcached_pool_destroy(pool) == memc);
319
320 return TEST_SUCCESS;
321 }