/root/doris/cloud/src/common/configbase.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | |
18 | | #include <fmt/core.h> |
19 | | |
20 | | #include <algorithm> |
21 | | #include <cerrno> |
22 | | #include <cstring> |
23 | | #include <filesystem> |
24 | | #include <fstream> |
25 | | #include <iostream> |
26 | | #include <list> |
27 | | #include <map> |
28 | | #include <mutex> |
29 | | #include <shared_mutex> |
30 | | #include <sstream> |
31 | | #include <utility> |
32 | | |
33 | | #define __IN_CONFIGBASE_CPP__ |
34 | | #include "common/config.h" |
35 | | #undef __IN_CONFIGBASE_CPP__ |
36 | | |
37 | | namespace doris::cloud::config { |
38 | | |
39 | | std::map<std::string, Register::Field>* Register::_s_field_map = nullptr; |
40 | | std::map<std::string, std::function<bool()>>* RegisterConfValidator::_s_field_validator = nullptr; |
41 | | std::map<std::string, std::string>* full_conf_map = nullptr; |
42 | | std::shared_mutex mutable_string_config_lock; |
43 | | std::mutex conf_persist_lock; |
44 | | |
45 | | // trim string |
46 | 2.80k | std::string& trim(std::string& s) { |
47 | | // rtrim |
48 | 2.80k | s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char c) { return !std::isspace(c); }) |
49 | 2.80k | .base(), |
50 | 2.80k | s.end()); |
51 | | // ltrim |
52 | 2.80k | s.erase(s.begin(), |
53 | 2.80k | std::find_if(s.begin(), s.end(), [](unsigned char c) { return !std::isspace(c); })); |
54 | 2.80k | return s; |
55 | 2.80k | } |
56 | | |
57 | | // split string by '=' |
58 | 100 | void splitkv(const std::string& s, std::string& k, std::string& v) { |
59 | 100 | const char sep = '='; |
60 | 100 | int start = 0; |
61 | 100 | int end = 0; |
62 | 100 | if ((end = s.find(sep, start)) != std::string::npos) { |
63 | 100 | k = s.substr(start, end - start); |
64 | 100 | v = s.substr(end + 1); |
65 | 100 | } else { |
66 | 0 | k = s; |
67 | 0 | v = ""; |
68 | 0 | } |
69 | 100 | } |
70 | | |
71 | | // replace env variables |
72 | 2.17k | bool replaceenv(std::string& s) { |
73 | 2.17k | std::size_t pos = 0; |
74 | 2.17k | std::size_t start = 0; |
75 | 2.17k | while ((start = s.find("${", pos)) != std::string::npos) { |
76 | 0 | std::size_t end = s.find("}", start + 2); |
77 | 0 | if (end == std::string::npos) { |
78 | 0 | return false; |
79 | 0 | } |
80 | 0 | std::string envkey = s.substr(start + 2, end - start - 2); |
81 | 0 | const char* envval = std::getenv(envkey.c_str()); |
82 | 0 | if (envval == nullptr) { |
83 | 0 | return false; |
84 | 0 | } |
85 | 0 | s.erase(start, end - start + 1); |
86 | 0 | s.insert(start, envval); |
87 | 0 | pos = start + strlen(envval); |
88 | 0 | } |
89 | 2.17k | return true; |
90 | 2.17k | } |
91 | | |
92 | | bool strtox(const std::string& valstr, bool& retval); |
93 | | bool strtox(const std::string& valstr, int16_t& retval); |
94 | | bool strtox(const std::string& valstr, int32_t& retval); |
95 | | bool strtox(const std::string& valstr, int64_t& retval); |
96 | | bool strtox(const std::string& valstr, double& retval); |
97 | | bool strtox(const std::string& valstr, std::string& retval); |
98 | | |
99 | | template <typename T> |
100 | 68 | bool strtox(const std::string& valstr, std::vector<T>& retval) { |
101 | 68 | std::stringstream ss(valstr); |
102 | 68 | std::string item; |
103 | 68 | T t; |
104 | 68 | while (std::getline(ss, item, ',')) { |
105 | 0 | if (!strtox(trim(item), t)) { |
106 | 0 | return false; |
107 | 0 | } |
108 | 0 | retval.push_back(t); |
109 | 0 | } |
110 | 68 | return true; |
111 | 68 | } Unexecuted instantiation: _ZN5doris5cloud6config6strtoxIbEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERSt6vectorIT_SaISC_EE Unexecuted instantiation: _ZN5doris5cloud6config6strtoxIsEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERSt6vectorIT_SaISC_EE Unexecuted instantiation: _ZN5doris5cloud6config6strtoxIiEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERSt6vectorIT_SaISC_EE Unexecuted instantiation: _ZN5doris5cloud6config6strtoxIlEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERSt6vectorIT_SaISC_EE Unexecuted instantiation: _ZN5doris5cloud6config6strtoxIdEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERSt6vectorIT_SaISC_EE _ZN5doris5cloud6config6strtoxINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEbRKS8_RSt6vectorIT_SaISC_EE Line | Count | Source | 100 | 68 | bool strtox(const std::string& valstr, std::vector<T>& retval) { | 101 | 68 | std::stringstream ss(valstr); | 102 | 68 | std::string item; | 103 | 68 | T t; | 104 | 68 | while (std::getline(ss, item, ',')) { | 105 | 0 | if (!strtox(trim(item), t)) { | 106 | 0 | return false; | 107 | 0 | } | 108 | 0 | retval.push_back(t); | 109 | 0 | } | 110 | 68 | return true; | 111 | 68 | } |
|
112 | | |
113 | 496 | bool strtox(const std::string& valstr, bool& retval) { |
114 | 496 | if (valstr.compare("true") == 0) { |
115 | 205 | retval = true; |
116 | 291 | } else if (valstr.compare("false") == 0) { |
117 | 291 | retval = false; |
118 | 291 | } else { |
119 | 0 | return false; |
120 | 0 | } |
121 | 496 | return true; |
122 | 496 | } |
123 | | |
124 | | template <typename T> |
125 | 995 | bool strtointeger(const std::string& valstr, T& retval) { |
126 | 995 | if (valstr.length() == 0) { |
127 | 0 | return false; // empty-string is only allowed for string type. |
128 | 0 | } |
129 | 995 | char* end; |
130 | 995 | errno = 0; |
131 | 995 | const char* valcstr = valstr.c_str(); |
132 | 995 | int64_t ret64 = strtoll(valcstr, &end, 10); |
133 | 995 | if (errno || end != valcstr + strlen(valcstr)) { |
134 | 0 | return false; // bad parse |
135 | 0 | } |
136 | 995 | T tmp = retval; |
137 | 995 | retval = static_cast<T>(ret64); |
138 | 995 | if (retval != ret64) { |
139 | 0 | retval = tmp; |
140 | 0 | return false; |
141 | 0 | } |
142 | 995 | return true; |
143 | 995 | } _ZN5doris5cloud6config12strtointegerIsEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_ Line | Count | Source | 125 | 17 | bool strtointeger(const std::string& valstr, T& retval) { | 126 | 17 | if (valstr.length() == 0) { | 127 | 0 | return false; // empty-string is only allowed for string type. | 128 | 0 | } | 129 | 17 | char* end; | 130 | 17 | errno = 0; | 131 | 17 | const char* valcstr = valstr.c_str(); | 132 | 17 | int64_t ret64 = strtoll(valcstr, &end, 10); | 133 | 17 | if (errno || end != valcstr + strlen(valcstr)) { | 134 | 0 | return false; // bad parse | 135 | 0 | } | 136 | 17 | T tmp = retval; | 137 | 17 | retval = static_cast<T>(ret64); | 138 | 17 | if (retval != ret64) { | 139 | 0 | retval = tmp; | 140 | 0 | return false; | 141 | 0 | } | 142 | 17 | return true; | 143 | 17 | } |
_ZN5doris5cloud6config12strtointegerIiEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_ Line | Count | Source | 125 | 476 | bool strtointeger(const std::string& valstr, T& retval) { | 126 | 476 | if (valstr.length() == 0) { | 127 | 0 | return false; // empty-string is only allowed for string type. | 128 | 0 | } | 129 | 476 | char* end; | 130 | 476 | errno = 0; | 131 | 476 | const char* valcstr = valstr.c_str(); | 132 | 476 | int64_t ret64 = strtoll(valcstr, &end, 10); | 133 | 476 | if (errno || end != valcstr + strlen(valcstr)) { | 134 | 0 | return false; // bad parse | 135 | 0 | } | 136 | 476 | T tmp = retval; | 137 | 476 | retval = static_cast<T>(ret64); | 138 | 476 | if (retval != ret64) { | 139 | 0 | retval = tmp; | 140 | 0 | return false; | 141 | 0 | } | 142 | 476 | return true; | 143 | 476 | } |
_ZN5doris5cloud6config12strtointegerIlEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_ Line | Count | Source | 125 | 502 | bool strtointeger(const std::string& valstr, T& retval) { | 126 | 502 | if (valstr.length() == 0) { | 127 | 0 | return false; // empty-string is only allowed for string type. | 128 | 0 | } | 129 | 502 | char* end; | 130 | 502 | errno = 0; | 131 | 502 | const char* valcstr = valstr.c_str(); | 132 | 502 | int64_t ret64 = strtoll(valcstr, &end, 10); | 133 | 502 | if (errno || end != valcstr + strlen(valcstr)) { | 134 | 0 | return false; // bad parse | 135 | 0 | } | 136 | 502 | T tmp = retval; | 137 | 502 | retval = static_cast<T>(ret64); | 138 | 502 | if (retval != ret64) { | 139 | 0 | retval = tmp; | 140 | 0 | return false; | 141 | 0 | } | 142 | 502 | return true; | 143 | 502 | } |
|
144 | | |
145 | 17 | bool strtox(const std::string& valstr, int16_t& retval) { |
146 | 17 | return strtointeger(valstr, retval); |
147 | 17 | } |
148 | | |
149 | 476 | bool strtox(const std::string& valstr, int32_t& retval) { |
150 | 476 | return strtointeger(valstr, retval); |
151 | 476 | } |
152 | | |
153 | 502 | bool strtox(const std::string& valstr, int64_t& retval) { |
154 | 502 | return strtointeger(valstr, retval); |
155 | 502 | } |
156 | | |
157 | 0 | bool strtox(const std::string& valstr, double& retval) { |
158 | 0 | if (valstr.length() == 0) { |
159 | 0 | return false; // empty-string is only allowed for string type. |
160 | 0 | } |
161 | 0 | char* end = nullptr; |
162 | 0 | errno = 0; |
163 | 0 | const char* valcstr = valstr.c_str(); |
164 | 0 | retval = strtod(valcstr, &end); |
165 | 0 | if (errno || end != valcstr + strlen(valcstr)) { |
166 | 0 | return false; // bad parse |
167 | 0 | } |
168 | 0 | return true; |
169 | 0 | } |
170 | | |
171 | 618 | bool strtox(const std::string& valstr, std::string& retval) { |
172 | 618 | retval = valstr; |
173 | 618 | return true; |
174 | 618 | } |
175 | | |
176 | | template <typename T> |
177 | 2.17k | bool convert(const std::string& value, T& retval) { |
178 | 2.17k | std::string valstr(value); |
179 | 2.17k | trim(valstr); |
180 | 2.17k | if (!replaceenv(valstr)) { |
181 | 0 | return false; |
182 | 0 | } |
183 | 2.17k | return strtox(valstr, retval); |
184 | 2.17k | } Unexecuted instantiation: _ZN5doris5cloud6config7convertISt6vectorIbSaIbEEEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_ Unexecuted instantiation: _ZN5doris5cloud6config7convertISt6vectorIsSaIsEEEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_ Unexecuted instantiation: _ZN5doris5cloud6config7convertISt6vectorIiSaIiEEEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_ Unexecuted instantiation: _ZN5doris5cloud6config7convertISt6vectorIlSaIlEEEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_ Unexecuted instantiation: _ZN5doris5cloud6config7convertISt6vectorIdSaIdEEEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_ _ZN5doris5cloud6config7convertISt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS9_EEEEbRKS9_RT_ Line | Count | Source | 177 | 68 | bool convert(const std::string& value, T& retval) { | 178 | 68 | std::string valstr(value); | 179 | 68 | trim(valstr); | 180 | 68 | if (!replaceenv(valstr)) { | 181 | 0 | return false; | 182 | 0 | } | 183 | 68 | return strtox(valstr, retval); | 184 | 68 | } |
_ZN5doris5cloud6config7convertIbEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_ Line | Count | Source | 177 | 496 | bool convert(const std::string& value, T& retval) { | 178 | 496 | std::string valstr(value); | 179 | 496 | trim(valstr); | 180 | 496 | if (!replaceenv(valstr)) { | 181 | 0 | return false; | 182 | 0 | } | 183 | 496 | return strtox(valstr, retval); | 184 | 496 | } |
_ZN5doris5cloud6config7convertIsEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_ Line | Count | Source | 177 | 17 | bool convert(const std::string& value, T& retval) { | 178 | 17 | std::string valstr(value); | 179 | 17 | trim(valstr); | 180 | 17 | if (!replaceenv(valstr)) { | 181 | 0 | return false; | 182 | 0 | } | 183 | 17 | return strtox(valstr, retval); | 184 | 17 | } |
_ZN5doris5cloud6config7convertIiEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_ Line | Count | Source | 177 | 476 | bool convert(const std::string& value, T& retval) { | 178 | 476 | std::string valstr(value); | 179 | 476 | trim(valstr); | 180 | 476 | if (!replaceenv(valstr)) { | 181 | 0 | return false; | 182 | 0 | } | 183 | 476 | return strtox(valstr, retval); | 184 | 476 | } |
_ZN5doris5cloud6config7convertIlEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_ Line | Count | Source | 177 | 502 | bool convert(const std::string& value, T& retval) { | 178 | 502 | std::string valstr(value); | 179 | 502 | trim(valstr); | 180 | 502 | if (!replaceenv(valstr)) { | 181 | 0 | return false; | 182 | 0 | } | 183 | 502 | return strtox(valstr, retval); | 184 | 502 | } |
Unexecuted instantiation: _ZN5doris5cloud6config7convertIdEEbRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERT_ _ZN5doris5cloud6config7convertINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEbRKS8_RT_ Line | Count | Source | 177 | 618 | bool convert(const std::string& value, T& retval) { | 178 | 618 | std::string valstr(value); | 179 | 618 | trim(valstr); | 180 | 618 | if (!replaceenv(valstr)) { | 181 | 0 | return false; | 182 | 0 | } | 183 | 618 | return strtox(valstr, retval); | 184 | 618 | } |
|
185 | | |
186 | | // load conf file |
187 | 21 | bool Properties::load(const char* conf_file, bool must_exist) { |
188 | | // if conf_file is null, use the empty props |
189 | 21 | if (conf_file == nullptr) { |
190 | 5 | return true; |
191 | 5 | } |
192 | | |
193 | | // open the conf file |
194 | 16 | std::ifstream input(conf_file); |
195 | 16 | if (!input.is_open()) { |
196 | 0 | if (must_exist) { |
197 | 0 | std::cerr << "config::load() failed to open the file:" << conf_file << std::endl; |
198 | 0 | return false; |
199 | 0 | } |
200 | 0 | return true; |
201 | 0 | } |
202 | | |
203 | | // load properties |
204 | 16 | std::string line; |
205 | 16 | std::string key; |
206 | 16 | std::string value; |
207 | 16 | line.reserve(512); |
208 | 444 | while (input) { |
209 | | // read one line at a time |
210 | 428 | std::getline(input, line); |
211 | | |
212 | | // remove left and right spaces |
213 | 428 | trim(line); |
214 | | |
215 | | // ignore comments |
216 | 428 | if (line.empty() || line[0] == '#') { |
217 | 328 | continue; |
218 | 328 | } |
219 | | |
220 | | // read key and value |
221 | 100 | splitkv(line, key, value); |
222 | 100 | trim(key); |
223 | 100 | trim(value); |
224 | | |
225 | | // insert into file_conf_map |
226 | 100 | file_conf_map[key] = value; |
227 | 100 | } |
228 | | |
229 | | // close the conf file |
230 | 16 | input.close(); |
231 | | |
232 | 16 | return true; |
233 | 16 | } |
234 | | |
235 | 5 | bool Properties::dump(const std::string& conffile) { |
236 | 5 | std::string conffile_tmp = conffile + ".tmp"; |
237 | | |
238 | 5 | if (std::filesystem::exists(conffile)) { |
239 | | // copy for modify |
240 | 4 | std::ifstream in(conffile, std::ios::binary); |
241 | 4 | std::ofstream out(conffile_tmp, std::ios::binary); |
242 | 4 | out << in.rdbuf(); |
243 | 4 | in.close(); |
244 | 4 | out.close(); |
245 | 4 | } |
246 | | |
247 | 5 | std::ofstream file_writer; |
248 | | |
249 | 5 | file_writer.open(conffile_tmp, std::ios::out | std::ios::app); |
250 | | |
251 | 5 | file_writer << std::endl; |
252 | | |
253 | 6 | for (auto const& iter : file_conf_map) { |
254 | 6 | file_writer << iter.first << " = " << iter.second << std::endl; |
255 | 6 | } |
256 | | |
257 | 5 | file_writer.close(); |
258 | 5 | if (!file_writer.good()) { |
259 | 0 | return false; |
260 | 0 | } |
261 | | |
262 | 5 | std::filesystem::rename(conffile_tmp, conffile); |
263 | 5 | return std::filesystem::exists(conffile); |
264 | 5 | } |
265 | | |
266 | | template <typename T> |
267 | | bool Properties::get_or_default(const char* key, const char* defstr, T& retval, |
268 | 2.16k | bool* is_retval_set) const { |
269 | 2.16k | const auto& it = file_conf_map.find(std::string(key)); |
270 | 2.16k | std::string valstr; |
271 | 2.16k | if (it == file_conf_map.end()) { |
272 | 2.07k | if (defstr == nullptr) { |
273 | | // Not found in conf map, and no default value need to be set, just return |
274 | 0 | *is_retval_set = false; |
275 | 0 | return true; |
276 | 2.07k | } else { |
277 | 2.07k | valstr = std::string(defstr); |
278 | 2.07k | } |
279 | 2.07k | } else { |
280 | 92 | valstr = it->second; |
281 | 92 | } |
282 | 2.16k | *is_retval_set = true; |
283 | 2.16k | return convert(valstr, retval); |
284 | 2.16k | } _ZNK5doris5cloud6config10Properties14get_or_defaultIbEEbPKcS5_RT_Pb Line | Count | Source | 268 | 494 | bool* is_retval_set) const { | 269 | 494 | const auto& it = file_conf_map.find(std::string(key)); | 270 | 494 | std::string valstr; | 271 | 494 | if (it == file_conf_map.end()) { | 272 | 493 | if (defstr == nullptr) { | 273 | | // Not found in conf map, and no default value need to be set, just return | 274 | 0 | *is_retval_set = false; | 275 | 0 | return true; | 276 | 493 | } else { | 277 | 493 | valstr = std::string(defstr); | 278 | 493 | } | 279 | 493 | } else { | 280 | 1 | valstr = it->second; | 281 | 1 | } | 282 | 494 | *is_retval_set = true; | 283 | 494 | return convert(valstr, retval); | 284 | 494 | } |
_ZNK5doris5cloud6config10Properties14get_or_defaultIsEEbPKcS5_RT_Pb Line | Count | Source | 268 | 17 | bool* is_retval_set) const { | 269 | 17 | const auto& it = file_conf_map.find(std::string(key)); | 270 | 17 | std::string valstr; | 271 | 17 | if (it == file_conf_map.end()) { | 272 | 17 | if (defstr == nullptr) { | 273 | | // Not found in conf map, and no default value need to be set, just return | 274 | 0 | *is_retval_set = false; | 275 | 0 | return true; | 276 | 17 | } else { | 277 | 17 | valstr = std::string(defstr); | 278 | 17 | } | 279 | 17 | } else { | 280 | 0 | valstr = it->second; | 281 | 0 | } | 282 | 17 | *is_retval_set = true; | 283 | 17 | return convert(valstr, retval); | 284 | 17 | } |
_ZNK5doris5cloud6config10Properties14get_or_defaultIiEEbPKcS5_RT_Pb Line | Count | Source | 268 | 476 | bool* is_retval_set) const { | 269 | 476 | const auto& it = file_conf_map.find(std::string(key)); | 270 | 476 | std::string valstr; | 271 | 476 | if (it == file_conf_map.end()) { | 272 | 452 | if (defstr == nullptr) { | 273 | | // Not found in conf map, and no default value need to be set, just return | 274 | 0 | *is_retval_set = false; | 275 | 0 | return true; | 276 | 452 | } else { | 277 | 452 | valstr = std::string(defstr); | 278 | 452 | } | 279 | 452 | } else { | 280 | 24 | valstr = it->second; | 281 | 24 | } | 282 | 476 | *is_retval_set = true; | 283 | 476 | return convert(valstr, retval); | 284 | 476 | } |
_ZNK5doris5cloud6config10Properties14get_or_defaultIlEEbPKcS5_RT_Pb Line | Count | Source | 268 | 497 | bool* is_retval_set) const { | 269 | 497 | const auto& it = file_conf_map.find(std::string(key)); | 270 | 497 | std::string valstr; | 271 | 497 | if (it == file_conf_map.end()) { | 272 | 481 | if (defstr == nullptr) { | 273 | | // Not found in conf map, and no default value need to be set, just return | 274 | 0 | *is_retval_set = false; | 275 | 0 | return true; | 276 | 481 | } else { | 277 | 481 | valstr = std::string(defstr); | 278 | 481 | } | 279 | 481 | } else { | 280 | 16 | valstr = it->second; | 281 | 16 | } | 282 | 497 | *is_retval_set = true; | 283 | 497 | return convert(valstr, retval); | 284 | 497 | } |
Unexecuted instantiation: _ZNK5doris5cloud6config10Properties14get_or_defaultIdEEbPKcS5_RT_Pb _ZNK5doris5cloud6config10Properties14get_or_defaultINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEbPKcSB_RT_Pb Line | Count | Source | 268 | 615 | bool* is_retval_set) const { | 269 | 615 | const auto& it = file_conf_map.find(std::string(key)); | 270 | 615 | std::string valstr; | 271 | 615 | if (it == file_conf_map.end()) { | 272 | 564 | if (defstr == nullptr) { | 273 | | // Not found in conf map, and no default value need to be set, just return | 274 | 0 | *is_retval_set = false; | 275 | 0 | return true; | 276 | 564 | } else { | 277 | 564 | valstr = std::string(defstr); | 278 | 564 | } | 279 | 564 | } else { | 280 | 51 | valstr = it->second; | 281 | 51 | } | 282 | 615 | *is_retval_set = true; | 283 | 615 | return convert(valstr, retval); | 284 | 615 | } |
Unexecuted instantiation: _ZNK5doris5cloud6config10Properties14get_or_defaultISt6vectorIbSaIbEEEEbPKcS8_RT_Pb Unexecuted instantiation: _ZNK5doris5cloud6config10Properties14get_or_defaultISt6vectorIsSaIsEEEEbPKcS8_RT_Pb Unexecuted instantiation: _ZNK5doris5cloud6config10Properties14get_or_defaultISt6vectorIiSaIiEEEEbPKcS8_RT_Pb Unexecuted instantiation: _ZNK5doris5cloud6config10Properties14get_or_defaultISt6vectorIlSaIlEEEEbPKcS8_RT_Pb Unexecuted instantiation: _ZNK5doris5cloud6config10Properties14get_or_defaultISt6vectorIdSaIdEEEEbPKcS8_RT_Pb _ZNK5doris5cloud6config10Properties14get_or_defaultISt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISA_EEEEbPKcSE_RT_Pb Line | Count | Source | 268 | 68 | bool* is_retval_set) const { | 269 | 68 | const auto& it = file_conf_map.find(std::string(key)); | 270 | 68 | std::string valstr; | 271 | 68 | if (it == file_conf_map.end()) { | 272 | 68 | if (defstr == nullptr) { | 273 | | // Not found in conf map, and no default value need to be set, just return | 274 | 0 | *is_retval_set = false; | 275 | 0 | return true; | 276 | 68 | } else { | 277 | 68 | valstr = std::string(defstr); | 278 | 68 | } | 279 | 68 | } else { | 280 | 0 | valstr = it->second; | 281 | 0 | } | 282 | 68 | *is_retval_set = true; | 283 | 68 | return convert(valstr, retval); | 284 | 68 | } |
|
285 | | |
286 | 0 | void Properties::set(const std::string& key, const std::string& val) { |
287 | 0 | file_conf_map.emplace(key, val); |
288 | 0 | } |
289 | | |
290 | 6 | void Properties::set_force(const std::string& key, const std::string& val) { |
291 | 6 | file_conf_map[key] = val; |
292 | 6 | } |
293 | | |
294 | | template <typename T> |
295 | 68 | std::ostream& operator<<(std::ostream& out, const std::vector<T>& v) { |
296 | 68 | size_t last = v.size() - 1; |
297 | 68 | for (size_t i = 0; i < v.size(); ++i) { |
298 | 0 | out << v[i]; |
299 | 0 | if (i != last) { |
300 | 0 | out << ", "; |
301 | 0 | } |
302 | 0 | } |
303 | 68 | return out; |
304 | 68 | } Unexecuted instantiation: _ZN5doris5cloud6configlsIbEERSoS3_RKSt6vectorIT_SaIS5_EE Unexecuted instantiation: _ZN5doris5cloud6configlsIsEERSoS3_RKSt6vectorIT_SaIS5_EE Unexecuted instantiation: _ZN5doris5cloud6configlsIiEERSoS3_RKSt6vectorIT_SaIS5_EE Unexecuted instantiation: _ZN5doris5cloud6configlsIlEERSoS3_RKSt6vectorIT_SaIS5_EE Unexecuted instantiation: _ZN5doris5cloud6configlsIdEERSoS3_RKSt6vectorIT_SaIS5_EE _ZN5doris5cloud6configlsINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEERSoS9_RKSt6vectorIT_SaISB_EE Line | Count | Source | 295 | 68 | std::ostream& operator<<(std::ostream& out, const std::vector<T>& v) { | 296 | 68 | size_t last = v.size() - 1; | 297 | 68 | for (size_t i = 0; i < v.size(); ++i) { | 298 | 0 | out << v[i]; | 299 | 0 | if (i != last) { | 300 | 0 | out << ", "; | 301 | 0 | } | 302 | 0 | } | 303 | 68 | return out; | 304 | 68 | } |
|
305 | | |
306 | | #define SET_FIELD(FIELD, TYPE, FILL_CONF_MAP, SET_TO_DEFAULT) \ |
307 | 8.41k | if (strcmp((FIELD).type, #TYPE) == 0) { \ |
308 | 2.15k | TYPE new_value = TYPE(); \ |
309 | 2.15k | bool is_newval_set = false; \ |
310 | 2.15k | if (!props.get_or_default((FIELD).name, ((SET_TO_DEFAULT) ? (FIELD).defval : nullptr), \ |
311 | 2.15k | new_value, &is_newval_set)) { \ |
312 | 0 | std::cerr << "config field error: " << (FIELD).name << std::endl; \ |
313 | 0 | return false; \ |
314 | 0 | } \ |
315 | 2.15k | if (!is_newval_set) { \ |
316 | 0 | continue; \ |
317 | 0 | } \ |
318 | 2.15k | TYPE& ref_conf_value = *reinterpret_cast<TYPE*>((FIELD).storage); \ |
319 | 2.15k | TYPE old_value = ref_conf_value; \ |
320 | 2.15k | ref_conf_value = new_value; \ |
321 | 2.15k | if (RegisterConfValidator::_s_field_validator != nullptr) { \ |
322 | 2.15k | auto validator = RegisterConfValidator::_s_field_validator->find((FIELD).name); \ |
323 | 2.15k | if (validator != RegisterConfValidator::_s_field_validator->end() && \ |
324 | 2.15k | !(validator->second)()) { \ |
325 | 0 | ref_conf_value = old_value; \ |
326 | 0 | std::cerr << "validate " << (FIELD).name << "=" << new_value << " failed" \ |
327 | 0 | << std::endl; \ |
328 | 0 | return false; \ |
329 | 0 | } \ |
330 | 2.15k | } \ |
331 | 2.15k | if (FILL_CONF_MAP) { \ |
332 | 2.15k | std::ostringstream oss; \ |
333 | 2.15k | oss << ref_conf_value; \ |
334 | 2.15k | (*full_conf_map)[(FIELD).name] = oss.str(); \ |
335 | 2.15k | } \ |
336 | 2.15k | continue; \ |
337 | 2.15k | } |
338 | | |
339 | | #define UPDATE_FIELD(FIELD, VALUE, TYPE, PERSIST) \ |
340 | 40 | if (strcmp((FIELD).type, #TYPE) == 0) { \ |
341 | 10 | TYPE new_value; \ |
342 | 10 | if (!convert((VALUE), new_value)) { \ |
343 | 0 | std::cerr << "convert " << VALUE << "as" << #TYPE << "failed"; \ |
344 | 0 | return false; \ |
345 | 0 | } \ |
346 | 10 | TYPE& ref_conf_value = *reinterpret_cast<TYPE*>((FIELD).storage); \ |
347 | 10 | TYPE old_value = ref_conf_value; \ |
348 | 10 | if (RegisterConfValidator::_s_field_validator != nullptr) { \ |
349 | 10 | auto validator = RegisterConfValidator::_s_field_validator->find((FIELD).name); \ |
350 | 10 | if (validator != RegisterConfValidator::_s_field_validator->end() && \ |
351 | 10 | !(validator->second)()) { \ |
352 | 0 | ref_conf_value = old_value; \ |
353 | 0 | std::cerr << "validate " << (FIELD).name << "=" << new_value << " failed" \ |
354 | 0 | << std::endl; \ |
355 | 0 | return false; \ |
356 | 0 | } \ |
357 | 10 | } \ |
358 | 10 | ref_conf_value = new_value; \ |
359 | 10 | if (full_conf_map != nullptr) { \ |
360 | 10 | std::ostringstream oss; \ |
361 | 10 | oss << new_value; \ |
362 | 10 | (*full_conf_map)[(FIELD).name] = oss.str(); \ |
363 | 10 | } \ |
364 | 10 | if (PERSIST) { \ |
365 | 6 | props.set_force(std::string((FIELD).name), VALUE); \ |
366 | 6 | } \ |
367 | 10 | return true; \ |
368 | 10 | } |
369 | | |
370 | | // init conf fields |
371 | 17 | bool init(const char* conf_file, bool fill_conf_map, bool must_exist, bool set_to_default) { |
372 | 17 | Properties props; |
373 | | // load properties file |
374 | 17 | if (!props.load(conf_file, must_exist)) { |
375 | 0 | return false; |
376 | 0 | } |
377 | | // fill full_conf_map ? |
378 | 17 | if (fill_conf_map && full_conf_map == nullptr) { |
379 | 17 | full_conf_map = new std::map<std::string, std::string>(); |
380 | 17 | } |
381 | | |
382 | | // set conf fields |
383 | 2.15k | for (const auto& it : *Register::_s_field_map) { |
384 | 2.15k | SET_FIELD(it.second, bool, fill_conf_map, set_to_default); |
385 | 1.66k | SET_FIELD(it.second, int16_t, fill_conf_map, set_to_default); |
386 | 1.64k | SET_FIELD(it.second, int32_t, fill_conf_map, set_to_default); |
387 | 1.17k | SET_FIELD(it.second, int64_t, fill_conf_map, set_to_default); |
388 | 680 | SET_FIELD(it.second, double, fill_conf_map, set_to_default); |
389 | 680 | SET_FIELD(it.second, std::string, fill_conf_map, set_to_default); |
390 | 68 | SET_FIELD(it.second, std::vector<bool>, fill_conf_map, set_to_default); |
391 | 68 | SET_FIELD(it.second, std::vector<int16_t>, fill_conf_map, set_to_default); |
392 | 68 | SET_FIELD(it.second, std::vector<int32_t>, fill_conf_map, set_to_default); |
393 | 68 | SET_FIELD(it.second, std::vector<int64_t>, fill_conf_map, set_to_default); |
394 | 68 | SET_FIELD(it.second, std::vector<double>, fill_conf_map, set_to_default); |
395 | 68 | SET_FIELD(it.second, std::vector<std::string>, fill_conf_map, set_to_default); |
396 | 0 | } |
397 | | |
398 | 17 | return true; |
399 | 17 | } |
400 | | |
401 | | bool do_set_config(const Register::Field& feild, const std::string& value, bool need_persist, |
402 | 10 | Properties& props) { |
403 | 10 | UPDATE_FIELD(feild, value, bool, need_persist); |
404 | 8 | UPDATE_FIELD(feild, value, int16_t, need_persist); |
405 | 8 | UPDATE_FIELD(feild, value, int32_t, need_persist); |
406 | 8 | UPDATE_FIELD(feild, value, int64_t, need_persist); |
407 | 3 | UPDATE_FIELD(feild, value, double, need_persist); |
408 | 3 | { |
409 | | // add lock to ensure thread safe |
410 | 3 | std::unique_lock<std::shared_mutex> lock(mutable_string_config_lock); |
411 | 3 | UPDATE_FIELD(feild, value, std::string, need_persist); |
412 | 0 | } |
413 | 0 | return false; |
414 | 3 | } |
415 | | |
416 | | std::pair<bool, std::string> set_config(const std::string& field, const std::string& value, |
417 | 12 | bool need_persist, Properties& props) { |
418 | 12 | auto it = Register::_s_field_map->find(field); |
419 | 12 | if (it == Register::_s_field_map->end()) { |
420 | 1 | return {false, fmt::format("config field={} not exists", field)}; |
421 | 1 | } |
422 | 11 | if (!it->second.valmutable) { |
423 | 1 | return {false, fmt::format("config field={} is immutable", field)}; |
424 | 1 | } |
425 | | |
426 | 10 | if (!do_set_config(it->second, value, need_persist, props)) { |
427 | 0 | return {false, fmt::format("not supported to modify field={}, value={}", field, value)}; |
428 | 0 | } |
429 | 10 | return {true, {}}; |
430 | 10 | } |
431 | | |
432 | | std::pair<bool, std::string> set_config(std::unordered_map<std::string, std::string> field_map, |
433 | 10 | bool need_persist, const std::string& custom_conf_path) { |
434 | 10 | Properties props; |
435 | 10 | auto set_conf_closure = [&]() -> std::pair<bool, std::string> { |
436 | 12 | for (const auto& [field, value] : field_map) { |
437 | 12 | if (auto [succ, cause] = set_config(field, value, need_persist, props); !succ) { |
438 | 2 | return {false, std::move(cause)}; |
439 | 2 | } |
440 | 12 | } |
441 | 8 | return {true, {}}; |
442 | 10 | }; |
443 | | |
444 | 10 | if (!need_persist) { |
445 | 5 | return set_conf_closure(); |
446 | 5 | } |
447 | | |
448 | | // lock to make sure only one thread can modify the conf file |
449 | 5 | std::lock_guard<std::mutex> l(conf_persist_lock); |
450 | 5 | auto [succ, cause] = set_conf_closure(); |
451 | 5 | if (!succ) { |
452 | 0 | return {succ, std::move(cause)}; |
453 | 0 | } |
454 | 5 | if (props.dump(custom_conf_path)) { |
455 | 5 | return {true, {}}; |
456 | 5 | } |
457 | 0 | return {false, fmt::format("dump config modification to custom_conf_path={} " |
458 | 0 | "failed, plz check config::custom_conf_path and io status", |
459 | 0 | custom_conf_path)}; |
460 | 5 | } |
461 | | |
462 | 482 | std::shared_mutex* get_mutable_string_config_lock() { |
463 | 482 | return &mutable_string_config_lock; |
464 | 482 | } |
465 | | } // namespace doris::cloud::config |