template<LockPolicy lp>
md_config_impl<lp>::md_config_impl(ConfigValues& values,
+ const ConfigTracker& tracker,
bool is_daemon)
: is_daemon(is_daemon)
{
if (val != *def_str) {
// if the validator normalizes the string into a different form than
// what was compiled in, use that.
- set_val_default(values, opt.name, val);
+ set_val_default(values, tracker, opt.name, val);
}
}
}
template<LockPolicy lp>
void md_config_impl<lp>::set_val_default(ConfigValues& values,
+ const ConfigTracker& tracker,
const string& name, const std::string& val)
{
const Option *o = find_option(name);
assert(o);
string err;
- int r = _set_val(values, val, *o, CONF_DEFAULT, &err);
+ int r = _set_val(values, tracker, val, *o, CONF_DEFAULT, &err);
assert(r >= 0);
}
template<LockPolicy lp>
int md_config_impl<lp>::set_mon_vals(CephContext *cct,
ConfigValues& values,
+ const ConfigTracker& tracker,
const map<string,string>& kv,
config_callback config_cb)
{
continue;
}
std::string err;
- int r = _set_val(values, i.second, *o, CONF_MON, &err);
+ int r = _set_val(values, tracker, i.second, *o, CONF_MON, &err);
if (r < 0) {
lderr(cct) << __func__ << " failed to set " << i.first << " = "
<< i.second << ": " << err << dendl;
return 0;
}
-template<LockPolicy lp>
-void md_config_impl<lp>::add_observer(md_config_obs_impl<lp>* observer_)
-{
- const char **keys = observer_->get_tracked_conf_keys();
- for (const char ** k = keys; *k; ++k) {
- observers.emplace(*k, observer_);
- }
-}
-
-template<LockPolicy lp>
-void md_config_impl<lp>::remove_observer(md_config_obs_impl<lp>* observer_)
-{
- bool found_obs = false;
- for (auto o = observers.begin(); o != observers.end(); ) {
- if (o->second == observer_) {
- observers.erase(o++);
- found_obs = true;
- }
- else {
- ++o;
- }
- }
- assert(found_obs);
-}
-
template<LockPolicy lp>
int md_config_impl<lp>::parse_config_files(ConfigValues& values,
+ const ConfigTracker& tracker,
const char *conf_files_str,
std::ostream *warnings,
int flags)
int ret = _get_val_from_conf_file(my_sections, opt.name, val);
if (ret == 0) {
std::string error_message;
- int r = _set_val(values, val, opt, CONF_FILE, &error_message);
+ int r = _set_val(values, tracker, val, opt, CONF_FILE, &error_message);
if (warnings != nullptr && (r < 0 || !error_message.empty())) {
*warnings << "parse error setting '" << opt.name << "' to '" << val
<< "'";
}
template<LockPolicy lp>
-void md_config_impl<lp>::parse_env(ConfigValues& values, const char *args_var)
+void md_config_impl<lp>::parse_env(ConfigValues& values,
+ const ConfigTracker& tracker,
+ const char *args_var)
{
if (safe_to_start_threads)
return;
args_var = "CEPH_ARGS";
}
if (getenv("CEPH_KEYRING")) {
- _set_val(values, getenv("CEPH_KEYRING"), *find_option("keyring"),
+ _set_val(values, tracker, getenv("CEPH_KEYRING"), *find_option("keyring"),
CONF_ENV, nullptr);
}
if (const char *dir = getenv("CEPH_LIB")) {
std::string err;
const Option *o = find_option(name);
assert(o);
- _set_val(values, dir, *o, CONF_ENV, &err);
+ _set_val(values, tracker, dir, *o, CONF_ENV, &err);
}
}
if (getenv(args_var)) {
vector<const char *> env_args;
env_to_vec(env_args, args_var);
- parse_argv(values, env_args, CONF_ENV);
+ parse_argv(values, tracker, env_args, CONF_ENV);
}
}
template<LockPolicy lp>
int md_config_impl<lp>::parse_argv(ConfigValues& values,
+ const ConfigTracker& tracker,
std::vector<const char*>& args, int level)
{
if (safe_to_start_threads) {
values.no_mon_config = false;
}
else if (ceph_argparse_flag(args, i, "--foreground", "-f", (char*)NULL)) {
- set_val_or_die(values, "daemonize", "false");
+ set_val_or_die(values, tracker, "daemonize", "false");
}
else if (ceph_argparse_flag(args, i, "-d", (char*)NULL)) {
- set_val_or_die(values, "daemonize", "false");
- set_val_or_die(values, "log_file", "");
- set_val_or_die(values, "log_to_stderr", "true");
- set_val_or_die(values, "err_to_stderr", "true");
- set_val_or_die(values, "log_to_syslog", "false");
+ set_val_or_die(values, tracker, "daemonize", "false");
+ set_val_or_die(values, tracker, "log_file", "");
+ set_val_or_die(values, tracker, "log_to_stderr", "true");
+ set_val_or_die(values, tracker, "err_to_stderr", "true");
+ set_val_or_die(values, tracker, "log_to_syslog", "false");
}
// Some stuff that we wanted to give universal single-character options for
// Careful: you can burn through the alphabet pretty quickly by adding
// to this list.
else if (ceph_argparse_witharg(args, i, &val, "--monmap", "-M", (char*)NULL)) {
- set_val_or_die(values, "monmap", val.c_str());
+ set_val_or_die(values, tracker, "monmap", val.c_str());
}
else if (ceph_argparse_witharg(args, i, &val, "--mon_host", "-m", (char*)NULL)) {
- set_val_or_die(values, "mon_host", val.c_str());
+ set_val_or_die(values, tracker, "mon_host", val.c_str());
}
else if (ceph_argparse_witharg(args, i, &val, "--bind", (char*)NULL)) {
- set_val_or_die(values, "public_addr", val.c_str());
+ set_val_or_die(values, tracker, "public_addr", val.c_str());
}
else if (ceph_argparse_witharg(args, i, &val, "--keyfile", "-K", (char*)NULL)) {
bufferlist bl;
}
if (r >= 0) {
string k(bl.c_str(), bl.length());
- set_val_or_die(values, "key", k.c_str());
+ set_val_or_die(values, tracker, "key", k.c_str());
}
}
else if (ceph_argparse_witharg(args, i, &val, "--keyring", "-k", (char*)NULL)) {
- set_val_or_die(values, "keyring", val.c_str());
+ set_val_or_die(values, tracker, "keyring", val.c_str());
}
else if (ceph_argparse_witharg(args, i, &val, "--client_mountpoint", "-r", (char*)NULL)) {
- set_val_or_die(values, "client_mountpoint", val.c_str());
+ set_val_or_die(values, tracker, "client_mountpoint", val.c_str());
}
else {
- int r = parse_option(values, args, i, NULL, level);
+ int r = parse_option(values, tracker, args, i, NULL, level);
if (r < 0) {
return r;
}
template<LockPolicy lp>
int md_config_impl<lp>::parse_option(ConfigValues& values,
+ const ConfigTracker& tracker,
std::vector<const char*>& args,
std::vector<const char*>::iterator& i,
ostream *oss,
if (ceph_argparse_binary_flag(args, i, &res, oss, as_option.c_str(),
(char*)NULL)) {
if (res == 0)
- ret = _set_val(values, "false", opt, level, &error_message);
+ ret = _set_val(values, tracker, "false", opt, level, &error_message);
else if (res == 1)
- ret = _set_val(values, "true", opt, level, &error_message);
+ ret = _set_val(values, tracker, "true", opt, level, &error_message);
else
ret = res;
break;
std::string no("--no-");
no += opt.name;
if (ceph_argparse_flag(args, i, no.c_str(), (char*)NULL)) {
- ret = _set_val(values, "false", opt, level, &error_message);
+ ret = _set_val(values, tracker, "false", opt, level, &error_message);
break;
}
}
ret = -EINVAL;
break;
}
- ret = _set_val(values, val, opt, level, &error_message);
+ ret = _set_val(values, tracker, val, opt, level, &error_message);
break;
}
++o;
template<LockPolicy lp>
int md_config_impl<lp>::parse_injectargs(ConfigValues& values,
+ const ConfigTracker& tracker,
std::vector<const char*>& args,
std::ostream *oss)
{
int ret = 0;
for (std::vector<const char*>::iterator i = args.begin(); i != args.end(); ) {
- int r = parse_option(values, args, i, oss, CONF_OVERRIDE);
+ int r = parse_option(values, tracker, args, i, oss, CONF_OVERRIDE);
if (r < 0)
ret = r;
}
return ret;
}
-template<LockPolicy lp>
-void md_config_impl<lp>::apply_changes(ConfigValues& values,
- const ConfigProxy& proxy,
- std::ostream *oss)
-{
- /*
- * apply changes until the cluster name is assigned
- */
- if (values.cluster.size()) {
- // meta expands could have modified anything. Copy it all out again.
- update_legacy_vals(values);
- _apply_changes(values, proxy, oss);
- }
-}
-
-template<LockPolicy lp>
-void md_config_impl<lp>::_apply_changes(ConfigValues& values,
- const ConfigProxy& proxy,
- std::ostream *oss)
-{
- /* Maps observers to the configuration options that they care about which
- * have changed. */
- typedef std::map < md_config_obs_t*, std::set <std::string> > rev_obs_map_t;
-
- // create the reverse observer mapping, mapping observers to the set of
- // changed keys that they'll get.
- rev_obs_map_t robs;
- std::set <std::string> empty_set;
- string val;
- for (changed_set_t::const_iterator c = changed.begin();
- c != changed.end(); ++c) {
- const std::string &key(*c);
- auto [first, last] = observers.equal_range(key);
- if ((oss) && !conf_stringify(_get_val(values, key), &val)) {
- (*oss) << key << " = '" << val << "' ";
- if (first == last) {
- (*oss) << "(not observed, change may require restart) ";
- }
- }
- for (auto r = first; r != last; ++r) {
- rev_obs_map_t::value_type robs_val(r->second, empty_set);
- pair < rev_obs_map_t::iterator, bool > robs_ret(robs.insert(robs_val));
- std::set <std::string> &keys(robs_ret.first->second);
- keys.insert(key);
- }
- }
-
- changed.clear();
-
- // Make any pending observer callbacks
- for (rev_obs_map_t::const_iterator r = robs.begin(); r != robs.end(); ++r) {
- md_config_obs_t *obs = r->first;
- obs->handle_conf_change(proxy, r->second);
- }
-}
-
-template<LockPolicy lp>
-void md_config_impl<lp>::call_all_observers(const ConfigProxy& proxy)
-{
- std::map<md_config_obs_t*,std::set<std::string> > obs;
- // Have the scope of the lock extend to the scope of
- // handle_conf_change since that function expects to be called with
- // the lock held. (And the comment in config.h says that is the
- // expected behavior.)
- //
- // An alternative might be to pass a std::unique_lock to
- // handle_conf_change and have a version of get_var that can take it
- // by reference and lock as appropriate.
- {
- for (auto r = observers.begin(); r != observers.end(); ++r) {
- obs[r->second].insert(r->first);
- }
- }
- for (auto p = obs.begin();
- p != obs.end();
- ++p) {
- p->first->handle_conf_change(proxy, p->second);
- }
-}
-
template<LockPolicy lp>
void md_config_impl<lp>::set_safe_to_start_threads()
{
template<LockPolicy lp>
int md_config_impl<lp>::injectargs(ConfigValues& values,
+ const ConfigTracker& tracker,
const std::string& s, std::ostream *oss)
{
int ret;
*p++ = 0;
while (*p && *p == ' ') p++;
}
- ret = parse_injectargs(values, nargs, oss);
+ ret = parse_injectargs(values, tracker, nargs, oss);
if (!nargs.empty()) {
*oss << " failed to parse arguments: ";
std::string prefix;
template<LockPolicy lp>
void md_config_impl<lp>::set_val_or_die(ConfigValues& values,
+ const ConfigTracker& tracker,
const std::string &key,
const std::string &val)
{
std::stringstream err;
- int ret = set_val(values, key, val, &err);
+ int ret = set_val(values, tracker, key, val, &err);
if (ret != 0) {
std::cerr << "set_val_or_die(" << key << "): " << err.str();
}
template<LockPolicy lp>
int md_config_impl<lp>::set_val(ConfigValues& values,
+ const ConfigTracker& tracker,
const std::string &key, const char *val,
std::stringstream *err_ss)
{
if (opt_iter != schema.end()) {
const Option &opt = opt_iter->second;
std::string error_message;
- int r = _set_val(values, v, opt, CONF_OVERRIDE, &error_message);
+ int r = _set_val(values, tracker, v, opt, CONF_OVERRIDE, &error_message);
if (r >= 0) {
if (err_ss) *err_ss << "Set " << opt.name << " to " << v;
r = 0;
}
template<LockPolicy lp>
-void md_config_impl<lp>::finalize_reexpand_meta(ConfigValues& values,
- const ConfigProxy& proxy)
+bool md_config_t::finalize_reexpand_meta(ConfigValues& values,
+ const ConfigTracker& tracker)
{
- for (auto &i : may_reexpand_meta) {
- set_val(values, i.first, i.second);
+ for (auto& [name, value] : may_reexpand_meta) {
+ set_val(values, tracker, name, value);
}
- if (may_reexpand_meta.size()) {
+ if (!may_reexpand_meta.empty()) {
// meta expands could have modified anything. Copy it all out again.
update_legacy_vals(values);
- _apply_changes(values, proxy, NULL);
- values.changed.clear();
+ return true;
+ } else {
+ return false;
}
}
template<LockPolicy lp>
int md_config_impl<lp>::_set_val(
ConfigValues& values,
+ const ConfigTracker& observers,
const std::string &raw_val,
const Option &opt,
int level,
// unsafe runtime change?
if (!opt.can_update_at_runtime() &&
safe_to_start_threads &&
- observers.count(opt.name) == 0) {
+ !observers.is_tracking(opt.name)) {
// accept value if it is not actually a change
if (new_value != _get_val_nometa(values, opt)) {
*error_message = string("Configuration option '") + opt.name +
#include "common/options.h"
#include "common/subsys_types.h"
#include "common/config_fwd.h"
+#include "common/config_tracker.h"
#include "common/config_values.h"
class CephContext;
} opt_type_t;
// Create a new md_config_t structure.
- explicit md_config_impl(ConfigValues& values, bool is_daemon=false);
+ explicit md_config_impl(ConfigValues& values,
+ const ConfigTracker& tracker,
+ bool is_daemon=false);
~md_config_impl();
- // Adds a new observer to this configuration. You can do this at any time,
- // but it will only receive notifications for the changes that happen after
- // you attach it, obviously.
- //
- // Most developers will probably attach their observers after global_init,
- // but before anyone can call injectargs.
- //
- // The caller is responsible for allocating observers.
- void add_observer(md_config_obs_impl<lock_policy>* observer_);
-
- // Remove an observer from this configuration.
- // This doesn't delete the observer! If you allocated it with new(),
- // you need to delete it yourself.
- // This function will assert if you try to delete an observer that isn't
- // there.
- void remove_observer(md_config_obs_impl<lock_policy>* observer_);
-
// Parse a config file
- int parse_config_files(ConfigValues& values, const char *conf_files,
+ int parse_config_files(ConfigValues& values, const ConfigTracker& tracker,
+ const char *conf_files,
std::ostream *warnings, int flags);
// Absorb config settings from the environment
- void parse_env(ConfigValues& values, const char *env_var = "CEPH_ARGS");
+ void parse_env(ConfigValues& values, const ConfigTracker& tracker,
+ const char *env_var = "CEPH_ARGS");
// Absorb config settings from argv
- int parse_argv(ConfigValues& values,
+ int parse_argv(ConfigValues& values, const ConfigTracker& tracker,
std::vector<const char*>& args, int level=CONF_CMDLINE);
// do any commands we got from argv (--show-config, --show-config-val)
void do_argv_commands(const ConfigValues& values);
- // Expand all metavariables. Make any pending observer callbacks.
- void apply_changes(ConfigValues& values, const ConfigProxy& proxy,
- std::ostream *oss);
- void _apply_changes(ConfigValues& values, const ConfigProxy& proxy,
- std::ostream *oss);
bool _internal_field(const string& k);
- void call_all_observers(const ConfigProxy& proxy);
void set_safe_to_start_threads();
void _clear_safe_to_start_threads(); // this is only used by the unit test
/// Set a default value
void set_val_default(ConfigValues& values,
+ const ConfigTracker& tracker,
const std::string& key, const std::string &val);
/// Set a values from mon
int set_mon_vals(CephContext *cct,
ConfigValues& values,
+ const ConfigTracker& tracker,
const map<std::string,std::string>& kv,
config_callback config_cb);
// Called by the Ceph daemons to make configuration changes at runtime
int injectargs(ConfigValues& values,
+ const ConfigTracker& tracker,
const std::string &s,
std::ostream *oss);
// Set a configuration value, or crash
// Metavariables will be expanded.
- void set_val_or_die(ConfigValues& values, const std::string &key, const std::string &val);
+ void set_val_or_die(ConfigValues& values, const ConfigTracker& tracker,
+ const std::string &key, const std::string &val);
// Set a configuration value.
// Metavariables will be expanded.
- int set_val(ConfigValues& values, const std::string &key, const char *val,
+ int set_val(ConfigValues& values, const ConfigTracker& tracker,
+ const std::string &key, const char *val,
std::stringstream *err_ss=nullptr);
- int set_val(ConfigValues& values, const std::string &key, const string& s,
+ int set_val(ConfigValues& values, const ConfigTracker& tracker,
+ const std::string &key, const string& s,
std::stringstream *err_ss=nullptr) {
- return set_val(values, key, s.c_str(), err_ss);
+ return set_val(values, tracker, key, s.c_str(), err_ss);
}
/// clear override value
const std::string &key, std::string &out) const;
int parse_option(ConfigValues& values,
+ const ConfigTracker& tracker,
std::vector<const char*>& args,
std::vector<const char*>::iterator& i,
std::ostream *oss,
int level);
int parse_injectargs(ConfigValues& values,
+ const ConfigTracker& tracker,
std::vector<const char*>& args,
std::ostream *oss);
int _set_val(
ConfigValues& values,
+ const ConfigTracker& tracker,
const std::string &val,
const Option &opt,
int level, // CONF_*
std::ostream *oss) const;
// for those want to reexpand special meta, e.g, $pid
- void finalize_reexpand_meta(ConfigValues& values, const ConfigProxy& proxy);
+ bool finalize_reexpand_meta(ConfigValues& values,
+ const ConfigTracker& tracker);
private:
/// expand all metavariables in config structure.
bool do_show_config = false;
string do_show_config_value;
- obs_map_t observers;
-
vector<Option> subsys_options;
public:
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+
+#pragma once
+
+#include <map>
+#include <set>
+#include <string>
+
+#include "common/config_tracker.h"
+
+class ConfigValues;
+
+// @c ObserverMgr manages a set of config observers which are interested in
+// the changes of settings at runtime.
+template<class ConfigObs>
+class ObserverMgr : public ConfigTracker {
+ // Maps configuration options to the observer listening for them.
+ using obs_map_t = std::multimap<std::string, ConfigObs*>;
+ obs_map_t observers;
+ /* Maps observers to the configuration options that they care about which
+ * have changed. */
+ using rev_obs_map_t = std::map<ConfigObs*, std::set<std::string>>;
+
+public:
+ // Adds a new observer to this configuration. You can do this at any time,
+ // but it will only receive notifications for the changes that happen after
+ // you attach it, obviously.
+ //
+ // Most developers will probably attach their observers after global_init,
+ // but before anyone can call injectargs.
+ //
+ // The caller is responsible for allocating observers.
+ void add_observer(ConfigObs* observer);
+
+ // Remove an observer from this configuration.
+ // This doesn't delete the observer! If you allocated it with new(),
+ // you need to delete it yourself.
+ // This function will assert if you try to delete an observer that isn't
+ // there.
+ void remove_observer(ConfigObs* observer);
+ template<class ConfigProxyT>
+ void call_all_observers(const ConfigProxyT& proxy);
+ template<class ConfigProxyT>
+ void apply_changes(const std::set<std::string>& changes,
+ const ConfigProxyT& proxy,
+ std::ostream *oss);
+ bool is_tracking(const std::string& name) const override;
+};
+
+// we could put the implementations in a .cc file, and only instantiate the
+// used template specializations explicitly, but that forces us to involve
+// unused headers and libraries at compile-time. for instance, for instantiate,
+// to instantiate ObserverMgr for seastar, we will need to include seastar
+// headers to get the necessary types in place, but that would force us to link
+// the non-seastar binaries against seastar libraries. so, to avoid pulling
+// in unused dependencies at the expense of increasing compiling time, we put
+// the implementation in the header file.
+template<class ConfigObs>
+void ObserverMgr<ConfigObs>::add_observer(ConfigObs* observer)
+{
+ const char **keys = observer->get_tracked_conf_keys();
+ for (const char ** k = keys; *k; ++k) {
+ observers.emplace(*k, observer);
+ }
+}
+
+template<class ConfigObs>
+void ObserverMgr<ConfigObs>::remove_observer(ConfigObs* observer)
+{
+ bool found_obs = false;
+ for (auto o = observers.begin(); o != observers.end(); ) {
+ if (o->second == observer) {
+ observers.erase(o++);
+ found_obs = true;
+ } else {
+ ++o;
+ }
+ }
+ assert(found_obs);
+}
+
+template<class ConfigObs>
+template<class ConfigProxyT>
+void ObserverMgr<ConfigObs>::call_all_observers(const ConfigProxyT& proxy)
+{
+ rev_obs_map_t rev_obs;
+ for (const auto& [key, obs] : observers) {
+ rev_obs[obs].insert(key);
+ }
+ for (auto& [obs, keys] : rev_obs) {
+ obs->handle_conf_change(proxy, keys);
+ }
+}
+
+template<class ConfigObs>
+template<class ConfigProxy>
+void ObserverMgr<ConfigObs>::apply_changes(const std::set<std::string>& changes,
+ const ConfigProxy& proxy,
+ std::ostream *oss)
+{
+ // create the reverse observer mapping, mapping observers to the set of
+ // changed keys that they'll get.
+ rev_obs_map_t robs;
+ string val;
+ for (auto& key : changes) {
+ auto [first, last] = observers.equal_range(key);
+ if ((oss) && !proxy.get_val(key, &val)) {
+ (*oss) << key << " = '" << val << "' ";
+ if (first == last) {
+ (*oss) << "(not observed, change may require restart) ";
+ }
+ }
+ for (auto r = first; r != last; ++r) {
+ auto obs = r->second;
+ robs[obs].insert(key);
+ }
+ }
+ // Make any pending observer callbacks
+ for (auto& [obs, keys] : robs) {
+ obs->handle_conf_change(proxy, keys);
+ }
+}
+
+template<class ConfigObs>
+bool ObserverMgr<ConfigObs>::is_tracking(const std::string& name) const
+{
+ return observers.count(name) > 0;
+}
#include <type_traits>
#include "common/config.h"
#include "common/config_fwd.h"
+#include "common/config_obs_mgr.h"
#include "common/Mutex.h"
class ConfigProxy {
* The current values of all settings described by the schema
*/
ConfigValues values;
+ ObserverMgr<md_config_obs_t> obs_mgr;
md_config_t config;
/** A lock that protects the md_config_t internals. It is
* recursive, for simplicity.
public:
explicit ConfigProxy(bool is_daemon)
- : config{values, is_daemon},
+ : config{values, obs_mgr, is_daemon},
lock{"ConfigProxy", true, false}
{}
const ConfigValues* operator->() const noexcept {
Mutex::Locker l{lock};
return config.early_expand_meta(values, val, oss);
}
- // change `values` in-place
+ // for those want to reexpand special meta, e.g, $pid
void finalize_reexpand_meta() {
- Mutex::Locker l{lock};
- config.finalize_reexpand_meta(values, *this);
+ Mutex::Locker l(lock);
+ if (config.finalize_reexpand_meta(values, obs_mgr)) {
+ obs_mgr.apply_changes(values.changed, *this, nullptr);
+ values.changed.clear();
+ }
}
void add_observer(md_config_obs_t* obs) {
- Mutex::Locker l{lock};
- config.add_observer(obs);
+ Mutex::Locker l(lock);
+ obs_mgr.add_observer(obs);
}
void remove_observer(md_config_obs_t* obs) {
- Mutex::Locker l{lock};
- config.remove_observer(obs);
+ Mutex::Locker l(lock);
+ obs_mgr.remove_observer(obs);
}
void call_all_observers() {
- Mutex::Locker l{lock};
+ Mutex::Locker l(lock);
// Have the scope of the lock extend to the scope of
// handle_conf_change since that function expects to be called with
// the lock held. (And the comment in config.h says that is the
// An alternative might be to pass a std::unique_lock to
// handle_conf_change and have a version of get_var that can take it
// by reference and lock as appropriate.
- config.call_all_observers(*this);
+ obs_mgr.call_all_observers(*this);
}
void set_safe_to_start_threads() {
config.set_safe_to_start_threads();
Mutex::Locker l{lock};
return config.rm_val(values, key);
}
+ // Expand all metavariables. Make any pending observer callbacks.
void apply_changes(std::ostream* oss) {
Mutex::Locker l{lock};
- config.apply_changes(values, *this, oss);
+ // apply changes until the cluster name is assigned
+ if (!values.cluster.empty()) {
+ // meta expands could have modified anything. Copy it all out again.
+ obs_mgr.apply_changes(values.changed, *this, oss);
+ values.changed.clear();
+ }
}
int set_val(const std::string& key, const std::string& s,
std::stringstream* err_ss=nullptr) {
Mutex::Locker l{lock};
- return config.set_val(values, key, s);
+ return config.set_val(values, obs_mgr, key, s);
}
void set_val_default(const std::string& key, const std::string& val) {
Mutex::Locker l{lock};
- config.set_val_default(values, key, val);
+ config.set_val_default(values, obs_mgr, key, val);
}
void set_val_or_die(const std::string& key, const std::string& val) {
Mutex::Locker l{lock};
- config.set_val_or_die(values, key, val);
+ config.set_val_or_die(values, obs_mgr, key, val);
}
int set_mon_vals(CephContext *cct,
const map<std::string,std::string>& kv,
md_config_t::config_callback config_cb) {
Mutex::Locker l{lock};
- int ret = config.set_mon_vals(cct, values, kv, config_cb);
- config._apply_changes(values, *this, nullptr);
+ int ret = config.set_mon_vals(cct, values, obs_mgr, kv, config_cb);
+ obs_mgr.apply_changes(values.changed, *this, nullptr);
values.changed.clear();
return ret;
}
int injectargs(const std::string &s, std::ostream *oss) {
Mutex::Locker l{lock};
- int ret = config.injectargs(values, s, oss);
- config._apply_changes(values, *this, oss);
+ int ret = config.injectargs(values, obs_mgr, s, oss);
+ obs_mgr.apply_changes(values.changed, *this, oss);
values.changed.clear();
return ret;
}
void parse_env(const char *env_var = "CEPH_ARGS") {
Mutex::Locker l{lock};
- config.parse_env(values, env_var);
+ config.parse_env(values, obs_mgr, env_var);
}
int parse_argv(std::vector<const char*>& args, int level=CONF_CMDLINE) {
Mutex::Locker l{lock};
- return config.parse_argv(values, args, level);
+ return config.parse_argv(values, obs_mgr, args, level);
}
int parse_config_files(const char *conf_files,
std::ostream *warnings, int flags) {
Mutex::Locker l{lock};
- return config.parse_config_files(values, conf_files, warnings, flags);
+ return config.parse_config_files(values, obs_mgr,
+ conf_files, warnings, flags);
}
size_t num_parse_errors() const {
return config.parse_errors.size();