mirror of
https://github.com/scylladb/scylladb.git
synced 2026-05-23 00:02:37 +00:00
Add a Boost test to verify that `prepare_for_tablets_migration()` produces the correct tablet boundaries when a wrap-around vnode exists. Tablets cannot wrap around the token ring as vnodes do; the last token of the last tablet must always be MAX_TOKEN. When the last vnode token does not coincide with MAX_TOKEN, the wrap-around vnode must be split into two tablets. The test is parameterized over both cases: unaligned (split expected) and aligned (no split expected). Signed-off-by: Nikos Dragazis <nikolaos.dragazis@scylladb.com>
84 lines
3.2 KiB
C++
84 lines
3.2 KiB
C++
/*
|
|
* Copyright (C) 2026-present ScyllaDB
|
|
*/
|
|
|
|
/*
|
|
* SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.1
|
|
*/
|
|
|
|
#undef SEASTAR_TESTING_MAIN
|
|
#include <seastar/testing/test_case.hh>
|
|
#include <seastar/util/bool_class.hh>
|
|
|
|
#include "db/config.hh"
|
|
#include "test/lib/cql_test_env.hh"
|
|
#include "locator/tablets.hh"
|
|
#include "service/storage_service.hh"
|
|
|
|
using aligned_last_token = bool_class<class aligned_last_token_tag>;
|
|
|
|
BOOST_AUTO_TEST_SUITE(vnodes_to_tablets_migration_test)
|
|
|
|
// Verify creation of extra tablet for wrap-around vnodes.
|
|
//
|
|
// Tablets cannot wrap around the token ring as vnodes do; the last token of
|
|
// the last tablet must always be MAX_TOKEN. So, when we build the tablet map,
|
|
// if a wrap-around vnode exists (i.e., the last vnode token is not MAX_TOKEN),
|
|
// it needs to be split into two tablets: (last_vnode_token, last_token()] and
|
|
// [first_token(), first_vnode_token].
|
|
static future<> test_migration_tablet_boundaries(aligned_last_token aligned) {
|
|
std::vector<int64_t> tokens{-7686143364045646507, 0, 7158264828641642373}; // some random tokens
|
|
if (aligned) {
|
|
tokens.back() = dht::last_token().raw();
|
|
}
|
|
|
|
cql_test_config cfg;
|
|
auto initial_token = fmt::format("{}", fmt::join(tokens, ", "));
|
|
cfg.db_config->initial_token.set(std::move(initial_token));
|
|
|
|
return do_with_cql_env_thread([tokens, aligned] (cql_test_env& e) {
|
|
auto ks_name = sstring("test_migration_ks");
|
|
e.execute_cql(format("CREATE KEYSPACE {} "
|
|
"WITH replication = {{'class': 'NetworkTopologyStrategy', 'replication_factor': 1}} "
|
|
"AND tablets = {{'enabled': false}}", ks_name)).get();
|
|
|
|
e.execute_cql(format("CREATE TABLE {}.t (pk int PRIMARY KEY)", ks_name)).get();
|
|
auto tid = e.local_db().find_schema(ks_name, "t")->id();
|
|
|
|
e.get_storage_service().local().prepare_for_tablets_migration(ks_name).get();
|
|
|
|
auto& stm = e.local_db().get_shared_token_metadata();
|
|
auto& tmap = stm.get()->tablets().get_tablet_map(tid);
|
|
|
|
auto expected = std::vector<dht::token>{};
|
|
for (const auto& t : tokens) {
|
|
expected.push_back(dht::token(t));
|
|
}
|
|
if (!aligned) {
|
|
expected.push_back(dht::last_token());
|
|
}
|
|
|
|
auto actual = std::vector<dht::token>{};
|
|
for (size_t i = 0; i < tmap.tablet_count(); ++i) {
|
|
actual.push_back(tmap.get_last_token(locator::tablet_id(i)));
|
|
}
|
|
BOOST_TEST_INFO("actual: " << fmt::format("{}", fmt::join(actual, ", ")));
|
|
BOOST_TEST_INFO("expected: " << fmt::format("{}", fmt::join(expected, ", ")));
|
|
BOOST_REQUIRE_EQUAL_COLLECTIONS(actual.begin(), actual.end(), expected.begin(), expected.end());
|
|
}, cfg);
|
|
}
|
|
|
|
// When the last vnode token != MAX_TOKEN, the wrap-around vnode is split
|
|
// into two tablets. Expect one more tablet than vnodes.
|
|
SEASTAR_TEST_CASE(test_unaligned_last_token) {
|
|
return test_migration_tablet_boundaries(aligned_last_token::no);
|
|
}
|
|
|
|
// When the last vnode token == MAX_TOKEN, no split is needed.
|
|
// Expect exactly one tablet per vnode.
|
|
SEASTAR_TEST_CASE(test_aligned_last_token) {
|
|
return test_migration_tablet_boundaries(aligned_last_token::yes);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE_END()
|