Merge in updates from m4.
[m6w6/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 <config.h>
38 #include <libtest/test.hpp>
39
40 #include <libmemcached/memcached.h>
41 #include <libmemcached/server_instance.h>
42 #include <libmemcached/continuum.hpp>
43 #include <libmemcached/instance.h>
44
45 #include <tests/ketama.h>
46 #include <tests/ketama_test_cases.h>
47
48 test_return_t ketama_compatibility_libmemcached(memcached_st *)
49 {
50 memcached_st *memc= memcached_create(NULL);
51 test_true(memc);
52
53 test_compare(MEMCACHED_SUCCESS,
54 memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, 1));
55
56 test_compare(uint64_t(1), memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED));
57
58 test_compare(MEMCACHED_SUCCESS, memcached_behavior_set_distribution(memc, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA));
59 test_compare(MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA, memcached_behavior_get_distribution(memc));
60
61 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");
62 memcached_server_push(memc, server_pool);
63
64 /* verify that the server list was parsed okay. */
65 test_compare(8U, memcached_server_count(memc));
66 test_strcmp(server_pool[0].hostname, "10.0.1.1");
67 test_compare(in_port_t(11211), server_pool[0].port);
68 test_compare(600U, server_pool[0].weight);
69 test_strcmp(server_pool[2].hostname, "10.0.1.3");
70 test_compare(in_port_t(11211), server_pool[2].port);
71 test_compare(200U, server_pool[2].weight);
72 test_strcmp(server_pool[7].hostname, "10.0.1.8");
73 test_compare(in_port_t(11211), server_pool[7].port);
74 test_compare(100U, server_pool[7].weight);
75
76 /* VDEAAAAA hashes to fffcd1b5, after the last continuum point, and lets
77 * us test the boundary wraparound.
78 */
79 test_true(memcached_generate_hash(memc, (char *)"VDEAAAAA", 8) == memc->ketama.continuum[0].index);
80
81 /* verify the standard ketama set. */
82 for (uint32_t x= 0; x < 99; x++)
83 {
84 uint32_t server_idx = memcached_generate_hash(memc, ketama_test_cases[x].key, strlen(ketama_test_cases[x].key));
85 memcached_server_instance_st instance=
86 memcached_server_instance_by_position(memc, server_idx);
87 const char *hostname = memcached_server_name(instance);
88
89 test_strcmp(hostname, ketama_test_cases[x].server);
90 }
91
92 memcached_server_list_free(server_pool);
93 memcached_free(memc);
94
95 return TEST_SUCCESS;
96 }
97
98 test_return_t user_supplied_bug18(memcached_st *trash)
99 {
100 memcached_return_t rc;
101 uint64_t value;
102 int x;
103 memcached_st *memc;
104
105 (void)trash;
106
107 memc= memcached_create(NULL);
108 test_true(memc);
109
110 rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, 1);
111 test_compare(MEMCACHED_SUCCESS, rc);
112
113 value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED);
114 test_true(value == 1);
115
116 rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_HASH, MEMCACHED_HASH_MD5);
117 test_compare(MEMCACHED_SUCCESS, rc);
118
119 value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_HASH);
120 test_true(value == MEMCACHED_HASH_MD5);
121
122 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");
123 memcached_server_push(memc, server_pool);
124
125 /* verify that the server list was parsed okay. */
126 test_true(memcached_server_count(memc) == 8);
127 test_strcmp(server_pool[0].hostname, "10.0.1.1");
128 test_true(server_pool[0].port == 11211);
129 test_true(server_pool[0].weight == 600);
130 test_strcmp(server_pool[2].hostname, "10.0.1.3");
131 test_true(server_pool[2].port == 11211);
132 test_true(server_pool[2].weight == 200);
133 test_strcmp(server_pool[7].hostname, "10.0.1.8");
134 test_true(server_pool[7].port == 11211);
135 test_true(server_pool[7].weight == 100);
136
137 /* VDEAAAAA hashes to fffcd1b5, after the last continuum point, and lets
138 * us test the boundary wraparound.
139 */
140 test_true(memcached_generate_hash(memc, (char *)"VDEAAAAA", 8) == memc->ketama.continuum[0].index);
141
142 /* verify the standard ketama set. */
143 for (x= 0; x < 99; x++)
144 {
145 uint32_t server_idx = memcached_generate_hash(memc, ketama_test_cases[x].key, strlen(ketama_test_cases[x].key));
146
147 memcached_server_instance_st instance=
148 memcached_server_instance_by_position(memc, server_idx);
149
150 const char *hostname = memcached_server_name(instance);
151 test_strcmp(hostname, ketama_test_cases[x].server);
152 }
153
154 memcached_server_list_free(server_pool);
155 memcached_free(memc);
156
157 return TEST_SUCCESS;
158 }
159
160 test_return_t auto_eject_hosts(memcached_st *trash)
161 {
162 (void) trash;
163
164 memcached_return_t rc;
165 memcached_st *memc= memcached_create(NULL);
166 test_true(memc);
167
168 rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, 1);
169 test_compare(MEMCACHED_SUCCESS, rc);
170
171 uint64_t value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED);
172 test_true(value == 1);
173
174 rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_HASH, MEMCACHED_HASH_MD5);
175 test_compare(MEMCACHED_SUCCESS, rc);
176
177 value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_HASH);
178 test_true(value == MEMCACHED_HASH_MD5);
179
180 /* server should be removed when in delay */
181 rc= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS, 1);
182 test_compare(MEMCACHED_SUCCESS, rc);
183
184 value= memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS);
185 test_true(value == 1);
186
187 memcached_server_st *server_pool;
188 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");
189 memcached_server_push(memc, server_pool);
190
191 /* verify that the server list was parsed okay. */
192 test_true(memcached_server_count(memc) == 8);
193 test_strcmp(server_pool[0].hostname, "10.0.1.1");
194 test_true(server_pool[0].port == 11211);
195 test_true(server_pool[0].weight == 600);
196 test_strcmp(server_pool[2].hostname, "10.0.1.3");
197 test_true(server_pool[2].port == 11211);
198 test_true(server_pool[2].weight == 200);
199 test_strcmp(server_pool[7].hostname, "10.0.1.8");
200 test_true(server_pool[7].port == 11211);
201 test_true(server_pool[7].weight == 100);
202
203 memcached_server_instance_st instance= memcached_server_instance_by_position(memc, 2);
204 memcached_instance_next_retry(instance, time(NULL) +15);
205 memc->ketama.next_distribution_rebuild= time(NULL) - 1;
206
207 /*
208 This would not work if there were only two hosts.
209 */
210 for (ptrdiff_t x= 0; x < 99; x++)
211 {
212 memcached_autoeject(memc);
213 uint32_t server_idx= memcached_generate_hash(memc, ketama_test_cases[x].key, strlen(ketama_test_cases[x].key));
214 test_true(server_idx != 2);
215 }
216
217 /* and re-added when it's back. */
218 time_t absolute_time= time(NULL) -1;
219 memcached_instance_next_retry(instance, absolute_time);
220 memc->ketama.next_distribution_rebuild= absolute_time;
221 memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_DISTRIBUTION,
222 memc->distribution);
223 for (ptrdiff_t x= 0; x < 99; x++)
224 {
225 uint32_t server_idx = memcached_generate_hash(memc, ketama_test_cases[x].key, strlen(ketama_test_cases[x].key));
226 // We re-use instance from above.
227 instance=
228 memcached_server_instance_by_position(memc, server_idx);
229 const char *hostname = memcached_server_name(instance);
230 test_strcmp(hostname, ketama_test_cases[x].server);
231 }
232
233 memcached_server_list_free(server_pool);
234 memcached_free(memc);
235
236 return TEST_SUCCESS;
237 }
238
239 test_return_t ketama_compatibility_spymemcached(memcached_st *)
240 {
241 memcached_st *memc= memcached_create(NULL);
242 test_true(memc);
243
244 test_compare(MEMCACHED_SUCCESS,
245 memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, 1));
246
247 test_compare(UINT64_C(1), memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED));
248
249 test_compare(MEMCACHED_SUCCESS, memcached_behavior_set_distribution(memc, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY));
250 test_compare(MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY, memcached_behavior_get_distribution(memc));
251
252 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");
253 test_true(server_pool);
254 memcached_server_push(memc, server_pool);
255
256 /* verify that the server list was parsed okay. */
257 test_compare(8U, memcached_server_count(memc));
258 test_strcmp(server_pool[0].hostname, "10.0.1.1");
259 test_compare(in_port_t(11211), server_pool[0].port);
260 test_compare(600U, server_pool[0].weight);
261 test_strcmp(server_pool[2].hostname, "10.0.1.3");
262 test_compare(in_port_t(11211), server_pool[2].port);
263 test_compare(200U, server_pool[2].weight);
264 test_strcmp(server_pool[7].hostname, "10.0.1.8");
265 test_compare(in_port_t(11211), server_pool[7].port);
266 test_compare(100U, server_pool[7].weight);
267
268 /* VDEAAAAA hashes to fffcd1b5, after the last continuum point, and lets
269 * us test the boundary wraparound.
270 */
271 test_true(memcached_generate_hash(memc, (char *)"VDEAAAAA", 8) == memc->ketama.continuum[0].index);
272
273 /* verify the standard ketama set. */
274 for (uint32_t x= 0; x < 99; x++)
275 {
276 uint32_t server_idx= memcached_generate_hash(memc, ketama_test_cases_spy[x].key, strlen(ketama_test_cases_spy[x].key));
277
278 memcached_server_instance_st instance=
279 memcached_server_instance_by_position(memc, server_idx);
280
281 const char *hostname= memcached_server_name(instance);
282
283 test_strcmp(hostname, ketama_test_cases_spy[x].server);
284 }
285
286 memcached_server_list_free(server_pool);
287 memcached_free(memc);
288
289 return TEST_SUCCESS;
290 }