1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3 * Libmemcached client and server library.
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
;
43 #include "libmemcached-1.0/memcached.h"
45 #include "libmemcached/server_instance.h"
47 #include "tests/replication.h"
48 #include "tests/debug.h"
50 #include "tests/libmemcached-1.0/setup_and_teardowns.h"
52 test_return_t
check_replication_sanity_TEST(memcached_st
*memc
)
55 test_compare(uint64_t(1),
56 memcached_behavior_get(memc
, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL
));
59 * Make sure that we store the item on all servers
60 * (master + replicas == number of servers)
62 test_compare(memcached_behavior_get(memc
, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS
), uint64_t(memcached_server_count(memc
) - 1));
67 test_return_t
replication_set_test(memcached_st
*memc
)
69 memcached_st
*memc_clone
= memcached_clone(NULL
, memc
);
70 test_true(memc_clone
);
71 test_compare(MEMCACHED_SUCCESS
,
72 memcached_behavior_set(memc_clone
, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS
, 0));
74 test_compare(MEMCACHED_SUCCESS
,
75 memcached_set(memc
, "bubba", 5, "0", 1, 0, 0));
78 ** We are using the quiet commands to store the replicas, so we need
79 ** to ensure that all of them are processed before we can continue.
80 ** In the test we go directly from storing the object to trying to
81 ** receive the object from all of the different servers, so we
82 ** could end up in a race condition (the memcached server hasn't yet
83 ** processed the quiet command from the replication set when it process
84 ** the request from the other client (created by the clone)). As a
85 ** workaround for that we call memcached_quit to send the quit command
86 ** to the server and wait for the response ;-) If you use the test code
87 ** as an example for your own code, please note that you shouldn't need
93 ** "bubba" should now be stored on all of our servers. We don't have an
94 ** easy to use API to address each individual server, so I'll just iterate
95 ** through a bunch of "master keys" and I should most likely hit all of the
98 for (int x
= 'a'; x
<= 'z'; ++x
)
100 const char key
[2]= { (char)x
, 0 };
103 memcached_return_t rc
;
104 char *val
= memcached_get_by_key(memc_clone
, key
, 1, "bubba", 5,
106 test_compare(MEMCACHED_SUCCESS
, rc
);
111 memcached_free(memc_clone
);
116 #include "libmemcached/instance.hpp"
118 test_return_t
replication_get_test(memcached_st
*memc
)
122 * Don't do the following in your code. I am abusing the internal details
123 * within the library, and this is not a supported interface.
124 * This is to verify correct behavior in the library
126 for (uint32_t host
= 0; host
< memcached_server_count(memc
); ++host
)
128 memcached_st
*memc_clone
= memcached_clone(NULL
, memc
);
129 memcached_instance_st
* instance
= (memcached_instance_st
*)memcached_server_instance_by_position(memc_clone
, host
);
133 for (int x
= 'a'; x
<= 'z'; ++x
)
135 const char key
[2]= { (char)x
, 0 };
138 memcached_return_t rc
;
139 char *val
= memcached_get_by_key(memc_clone
, key
, 1, "bubba", 5,
141 test_compare(MEMCACHED_SUCCESS
, rc
);
146 memcached_free(memc_clone
);
152 test_return_t
replication_mget_test(memcached_st
*memc
)
154 memcached_st
*memc_clone
= memcached_clone(NULL
, memc
);
155 test_true(memc_clone
);
156 test_compare(MEMCACHED_SUCCESS
,
157 memcached_behavior_set(memc_clone
, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS
, 0));
159 const char *keys
[]= { "bubba", "key1", "key2", "key3" };
160 size_t len
[]= { 5, 4, 4, 4 };
162 for (size_t x
= 0; x
< 4; ++x
)
164 test_compare(MEMCACHED_SUCCESS
, memcached_set(memc
, keys
[x
], len
[x
], "0", 1, 0, 0));
168 ** We are using the quiet commands to store the replicas, so we need
169 ** to ensure that all of them are processed before we can continue.
170 ** In the test we go directly from storing the object to trying to
171 ** receive the object from all of the different servers, so we
172 ** could end up in a race condition (the memcached server hasn't yet
173 ** processed the quiet command from the replication set when it process
174 ** the request from the other client (created by the clone)). As a
175 ** workaround for that we call memcached_quit to send the quit command
176 ** to the server and wait for the response ;-) If you use the test code
177 ** as an example for your own code, please note that you shouldn't need
180 memcached_quit(memc
);
183 * Don't do the following in your code. I am abusing the internal details
184 * within the library, and this is not a supported interface.
185 * This is to verify correct behavior in the library
187 memcached_result_st result_obj
;
188 for (uint32_t host
= 0; host
< memcached_server_count(memc_clone
); host
++)
190 memcached_st
*new_clone
= memcached_clone(NULL
, memc
);
191 const memcached_instance_st
* instance
= memcached_server_instance_by_position(new_clone
, host
);
192 ((memcached_server_write_instance_st
)instance
)->port(0);
194 for (int x
= 'a'; x
<= 'z'; ++x
)
196 char key
[2]= { (char)x
, 0 };
198 test_compare(MEMCACHED_SUCCESS
,
199 memcached_mget_by_key(new_clone
, key
, 1, keys
, len
, 4));
201 memcached_result_st
*results
= memcached_result_create(new_clone
, &result_obj
);
205 memcached_return_t rc
;
206 while ((results
= memcached_fetch_result(new_clone
, &result_obj
, &rc
)) != NULL
)
210 test_compare(4, hits
);
211 memcached_result_free(&result_obj
);
214 memcached_free(new_clone
);
217 memcached_free(memc_clone
);
222 test_return_t
replication_randomize_mget_test(memcached_st
*memc
)
224 memcached_result_st result_obj
;
225 memcached_st
*memc_clone
= memcached_clone(NULL
, memc
);
226 memcached_behavior_set(memc_clone
, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS
, 3);
227 memcached_behavior_set(memc_clone
, MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ
, 1);
229 const char *keys
[]= { "key1", "key2", "key3", "key4", "key5", "key6", "key7" };
230 size_t len
[]= { 4, 4, 4, 4, 4, 4, 4 };
232 for (size_t x
= 0; x
< 7; ++x
)
234 test_compare(MEMCACHED_SUCCESS
,
235 memcached_set(memc
, keys
[x
], len
[x
], "1", 1, 0, 0));
238 memcached_quit(memc
);
240 for (size_t x
= 0; x
< 7; ++x
)
242 const char key
[2]= { (char)x
, 0 };
244 test_compare(MEMCACHED_SUCCESS
,
245 memcached_mget_by_key(memc_clone
, key
, 1, keys
, len
, 7));
247 memcached_result_st
*results
= memcached_result_create(memc_clone
, &result_obj
);
251 memcached_return_t rc
;
252 while ((results
= memcached_fetch_result(memc_clone
, &result_obj
, &rc
)) != NULL
)
256 test_compare(hits
, 7);
257 memcached_result_free(&result_obj
);
259 memcached_free(memc_clone
);
264 test_return_t
replication_delete_test(memcached_st
*memc_just_cloned
)
266 memcached_flush(memc_just_cloned
, 0);
267 memcached_st
*memc_not_replicate
= memcached_clone(NULL
, memc_just_cloned
);
268 memcached_st
*memc_replicated
= memcached_clone(NULL
, memc_just_cloned
);
269 const char *keys
[]= { "bubba", "key1", "key2", "key3", "key4" };
271 test_compare(uint64_t(1), memcached_behavior_get(memc_replicated
, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL
));
272 test_compare(MEMCACHED_SUCCESS
, memcached_behavior_set(memc_replicated
, MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ
, false));
275 test_compare(MEMCACHED_SUCCESS
, memcached_behavior_set(memc_replicated
, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS
, 1UL));
276 test_compare(uint64_t(1), memcached_behavior_get(memc_replicated
, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS
));
278 test_compare(MEMCACHED_SUCCESS
, memcached_behavior_set(memc_not_replicate
, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS
, 0UL));
279 test_compare(uint64_t(0), memcached_behavior_get(memc_not_replicate
, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS
));
281 for (size_t x
= 0; x
< test_array_length(keys
); ++x
)
283 memcached_set(memc_replicated
,
284 test_string_make_from_cstr(keys
[x
]), // Keys
285 test_string_make_from_cstr(keys
[x
]), // We use the keys as values
289 memcached_flush_buffers(memc_replicated
);
291 // Confirm keys with replication read
292 test_compare(TEST_SUCCESS
, confirm_keys_exist(memc_replicated
, keys
, test_array_length(keys
), true, true));
293 test_compare(TEST_SUCCESS
, confirm_keys_exist(memc_not_replicate
, keys
, test_array_length(keys
), true, true));
295 /* Delete the items from all of the servers except 1, we use the non replicated memc so that we know we deleted the keys */
296 for (size_t x
= 0; x
< test_array_length(keys
); ++x
)
298 memcached_return_t del_rc
= memcached_delete(memc_replicated
,
299 test_string_make_from_cstr(keys
[x
]), // Keys
301 if (del_rc
== MEMCACHED_SUCCESS
or del_rc
== MEMCACHED_NOTFOUND
)
305 test_compare(MEMCACHED_SUCCESS
, del_rc
);
309 test_compare(TEST_SUCCESS
, confirm_keys_dont_exist(memc_replicated
, keys
, test_array_length(keys
)));
310 test_compare(TEST_SUCCESS
, confirm_keys_dont_exist(memc_not_replicate
, keys
, test_array_length(keys
)));
312 test_zero(confirm_key_count(memc_not_replicate
));
315 memcached_free(memc_not_replicate
);
316 memcached_free(memc_replicated
);
321 test_return_t
replication_randomize_mget_fail_test(memcached_st
*memc
)
323 memcached_st
*memc_clone
= memcached_clone(NULL
, memc
);
324 memcached_behavior_set(memc_clone
, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS
, 3);
326 for (int x
= int(MEMCACHED_SUCCESS
); x
< int(MEMCACHED_MAXIMUM_RETURN
); ++x
)
328 const char *key
= memcached_strerror(NULL
, memcached_return_t(x
));
329 test_compare(MEMCACHED_SUCCESS
,
332 key
, strlen(key
), 0, 0));
335 memcached_flush_buffers(memc
);
337 // We need to now cause a failure in one server, never do this in your own
339 close(memc_clone
->servers
[1].fd
);
340 memc_clone
->servers
[1].port(1);
341 memc_clone
->servers
[1].address_info_next
= NULL
;
343 for (int x
= int(MEMCACHED_SUCCESS
); x
< int(MEMCACHED_MAXIMUM_RETURN
); ++x
)
345 const char *key
= memcached_strerror(NULL
, memcached_return_t(x
));
348 memcached_return_t rc
;
349 char *value
= memcached_get(memc_clone
, key
, strlen(key
), &value_length
, &flags
, &rc
);
350 test_compare(MEMCACHED_SUCCESS
, rc
);
351 test_compare(strlen(key
), value_length
);
352 test_strcmp(key
, value
);
355 memcached_free(memc_clone
);
359 /* Test that single miss does not cause replica reads to fail */
360 test_return_t
replication_miss_test(memcached_st
*memc
)
362 test_skip(true, false);
364 memcached_st
*memc_repl
= memcached_clone(NULL
, memc
);
365 test_true(memc_repl
);
366 memcached_st
*memc_single
= memcached_clone(NULL
, memc
);
367 test_true(memc_single
);
369 const char *value
= "my_value";
373 /* this test makes sense only with 2 or more servers */
374 test_true(memcached_server_count(memc_repl
) > 1);
376 /* Consistent hash */
377 test_compare(MEMCACHED_SUCCESS
,
378 memcached_behavior_set_distribution(memc_repl
, MEMCACHED_DISTRIBUTION_CONSISTENT
));
379 test_compare(MEMCACHED_SUCCESS
,
380 memcached_behavior_set_distribution(memc_single
, MEMCACHED_DISTRIBUTION_CONSISTENT
));
382 /* The first clone writes to all servers */
383 test_compare(MEMCACHED_SUCCESS
,
384 memcached_behavior_set(memc_repl
, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL
, true));
385 test_compare(MEMCACHED_SUCCESS
,
386 memcached_behavior_set(memc_repl
, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS
,
387 memcached_server_count(memc_repl
)));
389 /* Write to servers */
391 memcached_return_t rc
= memcached_set(memc_repl
,
392 test_literal_param(__func__
),
393 value
, strlen(value
),
394 time_t(1200), uint32_t(0));
395 test_true(rc
== MEMCACHED_SUCCESS
or rc
== MEMCACHED_BUFFERED
);
398 /* Use the second clone to remove the key from primary server.
399 This should remove the key from only one server */
401 memcached_return_t rc
= memcached_delete(memc_single
,
402 test_literal_param(__func__
),
404 test_true(rc
== MEMCACHED_SUCCESS
or rc
== MEMCACHED_BUFFERED
);
407 /* Remove the server where the key was deleted */
410 memcached_return_t rc
;
411 const memcached_server_st
*instance
= memcached_server_by_key(memc_single
,
412 test_literal_param(__func__
),
414 test_compare(MEMCACHED_SUCCESS
, rc
);
415 test_compare(MEMCACHED_SUCCESS
,
416 memcached_server_remove(instance
));
420 /* Test that others still have it */
422 memcached_return_t rc
;
423 char *get_value
= memcached_get(memc_single
,
424 test_literal_param(__func__
),
426 test_true(rc
== MEMCACHED_SUCCESS
or rc
== MEMCACHED_BUFFERED
);
427 test_true(get_value
and strcmp(get_value
, value
) == 0);
431 /* This read should still return the value as we have it on other servers */
433 memcached_return_t rc
;
434 char *get_value
= memcached_get(memc_repl
,
435 test_literal_param(__func__
),
437 test_true(rc
== MEMCACHED_SUCCESS
|| rc
== MEMCACHED_BUFFERED
);
438 test_true(get_value
and strcmp(get_value
, value
) == 0);
442 memcached_free(memc_repl
);
443 memcached_free(memc_single
);