mirror of
https://github.com/scylladb/scylladb.git
synced 2026-04-26 19:35:12 +00:00
208 lines
6.6 KiB
C++
208 lines
6.6 KiB
C++
/*
|
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
*
|
|
* Copyright (C) 2020-present ScyllaDB
|
|
*/
|
|
|
|
#include <any>
|
|
#include <seastar/core/sstring.hh>
|
|
#include <seastar/core/seastar.hh>
|
|
#include <seastar/core/smp.hh>
|
|
#include "log.hh"
|
|
#include "db/config.hh"
|
|
#include "gms/feature.hh"
|
|
#include "gms/feature_service.hh"
|
|
#include "db/system_keyspace.hh"
|
|
#include "db/query_context.hh"
|
|
#include "utils/to_string.hh"
|
|
#include <boost/algorithm/string/classification.hpp>
|
|
#include <boost/algorithm/string/split.hpp>
|
|
#include <boost/range/adaptor/map.hpp>
|
|
|
|
namespace gms {
|
|
|
|
static logging::logger logger("features");
|
|
|
|
feature_config::feature_config() {
|
|
}
|
|
|
|
feature_service::feature_service(feature_config cfg) : _config(cfg)
|
|
{}
|
|
|
|
feature_config feature_config_from_db_config(const db::config& cfg, std::set<sstring> disabled) {
|
|
feature_config fcfg;
|
|
|
|
fcfg._disabled_features = std::move(disabled);
|
|
|
|
switch (sstables::version_from_string(cfg.sstable_format())) {
|
|
case sstables::sstable_version_types::ka:
|
|
case sstables::sstable_version_types::la:
|
|
case sstables::sstable_version_types::mc:
|
|
fcfg._disabled_features.insert("MD_SSTABLE_FORMAT"s);
|
|
[[fallthrough]];
|
|
case sstables::sstable_version_types::md:
|
|
fcfg._disabled_features.insert("ME_SSTABLE_FORMAT"s);
|
|
[[fallthrough]];
|
|
case sstables::sstable_version_types::me:
|
|
break;
|
|
}
|
|
|
|
if (!cfg.enable_user_defined_functions()) {
|
|
fcfg._disabled_features.insert("UDF");
|
|
} else {
|
|
if (!cfg.check_experimental(db::experimental_features_t::feature::UDF)) {
|
|
throw std::runtime_error(
|
|
"You must use both enable_user_defined_functions and experimental_features:udf "
|
|
"to enable user-defined functions");
|
|
}
|
|
}
|
|
|
|
if (!cfg.check_experimental(db::experimental_features_t::feature::ALTERNATOR_STREAMS)) {
|
|
fcfg._disabled_features.insert("ALTERNATOR_STREAMS"s);
|
|
}
|
|
if (!cfg.consistent_cluster_management()) {
|
|
fcfg._disabled_features.insert("SUPPORTS_RAFT_CLUSTER_MANAGEMENT"s);
|
|
}
|
|
if (!cfg.check_experimental(db::experimental_features_t::feature::KEYSPACE_STORAGE_OPTIONS)) {
|
|
fcfg._disabled_features.insert("KEYSPACE_STORAGE_OPTIONS"s);
|
|
}
|
|
if (!cfg.check_experimental(db::experimental_features_t::feature::TABLETS)) {
|
|
fcfg._disabled_features.insert("TABLETS"s);
|
|
}
|
|
|
|
return fcfg;
|
|
}
|
|
|
|
future<> feature_service::stop() {
|
|
return make_ready_future<>();
|
|
}
|
|
|
|
void feature_service::register_feature(feature& f) {
|
|
auto i = _registered_features.emplace(f.name(), f);
|
|
assert(i.second);
|
|
}
|
|
|
|
void feature_service::unregister_feature(feature& f) {
|
|
_registered_features.erase(f.name());
|
|
}
|
|
|
|
|
|
std::set<std::string_view> feature_service::supported_feature_set() const {
|
|
// Add features known by this local node. When a new feature is
|
|
// introduced in scylla, update it here, e.g.,
|
|
// return sstring("FEATURE1,FEATURE2")
|
|
std::set<std::string_view> features = {
|
|
// Deprecated features - sent to other nodes via gossip, but assumed true in the code
|
|
"RANGE_TOMBSTONES"sv,
|
|
"LARGE_PARTITIONS"sv,
|
|
"COUNTERS"sv,
|
|
"DIGEST_MULTIPARTITION_READ"sv,
|
|
"CORRECT_COUNTER_ORDER"sv,
|
|
"SCHEMA_TABLES_V3"sv,
|
|
"CORRECT_NON_COMPOUND_RANGE_TOMBSTONES"sv,
|
|
"WRITE_FAILURE_REPLY"sv,
|
|
"XXHASH"sv,
|
|
"ROLES"sv,
|
|
"LA_SSTABLE_FORMAT"sv,
|
|
"STREAM_WITH_RPC_STREAM"sv,
|
|
"MATERIALIZED_VIEWS"sv,
|
|
"INDEXES"sv,
|
|
"ROW_LEVEL_REPAIR"sv,
|
|
"TRUNCATION_TABLE"sv,
|
|
"CORRECT_STATIC_COMPACT_IN_MC"sv,
|
|
"UNBOUNDED_RANGE_TOMBSTONES"sv,
|
|
"MC_SSTABLE_FORMAT"sv,
|
|
"LARGE_COLLECTION_DETECTION"sv,
|
|
};
|
|
|
|
for (auto& [name, f_ref] : _registered_features) {
|
|
features.insert(name);
|
|
}
|
|
|
|
for (const sstring& s : _config._disabled_features) {
|
|
features.erase(s);
|
|
}
|
|
return features;
|
|
}
|
|
|
|
const std::unordered_map<sstring, std::reference_wrapper<feature>>& feature_service::registered_features() const {
|
|
return _registered_features;
|
|
}
|
|
|
|
feature::feature(feature_service& service, std::string_view name, bool enabled)
|
|
: _service(&service)
|
|
, _name(name)
|
|
, _enabled(enabled) {
|
|
_service->register_feature(*this);
|
|
}
|
|
|
|
feature::~feature() {
|
|
if (_service) {
|
|
_service->unregister_feature(*this);
|
|
}
|
|
}
|
|
|
|
feature& feature::operator=(feature&& other) {
|
|
_service->unregister_feature(*this);
|
|
_service = std::exchange(other._service, nullptr);
|
|
_name = other._name;
|
|
_enabled = other._enabled;
|
|
_s = std::move(other._s);
|
|
_service->register_feature(*this);
|
|
return *this;
|
|
}
|
|
|
|
void feature::enable() {
|
|
if (!_enabled) {
|
|
if (this_shard_id() == 0) {
|
|
logger.info("Feature {} is enabled", name());
|
|
}
|
|
_enabled = true;
|
|
_s();
|
|
}
|
|
}
|
|
|
|
db::schema_features feature_service::cluster_schema_features() const {
|
|
db::schema_features f;
|
|
f.set_if<db::schema_feature::VIEW_VIRTUAL_COLUMNS>(view_virtual_columns);
|
|
f.set_if<db::schema_feature::DIGEST_INSENSITIVE_TO_EXPIRY>(digest_insensitive_to_expiry);
|
|
f.set_if<db::schema_feature::COMPUTED_COLUMNS>(computed_columns);
|
|
f.set_if<db::schema_feature::CDC_OPTIONS>(cdc);
|
|
f.set_if<db::schema_feature::PER_TABLE_PARTITIONERS>(per_table_partitioners);
|
|
f.set_if<db::schema_feature::SCYLLA_KEYSPACES>(keyspace_storage_options);
|
|
f.set_if<db::schema_feature::SCYLLA_AGGREGATES>(aggregate_storage_options);
|
|
return f;
|
|
}
|
|
|
|
std::set<sstring> feature_service::to_feature_set(sstring features_string) {
|
|
std::set<sstring> features;
|
|
boost::split(features, features_string, boost::is_any_of(","));
|
|
features.erase("");
|
|
return features;
|
|
}
|
|
|
|
void feature_service::persist_enabled_feature_info(const gms::feature& f) const {
|
|
// Executed in seastar::async context, because `gms::feature::enable`
|
|
// is only allowed to run within a thread context
|
|
|
|
std::set<sstring> feats_set = db::system_keyspace::load_local_enabled_features().get0();
|
|
feats_set.emplace(f.name());
|
|
db::system_keyspace::save_local_enabled_features(std::move(feats_set)).get0();
|
|
}
|
|
|
|
future<> feature_service::enable(std::set<std::string_view> list) {
|
|
// `gms::feature::enable` should be run within a seastar thread context
|
|
return seastar::async([this, list = std::move(list)] {
|
|
for (gms::feature& f : _registered_features | boost::adaptors::map_values) {
|
|
if (list.contains(f.name())) {
|
|
if (db::qctx && !f) {
|
|
persist_enabled_feature_info(f);
|
|
}
|
|
f.enable();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
} // namespace gms
|