1717
1818#include " key_generator.hxx"
1919
20+ #include " core/topology/configuration.hxx"
21+
22+ #include < optional>
2023#include < spdlog/fmt/bundled/core.h>
2124
2225#include < gsl/assert>
@@ -145,8 +148,16 @@ key_generator::next_key() -> std::string
145148}
146149
147150auto
148- key_generator::next_keys (std::size_t count) -> std::vector<std::string>
151+ key_generator::next_keys (std::size_t count, bool skip_duplicates ) -> std::vector<std::string>
149152{
153+ if (skip_duplicates) {
154+ std::set<std::string> result;
155+ while (result.size () < count) {
156+ result.insert (next_key ());
157+ }
158+ return { result.begin (), result.end () };
159+ }
160+
150161 std::vector<std::string> result;
151162 result.reserve (count);
152163 for (std::size_t i = 0 ; i < count; ++i) {
@@ -166,9 +177,17 @@ key_generator::next_key_for_vbucket(std::uint16_t vbucket) -> std::string
166177}
167178
168179auto
169- key_generator::next_keys_for_vbucket (std::size_t count, std::uint16_t vbucket)
180+ key_generator::next_keys_for_vbucket (std::size_t count, std::uint16_t vbucket, bool skip_duplicates )
170181 -> std::vector<std::string>
171182{
183+ if (skip_duplicates) {
184+ std::set<std::string> result;
185+ while (result.size () < count) {
186+ result.insert (next_key_for_vbucket (vbucket));
187+ }
188+ return { result.begin (), result.end () };
189+ }
190+
172191 std::vector<std::string> result;
173192 result.reserve (count);
174193 for (std::size_t i = 0 ; i < count; ++i) {
@@ -177,6 +196,37 @@ key_generator::next_keys_for_vbucket(std::size_t count, std::uint16_t vbucket)
177196 return result;
178197}
179198
199+ auto
200+ key_generator::next_key_for_vbucket_set (const std::set<std::uint16_t >& vbuckets) -> std::string
201+ {
202+ std::string result;
203+ do {
204+ result = next_key ();
205+ } while (vbuckets.find (map_key_to_vbucket_id (result, number_of_vbuckets_)) == vbuckets.end ());
206+ return result;
207+ }
208+
209+ auto
210+ key_generator::next_keys_for_vbucket_set (std::size_t count,
211+ const std::set<std::uint16_t >& vbuckets,
212+ bool skip_duplicates) -> std::vector<std::string>
213+ {
214+ if (skip_duplicates) {
215+ std::set<std::string> result;
216+ while (result.size () < count) {
217+ result.insert (next_key_for_vbucket_set (vbuckets));
218+ }
219+ return { result.begin (), result.end () };
220+ }
221+
222+ std::vector<std::string> result;
223+ result.reserve (count);
224+ for (std::size_t i = 0 ; i < count; ++i) {
225+ result.push_back (next_key_for_vbucket_set (vbuckets));
226+ }
227+ return result;
228+ }
229+
180230auto
181231key_generator::next_key_for_parent (const std::string& parent_key) -> std::string
182232{
@@ -185,11 +235,110 @@ key_generator::next_key_for_parent(const std::string& parent_key) -> std::string
185235}
186236
187237auto
188- key_generator::next_keys_for_parent (std::size_t count, const std::string& parent_key)
189- -> std::vector<std::string>
238+ key_generator::next_keys_for_parent (std::size_t count,
239+ const std::string& parent_key,
240+ bool skip_duplicates) -> std::vector<std::string>
190241{
191242 auto parent_vbucket = map_key_to_vbucket_id (parent_key, number_of_vbuckets_);
192- return next_keys_for_vbucket (count, parent_vbucket);
243+ return next_keys_for_vbucket (count, parent_vbucket, skip_duplicates);
244+ }
245+
246+ auto
247+ key_generator::next_key_for_node (const key_value_node& node, const std::string& type) -> std::string
248+ {
249+ return next_key_for_vbucket_set (node.vbuckets (type));
250+ }
251+
252+ auto
253+ key_generator::next_keys_for_node (std::size_t count,
254+ const key_value_node& node,
255+ const std::string& type,
256+ bool skip_duplicates) -> std::vector<std::string>
257+ {
258+ return next_keys_for_vbucket_set (count, node.vbuckets (type), skip_duplicates);
193259}
194260
261+ namespace
262+ {
263+ auto
264+ extract_endpoints (const couchbase::core::topology::configuration& config)
265+ -> std::vector<std::string>
266+ {
267+ std::vector<std::string> default_plain_endpoints;
268+ std::vector<std::string> default_tls_endpoints;
269+ std::vector<std::string> external_plain_endpoints;
270+ std::vector<std::string> external_tls_endpoints;
271+
272+ for (const auto & node : config.nodes ) {
273+ if (auto port = node.services_plain .key_value ; port) {
274+ default_plain_endpoints.push_back (fmt::format (" {}:{}" , node.hostname , *port));
275+ }
276+ if (auto port = node.services_tls .key_value ; port) {
277+ default_tls_endpoints.push_back (fmt::format (" {}:{}" , node.hostname , *port));
278+ }
279+ if (auto external = node.alt .find (" external" ); external != node.alt .end ()) {
280+ const auto & alt_node = external->second ;
281+ if (auto port = alt_node.services_plain .key_value ; port) {
282+ external_plain_endpoints.push_back (fmt::format (" {}:{}" , alt_node.hostname , *port));
283+ }
284+ if (auto port = alt_node.services_tls .key_value ; port) {
285+ external_tls_endpoints.push_back (fmt::format (" {}:{}" , alt_node.hostname , *port));
286+ }
287+ }
288+ }
289+
290+ // prefer external addresses if all nodes have them
291+ if (external_tls_endpoints.size () >= default_plain_endpoints.size ()) {
292+ return external_tls_endpoints;
293+ }
294+ if (external_plain_endpoints.size () >= default_plain_endpoints.size ()) {
295+ return external_plain_endpoints;
296+ }
297+ // prefer TLS addresses if all nodes have them
298+ if (default_tls_endpoints.size () >= default_plain_endpoints.size ()) {
299+ return default_tls_endpoints;
300+ }
301+ return default_plain_endpoints;
302+ }
303+ } // namespace
304+
305+ auto
306+ extract_vbucket_map (const couchbase::core::topology::configuration& config)
307+ -> std::map<std::string, key_value_node>
308+ {
309+
310+ auto vbmap_opt = config.vbmap ;
311+ if (!vbmap_opt) {
312+ return {};
313+ }
314+ const auto & vbmap = *vbmap_opt;
315+
316+ std::map<std::string, key_value_node> result;
317+
318+ auto endpoints = extract_endpoints (config);
319+ for (std::size_t node_idx = 0 ; node_idx < endpoints.size (); ++node_idx) {
320+ const auto & endpoint = endpoints[node_idx];
321+ key_value_node node (node_idx, endpoint);
322+
323+ auto this_node_idx = static_cast <std::int16_t >(node_idx);
324+ for (std::uint16_t vb = 0 ; vb < static_cast <std::uint16_t >(vbmap.size ()); ++vb) {
325+ if (vbmap[vb][0 ] == this_node_idx) {
326+ node.add_active (vb);
327+ }
328+ if (vbmap[vb][1 ] == this_node_idx) {
329+ node.add_replica_1 (vb);
330+ }
331+ if (vbmap[vb][2 ] == this_node_idx) {
332+ node.add_replica_2 (vb);
333+ }
334+ if (vbmap[vb][3 ] == this_node_idx) {
335+ node.add_replica_3 (vb);
336+ }
337+ }
338+
339+ result.emplace (endpoint, node);
340+ }
341+
342+ return result;
343+ }
195344} // namespace cbc
0 commit comments