update TODO
[awesomized/libmemcached] / test / tests / memcached / ketama.cpp
1 #include "test/lib/common.hpp"
2 #include "test/lib/MemcachedCluster.hpp"
3
4 #include "test/fixtures/ketama.hpp"
5
6 #include "libmemcached/continuum.hpp"
7 #include "libmemcached/instance.hpp"
8
9 TEST_CASE("memcached_ketama_compat") {
10 auto test = MemcachedCluster::network();
11 auto memc = &test.memc;
12
13 REQUIRE_SUCCESS(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, 1));
14 REQUIRE(uint64_t(1) == memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED));
15
16 SECTION("generate hash") {
17 REQUIRE_SUCCESS(memcached_behavior_set_distribution(memc, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA));
18 REQUIRE(MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA == memcached_behavior_get_distribution(memc));
19
20 memcached_server_st *server_pool = memcached_servers_parse(
21 "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"
22 );
23 memcached_servers_reset(memc);
24 memcached_server_push(memc, server_pool);
25
26 /* verify that the server list was parsed okay. */
27 REQUIRE(8U == memcached_server_count(memc));
28 REQUIRE(server_pool[0].hostname == "10.0.1.1"s);
29 REQUIRE(in_port_t(11211) == server_pool[0].port);
30 REQUIRE(600U == server_pool[0].weight);
31 REQUIRE(server_pool[2].hostname == "10.0.1.3"s);
32 REQUIRE(in_port_t(11211) == server_pool[2].port);
33 REQUIRE(200U == server_pool[2].weight);
34 REQUIRE(server_pool[7].hostname == "10.0.1.8"s);
35 REQUIRE(in_port_t(11211) == server_pool[7].port);
36 REQUIRE(100U == server_pool[7].weight);
37
38 /* VDEAAAAA hashes to fffcd1b5, after the last continuum point, and lets
39 * us test the boundary wraparound.
40 */
41 REQUIRE(memcached_generate_hash(memc, (char *) "VDEAAAAA", 8) == memc->ketama.continuum[0].index);
42
43 /* verify the standard ketama set. */
44 for (uint32_t x = 0; x < 99; x++) {
45 uint32_t server_idx = memcached_generate_hash(memc, ketama_test_cases[x].key, strlen(ketama_test_cases[x].key));
46 const memcached_instance_st *instance =
47 memcached_server_instance_by_position(memc, server_idx);
48 const char *hostname = memcached_server_name(instance);
49
50 REQUIRE(string{hostname} == ketama_test_cases[x].server);
51 }
52
53 memcached_server_list_free(server_pool);
54 }
55
56 SECTION("user bug 18") {
57
58 REQUIRE_SUCCESS(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_HASH, MEMCACHED_HASH_MD5));
59 REQUIRE(MEMCACHED_HASH_MD5 == memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_HASH));
60
61 memcached_server_st *server_pool = memcached_servers_parse(
62 "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 );
64 memcached_servers_reset(memc);
65 memcached_server_push(memc, server_pool);
66
67 /* verify that the server list was parsed okay. */
68 REQUIRE(memcached_server_count(memc) == 8);
69 REQUIRE(server_pool[0].hostname == "10.0.1.1"s);
70 REQUIRE(server_pool[0].port == 11211);
71 REQUIRE(server_pool[0].weight == 600);
72 REQUIRE(server_pool[2].hostname == "10.0.1.3"s);
73 REQUIRE(server_pool[2].port == 11211);
74 REQUIRE(server_pool[2].weight == 200);
75 REQUIRE(server_pool[7].hostname == "10.0.1.8"s);
76 REQUIRE(server_pool[7].port == 11211);
77 REQUIRE(server_pool[7].weight == 100);
78
79 /* VDEAAAAA hashes to fffcd1b5, after the last continuum point, and lets
80 * us test the boundary wraparound.
81 */
82 REQUIRE(memcached_generate_hash(memc, (char *) "VDEAAAAA", 8) == memc->ketama.continuum[0].index);
83
84 /* verify the standard ketama set. */
85 for (auto x = 0; x < 99; x++) {
86 uint32_t server_idx = memcached_generate_hash(memc, ketama_test_cases[x].key, strlen(ketama_test_cases[x].key));
87
88 const memcached_instance_st *instance =
89 memcached_server_instance_by_position(memc, server_idx);
90
91 const char *hostname = memcached_server_name(instance);
92 REQUIRE(string{hostname} == ketama_test_cases[x].server);
93 }
94
95 memcached_server_list_free(server_pool);
96 }
97
98 SECTION("auto_eject_hosts") {
99 memcached_servers_reset(memc);
100
101 REQUIRE_SUCCESS(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_HASH, MEMCACHED_HASH_MD5));
102 REQUIRE(MEMCACHED_HASH_MD5 == memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_KETAMA_HASH));
103
104 /* server should be removed when in delay */
105 REQUIRE_SUCCESS(memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS, 1));
106 REQUIRE(memcached_behavior_get(memc, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS));
107
108 memcached_server_st *server_pool;
109 server_pool = memcached_servers_parse(
110 "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"
111 );
112 memcached_servers_reset(memc);
113 memcached_server_push(memc, server_pool);
114
115 /* verify that the server list was parsed okay. */
116 REQUIRE(memcached_server_count(memc) == 8);
117 REQUIRE(server_pool[0].hostname == "10.0.1.1"s);
118 REQUIRE(server_pool[0].port == 11211);
119 REQUIRE(server_pool[0].weight == 600);
120 REQUIRE(server_pool[2].hostname == "10.0.1.3"s);
121 REQUIRE(server_pool[2].port == 11211);
122 REQUIRE(server_pool[2].weight == 200);
123 REQUIRE(server_pool[7].hostname == "10.0.1.8"s);
124 REQUIRE(server_pool[7].port == 11211);
125 REQUIRE(server_pool[7].weight == 100);
126
127 const memcached_instance_st *instance = memcached_server_instance_by_position(memc, 2);
128 memcached_instance_next_retry(instance, time(nullptr) + 15);
129 memc->ketama.next_distribution_rebuild = time(nullptr) - 1;
130
131 /*
132 This would not work if there were only two hosts.
133 */
134 for (auto x = 0; x < 99; x++) {
135 memcached_autoeject(memc);
136 uint32_t server_idx = memcached_generate_hash(memc, ketama_test_cases[x].key, strlen(ketama_test_cases[x].key));
137 REQUIRE(server_idx != 2);
138 }
139
140 /* and re-added when it's back. */
141 time_t absolute_time = time(nullptr) - 1;
142 memcached_instance_next_retry(instance, absolute_time);
143 memc->ketama.next_distribution_rebuild = absolute_time;
144 memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_DISTRIBUTION, memc->distribution);
145 for (auto x = 0; x < 99; x++) {
146 uint32_t server_idx = memcached_generate_hash(memc, ketama_test_cases[x].key, strlen(ketama_test_cases[x].key));
147 // We re-use instance from above.
148 instance = memcached_server_instance_by_position(memc, server_idx);
149 const char *hostname = memcached_server_name(instance);
150 REQUIRE(string{hostname} == ketama_test_cases[x].server);
151 }
152
153 memcached_server_list_free(server_pool);
154 }
155
156 SECTION("spymemcached") {
157 memcached_servers_reset(memc);
158 REQUIRE_SUCCESS(memcached_behavior_set_distribution(memc, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY));
159 REQUIRE(MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY == memcached_behavior_get_distribution(memc));
160
161 memcached_server_st *server_pool = memcached_servers_parse(
162 "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"
163 );
164 REQUIRE(server_pool);
165 memcached_server_push(memc, server_pool);
166
167 /* verify that the server list was parsed okay. */
168 REQUIRE(8U == memcached_server_count(memc));
169 REQUIRE(server_pool[0].hostname == "10.0.1.1"s);
170 REQUIRE(in_port_t(11211) == server_pool[0].port);
171 REQUIRE(600U == server_pool[0].weight);
172 REQUIRE(server_pool[2].hostname == "10.0.1.3"s);
173 REQUIRE(in_port_t(11211) == server_pool[2].port);
174 REQUIRE(200U == server_pool[2].weight);
175 REQUIRE(server_pool[7].hostname == "10.0.1.8"s);
176 REQUIRE(in_port_t(11211) == server_pool[7].port);
177 REQUIRE(100U == server_pool[7].weight);
178
179 /* VDEAAAAA hashes to fffcd1b5, after the last continuum point, and lets
180 * us test the boundary wraparound.
181 */
182 REQUIRE(memcached_generate_hash(memc, (char *) "VDEAAAAA", 8) == memc->ketama.continuum[0].index);
183
184 /* verify the standard ketama set. */
185 for (uint32_t x = 0; x < 99; x++) {
186 uint32_t server_idx = memcached_generate_hash(memc, ketama_test_cases_spy[x].key,
187 strlen(ketama_test_cases_spy[x].key));
188
189 const memcached_instance_st *instance =
190 memcached_server_instance_by_position(memc, server_idx);
191
192 const char *hostname = memcached_server_name(instance);
193 REQUIRE(string{hostname} == ketama_test_cases_spy[x].server);
194 }
195
196 memcached_server_list_free(server_pool);
197 }
198 }