]> git.proxmox.com Git - ceph.git/blame - ceph/src/crimson/common/config_proxy.h
import 15.2.0 Octopus source
[ceph.git] / ceph / src / crimson / common / config_proxy.h
CommitLineData
11fdf7f2 1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
9f95a23c 2// vim: ts=8 sw=2 smarttab
11fdf7f2
TL
3
4#pragma once
5
6#include <seastar/core/reactor.hh>
7#include <seastar/core/sharded.hh>
8#include "common/config.h"
9#include "common/config_obs.h"
10#include "common/config_obs_mgr.h"
11#include "common/errno.h"
12
9f95a23c
TL
13namespace ceph {
14class Formatter;
15}
16
17namespace crimson::common {
11fdf7f2
TL
18
19// a facade for managing config. each shard has its own copy of ConfigProxy.
20//
21// In seastar-osd, there could be multiple instances of @c ConfigValues in a
22// single process, as we are using a variant of read-copy-update mechinary to
23// update the settings at runtime.
24class ConfigProxy : public seastar::peering_sharded_service<ConfigProxy>
25{
26 using LocalConfigValues = seastar::lw_shared_ptr<ConfigValues>;
27 seastar::foreign_ptr<LocalConfigValues> values;
28
29 md_config_t* remote_config = nullptr;
30 std::unique_ptr<md_config_t> local_config;
31
32 using ConfigObserver = ceph::md_config_obs_impl<ConfigProxy>;
33 ObserverMgr<ConfigObserver> obs_mgr;
34
35 const md_config_t& get_config() const {
36 return remote_config ? *remote_config : * local_config;
37 }
38 md_config_t& get_config() {
39 return remote_config ? *remote_config : * local_config;
40 }
41
42 // apply changes to all shards
43 // @param func a functor which accepts @c "ConfigValues&"
44 template<typename Func>
45 seastar::future<> do_change(Func&& func) {
46 return container().invoke_on(values.get_owner_shard(),
47 [func = std::move(func)](ConfigProxy& owner) {
48 // apply the changes to a copy of the values
49 auto new_values = seastar::make_lw_shared(*owner.values);
50 new_values->changed.clear();
51 func(*new_values);
52
53 // always apply the new settings synchronously on the owner shard, to
54 // avoid racings with other do_change() calls in parallel.
55 ObserverMgr<ConfigObserver>::rev_obs_map rev_obs;
56 owner.values.reset(new_values);
57 owner.obs_mgr.for_each_change(owner.values->changed, owner,
58 [&rev_obs](ConfigObserver *obs,
59 const std::string &key) {
60 rev_obs[obs].insert(key);
61 }, nullptr);
62 for (auto& [obs, keys] : rev_obs) {
63 obs->handle_conf_change(owner, keys);
64 }
65
66 return seastar::parallel_for_each(boost::irange(1u, seastar::smp::count),
67 [&owner, new_values] (auto cpu) {
68 return owner.container().invoke_on(cpu,
69 [foreign_values = seastar::make_foreign(new_values)](ConfigProxy& proxy) mutable {
70 proxy.values.reset();
71 proxy.values = std::move(foreign_values);
72
73 ObserverMgr<ConfigObserver>::rev_obs_map rev_obs;
74 proxy.obs_mgr.for_each_change(proxy.values->changed, proxy,
9f95a23c
TL
75 [&rev_obs](ConfigObserver *obs, const std::string& key) {
76 rev_obs[obs].insert(key);
77 }, nullptr);
11fdf7f2
TL
78 for (auto& obs_keys : rev_obs) {
79 obs_keys.first->handle_conf_change(proxy, obs_keys.second);
80 }
81 });
82 }).finally([new_values] {
83 new_values->changed.clear();
84 });
85 });
86 }
87public:
88 ConfigProxy(const EntityName& name, std::string_view cluster);
89 const ConfigValues* operator->() const noexcept {
90 return values.get();
91 }
9f95a23c
TL
92 const ConfigValues get_config_values() {
93 return *values.get();
94 }
11fdf7f2
TL
95 ConfigValues* operator->() noexcept {
96 return values.get();
97 }
98
99 // required by sharded<>
100 seastar::future<> start();
101 seastar::future<> stop() {
102 return seastar::make_ready_future<>();
103 }
104 void add_observer(ConfigObserver* obs) {
105 obs_mgr.add_observer(obs);
106 }
107 void remove_observer(ConfigObserver* obs) {
108 obs_mgr.remove_observer(obs);
109 }
110 seastar::future<> rm_val(const std::string& key) {
111 return do_change([key, this](ConfigValues& values) {
112 auto ret = get_config().rm_val(values, key);
113 if (ret < 0) {
114 throw std::invalid_argument(cpp_strerror(ret));
115 }
116 });
117 }
118 seastar::future<> set_val(const std::string& key,
119 const std::string& val) {
120 return do_change([key, val, this](ConfigValues& values) {
121 std::stringstream err;
122 auto ret = get_config().set_val(values, obs_mgr, key, val, &err);
123 if (ret < 0) {
124 throw std::invalid_argument(err.str());
125 }
126 });
127 }
128 int get_val(const std::string &key, std::string *val) const {
129 return get_config().get_val(*values, key, val);
130 }
131 template<typename T>
132 const T get_val(const std::string& key) const {
133 return get_config().template get_val<T>(*values, key);
134 }
135
136 int get_all_sections(std::vector<std::string>& sections) const {
137 return get_config().get_all_sections(sections);
138 }
139
140 int get_val_from_conf_file(const std::vector<std::string>& sections,
141 const std::string& key, std::string& out,
142 bool expand_meta) const {
143 return get_config().get_val_from_conf_file(*values, sections, key,
144 out, expand_meta);
145 }
146
147 unsigned get_osd_pool_default_min_size(uint8_t size) const {
148 return get_config().get_osd_pool_default_min_size(*values, size);
149 }
150
9f95a23c
TL
151 seastar::future<>
152 set_mon_vals(const std::map<std::string,std::string,std::less<>>& kv) {
11fdf7f2
TL
153 return do_change([kv, this](ConfigValues& values) {
154 get_config().set_mon_vals(nullptr, values, obs_mgr, kv, nullptr);
155 });
156 }
157
9f95a23c
TL
158 void show_config(ceph::Formatter* f) const;
159
160 seastar::future<> parse_argv(std::vector<const char*>& argv) {
161 // we could pass whatever is unparsed to seastar, but seastar::app_template
162 // is used for driving the seastar application, and
163 // crimson::common::ConfigProxy is not available until seastar engine is up
164 // and running, so we have to feed the command line args to app_template
165 // first, then pass them to ConfigProxy.
166 return do_change([&argv, this](ConfigValues& values) {
167 get_config().parse_argv(values,
168 obs_mgr,
169 argv,
170 CONF_CMDLINE);
171 });
172 }
173
11fdf7f2
TL
174 seastar::future<> parse_config_files(const std::string& conf_files) {
175 return do_change([this, conf_files](ConfigValues& values) {
176 const char* conf_file_paths =
177 conf_files.empty() ? nullptr : conf_files.c_str();
178 get_config().parse_config_files(values,
179 obs_mgr,
180 conf_file_paths,
181 &std::cerr,
182 CODE_ENVIRONMENT_DAEMON);
183 });
184 }
185
186 using ShardedConfig = seastar::sharded<ConfigProxy>;
187
188private:
189 static ShardedConfig sharded_conf;
190 friend ConfigProxy& local_conf();
191 friend ShardedConfig& sharded_conf();
192};
193
194inline ConfigProxy& local_conf() {
195 return ConfigProxy::sharded_conf.local();
196}
197
198inline ConfigProxy::ShardedConfig& sharded_conf() {
199 return ConfigProxy::sharded_conf;
200}
201
202}