]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
crimson/common: add ceph::common::ConfigProxy
authorKefu Chai <kchai@redhat.com>
Sat, 14 Jul 2018 04:02:55 +0000 (12:02 +0800)
committerKefu Chai <kchai@redhat.com>
Wed, 25 Jul 2018 05:13:45 +0000 (13:13 +0800)
Signed-off-by: Kefu Chai <kchai@redhat.com>
src/CMakeLists.txt
src/common/config_proxy.h
src/crimson/CMakeLists.txt
src/crimson/common/config_proxy.cc [new file with mode: 0644]
src/crimson/common/config_proxy.h [new file with mode: 0644]
src/test/crimson/CMakeLists.txt
src/test/crimson/test_config.cc [new file with mode: 0644]

index 9d370cc5dca4e6a48633c926958994aff3903451..b59f666a13d894cb70eff7a539ae1ce0a361ba48 100644 (file)
@@ -635,6 +635,7 @@ else()
 endif()
 
 add_library(common-objs OBJECT ${libcommon_files})
+
 set(ceph_common_objs
   $<TARGET_OBJECTS:common_buffer_obj>
   $<TARGET_OBJECTS:common_texttable_obj>
index 9c299b20cc8b4f7cbe91802489a509119cdb2628..af4e48c0f4024ac5b9f08d7dd844ba021c77fd05 100644 (file)
@@ -5,6 +5,7 @@
 #include <type_traits>
 #include "common/config.h"
 #include "common/config_fwd.h"
+#include "common/config_obs.h"
 #include "common/config_obs_mgr.h"
 #include "common/Mutex.h"
 
index ed31144471a5bdf27bd360d9eb3806e7d04aa449..d7b347ffcc6fffa4391e1a7e2271ab0f2213be64 100644 (file)
@@ -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 (file)
index 0000000..83e4909
--- /dev/null
@@ -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<ConfigValues>());
+  // 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 (file)
index 0000000..7ea0a23
--- /dev/null
@@ -0,0 +1,125 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+
+#pragma once
+
+#include <seastar/core/reactor.hh>
+#include <seastar/core/sharded.hh>
+#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<ConfigProxy>
+{
+  using LocalConfigValues = seastar::lw_shared_ptr<ConfigValues>;
+  seastar::foreign_ptr<LocalConfigValues> values;
+
+  md_config_t* remote_config = nullptr;
+  std::unique_ptr<md_config_t> local_config;
+
+  using ConfigObserver = ceph::internal::md_config_obs_impl<ConfigProxy>;
+  ObserverMgr<ConfigObserver> 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<typename Func>
+  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<typename T>
+  const T get_val(const std::string& key) const {
+    return get_config().template get_val<T>(*values, key);
+  }
+
+  seastar::future<> set_mon_vals(const std::map<std::string,std::string>& 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<ConfigProxy>;
+
+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;
+}
+
+}
index 05f08ea33452b01d48caefc2a2a26147a5d57acb..d37f01c08552e9d9ea168b38c11dce6179a79620 100644 (file)
@@ -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 (file)
index 0000000..eaf9261
--- /dev/null
@@ -0,0 +1,50 @@
+#include <chrono>
+#include <numeric>
+#include <seastar/core/app-template.hh>
+#include <seastar/core/sharded.hh>
+#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<bool>("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:
+ */