]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | ||
3 | #pragma once | |
4 | ||
5 | #include <type_traits> | |
6 | #include "common/config.h" | |
7 | #include "common/config_obs.h" | |
8 | #include "common/config_obs_mgr.h" | |
9 | #include "common/ceph_mutex.h" | |
10 | ||
11 | // @c ConfigProxy is a facade of multiple config related classes. it exposes | |
12 | // the legacy settings with arrow operator, and the new-style config with its | |
13 | // member methods. | |
9f95a23c | 14 | namespace ceph::common{ |
11fdf7f2 TL |
15 | class ConfigProxy { |
16 | static ConfigValues get_config_values(const ConfigProxy &config_proxy) { | |
17 | std::lock_guard locker(config_proxy.lock); | |
18 | return config_proxy.values; | |
19 | } | |
20 | ||
21 | /** | |
22 | * The current values of all settings described by the schema | |
23 | */ | |
24 | ConfigValues values; | |
25 | using md_config_obs_t = ceph::md_config_obs_impl<ConfigProxy>; | |
26 | ObserverMgr<md_config_obs_t> obs_mgr; | |
27 | md_config_t config; | |
28 | /** A lock that protects the md_config_t internals. It is | |
29 | * recursive, for simplicity. | |
30 | * It is best if this lock comes first in the lock hierarchy. We will | |
31 | * hold this lock when calling configuration observers. */ | |
32 | mutable ceph::recursive_mutex lock = | |
33 | ceph::make_recursive_mutex("ConfigProxy::lock"); | |
34 | ||
35 | class CallGate { | |
36 | private: | |
37 | uint32_t call_count = 0; | |
38 | ceph::mutex lock; | |
39 | ceph::condition_variable cond; | |
40 | public: | |
41 | CallGate() | |
42 | : lock(ceph::make_mutex("call::gate::lock")) { | |
43 | } | |
44 | ||
45 | void enter() { | |
46 | std::lock_guard<ceph::mutex> locker(lock); | |
47 | ++call_count; | |
48 | } | |
49 | void leave() { | |
50 | std::lock_guard<ceph::mutex> locker(lock); | |
51 | ceph_assert(call_count > 0); | |
52 | if (--call_count == 0) { | |
53 | cond.notify_all(); | |
54 | } | |
55 | } | |
56 | void close() { | |
57 | std::unique_lock<ceph::mutex> locker(lock); | |
58 | while (call_count != 0) { | |
59 | cond.wait(locker); | |
60 | } | |
61 | } | |
62 | }; | |
63 | ||
64 | void call_gate_enter(md_config_obs_t *obs) { | |
65 | auto p = obs_call_gate.find(obs); | |
66 | ceph_assert(p != obs_call_gate.end()); | |
67 | p->second->enter(); | |
68 | } | |
69 | void call_gate_leave(md_config_obs_t *obs) { | |
70 | auto p = obs_call_gate.find(obs); | |
71 | ceph_assert(p != obs_call_gate.end()); | |
72 | p->second->leave(); | |
73 | } | |
74 | void call_gate_close(md_config_obs_t *obs) { | |
75 | auto p = obs_call_gate.find(obs); | |
76 | ceph_assert(p != obs_call_gate.end()); | |
77 | p->second->close(); | |
78 | } | |
79 | ||
80 | using rev_obs_map_t = ObserverMgr<md_config_obs_t>::rev_obs_map; | |
81 | typedef std::unique_ptr<CallGate> CallGateRef; | |
82 | ||
83 | std::map<md_config_obs_t*, CallGateRef> obs_call_gate; | |
84 | ||
eafe8130 TL |
85 | void call_observers(std::unique_lock<ceph::recursive_mutex>& locker, |
86 | rev_obs_map_t& rev_obs) { | |
87 | // observers are notified outside of lock | |
88 | locker.unlock(); | |
11fdf7f2 TL |
89 | for (auto& [obs, keys] : rev_obs) { |
90 | obs->handle_conf_change(*this, keys); | |
eafe8130 TL |
91 | } |
92 | locker.lock(); | |
93 | ||
94 | for (auto& rev_ob : rev_obs) { | |
95 | call_gate_leave(rev_ob.first); | |
11fdf7f2 TL |
96 | } |
97 | } | |
98 | ||
99 | void map_observer_changes(md_config_obs_t *obs, const std::string &key, | |
100 | rev_obs_map_t *rev_obs) { | |
101 | ceph_assert(ceph_mutex_is_locked(lock)); | |
102 | ||
103 | auto [it, new_entry] = rev_obs->emplace(obs, std::set<std::string>{}); | |
104 | it->second.emplace(key); | |
105 | if (new_entry) { | |
106 | // this needs to be done under lock as once this lock is | |
107 | // dropped (before calling observers) a remove_observer() | |
108 | // can sneak in and cause havoc. | |
109 | call_gate_enter(obs); | |
110 | } | |
111 | } | |
112 | ||
113 | public: | |
114 | explicit ConfigProxy(bool is_daemon) | |
115 | : config{values, obs_mgr, is_daemon} | |
116 | {} | |
117 | explicit ConfigProxy(const ConfigProxy &config_proxy) | |
118 | : values(get_config_values(config_proxy)), | |
119 | config{values, obs_mgr, config_proxy.config.is_daemon} | |
120 | {} | |
121 | const ConfigValues* operator->() const noexcept { | |
122 | return &values; | |
123 | } | |
124 | ConfigValues* operator->() noexcept { | |
125 | return &values; | |
126 | } | |
9f95a23c TL |
127 | #ifdef WITH_SEASTAR |
128 | void set_config_values(const ConfigValues& val) { | |
129 | values = val; | |
130 | } | |
131 | #endif | |
132 | int get_val(const std::string_view key, char** buf, int len) const { | |
11fdf7f2 TL |
133 | std::lock_guard l{lock}; |
134 | return config.get_val(values, key, buf, len); | |
135 | } | |
9f95a23c | 136 | int get_val(const std::string_view key, std::string *val) const { |
11fdf7f2 TL |
137 | std::lock_guard l{lock}; |
138 | return config.get_val(values, key, val); | |
139 | } | |
140 | template<typename T> | |
9f95a23c | 141 | const T get_val(const std::string_view key) const { |
11fdf7f2 TL |
142 | std::lock_guard l{lock}; |
143 | return config.template get_val<T>(values, key); | |
144 | } | |
145 | template<typename T, typename Callback, typename...Args> | |
9f95a23c | 146 | auto with_val(const std::string_view key, Callback&& cb, Args&&... args) const { |
11fdf7f2 TL |
147 | std::lock_guard l{lock}; |
148 | return config.template with_val<T>(values, key, | |
149 | std::forward<Callback>(cb), | |
150 | std::forward<Args>(args)...); | |
151 | } | |
9f95a23c | 152 | void config_options(ceph::Formatter *f) const { |
11fdf7f2 TL |
153 | config.config_options(f); |
154 | } | |
155 | const decltype(md_config_t::schema)& get_schema() const { | |
156 | return config.schema; | |
157 | } | |
9f95a23c | 158 | const Option* get_schema(const std::string_view key) const { |
11fdf7f2 TL |
159 | auto found = config.schema.find(key); |
160 | if (found == config.schema.end()) { | |
161 | return nullptr; | |
162 | } else { | |
163 | return &found->second; | |
164 | } | |
165 | } | |
9f95a23c | 166 | const Option *find_option(const std::string& name) const { |
11fdf7f2 TL |
167 | return config.find_option(name); |
168 | } | |
9f95a23c | 169 | void diff(ceph::Formatter *f, const std::string& name = {}) const { |
11fdf7f2 TL |
170 | std::lock_guard l{lock}; |
171 | return config.diff(values, f, name); | |
172 | } | |
173 | void get_my_sections(std::vector <std::string> §ions) const { | |
174 | std::lock_guard l{lock}; | |
175 | config.get_my_sections(values, sections); | |
176 | } | |
177 | int get_all_sections(std::vector<std::string>& sections) const { | |
178 | std::lock_guard l{lock}; | |
179 | return config.get_all_sections(sections); | |
180 | } | |
181 | int get_val_from_conf_file(const std::vector<std::string>& sections, | |
9f95a23c | 182 | const std::string_view key, std::string& out, |
11fdf7f2 TL |
183 | bool emeta) const { |
184 | std::lock_guard l{lock}; | |
185 | return config.get_val_from_conf_file(values, | |
186 | sections, key, out, emeta); | |
187 | } | |
188 | unsigned get_osd_pool_default_min_size(uint8_t size) const { | |
189 | return config.get_osd_pool_default_min_size(values, size); | |
190 | } | |
191 | void early_expand_meta(std::string &val, | |
192 | std::ostream *oss) const { | |
193 | std::lock_guard l{lock}; | |
194 | return config.early_expand_meta(values, val, oss); | |
195 | } | |
196 | // for those want to reexpand special meta, e.g, $pid | |
197 | void finalize_reexpand_meta() { | |
eafe8130 | 198 | std::unique_lock locker(lock); |
11fdf7f2 | 199 | rev_obs_map_t rev_obs; |
eafe8130 TL |
200 | if (config.finalize_reexpand_meta(values, obs_mgr)) { |
201 | _gather_changes(values.changed, &rev_obs, nullptr); | |
202 | values.changed.clear(); | |
11fdf7f2 TL |
203 | } |
204 | ||
eafe8130 | 205 | call_observers(locker, rev_obs); |
11fdf7f2 TL |
206 | } |
207 | void add_observer(md_config_obs_t* obs) { | |
208 | std::lock_guard l(lock); | |
209 | obs_mgr.add_observer(obs); | |
210 | obs_call_gate.emplace(obs, std::make_unique<CallGate>()); | |
211 | } | |
212 | void remove_observer(md_config_obs_t* obs) { | |
213 | std::lock_guard l(lock); | |
214 | call_gate_close(obs); | |
215 | obs_call_gate.erase(obs); | |
216 | obs_mgr.remove_observer(obs); | |
217 | } | |
218 | void call_all_observers() { | |
eafe8130 | 219 | std::unique_lock locker(lock); |
11fdf7f2 | 220 | rev_obs_map_t rev_obs; |
eafe8130 TL |
221 | obs_mgr.for_each_observer( |
222 | [this, &rev_obs](md_config_obs_t *obs, const std::string &key) { | |
223 | map_observer_changes(obs, key, &rev_obs); | |
224 | }); | |
11fdf7f2 | 225 | |
eafe8130 | 226 | call_observers(locker, rev_obs); |
11fdf7f2 TL |
227 | } |
228 | void set_safe_to_start_threads() { | |
229 | config.set_safe_to_start_threads(); | |
230 | } | |
231 | void _clear_safe_to_start_threads() { | |
232 | config._clear_safe_to_start_threads(); | |
233 | } | |
234 | void show_config(std::ostream& out) { | |
235 | std::lock_guard l{lock}; | |
236 | config.show_config(values, out); | |
237 | } | |
9f95a23c | 238 | void show_config(ceph::Formatter *f) { |
11fdf7f2 TL |
239 | std::lock_guard l{lock}; |
240 | config.show_config(values, f); | |
241 | } | |
9f95a23c | 242 | void config_options(ceph::Formatter *f) { |
11fdf7f2 TL |
243 | std::lock_guard l{lock}; |
244 | config.config_options(f); | |
245 | } | |
9f95a23c | 246 | int rm_val(const std::string_view key) { |
11fdf7f2 TL |
247 | std::lock_guard l{lock}; |
248 | return config.rm_val(values, key); | |
249 | } | |
250 | // Expand all metavariables. Make any pending observer callbacks. | |
251 | void apply_changes(std::ostream* oss) { | |
eafe8130 | 252 | std::unique_lock locker(lock); |
11fdf7f2 | 253 | rev_obs_map_t rev_obs; |
eafe8130 TL |
254 | |
255 | // apply changes until the cluster name is assigned | |
256 | if (!values.cluster.empty()) { | |
257 | // meta expands could have modified anything. Copy it all out again. | |
258 | _gather_changes(values.changed, &rev_obs, oss); | |
259 | values.changed.clear(); | |
11fdf7f2 TL |
260 | } |
261 | ||
eafe8130 | 262 | call_observers(locker, rev_obs); |
11fdf7f2 TL |
263 | } |
264 | void _gather_changes(std::set<std::string> &changes, | |
265 | rev_obs_map_t *rev_obs, std::ostream* oss) { | |
266 | obs_mgr.for_each_change( | |
267 | changes, *this, | |
268 | [this, rev_obs](md_config_obs_t *obs, const std::string &key) { | |
269 | map_observer_changes(obs, key, rev_obs); | |
270 | }, oss); | |
271 | } | |
9f95a23c | 272 | int set_val(const std::string_view key, const std::string& s, |
11fdf7f2 TL |
273 | std::stringstream* err_ss=nullptr) { |
274 | std::lock_guard l{lock}; | |
275 | return config.set_val(values, obs_mgr, key, s, err_ss); | |
276 | } | |
9f95a23c | 277 | void set_val_default(const std::string_view key, const std::string& val) { |
11fdf7f2 TL |
278 | std::lock_guard l{lock}; |
279 | config.set_val_default(values, obs_mgr, key, val); | |
280 | } | |
9f95a23c | 281 | void set_val_or_die(const std::string_view key, const std::string& val) { |
11fdf7f2 TL |
282 | std::lock_guard l{lock}; |
283 | config.set_val_or_die(values, obs_mgr, key, val); | |
284 | } | |
285 | int set_mon_vals(CephContext *cct, | |
9f95a23c | 286 | const std::map<std::string,std::string,std::less<>>& kv, |
11fdf7f2 | 287 | md_config_t::config_callback config_cb) { |
eafe8130 TL |
288 | std::unique_lock locker(lock); |
289 | int ret = config.set_mon_vals(cct, values, obs_mgr, kv, config_cb); | |
290 | ||
11fdf7f2 | 291 | rev_obs_map_t rev_obs; |
eafe8130 TL |
292 | _gather_changes(values.changed, &rev_obs, nullptr); |
293 | values.changed.clear(); | |
11fdf7f2 | 294 | |
eafe8130 | 295 | call_observers(locker, rev_obs); |
11fdf7f2 TL |
296 | return ret; |
297 | } | |
298 | int injectargs(const std::string &s, std::ostream *oss) { | |
eafe8130 TL |
299 | std::unique_lock locker(lock); |
300 | int ret = config.injectargs(values, obs_mgr, s, oss); | |
301 | ||
11fdf7f2 | 302 | rev_obs_map_t rev_obs; |
eafe8130 TL |
303 | _gather_changes(values.changed, &rev_obs, oss); |
304 | values.changed.clear(); | |
11fdf7f2 | 305 | |
eafe8130 | 306 | call_observers(locker, rev_obs); |
11fdf7f2 TL |
307 | return ret; |
308 | } | |
309 | void parse_env(unsigned entity_type, | |
310 | const char *env_var = "CEPH_ARGS") { | |
311 | std::lock_guard l{lock}; | |
312 | config.parse_env(entity_type, values, obs_mgr, env_var); | |
313 | } | |
314 | int parse_argv(std::vector<const char*>& args, int level=CONF_CMDLINE) { | |
315 | std::lock_guard l{lock}; | |
316 | return config.parse_argv(values, obs_mgr, args, level); | |
317 | } | |
318 | int parse_config_files(const char *conf_files, | |
319 | std::ostream *warnings, int flags) { | |
320 | std::lock_guard l{lock}; | |
321 | return config.parse_config_files(values, obs_mgr, | |
322 | conf_files, warnings, flags); | |
323 | } | |
9f95a23c TL |
324 | bool has_parse_error() const { |
325 | return !config.parse_error.empty(); | |
11fdf7f2 | 326 | } |
9f95a23c TL |
327 | void complain_about_parse_error(CephContext *cct) { |
328 | return config.complain_about_parse_error(cct); | |
11fdf7f2 TL |
329 | } |
330 | void do_argv_commands() const { | |
331 | std::lock_guard l{lock}; | |
332 | config.do_argv_commands(values); | |
333 | } | |
334 | void get_config_bl(uint64_t have_version, | |
9f95a23c | 335 | ceph::buffer::list *bl, |
11fdf7f2 TL |
336 | uint64_t *got_version) { |
337 | std::lock_guard l{lock}; | |
338 | config.get_config_bl(values, have_version, bl, got_version); | |
339 | } | |
9f95a23c | 340 | void get_defaults_bl(ceph::buffer::list *bl) { |
11fdf7f2 TL |
341 | std::lock_guard l{lock}; |
342 | config.get_defaults_bl(values, bl); | |
343 | } | |
344 | }; | |
9f95a23c TL |
345 | |
346 | } |