From: Kefu Chai Date: Sat, 14 Jul 2018 04:02:55 +0000 (+0800) Subject: crimson/common: add ceph::common::ConfigProxy X-Git-Tag: v14.0.1~777^2~4 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=5e0f3b2ae15bb35506dc9804573dd3ccc5b07723;p=ceph.git crimson/common: add ceph::common::ConfigProxy Signed-off-by: Kefu Chai --- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9d370cc5dca4..b59f666a13d8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -635,6 +635,7 @@ else() endif() add_library(common-objs OBJECT ${libcommon_files}) + set(ceph_common_objs $ $ diff --git a/src/common/config_proxy.h b/src/common/config_proxy.h index 9c299b20cc8b..af4e48c0f402 100644 --- a/src/common/config_proxy.h +++ b/src/common/config_proxy.h @@ -5,6 +5,7 @@ #include #include "common/config.h" #include "common/config_fwd.h" +#include "common/config_obs.h" #include "common/config_obs_mgr.h" #include "common/Mutex.h" diff --git a/src/crimson/CMakeLists.txt b/src/crimson/CMakeLists.txt index ed31144471a5..d7b347ffcc6f 100644 --- a/src/crimson/CMakeLists.txt +++ b/src/crimson/CMakeLists.txt @@ -6,7 +6,10 @@ set(crimson_net_srcs set(crimson_thread_srcs thread/ThreadPool.cc thread/Throttle.cc) +set(crimson_common_srcs + common/config_proxy.cc) add_library(crimson STATIC + ${crimson_common_srcs} ${crimson_net_srcs} ${crimson_thread_srcs} ${CMAKE_SOURCE_DIR}/src/common/buffer_seastar.cc) diff --git a/src/crimson/common/config_proxy.cc b/src/crimson/common/config_proxy.cc new file mode 100644 index 000000000000..83e4909ab504 --- /dev/null +++ b/src/crimson/common/config_proxy.cc @@ -0,0 +1,36 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- + +#include "config_proxy.h" + +namespace ceph::common { + +ConfigProxy::ConfigProxy() +{ + if (seastar::engine().cpu_id() != 0) { + return; + } + // set the initial value on CPU#0 + values.reset(seastar::make_lw_shared()); + // and the only copy of md_config_impl<> is allocated on CPU#0 + local_config.reset(new md_config_t{*values, obs_mgr, true}); +} + +seastar::future<> ConfigProxy::start() +{ + // populate values and config to all other shards + if (!values) { + return seastar::make_ready_future<>(); + } + return container().invoke_on_others([this](auto& proxy) { + return values.copy().then([config=local_config.get(), + &proxy](auto foreign_values) { + proxy.values.reset(); + proxy.values = std::move(foreign_values); + proxy.remote_config = config; + return seastar::make_ready_future<>(); + }); + }); +} + +ConfigProxy::ShardedConfig ConfigProxy::sharded_conf; +} diff --git a/src/crimson/common/config_proxy.h b/src/crimson/common/config_proxy.h new file mode 100644 index 000000000000..7ea0a2396037 --- /dev/null +++ b/src/crimson/common/config_proxy.h @@ -0,0 +1,125 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- + +#pragma once + +#include +#include +#include "common/config.h" +#include "common/config_obs.h" +#include "common/config_obs_mgr.h" + +namespace ceph::common { + +// a facade for managing config. each shard has its own copy of ConfigProxy. +// +// In seastar-osd, there could be multiple instances of @c ConfigValues in a +// single process, as we are using a variant of read-copy-update mechinary to +// update the settings at runtime. +class ConfigProxy : public seastar::peering_sharded_service +{ + using LocalConfigValues = seastar::lw_shared_ptr; + seastar::foreign_ptr values; + + md_config_t* remote_config = nullptr; + std::unique_ptr local_config; + + using ConfigObserver = ceph::internal::md_config_obs_impl; + ObserverMgr obs_mgr; + + const md_config_t& get_config() const { + return remote_config ? *remote_config : * local_config; + } + md_config_t& get_config() { + return remote_config ? *remote_config : * local_config; + } + + // apply changes to all shards + // @param func a functor which accepts @c "ConfigValues&", and returns + // a boolean indicating if the values is changed or not + template + seastar::future<> do_change(Func&& func) { + auto new_values = seastar::make_lw_shared(*values); + func(*new_values); + return seastar::do_with(seastar::make_foreign(new_values), + [this](auto& foreign_values) { + return container().invoke_on_all([&foreign_values](ConfigProxy& proxy) { + return foreign_values.copy().then([&proxy](auto foreign_values) { + proxy.values.reset(); + proxy.values = std::move(foreign_values); + proxy.obs_mgr.apply_changes(proxy.values->changed, + proxy, nullptr); + }); + }); + }).then([this] { + values->changed.clear(); + }); + } +public: + ConfigProxy(); + const ConfigValues* operator->() const noexcept { + return values.get(); + } + ConfigValues* operator->() noexcept { + return values.get(); + } + + // required by sharded<> + seastar::future<> start(); + seastar::future<> stop() { + return seastar::make_ready_future<>(); + } + void add_observer(ConfigObserver* obs) { + obs_mgr.add_observer(obs); + } + void remove_observer(ConfigObserver* obs) { + obs_mgr.remove_observer(obs); + } + seastar::future<> rm_val(const std::string& key) { + return do_change([key, this](ConfigValues& values) { + return get_config().rm_val(values, key) >= 0; + }); + } + seastar::future<> set_val(const std::string& key, + const std::string& val) { + return do_change([key, val, this](ConfigValues& values) { + std::stringstream err; + auto ret = get_config().set_val(values, obs_mgr, key, val, &err); + if (ret < 0) { + throw std::invalid_argument(err.str()); + } + return ret > 0; + }); + } + int get_val(const std::string &key, std::string *val) const { + return get_config().get_val(*values, key, val); + } + template + const T get_val(const std::string& key) const { + return get_config().template get_val(*values, key); + } + + seastar::future<> set_mon_vals(const std::map& kv) { + return do_change([kv, this](ConfigValues& values) { + auto ret = get_config().set_mon_vals(nullptr, values, obs_mgr, + kv, nullptr); + return ret > 0; + }); + } + + using ShardedConfig = seastar::sharded; + +private: + static ShardedConfig sharded_conf; + friend ConfigProxy& local_conf(); + friend ShardedConfig& sharded_conf(); +}; + +inline ConfigProxy& local_conf() { + return ConfigProxy::sharded_conf.local(); +} + +inline ConfigProxy::ShardedConfig& sharded_conf() { + return ConfigProxy::sharded_conf; +} + +} diff --git a/src/test/crimson/CMakeLists.txt b/src/test/crimson/CMakeLists.txt index 05f08ea33452..d37f01c08552 100644 --- a/src/test/crimson/CMakeLists.txt +++ b/src/test/crimson/CMakeLists.txt @@ -20,3 +20,7 @@ add_executable(unittest_seastar_thread_pool test_thread_pool.cc) add_ceph_unittest(unittest_seastar_thread_pool) target_link_libraries(unittest_seastar_thread_pool crimson) + +add_executable(unittest_seastar_config + test_config.cc) +target_link_libraries(unittest_seastar_config crimson) diff --git a/src/test/crimson/test_config.cc b/src/test/crimson/test_config.cc new file mode 100644 index 000000000000..eaf9261c30a9 --- /dev/null +++ b/src/test/crimson/test_config.cc @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include "crimson/common/config_proxy.h" + +using Config = ceph::common::ConfigProxy; + +static seastar::future<> test_config() +{ + return ceph::common::sharded_conf().start().then([] { + return ceph::common::sharded_conf().invoke_on(0, &Config::start); + }).then([] { + return ceph::common::sharded_conf().invoke_on_all([](auto& config) { + return config.set_val("osd_tracing", "true"); + }); + }).then([] { + return ceph::common::local_conf().get_val("osd_tracing"); + }).then([](bool osd_tracing) { + if (osd_tracing) { + return seastar::make_ready_future<>(); + } else { + throw std::runtime_error("run osd_tracing"); + } + }).then([] { + return ceph::common::sharded_conf().stop(); + }); +} + +int main(int argc, char** argv) +{ + seastar::app_template app; + return app.run(argc, argv, [&] { + return test_config().then([] { + std::cout << "All tests succeeded" << std::endl; + }).handle_exception([] (auto eptr) { + std::cout << "Test failure" << std::endl; + return seastar::make_exception_future<>(eptr); + }); + }); +} + + +/* + * Local Variables: + * compile-command: "make -j4 \ + * -C ../../../build \ + * unittest_seastar_config" + * End: + */