1 #include "test/lib/common.hpp"
2 #include "test/lib/MemcachedCluster.hpp"
4 #include "test/fixtures/ketama.hpp"
6 #include "libmemcached/continuum.hpp"
7 #include "libmemcached/instance.hpp"
9 TEST_CASE("memcached_ketama_compat") {
10 auto test
= MemcachedCluster::network();
11 auto memc
= &test
.memc
;
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
));
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
));
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"
23 memcached_servers_reset(memc
);
24 memcached_server_push(memc
, server_pool
);
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
);
38 /* VDEAAAAA hashes to fffcd1b5, after the last continuum point, and lets
39 * us test the boundary wraparound.
41 REQUIRE(memcached_generate_hash(memc
, (char *) "VDEAAAAA", 8) == memc
->ketama
.continuum
[0].index
);
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
);
50 REQUIRE(string
{hostname
} == ketama_test_cases
[x
].server
);
53 memcached_server_list_free(server_pool
);
56 SECTION("user bug 18") {
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
));
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"
64 memcached_servers_reset(memc
);
65 memcached_server_push(memc
, server_pool
);
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);
79 /* VDEAAAAA hashes to fffcd1b5, after the last continuum point, and lets
80 * us test the boundary wraparound.
82 REQUIRE(memcached_generate_hash(memc
, (char *) "VDEAAAAA", 8) == memc
->ketama
.continuum
[0].index
);
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
));
88 const memcached_instance_st
*instance
=
89 memcached_server_instance_by_position(memc
, server_idx
);
91 const char *hostname
= memcached_server_name(instance
);
92 REQUIRE(string
{hostname
} == ketama_test_cases
[x
].server
);
95 memcached_server_list_free(server_pool
);
98 SECTION("auto_eject_hosts") {
99 memcached_servers_reset(memc
);
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
));
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
));
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"
112 memcached_servers_reset(memc
);
113 memcached_server_push(memc
, server_pool
);
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);
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;
132 This would not work if there were only two hosts.
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);
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
);
153 memcached_server_list_free(server_pool
);
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
));
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"
164 REQUIRE(server_pool
);
165 memcached_server_push(memc
, server_pool
);
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
);
179 /* VDEAAAAA hashes to fffcd1b5, after the last continuum point, and lets
180 * us test the boundary wraparound.
182 REQUIRE(memcached_generate_hash(memc
, (char *) "VDEAAAAA", 8) == memc
->ketama
.continuum
[0].index
);
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
));
189 const memcached_instance_st
*instance
=
190 memcached_server_instance_by_position(memc
, server_idx
);
192 const char *hostname
= memcached_server_name(instance
);
193 REQUIRE(string
{hostname
} == ketama_test_cases_spy
[x
].server
);
196 memcached_server_list_free(server_pool
);