1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
18 #include "common/ConfUtils.h"
19 #include "common/entity_name.h"
20 #include "common/Mutex.h"
21 #include "log/SubsystemMap.h"
22 #include "common/config_obs.h"
24 #define OSD_REP_PRIMARY 0
25 #define OSD_REP_SPLAY 1
26 #define OSD_REP_CHAIN 2
30 extern const char *CEPH_CONF_FILE_DEFAULT
;
32 #define LOG_TO_STDERR_NONE 0
33 #define LOG_TO_STDERR_SOME 1
34 #define LOG_TO_STDERR_ALL 2
36 /** This class represents the current Ceph configuration.
38 * For Ceph daemons, this is the daemon configuration. Log levels, caching
39 * settings, btrfs settings, and so forth can all be found here. For libcephfs
40 * and librados users, this is the configuration associated with their context.
42 * For information about how this class is loaded from a configuration file,
43 * see common/ConfUtils.
47 * There are 3 ways to read the ceph context-- the old way and two new ways.
48 * In the old way, code would simply read the public variables of the
49 * configuration, without taking a lock. In the new way #1, code registers a
50 * configuration obserever which receives callbacks when a value changes. These
51 * callbacks take place under the md_config_t lock. Alternatively one can use
52 * get_val(const char *name) method to safely get a copy of the value.
54 * To prevent serious problems resulting from thread-safety issues, we disallow
55 * changing std::string configuration values after
56 * md_config_t::internal_safe_to_start_threads becomes true. You can still
57 * change integer or floating point values, and the option declared with
58 * SAFE_OPTION macro. Notice the latter options can not be read directly
59 * (conf->foo), one should use either observers or get_val() method
60 * (conf->get_val("foo")).
62 * FIXME: really we shouldn't allow changing integer or floating point values
63 * while another thread is reading them, either.
67 /* Maps configuration options to the observer listening for them. */
68 typedef std::multimap
<std::string
, md_config_obs_t
*> obs_map_t
;
70 /* Set of configuration options that have changed since the last
72 typedef std::set
< std::string
> changed_set_t
;
74 struct invalid_config_value_t
{ };
75 typedef boost::variant
<invalid_config_value_t
,
85 uuid_d
> config_value_t
;
86 typedef boost::variant
<const int md_config_t::*,
87 const long long md_config_t::*,
88 const std::string
md_config_t::*,
89 const double md_config_t::*,
90 const float md_config_t::*,
91 const bool md_config_t::*,
92 const entity_addr_t
md_config_t::*,
93 const uint32_t md_config_t::*,
94 const uint64_t md_config_t::*,
95 const uuid_d
md_config_t::*> member_ptr_t
;
98 OPT_INT
, OPT_LONGLONG
, OPT_STR
, OPT_DOUBLE
, OPT_FLOAT
, OPT_BOOL
,
99 OPT_ADDR
, OPT_U32
, OPT_U64
, OPT_UUID
102 typedef std::function
<int(std::string
*, std::string
*)> validator_t
;
104 class config_option
{
108 md_config_t::member_ptr_t md_member_ptr
;
109 bool safe
; // promise to access it only via md_config_t::get_val
110 validator_t validator
;
112 template<typename T
> struct get_typed_pointer_visitor
: public boost::static_visitor
<T
const *> {
113 md_config_t
const *conf
;
114 explicit get_typed_pointer_visitor(md_config_t
const *conf_
) : conf(conf_
) { }
116 typename
boost::enable_if
<boost::is_same
<T
, U
>, int>::type
= 0>
117 T
const *operator()(const U
md_config_t::* member_ptr
) {
118 return &(conf
->*member_ptr
);
121 typename
boost::enable_if_c
<!boost::is_same
<T
, U
>::value
, int>::type
= 0>
122 T
const *operator()(const U
md_config_t::* member_ptr
) {
127 // is it OK to alter the value when threads are running?
128 bool is_safe() const;
129 // Given a configuration, return a pointer to this option inside
130 // that configuration.
131 template<typename T
> void conf_ptr(T
const *&ptr
, md_config_t
const *conf
) const {
132 get_typed_pointer_visitor
<T
> gtpv(conf
);
133 ptr
= boost::apply_visitor(gtpv
, md_member_ptr
);
135 template<typename T
> void conf_ptr(T
*&ptr
, md_config_t
*conf
) const {
136 get_typed_pointer_visitor
<T
> gtpv(conf
);
137 ptr
= const_cast<T
*>(boost::apply_visitor(gtpv
, md_member_ptr
));
139 template<typename T
> T
const *conf_ptr(md_config_t
const *conf
) const {
140 get_typed_pointer_visitor
<T
> gtpv(conf
);
141 return boost::apply_visitor(gtpv
, md_member_ptr
);
143 template<typename T
> T
*conf_ptr(md_config_t
*conf
) const {
144 get_typed_pointer_visitor
<T
> gtpv(conf
);
145 return const_cast<T
*>(boost::apply_visitor(gtpv
, md_member_ptr
));
149 // Create a new md_config_t structure.
153 // Adds a new observer to this configuration. You can do this at any time,
154 // but it will only receive notifications for the changes that happen after
155 // you attach it, obviously.
157 // Most developers will probably attach their observers after global_init,
158 // but before anyone can call injectargs.
160 // The caller is responsible for allocating observers.
161 void add_observer(md_config_obs_t
* observer_
);
163 // Remove an observer from this configuration.
164 // This doesn't delete the observer! If you allocated it with new(),
165 // you need to delete it yourself.
166 // This function will assert if you try to delete an observer that isn't
168 void remove_observer(md_config_obs_t
* observer_
);
170 // Parse a config file
171 int parse_config_files(const char *conf_files
,
172 std::ostream
*warnings
, int flags
);
174 // Absorb config settings from the environment
177 // Absorb config settings from argv
178 int parse_argv(std::vector
<const char*>& args
);
180 // Expand all metavariables. Make any pending observer callbacks.
181 void apply_changes(std::ostream
*oss
);
182 void _apply_changes(std::ostream
*oss
);
183 bool _internal_field(const string
& k
);
184 void call_all_observers();
186 // Called by the Ceph daemons to make configuration changes at runtime
187 int injectargs(const std::string
&s
, std::ostream
*oss
);
189 // Set a configuration value, or crash
190 // Metavariables will be expanded.
191 void set_val_or_die(const char *key
, const char *val
);
193 // Set a configuration value.
194 // Metavariables will be expanded.
195 int set_val(const char *key
, const char *val
, bool meta
=true);
196 int set_val(const char *key
, const string
& s
, bool meta
=true) {
197 return set_val(key
, s
.c_str(), meta
);
200 // Get a configuration value.
201 // No metavariables will be returned (they will have already been expanded)
202 int get_val(const char *key
, char **buf
, int len
) const;
203 int _get_val(const char *key
, char **buf
, int len
) const;
204 config_value_t
get_val_generic(const char *key
) const;
205 template<typename T
> T
get_val(const char *key
) const;
207 void get_all_keys(std::vector
<std::string
> *keys
) const;
209 // Return a list of all the sections that the current entity is a member of.
210 void get_my_sections(std::vector
<std::string
> §ions
) const;
212 // Return a list of all sections
213 int get_all_sections(std::vector
<std::string
> §ions
) const;
215 // Get a value from the configuration file that we read earlier.
216 // Metavariables will be expanded if emeta is true.
217 int get_val_from_conf_file(const std::vector
<std::string
> §ions
,
218 const char *key
, std::string
&out
, bool emeta
) const;
220 /// dump all config values to a stream
221 void show_config(std::ostream
& out
);
222 /// dump all config values to a formatter
223 void show_config(Formatter
*f
);
225 /// obtain a diff between our config values and another md_config_t values
226 void diff(const md_config_t
*other
,
227 map
<string
,pair
<string
,string
> > *diff
, set
<string
> *unknown
);
229 /// obtain a diff between config values and another md_config_t
230 /// values for a specific setting.
231 void diff(const md_config_t
*other
,
232 map
<string
,pair
<string
,string
>> *diff
, set
<string
> *unknown
,
233 const string
& setting
);
235 /// print/log warnings/errors from parsing the config
236 void complain_about_parse_errors(CephContext
*cct
);
239 void validate_default_settings();
241 int _get_val(const char *key
, std::string
*value
) const;
242 config_value_t
_get_val(const char *key
) const;
243 void _show_config(std::ostream
*out
, Formatter
*f
);
245 void _get_my_sections(std::vector
<std::string
> §ions
) const;
247 int _get_val_from_conf_file(const std::vector
<std::string
> §ions
,
248 const char *key
, std::string
&out
, bool emeta
) const;
250 int parse_option(std::vector
<const char*>& args
,
251 std::vector
<const char*>::iterator
& i
,
253 int parse_injectargs(std::vector
<const char*>& args
,
255 int parse_config_files_impl(const std::list
<std::string
> &conf_files
,
256 std::ostream
*warnings
);
258 int set_val_impl(const std::string
&val
, config_option
const *opt
,
259 std::string
*error_message
);
260 int set_val_raw(const char *val
, config_option
const *opt
);
264 bool expand_meta(std::string
&val
,
265 std::ostream
*oss
) const;
267 void diff_helper(const md_config_t
* other
,
268 map
<string
, pair
<string
, string
>>* diff
,
269 set
<string
>* unknown
, const string
& setting
= string
{});
271 public: // for global_init
272 bool early_expand_meta(std::string
&val
,
273 std::ostream
*oss
) const {
274 Mutex::Locker
l(lock
);
275 return expand_meta(val
, oss
);
278 bool expand_meta(std::string
&val
,
279 config_option
const *opt
,
280 std::list
<config_option
const *> stack
,
281 std::ostream
*oss
) const;
283 /// expand all metavariables in config structure.
284 void expand_all_meta();
286 // The configuration file we read, or NULL if we haven't read one.
289 std::deque
<std::string
> parse_errors
;
293 changed_set_t changed
;
296 ceph::logging::SubsystemMap subsys
;
299 string data_dir_option
; ///< data_dir config option, if any
304 #define OPTION_OPT_INT(name) const int name;
305 #define OPTION_OPT_LONGLONG(name) const long long name;
306 #define OPTION_OPT_STR(name) const std::string name;
307 #define OPTION_OPT_DOUBLE(name) const double name;
308 #define OPTION_OPT_FLOAT(name) const float name;
309 #define OPTION_OPT_BOOL(name) const bool name;
310 #define OPTION_OPT_ADDR(name) const entity_addr_t name;
311 #define OPTION_OPT_U32(name) const uint32_t name;
312 #define OPTION_OPT_U64(name) const uint64_t name;
313 #define OPTION_OPT_UUID(name) const uuid_d name;
314 #define OPTION(name, ty, init) \
317 struct option_##name##_t;
318 #define OPTION_VALIDATOR(name)
319 #define SAFE_OPTION(name, ty, init) \
323 struct option_##name##_t;
324 #define SUBSYS(name, log, gather)
325 #define DEFAULT_SUBSYS(log, gather)
326 #include "common/config_opts.h"
327 #undef OPTION_OPT_INT
328 #undef OPTION_OPT_LONGLONG
329 #undef OPTION_OPT_STR
330 #undef OPTION_OPT_DOUBLE
331 #undef OPTION_OPT_FLOAT
332 #undef OPTION_OPT_BOOL
333 #undef OPTION_OPT_ADDR
334 #undef OPTION_OPT_U32
335 #undef OPTION_OPT_U64
336 #undef OPTION_OPT_UUID
338 #undef OPTION_VALIDATOR
341 #undef DEFAULT_SUBSYS
343 unsigned get_osd_pool_default_min_size() const {
344 return osd_pool_default_min_size
?
345 MIN(osd_pool_default_min_size
, osd_pool_default_size
) :
346 osd_pool_default_size
- osd_pool_default_size
/ 2;
349 /** A lock that protects the md_config_t internals. It is
350 * recursive, for simplicity.
351 * It is best if this lock comes first in the lock hierarchy. We will
352 * hold this lock when calling configuration observers. */
355 friend class test_md_config_t
;
357 // Tests and possibly users expect options to appear in the output
358 // of ceph-conf in the same order as declared in config_opts.h
359 std::shared_ptr
<const std::vector
<config_option
>> config_options
;
360 config_option
const *find_config_option(const std::string
& normalized_key
) const;
364 struct get_typed_value_visitor
: public boost::static_visitor
<T
> {
366 typename
boost::enable_if
<boost::is_same
<T
, U
>, int>::type
= 0>
367 T
operator()(U
& val
) {
368 return std::move(val
);
371 typename
boost::enable_if_c
<!boost::is_same
<T
, U
>::value
, int>::type
= 0>
372 T
operator()(U
&val
) {
373 assert("wrong type or option does not exist" == nullptr);
377 template<typename T
> T
md_config_t::get_val(const char *key
) const {
378 config_value_t generic_val
= this->get_val_generic(key
);
379 get_typed_value_visitor
<T
> gtv
;
380 return boost::apply_visitor(gtv
, generic_val
);
383 inline std::ostream
& operator<<(std::ostream
& o
, const md_config_t::invalid_config_value_t
& ) {
384 return o
<< "INVALID_CONFIG_VALUE";
387 int ceph_resolve_file_search(const std::string
& filename_list
,
388 std::string
& result
);
390 typedef md_config_t::config_option config_option
;
393 enum config_subsys_id
{
394 ceph_subsys_
, // default
395 #define OPTION(a,b,c)
396 #define OPTION_VALIDATOR(name)
397 #define SAFE_OPTION(a,b,c)
398 #define SUBSYS(name, log, gather) \
400 #define DEFAULT_SUBSYS(log, gather)
401 #include "common/config_opts.h"
404 #undef OPTION_VALIDATOR
406 #undef DEFAULT_SUBSYS