Lists can grow very big. Let's use a chunked vector to prevent large contiguous allocations. Fixes: #15302. Closes scylladb/scylladb#15428
153 lines
6.4 KiB
C++
153 lines
6.4 KiB
C++
/*
|
|
* Copyright (C) 2021-present ScyllaDB
|
|
*/
|
|
|
|
/*
|
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
*/
|
|
|
|
#define BOOST_TEST_MODULE core
|
|
|
|
#include <boost/test/unit_test.hpp>
|
|
#include <vector>
|
|
|
|
#include "cdc/generation.hh"
|
|
#include "test/lib/random_utils.hh"
|
|
|
|
namespace cdc {
|
|
|
|
size_t limit_of_streams_in_topology_description();
|
|
topology_description limit_number_of_streams_if_needed(topology_description&& desc);
|
|
|
|
} // namespace cdc
|
|
|
|
static cdc::topology_description create_description(const std::vector<size_t>& streams_count_per_vnode) {
|
|
utils::chunked_vector<cdc::token_range_description> result;
|
|
result.reserve(streams_count_per_vnode.size());
|
|
size_t vnode_index = 0;
|
|
int64_t token = std::numeric_limits<int64_t>::min() + 100;
|
|
for (size_t streams_count : streams_count_per_vnode) {
|
|
std::vector<cdc::stream_id> streams(streams_count);
|
|
token += 500;
|
|
for (size_t idx = 0; idx < streams_count; ++idx) {
|
|
streams[idx] = cdc::stream_id{dht::token::from_int64(token), vnode_index};
|
|
token += 100;
|
|
}
|
|
token += 10000;
|
|
// sharding_ignore_msb should not matter for limit_number_of_streams_if_needed
|
|
// so we're using sharding_ignore_msb equal to 12.
|
|
result.push_back(
|
|
cdc::token_range_description{dht::token::from_int64(token), std::move(streams), uint8_t{12}});
|
|
++vnode_index;
|
|
}
|
|
return cdc::topology_description(std::move(result));
|
|
}
|
|
|
|
static void assert_streams_count(const cdc::topology_description& desc, const std::vector<size_t>& expected_count) {
|
|
BOOST_REQUIRE_EQUAL(expected_count.size(), desc.entries().size());
|
|
|
|
for (size_t idx = 0; idx < expected_count.size(); ++idx) {
|
|
BOOST_REQUIRE_EQUAL(expected_count[idx], desc.entries()[idx].streams.size());
|
|
}
|
|
}
|
|
|
|
static void assert_stream_ids_in_right_token_ranges(const cdc::topology_description& desc) {
|
|
dht::token start = desc.entries().back().token_range_end;
|
|
dht::token end = desc.entries().front().token_range_end;
|
|
for (auto& stream : desc.entries().front().streams) {
|
|
dht::token t = stream.token();
|
|
if (t > end) {
|
|
BOOST_REQUIRE(start < t);
|
|
} else {
|
|
BOOST_REQUIRE(t <= end);
|
|
}
|
|
}
|
|
for (size_t idx = 1; idx < desc.entries().size(); ++idx) {
|
|
for (auto& stream : desc.entries()[idx].streams) {
|
|
BOOST_REQUIRE(desc.entries()[idx - 1].token_range_end < stream.token());
|
|
BOOST_REQUIRE(stream.token() <= desc.entries()[idx].token_range_end);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
cdc::stream_id get_stream(const utils::chunked_vector<cdc::token_range_description>& entries, dht::token tok);
|
|
|
|
static void assert_random_tokens_mapped_to_streams_with_tokens_in_the_same_token_range(const cdc::topology_description& desc) {
|
|
for (size_t count = 0; count < 100; ++count) {
|
|
int64_t token_value = tests::random::get_int(std::numeric_limits<int64_t>::min(), std::numeric_limits<int64_t>::max());
|
|
dht::token t = dht::token::from_int64(token_value);
|
|
auto stream = get_stream(desc.entries(), t);
|
|
auto& e = desc.entries().at(stream.index());
|
|
BOOST_REQUIRE(std::find(e.streams.begin(), e.streams.end(), stream) != e.streams.end());
|
|
if (stream.index() != 0) {
|
|
BOOST_REQUIRE(t <= e.token_range_end);
|
|
BOOST_REQUIRE(t > desc.entries().at(stream.index() - 1).token_range_end);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_cdc_generation_limitting_single_vnode_should_not_limit) {
|
|
cdc::topology_description given = create_description({cdc::limit_of_streams_in_topology_description()});
|
|
|
|
cdc::topology_description result = cdc::limit_number_of_streams_if_needed(std::move(given));
|
|
|
|
assert_streams_count(result, {cdc::limit_of_streams_in_topology_description()});
|
|
assert_stream_ids_in_right_token_ranges(result);
|
|
assert_random_tokens_mapped_to_streams_with_tokens_in_the_same_token_range(result);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_cdc_generation_limitting_single_vnode_should_limit) {
|
|
cdc::topology_description given = create_description({cdc::limit_of_streams_in_topology_description() + 1});
|
|
|
|
cdc::topology_description result = cdc::limit_number_of_streams_if_needed(std::move(given));
|
|
|
|
assert_streams_count(result, {cdc::limit_of_streams_in_topology_description()});
|
|
assert_stream_ids_in_right_token_ranges(result);
|
|
assert_random_tokens_mapped_to_streams_with_tokens_in_the_same_token_range(result);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_cdc_generation_limitting_multiple_vnodes_should_not_limit) {
|
|
size_t total = 0;
|
|
std::vector<size_t> streams_count_per_vnode;
|
|
size_t count_for_next_vnode = 1;
|
|
while (total + count_for_next_vnode <= cdc::limit_of_streams_in_topology_description()) {
|
|
streams_count_per_vnode.push_back(count_for_next_vnode);
|
|
total += count_for_next_vnode;
|
|
++count_for_next_vnode;
|
|
}
|
|
cdc::topology_description given = create_description(streams_count_per_vnode);
|
|
|
|
cdc::topology_description result = cdc::limit_number_of_streams_if_needed(std::move(given));
|
|
|
|
assert_streams_count(result, streams_count_per_vnode);
|
|
assert_stream_ids_in_right_token_ranges(result);
|
|
assert_random_tokens_mapped_to_streams_with_tokens_in_the_same_token_range(result);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(test_cdc_generation_limitting_multiple_vnodes_should_limit) {
|
|
size_t total = 0;
|
|
std::vector<size_t> streams_count_per_vnode;
|
|
size_t count_for_next_vnode = 1;
|
|
while (total + count_for_next_vnode <= cdc::limit_of_streams_in_topology_description()) {
|
|
streams_count_per_vnode.push_back(count_for_next_vnode);
|
|
total += count_for_next_vnode;
|
|
++count_for_next_vnode;
|
|
}
|
|
streams_count_per_vnode.push_back(cdc::limit_of_streams_in_topology_description() - total + 1);
|
|
cdc::topology_description given = create_description(streams_count_per_vnode);
|
|
|
|
cdc::topology_description result = cdc::limit_number_of_streams_if_needed(std::move(given));
|
|
|
|
assert(streams_count_per_vnode.size() <= cdc::limit_of_streams_in_topology_description());
|
|
size_t per_vnode_limit = cdc::limit_of_streams_in_topology_description() / streams_count_per_vnode.size();
|
|
for (auto& count : streams_count_per_vnode) {
|
|
count = std::min(count, per_vnode_limit);
|
|
}
|
|
|
|
assert_streams_count(result, streams_count_per_vnode);
|
|
assert_stream_ids_in_right_token_ranges(result);
|
|
assert_random_tokens_mapped_to_streams_with_tokens_in_the_same_token_range(result);
|
|
}
|
|
|