locator: Introduce per-table replication strategy

Will be used by tablet-based replication strategies, for which
effective replication map is different per table.

Also, this patch adapts existing users of effective replication map to
use the per-table effective replication map.

For simplicity, every table has an effective replication map, even if
the erm is per keyspace. This way the client code can be uniform and
doesn't have to check whether replication strategy is per table.

Not all users of per-keyspace get_effective_replication_map() are
adapted yet to work per-table. Those algorithms will throw an
exception when invoked on a keyspace which uses per-table replication
strategy.
This commit is contained in:
Tomasz Grabiec
2023-03-22 00:24:10 +01:00
parent 5d9bcb45de
commit 9b17ad3771
16 changed files with 131 additions and 44 deletions

View File

@@ -107,6 +107,13 @@ inet_address_vector_topology_change vnode_effective_replication_map::get_pending
return _tmptr->pending_endpoints_for(search_token, ks_name);
}
const per_table_replication_strategy* abstract_replication_strategy::maybe_as_per_table() const {
if (!_per_table) {
return nullptr;
}
return dynamic_cast<const per_table_replication_strategy*>(this);
}
void abstract_replication_strategy::validate_replication_factor(sstring rf)
{
if (rf.empty() || std::any_of(rf.begin(), rf.end(), [] (char c) {return !isdigit(c);})) {

View File

@@ -51,12 +51,15 @@ using endpoint_set = utils::basic_sequenced_set<inet_address, inet_address_vecto
class vnode_effective_replication_map;
class effective_replication_map_factory;
class per_table_replication_strategy;
class abstract_replication_strategy {
friend class vnode_effective_replication_map;
friend class per_table_replication_strategy;
protected:
replication_strategy_config_options _config_options;
replication_strategy_type _my_type;
bool _per_table = false;
template <typename... Args>
void err(const char* fmt, Args&&... args) const {
@@ -117,6 +120,15 @@ public:
replication_strategy_type get_type() const noexcept { return _my_type; }
const replication_strategy_config_options get_config_options() const noexcept { return _config_options; }
// If returns true then tables governed by this replication strategy have separate
// effective_replication_maps.
// If returns false, they share the same effective_replication_map, which is per keyspace.
// If returns true, then this replication strategy extends per_table_replication_strategy.
// Note, a replication strategy may extend per_table_replication_strategy while !is_per_table(),
// depending on actual strategy options.
bool is_per_table() const { return _per_table; }
const per_table_replication_strategy* maybe_as_per_table() const;
// Use the token_metadata provided by the caller instead of _token_metadata
// Note: must be called with initialized, non-empty token_metadata.
future<dht::token_range_vector> get_ranges(inet_address ep, token_metadata_ptr tmptr) const;
@@ -177,6 +189,21 @@ public:
using effective_replication_map_ptr = seastar::shared_ptr<const effective_replication_map>;
using mutable_effective_replication_map_ptr = seastar::shared_ptr<effective_replication_map>;
/// Replication strategies which support per-table replication extend this trait.
///
/// It will be accessed only if the replication strategy actually works in per-table mode,
/// that is after mark_as_per_table() is called, and as a result
/// abstract_replication_strategy::is_per_table() returns true.
class per_table_replication_strategy {
protected:
void mark_as_per_table(abstract_replication_strategy& self) {
self._per_table = true;
}
public:
virtual ~per_table_replication_strategy() = default;
virtual effective_replication_map_ptr make_replication_map(table_id, token_metadata_ptr) const = 0;
};
// Holds the full replication_map resulting from applying the
// effective replication strategy over the given token_metadata
// and replication_strategy_config_options.