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