Bring the Configurable options together (#5753)
Summary: This PR merges the functionality of making the ColumnFamilyOptions, TableFactory, and DBOptions into Configurable into a single PR, resolving any merge conflicts Pull Request resolved: https://github.com/facebook/rocksdb/pull/5753 Reviewed By: ajkr Differential Revision: D23385030 Pulled By: zhichao-cao fbshipit-source-id: 8b977a7731556230b9b8c5a081b98e49ee4f160amain
parent
18a3227b12
commit
7d472accdc
@ -0,0 +1,364 @@ |
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#pragma once |
||||
|
||||
#include <string> |
||||
#include <unordered_map> |
||||
#include <unordered_set> |
||||
#include <vector> |
||||
|
||||
#include "rocksdb/rocksdb_namespace.h" |
||||
#include "rocksdb/status.h" |
||||
|
||||
namespace ROCKSDB_NAMESPACE { |
||||
class Logger; |
||||
class ObjectRegistry; |
||||
class OptionTypeInfo; |
||||
struct ColumnFamilyOptions; |
||||
struct ConfigOptions; |
||||
struct DBOptions; |
||||
|
||||
// Configurable is a base class used by the rocksdb that describes a
|
||||
// standard way of configuring objects. A Configurable object can:
|
||||
// -> Populate itself given:
|
||||
// - One or more "name/value" pair strings
|
||||
// - A string repesenting the set of name=value properties
|
||||
// - A map of name/value properties.
|
||||
// -> Convert itself into its string representation
|
||||
// -> Dump itself to a Logger
|
||||
// -> Compare itself to another Configurable object to see if the two objects
|
||||
// have equivalent options settings
|
||||
//
|
||||
// If a derived class calls RegisterOptions to register (by name) how its
|
||||
// options objects are to be processed, this functionality can typically be
|
||||
// handled by this class without additional overrides. Otherwise, the derived
|
||||
// class will need to implement the methods for handling the corresponding
|
||||
// functionality.
|
||||
class Configurable { |
||||
protected: |
||||
friend class ConfigurableHelper; |
||||
struct RegisteredOptions { |
||||
// The name of the options being registered
|
||||
std::string name; |
||||
// Pointer to the object being registered
|
||||
void* opt_ptr; |
||||
#ifndef ROCKSDB_LITE |
||||
// The map of options being registered
|
||||
const std::unordered_map<std::string, OptionTypeInfo>* type_map; |
||||
#endif |
||||
}; |
||||
|
||||
public: |
||||
Configurable() : prepared_(false) {} |
||||
virtual ~Configurable() {} |
||||
|
||||
// Returns the raw pointer of the named options that is used by this
|
||||
// object, or nullptr if this function is not supported.
|
||||
// Since the return value is a raw pointer, the object owns the
|
||||
// pointer and the caller should not delete the pointer.
|
||||
//
|
||||
// Note that changing the underlying options while the object
|
||||
// is currently used by any open DB is undefined behavior.
|
||||
// Developers should use DB::SetOption() instead to dynamically change
|
||||
// options while the DB is open.
|
||||
template <typename T> |
||||
const T* GetOptions() const { |
||||
return GetOptions<T>(T::kName()); |
||||
} |
||||
template <typename T> |
||||
T* GetOptions() { |
||||
return GetOptions<T>(T::kName()); |
||||
} |
||||
template <typename T> |
||||
const T* GetOptions(const std::string& name) const { |
||||
return reinterpret_cast<const T*>(GetOptionsPtr(name)); |
||||
} |
||||
template <typename T> |
||||
T* GetOptions(const std::string& name) { |
||||
return reinterpret_cast<T*>(const_cast<void*>(GetOptionsPtr(name))); |
||||
} |
||||
|
||||
// Configures the options for this class based on the input parameters.
|
||||
// On successful completion, the object is updated with the settings from
|
||||
// the opt_map.
|
||||
// If this method fails, an attempt is made to revert the object to original
|
||||
// state. Note that the revert may not be the original state but may be an
|
||||
// equivalent. For example, if the object contains an option that is a
|
||||
// shared_ptr, the shared_ptr may not be the original one but a copy (e.g. not
|
||||
// the Cache object that was passed in, but a Cache object of the same size).
|
||||
//
|
||||
// The acceptable values of the name/value pairs are documented with the
|
||||
// specific class/instance.
|
||||
//
|
||||
// @param config_options Controls how the arguments are processed.
|
||||
// @param opt_map Name/value pairs of the options to update
|
||||
// @param unused If specified, this value will return the name/value
|
||||
// pairs from opt_map that were NotFound for this object.
|
||||
// @return OK If all values in the map were successfully updated
|
||||
// If invoke_prepare_options is true, OK also implies
|
||||
// PrepareOptions ran successfully.
|
||||
// @return NotFound If any of the names in the opt_map were not valid
|
||||
// for this object. If unused is specified, it will contain the
|
||||
// collection of NotFound names.
|
||||
// @return NotSupported If any of the names are valid but the object does
|
||||
// not know how to convert the value. This can happen if, for example,
|
||||
// there is some nested Configurable that cannot be created.
|
||||
// @return InvalidArgument If any of the values cannot be successfully
|
||||
// parsed. This can also be returned if PrepareOptions encounters an
|
||||
// error.
|
||||
// @see ConfigOptions for a description of the controls.
|
||||
Status ConfigureFromMap( |
||||
const ConfigOptions& config_options, |
||||
const std::unordered_map<std::string, std::string>& opt_map); |
||||
Status ConfigureFromMap( |
||||
const ConfigOptions& config_options, |
||||
const std::unordered_map<std::string, std::string>& opt_map, |
||||
std::unordered_map<std::string, std::string>* unused); |
||||
|
||||
#ifndef ROCKSDB_LITE |
||||
// Updates the named option to the input value, returning OK if successful.
|
||||
// Note that ConfigureOption does not cause PrepareOptions to be invoked.
|
||||
// @param config_options Controls how the name/value is processed.
|
||||
// @param name The name of the option to update
|
||||
// @param value The value to set for the named option
|
||||
// @return OK If the named field was successfully updated to value.
|
||||
// @return NotFound If the name is not valid for this object.
|
||||
// @return NotSupported If the name is valid but the object does
|
||||
// not know how to convert the value. This can happen if, for example,
|
||||
// there is some nested Configurable that cannot be created.
|
||||
// @return InvalidArgument If the value cannot be successfully parsed.
|
||||
Status ConfigureOption(const ConfigOptions& config_options, |
||||
const std::string& name, const std::string& value); |
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
// Configures the options for this class based on the input parameters.
|
||||
// On successful completion, the object is updated with the settings from
|
||||
// the opt_map. If this method fails, an attempt is made to revert the
|
||||
// object to original state. Note that the revert may not be the original
|
||||
// state but may be an equivalent.
|
||||
// @see ConfigureFromMap for more details
|
||||
// @param config_options Controls how the arguments are processed.
|
||||
// @param opt_str string containing the values to update.
|
||||
// @param unused If specified, this value will return the name/value
|
||||
// pairs from opt_map that were NotFound for this object.
|
||||
// @return OK If all specified values were successfully updated
|
||||
// If invoke_prepare_options is true, OK also implies
|
||||
// PrepareOptions ran successfully.
|
||||
// @return NotFound If any of the names were not valid for this object.
|
||||
// If unused is specified, it will contain the collection of NotFound
|
||||
// names.
|
||||
// @return NotSupported If any of the names are valid but the object does
|
||||
// not know how to convert the value. This can happen if, for example,
|
||||
// there is some nested Configurable that cannot be created.
|
||||
// @return InvalidArgument If any of the values cannot be successfully
|
||||
// parsed. This can also be returned if PrepareOptions encounters an
|
||||
// error.
|
||||
Status ConfigureFromString(const ConfigOptions& config_options, |
||||
const std::string& opts); |
||||
|
||||
// Fills in result with the serialized options for this object.
|
||||
// This is the inverse of ConfigureFromString.
|
||||
// @param config_options Controls how serialization happens.
|
||||
// @param result The string representation of this object.
|
||||
// @return OK If the options for this object wer successfully serialized.
|
||||
// @return InvalidArgument If one or more of the options could not be
|
||||
// serialized.
|
||||
Status GetOptionString(const ConfigOptions& config_options, |
||||
std::string* result) const; |
||||
#ifndef ROCKSDB_LITE |
||||
// Returns the serialized options for this object.
|
||||
// This method is similar to GetOptionString with no errors.
|
||||
// @param config_options Controls how serialization happens.
|
||||
// @param prefix A string to prepend to every option.
|
||||
// @return The serialized representation of the options for this object
|
||||
std::string ToString(const ConfigOptions& config_options) const { |
||||
return ToString(config_options, ""); |
||||
} |
||||
std::string ToString(const ConfigOptions& config_options, |
||||
const std::string& prefix) const; |
||||
|
||||
// Returns the list of option names associated with this configurable
|
||||
// @param config_options Controls how the names are returned
|
||||
// @param result The set of option names for this object. Note that
|
||||
// options that are deprecated or aliases are not returned.
|
||||
// @return OK on success.
|
||||
Status GetOptionNames(const ConfigOptions& config_options, |
||||
std::unordered_set<std::string>* result) const; |
||||
|
||||
// Returns the value of the option associated with the input name
|
||||
// This method is the functional inverse of ConfigureOption
|
||||
// @param config_options Controls how the value is returned
|
||||
// @param name The name of the option to return a value for.
|
||||
// @param value The returned value associated with the named option.
|
||||
// @return OK If the named field was successfully updated to value.
|
||||
// @return NotFound If the name is not valid for this object.
|
||||
// @param InvalidArgument If the name is valid for this object but
|
||||
// its value cannot be serialized.
|
||||
virtual Status GetOption(const ConfigOptions& config_options, |
||||
const std::string& name, std::string* value) const; |
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
// Checks to see if this Configurable is equivalent to other.
|
||||
// This method assumes that the two objects are of the same class.
|
||||
// @param config_options Controls how the options are compared.
|
||||
// @param other The other object to compare to.
|
||||
// @param mismatch If the objects do not match, this parameter contains
|
||||
// the name of the option that triggered the match failure.
|
||||
// @param True if the objects match, false otherwise.
|
||||
virtual bool AreEquivalent(const ConfigOptions& config_options, |
||||
const Configurable* other, |
||||
std::string* name) const; |
||||
|
||||
// Returns a pretty-printed, human-readable version of the options.
|
||||
// This method is typically used to dump the options to a log file.
|
||||
// Classes should override this method
|
||||
virtual std::string GetPrintableOptions() const { return ""; } |
||||
|
||||
// Validates that the settings are valid/consistent and performs any object
|
||||
// initialization required by this object. This method may be called as part
|
||||
// of Configure (if invoke_prepare_options is set), or may be invoked
|
||||
// separately.
|
||||
//
|
||||
// Once an object has been prepared, non-mutable options can no longer be
|
||||
// updated.
|
||||
//
|
||||
// Classes must override this method to provide any implementation-specific
|
||||
// initialization, such as opening log files or setting up cache parameters.
|
||||
// Implementations should be idempotent (e.g. don't re-open the log file or
|
||||
// reconfigure the cache), as there is the potential this method can be called
|
||||
// more than once.
|
||||
//
|
||||
// By default, this method will also prepare all nested (Inner and
|
||||
// OptionType::kConfigurable) objects.
|
||||
//
|
||||
// @param config_options Controls how the object is prepared. Also contains
|
||||
// a Logger and Env that can be used to initialize this object.
|
||||
// @return OK If the object was successfully initialized.
|
||||
// @return InvalidArgument If this object could not be successfull
|
||||
// initialized.
|
||||
virtual Status PrepareOptions(const ConfigOptions& config_options); |
||||
|
||||
// Checks to see if the settings are valid for this object.
|
||||
// This method checks to see if the input DBOptions and ColumnFamilyOptions
|
||||
// are valid for the settings of this object. For example, an Env might not
|
||||
// support certain mmap modes or a TableFactory might require certain
|
||||
// settings.
|
||||
//
|
||||
// By default, this method will also validate all nested (Inner and
|
||||
// OptionType::kConfigurable) objects.
|
||||
//
|
||||
// @param db_opts The DBOptions to validate
|
||||
// @param cf_opts The ColumnFamilyOptions to validate
|
||||
// @return OK if the options are valid
|
||||
// @return InvalidArgument If the arguments are not valid for the options
|
||||
// of the current object.
|
||||
virtual Status ValidateOptions(const DBOptions& db_opts, |
||||
const ColumnFamilyOptions& cf_opts) const; |
||||
|
||||
// Returns true if this object has been initialized via PrepareOptions, false
|
||||
// otherwise. Once an object has been prepared, only mutable options may be
|
||||
// changed.
|
||||
virtual bool IsPrepared() const { return prepared_; } |
||||
|
||||
protected: |
||||
// True once the object is prepared. Once the object is prepared, only
|
||||
// mutable options can be configured.
|
||||
bool prepared_; |
||||
// If this class is a wrapper (has-a), this method should be
|
||||
// over-written to return the inner configurable (like an EnvWrapper).
|
||||
// This method should NOT recurse, but should instead return the
|
||||
// direct Inner object.
|
||||
virtual Configurable* Inner() const { return nullptr; } |
||||
|
||||
// Returns the raw pointer for the associated named option.
|
||||
// The name is typically the name of an option registered via the
|
||||
// Classes may override this method to provide further specialization (such as
|
||||
// returning a sub-option)
|
||||
//
|
||||
// The default implemntation looks at the registered options. If the
|
||||
// input name matches that of a registered option, the pointer registered
|
||||
// with that name is returned.
|
||||
// e.g,, RegisterOptions("X", &my_ptr, ...); GetOptionsPtr("X") returns
|
||||
// "my_ptr"
|
||||
virtual const void* GetOptionsPtr(const std::string& name) const; |
||||
|
||||
// Method for allowing options to be configured outside of the normal
|
||||
// registered options framework. Classes may override this method if they
|
||||
// wish to support non-standard options implementations (such as configuring
|
||||
// themselves from constant or simple ":"-separated strings.
|
||||
//
|
||||
// The default implementation does nothing and returns OK
|
||||
virtual Status ParseStringOptions(const ConfigOptions& config_options, |
||||
const std::string& opts_str); |
||||
|
||||
// Internal method to configure an object from a map of name-value options.
|
||||
// This method uses the input config_options to drive the configuration of
|
||||
// the options in opt_map. Any option name that cannot be found from the
|
||||
// input set will be returned in "unused".
|
||||
//
|
||||
// Classes may override this method to extend the functionality if required.
|
||||
// @param config_options Controls how the options are configured and errors
|
||||
// handled.
|
||||
// @param opts_map The set of options to configure
|
||||
// @param unused Any options from opt_map that were not configured.
|
||||
// @returns a Status based on the rules outlined in ConfigureFromMap
|
||||
virtual Status ConfigureOptions( |
||||
const ConfigOptions& config_options, |
||||
const std::unordered_map<std::string, std::string>& opts_map, |
||||
std::unordered_map<std::string, std::string>* unused); |
||||
|
||||
#ifndef ROCKSDB_LITE |
||||
// Method that configures a the specific opt_name from opt_value.
|
||||
// By default, this method calls opt_info.ParseOption with the
|
||||
// input parameters.
|
||||
// Classes may override this method to extend the functionality, or
|
||||
// change the returned Status.
|
||||
virtual Status ParseOption(const ConfigOptions& config_options, |
||||
const OptionTypeInfo& opt_info, |
||||
const std::string& opt_name, |
||||
const std::string& opt_value, void* opt_ptr); |
||||
|
||||
// Internal method to see if the single option name/info matches for this and
|
||||
// that Classes may override this value to change its behavior.
|
||||
// @param config_options Controls how the options are being matched
|
||||
// @param opt_info The OptionTypeInfo registered for this option name
|
||||
// that controls what field is matched (offset) and how (type).
|
||||
// @param name The name associated with this opt_info.
|
||||
// @param this_ptr The base pointer to compare to. This is the object
|
||||
// registered for
|
||||
// for this OptionTypeInfo.
|
||||
// @param that_ptr The other pointer to compare to. This is the object
|
||||
// registered for
|
||||
// for this OptionTypeInfo.
|
||||
// @param bad_name If the match fails, the name of the option that failed to
|
||||
// match.
|
||||
virtual bool OptionsAreEqual(const ConfigOptions& config_options, |
||||
const OptionTypeInfo& opt_info, |
||||
const std::string& name, |
||||
const void* const this_ptr, |
||||
const void* const that_ptr, |
||||
std::string* bad_name) const; |
||||
#endif |
||||
#ifndef ROCKSDB_LITE |
||||
// Internal method to serialize options (ToString)
|
||||
// Classes may override this value to change its behavior.
|
||||
virtual std::string SerializeOptions(const ConfigOptions& config_options, |
||||
const std::string& header) const; |
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
// Given a name (e.g. rocksdb.my.type.opt), returns the short name (opt)
|
||||
virtual std::string GetOptionName(const std::string& long_name) const; |
||||
|
||||
private: |
||||
// Contains the collection of options (name, opt_ptr, opt_map) associated with
|
||||
// this object. This collection is typically set in the constructor of the
|
||||
// Configurable option via
|
||||
std::vector<RegisteredOptions> options_; |
||||
}; |
||||
} // namespace ROCKSDB_NAMESPACE
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,610 @@ |
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
#include "rocksdb/configurable.h" |
||||
|
||||
#include "logging/logging.h" |
||||
#include "options/configurable_helper.h" |
||||
#include "options/options_helper.h" |
||||
#include "rocksdb/status.h" |
||||
#include "rocksdb/utilities/object_registry.h" |
||||
#include "rocksdb/utilities/options_type.h" |
||||
#include "util/coding.h" |
||||
#include "util/string_util.h" |
||||
|
||||
namespace ROCKSDB_NAMESPACE { |
||||
|
||||
void ConfigurableHelper::RegisterOptions( |
||||
Configurable& configurable, const std::string& name, void* opt_ptr, |
||||
const std::unordered_map<std::string, OptionTypeInfo>* type_map) { |
||||
Configurable::RegisteredOptions opts; |
||||
opts.name = name; |
||||
#ifndef ROCKSDB_LITE |
||||
opts.type_map = type_map; |
||||
#else |
||||
(void)type_map; |
||||
#endif // ROCKSDB_LITE
|
||||
opts.opt_ptr = opt_ptr; |
||||
configurable.options_.emplace_back(opts); |
||||
} |
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// Methods for Initializing and Validating Configurable Objects
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
Status Configurable::PrepareOptions(const ConfigOptions& opts) { |
||||
Status status = Status::OK(); |
||||
#ifndef ROCKSDB_LITE |
||||
for (auto opt_iter : options_) { |
||||
for (auto map_iter : *(opt_iter.type_map)) { |
||||
auto& opt_info = map_iter.second; |
||||
if (!opt_info.IsDeprecated() && !opt_info.IsAlias() && |
||||
opt_info.IsConfigurable()) { |
||||
if (!opt_info.IsEnabled(OptionTypeFlags::kDontPrepare)) { |
||||
Configurable* config = |
||||
opt_info.AsRawPointer<Configurable>(opt_iter.opt_ptr); |
||||
if (config != nullptr) { |
||||
status = config->PrepareOptions(opts); |
||||
if (!status.ok()) { |
||||
return status; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
#endif // ROCKSDB_LITE
|
||||
if (status.ok()) { |
||||
auto inner = Inner(); |
||||
if (inner != nullptr) { |
||||
status = inner->PrepareOptions(opts); |
||||
} |
||||
} |
||||
if (status.ok()) { |
||||
prepared_ = true; |
||||
} |
||||
return status; |
||||
} |
||||
|
||||
Status Configurable::ValidateOptions(const DBOptions& db_opts, |
||||
const ColumnFamilyOptions& cf_opts) const { |
||||
Status status; |
||||
#ifndef ROCKSDB_LITE |
||||
for (auto opt_iter : options_) { |
||||
for (auto map_iter : *(opt_iter.type_map)) { |
||||
auto& opt_info = map_iter.second; |
||||
if (!opt_info.IsDeprecated() && !opt_info.IsAlias()) { |
||||
if (opt_info.IsConfigurable()) { |
||||
const Configurable* config = |
||||
opt_info.AsRawPointer<Configurable>(opt_iter.opt_ptr); |
||||
if (config != nullptr) { |
||||
status = config->ValidateOptions(db_opts, cf_opts); |
||||
} else if (!opt_info.CanBeNull()) { |
||||
status = |
||||
Status::NotFound("Missing configurable object", map_iter.first); |
||||
} |
||||
if (!status.ok()) { |
||||
return status; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
#endif // ROCKSDB_LITE
|
||||
if (status.ok()) { |
||||
const auto inner = Inner(); |
||||
if (inner != nullptr) { |
||||
status = inner->ValidateOptions(db_opts, cf_opts); |
||||
} |
||||
} |
||||
return status; |
||||
} |
||||
|
||||
/*********************************************************************************/ |
||||
/* */ |
||||
/* Methods for Retrieving Options from Configurables */ |
||||
/* */ |
||||
/*********************************************************************************/ |
||||
|
||||
const void* Configurable::GetOptionsPtr(const std::string& name) const { |
||||
for (auto o : options_) { |
||||
if (o.name == name) { |
||||
return o.opt_ptr; |
||||
} |
||||
} |
||||
auto inner = Inner(); |
||||
if (inner != nullptr) { |
||||
return inner->GetOptionsPtr(name); |
||||
} else { |
||||
return nullptr; |
||||
} |
||||
} |
||||
|
||||
std::string Configurable::GetOptionName(const std::string& opt_name) const { |
||||
return opt_name; |
||||
} |
||||
|
||||
#ifndef ROCKSDB_LITE |
||||
const OptionTypeInfo* ConfigurableHelper::FindOption( |
||||
const std::vector<Configurable::RegisteredOptions>& options, |
||||
const std::string& short_name, std::string* opt_name, void** opt_ptr) { |
||||
for (auto iter : options) { |
||||
const auto opt_info = |
||||
OptionTypeInfo::Find(short_name, *(iter.type_map), opt_name); |
||||
if (opt_info != nullptr) { |
||||
*opt_ptr = iter.opt_ptr; |
||||
return opt_info; |
||||
} |
||||
} |
||||
return nullptr; |
||||
} |
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
//*************************************************************************
|
||||
//
|
||||
// Methods for Configuring Options from Strings/Name-Value Pairs/Maps
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
Status Configurable::ConfigureFromMap( |
||||
const ConfigOptions& config_options, |
||||
const std::unordered_map<std::string, std::string>& opts_map) { |
||||
Status s = ConfigureFromMap(config_options, opts_map, nullptr); |
||||
return s; |
||||
} |
||||
|
||||
Status Configurable::ConfigureFromMap( |
||||
const ConfigOptions& config_options, |
||||
const std::unordered_map<std::string, std::string>& opts_map, |
||||
std::unordered_map<std::string, std::string>* unused) { |
||||
return ConfigureOptions(config_options, opts_map, unused); |
||||
} |
||||
|
||||
Status Configurable::ConfigureOptions( |
||||
const ConfigOptions& config_options, |
||||
const std::unordered_map<std::string, std::string>& opts_map, |
||||
std::unordered_map<std::string, std::string>* unused) { |
||||
std::string curr_opts; |
||||
#ifndef ROCKSDB_LITE |
||||
if (!config_options.ignore_unknown_options) { |
||||
// If we are not ignoring unused, get the defaults in case we need to reset
|
||||
GetOptionString(config_options, &curr_opts).PermitUncheckedError(); |
||||
} |
||||
#endif // ROCKSDB_LITE
|
||||
Status s = ConfigurableHelper::ConfigureOptions(config_options, *this, |
||||
opts_map, unused); |
||||
if (config_options.invoke_prepare_options && s.ok()) { |
||||
s = PrepareOptions(config_options); |
||||
} |
||||
#ifndef ROCKSDB_LITE |
||||
if (!s.ok() && !curr_opts.empty()) { |
||||
ConfigOptions reset = config_options; |
||||
reset.ignore_unknown_options = true; |
||||
reset.invoke_prepare_options = true; |
||||
// There are some options to reset from this current error
|
||||
ConfigureFromString(reset, curr_opts).PermitUncheckedError(); |
||||
} |
||||
#endif // ROCKSDB_LITE
|
||||
return s; |
||||
} |
||||
|
||||
Status Configurable::ParseStringOptions(const ConfigOptions& /*config_options*/, |
||||
const std::string& /*opts_str*/) { |
||||
return Status::OK(); |
||||
} |
||||
|
||||
Status Configurable::ConfigureFromString(const ConfigOptions& config_options, |
||||
const std::string& opts_str) { |
||||
Status s; |
||||
if (!opts_str.empty()) { |
||||
#ifndef ROCKSDB_LITE |
||||
if (opts_str.find(';') != std::string::npos || |
||||
opts_str.find('=') != std::string::npos) { |
||||
std::unordered_map<std::string, std::string> opt_map; |
||||
s = StringToMap(opts_str, &opt_map); |
||||
if (s.ok()) { |
||||
s = ConfigureFromMap(config_options, opt_map, nullptr); |
||||
} |
||||
} else { |
||||
#endif // ROCKSDB_LITE
|
||||
s = ParseStringOptions(config_options, opts_str); |
||||
if (s.ok() && config_options.invoke_prepare_options) { |
||||
s = PrepareOptions(config_options); |
||||
} |
||||
#ifndef ROCKSDB_LITE |
||||
} |
||||
#endif // ROCKSDB_LITE
|
||||
} else if (config_options.invoke_prepare_options) { |
||||
s = PrepareOptions(config_options); |
||||
} else { |
||||
s = Status::OK(); |
||||
} |
||||
return s; |
||||
} |
||||
|
||||
#ifndef ROCKSDB_LITE |
||||
/**
|
||||
* Sets the value of the named property to the input value, returning OK on |
||||
* succcess. |
||||
*/ |
||||
Status Configurable::ConfigureOption(const ConfigOptions& config_options, |
||||
const std::string& name, |
||||
const std::string& value) { |
||||
const std::string& opt_name = GetOptionName(name); |
||||
return ConfigurableHelper::ConfigureSingleOption(config_options, *this, |
||||
opt_name, value); |
||||
} |
||||
|
||||
/**
|
||||
* Looks for the named option amongst the options for this type and sets |
||||
* the value for it to be the input value. |
||||
* If the name was found, found_option will be set to true and the resulting |
||||
* status should be returned. |
||||
*/ |
||||
|
||||
Status Configurable::ParseOption(const ConfigOptions& config_options, |
||||
const OptionTypeInfo& opt_info, |
||||
const std::string& opt_name, |
||||
const std::string& opt_value, void* opt_ptr) { |
||||
if (opt_info.IsMutable() || opt_info.IsConfigurable()) { |
||||
return opt_info.Parse(config_options, opt_name, opt_value, opt_ptr); |
||||
} else if (prepared_) { |
||||
return Status::InvalidArgument("Option not changeable: " + opt_name); |
||||
} else { |
||||
return opt_info.Parse(config_options, opt_name, opt_value, opt_ptr); |
||||
} |
||||
} |
||||
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
Status ConfigurableHelper::ConfigureOptions( |
||||
const ConfigOptions& config_options, Configurable& configurable, |
||||
const std::unordered_map<std::string, std::string>& opts_map, |
||||
std::unordered_map<std::string, std::string>* unused) { |
||||
std::unordered_map<std::string, std::string> remaining = opts_map; |
||||
Status s = Status::OK(); |
||||
if (!opts_map.empty()) { |
||||
#ifndef ROCKSDB_LITE |
||||
for (const auto& iter : configurable.options_) { |
||||
s = ConfigureSomeOptions(config_options, configurable, *(iter.type_map), |
||||
&remaining, iter.opt_ptr); |
||||
if (remaining.empty()) { // Are there more options left?
|
||||
break; |
||||
} else if (!s.ok()) { |
||||
break; |
||||
} |
||||
} |
||||
#else |
||||
(void)configurable; |
||||
if (!config_options.ignore_unknown_options) { |
||||
s = Status::NotSupported("ConfigureFromMap not supported in LITE mode"); |
||||
} |
||||
#endif // ROCKSDB_LITE
|
||||
} |
||||
if (unused != nullptr && !remaining.empty()) { |
||||
unused->insert(remaining.begin(), remaining.end()); |
||||
} |
||||
if (config_options.ignore_unknown_options) { |
||||
s = Status::OK(); |
||||
} else if (s.ok() && unused == nullptr && !remaining.empty()) { |
||||
s = Status::NotFound("Could not find option: ", remaining.begin()->first); |
||||
} |
||||
return s; |
||||
} |
||||
|
||||
#ifndef ROCKSDB_LITE |
||||
/**
|
||||
* Updates the object with the named-value property values, returning OK on |
||||
* succcess. Any properties that were found are removed from the options list; |
||||
* upon return only options that were not found in this opt_map remain. |
||||
|
||||
* Returns: |
||||
* - OK if ignore_unknown_options is set |
||||
* - InvalidArgument, if any option was invalid |
||||
* - NotSupported, if any option is unsupported and ignore_unsupported_options |
||||
is OFF |
||||
* - OK, if no option was invalid or not supported (or ignored) |
||||
*/ |
||||
Status ConfigurableHelper::ConfigureSomeOptions( |
||||
const ConfigOptions& config_options, Configurable& configurable, |
||||
const std::unordered_map<std::string, OptionTypeInfo>& type_map, |
||||
std::unordered_map<std::string, std::string>* options, void* opt_ptr) { |
||||
Status result = Status::OK(); // The last non-OK result (if any)
|
||||
Status notsup = Status::OK(); // The last NotSupported result (if any)
|
||||
std::string elem_name; |
||||
int found = 1; |
||||
std::unordered_set<std::string> unsupported; |
||||
// While there are unused properties and we processed at least one,
|
||||
// go through the remaining unused properties and attempt to configure them.
|
||||
while (found > 0 && !options->empty()) { |
||||
found = 0; |
||||
notsup = Status::OK(); |
||||
for (auto it = options->begin(); it != options->end();) { |
||||
const std::string& opt_name = configurable.GetOptionName(it->first); |
||||
const std::string& opt_value = it->second; |
||||
const auto opt_info = |
||||
OptionTypeInfo::Find(opt_name, type_map, &elem_name); |
||||
if (opt_info == nullptr) { // Did not find the option. Skip it
|
||||
++it; |
||||
} else { |
||||
Status s = ConfigureOption(config_options, configurable, *opt_info, |
||||
opt_name, elem_name, opt_value, opt_ptr); |
||||
if (s.IsNotFound()) { |
||||
++it; |
||||
} else if (s.IsNotSupported()) { |
||||
notsup = s; |
||||
unsupported.insert(it->first); |
||||
++it; // Skip it for now
|
||||
} else { |
||||
found++; |
||||
it = options->erase(it); |
||||
if (!s.ok()) { |
||||
result = s; |
||||
} |
||||
} |
||||
} |
||||
} // End for all remaining options
|
||||
} // End while found one or options remain
|
||||
|
||||
// Now that we have been through the list, remove any unsupported
|
||||
for (auto u : unsupported) { |
||||
auto it = options->find(u); |
||||
if (it != options->end()) { |
||||
options->erase(it); |
||||
} |
||||
} |
||||
if (config_options.ignore_unknown_options) { |
||||
if (!result.ok()) result.PermitUncheckedError(); |
||||
if (!notsup.ok()) notsup.PermitUncheckedError(); |
||||
return Status::OK(); |
||||
} else if (!result.ok()) { |
||||
if (!notsup.ok()) notsup.PermitUncheckedError(); |
||||
return result; |
||||
} else if (config_options.ignore_unsupported_options) { |
||||
if (!notsup.ok()) notsup.PermitUncheckedError(); |
||||
return Status::OK(); |
||||
} else { |
||||
return notsup; |
||||
} |
||||
} |
||||
|
||||
Status ConfigurableHelper::ConfigureSingleOption( |
||||
const ConfigOptions& config_options, Configurable& configurable, |
||||
const std::string& name, const std::string& value) { |
||||
std::string opt_name; |
||||
void* opt_ptr = nullptr; |
||||
const auto opt_info = |
||||
FindOption(configurable.options_, name, &opt_name, &opt_ptr); |
||||
if (opt_info == nullptr) { |
||||
return Status::NotFound("Could not find option: ", name); |
||||
} else { |
||||
return ConfigureOption(config_options, configurable, *opt_info, name, |
||||
opt_name, value, opt_ptr); |
||||
} |
||||
} |
||||
|
||||
Status ConfigurableHelper::ConfigureOption( |
||||
const ConfigOptions& config_options, Configurable& configurable, |
||||
const OptionTypeInfo& opt_info, const std::string& opt_name, |
||||
const std::string& name, const std::string& value, void* opt_ptr) { |
||||
if (opt_name == name) { |
||||
return configurable.ParseOption(config_options, opt_info, opt_name, value, |
||||
opt_ptr); |
||||
} else if (opt_info.IsStruct() || opt_info.IsConfigurable()) { |
||||
return configurable.ParseOption(config_options, opt_info, name, value, |
||||
opt_ptr); |
||||
} else { |
||||
return Status::NotFound("Could not find option: ", name); |
||||
} |
||||
} |
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
//*******************************************************************************
|
||||
//
|
||||
// Methods for Converting Options into strings
|
||||
//
|
||||
//*******************************************************************************
|
||||
|
||||
Status Configurable::GetOptionString(const ConfigOptions& config_options, |
||||
std::string* result) const { |
||||
assert(result); |
||||
result->clear(); |
||||
#ifndef ROCKSDB_LITE |
||||
return ConfigurableHelper::SerializeOptions(config_options, *this, "", |
||||
result); |
||||
#else |
||||
(void)config_options; |
||||
return Status::NotSupported("GetOptionString not supported in LITE mode"); |
||||
#endif // ROCKSDB_LITE
|
||||
} |
||||
|
||||
#ifndef ROCKSDB_LITE |
||||
std::string Configurable::ToString(const ConfigOptions& config_options, |
||||
const std::string& prefix) const { |
||||
std::string result = SerializeOptions(config_options, prefix); |
||||
if (result.empty() || result.find('=') == std::string::npos) { |
||||
return result; |
||||
} else { |
||||
return "{" + result + "}"; |
||||
} |
||||
} |
||||
|
||||
std::string Configurable::SerializeOptions(const ConfigOptions& config_options, |
||||
const std::string& header) const { |
||||
std::string result; |
||||
Status s = ConfigurableHelper::SerializeOptions(config_options, *this, header, |
||||
&result); |
||||
assert(s.ok()); |
||||
return result; |
||||
} |
||||
|
||||
Status Configurable::GetOption(const ConfigOptions& config_options, |
||||
const std::string& name, |
||||
std::string* value) const { |
||||
return ConfigurableHelper::GetOption(config_options, *this, |
||||
GetOptionName(name), value); |
||||
} |
||||
|
||||
Status ConfigurableHelper::GetOption(const ConfigOptions& config_options, |
||||
const Configurable& configurable, |
||||
const std::string& short_name, |
||||
std::string* value) { |
||||
// Look for option directly
|
||||
assert(value); |
||||
value->clear(); |
||||
|
||||
std::string opt_name; |
||||
void* opt_ptr = nullptr; |
||||
const auto opt_info = |
||||
FindOption(configurable.options_, short_name, &opt_name, &opt_ptr); |
||||
if (opt_info != nullptr) { |
||||
ConfigOptions embedded = config_options; |
||||
embedded.delimiter = ";"; |
||||
if (short_name == opt_name) { |
||||
return opt_info->Serialize(embedded, opt_name, opt_ptr, value); |
||||
} else if (opt_info->IsStruct()) { |
||||
return opt_info->Serialize(embedded, opt_name, opt_ptr, value); |
||||
} else if (opt_info->IsConfigurable()) { |
||||
auto const* config = opt_info->AsRawPointer<Configurable>(opt_ptr); |
||||
if (config != nullptr) { |
||||
return config->GetOption(embedded, opt_name, value); |
||||
} |
||||
} |
||||
} |
||||
return Status::NotFound("Cannot find option: ", short_name); |
||||
} |
||||
|
||||
Status ConfigurableHelper::SerializeOptions(const ConfigOptions& config_options, |
||||
const Configurable& configurable, |
||||
const std::string& prefix, |
||||
std::string* result) { |
||||
assert(result); |
||||
for (auto const& opt_iter : configurable.options_) { |
||||
for (const auto& map_iter : *(opt_iter.type_map)) { |
||||
const auto& opt_name = map_iter.first; |
||||
const auto& opt_info = map_iter.second; |
||||
if (opt_info.ShouldSerialize()) { |
||||
std::string value; |
||||
Status s = opt_info.Serialize(config_options, prefix + opt_name, |
||||
opt_iter.opt_ptr, &value); |
||||
if (!s.ok()) { |
||||
return s; |
||||
} else if (!value.empty()) { |
||||
// <prefix><opt_name>=<value><delimiter>
|
||||
result->append(prefix + opt_name + "=" + value + |
||||
config_options.delimiter); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
return Status::OK(); |
||||
} |
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
//********************************************************************************
|
||||
//
|
||||
// Methods for listing the options from Configurables
|
||||
//
|
||||
//********************************************************************************
|
||||
#ifndef ROCKSDB_LITE |
||||
Status Configurable::GetOptionNames( |
||||
const ConfigOptions& config_options, |
||||
std::unordered_set<std::string>* result) const { |
||||
assert(result); |
||||
return ConfigurableHelper::ListOptions(config_options, *this, "", result); |
||||
} |
||||
|
||||
Status ConfigurableHelper::ListOptions( |
||||
const ConfigOptions& /*config_options*/, const Configurable& configurable, |
||||
const std::string& prefix, std::unordered_set<std::string>* result) { |
||||
Status status; |
||||
for (auto const& opt_iter : configurable.options_) { |
||||
for (const auto& map_iter : *(opt_iter.type_map)) { |
||||
const auto& opt_name = map_iter.first; |
||||
const auto& opt_info = map_iter.second; |
||||
// If the option is no longer used in rocksdb and marked as deprecated,
|
||||
// we skip it in the serialization.
|
||||
if (!opt_info.IsDeprecated() && !opt_info.IsAlias()) { |
||||
result->emplace(prefix + opt_name); |
||||
} |
||||
} |
||||
} |
||||
return status; |
||||
} |
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
//*******************************************************************************
|
||||
//
|
||||
// Methods for Comparing Configurables
|
||||
//
|
||||
//*******************************************************************************
|
||||
|
||||
bool Configurable::AreEquivalent(const ConfigOptions& config_options, |
||||
const Configurable* other, |
||||
std::string* name) const { |
||||
assert(name); |
||||
name->clear(); |
||||
if (this == other || config_options.IsCheckDisabled()) { |
||||
return true; |
||||
} else if (other != nullptr) { |
||||
#ifndef ROCKSDB_LITE |
||||
return ConfigurableHelper::AreEquivalent(config_options, *this, *other, |
||||
name); |
||||
#else |
||||
return true; |
||||
#endif // ROCKSDB_LITE
|
||||
} else { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
#ifndef ROCKSDB_LITE |
||||
bool Configurable::OptionsAreEqual(const ConfigOptions& config_options, |
||||
const OptionTypeInfo& opt_info, |
||||
const std::string& opt_name, |
||||
const void* const this_ptr, |
||||
const void* const that_ptr, |
||||
std::string* mismatch) const { |
||||
if (opt_info.AreEqual(config_options, opt_name, this_ptr, that_ptr, |
||||
mismatch)) { |
||||
return true; |
||||
} else if (opt_info.AreEqualByName(config_options, opt_name, this_ptr, |
||||
that_ptr)) { |
||||
*mismatch = ""; |
||||
return true; |
||||
} else { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
bool ConfigurableHelper::AreEquivalent(const ConfigOptions& config_options, |
||||
const Configurable& this_one, |
||||
const Configurable& that_one, |
||||
std::string* mismatch) { |
||||
assert(mismatch != nullptr); |
||||
for (auto const& o : this_one.options_) { |
||||
const auto this_offset = this_one.GetOptionsPtr(o.name); |
||||
const auto that_offset = that_one.GetOptionsPtr(o.name); |
||||
if (this_offset != that_offset) { |
||||
if (this_offset == nullptr || that_offset == nullptr) { |
||||
return false; |
||||
} else { |
||||
for (const auto& map_iter : *(o.type_map)) { |
||||
if (config_options.IsCheckEnabled(map_iter.second.GetSanityLevel()) && |
||||
!this_one.OptionsAreEqual(config_options, map_iter.second, |
||||
map_iter.first, this_offset, |
||||
that_offset, mismatch)) { |
||||
return false; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
#endif // ROCKSDB_LITE
|
||||
} // namespace ROCKSDB_NAMESPACE
|
@ -0,0 +1,211 @@ |
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
#pragma once |
||||
|
||||
#include <map> |
||||
#include <stdexcept> |
||||
#include <string> |
||||
#include <vector> |
||||
|
||||
#include "rocksdb/configurable.h" |
||||
#include "rocksdb/convenience.h" |
||||
|
||||
namespace ROCKSDB_NAMESPACE { |
||||
// Helper class defining static methods for supporting the Configurable
|
||||
// class. The purpose of this class is to keep the Configurable class
|
||||
// as tight as possible and provide methods for doing the actual work
|
||||
// of configuring the objects.
|
||||
class ConfigurableHelper { |
||||
public: |
||||
// Registers the input name with the options and associated map.
|
||||
// When classes register their options in this manner, most of the
|
||||
// functionality (excluding unknown options and validate/prepare) is
|
||||
// implemented by the base class.
|
||||
//
|
||||
// This method should be called in the class constructor to register the
|
||||
// option set for this object. For example, to register the options
|
||||
// associated with the BlockBasedTableFactory, the constructor calls this
|
||||
// method passing in:
|
||||
// - the name of the options ("BlockBasedTableOptions");
|
||||
// - the options object (the BlockBasedTableOptions object for this object;
|
||||
// - the options type map for the BlockBasedTableOptions.
|
||||
// This registration allows the Configurable class to process the option
|
||||
// values associated with the BlockBasedTableOptions without further code in
|
||||
// the derived class.
|
||||
//
|
||||
// @param name The name of this set of options (@see GetOptionsPtr)
|
||||
// @param opt_ptr Pointer to the options to associate with this name
|
||||
// @param opt_map Options map that controls how this option is configured.
|
||||
template <typename T> |
||||
static void RegisterOptions( |
||||
Configurable& configurable, T* opt_ptr, |
||||
const std::unordered_map<std::string, OptionTypeInfo>* opt_map) { |
||||
RegisterOptions(configurable, T::kName(), opt_ptr, opt_map); |
||||
} |
||||
static void RegisterOptions( |
||||
Configurable& configurable, const std::string& name, void* opt_ptr, |
||||
const std::unordered_map<std::string, OptionTypeInfo>* opt_map); |
||||
|
||||
// Configures the input Configurable object based on the parameters.
|
||||
// On successful completion, the Configurable is updated with the settings
|
||||
// from the opt_map.
|
||||
//
|
||||
// The acceptable values of the name/value pairs are documented with the
|
||||
// specific class/instance.
|
||||
//
|
||||
// @param config_options Controls how the arguments are processed.
|
||||
// @param opt_map Name/value pairs of the options to update
|
||||
// @param unused If specified, this value will return the name/value
|
||||
// pairs from opt_map that were NotFound for this object.
|
||||
// @return OK If all values in the map were successfully updated
|
||||
// @return NotFound If any of the names in the opt_map were not valid
|
||||
// for this object. If unused is specified, it will contain the
|
||||
// collection of NotFound entries
|
||||
// @return NotSupported If any of the names are valid but the object does
|
||||
// not know how to convert the value. This can happen if, for example,
|
||||
// there is some nested Configurable that cannot be created.
|
||||
// @return InvalidArgument If any of the values cannot be successfully
|
||||
// parsed. This can also be returned if PrepareOptions encounters an
|
||||
// error.
|
||||
static Status ConfigureOptions( |
||||
const ConfigOptions& config_options, Configurable& configurable, |
||||
const std::unordered_map<std::string, std::string>& options, |
||||
std::unordered_map<std::string, std::string>* unused); |
||||
|
||||
#ifndef ROCKSDB_LITE |
||||
// Internal method to configure a set of options for this object.
|
||||
// Classes may override this value to change its behavior.
|
||||
// @param config_options Controls how the options are being configured
|
||||
// @param type_name The name that was registered for this set of options
|
||||
// @param type_map The map of options for this name
|
||||
// @param opt_ptr Pointer to the object being configured for this option set.
|
||||
// @param options The option name/values being updated. On return, any
|
||||
// option that was found is removed from the list.
|
||||
// @return OK If all of the options were successfully updated.
|
||||
// @return InvalidArgument If an option was found but the value could not
|
||||
// be updated.
|
||||
// @return NotFound If an option name was not found in type_mape
|
||||
// @return NotSupported If the option was found but no rule for converting
|
||||
// the value could be found.
|
||||
static Status ConfigureSomeOptions( |
||||
const ConfigOptions& config_options, Configurable& configurable, |
||||
const std::unordered_map<std::string, OptionTypeInfo>& type_map, |
||||
std::unordered_map<std::string, std::string>* options, void* opt_ptr); |
||||
|
||||
// Configures a single option in the input Configurable.
|
||||
// This method will look through the set of option names for this
|
||||
// Configurable searching for one with the input name. If such an option
|
||||
// is found, it will be configured via the input value.
|
||||
//
|
||||
// @param config_options Controls how the option is being configured
|
||||
// @param configurable The object to configure
|
||||
// @param name For options with sub-options (like Structs or
|
||||
// Configurables),
|
||||
// this value may be the name of the sub-field of the option being
|
||||
// updated. For example, if the option is
|
||||
// "compaction_options_fifo.allow_compaction", then field name would be
|
||||
// "allow_compaction". For most options, field_name and opt_name will be
|
||||
// equivalent.
|
||||
// @param value The new value for this option.
|
||||
// @param See ConfigureOptions for the possible return values
|
||||
static Status ConfigureSingleOption(const ConfigOptions& config_options, |
||||
Configurable& configurable, |
||||
const std::string& name, |
||||
const std::string& value); |
||||
|
||||
// Configures the option referenced by opt_info for this configurable
|
||||
// This method configures the option based on opt_info for the input
|
||||
// configurable.
|
||||
// @param config_options Controls how the option is being configured
|
||||
// @param configurable The object to configure
|
||||
// @param opt_name The full option name
|
||||
// @param name For options with sub-options (like Structs or
|
||||
// Configurables),
|
||||
// this value may be the name of the sub-field of the option being
|
||||
// updated. For example, if the option is
|
||||
// "compaction_options_fifo.allow_compaction", then field name would be
|
||||
// "allow_compaction". For most options, field_name and opt_name will be
|
||||
// equivalent.
|
||||
// @param value The new value for this option.
|
||||
// @param See ConfigureOptions for the possible return values
|
||||
static Status ConfigureOption(const ConfigOptions& config_options, |
||||
Configurable& configurable, |
||||
const OptionTypeInfo& opt_info, |
||||
const std::string& opt_name, |
||||
const std::string& name, |
||||
const std::string& value, void* opt_ptr); |
||||
|
||||
// Returns the value of the option associated with the input name
|
||||
// This method is the functional inverse of ConfigureOption
|
||||
// @param config_options Controls how the value is returned
|
||||
// @param configurable The object from which to get the option.
|
||||
// @param name The name of the option to return a value for.
|
||||
// @param value The returned value associated with the named option.
|
||||
// Note that value will be only the serialized version
|
||||
// of the option and not "name=value"
|
||||
// @return OK If the named field was successfully updated to value.
|
||||
// @return NotFound If the name is not valid for this object.
|
||||
// @param InvalidArgument If the name is valid for this object but
|
||||
// its value cannot be serialized.
|
||||
static Status GetOption(const ConfigOptions& config_options, |
||||
const Configurable& configurable, |
||||
const std::string& name, std::string* value); |
||||
|
||||
// Serializes the input Configurable into the output result.
|
||||
// This is the inverse of ConfigureOptions
|
||||
// @param config_options Controls how serialization happens.
|
||||
// @param configurable The object to serialize
|
||||
// @param prefix A prefix to add to the each option as it is serialized.
|
||||
// @param result The string representation of the configurable.
|
||||
// @return OK If the options for this object wer successfully serialized.
|
||||
// @return InvalidArgument If one or more of the options could not be
|
||||
// serialized.
|
||||
static Status SerializeOptions(const ConfigOptions& config_options, |
||||
const Configurable& configurable, |
||||
const std::string& prefix, |
||||
std::string* result); |
||||
|
||||
// Internal method to list the option names for this object.
|
||||
// Classes may override this value to change its behavior.
|
||||
// @see ListOptions for more details
|
||||
static Status ListOptions(const ConfigOptions& config_options, |
||||
const Configurable& configurable, |
||||
const std::string& prefix, |
||||
std::unordered_set<std::string>* result); |
||||
|
||||
// Checks to see if the two configurables are equivalent to one other.
|
||||
// This method assumes that the two objects are of the same class.
|
||||
// @param config_options Controls how the options are compared.
|
||||
// @param this_one The object to compare to.
|
||||
// @param that_one The other object being compared.
|
||||
// @param mismatch If the objects do not match, this parameter contains
|
||||
// the name of the option that triggered the match failure.
|
||||
// @param True if the objects match, false otherwise.
|
||||
static bool AreEquivalent(const ConfigOptions& config_options, |
||||
const Configurable& this_one, |
||||
const Configurable& that_one, |
||||
std::string* mismatch); |
||||
|
||||
private: |
||||
// Looks for the option specified by name in the RegisteredOptions.
|
||||
// This method traverses the types in the input options vector. If an entry
|
||||
// matching name is found, that entry, opt_name, and pointer are returned.
|
||||
// @param options The vector of options to search through
|
||||
// @param name The name of the option to search for in the OptionType map
|
||||
// @param opt_name If the name was found, this value is set to the option name
|
||||
// associated with the input name/type.
|
||||
// @param opt_ptr If the name was found, this value is set to the option
|
||||
// pointer
|
||||
// in the RegisteredOptions vector associated with this entry
|
||||
// @return A pointer to the OptionTypeInfo from the options if found,
|
||||
// nullptr if the name was not found in the input options
|
||||
static const OptionTypeInfo* FindOption( |
||||
const std::vector<Configurable::RegisteredOptions>& options, |
||||
const std::string& name, std::string* opt_name, void** opt_ptr); |
||||
#endif // ROCKSDB_LITE
|
||||
}; |
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
@ -0,0 +1,791 @@ |
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
//
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include "options/configurable_test.h" |
||||
|
||||
#include <cctype> |
||||
#include <cinttypes> |
||||
#include <cstring> |
||||
#include <unordered_map> |
||||
|
||||
#include "options/configurable_helper.h" |
||||
#include "options/options_helper.h" |
||||
#include "options/options_parser.h" |
||||
#include "rocksdb/configurable.h" |
||||
#include "test_util/testharness.h" |
||||
#include "test_util/testutil.h" |
||||
|
||||
#ifndef GFLAGS |
||||
bool FLAGS_enable_print = false; |
||||
#else |
||||
#include "util/gflags_compat.h" |
||||
using GFLAGS_NAMESPACE::ParseCommandLineFlags; |
||||
DEFINE_bool(enable_print, false, "Print options generated to console."); |
||||
#endif // GFLAGS
|
||||
|
||||
namespace ROCKSDB_NAMESPACE { |
||||
namespace test { |
||||
class StringLogger : public Logger { |
||||
public: |
||||
using Logger::Logv; |
||||
void Logv(const char* format, va_list ap) override { |
||||
char buffer[1000]; |
||||
vsnprintf(buffer, sizeof(buffer), format, ap); |
||||
string_.append(buffer); |
||||
} |
||||
const std::string& str() const { return string_; } |
||||
void clear() { string_.clear(); } |
||||
|
||||
private: |
||||
std::string string_; |
||||
}; |
||||
|
||||
class SimpleConfigurable : public TestConfigurable<Configurable> { |
||||
public: |
||||
static SimpleConfigurable* Create( |
||||
const std::string& name = "simple", |
||||
int mode = TestConfigMode::kDefaultMode, |
||||
const std::unordered_map<std::string, OptionTypeInfo>* map = |
||||
&simple_option_info) { |
||||
return new SimpleConfigurable(name, mode, map); |
||||
} |
||||
|
||||
SimpleConfigurable(const std::string& name, int mode, |
||||
const std::unordered_map<std::string, OptionTypeInfo>* |
||||
map = &simple_option_info) |
||||
: TestConfigurable(name, mode, map) { |
||||
if ((mode & TestConfigMode::kUniqueMode) != 0) { |
||||
unique_.reset(SimpleConfigurable::Create("Unique" + name_)); |
||||
ConfigurableHelper::RegisterOptions(*this, name_ + "Unique", &unique_, |
||||
&unique_option_info); |
||||
} |
||||
if ((mode & TestConfigMode::kSharedMode) != 0) { |
||||
shared_.reset(SimpleConfigurable::Create("Shared" + name_)); |
||||
ConfigurableHelper::RegisterOptions(*this, name_ + "Shared", &shared_, |
||||
&shared_option_info); |
||||
} |
||||
if ((mode & TestConfigMode::kRawPtrMode) != 0) { |
||||
pointer_ = SimpleConfigurable::Create("Pointer" + name_); |
||||
ConfigurableHelper::RegisterOptions(*this, name_ + "Pointer", &pointer_, |
||||
&pointer_option_info); |
||||
} |
||||
} |
||||
|
||||
}; // End class SimpleConfigurable
|
||||
|
||||
static std::unordered_map<std::string, OptionTypeInfo> wrapped_option_info = { |
||||
#ifndef ROCKSDB_LITE |
||||
{"inner", |
||||
{0, OptionType::kConfigurable, OptionVerificationType::kNormal, |
||||
OptionTypeFlags::kShared}}, |
||||
#endif // ROCKSDB_LITE
|
||||
}; |
||||
class WrappedConfigurable : public SimpleConfigurable { |
||||
public: |
||||
WrappedConfigurable(const std::string& name, unsigned char mode, |
||||
const std::shared_ptr<Configurable>& t) |
||||
: SimpleConfigurable(name, mode, &simple_option_info), inner_(t) { |
||||
ConfigurableHelper::RegisterOptions(*this, "WrappedOptions", &inner_, |
||||
&wrapped_option_info); |
||||
} |
||||
|
||||
protected: |
||||
Configurable* Inner() const override { return inner_.get(); } |
||||
|
||||
private: |
||||
std::shared_ptr<Configurable> inner_; |
||||
}; |
||||
|
||||
using ConfigTestFactoryFunc = std::function<Configurable*()>; |
||||
|
||||
class ConfigurableTest : public testing::Test { |
||||
public: |
||||
ConfigurableTest() { config_options_.invoke_prepare_options = false; } |
||||
|
||||
ConfigOptions config_options_; |
||||
}; |
||||
|
||||
class ConfigurableParamTest |
||||
: public ConfigurableTest, |
||||
virtual public ::testing::WithParamInterface< |
||||
std::pair<std::string, ConfigTestFactoryFunc>> { |
||||
public: |
||||
ConfigurableParamTest() { |
||||
configuration_ = GetParam().first; |
||||
factory_ = GetParam().second; |
||||
object_.reset(factory_()); |
||||
} |
||||
void TestConfigureOptions(const ConfigOptions& opts); |
||||
ConfigTestFactoryFunc factory_; |
||||
std::string configuration_; |
||||
std::unique_ptr<Configurable> object_; |
||||
}; |
||||
|
||||
TEST_F(ConfigurableTest, GetOptionsPtrTest) { |
||||
std::string opt_str; |
||||
std::unique_ptr<Configurable> configurable(SimpleConfigurable::Create()); |
||||
ASSERT_NE(configurable->GetOptions<TestOptions>("simple"), nullptr); |
||||
ASSERT_EQ(configurable->GetOptions<TestOptions>("bad-opt"), nullptr); |
||||
} |
||||
|
||||
TEST_F(ConfigurableTest, ConfigureFromMapTest) { |
||||
std::unique_ptr<Configurable> configurable(SimpleConfigurable::Create()); |
||||
auto* opts = configurable->GetOptions<TestOptions>("simple"); |
||||
ASSERT_OK(configurable->ConfigureFromMap(config_options_, {})); |
||||
ASSERT_NE(opts, nullptr); |
||||
#ifndef ROCKSDB_LITE |
||||
std::unordered_map<std::string, std::string> options_map = { |
||||
{"int", "1"}, {"bool", "true"}, {"string", "string"}}; |
||||
ASSERT_OK(configurable->ConfigureFromMap(config_options_, options_map)); |
||||
ASSERT_EQ(opts->i, 1); |
||||
ASSERT_EQ(opts->b, true); |
||||
ASSERT_EQ(opts->s, "string"); |
||||
#endif |
||||
} |
||||
|
||||
TEST_F(ConfigurableTest, ConfigureFromStringTest) { |
||||
std::unique_ptr<Configurable> configurable(SimpleConfigurable::Create()); |
||||
auto* opts = configurable->GetOptions<TestOptions>("simple"); |
||||
ASSERT_OK(configurable->ConfigureFromString(config_options_, "")); |
||||
ASSERT_NE(opts, nullptr); |
||||
#ifndef ROCKSDB_LITE // GetOptionsFromMap is not supported in ROCKSDB_LITE
|
||||
ASSERT_OK(configurable->ConfigureFromString(config_options_, |
||||
"int=1;bool=true;string=s")); |
||||
ASSERT_EQ(opts->i, 1); |
||||
ASSERT_EQ(opts->b, true); |
||||
ASSERT_EQ(opts->s, "s"); |
||||
#endif |
||||
} |
||||
|
||||
#ifndef ROCKSDB_LITE // GetOptionsFromMap is not supported in ROCKSDB_LITE
|
||||
TEST_F(ConfigurableTest, ConfigureIgnoreTest) { |
||||
std::unique_ptr<Configurable> configurable(SimpleConfigurable::Create()); |
||||
std::unordered_map<std::string, std::string> options_map = {{"unused", "u"}}; |
||||
ConfigOptions ignore = config_options_; |
||||
ignore.ignore_unknown_options = true; |
||||
ASSERT_NOK(configurable->ConfigureFromMap(config_options_, options_map)); |
||||
ASSERT_OK(configurable->ConfigureFromMap(ignore, options_map)); |
||||
ASSERT_NOK(configurable->ConfigureFromString(config_options_, "unused=u")); |
||||
ASSERT_OK(configurable->ConfigureFromString(ignore, "unused=u")); |
||||
} |
||||
|
||||
TEST_F(ConfigurableTest, ConfigureNestedOptionsTest) { |
||||
std::unique_ptr<Configurable> base, copy; |
||||
std::string opt_str; |
||||
std::string mismatch; |
||||
|
||||
base.reset(SimpleConfigurable::Create("simple", TestConfigMode::kAllOptMode)); |
||||
copy.reset(SimpleConfigurable::Create("simple", TestConfigMode::kAllOptMode)); |
||||
ASSERT_OK(base->ConfigureFromString(config_options_, |
||||
"shared={int=10; string=10};" |
||||
"unique={int=20; string=20};" |
||||
"pointer={int=30; string=30};")); |
||||
ASSERT_OK(base->GetOptionString(config_options_, &opt_str)); |
||||
ASSERT_OK(copy->ConfigureFromString(config_options_, opt_str)); |
||||
ASSERT_TRUE(base->AreEquivalent(config_options_, copy.get(), &mismatch)); |
||||
} |
||||
|
||||
TEST_F(ConfigurableTest, GetOptionsTest) { |
||||
std::unique_ptr<Configurable> simple; |
||||
|
||||
simple.reset( |
||||
SimpleConfigurable::Create("simple", TestConfigMode::kAllOptMode)); |
||||
int i = 11; |
||||
for (auto opt : {"", "shared.", "unique.", "pointer."}) { |
||||
std::string value; |
||||
std::string expected = ToString(i); |
||||
std::string opt_name = opt; |
||||
ASSERT_OK( |
||||
simple->ConfigureOption(config_options_, opt_name + "int", expected)); |
||||
ASSERT_OK(simple->GetOption(config_options_, opt_name + "int", &value)); |
||||
ASSERT_EQ(expected, value); |
||||
ASSERT_OK(simple->ConfigureOption(config_options_, opt_name + "string", |
||||
expected)); |
||||
ASSERT_OK(simple->GetOption(config_options_, opt_name + "string", &value)); |
||||
ASSERT_EQ(expected, value); |
||||
|
||||
ASSERT_NOK( |
||||
simple->ConfigureOption(config_options_, opt_name + "bad", expected)); |
||||
ASSERT_NOK(simple->GetOption(config_options_, "bad option", &value)); |
||||
ASSERT_TRUE(value.empty()); |
||||
i += 11; |
||||
} |
||||
} |
||||
|
||||
TEST_F(ConfigurableTest, ConfigureBadOptionsTest) { |
||||
std::unique_ptr<Configurable> configurable(SimpleConfigurable::Create()); |
||||
auto* opts = configurable->GetOptions<TestOptions>("simple"); |
||||
ASSERT_NE(opts, nullptr); |
||||
ASSERT_OK(configurable->ConfigureOption(config_options_, "int", "42")); |
||||
ASSERT_EQ(opts->i, 42); |
||||
ASSERT_NOK(configurable->ConfigureOption(config_options_, "int", "fred")); |
||||
ASSERT_NOK(configurable->ConfigureOption(config_options_, "bool", "fred")); |
||||
ASSERT_NOK( |
||||
configurable->ConfigureFromString(config_options_, "int=33;unused=u")); |
||||
ASSERT_EQ(opts->i, 42); |
||||
} |
||||
|
||||
TEST_F(ConfigurableTest, InvalidOptionTest) { |
||||
std::unique_ptr<Configurable> configurable(SimpleConfigurable::Create()); |
||||
std::unordered_map<std::string, std::string> options_map = { |
||||
{"bad-option", "bad"}}; |
||||
ASSERT_NOK(configurable->ConfigureFromMap(config_options_, options_map)); |
||||
ASSERT_NOK( |
||||
configurable->ConfigureFromString(config_options_, "bad-option=bad")); |
||||
ASSERT_NOK( |
||||
configurable->ConfigureOption(config_options_, "bad-option", "bad")); |
||||
} |
||||
|
||||
static std::unordered_map<std::string, OptionTypeInfo> validated_option_info = { |
||||
#ifndef ROCKSDB_LITE |
||||
{"validated", |
||||
{0, OptionType::kBoolean, OptionVerificationType::kNormal, |
||||
OptionTypeFlags::kNone}}, |
||||
#endif // ROCKSDB_LITE
|
||||
}; |
||||
static std::unordered_map<std::string, OptionTypeInfo> prepared_option_info = { |
||||
#ifndef ROCKSDB_LITE |
||||
{"prepared", |
||||
{0, OptionType::kInt, OptionVerificationType::kNormal, |
||||
OptionTypeFlags::kMutable}}, |
||||
#endif // ROCKSDB_LITE
|
||||
}; |
||||
static std::unordered_map<std::string, OptionTypeInfo> |
||||
dont_prepare_option_info = { |
||||
#ifndef ROCKSDB_LITE |
||||
{"unique", |
||||
{0, OptionType::kConfigurable, OptionVerificationType::kNormal, |
||||
(OptionTypeFlags::kUnique | OptionTypeFlags::kDontPrepare)}}, |
||||
|
||||
#endif // ROCKSDB_LITE
|
||||
}; |
||||
|
||||
class ValidatedConfigurable : public SimpleConfigurable { |
||||
public: |
||||
ValidatedConfigurable(const std::string& name, unsigned char mode, |
||||
bool dont_prepare = false) |
||||
: SimpleConfigurable(name, TestConfigMode::kDefaultMode), |
||||
validated(false), |
||||
prepared(0) { |
||||
ConfigurableHelper::RegisterOptions(*this, "Validated", &validated, |
||||
&validated_option_info); |
||||
ConfigurableHelper::RegisterOptions(*this, "Prepared", &prepared, |
||||
&prepared_option_info); |
||||
if ((mode & TestConfigMode::kUniqueMode) != 0) { |
||||
unique_.reset(new ValidatedConfigurable( |
||||
"Unique" + name_, TestConfigMode::kDefaultMode, false)); |
||||
if (dont_prepare) { |
||||
ConfigurableHelper::RegisterOptions(*this, name_ + "Unique", &unique_, |
||||
&dont_prepare_option_info); |
||||
} else { |
||||
ConfigurableHelper::RegisterOptions(*this, name_ + "Unique", &unique_, |
||||
&unique_option_info); |
||||
} |
||||
} |
||||
} |
||||
|
||||
Status PrepareOptions(const ConfigOptions& config_options) override { |
||||
if (++prepared <= 0) { |
||||
return Status::InvalidArgument("Cannot prepare option"); |
||||
} else { |
||||
return SimpleConfigurable::PrepareOptions(config_options); |
||||
} |
||||
} |
||||
|
||||
Status ValidateOptions(const DBOptions& db_opts, |
||||
const ColumnFamilyOptions& cf_opts) const override { |
||||
if (!validated) { |
||||
return Status::InvalidArgument("Not Validated"); |
||||
} else { |
||||
return SimpleConfigurable::ValidateOptions(db_opts, cf_opts); |
||||
} |
||||
} |
||||
|
||||
private: |
||||
bool validated; |
||||
int prepared; |
||||
}; |
||||
|
||||
TEST_F(ConfigurableTest, ValidateOptionsTest) { |
||||
std::unique_ptr<Configurable> configurable( |
||||
new ValidatedConfigurable("validated", TestConfigMode::kDefaultMode)); |
||||
ColumnFamilyOptions cf_opts; |
||||
DBOptions db_opts; |
||||
ASSERT_OK( |
||||
configurable->ConfigureOption(config_options_, "validated", "false")); |
||||
ASSERT_NOK(configurable->ValidateOptions(db_opts, cf_opts)); |
||||
ASSERT_OK( |
||||
configurable->ConfigureOption(config_options_, "validated", "true")); |
||||
ASSERT_OK(configurable->ValidateOptions(db_opts, cf_opts)); |
||||
} |
||||
|
||||
TEST_F(ConfigurableTest, PrepareOptionsTest) { |
||||
std::unique_ptr<Configurable> c( |
||||
new ValidatedConfigurable("Simple", TestConfigMode::kUniqueMode, false)); |
||||
auto cp = c->GetOptions<int>("Prepared"); |
||||
auto u = c->GetOptions<std::unique_ptr<Configurable>>("SimpleUnique"); |
||||
auto up = u->get()->GetOptions<int>("Prepared"); |
||||
config_options_.invoke_prepare_options = false; |
||||
|
||||
ASSERT_NE(cp, nullptr); |
||||
ASSERT_NE(up, nullptr); |
||||
ASSERT_EQ(*cp, 0); |
||||
ASSERT_EQ(*up, 0); |
||||
ASSERT_OK(c->ConfigureFromMap(config_options_, {})); |
||||
ASSERT_EQ(*cp, 0); |
||||
ASSERT_EQ(*up, 0); |
||||
config_options_.invoke_prepare_options = true; |
||||
ASSERT_OK(c->ConfigureFromMap(config_options_, {})); |
||||
ASSERT_EQ(*cp, 1); |
||||
ASSERT_EQ(*up, 1); |
||||
ASSERT_OK(c->ConfigureFromString(config_options_, "prepared=0")); |
||||
ASSERT_EQ(*up, 2); |
||||
ASSERT_EQ(*cp, 1); |
||||
|
||||
ASSERT_NOK(c->ConfigureFromString(config_options_, "prepared=-2")); |
||||
|
||||
c.reset( |
||||
new ValidatedConfigurable("Simple", TestConfigMode::kUniqueMode, true)); |
||||
cp = c->GetOptions<int>("Prepared"); |
||||
u = c->GetOptions<std::unique_ptr<Configurable>>("SimpleUnique"); |
||||
up = u->get()->GetOptions<int>("Prepared"); |
||||
|
||||
ASSERT_OK(c->ConfigureFromString(config_options_, "prepared=0")); |
||||
ASSERT_EQ(*cp, 1); |
||||
ASSERT_EQ(*up, 0); |
||||
} |
||||
|
||||
TEST_F(ConfigurableTest, DeprecatedOptionsTest) { |
||||
static std::unordered_map<std::string, OptionTypeInfo> |
||||
deprecated_option_info = { |
||||
{"deprecated", |
||||
{offsetof(struct TestOptions, b), OptionType::kBoolean, |
||||
OptionVerificationType::kDeprecated, OptionTypeFlags::kNone}}}; |
||||
std::unique_ptr<Configurable> orig; |
||||
orig.reset(SimpleConfigurable::Create("simple", TestConfigMode::kDefaultMode, |
||||
&deprecated_option_info)); |
||||
auto* opts = orig->GetOptions<TestOptions>("simple"); |
||||
ASSERT_NE(opts, nullptr); |
||||
opts->d = true; |
||||
ASSERT_OK(orig->ConfigureOption(config_options_, "deprecated", "false")); |
||||
ASSERT_TRUE(opts->d); |
||||
ASSERT_OK(orig->ConfigureFromString(config_options_, "deprecated=false")); |
||||
ASSERT_TRUE(opts->d); |
||||
} |
||||
|
||||
TEST_F(ConfigurableTest, AliasOptionsTest) { |
||||
static std::unordered_map<std::string, OptionTypeInfo> alias_option_info = { |
||||
{"bool", |
||||
{offsetof(struct TestOptions, b), OptionType::kBoolean, |
||||
OptionVerificationType::kNormal, OptionTypeFlags::kNone}}, |
||||
{"alias", |
||||
{offsetof(struct TestOptions, b), OptionType::kBoolean, |
||||
OptionVerificationType::kAlias, OptionTypeFlags::kNone, 0}}}; |
||||
std::unique_ptr<Configurable> orig; |
||||
orig.reset(SimpleConfigurable::Create("simple", TestConfigMode::kDefaultMode, |
||||
&alias_option_info)); |
||||
auto* opts = orig->GetOptions<TestOptions>("simple"); |
||||
ASSERT_NE(opts, nullptr); |
||||
ASSERT_OK(orig->ConfigureOption(config_options_, "bool", "false")); |
||||
ASSERT_FALSE(opts->b); |
||||
ASSERT_OK(orig->ConfigureOption(config_options_, "alias", "true")); |
||||
ASSERT_TRUE(opts->b); |
||||
std::string opts_str; |
||||
ASSERT_OK(orig->GetOptionString(config_options_, &opts_str)); |
||||
ASSERT_EQ(opts_str.find("alias"), std::string::npos); |
||||
|
||||
ASSERT_OK(orig->ConfigureOption(config_options_, "bool", "false")); |
||||
ASSERT_FALSE(opts->b); |
||||
ASSERT_OK(orig->GetOption(config_options_, "alias", &opts_str)); |
||||
ASSERT_EQ(opts_str, "false"); |
||||
} |
||||
|
||||
TEST_F(ConfigurableTest, NestedUniqueConfigTest) { |
||||
std::unique_ptr<Configurable> simple; |
||||
simple.reset( |
||||
SimpleConfigurable::Create("Outer", TestConfigMode::kAllOptMode)); |
||||
const auto outer = simple->GetOptions<TestOptions>("Outer"); |
||||
const auto unique = |
||||
simple->GetOptions<std::unique_ptr<Configurable>>("OuterUnique"); |
||||
ASSERT_NE(outer, nullptr); |
||||
ASSERT_NE(unique, nullptr); |
||||
ASSERT_OK( |
||||
simple->ConfigureFromString(config_options_, "int=24;string=outer")); |
||||
ASSERT_OK(simple->ConfigureFromString(config_options_, |
||||
"unique={int=42;string=nested}")); |
||||
const auto inner = unique->get()->GetOptions<TestOptions>("UniqueOuter"); |
||||
ASSERT_NE(inner, nullptr); |
||||
ASSERT_EQ(outer->i, 24); |
||||
ASSERT_EQ(outer->s, "outer"); |
||||
ASSERT_EQ(inner->i, 42); |
||||
ASSERT_EQ(inner->s, "nested"); |
||||
} |
||||
|
||||
TEST_F(ConfigurableTest, NestedSharedConfigTest) { |
||||
std::unique_ptr<Configurable> simple; |
||||
simple.reset(SimpleConfigurable::Create( |
||||
"Outer", TestConfigMode::kDefaultMode | TestConfigMode::kSharedMode)); |
||||
ASSERT_OK( |
||||
simple->ConfigureFromString(config_options_, "int=24;string=outer")); |
||||
ASSERT_OK(simple->ConfigureFromString(config_options_, |
||||
"shared={int=42;string=nested}")); |
||||
const auto outer = simple->GetOptions<TestOptions>("Outer"); |
||||
const auto shared = |
||||
simple->GetOptions<std::shared_ptr<Configurable>>("OuterShared"); |
||||
ASSERT_NE(outer, nullptr); |
||||
ASSERT_NE(shared, nullptr); |
||||
const auto inner = shared->get()->GetOptions<TestOptions>("SharedOuter"); |
||||
ASSERT_NE(inner, nullptr); |
||||
ASSERT_EQ(outer->i, 24); |
||||
ASSERT_EQ(outer->s, "outer"); |
||||
ASSERT_EQ(inner->i, 42); |
||||
ASSERT_EQ(inner->s, "nested"); |
||||
} |
||||
|
||||
TEST_F(ConfigurableTest, NestedRawConfigTest) { |
||||
std::unique_ptr<Configurable> simple; |
||||
simple.reset(SimpleConfigurable::Create( |
||||
"Outer", TestConfigMode::kDefaultMode | TestConfigMode::kRawPtrMode)); |
||||
ASSERT_OK( |
||||
simple->ConfigureFromString(config_options_, "int=24;string=outer")); |
||||
ASSERT_OK(simple->ConfigureFromString(config_options_, |
||||
"pointer={int=42;string=nested}")); |
||||
const auto outer = simple->GetOptions<TestOptions>("Outer"); |
||||
const auto pointer = simple->GetOptions<Configurable*>("OuterPointer"); |
||||
ASSERT_NE(outer, nullptr); |
||||
ASSERT_NE(pointer, nullptr); |
||||
const auto inner = (*pointer)->GetOptions<TestOptions>("PointerOuter"); |
||||
ASSERT_NE(inner, nullptr); |
||||
ASSERT_EQ(outer->i, 24); |
||||
ASSERT_EQ(outer->s, "outer"); |
||||
ASSERT_EQ(inner->i, 42); |
||||
ASSERT_EQ(inner->s, "nested"); |
||||
} |
||||
|
||||
TEST_F(ConfigurableTest, MatchesTest) { |
||||
std::string mismatch; |
||||
std::unique_ptr<Configurable> base, copy; |
||||
base.reset(SimpleConfigurable::Create( |
||||
"simple", TestConfigMode::kDefaultMode | TestConfigMode::kNestedMode)); |
||||
copy.reset(SimpleConfigurable::Create( |
||||
"simple", TestConfigMode::kDefaultMode | TestConfigMode::kNestedMode)); |
||||
ASSERT_OK(base->ConfigureFromString( |
||||
config_options_, |
||||
"int=11;string=outer;unique={int=22;string=u};shared={int=33;string=s}")); |
||||
ASSERT_OK(copy->ConfigureFromString( |
||||
config_options_, |
||||
"int=11;string=outer;unique={int=22;string=u};shared={int=33;string=s}")); |
||||
ASSERT_TRUE(base->AreEquivalent(config_options_, copy.get(), &mismatch)); |
||||
ASSERT_OK(base->ConfigureOption(config_options_, "shared", "int=44")); |
||||
ASSERT_FALSE(base->AreEquivalent(config_options_, copy.get(), &mismatch)); |
||||
ASSERT_EQ(mismatch, "shared.int"); |
||||
std::string c1value, c2value; |
||||
ASSERT_OK(base->GetOption(config_options_, mismatch, &c1value)); |
||||
ASSERT_OK(copy->GetOption(config_options_, mismatch, &c2value)); |
||||
ASSERT_NE(c1value, c2value); |
||||
} |
||||
|
||||
static Configurable* SimpleStructFactory() { |
||||
static std::unordered_map<std::string, OptionTypeInfo> struct_option_info = { |
||||
#ifndef ROCKSDB_LITE |
||||
{"struct", OptionTypeInfo::Struct("struct", &simple_option_info, 0, |
||||
OptionVerificationType::kNormal, |
||||
OptionTypeFlags::kMutable)}, |
||||
#endif // ROCKSDB_LITE
|
||||
}; |
||||
return SimpleConfigurable::Create( |
||||
"simple-struct", TestConfigMode::kDefaultMode, &struct_option_info); |
||||
} |
||||
|
||||
TEST_F(ConfigurableTest, ConfigureStructTest) { |
||||
std::unique_ptr<Configurable> base(SimpleStructFactory()); |
||||
std::unique_ptr<Configurable> copy(SimpleStructFactory()); |
||||
std::string opt_str, value; |
||||
std::string mismatch; |
||||
std::unordered_set<std::string> names; |
||||
|
||||
ASSERT_OK( |
||||
base->ConfigureFromString(config_options_, "struct={int=10; string=10}")); |
||||
ASSERT_OK(base->GetOptionString(config_options_, &opt_str)); |
||||
ASSERT_OK(copy->ConfigureFromString(config_options_, opt_str)); |
||||
ASSERT_TRUE(base->AreEquivalent(config_options_, copy.get(), &mismatch)); |
||||
ASSERT_OK(base->GetOptionNames(config_options_, &names)); |
||||
ASSERT_EQ(names.size(), 1); |
||||
ASSERT_EQ(*(names.begin()), "struct"); |
||||
ASSERT_OK( |
||||
base->ConfigureFromString(config_options_, "struct={int=20; string=20}")); |
||||
ASSERT_OK(base->GetOption(config_options_, "struct", &value)); |
||||
ASSERT_OK(copy->ConfigureOption(config_options_, "struct", value)); |
||||
ASSERT_TRUE(base->AreEquivalent(config_options_, copy.get(), &mismatch)); |
||||
|
||||
ASSERT_NOK(base->ConfigureFromString(config_options_, |
||||
"struct={int=10; string=10; bad=11}")); |
||||
ASSERT_OK(base->ConfigureOption(config_options_, "struct.int", "42")); |
||||
ASSERT_NOK(base->ConfigureOption(config_options_, "struct.bad", "42")); |
||||
ASSERT_NOK(base->GetOption(config_options_, "struct.bad", &value)); |
||||
ASSERT_OK(base->GetOption(config_options_, "struct.int", &value)); |
||||
ASSERT_EQ(value, "42"); |
||||
} |
||||
|
||||
TEST_F(ConfigurableTest, ConfigurableEnumTest) { |
||||
std::unique_ptr<Configurable> base, copy; |
||||
base.reset(SimpleConfigurable::Create("e", TestConfigMode::kEnumMode)); |
||||
copy.reset(SimpleConfigurable::Create("e", TestConfigMode::kEnumMode)); |
||||
|
||||
std::string opts_str; |
||||
std::string mismatch; |
||||
|
||||
ASSERT_OK(base->ConfigureFromString(config_options_, "enum=B")); |
||||
ASSERT_FALSE(base->AreEquivalent(config_options_, copy.get(), &mismatch)); |
||||
ASSERT_OK(base->GetOptionString(config_options_, &opts_str)); |
||||
ASSERT_OK(copy->ConfigureFromString(config_options_, opts_str)); |
||||
ASSERT_TRUE(base->AreEquivalent(config_options_, copy.get(), &mismatch)); |
||||
ASSERT_NOK(base->ConfigureOption(config_options_, "enum", "bad")); |
||||
ASSERT_NOK(base->ConfigureOption(config_options_, "unknown", "bad")); |
||||
} |
||||
|
||||
#ifndef ROCKSDB_LITE |
||||
static std::unordered_map<std::string, OptionTypeInfo> noserialize_option_info = |
||||
{ |
||||
{"int", |
||||
{offsetof(struct TestOptions, i), OptionType::kInt, |
||||
OptionVerificationType::kNormal, OptionTypeFlags::kDontSerialize}}, |
||||
}; |
||||
|
||||
TEST_F(ConfigurableTest, TestNoSerialize) { |
||||
std::unique_ptr<Configurable> base; |
||||
base.reset(SimpleConfigurable::Create("c", TestConfigMode::kDefaultMode, |
||||
&noserialize_option_info)); |
||||
std::string opts_str, value; |
||||
ASSERT_OK(base->ConfigureFromString(config_options_, "int=10")); |
||||
ASSERT_OK(base->GetOptionString(config_options_, &opts_str)); |
||||
ASSERT_EQ(opts_str, ""); |
||||
ASSERT_NOK(base->GetOption(config_options_, "int", &value)); |
||||
} |
||||
|
||||
TEST_F(ConfigurableTest, TestNoCompare) { |
||||
std::unordered_map<std::string, OptionTypeInfo> nocomp_option_info = { |
||||
{"int", |
||||
{offsetof(struct TestOptions, i), OptionType::kInt, |
||||
OptionVerificationType::kNormal, OptionTypeFlags::kCompareNever}}, |
||||
}; |
||||
std::unordered_map<std::string, OptionTypeInfo> normal_option_info = { |
||||
{"int", |
||||
{offsetof(struct TestOptions, i), OptionType::kInt, |
||||
OptionVerificationType::kNormal, OptionTypeFlags::kNone}}, |
||||
}; |
||||
|
||||
std::unique_ptr<Configurable> base, copy; |
||||
base.reset(SimpleConfigurable::Create("c", TestConfigMode::kDefaultMode, |
||||
&nocomp_option_info)); |
||||
copy.reset(SimpleConfigurable::Create("c", TestConfigMode::kDefaultMode, |
||||
&normal_option_info)); |
||||
ASSERT_OK(base->ConfigureFromString(config_options_, "int=10")); |
||||
ASSERT_OK(copy->ConfigureFromString(config_options_, "int=20")); |
||||
std::string bvalue, cvalue, mismatch; |
||||
ASSERT_OK(base->GetOption(config_options_, "int", &bvalue)); |
||||
ASSERT_OK(copy->GetOption(config_options_, "int", &cvalue)); |
||||
ASSERT_EQ(bvalue, "10"); |
||||
ASSERT_EQ(cvalue, "20"); |
||||
ASSERT_TRUE(base->AreEquivalent(config_options_, copy.get(), &mismatch)); |
||||
ASSERT_FALSE(copy->AreEquivalent(config_options_, base.get(), &mismatch)); |
||||
} |
||||
#endif |
||||
|
||||
void ConfigurableParamTest::TestConfigureOptions( |
||||
const ConfigOptions& config_options) { |
||||
std::unique_ptr<Configurable> base, copy; |
||||
std::unordered_set<std::string> names; |
||||
std::string opt_str, mismatch; |
||||
|
||||
base.reset(factory_()); |
||||
copy.reset(factory_()); |
||||
|
||||
ASSERT_OK(base->ConfigureFromString(config_options, configuration_)); |
||||
ASSERT_OK(base->GetOptionString(config_options, &opt_str)); |
||||
ASSERT_OK(copy->ConfigureFromString(config_options, opt_str)); |
||||
ASSERT_OK(copy->GetOptionString(config_options, &opt_str)); |
||||
ASSERT_TRUE(base->AreEquivalent(config_options, copy.get(), &mismatch)); |
||||
|
||||
copy.reset(factory_()); |
||||
ASSERT_OK(base->GetOptionNames(config_options, &names)); |
||||
std::unordered_map<std::string, std::string> unused; |
||||
bool found_one = false; |
||||
for (auto name : names) { |
||||
std::string value; |
||||
Status s = base->GetOption(config_options, name, &value); |
||||
if (s.ok()) { |
||||
s = copy->ConfigureOption(config_options, name, value); |
||||
if (s.ok() || s.IsNotSupported()) { |
||||
found_one = true; |
||||
} else { |
||||
unused[name] = value; |
||||
} |
||||
} else { |
||||
ASSERT_TRUE(s.IsNotSupported()); |
||||
} |
||||
} |
||||
ASSERT_TRUE(found_one || names.empty()); |
||||
while (found_one && !unused.empty()) { |
||||
found_one = false; |
||||
for (auto iter = unused.begin(); iter != unused.end();) { |
||||
if (copy->ConfigureOption(config_options, iter->first, iter->second) |
||||
.ok()) { |
||||
found_one = true; |
||||
iter = unused.erase(iter); |
||||
} else { |
||||
++iter; |
||||
} |
||||
} |
||||
} |
||||
ASSERT_EQ(0, unused.size()); |
||||
ASSERT_TRUE(base->AreEquivalent(config_options, copy.get(), &mismatch)); |
||||
} |
||||
|
||||
TEST_P(ConfigurableParamTest, GetDefaultOptionsTest) { |
||||
TestConfigureOptions(config_options_); |
||||
} |
||||
|
||||
TEST_P(ConfigurableParamTest, ConfigureFromPropsTest) { |
||||
std::string opt_str, mismatch; |
||||
std::unordered_set<std::string> names; |
||||
std::unique_ptr<Configurable> copy(factory_()); |
||||
|
||||
ASSERT_OK(object_->ConfigureFromString(config_options_, configuration_)); |
||||
config_options_.delimiter = "\n"; |
||||
ASSERT_OK(object_->GetOptionString(config_options_, &opt_str)); |
||||
std::istringstream iss(opt_str); |
||||
std::unordered_map<std::string, std::string> copy_map; |
||||
std::string line; |
||||
for (int line_num = 0; std::getline(iss, line); line_num++) { |
||||
std::string name; |
||||
std::string value; |
||||
ASSERT_OK( |
||||
RocksDBOptionsParser::ParseStatement(&name, &value, line, line_num)); |
||||
copy_map[name] = value; |
||||
} |
||||
ASSERT_OK(copy->ConfigureFromMap(config_options_, copy_map)); |
||||
ASSERT_TRUE(object_->AreEquivalent(config_options_, copy.get(), &mismatch)); |
||||
} |
||||
|
||||
static Configurable* SimpleFactory() { |
||||
return SimpleConfigurable::Create("simple"); |
||||
} |
||||
|
||||
static Configurable* UniqueFactory() { |
||||
return SimpleConfigurable::Create( |
||||
"simple", TestConfigMode::kSimpleMode | TestConfigMode::kUniqueMode); |
||||
} |
||||
static Configurable* SharedFactory() { |
||||
return SimpleConfigurable::Create( |
||||
"simple", TestConfigMode::kSimpleMode | TestConfigMode::kSharedMode); |
||||
} |
||||
|
||||
static Configurable* NestedFactory() { |
||||
return SimpleConfigurable::Create( |
||||
"simple", TestConfigMode::kSimpleMode | TestConfigMode::kNestedMode); |
||||
} |
||||
|
||||
static Configurable* MutableFactory() { |
||||
return SimpleConfigurable::Create("simple", TestConfigMode::kMutableMode | |
||||
TestConfigMode::kSimpleMode | |
||||
TestConfigMode::kNestedMode); |
||||
} |
||||
|
||||
static Configurable* ThreeWrappedFactory() { |
||||
std::shared_ptr<Configurable> child; |
||||
child.reset( |
||||
SimpleConfigurable::Create("child", TestConfigMode::kDefaultMode)); |
||||
std::shared_ptr<Configurable> parent; |
||||
parent.reset( |
||||
new WrappedConfigurable("parent", TestConfigMode::kDefaultMode, child)); |
||||
return new WrappedConfigurable("master", TestConfigMode::kDefaultMode, |
||||
parent); |
||||
} |
||||
|
||||
static Configurable* ThreeDeepFactory() { |
||||
Configurable* simple = SimpleConfigurable::Create( |
||||
"Simple", TestConfigMode::kUniqueMode | TestConfigMode::kDefaultMode); |
||||
auto* unique = |
||||
simple->GetOptions<std::unique_ptr<Configurable>>("SimpleUnique"); |
||||
unique->reset(SimpleConfigurable::Create( |
||||
"Child", TestConfigMode::kUniqueMode | TestConfigMode::kDefaultMode)); |
||||
unique = |
||||
unique->get()->GetOptions<std::unique_ptr<Configurable>>("ChildUnique"); |
||||
unique->reset( |
||||
SimpleConfigurable::Create("Child", TestConfigMode::kDefaultMode)); |
||||
return simple; |
||||
} |
||||
|
||||
static Configurable* DBOptionsFactory() { |
||||
auto config = DBOptionsAsConfigurable(DBOptions()); |
||||
return config.release(); |
||||
} |
||||
|
||||
static Configurable* CFOptionsFactory() { |
||||
auto config = CFOptionsAsConfigurable(ColumnFamilyOptions()); |
||||
return config.release(); |
||||
} |
||||
|
||||
static Configurable* BlockBasedFactory() { return NewBlockBasedTableFactory(); } |
||||
|
||||
INSTANTIATE_TEST_CASE_P( |
||||
ParamTest, ConfigurableParamTest, |
||||
testing::Values( |
||||
std::pair<std::string, ConfigTestFactoryFunc>( |
||||
"int=42;bool=true;string=s", SimpleFactory), |
||||
std::pair<std::string, ConfigTestFactoryFunc>( |
||||
"int=42;unique={int=33;string=unique}", MutableFactory), |
||||
std::pair<std::string, ConfigTestFactoryFunc>( |
||||
"struct={int=33;bool=true;string=s;}", SimpleStructFactory), |
||||
std::pair<std::string, ConfigTestFactoryFunc>( |
||||
"int=33;bool=true;string=outer;" |
||||
"shared={int=42;string=shared}", |
||||
SharedFactory), |
||||
std::pair<std::string, ConfigTestFactoryFunc>( |
||||
"int=33;bool=true;string=outer;" |
||||
"unique={int=42;string=unique}", |
||||
UniqueFactory), |
||||
std::pair<std::string, ConfigTestFactoryFunc>( |
||||
"int=11;bool=true;string=outer;" |
||||
"pointer={int=22;string=pointer};" |
||||
"unique={int=33;string=unique};" |
||||
"shared={int=44;string=shared}", |
||||
NestedFactory), |
||||
std::pair<std::string, ConfigTestFactoryFunc>( |
||||
"int=11;bool=true;string=outer;" |
||||
"inner={int=22;string=parent;" |
||||
"inner={int=33;string=child}};", |
||||
ThreeWrappedFactory), |
||||
std::pair<std::string, ConfigTestFactoryFunc>( |
||||
"int=11;bool=true;string=outer;" |
||||
"unique={int=22;string=inner;" |
||||
"unique={int=33;string=unique}};", |
||||
ThreeDeepFactory), |
||||
std::pair<std::string, ConfigTestFactoryFunc>("max_background_jobs=100;" |
||||
"max_open_files=200;", |
||||
DBOptionsFactory), |
||||
std::pair<std::string, ConfigTestFactoryFunc>( |
||||
"table_factory=BlockBasedTable;" |
||||
"disable_auto_compactions=true;", |
||||
CFOptionsFactory), |
||||
std::pair<std::string, ConfigTestFactoryFunc>("block_size=1024;" |
||||
"no_block_cache=true;", |
||||
BlockBasedFactory))); |
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
} // namespace test
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
int main(int argc, char** argv) { |
||||
::testing::InitGoogleTest(&argc, argv); |
||||
#ifdef GFLAGS |
||||
ParseCommandLineFlags(&argc, &argv, true); |
||||
#endif // GFLAGS
|
||||
return RUN_ALL_TESTS(); |
||||
} |
@ -0,0 +1,127 @@ |
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
//
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#pragma once |
||||
#include <algorithm> |
||||
#include <memory> |
||||
#include <unordered_map> |
||||
|
||||
#include "options/configurable_helper.h" |
||||
#include "rocksdb/configurable.h" |
||||
#include "rocksdb/utilities/options_type.h" |
||||
|
||||
namespace ROCKSDB_NAMESPACE { |
||||
struct ColumnFamilyOptions; |
||||
struct DBOptions; |
||||
|
||||
namespace test { |
||||
enum TestEnum { kTestA, kTestB }; |
||||
|
||||
static const std::unordered_map<std::string, int> test_enum_map = { |
||||
{"A", TestEnum::kTestA}, |
||||
{"B", TestEnum::kTestB}, |
||||
}; |
||||
|
||||
struct TestOptions { |
||||
int i = 0; |
||||
bool b = false; |
||||
bool d = true; |
||||
TestEnum e = TestEnum::kTestA; |
||||
std::string s = ""; |
||||
std::string u = ""; |
||||
}; |
||||
|
||||
static std::unordered_map<std::string, OptionTypeInfo> simple_option_info = { |
||||
#ifndef ROCKSDB_LITE |
||||
{"int", |
||||
{offsetof(struct TestOptions, i), OptionType::kInt, |
||||
OptionVerificationType::kNormal, OptionTypeFlags::kMutable}}, |
||||
{"bool", |
||||
{offsetof(struct TestOptions, b), OptionType::kBoolean, |
||||
OptionVerificationType::kNormal, OptionTypeFlags::kNone}}, |
||||
{"string", |
||||
{offsetof(struct TestOptions, s), OptionType::kString, |
||||
OptionVerificationType::kNormal, OptionTypeFlags::kNone}}, |
||||
#endif // ROCKSDB_LITE
|
||||
}; |
||||
|
||||
static std::unordered_map<std::string, OptionTypeInfo> enum_option_info = { |
||||
#ifndef ROCKSDB_LITE |
||||
{"enum", |
||||
OptionTypeInfo::Enum(offsetof(struct TestOptions, e), &test_enum_map)} |
||||
#endif |
||||
}; |
||||
|
||||
static std::unordered_map<std::string, OptionTypeInfo> unique_option_info = { |
||||
#ifndef ROCKSDB_LITE |
||||
{"unique", |
||||
{0, OptionType::kConfigurable, OptionVerificationType::kNormal, |
||||
(OptionTypeFlags::kUnique | OptionTypeFlags::kMutable)}}, |
||||
#endif // ROCKSDB_LITE
|
||||
}; |
||||
|
||||
static std::unordered_map<std::string, OptionTypeInfo> shared_option_info = { |
||||
#ifndef ROCKSDB_LITE |
||||
{"shared", |
||||
{0, OptionType::kConfigurable, OptionVerificationType::kNormal, |
||||
(OptionTypeFlags::kShared)}}, |
||||
#endif // ROCKSDB_LITE
|
||||
}; |
||||
static std::unordered_map<std::string, OptionTypeInfo> pointer_option_info = { |
||||
#ifndef ROCKSDB_LITE |
||||
{"pointer", |
||||
{0, OptionType::kConfigurable, OptionVerificationType::kNormal, |
||||
OptionTypeFlags::kRawPointer}}, |
||||
#endif // ROCKSDB_LITE
|
||||
}; |
||||
|
||||
enum TestConfigMode { |
||||
kEmptyMode = 0x0, // Don't register anything
|
||||
kMutableMode = 0x01, // Configuration is mutable
|
||||
kSimpleMode = 0x02, // Use the simple options
|
||||
kEnumMode = 0x04, // Use the enum options
|
||||
kDefaultMode = kSimpleMode, // Use no inner nested configurations
|
||||
kSharedMode = 0x10, // Use shared configuration
|
||||
kUniqueMode = 0x20, // Use unique configuration
|
||||
kRawPtrMode = 0x40, // Use pointer configuration
|
||||
kNestedMode = (kSharedMode | kUniqueMode | kRawPtrMode), |
||||
kAllOptMode = (kNestedMode | kEnumMode | kSimpleMode), |
||||
}; |
||||
|
||||
template <typename T> |
||||
class TestConfigurable : public Configurable { |
||||
protected: |
||||
std::string name_; |
||||
std::string prefix_; |
||||
TestOptions options_; |
||||
|
||||
public: |
||||
std::unique_ptr<T> unique_; |
||||
std::shared_ptr<T> shared_; |
||||
T* pointer_; |
||||
|
||||
TestConfigurable(const std::string& name, int mode, |
||||
const std::unordered_map<std::string, OptionTypeInfo>* map = |
||||
&simple_option_info) |
||||
: name_(name), pointer_(nullptr) { |
||||
prefix_ = "test." + name + "."; |
||||
if ((mode & TestConfigMode::kSimpleMode) != 0) { |
||||
ConfigurableHelper::RegisterOptions(*this, name_, &options_, map); |
||||
} |
||||
if ((mode & TestConfigMode::kEnumMode) != 0) { |
||||
ConfigurableHelper::RegisterOptions(*this, name_ + "Enum", &options_, |
||||
&enum_option_info); |
||||
} |
||||
} |
||||
|
||||
~TestConfigurable() override { delete pointer_; } |
||||
}; |
||||
|
||||
} // namespace test
|
||||
} // namespace ROCKSDB_NAMESPACE
|
@ -0,0 +1,49 @@ |
||||
// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include "rocksdb/convenience.h" |
||||
#include "rocksdb/table.h" |
||||
#include "table/block_based/block_based_table_factory.h" |
||||
#include "table/cuckoo/cuckoo_table_factory.h" |
||||
#include "table/plain/plain_table_factory.h" |
||||
|
||||
namespace ROCKSDB_NAMESPACE { |
||||
|
||||
Status TableFactory::CreateFromString(const ConfigOptions& config_options_in, |
||||
const std::string& id, |
||||
std::shared_ptr<TableFactory>* factory) { |
||||
Status status; |
||||
std::string name = id; |
||||
|
||||
std::string existing_opts; |
||||
|
||||
ConfigOptions config_options = config_options_in; |
||||
if (factory->get() != nullptr && name == factory->get()->Name()) { |
||||
config_options.delimiter = ";"; |
||||
|
||||
status = factory->get()->GetOptionString(config_options, &existing_opts); |
||||
if (!status.ok()) { |
||||
return status; |
||||
} |
||||
} |
||||
if (name == TableFactory::kBlockBasedTableName()) { |
||||
factory->reset(new BlockBasedTableFactory()); |
||||
#ifndef ROCKSDB_LITE |
||||
} else if (name == TableFactory::kPlainTableName()) { |
||||
factory->reset(new PlainTableFactory()); |
||||
} else if (name == TableFactory::kCuckooTableName()) { |
||||
factory->reset(new CuckooTableFactory()); |
||||
#endif // ROCKSDB_LITE
|
||||
} else { |
||||
return Status::NotSupported("Could not load table factory: ", name); |
||||
} |
||||
if (!existing_opts.empty()) { |
||||
config_options.invoke_prepare_options = false; |
||||
status = factory->get()->ConfigureFromString(config_options, existing_opts); |
||||
} |
||||
return status; |
||||
} |
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
Loading…
Reference in new issue