[PATCH] Allow Seastar configuration in scylla.yaml

30 views
Skip to first unread message

rafie@scylladb.com

<rafie@scylladb.com>
unread,
Sep 24, 2018, 2:52:59 PM9/24/18
to scylladb-dev@googlegroups.com, Rafi Einstein
From: Rafi Einstein <ra...@scylladb.com>

Patch is enabled by the following:
- Custom app_template::configuration_reader to handle initial Scylla configuration,
- Seastar configuration items defined in db::config (using UsedFromSeastar category),
- Seastar program_options::variable_map config items are synched with Scylla db::config items
prior to Seastar initialization via app.run_deprecated(),
- Enabled reading config_file configuration items from text form.

This patch is preceded by a patch to Seastar to allow access to app_template::get_default_configuration_reader(),
and followed by a patch to enable configuration reloading via SIGHUP.
---
db/config.hh | 58 +++++++++++++
utils/config_file.hh | 41 +++++++--
utils/config_file_impl.hh | 23 +++--
db/config.cc | 19 +++-
main.cc | 56 +++++++++---
utils/config_file.cc | 216 ++++++++++++++++++++++++++++++++++++++++++----
6 files changed, 370 insertions(+), 43 deletions(-)

diff --git a/db/config.hh b/db/config.hh
index 698ddd88b..9e9451551 100644
--- a/db/config.hh
+++ b/db/config.hh
@@ -55,6 +55,8 @@ struct seed_provider_type {
}
sstring class_name;
std::unordered_map<sstring, sstring> parameters;
+
+ friend std::istream& operator>>(std::istream& is, db::seed_provider_type& self);
};

