diff --git a/locator/tablets.cc b/locator/tablets.cc index 5a732d80bf..11f80cc44c 100644 --- a/locator/tablets.cc +++ b/locator/tablets.cc @@ -105,6 +105,23 @@ void tablet_map::set_tablet_transition_info(tablet_id id, tablet_transition_info _transitions.insert_or_assign(id, std::move(info)); } +std::optional tablet_map::get_shard(tablet_id tid, host_id host) const { + auto&& info = get_tablet_info(tid); + + for (auto&& r : info.replicas) { + if (r.host == host) { + return r.shard; + } + } + + auto tinfo = get_tablet_transition_info(tid); + if (tinfo && tinfo->pending_replica.host == host) { + return tinfo->pending_replica.shard; + } + + return std::nullopt; +} + future<> tablet_map::clear_gently() { return utils::clear_gently(_tablets); } diff --git a/locator/tablets.hh b/locator/tablets.hh index ddb812cd15..385402c696 100644 --- a/locator/tablets.hh +++ b/locator/tablets.hh @@ -52,15 +52,6 @@ using tablet_replica_set = utils::small_vector; struct tablet_info { tablet_replica_set replicas; - std::optional get_shard(host_id host) const { - for (auto&& r : replicas) { - if (r.host == host) { - return r.shard; - } - } - return std::nullopt; - } - bool operator==(const tablet_info&) const = default; }; @@ -148,6 +139,12 @@ public: return tablet_id(size_t(t) + 1); } + /// Returns shard id which is a replica for a given tablet on a given host. + /// If there is no replica on a given host, returns nullopt. + /// If the topology is transitional, also considers the new replica set. + /// The old replica set is preferred in case of ambiguity. + std::optional get_shard(tablet_id, host_id) const; + const tablet_container& tablets() const { return _tablets; } diff --git a/test/boost/tablets_test.cc b/test/boost/tablets_test.cc index 81a6678d2f..4d95bbffe7 100644 --- a/test/boost/tablets_test.cc +++ b/test/boost/tablets_test.cc @@ -212,6 +212,57 @@ SEASTAR_TEST_CASE(test_tablet_metadata_persistence) { }, tablet_cql_test_config()); } +SEASTAR_TEST_CASE(test_get_shard) { + return do_with_cql_env_thread([] (cql_test_env& e) { + auto h1 = host_id(utils::UUID_gen::get_time_UUID()); + auto h2 = host_id(utils::UUID_gen::get_time_UUID()); + auto h3 = host_id(utils::UUID_gen::get_time_UUID()); + + auto table1 = table_id(utils::UUID_gen::get_time_UUID()); + + tablet_metadata tm; + tablet_id tid; + tablet_id tid1; + + { + tablet_map tmap(2); + tid = tmap.first_tablet(); + tmap.set_tablet(tid, tablet_info { + tablet_replica_set { + tablet_replica {h1, 0}, + tablet_replica {h3, 5}, + } + }); + tid1 = *tmap.next_tablet(tid); + tmap.set_tablet(tid1, tablet_info { + tablet_replica_set { + tablet_replica {h1, 2}, + tablet_replica {h3, 1}, + } + }); + tmap.set_tablet_transition_info(tid, tablet_transition_info { + tablet_replica_set { + tablet_replica {h1, 0}, + tablet_replica {h2, 3}, + }, + tablet_replica {h2, 3} + }); + tm.set_tablet_map(table1, std::move(tmap)); + } + + auto&& tmap = tm.get_tablet_map(table1); + + BOOST_REQUIRE_EQUAL(tmap.get_shard(tid1, h1), std::make_optional(shard_id(2))); + BOOST_REQUIRE(!tmap.get_shard(tid1, h2)); + BOOST_REQUIRE_EQUAL(tmap.get_shard(tid1, h3), std::make_optional(shard_id(1))); + + BOOST_REQUIRE_EQUAL(tmap.get_shard(tid, h1), std::make_optional(shard_id(0))); + BOOST_REQUIRE_EQUAL(tmap.get_shard(tid, h2), std::make_optional(shard_id(3))); + BOOST_REQUIRE_EQUAL(tmap.get_shard(tid, h3), std::make_optional(shard_id(5))); + + }, tablet_cql_test_config()); +} + SEASTAR_TEST_CASE(test_large_tablet_metadata) { return do_with_cql_env_thread([] (cql_test_env& e) { tablet_metadata tm;