]>
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 | } | |
20effc67 | 128 | int get_val(std::string_view key, std::string *val) const { |
11fdf7f2 TL |
129 | return get_config().get_val(*values, key, val); |
130 | } | |
131 | template<typename T> | |
20effc67 | 132 | const T get_val(std::string_view key) const { |
11fdf7f2 TL |
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 | ||
f67539c2 TL |
158 | seastar::future<> inject_args(const std::string& s) { |
159 | return do_change([s, this](ConfigValues& values) { | |
160 | std::stringstream err; | |
161 | if (get_config().injectargs(values, obs_mgr, s, &err)) { | |
162 | throw std::invalid_argument(err.str()); | |
163 | } | |
164 | }); | |
165 | } | |
9f95a23c TL |
166 | void show_config(ceph::Formatter* f) const; |
167 | ||
168 | seastar::future<> parse_argv(std::vector<const char*>& argv) { | |
169 | // we could pass whatever is unparsed to seastar, but seastar::app_template | |
170 | // is used for driving the seastar application, and | |
171 | // crimson::common::ConfigProxy is not available until seastar engine is up | |
172 | // and running, so we have to feed the command line args to app_template | |
173 | // first, then pass them to ConfigProxy. | |
174 | return do_change([&argv, this](ConfigValues& values) { | |
175 | get_config().parse_argv(values, | |
176 | obs_mgr, | |
177 | argv, | |
178 | CONF_CMDLINE); | |
179 | }); | |
180 | } | |
181 | ||
20effc67 TL |
182 | seastar::future<> parse_env() { |
183 | return do_change([this](ConfigValues& values) { | |
184 | get_config().parse_env(CEPH_ENTITY_TYPE_OSD, | |
185 | values, | |
186 | obs_mgr); | |
187 | }); | |
188 | } | |
189 | ||
f67539c2 | 190 | seastar::future<> parse_config_files(const std::string& conf_files); |
11fdf7f2 TL |
191 | |
192 | using ShardedConfig = seastar::sharded<ConfigProxy>; | |
193 | ||
194 | private: | |
195 | static ShardedConfig sharded_conf; | |
196 | friend ConfigProxy& local_conf(); | |
197 | friend ShardedConfig& sharded_conf(); | |
198 | }; | |
199 | ||
200 | inline ConfigProxy& local_conf() { | |
201 | return ConfigProxy::sharded_conf.local(); | |
202 | } | |
203 | ||
204 | inline ConfigProxy::ShardedConfig& sharded_conf() { | |
205 | return ConfigProxy::sharded_conf; | |
206 | } | |
207 | ||
20effc67 TL |
208 | template<typename T> |
209 | const T get_conf(const std::string& key) { | |
210 | return local_conf().template get_val<T>(key); | |
211 | } | |
212 | ||
11fdf7f2 | 213 | } |