]> git.proxmox.com Git - ceph.git/blame - ceph/src/crimson/common/config_proxy.h
import quincy beta 17.1.0
[ceph.git] / ceph / src / crimson / common / config_proxy.h
CommitLineData
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
13namespace ceph {
14class Formatter;
15}
16
17namespace 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.
24class 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 }
87public:
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
194private:
195 static ShardedConfig sharded_conf;
196 friend ConfigProxy& local_conf();
197 friend ShardedConfig& sharded_conf();
198};
199
200inline ConfigProxy& local_conf() {
201 return ConfigProxy::sharded_conf.local();
202}
203
204inline ConfigProxy::ShardedConfig& sharded_conf() {
205 return ConfigProxy::sharded_conf;
206}
207
20effc67
TL
208template<typename T>
209const T get_conf(const std::string& key) {
210 return local_conf().template get_val<T>(key);
211}
212
11fdf7f2 213}