Merge lp:~tangent-org/libmemcached/1.0-build/ Build: jenkins-Libmemcached-170
[awesomized/libmemcached] / tests / libmemcached-1.0 / ketama.cc
1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * Libmemcached library
4 *
5 * Copyright (C) 2011 Data Differential, http://datadifferential.com/
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following disclaimer
16 * in the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * * The names of its contributors may not be used to endorse or
20 * promote products derived from this software without specific prior
21 * written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 *
35 */
36
37 #include <mem_config.h>
38 #include <libtest/test.hpp>
39
40 #include <libmemcached-1.0/memcached.h>
41
42 #include "libmemcached/server_instance.h"
43 #include "libmemcached/continuum.hpp"
44 #include "libmemcached/instance.hpp"
45
46 #include <tests/ketama.h>
47 #include <tests/ketama_test_cases.h>
48
49 test_return_t ketama_compatibility_libmemcached(memcached_st *)
50 {
51 memcached_st *memc= memcached_create(NULL);
52 test_true(memc);
53
54 test_compare(MEMCACHED_SUCCESS,
55 memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, 1));
56
57 test_compare(uint64_t(1), memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED));
58
59 test_compare(MEMCACHED_SUCCESS, memcached_behavior_set_distribution(memc, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA));
60 test_compare(MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA, memcached_behavior_get_distribution(memc));
61
62 memcached_server_st *server_pool= memcached_servers_parse("10.0.1.1:11211 600,10.0.1.2:11211 300,10.0.1.3:11211 200,10.0.1.4:11211 350,10.0.1.5:11211 1000,10.0.1.6:11211 800,10.0.1.7:11211 950,10.0.1.8:11211 100");
63 memcached_server_push(memc, server_pool);
64
65 /* verify that the server list was parsed okay. */
66 test_compare(8U, memcached_server_count(memc));
67 test_strcmp(server_pool[0].hostname, "10.0.1.1");
68 test_compare(in_port_t(11211), server_pool[0].port);
69 test_compare(600U, server_pool[0].weight);
70 test_strcmp(server_pool[2].hostname, "10.0.1.3");
71 test_compare(in_port_t(11211), server_pool[2].port);
72 test_compare(200U, server_pool[2].weight);
73 test_strcmp(server_pool[7].hostname, "10.0.1.8");
74 test_compare(in_port_t(11211), server_pool[7].port);
75 test_compare(100U, server_pool[7].weight);
76
77 /* VDEAAAAA hashes to fffcd1b5, after the last continuum point, and lets
78 * us test the boundary wraparound.
79 */
80 test_true(memcached_generate_hash(memc, (char *)"VDEAAAAA", 8) == memc->ketama.continuum[0].index);
81
82 /* verify the standard ketama set. */
83 for (uint32_t x= 0; x < 99; x++)
84 {
85 uint32_t server_idx = memcached_generate_hash(memc, ketama_test_cases[x].key, strlen(ketama_test_cases[x].key));
86 memcached_server_instance_st instance=
87 memcached_server_instance_by_position(memc, server_idx);
88 const char *hostname = memcached_server_name(instance);
89
90 test_strcmp(hostname, ketama_test_cases[x].server);
91 }
92
93 memcached_server_list_free(server_pool);
94 memcached_free(memc);
95
96 return TEST_SUCCESS;
97 }
98
99 test_return_t user_supplied_bug18(memcached_st *trash)
100 {
101 memcached_return_t rc;
102 uint64_t value;
103 int x;
104 memcached_st *memc;
105
106 (void)trash;
107
108 memc= memcached_create(NULL);
109 test_true(memc);
110
111 rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, 1);
112 test_compare(MEMCACHED_SUCCESS, rc);
113
114 value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED);
115 test_true(value == 1);
116
117 rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_HASH, MEMCACHED_HASH_MD5);
118 test_compare(MEMCACHED_SUCCESS, rc);
119
120 value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_HASH);
121 test_true(value == MEMCACHED_HASH_MD5);
122
123 memcached_server_st *server_pool= memcached_servers_parse("10.0.1.1:11211 600,10.0.1.2:11211 300,10.0.1.3:11211 200,10.0.1.4:11211 350,10.0.1.5:11211 1000,10.0.1.6:11211 800,10.0.1.7:11211 950,10.0.1.8:11211 100");
124 memcached_server_push(memc, server_pool);
125
126 /* verify that the server list was parsed okay. */
127 test_true(memcached_server_count(memc) == 8);
128 test_strcmp(server_pool[0].hostname, "10.0.1.1");
129 test_true(server_pool[0].port == 11211);
130 test_true(server_pool[0].weight == 600);
131 test_strcmp(server_pool[2].hostname, "10.0.1.3");
132 test_true(server_pool[2].port == 11211);
133 test_true(server_pool[2].weight == 200);
134 test_strcmp(server_pool[7].hostname, "10.0.1.8");
135 test_true(server_pool[7].port == 11211);
136 test_true(server_pool[7].weight == 100);
137
138 /* VDEAAAAA hashes to fffcd1b5, after the last continuum point, and lets
139 * us test the boundary wraparound.
140 */
141 test_true(memcached_generate_hash(memc, (char *)"VDEAAAAA", 8) == memc->ketama.continuum[0].index);
142
143 /* verify the standard ketama set. */
144 for (x= 0; x < 99; x++)
145 {
146 uint32_t server_idx = memcached_generate_hash(memc, ketama_test_cases[x].key, strlen(ketama_test_cases[x].key));
147
148 memcached_server_instance_st instance=
149 memcached_server_instance_by_position(memc, server_idx);
150
151 const char *hostname = memcached_server_name(instance);
152 test_strcmp(hostname, ketama_test_cases[x].server);
153 }
154
155 memcached_server_list_free(server_pool);
156 memcached_free(memc);
157
158 return TEST_SUCCESS;
159 }
160
161 test_return_t auto_eject_hosts(memcached_st *trash)
162 {
163 (void) trash;
164
165 memcached_return_t rc;
166 memcached_st *memc= memcached_create(NULL);
167 test_true(memc);
168
169 rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, 1);
170 test_compare(MEMCACHED_SUCCESS, rc);
171
172 uint64_t value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED);
173 test_true(value == 1);
174
175 rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_HASH, MEMCACHED_HASH_MD5);
176 test_compare(MEMCACHED_SUCCESS, rc);
177
178 value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_HASH);
179 test_true(value == MEMCACHED_HASH_MD5);
180
181 /* server should be removed when in delay */
182 rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS, 1);
183 test_compare(MEMCACHED_SUCCESS, rc);
184
185 value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS);
186 test_true(value == 1);
187
188 memcached_server_st *server_pool;
189 server_pool = memcached_servers_parse("10.0.1.1:11211 600,10.0.1.2:11211 300,10.0.1.3:11211 200,10.0.1.4:11211 350,10.0.1.5:11211 1000,10.0.1.6:11211 800,10.0.1.7:11211 950,10.0.1.8:11211 100");
190 memcached_server_push(memc, server_pool);
191
192 /* verify that the server list was parsed okay. */
193 test_true(memcached_server_count(memc) == 8);
194 test_strcmp(server_pool[0].hostname, "10.0.1.1");
195 test_true(server_pool[0].port == 11211);
196 test_true(server_pool[0].weight == 600);
197 test_strcmp(server_pool[2].hostname, "10.0.1.3");
198 test_true(server_pool[2].port == 11211);
199 test_true(server_pool[2].weight == 200);
200 test_strcmp(server_pool[7].hostname, "10.0.1.8");
201 test_true(server_pool[7].port == 11211);
202 test_true(server_pool[7].weight == 100);
203
204 memcached_server_instance_st instance= memcached_server_instance_by_position(memc, 2);
205 memcached_instance_next_retry(instance, time(NULL) +15);
206 memc->ketama.next_distribution_rebuild= time(NULL) - 1;
207
208 /*
209 This would not work if there were only two hosts.
210 */
211 for (ptrdiff_t x= 0; x < 99; x++)
212 {
213 memcached_autoeject(memc);
214 uint32_t server_idx= memcached_generate_hash(memc, ketama_test_cases[x].key, strlen(ketama_test_cases[x].key));
215 test_true(server_idx != 2);
216 }
217
218 /* and re-added when it's back. */
219 time_t absolute_time= time(NULL) -1;
220 memcached_instance_next_retry(instance, absolute_time);
221 memc->ketama.next_distribution_rebuild= absolute_time;
222 memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_DISTRIBUTION,
223 memc->distribution);
224 for (ptrdiff_t x= 0; x < 99; x++)
225 {
226 uint32_t server_idx = memcached_generate_hash(memc, ketama_test_cases[x].key, strlen(ketama_test_cases[x].key));
227 // We re-use instance from above.
228 instance=
229 memcached_server_instance_by_position(memc, server_idx);
230 const char *hostname = memcached_server_name(instance);
231 test_strcmp(hostname, ketama_test_cases[x].server);
232 }
233
234 memcached_server_list_free(server_pool);
235 memcached_free(memc);
236
237 return TEST_SUCCESS;
238 }
239
240 test_return_t ketama_compatibility_spymemcached(memcached_st *)
241 {
242 memcached_st *memc= memcached_create(NULL);
243 test_true(memc);
244
245 test_compare(MEMCACHED_SUCCESS,
246 memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, 1));
247
248 test_compare(UINT64_C(1), memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED));
249
250 test_compare(MEMCACHED_SUCCESS, memcached_behavior_set_distribution(memc, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY));
251 test_compare(MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY, memcached_behavior_get_distribution(memc));
252
253 memcached_server_st *server_pool= memcached_servers_parse("10.0.1.1:11211 600,10.0.1.2:11211 300,10.0.1.3:11211 200,10.0.1.4:11211 350,10.0.1.5:11211 1000,10.0.1.6:11211 800,10.0.1.7:11211 950,10.0.1.8:11211 100");
254 test_true(server_pool);
255 memcached_server_push(memc, server_pool);
256
257 /* verify that the server list was parsed okay. */
258 test_compare(8U, memcached_server_count(memc));
259 test_strcmp(server_pool[0].hostname, "10.0.1.1");
260 test_compare(in_port_t(11211), server_pool[0].port);
261 test_compare(600U, server_pool[0].weight);
262 test_strcmp(server_pool[2].hostname, "10.0.1.3");
263 test_compare(in_port_t(11211), server_pool[2].port);
264 test_compare(200U, server_pool[2].weight);
265 test_strcmp(server_pool[7].hostname, "10.0.1.8");
266 test_compare(in_port_t(11211), server_pool[7].port);
267 test_compare(100U, server_pool[7].weight);
268
269 /* VDEAAAAA hashes to fffcd1b5, after the last continuum point, and lets
270 * us test the boundary wraparound.
271 */
272 test_true(memcached_generate_hash(memc, (char *)"VDEAAAAA", 8) == memc->ketama.continuum[0].index);
273
274 /* verify the standard ketama set. */
275 for (uint32_t x= 0; x < 99; x++)
276 {
277 uint32_t server_idx= memcached_generate_hash(memc, ketama_test_cases_spy[x].key, strlen(ketama_test_cases_spy[x].key));
278
279 memcached_server_instance_st instance=
280 memcached_server_instance_by_position(memc, server_idx);
281
282 const char *hostname= memcached_server_name(instance);
283
284 test_strcmp(hostname, ketama_test_cases_spy[x].server);
285 }
286
287 memcached_server_list_free(server_pool);
288 memcached_free(memc);
289
290 return TEST_SUCCESS;
291 }