]> git.proxmox.com Git - ceph.git/blame - ceph/src/common/config_proxy.h
import 15.2.0 Octopus source
[ceph.git] / ceph / src / common / config_proxy.h
CommitLineData
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 14namespace ceph::common{
11fdf7f2
TL
15class 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
113public:
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> &sections) 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}