/src/rocksdb/options/configurable.cc
Line | Count | Source |
1 | | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
2 | | // This source code is licensed under both the GPLv2 (found in the |
3 | | // COPYING file in the root directory) and Apache 2.0 License |
4 | | // (found in the LICENSE.Apache file in the root directory). |
5 | | |
6 | | #include "rocksdb/configurable.h" |
7 | | |
8 | | #include "logging/logging.h" |
9 | | #include "options/configurable_helper.h" |
10 | | #include "options/options_helper.h" |
11 | | #include "rocksdb/customizable.h" |
12 | | #include "rocksdb/status.h" |
13 | | #include "rocksdb/utilities/object_registry.h" |
14 | | #include "rocksdb/utilities/options_type.h" |
15 | | #include "util/coding.h" |
16 | | #include "util/string_util.h" |
17 | | |
18 | | namespace ROCKSDB_NAMESPACE { |
19 | | |
20 | | namespace { |
21 | 2.77M | intptr_t GetOffset(const Configurable* holder, void* field) { |
22 | 2.77M | return reinterpret_cast<intptr_t>(field) - |
23 | 2.77M | reinterpret_cast<intptr_t>(static_cast<const void*>(holder)); |
24 | 2.77M | } |
25 | | |
26 | 49.3M | void* ApplyOffset(const Configurable* holder, intptr_t offset) { |
27 | 49.3M | return reinterpret_cast<void*>( |
28 | 49.3M | reinterpret_cast<intptr_t>(static_cast<const void*>(holder)) + offset); |
29 | 49.3M | } |
30 | | } // namespace |
31 | | |
32 | | void Configurable::RegisterOptions( |
33 | | const std::string& name, void* opt_ptr, |
34 | 2.77M | const std::unordered_map<std::string, OptionTypeInfo>* type_map) { |
35 | 2.77M | RegisteredOptions opts; |
36 | 2.77M | opts.name = name; |
37 | 2.77M | opts.type_map = type_map; |
38 | 2.77M | opts.opt_offset = GetOffset(this, opt_ptr); |
39 | 2.77M | options_.emplace_back(opts); |
40 | 2.77M | } |
41 | | |
42 | | //************************************************************************* |
43 | | // |
44 | | // Methods for Initializing and Validating Configurable Objects |
45 | | // |
46 | | //************************************************************************* |
47 | | |
48 | 454k | Status Configurable::PrepareOptions(const ConfigOptions& opts) { |
49 | | // We ignore the invoke_prepare_options here intentionally, |
50 | | // as if you are here, you must have called PrepareOptions explicitly. |
51 | 454k | Status status = Status::OK(); |
52 | 454k | for (const auto& opt_iter : options_) { |
53 | 454k | if (opt_iter.type_map != nullptr) { |
54 | 20.5M | for (const auto& map_iter : *(opt_iter.type_map)) { |
55 | 20.5M | auto& opt_info = map_iter.second; |
56 | 20.5M | if (opt_info.ShouldPrepare()) { |
57 | 1.21M | status = opt_info.Prepare(opts, map_iter.first, |
58 | 1.21M | ApplyOffset(this, opt_iter.opt_offset)); |
59 | 1.21M | if (!status.ok()) { |
60 | 0 | return status; |
61 | 0 | } |
62 | 1.21M | } |
63 | 20.5M | } |
64 | 454k | } |
65 | 454k | } |
66 | 454k | return status; |
67 | 454k | } |
68 | | |
69 | | Status Configurable::ValidateOptions(const DBOptions& db_opts, |
70 | 402k | const ColumnFamilyOptions& cf_opts) const { |
71 | 402k | Status status; |
72 | 402k | for (const auto& opt_iter : options_) { |
73 | 344k | if (opt_iter.type_map != nullptr) { |
74 | 16.1M | for (const auto& map_iter : *(opt_iter.type_map)) { |
75 | 16.1M | auto& opt_info = map_iter.second; |
76 | 16.1M | if (opt_info.ShouldValidate()) { |
77 | 976k | status = opt_info.Validate(db_opts, cf_opts, map_iter.first, |
78 | 976k | ApplyOffset(this, opt_iter.opt_offset)); |
79 | 976k | if (!status.ok()) { |
80 | 0 | return status; |
81 | 0 | } |
82 | 976k | } |
83 | 16.1M | } |
84 | 344k | } |
85 | 344k | } |
86 | 402k | return status; |
87 | 402k | } |
88 | | |
89 | | /*********************************************************************************/ |
90 | | /* */ |
91 | | /* Methods for Retrieving Options from Configurables */ |
92 | | /* */ |
93 | | /*********************************************************************************/ |
94 | | |
95 | 1.45M | const void* Configurable::GetOptionsPtr(const std::string& name) const { |
96 | 1.80M | for (const auto& o : options_) { |
97 | 1.80M | if (o.name == name) { |
98 | 1.45M | return ApplyOffset(this, o.opt_offset); |
99 | 1.45M | } |
100 | 1.80M | } |
101 | 0 | return nullptr; |
102 | 1.45M | } |
103 | | |
104 | 34.9M | std::string Configurable::GetOptionName(const std::string& opt_name) const { |
105 | 34.9M | return opt_name; |
106 | 34.9M | } |
107 | | |
108 | | const OptionTypeInfo* ConfigurableHelper::FindOption( |
109 | | const Configurable& configurable, const std::string& short_name, |
110 | 0 | std::string* opt_name, void** opt_ptr) { |
111 | 0 | for (const auto& iter : configurable.options_) { |
112 | 0 | if (iter.type_map != nullptr) { |
113 | 0 | const auto opt_info = |
114 | 0 | OptionTypeInfo::Find(short_name, *(iter.type_map), opt_name); |
115 | 0 | if (opt_info != nullptr) { |
116 | 0 | *opt_ptr = ApplyOffset(&configurable, iter.opt_offset); |
117 | 0 | return opt_info; |
118 | 0 | } |
119 | 0 | } |
120 | 0 | } |
121 | 0 | return nullptr; |
122 | 0 | } |
123 | | |
124 | | //************************************************************************* |
125 | | // |
126 | | // Methods for Configuring Options from Strings/Name-Value Pairs/Maps |
127 | | // |
128 | | //************************************************************************* |
129 | | |
130 | | Status Configurable::ConfigureFromMap( |
131 | | const ConfigOptions& config_options, |
132 | 691k | const std::unordered_map<std::string, std::string>& opts_map) { |
133 | 691k | Status s = ConfigureFromMap(config_options, opts_map, nullptr); |
134 | 691k | return s; |
135 | 691k | } |
136 | | |
137 | | Status Configurable::ConfigureFromMap( |
138 | | const ConfigOptions& config_options, |
139 | | const std::unordered_map<std::string, std::string>& opts_map, |
140 | 691k | std::unordered_map<std::string, std::string>* unused) { |
141 | 691k | return ConfigureOptions(config_options, opts_map, unused); |
142 | 691k | } |
143 | | |
144 | | Status Configurable::ConfigureOptions( |
145 | | const ConfigOptions& config_options, |
146 | | const std::unordered_map<std::string, std::string>& opts_map, |
147 | 691k | std::unordered_map<std::string, std::string>* unused) { |
148 | 691k | std::string curr_opts; |
149 | 691k | Status s; |
150 | 691k | if (!opts_map.empty()) { |
151 | | // There are options in the map. |
152 | | // Save the current configuration in curr_opts and then configure the |
153 | | // options, but do not prepare them now. We will do all the prepare when |
154 | | // the configuration is complete. |
155 | 278k | ConfigOptions copy = config_options; |
156 | 278k | copy.invoke_prepare_options = false; |
157 | 278k | if (!config_options.ignore_unknown_options) { |
158 | | // If we are not ignoring unused, get the defaults in case we need to |
159 | | // reset |
160 | 278k | copy.depth = ConfigOptions::kDepthDetailed; |
161 | 278k | copy.delimiter = "; "; |
162 | 278k | GetOptionString(copy, &curr_opts).PermitUncheckedError(); |
163 | 278k | } |
164 | | |
165 | 278k | s = ConfigurableHelper::ConfigureOptions(copy, *this, opts_map, unused); |
166 | 278k | } |
167 | 691k | if (config_options.invoke_prepare_options && s.ok()) { |
168 | 0 | s = PrepareOptions(config_options); |
169 | 0 | } |
170 | 691k | if (!s.ok() && !curr_opts.empty()) { |
171 | 0 | ConfigOptions reset = config_options; |
172 | 0 | reset.ignore_unknown_options = true; |
173 | 0 | reset.invoke_prepare_options = true; |
174 | 0 | reset.ignore_unsupported_options = true; |
175 | | // There are some options to reset from this current error |
176 | 0 | ConfigureFromString(reset, curr_opts).PermitUncheckedError(); |
177 | 0 | } |
178 | 691k | return s; |
179 | 691k | } |
180 | | |
181 | | Status Configurable::ParseStringOptions(const ConfigOptions& /*config_options*/, |
182 | 0 | const std::string& /*opts_str*/) { |
183 | 0 | return Status::OK(); |
184 | 0 | } |
185 | | |
186 | | Status Configurable::ConfigureFromString(const ConfigOptions& config_options, |
187 | 0 | const std::string& opts_str) { |
188 | 0 | Status s; |
189 | 0 | if (!opts_str.empty()) { |
190 | 0 | if (opts_str.find(';') != std::string::npos || |
191 | 0 | opts_str.find('=') != std::string::npos) { |
192 | 0 | std::unordered_map<std::string, std::string> opt_map; |
193 | 0 | s = StringToMap(opts_str, &opt_map); |
194 | 0 | if (s.ok()) { |
195 | 0 | s = ConfigureFromMap(config_options, opt_map, nullptr); |
196 | 0 | } |
197 | 0 | } else { |
198 | 0 | s = ParseStringOptions(config_options, opts_str); |
199 | 0 | if (s.ok() && config_options.invoke_prepare_options) { |
200 | 0 | s = PrepareOptions(config_options); |
201 | 0 | } |
202 | 0 | } |
203 | 0 | } else if (config_options.invoke_prepare_options) { |
204 | 0 | s = PrepareOptions(config_options); |
205 | 0 | } else { |
206 | 0 | s = Status::OK(); |
207 | 0 | } |
208 | 0 | return s; |
209 | 0 | } |
210 | | |
211 | | /** |
212 | | * Sets the value of the named property to the input value, returning OK on |
213 | | * succcess. |
214 | | */ |
215 | | Status Configurable::ConfigureOption(const ConfigOptions& config_options, |
216 | | const std::string& name, |
217 | 0 | const std::string& value) { |
218 | 0 | return ConfigurableHelper::ConfigureSingleOption(config_options, *this, name, |
219 | 0 | value); |
220 | 0 | } |
221 | | |
222 | | /** |
223 | | * Looks for the named option amongst the options for this type and sets |
224 | | * the value for it to be the input value. |
225 | | * If the name was found, found_option will be set to true and the resulting |
226 | | * status should be returned. |
227 | | */ |
228 | | |
229 | | Status Configurable::ParseOption(const ConfigOptions& config_options, |
230 | | const OptionTypeInfo& opt_info, |
231 | | const std::string& opt_name, |
232 | 20.0M | const std::string& opt_value, void* opt_ptr) { |
233 | 20.0M | if (opt_info.IsMutable()) { |
234 | 8.30M | if (config_options.mutable_options_only) { |
235 | | // This option is mutable. Treat all of its children as mutable as well |
236 | 0 | ConfigOptions copy = config_options; |
237 | 0 | copy.mutable_options_only = false; |
238 | 0 | return opt_info.Parse(copy, opt_name, opt_value, opt_ptr); |
239 | 8.30M | } else { |
240 | 8.30M | return opt_info.Parse(config_options, opt_name, opt_value, opt_ptr); |
241 | 8.30M | } |
242 | 11.7M | } else if (config_options.mutable_options_only) { |
243 | 0 | return Status::InvalidArgument("Option not changeable: " + opt_name); |
244 | 11.7M | } else { |
245 | 11.7M | return opt_info.Parse(config_options, opt_name, opt_value, opt_ptr); |
246 | 11.7M | } |
247 | 20.0M | } |
248 | | |
249 | | Status ConfigurableHelper::ConfigureOptions( |
250 | | const ConfigOptions& config_options, Configurable& configurable, |
251 | | const std::unordered_map<std::string, std::string>& opts_map, |
252 | 278k | std::unordered_map<std::string, std::string>* unused) { |
253 | 278k | std::unordered_map<std::string, std::string> remaining = opts_map; |
254 | 278k | Status s = Status::OK(); |
255 | 278k | if (!opts_map.empty()) { |
256 | 454k | for (const auto& iter : configurable.options_) { |
257 | 454k | if (iter.type_map != nullptr) { |
258 | 454k | s = ConfigureSomeOptions(config_options, configurable, *(iter.type_map), |
259 | 454k | &remaining, |
260 | 454k | ApplyOffset(&configurable, iter.opt_offset)); |
261 | 454k | if (remaining.empty()) { // Are there more options left? |
262 | 278k | break; |
263 | 278k | } else if (!s.ok()) { |
264 | 0 | break; |
265 | 0 | } |
266 | 454k | } |
267 | 454k | } |
268 | 278k | } |
269 | 278k | if (unused != nullptr && !remaining.empty()) { |
270 | 0 | unused->insert(remaining.begin(), remaining.end()); |
271 | 0 | } |
272 | 278k | if (config_options.ignore_unknown_options) { |
273 | 0 | s = Status::OK(); |
274 | 278k | } else if (s.ok() && unused == nullptr && !remaining.empty()) { |
275 | 0 | s = Status::NotFound("Extra option not recognized", |
276 | 0 | remaining.begin()->first); |
277 | 0 | } |
278 | 278k | return s; |
279 | 278k | } |
280 | | |
281 | | /** |
282 | | * Updates the object with the named-value property values, returning OK on |
283 | | * succcess. Any properties that were found are removed from the options list; |
284 | | * upon return only options that were not found in this opt_map remain. |
285 | | |
286 | | * Returns: |
287 | | * - OK if ignore_unknown_options is set |
288 | | * - InvalidArgument, if any option was invalid |
289 | | * - NotSupported, if any option is unsupported and ignore_unsupported_options |
290 | | is OFF |
291 | | * - OK, if no option was invalid or not supported (or ignored) |
292 | | */ |
293 | | Status ConfigurableHelper::ConfigureSomeOptions( |
294 | | const ConfigOptions& config_options, Configurable& configurable, |
295 | | const std::unordered_map<std::string, OptionTypeInfo>& type_map, |
296 | 454k | std::unordered_map<std::string, std::string>* options, void* opt_ptr) { |
297 | 454k | Status result = Status::OK(); // The last non-OK result (if any) |
298 | 454k | Status notsup = Status::OK(); // The last NotSupported result (if any) |
299 | 454k | std::string elem_name; |
300 | 454k | int found = 1; |
301 | 454k | std::unordered_set<std::string> unsupported; |
302 | | // While there are unused properties and we processed at least one, |
303 | | // go through the remaining unused properties and attempt to configure them. |
304 | 1.08M | while (found > 0 && !options->empty()) { |
305 | 630k | found = 0; |
306 | 630k | notsup = Status::OK(); |
307 | 35.6M | for (auto it = options->begin(); it != options->end();) { |
308 | 34.9M | const std::string& opt_name = configurable.GetOptionName(it->first); |
309 | 34.9M | const std::string& opt_value = it->second; |
310 | 34.9M | const auto opt_info = |
311 | 34.9M | OptionTypeInfo::Find(opt_name, type_map, &elem_name); |
312 | 34.9M | if (opt_info == nullptr) { // Did not find the option. Skip it |
313 | 14.9M | ++it; |
314 | 20.0M | } else { |
315 | 20.0M | Status s = ConfigureOption(config_options, configurable, *opt_info, |
316 | 20.0M | opt_name, elem_name, opt_value, opt_ptr); |
317 | 20.0M | if (s.IsNotFound()) { |
318 | 0 | ++it; |
319 | 20.0M | } else if (s.IsNotSupported()) { |
320 | 0 | notsup = s; |
321 | 0 | unsupported.insert(it->first); |
322 | 0 | ++it; // Skip it for now |
323 | 20.0M | } else { |
324 | 20.0M | found++; |
325 | 20.0M | it = options->erase(it); |
326 | 20.0M | if (!s.ok()) { |
327 | 0 | result = s; |
328 | 0 | } |
329 | 20.0M | } |
330 | 20.0M | } |
331 | 34.9M | } // End for all remaining options |
332 | 630k | } // End while found one or options remain |
333 | | |
334 | | // Now that we have been through the list, remove any unsupported |
335 | 454k | for (const auto& u : unsupported) { |
336 | 0 | auto it = options->find(u); |
337 | 0 | if (it != options->end()) { |
338 | 0 | options->erase(it); |
339 | 0 | } |
340 | 0 | } |
341 | 454k | if (config_options.ignore_unknown_options) { |
342 | 0 | if (!result.ok()) { |
343 | 0 | result.PermitUncheckedError(); |
344 | 0 | } |
345 | 0 | if (!notsup.ok()) { |
346 | 0 | notsup.PermitUncheckedError(); |
347 | 0 | } |
348 | 0 | return Status::OK(); |
349 | 454k | } else if (!result.ok()) { |
350 | 0 | if (!notsup.ok()) { |
351 | 0 | notsup.PermitUncheckedError(); |
352 | 0 | } |
353 | 0 | return result; |
354 | 454k | } else if (config_options.ignore_unsupported_options) { |
355 | 454k | if (!notsup.ok()) { |
356 | 0 | notsup.PermitUncheckedError(); |
357 | 0 | } |
358 | 454k | return Status::OK(); |
359 | 454k | } else { |
360 | 0 | return notsup; |
361 | 0 | } |
362 | 454k | } |
363 | | |
364 | | Status ConfigurableHelper::ConfigureSingleOption( |
365 | | const ConfigOptions& config_options, Configurable& configurable, |
366 | 0 | const std::string& name, const std::string& value) { |
367 | 0 | const std::string& opt_name = configurable.GetOptionName(name); |
368 | 0 | std::string elem_name; |
369 | 0 | void* opt_ptr = nullptr; |
370 | 0 | const auto opt_info = |
371 | 0 | FindOption(configurable, opt_name, &elem_name, &opt_ptr); |
372 | 0 | if (opt_info == nullptr) { |
373 | 0 | return Status::NotFound("Could not find option", name); |
374 | 0 | } else { |
375 | 0 | return ConfigureOption(config_options, configurable, *opt_info, opt_name, |
376 | 0 | elem_name, value, opt_ptr); |
377 | 0 | } |
378 | 0 | } |
379 | | Status ConfigurableHelper::ConfigureCustomizableOption( |
380 | | const ConfigOptions& config_options, Configurable& configurable, |
381 | | const OptionTypeInfo& opt_info, const std::string& opt_name, |
382 | 1.48M | const std::string& name, const std::string& value, void* opt_ptr) { |
383 | 1.48M | Customizable* custom = opt_info.AsRawPointer<Customizable>(opt_ptr); |
384 | 1.48M | ConfigOptions copy = config_options; |
385 | 1.48M | if (opt_info.IsMutable()) { |
386 | | // This option is mutable. Pass that property on to any subsequent calls |
387 | 309k | copy.mutable_options_only = false; |
388 | 309k | } |
389 | | |
390 | 1.48M | if (opt_info.IsMutable() || !config_options.mutable_options_only) { |
391 | | // Either the option is mutable, or we are processing all of the options |
392 | 1.48M | if (opt_name == name || name == OptionTypeInfo::kIdPropName() || |
393 | 1.48M | EndsWith(opt_name, OptionTypeInfo::kIdPropSuffix())) { |
394 | 1.48M | return configurable.ParseOption(copy, opt_info, name, value, opt_ptr); |
395 | 1.48M | } else if (value.empty()) { |
396 | 0 | return Status::OK(); |
397 | 0 | } else if (custom == nullptr || !StartsWith(name, custom->GetId() + ".")) { |
398 | 0 | return configurable.ParseOption(copy, opt_info, name, value, opt_ptr); |
399 | 0 | } else if (value.find('=') != std::string::npos) { |
400 | 0 | return custom->ConfigureFromString(copy, value); |
401 | 0 | } else { |
402 | 0 | return custom->ConfigureOption(copy, name, value); |
403 | 0 | } |
404 | 1.48M | } else { |
405 | | // We are processing immutable options, which means that we cannot change |
406 | | // the Customizable object itself, but could change its mutable properties. |
407 | | // Check to make sure that nothing is trying to change the Customizable |
408 | 0 | if (custom == nullptr) { |
409 | | // We do not have a Customizable to configure. This is OK if the |
410 | | // value is empty (nothing being configured) but an error otherwise |
411 | 0 | if (value.empty()) { |
412 | 0 | return Status::OK(); |
413 | 0 | } else { |
414 | 0 | return Status::InvalidArgument("Option not changeable: " + opt_name); |
415 | 0 | } |
416 | 0 | } else if (EndsWith(opt_name, OptionTypeInfo::kIdPropSuffix()) || |
417 | 0 | name == OptionTypeInfo::kIdPropName()) { |
418 | | // We have a property of the form "id=value" or "table.id=value" |
419 | | // This is OK if we ID/value matches the current customizable object |
420 | 0 | if (custom->GetId() == value) { |
421 | 0 | return Status::OK(); |
422 | 0 | } else { |
423 | 0 | return Status::InvalidArgument("Option not changeable: " + opt_name); |
424 | 0 | } |
425 | 0 | } else if (opt_name == name) { |
426 | | // The properties are of one of forms: |
427 | | // name = { id = id; prop1 = value1; ... } |
428 | | // name = { prop1=value1; prop2=value2; ... } |
429 | | // name = ID |
430 | | // Convert the value to a map and extract the ID |
431 | | // If the ID does not match that of the current customizable, return an |
432 | | // error. Otherwise, update the current customizable via the properties |
433 | | // map |
434 | 0 | std::unordered_map<std::string, std::string> props; |
435 | 0 | std::string id; |
436 | 0 | Status s = |
437 | 0 | Configurable::GetOptionsMap(value, custom->GetId(), &id, &props); |
438 | 0 | if (!s.ok()) { |
439 | 0 | return s; |
440 | 0 | } else if (custom->GetId() != id) { |
441 | 0 | return Status::InvalidArgument("Option not changeable: " + opt_name); |
442 | 0 | } else if (props.empty()) { |
443 | 0 | return Status::OK(); |
444 | 0 | } else { |
445 | 0 | return custom->ConfigureFromMap(copy, props); |
446 | 0 | } |
447 | 0 | } else { |
448 | | // Attempting to configure one of the properties of the customizable |
449 | | // Let it through |
450 | 0 | return custom->ConfigureOption(copy, name, value); |
451 | 0 | } |
452 | 0 | } |
453 | 1.48M | } |
454 | | |
455 | | Status ConfigurableHelper::ConfigureOption( |
456 | | const ConfigOptions& config_options, Configurable& configurable, |
457 | | const OptionTypeInfo& opt_info, const std::string& opt_name, |
458 | 20.0M | const std::string& name, const std::string& value, void* opt_ptr) { |
459 | 20.0M | if (opt_info.IsCustomizable()) { |
460 | 1.48M | return ConfigureCustomizableOption(config_options, configurable, opt_info, |
461 | 1.48M | opt_name, name, value, opt_ptr); |
462 | 18.5M | } else if (opt_name == name) { |
463 | 18.5M | return configurable.ParseOption(config_options, opt_info, opt_name, value, |
464 | 18.5M | opt_ptr); |
465 | 18.5M | } else if (opt_info.IsStruct() || opt_info.IsConfigurable()) { |
466 | 0 | return configurable.ParseOption(config_options, opt_info, name, value, |
467 | 0 | opt_ptr); |
468 | 0 | } else { |
469 | 0 | return Status::NotFound("Unknown how to configure option", name); |
470 | 0 | } |
471 | 20.0M | } |
472 | | |
473 | | //******************************************************************************* |
474 | | // |
475 | | // Methods for Converting Options into strings |
476 | | // |
477 | | //******************************************************************************* |
478 | | |
479 | | Status Configurable::GetOptionString(const ConfigOptions& config_options, |
480 | 763k | std::string* result) const { |
481 | 763k | assert(result); |
482 | 763k | result->clear(); |
483 | 763k | return ConfigurableHelper::SerializeOptions(config_options, *this, "", |
484 | 763k | result); |
485 | 763k | } |
486 | | |
487 | | std::string Configurable::ToString(const ConfigOptions& config_options, |
488 | 824k | const std::string& prefix) const { |
489 | 824k | std::string result = SerializeOptions(config_options, prefix); |
490 | 824k | if (result.empty() || result.find('=') == std::string::npos) { |
491 | 721k | return result; |
492 | 721k | } else { |
493 | 103k | return "{" + result + "}"; |
494 | 103k | } |
495 | 824k | } |
496 | | |
497 | | std::string Configurable::SerializeOptions(const ConfigOptions& config_options, |
498 | 824k | const std::string& header) const { |
499 | 824k | std::string result; |
500 | 824k | Status s = ConfigurableHelper::SerializeOptions(config_options, *this, header, |
501 | 824k | &result); |
502 | 824k | assert(s.ok()); |
503 | 824k | return result; |
504 | 824k | } |
505 | | |
506 | | Status Configurable::GetOption(const ConfigOptions& config_options, |
507 | | const std::string& name, |
508 | 0 | std::string* value) const { |
509 | 0 | return ConfigurableHelper::GetOption(config_options, *this, |
510 | 0 | GetOptionName(name), value); |
511 | 0 | } |
512 | | |
513 | | Status ConfigurableHelper::GetOption(const ConfigOptions& config_options, |
514 | | const Configurable& configurable, |
515 | | const std::string& short_name, |
516 | 0 | std::string* value) { |
517 | | // Look for option directly |
518 | 0 | assert(value); |
519 | 0 | value->clear(); |
520 | |
|
521 | 0 | std::string opt_name; |
522 | 0 | void* opt_ptr = nullptr; |
523 | 0 | const auto opt_info = |
524 | 0 | FindOption(configurable, short_name, &opt_name, &opt_ptr); |
525 | 0 | if (opt_info != nullptr) { |
526 | 0 | ConfigOptions embedded = config_options; |
527 | 0 | embedded.delimiter = ";"; |
528 | 0 | if (short_name == opt_name) { |
529 | 0 | return opt_info->Serialize(embedded, opt_name, opt_ptr, value); |
530 | 0 | } else if (opt_info->IsStruct()) { |
531 | 0 | return opt_info->Serialize(embedded, opt_name, opt_ptr, value); |
532 | 0 | } else if (opt_info->IsConfigurable()) { |
533 | 0 | auto const* config = opt_info->AsRawPointer<Configurable>(opt_ptr); |
534 | 0 | if (config != nullptr) { |
535 | 0 | return config->GetOption(embedded, opt_name, value); |
536 | 0 | } |
537 | 0 | } |
538 | 0 | } |
539 | 0 | return Status::NotFound("Cannot find option: ", short_name); |
540 | 0 | } |
541 | | |
542 | | Status ConfigurableHelper::SerializeOptions(const ConfigOptions& config_options, |
543 | | const Configurable& configurable, |
544 | | const std::string& prefix, |
545 | 1.58M | std::string* result) { |
546 | 1.58M | assert(result); |
547 | 1.58M | for (auto const& opt_iter : configurable.options_) { |
548 | 1.21M | if (opt_iter.type_map != nullptr) { |
549 | 56.0M | for (const auto& map_iter : *(opt_iter.type_map)) { |
550 | 56.0M | const auto& opt_name = map_iter.first; |
551 | 56.0M | const auto& opt_info = map_iter.second; |
552 | 56.0M | if (opt_info.ShouldSerialize()) { |
553 | 45.2M | std::string value; |
554 | 45.2M | Status s; |
555 | 45.2M | void* opt_ptr = ApplyOffset(&configurable, opt_iter.opt_offset); |
556 | 45.2M | if (!config_options.mutable_options_only) { |
557 | 45.2M | s = opt_info.Serialize(config_options, prefix + opt_name, opt_ptr, |
558 | 45.2M | &value); |
559 | 45.2M | } else if (opt_info.IsMutable()) { |
560 | 0 | ConfigOptions copy = config_options; |
561 | 0 | copy.mutable_options_only = false; |
562 | 0 | s = opt_info.Serialize(copy, prefix + opt_name, opt_ptr, &value); |
563 | 0 | } else if (opt_info.IsConfigurable()) { |
564 | | // If it is a Configurable and we are either printing all of the |
565 | | // details or not printing only the name, this option should be |
566 | | // included in the list |
567 | 0 | if (config_options.IsDetailed() || |
568 | 0 | !opt_info.IsEnabled(OptionTypeFlags::kStringNameOnly)) { |
569 | 0 | s = opt_info.Serialize(config_options, prefix + opt_name, opt_ptr, |
570 | 0 | &value); |
571 | 0 | } |
572 | 0 | } |
573 | 45.2M | if (!s.ok()) { |
574 | 0 | return s; |
575 | 45.2M | } else if (!value.empty()) { |
576 | | // <prefix><opt_name>=<value><delimiter> |
577 | 44.2M | result->append(prefix + opt_name + "=" + value + |
578 | 44.2M | config_options.delimiter); |
579 | 44.2M | } |
580 | 45.2M | } |
581 | 56.0M | } |
582 | 1.21M | } |
583 | 1.21M | } |
584 | 1.58M | return Status::OK(); |
585 | 1.58M | } |
586 | | |
587 | | //******************************************************************************** |
588 | | // |
589 | | // Methods for listing the options from Configurables |
590 | | // |
591 | | //******************************************************************************** |
592 | | Status Configurable::GetOptionNames( |
593 | | const ConfigOptions& config_options, |
594 | 0 | std::unordered_set<std::string>* result) const { |
595 | 0 | assert(result); |
596 | 0 | return ConfigurableHelper::ListOptions(config_options, *this, "", result); |
597 | 0 | } |
598 | | |
599 | | Status ConfigurableHelper::ListOptions( |
600 | | const ConfigOptions& config_options, const Configurable& configurable, |
601 | 0 | const std::string& prefix, std::unordered_set<std::string>* result) { |
602 | 0 | Status status; |
603 | 0 | for (auto const& opt_iter : configurable.options_) { |
604 | 0 | if (opt_iter.type_map != nullptr) { |
605 | 0 | for (const auto& map_iter : *(opt_iter.type_map)) { |
606 | 0 | const auto& opt_name = map_iter.first; |
607 | 0 | const auto& opt_info = map_iter.second; |
608 | | // If the option is no longer used in rocksdb and marked as deprecated, |
609 | | // we skip it in the serialization. |
610 | 0 | if (!opt_info.IsDeprecated() && !opt_info.IsAlias()) { |
611 | 0 | if (!config_options.mutable_options_only) { |
612 | 0 | result->emplace(prefix + opt_name); |
613 | 0 | } else if (opt_info.IsMutable()) { |
614 | 0 | result->emplace(prefix + opt_name); |
615 | 0 | } |
616 | 0 | } |
617 | 0 | } |
618 | 0 | } |
619 | 0 | } |
620 | 0 | return status; |
621 | 0 | } |
622 | | |
623 | | //******************************************************************************* |
624 | | // |
625 | | // Methods for Comparing Configurables |
626 | | // |
627 | | //******************************************************************************* |
628 | | |
629 | | bool Configurable::AreEquivalent(const ConfigOptions& config_options, |
630 | | const Configurable* other, |
631 | 381k | std::string* name) const { |
632 | 381k | assert(name); |
633 | 381k | name->clear(); |
634 | 381k | if (this == other || config_options.IsCheckDisabled()) { |
635 | 0 | return true; |
636 | 381k | } else if (other != nullptr) { |
637 | 381k | return ConfigurableHelper::AreEquivalent(config_options, *this, *other, |
638 | 381k | name); |
639 | 381k | } else { |
640 | 0 | return false; |
641 | 0 | } |
642 | 381k | } |
643 | | |
644 | | bool Configurable::OptionsAreEqual(const ConfigOptions& config_options, |
645 | | const OptionTypeInfo& opt_info, |
646 | | const std::string& opt_name, |
647 | | const void* const this_ptr, |
648 | | const void* const that_ptr, |
649 | 4.22M | std::string* mismatch) const { |
650 | 4.22M | if (opt_info.AreEqual(config_options, opt_name, this_ptr, that_ptr, |
651 | 4.22M | mismatch)) { |
652 | 4.22M | return true; |
653 | 4.22M | } else if (opt_info.AreEqualByName(config_options, opt_name, this_ptr, |
654 | 0 | that_ptr)) { |
655 | 0 | *mismatch = ""; |
656 | 0 | return true; |
657 | 0 | } else { |
658 | 0 | return false; |
659 | 0 | } |
660 | 4.22M | } |
661 | | |
662 | | bool ConfigurableHelper::AreEquivalent(const ConfigOptions& config_options, |
663 | | const Configurable& this_one, |
664 | | const Configurable& that_one, |
665 | 381k | std::string* mismatch) { |
666 | 381k | assert(mismatch != nullptr); |
667 | 557k | for (auto const& o : this_one.options_) { |
668 | 557k | const auto this_offset = this_one.GetOptionsPtr(o.name); |
669 | 557k | const auto that_offset = that_one.GetOptionsPtr(o.name); |
670 | 557k | if (this_offset != that_offset) { |
671 | 557k | if (this_offset == nullptr || that_offset == nullptr) { |
672 | 0 | return false; |
673 | 557k | } else if (o.type_map != nullptr) { |
674 | 25.5M | for (const auto& map_iter : *(o.type_map)) { |
675 | 25.5M | const auto& opt_info = map_iter.second; |
676 | 25.5M | if (config_options.IsCheckEnabled(opt_info.GetSanityLevel())) { |
677 | 19.8M | if (!config_options.mutable_options_only) { |
678 | 19.8M | if (!this_one.OptionsAreEqual(config_options, opt_info, |
679 | 19.8M | map_iter.first, this_offset, |
680 | 19.8M | that_offset, mismatch)) { |
681 | 0 | return false; |
682 | 0 | } |
683 | 19.8M | } else if (opt_info.IsMutable()) { |
684 | 0 | ConfigOptions copy = config_options; |
685 | 0 | copy.mutable_options_only = false; |
686 | 0 | if (!this_one.OptionsAreEqual(copy, opt_info, map_iter.first, |
687 | 0 | this_offset, that_offset, |
688 | 0 | mismatch)) { |
689 | 0 | return false; |
690 | 0 | } |
691 | 0 | } |
692 | 19.8M | } |
693 | 25.5M | } |
694 | 557k | } |
695 | 557k | } |
696 | 557k | } |
697 | 381k | return true; |
698 | 381k | } |
699 | | |
700 | | Status Configurable::GetOptionsMap( |
701 | | const std::string& value, const std::string& default_id, std::string* id, |
702 | 515k | std::unordered_map<std::string, std::string>* props) { |
703 | 515k | assert(id); |
704 | 515k | assert(props); |
705 | 515k | Status status; |
706 | 515k | if (value.empty() || value == kNullptrString) { |
707 | 0 | *id = default_id; |
708 | 515k | } else if (value.find('=') == std::string::npos) { |
709 | 515k | *id = value; |
710 | 515k | } else { |
711 | 0 | status = StringToMap(value, props); |
712 | 0 | if (!status.ok()) { // There was an error creating the map. |
713 | 0 | *id = value; // Treat the value as id |
714 | 0 | props->clear(); // Clear the properties |
715 | 0 | status = Status::OK(); // and ignore the error |
716 | 0 | } else { |
717 | 0 | auto iter = props->find(OptionTypeInfo::kIdPropName()); |
718 | 0 | if (iter != props->end()) { |
719 | 0 | *id = iter->second; |
720 | 0 | props->erase(iter); |
721 | 0 | if (*id == kNullptrString) { |
722 | 0 | id->clear(); |
723 | 0 | } |
724 | 0 | } else if (!default_id.empty()) { |
725 | 0 | *id = default_id; |
726 | 0 | } else { // No id property and no default |
727 | 0 | *id = value; // Treat the value as id |
728 | 0 | props->clear(); // Clear the properties |
729 | 0 | } |
730 | 0 | } |
731 | 0 | } |
732 | 515k | return status; |
733 | 515k | } |
734 | | } // namespace ROCKSDB_NAMESPACE |