configurable.cc 27 KB

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