class config : public utils::config_file {
@@ -739,6 +741,62 @@ class config : public utils::config_file {
" Performance is affected to some extent as a result. Useful to help debugging problems that may arise at another layers.") \
val(cpu_scheduler, bool, true, Used, "Enable cpu scheduling") \
val(view_building, bool, true, Used, "Enable view building; should only be set to false when the node is experience issues due to view building") \
+ \
+ /* Seastar */ \
+ \
+ val(metrics_hostname, sstring, /**/, UsedFromSeastar, "set the hostname used by the metrics, if not set, the local hostname will be used") \
+ val(network_stack, sstring, /**/, UsedFromSeastar, "network stack") \
+ val(no_handle_interrupt, bool, false, UsedFromSeastar, "ignore SIGINT (for gdb)") \
+ val(poll_mode, bool, false, UsedFromSeastar, "poll continuously (100% cpu use)") \
+ val(idle_poll_time_us, unsigned, 200, UsedFromSeastar, "idle polling time in microseconds (reduce for overprovisioned environments or laptops)") \
+ val(poll_aio, bool, true, UsedFromSeastar, "busy-poll for disk I/O (reduces latency and increases throughput)") \
+ val(task_quota_ms, double, 0.5, UsedFromSeastar, "Max time (ms) between polls") \
+ val(max_task_backlog, unsigned, 1000, UsedFromSeastar, "Maximum number of task backlog to allow; above this we ignore I/O") \
+ val(blocked_reactor_notify_ms, unsigned, 2000, UsedFromSeastar, "threshold in miliseconds over which the reactor is considered blocked if no progress is made") \
+ val(blocked_reactor_reports_per_minute, unsigned, 5, UsedFromSeastar, "Maximum number of backtraces reported by stall detector per minute") \
+ val(relaxed_dma, bool, false, UsedFromSeastar, "allow using buffered I/O if DMA is not available (reduces performance)") \
+ val(unsafe_bypass_fsync, bool, false, UsedFromSeastar, "Bypass fsync(, may result in data loss. Use for testing on consumer drives") \
+ val(overprovisioned, bool, false, UsedFromSeastar, "run in an overprovisioned environment (such as docker or a laptop); equivalent to --idle-poll-time-us 0 --thread-affinity 0 --poll-aio 0") \
+ val(abort_on_seastar_bad_alloc, bool, false, UsedFromSeastar, "abort when seastar allocator cannot allocate memory") \
+ \
+ val(smp, unsigned, /**/, UsedFromSeastar, "number of threads (default: one per CPU)") \
+ val(cpuset, sstring, /**/, UsedFromSeastar, "CPUs to use (in cpuset(7) format; default: all))") \
+ val(memory, sstring, /**/, UsedFromSeastar, "memory to use, in bytes (ex: 4G) (default: all)") \
+ val(reserve_memory, sstring, /**/, UsedFromSeastar, "memory reserved to OS (if --memory not specified)") \
+ val(hugepages, sstring, /**/, UsedFromSeastar, "path to accessible hugetlbfs mount (typically /dev/hugepages/something)") \
+ val(lock_memory, bool, /**/, UsedFromSeastar, "lock all memory (prevents swapping)") \
+ val(thread_affinity, bool, true, UsedFromSeastar, "pin threads to their cpus (disable for overprovisioning)") \
+ val(num_io_queues, unsigned, /**/, UsedFromSeastar, "Number of IO queues. Each IO unit will be responsible for a fraction of the IO requests. Defaults to the number of threads") \
+ val(max_io_requests, unsigned, /**/, UsedFromSeastar, "Maximum amount of concurrent requests to be sent to the disk. Defaults to 128 times the number of IO queues") \
+ val(io_properties_file, sstring, /**/, UsedFromSeastar, "path to a YAML file describing the chraracteristics of the I/O Subsystem") \
+ val(io_properties, sstring, /**/, UsedFromSeastar, "a YAML string describing the chraracteristics of the I/O Subsystem") \
+ val(mbind, bool, true, UsedFromSeastar, "enable mbind") \
+ val(enable_glibc_exception_scaling_workaround, bool, true, UsedFromSeastar, "enable workaround for glibc/gcc c++ exception scalablity problem") \
+ \
+ val(collectd, bool, false, UsedFromSeastar, "enable collectd daemon") \
+ val(collectd_address, sstring, "239.192.74.66:25826", UsedFromSeastar, "address to send/broadcast metrics to") \
+ val(collectd_poll_period, unsigned, 1000, UsedFromSeastar, "poll period - frequency of sending counter metrics (default: 1000ms, 0 disables)") \
+ val(collectd_hostname, sstring, "", UsedFromSeastar, "Deprecated option, use metrics-hostname instead") \
+ \
+ val(dpdk_port_index, unsigned, 0, UsedFromSeastar, "DPDK Port Index") \
+ val(hw_fc, sstring, "on", UsedFromSeastar, "Enable HW Flow Control (on / off)") \
+ \
+ val(tap_device, sstring, "tap0", UsedFromSeastar, "tap device to connect to") \
+ val(host_ipv4_addr, sstring, "192.168.122.2", UsedFromSeastar, "static IPv4 address to use") \
+ val(gw_ipv4_addr, sstring, "192.168.122.1", UsedFromSeastar, "static IPv4 gateway to use") \
+ val(netmask_ipv4_addr, sstring, "255.255.255.0", UsedFromSeastar, "static IPv4 netmask to use") \
+ val(udpv4_queue_size, int, /* ipv4_udp::default_queue_size */, UsedFromSeastar, "Default size of the UDPv4 per-channel packet queue") \
+ val(dhcp, bool, true, UsedFromSeastar, "Use DHCP discovery") \
+ val(hw_queue_weight, float, 1.0f, UsedFromSeastar, "Weighing of a hardware network queue relative to a software queue (0=no work, 1=equal share)") \
+ val(dpdk_pmd, bool, false, UsedFromSeastar, "Use DPDK PMD drivers") \
+ val(lro, sstring, "on", UsedFromSeastar, "Enable LRO") \
+ \
+ val(event_index, sstring, "on", UsedFromSeastar, "Enable event-index feature (on / off)") \
+ val(csum_offload, sstring, "on", UsedFromSeastar, "Enable checksum offload feature (on / off)") \
+ val(tso, sstring, "on", UsedFromSeastar, "Enable TCP segment offload feature (on / off)") \
+ val(ufo, sstring, "on", UsedFromSeastar, "Enable UDP fragmentation offload feature (on / off)") \
+ val(virtio_ring_size, unsigned, 256, UsedFromSeastar, "Virtio ring size (must be power-of-two)") \
+ \
/* done! */

#define _make_value_member(name, type, deflt, status, desc, ...) \
diff --git a/utils/config_file.hh b/utils/config_file.hh
index ee421e167..47f576ede 100644
--- a/utils/config_file.hh
+++ b/utils/config_file.hh
@@ -48,9 +48,10 @@ class config_file {
typedef std::vector<sstring> string_list;

enum class value_status {
- Used,
+ UsedFromSeastar,
+ Used, // note that it is used as pivot in comparisons
Unused,
- Invalid,
+ Invalid
};

enum class config_source : uint8_t {
@@ -61,6 +62,8 @@ class config_file {

struct config_src {
stdx::string_view _name, _desc;
+ sstring _text;
+
public:
config_src(stdx::string_view name, stdx::string_view desc)
: _name(name)
@@ -74,11 +77,16 @@ class config_file {
const stdx::string_view & desc() const {
return _desc;
}
+ virtual sstring text_value() const {
+ return _text;
+ }

virtual void add_command_line_option(
bpo::options_description_easy_init&, const stdx::string_view&,
const stdx::string_view&) = 0;
+ virtual boost::any value() const = 0;
virtual void set_value(const YAML::Node&) = 0;
+ virtual void set_value(sstring) = 0;
virtual value_status status() const = 0;
virtual config_source source() const = 0;
};
@@ -90,6 +98,7 @@ class config_file {
stdx::string_view _name, _desc;
T _value = T();
config_source _source = config_source::None;
+
public:
typedef T type;
typedef named_value<T, S> MyType;
@@ -104,6 +113,9 @@ class config_file {
config_source source() const override {
return _source;
}
+ boost::any value() const override {
+ return _value;
+ }
bool is_set() const {
return _source > config_source::None;
}
@@ -128,6 +140,7 @@ class config_file {
void add_command_line_option(bpo::options_description_easy_init&,
const stdx::string_view&, const stdx::string_view&) override;
void set_value(const YAML::Node&) override;
+ void set_value(sstring) override;
};

typedef std::reference_wrapper<config_src> cfg_ref;
@@ -138,11 +151,10 @@ class config_file {
void add(std::initializer_list<cfg_ref>);
void add(const std::vector<cfg_ref> &);

- boost::program_options::options_description get_options_description();
- boost::program_options::options_description get_options_description(boost::program_options::options_description);
+ bpo::options_description get_options_description();
+ bpo::options_description get_options_description(bpo::options_description);

- boost::program_options::options_description_easy_init&
- add_options(boost::program_options::options_description_easy_init&);
+ bpo::options_description_easy_init& add_options(bpo::options_description_easy_init&);

/**
* Default behaviour for yaml parser is to throw on
@@ -161,6 +173,7 @@ class config_file {

void read_from_yaml(const sstring&, error_handler = {});
void read_from_yaml(const char *, error_handler = {});
+
future<> read_from_file(const sstring&, error_handler = {});
future<> read_from_file(file, error_handler = {});

@@ -171,12 +184,22 @@ class config_file {
const configs& values() const {
return _cfgs;
}
+
+ stdx::optional<cfg_ref> find(sstring name);
+
private:
- configs
- _cfgs;
+ configs _cfgs;
+
+public:
+ void set(sstring name, sstring value);
+
+ void print(sstring title = "Configuation", std::ostream& out = std::cout) const;
+ friend std::ostream& operator<<(std::ostream& out, const config_file::configs& cfg);
+
+ void sync(bpo::variables_map& opts);
};

extern template struct config_file::named_value<seastar::log_level, config_file::value_status::Used>;

-}
+} // namespace utils

diff --git a/utils/config_file_impl.hh b/utils/config_file_impl.hh
index eb81334f1..c807f4b7e 100644
--- a/utils/config_file_impl.hh
+++ b/utils/config_file_impl.hh
@@ -179,14 +179,12 @@ inline typed_value_ex<std::vector<T>>* value_ex(std::vector<T>* v) {
return r;
}

-}
+} // namespace

sstring hyphenate(const stdx::string_view&);

-}
-
template<typename T, utils::config_file::value_status S>
-void utils::config_file::named_value<T, S>::add_command_line_option(
+void config_file::named_value<T, S>::add_command_line_option(
boost::program_options::options_description_easy_init& init,
const stdx::string_view& name, const stdx::string_view& desc) {
// NOTE. We are not adding default values. We could, but must in that case manually (in some way) geenrate the textual
@@ -195,8 +193,21 @@ void utils::config_file::named_value<T, S>::add_command_line_option(
init(hyphenate(name).data(), value_ex(&_value)->notifier([this](auto&&) { _source = config_source::CommandLine; }), desc.data());
}

-template<typename T, utils::config_file::value_status S>
-void utils::config_file::named_value<T, S>::set_value(const YAML::Node& node) {
+template<typename T, config_file::value_status S>
+void config_file::named_value<T, S>::set_value(const YAML::Node& node) {
(*this)(node.as<T>());
+ if (node.IsScalar()) {
+ _text = node.as<sstring>();
+ }
+
_source = config_source::SettingsFile;
}
+
+template<typename T, config_file::value_status S>
+void config_file::named_value<T, S>::set_value(sstring val) {
+ (*this)(boost::lexical_cast<T>(val));
+ _text = val;
+ _source = config_source::SettingsFile;
+}
+
+} // namespace utils
diff --git a/db/config.cc b/db/config.cc
index 2f928db96..f7f611e97 100644
--- a/db/config.cc
+++ b/db/config.cc
@@ -80,13 +80,28 @@ struct convert<db::config::seed_provider_type> {

}

+namespace db {
+std::istream& operator>>(std::istream& is, db::seed_provider_type& self)
+{
+ YAML::Node node = YAML::Load(is);
+ YAML::convert<db::config::seed_provider_type>::decode(node, self);
+ return is;
+}
+
+}
+
#define _mk_name(name, ...) name,
#define str(x) #x
#define _mk_init(name, type, deflt, status, desc, ...) , name(str(name), type(deflt), desc)

db::config::config(std::shared_ptr<db::extensions> exts)
- : utils::config_file({ _make_config_values(_mk_name)
- default_log_level, logger_log_level, log_to_stdout, log_to_syslog })
+ : utils::config_file({
+ _make_config_values(_mk_name)
+ default_log_level,
+ logger_log_level,
+ log_to_stdout,
+ log_to_syslog
+ })
_make_config_values(_mk_init)
, default_log_level("default_log_level")
, logger_log_level("logger_log_level")
diff --git a/main.cc b/main.cc
index 0c416d0ea..3d1680140 100644
--- a/main.cc
+++ b/main.cc
@@ -52,6 +52,7 @@
#include <core/file.hh>
#include <sys/time.h>
#include <sys/resource.h>
+#include <boost/filesystem.hpp>
#include "disk-error-handler.hh"
#include "tracing/tracing.hh"
#include "core/prometheus.hh"
@@ -63,6 +64,7 @@
#include "sstables/compaction_manager.hh"
#include "sstables/sstables.hh"

+extern logging::logger configlog;
seastar::metrics::metric_groups app_metrics;

using namespace std::chrono_literals;
@@ -83,29 +85,61 @@ static boost::filesystem::path relative_conf_dir(boost::filesystem::path path) {
return conf_dir / path;
}

-static future<>
-read_config(bpo::variables_map& opts, db::config& cfg) {
+static boost::filesystem::path config_file_path(const bpo::variables_map& opts) {
using namespace boost::filesystem;
- sstring file;
-
- if (opts.count("options-file") > 0) {
- file = opts["options-file"].as<sstring>();
- } else {
- file = relative_conf_dir("scylla.yaml").string();
+ if (! opts.count("options-file")) {
+ return relative_conf_dir("scylla.yaml").string();
}
+ return std::string(opts["options-file"].as<sstring>());
+}
+
+#if 0 // will be back with configuration reloading
+
+static future<>
+read_config_async(boost::filesystem::path config_file, db::config& cfg) {
+ sstring file = config_file.string();
return check_direct_io_support(file).then([file, &cfg] {
return cfg.read_from_file(file, [](auto & opt, auto & msg, auto status) {
auto level = log_level::warn;
if (status.value_or(db::config::value_status::Invalid) != db::config::value_status::Invalid) {
level = log_level::error;
}
- startlog.log(level, "{} : {}", msg, opt);
+ configlog.log(level, "{} : {}", msg, opt);
});
}).handle_exception([file](auto ep) {
- startlog.error("Could not read configuration file {}: {}", file, ep);
+ configlog.error("Could not read configuration file {}: {}", file, ep);
return make_exception_future<>(ep);
});
}
+
+#endif
+
+static void
+read_config(boost::filesystem::path config_file, db::config& cfg) {
+ try {
+ std::ifstream ifs(config_file.string());
+ std::string yaml{std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>()};
+ cfg.read_from_yaml(yaml, [] (auto& opt, auto& msg, auto status) {
+ auto level = log_level::warn;
+ if (status.value_or(db::config::value_status::Invalid) != db::config::value_status::Invalid) {
+ level = log_level::error;
+ }
+ configlog.log(level, "{} : {}", msg, opt);
+ });
+ } catch (std::exception ep) {
+ configlog.error("Could not read configuration file {}: {}", config_file.string(), ep);
+ }
+}
+
+app_template::configuration_reader
+app_config_reader(app_template& app, db::config& db_config) {
+ return [&] (bpo::variables_map& configuration) {
+ app.get_default_configuration_reader()(configuration);
+ read_config(config_file_path(configuration), db_config);
+ db_config.sync(configuration);
+ };
+}
+
static future<> disk_sanity(sstring path, bool developer_mode) {
return check_direct_io_support(path).then([] {
return make_ready_future<>();
@@ -297,6 +331,7 @@ int main(int ac, char** av) {

auto ext = std::make_shared<db::extensions>();
auto cfg = make_lw_shared<db::config>(ext);
+ app.set_configuration_reader(app_config_reader(app, *cfg));
auto init = app.get_options_description().add_options();

// If --version is requested, print it out and exit immediately to avoid
@@ -359,7 +394,6 @@ int main(int ac, char** av) {
tcp_syncookies_sanity();

return seastar::async([cfg, ext, &db, &qp, &proxy, &mm, &ctx, &opts, &dirs, &pctx, &prometheus_server, &return_value, &cf_cache_hitrate_calculator] {
- read_config(opts, *cfg).get();
configurable::init_all(opts, *cfg, *ext).get();

logalloc::prime_segment_pool(memory::stats().total_memory(), memory::min_free_memory()).get();
diff --git a/utils/config_file.cc b/utils/config_file.cc
index c79668288..24f0d8f25 100644
--- a/utils/config_file.cc
+++ b/utils/config_file.cc
@@ -36,9 +36,13 @@
#include <seastar/core/do_with.hh>
#include <seastar/core/print.hh>

+#include "log.hh"
+
#include "config_file.hh"
#include "config_file_impl.hh"

+logging::logger configlog("config");
+
namespace bpo = boost::program_options;

template<>
@@ -197,43 +201,51 @@ std::istream& std::operator>>(std::istream& is, std::vector<seastar::sstring>& r

return is;
}
+
template std::istream& std::operator>>(std::istream&, std::unordered_map<seastar::sstring, seastar::sstring>&);

-sstring utils::hyphenate(const stdx::string_view& v) {
+namespace utils {
+
+sstring hyphenate(const stdx::string_view& v) {
sstring result(v.begin(), v.end());
std::replace(result.begin(), result.end(), '_', '-');
return result;
}

-utils::config_file::config_file(std::initializer_list<cfg_ref> cfgs)
- : _cfgs(cfgs)
+sstring dehyphenate(const stdx::string_view& v) {
+ sstring result(v.begin(), v.end());
+ std::replace(result.begin(), result.end(), '-', '_');
+ return result;
+}
+
+config_file::config_file(std::initializer_list<cfg_ref> cfgs) : _cfgs(cfgs)
{}

-void utils::config_file::add(cfg_ref cfg) {
+void config_file::add(cfg_ref cfg) {
_cfgs.emplace_back(cfg);
}

-void utils::config_file::add(std::initializer_list<cfg_ref> cfgs) {
+void config_file::add(std::initializer_list<cfg_ref> cfgs) {
_cfgs.insert(_cfgs.end(), cfgs.begin(), cfgs.end());
}

-void utils::config_file::add(const std::vector<cfg_ref> & cfgs) {
+void config_file::add(const std::vector<cfg_ref>& cfgs) {
_cfgs.insert(_cfgs.end(), cfgs.begin(), cfgs.end());
}

-bpo::options_description utils::config_file::get_options_description() {
+bpo::options_description config_file::get_options_description() {
bpo::options_description opts("");
return get_options_description(opts);
}

-bpo::options_description utils::config_file::get_options_description(boost::program_options::options_description opts) {
+bpo::options_description config_file::get_options_description(boost::program_options::options_description opts) {
auto init = opts.add_options();
add_options(init);
return std::move(opts);
}

bpo::options_description_easy_init&
-utils::config_file::add_options(bpo::options_description_easy_init& init) {
+config_file::add_options(bpo::options_description_easy_init& init) {
for (config_src& src : _cfgs) {
if (src.status() == value_status::Used) {
auto&& name = src.name();
@@ -245,11 +257,11 @@ utils::config_file::add_options(bpo::options_description_easy_init& init) {
return init;
}

-void utils::config_file::read_from_yaml(const sstring& yaml, error_handler h) {
+void config_file::read_from_yaml(const sstring& yaml, error_handler h) {
read_from_yaml(yaml.c_str(), std::move(h));
}

-void utils::config_file::read_from_yaml(const char* yaml, error_handler h) {
+void config_file::read_from_yaml(const char* yaml, error_handler h) {
std::unordered_map<sstring, cfg_ref> values;

if (!h) {
@@ -302,13 +314,13 @@ void utils::config_file::read_from_yaml(const char* yaml, error_handler h) {
}
}

-utils::config_file::configs utils::config_file::set_values() const {
+config_file::configs config_file::set_values() const {
return boost::copy_range<configs>(_cfgs | boost::adaptors::filtered([] (const config_src& cfg) {
return cfg.status() > value_status::Used || cfg.source() > config_source::None;
}));
}

-utils::config_file::configs utils::config_file::unset_values() const {
+config_file::configs config_file::unset_values() const {
configs res;
for (config_src& cfg : _cfgs) {
if (cfg.status() > value_status::Used) {
@@ -322,7 +334,7 @@ utils::config_file::configs utils::config_file::unset_values() const {
return res;
}

-future<> utils::config_file::read_from_file(file f, error_handler h) {
+future<> config_file::read_from_file(file f, error_handler h) {
return f.size().then([this, f, h](size_t s) {
return do_with(make_file_input_stream(f), [this, s, h](input_stream<char>& in) {
return in.read_exactly(s).then([this, h](temporary_buffer<char> buf) {
@@ -332,11 +344,185 @@ future<> utils::config_file::read_from_file(file f, error_handler h) {
});
}

-future<> utils::config_file::read_from_file(const sstring& filename, error_handler h) {
+future<> config_file::read_from_file(const sstring& filename, error_handler h) {
return open_file_dma(filename, open_flags::ro).then([this, h](file f) {
return read_from_file(std::move(f), h);
});
}

+stdx::optional<config_file::cfg_ref> config_file::find(sstring name) {
+ for (auto& ci: values()) {
+ auto& c = ci.get();
+ if (c.name() == name) {
+ return ci;
+ }
+ }
+ return stdx::nullopt;
+}

+void config_file::print(sstring title, std::ostream& out) const {
+ if (!title.empty()) {
+ out << title << ":\n";
+ }
+ out << _cfgs;
+}
+
+std::ostream& operator<<(std::ostream& out, const config_file::configs& cfg) {
+ for (auto& ci: cfg) {
+ auto& c = ci.get();
+ sstring source;
+ switch (c.source()) {
+ case config_file::config_source::None:
+ source = "none";
+ continue;
+ case config_file::config_source::SettingsFile:
+ source = "yaml";
+ break;
+ case config_file::config_source::CommandLine:
+ source = "cmdline";
+ break;
+ };
+ out << "> " << c.name() << ": " << source << ": " << c.text_value() << "\n";
+ }
+ out << "---\n";
+ return out;
+}
+
+// boost::any to be re-assigned to its original type
+
+template <class T>
+void any_compat_set(boost::any& a, T&& b) {
+ auto& t = a.type();
+ if (t == typeid(std::string)) {
+ a = boost::lexical_cast<std::string>(b);
+ } else if (t == typeid(seastar::sstring)) {
+ a = boost::lexical_cast<sstring>(b);
+ } else if (t == typeid(int)) {
+ a = boost::lexical_cast<int>(b);
+ } else if (t == typeid(int32_t)) {
+ a = boost::lexical_cast<int32_t>(b);
+ } else if (t == typeid(uint32_t)) {
+ a = boost::lexical_cast<uint32_t>(b);
+ } else if (t == typeid(int64_t)) {
+ a = boost::lexical_cast<int64_t>(b);
+ } else if (t == typeid(unsigned)) {
+ a = boost::lexical_cast<unsigned>(b);
+ } else if (t == typeid(bool)) {
+ a = boost::lexical_cast<bool>(b);
+ } else if (t == typeid(float)) {
+ a = boost::lexical_cast<float>(b);
+ } else if (t == typeid(double)) {
+ a = boost::lexical_cast<double>(b);
+ } else {
+ throw boost::bad_lexical_cast(typeid(b), t);
+ }
+}
+
+static sstring
+to_sstring(const bpo::variable_value& v) {
+ boost::any a = v.value();
+ auto& t = a.type();
+
+ sstring s;
+ if (t == typeid(std::string)) {
+ s = v.as<std::string>();
+ } else if (t == typeid(seastar::sstring)) {
+ s = v.as<sstring>();
+ } else if (t == typeid(int)) {
+ s = boost::lexical_cast<std::string>(v.as<int>());
+ } else if (t == typeid(int32_t)) {
+ s = boost::lexical_cast<std::string>(v.as<int32_t>());
+ } else if (t == typeid(uint32_t)) {
+ s = boost::lexical_cast<std::string>(v.as<uint32_t>());
+ } else if (t == typeid(int64_t)) {
+ s = boost::lexical_cast<std::string>(v.as<int64_t>());
+ } else if (t == typeid(unsigned)) {
+ s = boost::lexical_cast<std::string>(v.as<unsigned>());
+ } else if (t == typeid(bool)) {
+ s = boost::lexical_cast<std::string>(v.as<bool>());
+ } else if (t == typeid(float)) {
+ s = boost::lexical_cast<std::string>(v.as<float>());
+ } else if (t == typeid(double)) {
+ s = boost::lexical_cast<std::string>(v.as<double>());
+ } else {
+ throw boost::bad_lexical_cast(t, typeid(sstring));
+ }
+
+ return s;
+}
+
+void config_file::sync(bpo::variables_map& opts) {
+ // opts->config: opts should override existing config
+ sstring item_name;
+
+ for (auto opt_i: opts) {
+ try {
+ auto& opt_name = opt_i.first;
+ auto& opt = opt_i.second;
+
+ item_name = opt_name;
+
+ if (opt.empty() || opt.defaulted()) {
+ continue;
+ }
+
+ auto cfg_name{dehyphenate(opt_name)};
+ stdx::optional<cfg_ref> cfg_item = find(cfg_name);
+ if (!cfg_item) {
+ continue;
+ }
+ sstring opt_sval;
+ try {
+ opt_sval = to_sstring(opt);
+ } catch (...) {
+ continue;
+ }
+
+ auto cfg_sval = cfg_item->get().text_value();
+ if (cfg_sval == opt_sval) {
+ continue;
+ }
+ configlog.info("sync opts->yaml: {}={} [was {}]", opt_name, opt_sval, cfg_sval);
+ cfg_item->get().set_value(opt_sval);
+ } catch (...) {
+ configlog.error("sync opt->yaml: problem with {}", item_name);
+ }
+ }
+
+ // config->opts: set if config is present in file (not by default) and opt is missing
+ for (auto& cfg_i: values()) {
+ try {
+ auto& cfg = cfg_i.get();
+
+ sstring cfg_name{cfg.name()};
+ auto opt_name = hyphenate(cfg_name);
+ item_name = opt_name;
+
+ auto& opt = opts[opt_name];
+ if (! (opt.empty() || opt.defaulted())) {
+ continue;
+ }
+
+ sstring opt_sval;
+ try {
+ opt_sval = to_sstring(opt);
+ } catch (...) {}
+
+ if (cfg.source() == config_source::SettingsFile && cfg.status() == value_status::UsedFromSeastar) {
+ auto cfg_sval = cfg.text_value();
+ if (cfg_sval != opt_sval) {
+ configlog.info("sync yaml->opts: {}={} [was {}]", cfg_name, cfg_sval, opt_sval);
+ try {
+ any_compat_set(opts.at(std::string(opt_name)).value(), cfg_sval);
+ } catch (...) {
+ opts.insert(std::make_pair(opt_name, bpo::variable_value(cfg.value(), false)));
+ }
+ }
+ }
+ } catch (...) {
+ configlog.error("sync yaml->opt: problem with {}", item_name);
+ }
+ }
+}

+} // namespace utils
--
2.14.4

Calle Wilund

<calle@scylladb.com>
unread,
Sep 25, 2018, 3:52:33 AM9/25/18
to scylladb-dev@googlegroups.com
I have serious issues with this.

Why do you put seastar options in scyllas db::config object? They have
no business being there.

There already is a feature to allow extending configuration reading in
the "configurable" framework, used by extensions.

If you want to allow seastar parameters in scylla.yaml, this is where
you should hook processing them in. Right now, you are mixing config
apples and oranges.

Avi Kivity

<avi@scylladb.com>
unread,
Sep 25, 2018, 4:23:13 AM9/25/18
to rafie@scylladb.com, scylladb-dev@googlegroups.com
Rather than duplicating every Seastar configuration item here (and
updating it every time something changes), Seastar should expose a
configuration hierarchy which Scylla should use to populate its own
configuration.
Reply all
Reply to author
Forward
0 new messages