1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
6 #include "common/config.h"
7 #include "common/config_obs.h"
8 #include "common/config_obs_mgr.h"
9 #include "common/ceph_mutex.h"
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
14 namespace ceph::common
{
16 static ConfigValues
get_config_values(const ConfigProxy
&config_proxy
) {
17 std::lock_guard
locker(config_proxy
.lock
);
18 return config_proxy
.values
;
22 * The current values of all settings described by the schema
25 using md_config_obs_t
= ceph::md_config_obs_impl
<ConfigProxy
>;
26 ObserverMgr
<md_config_obs_t
> obs_mgr
;
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");
37 uint32_t call_count
= 0;
39 ceph::condition_variable cond
;
42 : lock(ceph::make_mutex("call::gate::lock")) {
46 std::lock_guard
<ceph::mutex
> locker(lock
);
50 std::lock_guard
<ceph::mutex
> locker(lock
);
51 ceph_assert(call_count
> 0);
52 if (--call_count
== 0) {
57 std::unique_lock
<ceph::mutex
> locker(lock
);
58 while (call_count
!= 0) {
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());
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());
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());
80 using rev_obs_map_t
= ObserverMgr
<md_config_obs_t
>::rev_obs_map
;
81 typedef std::unique_ptr
<CallGate
> CallGateRef
;
83 std::map
<md_config_obs_t
*, CallGateRef
> obs_call_gate
;
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
89 for (auto& [obs
, keys
] : rev_obs
) {
90 obs
->handle_conf_change(*this, keys
);
94 for (auto& rev_ob
: rev_obs
) {
95 call_gate_leave(rev_ob
.first
);
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
));
103 auto [it
, new_entry
] = rev_obs
->emplace(obs
, std::set
<std::string
>{});
104 it
->second
.emplace(key
);
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
);
114 explicit ConfigProxy(bool is_daemon
)
115 : config
{values
, obs_mgr
, is_daemon
}
117 explicit ConfigProxy(const ConfigProxy
&config_proxy
)
118 : values(get_config_values(config_proxy
)),
119 config
{values
, obs_mgr
, config_proxy
.config
.is_daemon
}
121 const ConfigValues
* operator->() const noexcept
{
124 ConfigValues
* operator->() noexcept
{
128 void set_config_values(const ConfigValues
& val
) {
132 int get_val(const std::string_view key
, char** buf
, int len
) const {
133 std::lock_guard l
{lock
};
134 return config
.get_val(values
, key
, buf
, len
);
136 int get_val(const std::string_view key
, std::string
*val
) const {
137 std::lock_guard l
{lock
};
138 return config
.get_val(values
, key
, val
);
141 const T
get_val(const std::string_view key
) const {
142 std::lock_guard l
{lock
};
143 return config
.template get_val
<T
>(values
, key
);
145 template<typename T
, typename Callback
, typename
...Args
>
146 auto with_val(const std::string_view key
, Callback
&& cb
, Args
&&... args
) const {
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
)...);
152 void config_options(ceph::Formatter
*f
) const {
153 config
.config_options(f
);
155 const decltype(md_config_t::schema
)& get_schema() const {
156 return config
.schema
;
158 const Option
* get_schema(const std::string_view key
) const {
159 auto found
= config
.schema
.find(key
);
160 if (found
== config
.schema
.end()) {
163 return &found
->second
;
166 const Option
*find_option(const std::string
& name
) const {
167 return config
.find_option(name
);
169 void diff(ceph::Formatter
*f
, const std::string
& name
= {}) const {
170 std::lock_guard l
{lock
};
171 return config
.diff(values
, f
, name
);
173 void get_my_sections(std::vector
<std::string
> §ions
) const {
174 std::lock_guard l
{lock
};
175 config
.get_my_sections(values
, sections
);
177 int get_all_sections(std::vector
<std::string
>& sections
) const {
178 std::lock_guard l
{lock
};
179 return config
.get_all_sections(sections
);
181 int get_val_from_conf_file(const std::vector
<std::string
>& sections
,
182 const std::string_view key
, std::string
& out
,
184 std::lock_guard l
{lock
};
185 return config
.get_val_from_conf_file(values
,
186 sections
, key
, out
, emeta
);
188 unsigned get_osd_pool_default_min_size(uint8_t size
) const {
189 return config
.get_osd_pool_default_min_size(values
, size
);
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
);
196 // for those want to reexpand special meta, e.g, $pid
197 void finalize_reexpand_meta() {
198 std::unique_lock
locker(lock
);
199 rev_obs_map_t rev_obs
;
200 if (config
.finalize_reexpand_meta(values
, obs_mgr
)) {
201 _gather_changes(values
.changed
, &rev_obs
, nullptr);
204 call_observers(locker
, rev_obs
);
206 void add_observer(md_config_obs_t
* obs
) {
207 std::lock_guard
l(lock
);
208 obs_mgr
.add_observer(obs
);
209 obs_call_gate
.emplace(obs
, std::make_unique
<CallGate
>());
211 void remove_observer(md_config_obs_t
* obs
) {
212 std::lock_guard
l(lock
);
213 call_gate_close(obs
);
214 obs_call_gate
.erase(obs
);
215 obs_mgr
.remove_observer(obs
);
217 void call_all_observers() {
218 std::unique_lock
locker(lock
);
219 rev_obs_map_t rev_obs
;
220 obs_mgr
.for_each_observer(
221 [this, &rev_obs
](md_config_obs_t
*obs
, const std::string
&key
) {
222 map_observer_changes(obs
, key
, &rev_obs
);
225 call_observers(locker
, rev_obs
);
227 void set_safe_to_start_threads() {
228 config
.set_safe_to_start_threads();
230 void _clear_safe_to_start_threads() {
231 config
._clear_safe_to_start_threads();
233 void show_config(std::ostream
& out
) {
234 std::lock_guard l
{lock
};
235 config
.show_config(values
, out
);
237 void show_config(ceph::Formatter
*f
) {
238 std::lock_guard l
{lock
};
239 config
.show_config(values
, f
);
241 void config_options(ceph::Formatter
*f
) {
242 std::lock_guard l
{lock
};
243 config
.config_options(f
);
245 int rm_val(const std::string_view key
) {
246 std::lock_guard l
{lock
};
247 return config
.rm_val(values
, key
);
249 // Expand all metavariables. Make any pending observer callbacks.
250 void apply_changes(std::ostream
* oss
) {
251 std::unique_lock
locker(lock
);
252 rev_obs_map_t rev_obs
;
254 // apply changes until the cluster name is assigned
255 if (!values
.cluster
.empty()) {
256 // meta expands could have modified anything. Copy it all out again.
257 _gather_changes(values
.changed
, &rev_obs
, oss
);
260 call_observers(locker
, rev_obs
);
262 void _gather_changes(std::set
<std::string
> &changes
,
263 rev_obs_map_t
*rev_obs
, std::ostream
* oss
) {
264 obs_mgr
.for_each_change(
266 [this, rev_obs
](md_config_obs_t
*obs
, const std::string
&key
) {
267 map_observer_changes(obs
, key
, rev_obs
);
271 int set_val(const std::string_view key
, const std::string
& s
,
272 std::stringstream
* err_ss
=nullptr) {
273 std::lock_guard l
{lock
};
274 return config
.set_val(values
, obs_mgr
, key
, s
, err_ss
);
276 void set_val_default(const std::string_view key
, const std::string
& val
) {
277 std::lock_guard l
{lock
};
278 config
.set_val_default(values
, obs_mgr
, key
, val
);
280 void set_val_or_die(const std::string_view key
, const std::string
& val
) {
281 std::lock_guard l
{lock
};
282 config
.set_val_or_die(values
, obs_mgr
, key
, val
);
284 int set_mon_vals(CephContext
*cct
,
285 const std::map
<std::string
,std::string
,std::less
<>>& kv
,
286 md_config_t::config_callback config_cb
) {
287 std::unique_lock
locker(lock
);
288 int ret
= config
.set_mon_vals(cct
, values
, obs_mgr
, kv
, config_cb
);
290 rev_obs_map_t rev_obs
;
291 _gather_changes(values
.changed
, &rev_obs
, nullptr);
293 call_observers(locker
, rev_obs
);
296 int injectargs(const std::string
&s
, std::ostream
*oss
) {
297 std::unique_lock
locker(lock
);
298 int ret
= config
.injectargs(values
, obs_mgr
, s
, oss
);
300 rev_obs_map_t rev_obs
;
301 _gather_changes(values
.changed
, &rev_obs
, oss
);
303 call_observers(locker
, rev_obs
);
306 void parse_env(unsigned entity_type
,
307 const char *env_var
= "CEPH_ARGS") {
308 std::lock_guard l
{lock
};
309 config
.parse_env(entity_type
, values
, obs_mgr
, env_var
);
311 int parse_argv(std::vector
<const char*>& args
, int level
=CONF_CMDLINE
) {
312 std::lock_guard l
{lock
};
313 return config
.parse_argv(values
, obs_mgr
, args
, level
);
315 int parse_config_files(const char *conf_files
,
316 std::ostream
*warnings
, int flags
) {
317 std::lock_guard l
{lock
};
318 return config
.parse_config_files(values
, obs_mgr
,
319 conf_files
, warnings
, flags
);
321 bool has_parse_error() const {
322 return !config
.parse_error
.empty();
324 void complain_about_parse_error(CephContext
*cct
) {
325 return config
.complain_about_parse_error(cct
);
327 void do_argv_commands() const {
328 std::lock_guard l
{lock
};
329 config
.do_argv_commands(values
);
331 void get_config_bl(uint64_t have_version
,
332 ceph::buffer::list
*bl
,
333 uint64_t *got_version
) {
334 std::lock_guard l
{lock
};
335 config
.get_config_bl(values
, have_version
, bl
, got_version
);
337 void get_defaults_bl(ceph::buffer::list
*bl
) {
338 std::lock_guard l
{lock
};
339 config
.get_defaults_bl(values
, bl
);