]>
Commit | Line | Data |
---|---|---|
11fdf7f2 | 1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
9f95a23c | 2 | // vim: ts=8 sw=2 smarttab |
11fdf7f2 TL |
3 | |
4 | #pragma once | |
5 | ||
6 | #include <seastar/core/reactor.hh> | |
7 | #include <seastar/core/sharded.hh> | |
8 | #include "common/config.h" | |
9 | #include "common/config_obs.h" | |
10 | #include "common/config_obs_mgr.h" | |
11 | #include "common/errno.h" | |
12 | ||
9f95a23c TL |
13 | namespace ceph { |
14 | class Formatter; | |
15 | } | |
16 | ||
17 | namespace crimson::common { | |
11fdf7f2 TL |
18 | |
19 | // a facade for managing config. each shard has its own copy of ConfigProxy. | |
20 | // | |
21 | // In seastar-osd, there could be multiple instances of @c ConfigValues in a | |
22 | // single process, as we are using a variant of read-copy-update mechinary to | |
23 | // update the settings at runtime. | |
24 | class ConfigProxy : public seastar::peering_sharded_service<ConfigProxy> | |
25 | { | |
26 | using LocalConfigValues = seastar::lw_shared_ptr<ConfigValues>; | |
27 | seastar::foreign_ptr<LocalConfigValues> values; | |
28 | ||
29 | md_config_t* remote_config = nullptr; | |
30 | std::unique_ptr<md_config_t> local_config; | |
31 | ||
32 | using ConfigObserver = ceph::md_config_obs_impl<ConfigProxy>; | |
33 | ObserverMgr<ConfigObserver> obs_mgr; | |
34 | ||
35 | const md_config_t& get_config() const { | |
36 | return remote_config ? *remote_config : * local_config; | |
37 | } | |
38 | md_config_t& get_config() { | |
39 | return remote_config ? *remote_config : * local_config; | |
40 | } | |
41 | ||
42 | // apply changes to all shards | |
43 | // @param func a functor which accepts @c "ConfigValues&" | |
44 | template<typename Func> | |
45 | seastar::future<> do_change(Func&& func) { | |
46 | return container().invoke_on(values.get_owner_shard(), | |
47 | [func = std::move(func)](ConfigProxy& owner) { | |
48 | // apply the changes to a copy of the values | |
49 | auto new_values = seastar::make_lw_shared(*owner.values); | |
50 | new_values->changed.clear(); | |
51 | func(*new_values); | |
52 | ||
53 | // always apply the new settings synchronously on the owner shard, to | |
54 | // avoid racings with other do_change() calls in parallel. | |
55 | ObserverMgr<ConfigObserver>::rev_obs_map rev_obs; | |
56 | owner.values.reset(new_values); | |
57 | owner.obs_mgr.for_each_change(owner.values->changed, owner, | |
58 | [&rev_obs](ConfigObserver *obs, | |
59 | const std::string &key) { | |
60 | rev_obs[obs].insert(key); | |
61 | }, nullptr); | |
62 | for (auto& [obs, keys] : rev_obs) { | |
63 | obs->handle_conf_change(owner, keys); | |
64 | } | |
65 | ||
66 | return seastar::parallel_for_each(boost::irange(1u, seastar::smp::count), | |
67 | [&owner, new_values] (auto cpu) { | |
68 | return owner.container().invoke_on(cpu, | |
69 | [foreign_values = seastar::make_foreign(new_values)](ConfigProxy& proxy) mutable { | |
70 | proxy.values.reset(); | |
71 | proxy.values = std::move(foreign_values); | |
72 | ||
73 | ObserverMgr<ConfigObserver>::rev_obs_map rev_obs; | |
74 | proxy.obs_mgr.for_each_change(proxy.values->changed, proxy, | |
9f95a23c TL |
75 | [&rev_obs](ConfigObserver *obs, const std::string& key) { |
76 | rev_obs[obs].insert(key); | |
77 | }, nullptr); | |
11fdf7f2 TL |
78 | for (auto& obs_keys : rev_obs) { |
79 | obs_keys.first->handle_conf_change(proxy, obs_keys.second); | |
80 | } | |
81 | }); | |
82 | }).finally([new_values] { | |
83 | new_values->changed.clear(); | |
84 | }); | |
85 | }); | |
86 | } | |
87 | public: | |
88 | ConfigProxy(const EntityName& name, std::string_view cluster); | |
89 | const ConfigValues* operator->() const noexcept { | |
90 | return values.get(); | |
91 | } | |
9f95a23c TL |
92 | const ConfigValues get_config_values() { |
93 | return *values.get(); | |
94 | } | |
11fdf7f2 TL |
95 | ConfigValues* operator->() noexcept { |
96 | return values.get(); | |
97 | } | |
98 | ||
99 | // required by sharded<> | |
100 | seastar::future<> start(); | |
101 | seastar::future<> stop() { | |
102 | return seastar::make_ready_future<>(); | |
103 | } | |
104 | void add_observer(ConfigObserver* obs) { | |
105 | obs_mgr.add_observer(obs); | |
106 | } | |
107 | void remove_observer(ConfigObserver* obs) { | |
108 | obs_mgr.remove_observer(obs); | |
109 | } | |
110 | seastar::future<> rm_val(const std::string& key) { | |
111 | return do_change([key, this](ConfigValues& values) { | |
112 | auto ret = get_config().rm_val(values, key); | |
113 | if (ret < 0) { | |
114 | throw std::invalid_argument(cpp_strerror(ret)); | |
115 | } | |
116 | }); | |
117 | } | |
118 | seastar::future<> set_val(const std::string& key, | |
119 | const std::string& val) { | |
120 | return do_change([key, val, this](ConfigValues& values) { | |
121 | std::stringstream err; | |
122 | auto ret = get_config().set_val(values, obs_mgr, key, val, &err); | |
123 | if (ret < 0) { | |
124 | throw std::invalid_argument(err.str()); | |
125 | } | |
126 | }); | |
127 | } | |
128 | int get_val(const std::string &key, std::string *val) const { | |
129 | return get_config().get_val(*values, key, val); | |
130 | } | |
131 | template<typename T> | |
132 | const T get_val(const std::string& key) const { | |
133 | return get_config().template get_val<T>(*values, key); | |
134 | } | |
135 | ||
136 | int get_all_sections(std::vector<std::string>& sections) const { | |
137 | return get_config().get_all_sections(sections); | |
138 | } | |
139 | ||
140 | int get_val_from_conf_file(const std::vector<std::string>& sections, | |
141 | const std::string& key, std::string& out, | |
142 | bool expand_meta) const { | |
143 | return get_config().get_val_from_conf_file(*values, sections, key, | |
144 | out, expand_meta); | |
145 | } | |
146 | ||
147 | unsigned get_osd_pool_default_min_size(uint8_t size) const { | |
148 | return get_config().get_osd_pool_default_min_size(*values, size); | |
149 | } | |
150 | ||
9f95a23c TL |
151 | seastar::future<> |
152 | set_mon_vals(const std::map<std::string,std::string,std::less<>>& kv) { | |
11fdf7f2 TL |
153 | return do_change([kv, this](ConfigValues& values) { |
154 | get_config().set_mon_vals(nullptr, values, obs_mgr, kv, nullptr); | |
155 | }); | |
156 | } | |
157 | ||
9f95a23c TL |
158 | void show_config(ceph::Formatter* f) const; |
159 | ||
160 | seastar::future<> parse_argv(std::vector<const char*>& argv) { | |
161 | // we could pass whatever is unparsed to seastar, but seastar::app_template | |
162 | // is used for driving the seastar application, and | |
163 | // crimson::common::ConfigProxy is not available until seastar engine is up | |
164 | // and running, so we have to feed the command line args to app_template | |
165 | // first, then pass them to ConfigProxy. | |
166 | return do_change([&argv, this](ConfigValues& values) { | |
167 | get_config().parse_argv(values, | |
168 | obs_mgr, | |
169 | argv, | |
170 | CONF_CMDLINE); | |
171 | }); | |
172 | } | |
173 | ||
11fdf7f2 TL |
174 | seastar::future<> parse_config_files(const std::string& conf_files) { |
175 | return do_change([this, conf_files](ConfigValues& values) { | |
176 | const char* conf_file_paths = | |
177 | conf_files.empty() ? nullptr : conf_files.c_str(); | |
178 | get_config().parse_config_files(values, | |
179 | obs_mgr, | |
180 | conf_file_paths, | |
181 | &std::cerr, | |
182 | CODE_ENVIRONMENT_DAEMON); | |
183 | }); | |
184 | } | |
185 | ||
186 | using ShardedConfig = seastar::sharded<ConfigProxy>; | |
187 | ||
188 | private: | |
189 | static ShardedConfig sharded_conf; | |
190 | friend ConfigProxy& local_conf(); | |
191 | friend ShardedConfig& sharded_conf(); | |
192 | }; | |
193 | ||
194 | inline ConfigProxy& local_conf() { | |
195 | return ConfigProxy::sharded_conf.local(); | |
196 | } | |
197 | ||
198 | inline ConfigProxy::ShardedConfig& sharded_conf() { | |
199 | return ConfigProxy::sharded_conf; | |
200 | } | |
201 | ||
202 | } |