Skip to content

Commit 5acf94c

Browse files
avsejDemetrisChr
andauthored
CXXCBC-729: cbc-keygen: generate keys grouped by nodes (#833)
* CXXCBC-729: cbc-keygen: generate keys grouped by nodes * Update tools/key_generator.hxx --------- Co-authored-by: Dimitris Christodoulou <36637689+DemetrisChr@users.noreply.github.com>
1 parent dbdb132 commit 5acf94c

File tree

4 files changed

+341
-21
lines changed

4 files changed

+341
-21
lines changed

docs/cbc-keygen.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ You can also set the number of vbuckets with the `--number-of-vbuckets` switch.
3232
<dt>`--vbucket=INTEGER ...`</dt><dd>Pin generated keys to the given vBucket.</dd>
3333
<dt>`--parent-key=STRING ...`</dt><dd>Pin generated keys to the same vBucket as the given key.</dd>
3434
<dt>`--all-vbuckets`</dt><dd>Generate key(s) for each available vBucket.</dd>
35+
<dt>`--vbuckets-for-nodes=STRING`</dt><dd>Generate key(s) for each available vBucket on the given type for each of the nodes (allowed values are: `active`, `replica_1`, `replica_2`, `replica_3`).[</dd>
3536
<dt>`--number-of-vbuckets=INTEGER`</dt><dd>Override number of vBuckets. Otherwise try to connect to cluster and infer number of vBuckets from the bucket configuration.</dd>
3637
<dt>`--bucket-name=BUCKET_NAME`</dt><dd>Name of the bucket (only used when `--number-of-vbuckets` switch is not specified). [default: `default`]</dd>
3738
<dt>`--json`</dt><dd>Output generation result as JSON.</dd>
@@ -177,6 +178,11 @@ You can also set the number of vbuckets with the `--number-of-vbuckets` switch.
177178

178179
cbc keygen --number-of-keys=10 --randomize --parent-key foo
179180

181+
4. Generate 3 keys for each of the nodes in the cluster that map to the first
182+
replica and print results as a JSON:
183+
184+
cbc keygen --vbuckets-for-nodes=replica_1 --json --number-of-keys=3
185+
180186
### SEE ALSO
181187

182188
[cbc](#cbc), [cbc-pillowfight](#cbc-pillowfight).

tools/key_generator.cxx

Lines changed: 154 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
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

147150
auto
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

168179
auto
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+
180230
auto
181231
key_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

187237
auto
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

Comments
 (0)