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
15 static ConfigValues
get_config_values(const ConfigProxy
&config_proxy
) {
16 std::lock_guard
locker(config_proxy
.lock
);
17 return config_proxy
.values
;
21 * The current values of all settings described by the schema
24 using md_config_obs_t
= ceph::md_config_obs_impl
<ConfigProxy
>;
25 ObserverMgr
<md_config_obs_t
> obs_mgr
;
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");
36 uint32_t call_count
= 0;
38 ceph::condition_variable cond
;
41 : lock(ceph::make_mutex("call::gate::lock")) {
45 std::lock_guard
<ceph::mutex
> locker(lock
);
49 std::lock_guard
<ceph::mutex
> locker(lock
);
50 ceph_assert(call_count
> 0);
51 if (--call_count
== 0) {
56 std::unique_lock
<ceph::mutex
> locker(lock
);
57 while (call_count
!= 0) {
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());
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());
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());
79 using rev_obs_map_t
= ObserverMgr
<md_config_obs_t
>::rev_obs_map
;
80 typedef std::unique_ptr
<CallGate
> CallGateRef
;
82 std::map
<md_config_obs_t
*, CallGateRef
> obs_call_gate
;
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
88 for (auto& [obs
, keys
] : rev_obs
) {
89 obs
->handle_conf_change(*this, keys
);
93 for (auto& rev_ob
: rev_obs
) {
94 call_gate_leave(rev_ob
.first
);
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
));
102 auto [it
, new_entry
] = rev_obs
->emplace(obs
, std::set
<std::string
>{});
103 it
->second
.emplace(key
);
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
);
113 explicit ConfigProxy(bool is_daemon
)
114 : config
{values
, obs_mgr
, is_daemon
}
116 explicit ConfigProxy(const ConfigProxy
&config_proxy
)
117 : values(get_config_values(config_proxy
)),
118 config
{values
, obs_mgr
, config_proxy
.config
.is_daemon
}
120 const ConfigValues
* operator->() const noexcept
{
123 ConfigValues
* operator->() noexcept
{
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
);
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
);
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
);
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
)...);
146 void config_options(Formatter
*f
) const {
147 config
.config_options(f
);
149 const decltype(md_config_t::schema
)& get_schema() const {
150 return config
.schema
;
152 const Option
* get_schema(const std::string
& key
) const {
153 auto found
= config
.schema
.find(key
);
154 if (found
== config
.schema
.end()) {
157 return &found
->second
;
160 const Option
*find_option(const string
& name
) const {
161 return config
.find_option(name
);
163 void diff(Formatter
*f
, const std::string
& name
=string
{}) const {
164 std::lock_guard l
{lock
};
165 return config
.diff(values
, f
, name
);
167 void get_my_sections(std::vector
<std::string
> §ions
) const {
168 std::lock_guard l
{lock
};
169 config
.get_my_sections(values
, sections
);
171 int get_all_sections(std::vector
<std::string
>& sections
) const {
172 std::lock_guard l
{lock
};
173 return config
.get_all_sections(sections
);
175 int get_val_from_conf_file(const std::vector
<std::string
>& sections
,
176 const std::string
& key
, std::string
& out
,
178 std::lock_guard l
{lock
};
179 return config
.get_val_from_conf_file(values
,
180 sections
, key
, out
, emeta
);
182 unsigned get_osd_pool_default_min_size(uint8_t size
) const {
183 return config
.get_osd_pool_default_min_size(values
, size
);
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
);
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();
199 call_observers(locker
, rev_obs
);
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
>());
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
);
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
);
220 call_observers(locker
, rev_obs
);
222 void set_safe_to_start_threads() {
223 config
.set_safe_to_start_threads();
225 void _clear_safe_to_start_threads() {
226 config
._clear_safe_to_start_threads();
228 void show_config(std::ostream
& out
) {
229 std::lock_guard l
{lock
};
230 config
.show_config(values
, out
);
232 void show_config(Formatter
*f
) {
233 std::lock_guard l
{lock
};
234 config
.show_config(values
, f
);
236 void config_options(Formatter
*f
) {
237 std::lock_guard l
{lock
};
238 config
.config_options(f
);
240 int rm_val(const std::string
& key
) {
241 std::lock_guard l
{lock
};
242 return config
.rm_val(values
, key
);
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
;
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();
256 call_observers(locker
, rev_obs
);
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(
262 [this, rev_obs
](md_config_obs_t
*obs
, const std::string
&key
) {
263 map_observer_changes(obs
, key
, rev_obs
);
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
);
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
);
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
);
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
);
285 rev_obs_map_t rev_obs
;
286 _gather_changes(values
.changed
, &rev_obs
, nullptr);
287 values
.changed
.clear();
289 call_observers(locker
, rev_obs
);
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
);
296 rev_obs_map_t rev_obs
;
297 _gather_changes(values
.changed
, &rev_obs
, oss
);
298 values
.changed
.clear();
300 call_observers(locker
, rev_obs
);
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
);
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
);
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
);
318 size_t num_parse_errors() const {
319 return config
.parse_errors
.size();
321 void complain_about_parse_errors(CephContext
*cct
) {
322 return config
.complain_about_parse_errors(cct
);
324 void do_argv_commands() const {
325 std::lock_guard l
{lock
};
326 config
.do_argv_commands(values
);
328 void get_config_bl(uint64_t have_version
,
330 uint64_t *got_version
) {
331 std::lock_guard l
{lock
};
332 config
.get_config_bl(values
, have_version
, bl
, got_version
);
334 void get_defaults_bl(bufferlist
*bl
) {
335 std::lock_guard l
{lock
};
336 config
.get_defaults_bl(values
, bl
);