summaryrefslogtreecommitdiffstats
path: root/src/rocksdb/include/rocksdb/utilities/options_type.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/rocksdb/include/rocksdb/utilities/options_type.h1221
1 files changed, 1221 insertions, 0 deletions
diff --git a/src/rocksdb/include/rocksdb/utilities/options_type.h b/src/rocksdb/include/rocksdb/utilities/options_type.h
new file mode 100644
index 000000000..cd340ed59
--- /dev/null
+++ b/src/rocksdb/include/rocksdb/utilities/options_type.h
@@ -0,0 +1,1221 @@
+// 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).
+//
+// The OptionTypeInfo and related classes provide a framework for
+// configuring and validating RocksDB classes via the Options framework.
+// This file is part of the public API to allow developers who wish to
+// write their own extensions and plugins to take use the Options
+// framework in their custom implementations.
+//
+// See https://github.com/facebook/rocksdb/wiki/RocksDB-Configurable-Objects
+// for more information on how to develop and use custom extensions
+
+#pragma once
+
+#include <functional>
+#include <memory>
+#include <unordered_map>
+
+#include "rocksdb/convenience.h"
+#include "rocksdb/rocksdb_namespace.h"
+#include "rocksdb/status.h"
+
+namespace ROCKSDB_NAMESPACE {
+class OptionTypeInfo;
+struct ColumnFamilyOptions;
+struct DBOptions;
+
+// The underlying "class/type" of the option.
+// This enum is used to determine how the option should
+// be converted to/from strings and compared.
+enum class OptionType {
+ kBoolean,
+ kInt,
+ kInt32T,
+ kInt64T,
+ kUInt,
+ kUInt8T,
+ kUInt32T,
+ kUInt64T,
+ kSizeT,
+ kString,
+ kDouble,
+ kCompactionStyle,
+ kCompactionPri,
+ kCompressionType,
+ kCompactionStopStyle,
+ kChecksumType,
+ kEncodingType,
+ kEnv,
+ kEnum,
+ kStruct,
+ kVector,
+ kConfigurable,
+ kCustomizable,
+ kEncodedString,
+ kTemperature,
+ kArray,
+ kUnknown,
+};
+
+enum class OptionVerificationType {
+ kNormal,
+ kByName, // The option is pointer typed so we can only verify
+ // based on it's name.
+ kByNameAllowNull, // Same as kByName, but it also allows the case
+ // where one of them is a nullptr.
+ kByNameAllowFromNull, // Same as kByName, but it also allows the case
+ // where the old option is nullptr.
+ kDeprecated, // The option is no longer used in rocksdb. The RocksDB
+ // OptionsParser will still accept this option if it
+ // happen to exists in some Options file. However,
+ // the parser will not include it in serialization
+ // and verification processes.
+ kAlias, // This option represents is a name/shortcut for
+ // another option and should not be written or verified
+ // independently
+};
+
+// A set of modifier flags used to alter how an option is evaluated or
+// processed. These flags can be combined together (e.g. kMutable | kShared).
+// The kCompare flags can be used to control if/when options are compared.
+// If kCompareNever is set, two related options would never be compared (always
+// equal) If kCompareExact is set, the options will only be compared if the
+// sanity mode
+// is exact
+// kMutable means the option can be changed after it is prepared
+// kShared means the option is contained in a std::shared_ptr
+// kUnique means the option is contained in a std::uniqued_ptr
+// kRawPointer means the option is a raw pointer value.
+// kAllowNull means that an option is allowed to be null for verification
+// purposes.
+// kDontSerialize means this option should not be serialized and included in
+// the string representation.
+// kDontPrepare means do not call PrepareOptions for this pointer value.
+enum class OptionTypeFlags : uint32_t {
+ kNone = 0x00, // No flags
+ kCompareDefault = 0x0,
+ kCompareNever = ConfigOptions::kSanityLevelNone,
+ kCompareLoose = ConfigOptions::kSanityLevelLooselyCompatible,
+ kCompareExact = ConfigOptions::kSanityLevelExactMatch,
+
+ kMutable = 0x0100, // Option is mutable
+ kRawPointer = 0x0200, // The option is stored as a raw pointer
+ kShared = 0x0400, // The option is stored as a shared_ptr
+ kUnique = 0x0800, // The option is stored as a unique_ptr
+ kAllowNull = 0x1000, // The option can be null
+ kDontSerialize = 0x2000, // Don't serialize the option
+ kDontPrepare = 0x4000, // Don't prepare or sanitize this option
+ kStringNameOnly = 0x8000, // The option serializes to a name only
+};
+
+inline OptionTypeFlags operator|(const OptionTypeFlags& a,
+ const OptionTypeFlags& b) {
+ return static_cast<OptionTypeFlags>(static_cast<uint32_t>(a) |
+ static_cast<uint32_t>(b));
+}
+
+inline OptionTypeFlags operator&(const OptionTypeFlags& a,
+ const OptionTypeFlags& b) {
+ return static_cast<OptionTypeFlags>(static_cast<uint32_t>(a) &
+ static_cast<uint32_t>(b));
+}
+
+// Converts an string into its enumerated value.
+// @param type_map Mapping between strings and enum values
+// @param type The string representation of the enum
+// @param value Returns the enum value represented by the string
+// @return true if the string was found in the enum map, false otherwise.
+template <typename T>
+bool ParseEnum(const std::unordered_map<std::string, T>& type_map,
+ const std::string& type, T* value) {
+ auto iter = type_map.find(type);
+ if (iter != type_map.end()) {
+ *value = iter->second;
+ return true;
+ }
+ return false;
+}
+
+// Converts an enum into its string representation.
+// @param type_map Mapping between strings and enum values
+// @param type The enum
+// @param value Returned as the string representation of the enum
+// @return true if the enum was found in the enum map, false otherwise.
+template <typename T>
+bool SerializeEnum(const std::unordered_map<std::string, T>& type_map,
+ const T& type, std::string* value) {
+ for (const auto& pair : type_map) {
+ if (pair.second == type) {
+ *value = pair.first;
+ return true;
+ }
+ }
+ return false;
+}
+
+template <typename T, size_t kSize>
+Status ParseArray(const ConfigOptions& config_options,
+ const OptionTypeInfo& elem_info, char separator,
+ const std::string& name, const std::string& value,
+ std::array<T, kSize>* result);
+
+template <typename T, size_t kSize>
+Status SerializeArray(const ConfigOptions& config_options,
+ const OptionTypeInfo& elem_info, char separator,
+ const std::string& name, const std::array<T, kSize>& vec,
+ std::string* value);
+
+template <typename T, size_t kSize>
+bool ArraysAreEqual(const ConfigOptions& config_options,
+ const OptionTypeInfo& elem_info, const std::string& name,
+ const std::array<T, kSize>& array1,
+ const std::array<T, kSize>& array2, std::string* mismatch);
+
+template <typename T>
+Status ParseVector(const ConfigOptions& config_options,
+ const OptionTypeInfo& elem_info, char separator,
+ const std::string& name, const std::string& value,
+ std::vector<T>* result);
+
+template <typename T>
+Status SerializeVector(const ConfigOptions& config_options,
+ const OptionTypeInfo& elem_info, char separator,
+ const std::string& name, const std::vector<T>& vec,
+ std::string* value);
+template <typename T>
+bool VectorsAreEqual(const ConfigOptions& config_options,
+ const OptionTypeInfo& elem_info, const std::string& name,
+ const std::vector<T>& vec1, const std::vector<T>& vec2,
+ std::string* mismatch);
+
+// Function for converting a option string value into its underlying
+// representation in "addr"
+// On success, Status::OK is returned and addr is set to the parsed form
+// On failure, a non-OK status is returned
+// @param opts The ConfigOptions controlling how the value is parsed
+// @param name The name of the options being parsed
+// @param value The string representation of the option
+// @param addr Pointer to the object
+using ParseFunc = std::function<Status(
+ const ConfigOptions& /*opts*/, const std::string& /*name*/,
+ const std::string& /*value*/, void* /*addr*/)>;
+
+// Function for converting an option "addr" into its string representation.
+// On success, Status::OK is returned and value is the serialized form.
+// On failure, a non-OK status is returned
+// @param opts The ConfigOptions controlling how the values are serialized
+// @param name The name of the options being serialized
+// @param addr Pointer to the value being serialized
+// @param value The result of the serialization.
+using SerializeFunc = std::function<Status(
+ const ConfigOptions& /*opts*/, const std::string& /*name*/,
+ const void* /*addr*/, std::string* /*value*/)>;
+
+// Function for comparing two option values
+// If they are not equal, updates "mismatch" with the name of the bad option
+// @param opts The ConfigOptions controlling how the values are compared
+// @param name The name of the options being compared
+// @param addr1 The first address to compare
+// @param addr2 The address to compare to
+// @param mismatch If the values are not equal, the name of the option that
+// first differs
+using EqualsFunc = std::function<bool(
+ const ConfigOptions& /*opts*/, const std::string& /*name*/,
+ const void* /*addr1*/, const void* /*addr2*/, std::string* mismatch)>;
+
+// Function for preparing/initializing an option.
+using PrepareFunc =
+ std::function<Status(const ConfigOptions& /*opts*/,
+ const std::string& /*name*/, void* /*addr*/)>;
+
+// Function for validating an option.
+using ValidateFunc = std::function<Status(
+ const DBOptions& /*db_opts*/, const ColumnFamilyOptions& /*cf_opts*/,
+ const std::string& /*name*/, const void* /*addr*/)>;
+
+// A struct for storing constant option information such as option name,
+// option type, and offset.
+class OptionTypeInfo {
+ public:
+ // A simple "normal", non-mutable Type "type" at offset
+ OptionTypeInfo(int offset, OptionType type)
+ : offset_(offset),
+ parse_func_(nullptr),
+ serialize_func_(nullptr),
+ equals_func_(nullptr),
+ type_(type),
+ verification_(OptionVerificationType::kNormal),
+ flags_(OptionTypeFlags::kNone) {}
+
+ OptionTypeInfo(int offset, OptionType type,
+ OptionVerificationType verification, OptionTypeFlags flags)
+ : offset_(offset),
+ parse_func_(nullptr),
+ serialize_func_(nullptr),
+ equals_func_(nullptr),
+ type_(type),
+ verification_(verification),
+ flags_(flags) {}
+
+ OptionTypeInfo(int offset, OptionType type,
+ OptionVerificationType verification, OptionTypeFlags flags,
+ const ParseFunc& parse_func)
+ : offset_(offset),
+ parse_func_(parse_func),
+ serialize_func_(nullptr),
+ equals_func_(nullptr),
+ type_(type),
+ verification_(verification),
+ flags_(flags) {}
+
+ OptionTypeInfo(int offset, OptionType type,
+ OptionVerificationType verification, OptionTypeFlags flags,
+ const ParseFunc& parse_func,
+ const SerializeFunc& serialize_func,
+ const EqualsFunc& equals_func)
+ : offset_(offset),
+ parse_func_(parse_func),
+ serialize_func_(serialize_func),
+ equals_func_(equals_func),
+ type_(type),
+ verification_(verification),
+ flags_(flags) {}
+
+ // Creates an OptionTypeInfo for an enum type. Enums use an additional
+ // map to convert the enums to/from their string representation.
+ // To create an OptionTypeInfo that is an Enum, one should:
+ // - Create a static map of string values to the corresponding enum value
+ // - Call this method passing the static map in as a parameter.
+ // Note that it is not necessary to add a new OptionType or make any
+ // other changes -- the returned object handles parsing, serialization, and
+ // comparisons.
+ //
+ // @param offset The offset in the option object for this enum
+ // @param map The string to enum mapping for this enum
+ template <typename T>
+ static OptionTypeInfo Enum(
+ int offset, const std::unordered_map<std::string, T>* const map,
+ OptionTypeFlags flags = OptionTypeFlags::kNone) {
+ OptionTypeInfo info(offset, OptionType::kEnum,
+ OptionVerificationType::kNormal, flags);
+ info.SetParseFunc(
+ // Uses the map argument to convert the input string into
+ // its corresponding enum value. If value is found in the map,
+ // addr is updated to the corresponding map entry.
+ // @return OK if the value is found in the map
+ // @return InvalidArgument if the value is not found in the map
+ [map](const ConfigOptions&, const std::string& name,
+ const std::string& value, void* addr) {
+ if (map == nullptr) {
+ return Status::NotSupported("No enum mapping ", name);
+ } else if (ParseEnum<T>(*map, value, static_cast<T*>(addr))) {
+ return Status::OK();
+ } else {
+ return Status::InvalidArgument("No mapping for enum ", name);
+ }
+ });
+ info.SetSerializeFunc(
+ // Uses the map argument to convert the input enum into
+ // its corresponding string value. If enum value is found in the map,
+ // value is updated to the corresponding string value in the map.
+ // @return OK if the enum is found in the map
+ // @return InvalidArgument if the enum is not found in the map
+ [map](const ConfigOptions&, const std::string& name, const void* addr,
+ std::string* value) {
+ if (map == nullptr) {
+ return Status::NotSupported("No enum mapping ", name);
+ } else if (SerializeEnum<T>(*map, (*static_cast<const T*>(addr)),
+ value)) {
+ return Status::OK();
+ } else {
+ return Status::InvalidArgument("No mapping for enum ", name);
+ }
+ });
+ info.SetEqualsFunc(
+ // Casts addr1 and addr2 to the enum type and returns true if
+ // they are equal, false otherwise.
+ [](const ConfigOptions&, const std::string&, const void* addr1,
+ const void* addr2, std::string*) {
+ return (*static_cast<const T*>(addr1) ==
+ *static_cast<const T*>(addr2));
+ });
+ return info;
+ } // End OptionTypeInfo::Enum
+
+ // Creates an OptionTypeInfo for a Struct type. Structs have a
+ // map of string-OptionTypeInfo associated with them that describes how
+ // to process the object for parsing, serializing, and matching.
+ // Structs also have a struct_name, which is the name of the object
+ // as registered in the parent map.
+ // When processing a struct, the option name can be specified as:
+ // - <struct_name> Meaning to process the entire struct.
+ // - <struct_name.field> Meaning to process the single field
+ // - <field> Process the single fields
+ // The CompactionOptionsFIFO, CompactionOptionsUniversal, and LRUCacheOptions
+ // are all examples of Struct options.
+ //
+ // To create an OptionTypeInfo that is a Struct, one should:
+ // - Create a static map of string-OptionTypeInfo corresponding to the
+ // properties of the object that can be set via the options.
+ // - Call this method passing the name and map in as parameters.
+ // Note that it is not necessary to add a new OptionType or make any
+ // other changes -- the returned object handles parsing, serialization, and
+ // comparisons.
+ //
+ // @param offset The offset in the option object for this enum
+ // @param map The string to enum mapping for this enum
+ static OptionTypeInfo Struct(
+ const std::string& struct_name,
+ const std::unordered_map<std::string, OptionTypeInfo>* struct_map,
+ int offset, OptionVerificationType verification, OptionTypeFlags flags) {
+ OptionTypeInfo info(offset, OptionType::kStruct, verification, flags);
+ info.SetParseFunc(
+ // Parses the struct and updates the fields at addr
+ [struct_name, struct_map](const ConfigOptions& opts,
+ const std::string& name,
+ const std::string& value, void* addr) {
+ return ParseStruct(opts, struct_name, struct_map, name, value, addr);
+ });
+ info.SetSerializeFunc(
+ // Serializes the struct options into value
+ [struct_name, struct_map](const ConfigOptions& opts,
+ const std::string& name, const void* addr,
+ std::string* value) {
+ return SerializeStruct(opts, struct_name, struct_map, name, addr,
+ value);
+ });
+ info.SetEqualsFunc(
+ // Compares the struct fields of addr1 and addr2 for equality
+ [struct_name, struct_map](const ConfigOptions& opts,
+ const std::string& name, const void* addr1,
+ const void* addr2, std::string* mismatch) {
+ return StructsAreEqual(opts, struct_name, struct_map, name, addr1,
+ addr2, mismatch);
+ });
+ return info;
+ }
+ static OptionTypeInfo Struct(
+ const std::string& struct_name,
+ const std::unordered_map<std::string, OptionTypeInfo>* struct_map,
+ int offset, OptionVerificationType verification, OptionTypeFlags flags,
+ const ParseFunc& parse_func) {
+ OptionTypeInfo info(
+ Struct(struct_name, struct_map, offset, verification, flags));
+ return info.SetParseFunc(parse_func);
+ }
+
+ template <typename T, size_t kSize>
+ static OptionTypeInfo Array(int _offset, OptionVerificationType _verification,
+ OptionTypeFlags _flags,
+ const OptionTypeInfo& elem_info,
+ char separator = ':') {
+ OptionTypeInfo info(_offset, OptionType::kArray, _verification, _flags);
+ info.SetParseFunc([elem_info, separator](
+ const ConfigOptions& opts, const std::string& name,
+ const std::string& value, void* addr) {
+ auto result = static_cast<std::array<T, kSize>*>(addr);
+ return ParseArray<T, kSize>(opts, elem_info, separator, name, value,
+ result);
+ });
+ info.SetSerializeFunc([elem_info, separator](const ConfigOptions& opts,
+ const std::string& name,
+ const void* addr,
+ std::string* value) {
+ const auto& array = *(static_cast<const std::array<T, kSize>*>(addr));
+ return SerializeArray<T, kSize>(opts, elem_info, separator, name, array,
+ value);
+ });
+ info.SetEqualsFunc([elem_info](const ConfigOptions& opts,
+ const std::string& name, const void* addr1,
+ const void* addr2, std::string* mismatch) {
+ const auto& array1 = *(static_cast<const std::array<T, kSize>*>(addr1));
+ const auto& array2 = *(static_cast<const std::array<T, kSize>*>(addr2));
+ return ArraysAreEqual<T, kSize>(opts, elem_info, name, array1, array2,
+ mismatch);
+ });
+ return info;
+ }
+
+ template <typename T>
+ static OptionTypeInfo Vector(int _offset,
+ OptionVerificationType _verification,
+ OptionTypeFlags _flags,
+ const OptionTypeInfo& elem_info,
+ char separator = ':') {
+ OptionTypeInfo info(_offset, OptionType::kVector, _verification, _flags);
+ info.SetParseFunc([elem_info, separator](
+ const ConfigOptions& opts, const std::string& name,
+ const std::string& value, void* addr) {
+ auto result = static_cast<std::vector<T>*>(addr);
+ return ParseVector<T>(opts, elem_info, separator, name, value, result);
+ });
+ info.SetSerializeFunc([elem_info, separator](const ConfigOptions& opts,
+ const std::string& name,
+ const void* addr,
+ std::string* value) {
+ const auto& vec = *(static_cast<const std::vector<T>*>(addr));
+ return SerializeVector<T>(opts, elem_info, separator, name, vec, value);
+ });
+ info.SetEqualsFunc([elem_info](const ConfigOptions& opts,
+ const std::string& name, const void* addr1,
+ const void* addr2, std::string* mismatch) {
+ const auto& vec1 = *(static_cast<const std::vector<T>*>(addr1));
+ const auto& vec2 = *(static_cast<const std::vector<T>*>(addr2));
+ return VectorsAreEqual<T>(opts, elem_info, name, vec1, vec2, mismatch);
+ });
+ return info;
+ }
+
+ // Create a new std::shared_ptr<Customizable> OptionTypeInfo
+ // This function will call the T::CreateFromString method to create a new
+ // std::shared_ptr<T> object.
+ //
+ // @param offset The offset for the Customizable from the base pointer
+ // @param ovt How to verify this option
+ // @param flags, Extra flags specifying the behavior of this option
+ // @param _sfunc Optional function for serializing this option
+ // @param _efunc Optional function for comparing this option
+ template <typename T>
+ static OptionTypeInfo AsCustomSharedPtr(int offset,
+ OptionVerificationType ovt,
+ OptionTypeFlags flags) {
+ OptionTypeInfo info(offset, OptionType::kCustomizable, ovt,
+ flags | OptionTypeFlags::kShared);
+ return info.SetParseFunc([](const ConfigOptions& opts,
+ const std::string& name,
+ const std::string& value, void* addr) {
+ auto* shared = static_cast<std::shared_ptr<T>*>(addr);
+ if (name == kIdPropName() && value.empty()) {
+ shared->reset();
+ return Status::OK();
+ } else {
+ return T::CreateFromString(opts, value, shared);
+ }
+ });
+ }
+
+ template <typename T>
+ static OptionTypeInfo AsCustomSharedPtr(int offset,
+ OptionVerificationType ovt,
+ OptionTypeFlags flags,
+ const SerializeFunc& serialize_func,
+ const EqualsFunc& equals_func) {
+ OptionTypeInfo info(AsCustomSharedPtr<T>(offset, ovt, flags));
+ info.SetSerializeFunc(serialize_func);
+ info.SetEqualsFunc(equals_func);
+ return info;
+ }
+
+ // Create a new std::unique_ptr<Customizable> OptionTypeInfo
+ // This function will call the T::CreateFromString method to create a new
+ // std::unique_ptr<T> object.
+ //
+ // @param offset The offset for the Customizable from the base pointer
+ // @param ovt How to verify this option
+ // @param flags, Extra flags specifying the behavior of this option
+ // @param _sfunc Optional function for serializing this option
+ // @param _efunc Optional function for comparing this option
+ template <typename T>
+ static OptionTypeInfo AsCustomUniquePtr(int offset,
+ OptionVerificationType ovt,
+ OptionTypeFlags flags) {
+ OptionTypeInfo info(offset, OptionType::kCustomizable, ovt,
+ flags | OptionTypeFlags::kUnique);
+ return info.SetParseFunc([](const ConfigOptions& opts,
+ const std::string& name,
+ const std::string& value, void* addr) {
+ auto* unique = static_cast<std::unique_ptr<T>*>(addr);
+ if (name == kIdPropName() && value.empty()) {
+ unique->reset();
+ return Status::OK();
+ } else {
+ return T::CreateFromString(opts, value, unique);
+ }
+ });
+ }
+
+ template <typename T>
+ static OptionTypeInfo AsCustomUniquePtr(int offset,
+ OptionVerificationType ovt,
+ OptionTypeFlags flags,
+ const SerializeFunc& serialize_func,
+ const EqualsFunc& equals_func) {
+ OptionTypeInfo info(AsCustomUniquePtr<T>(offset, ovt, flags));
+ info.SetSerializeFunc(serialize_func);
+ info.SetEqualsFunc(equals_func);
+ return info;
+ }
+
+ // Create a new Customizable* OptionTypeInfo
+ // This function will call the T::CreateFromString method to create a new
+ // T object.
+ //
+ // @param _offset The offset for the Customizable from the base pointer
+ // @param ovt How to verify this option
+ // @param flags, Extra flags specifying the behavior of this option
+ // @param _sfunc Optional function for serializing this option
+ // @param _efunc Optional function for comparing this option
+ template <typename T>
+ static OptionTypeInfo AsCustomRawPtr(int offset, OptionVerificationType ovt,
+ OptionTypeFlags flags) {
+ OptionTypeInfo info(offset, OptionType::kCustomizable, ovt,
+ flags | OptionTypeFlags::kRawPointer);
+ return info.SetParseFunc([](const ConfigOptions& opts,
+ const std::string& name,
+ const std::string& value, void* addr) {
+ auto** pointer = static_cast<T**>(addr);
+ if (name == kIdPropName() && value.empty()) {
+ *pointer = nullptr;
+ return Status::OK();
+ } else {
+ return T::CreateFromString(opts, value, pointer);
+ }
+ });
+ }
+
+ template <typename T>
+ static OptionTypeInfo AsCustomRawPtr(int offset, OptionVerificationType ovt,
+ OptionTypeFlags flags,
+ const SerializeFunc& serialize_func,
+ const EqualsFunc& equals_func) {
+ OptionTypeInfo info(AsCustomRawPtr<T>(offset, ovt, flags));
+ info.SetSerializeFunc(serialize_func);
+ info.SetEqualsFunc(equals_func);
+ return info;
+ }
+
+ OptionTypeInfo& SetParseFunc(const ParseFunc& f) {
+ parse_func_ = f;
+ return *this;
+ }
+
+ OptionTypeInfo& SetSerializeFunc(const SerializeFunc& f) {
+ serialize_func_ = f;
+ return *this;
+ }
+ OptionTypeInfo& SetEqualsFunc(const EqualsFunc& f) {
+ equals_func_ = f;
+ return *this;
+ }
+
+ OptionTypeInfo& SetPrepareFunc(const PrepareFunc& f) {
+ prepare_func_ = f;
+ return *this;
+ }
+
+ OptionTypeInfo& SetValidateFunc(const ValidateFunc& f) {
+ validate_func_ = f;
+ return *this;
+ }
+
+ bool IsEnabled(OptionTypeFlags otf) const { return (flags_ & otf) == otf; }
+
+ bool IsEditable(const ConfigOptions& opts) const {
+ if (opts.mutable_options_only) {
+ return IsMutable();
+ } else {
+ return true;
+ }
+ }
+ bool IsMutable() const { return IsEnabled(OptionTypeFlags::kMutable); }
+
+ bool IsDeprecated() const {
+ return IsEnabled(OptionVerificationType::kDeprecated);
+ }
+
+ // Returns true if the option is marked as an Alias.
+ // Aliases are valid options that are parsed but are not converted to strings
+ // or compared.
+ bool IsAlias() const { return IsEnabled(OptionVerificationType::kAlias); }
+
+ bool IsEnabled(OptionVerificationType ovf) const {
+ return verification_ == ovf;
+ }
+
+ // Returns the sanity level for comparing the option.
+ // If the options should not be compared, returns None
+ // If the option has a compare flag, returns it.
+ // Otherwise, returns "exact"
+ ConfigOptions::SanityLevel GetSanityLevel() const {
+ if (IsDeprecated() || IsAlias()) {
+ return ConfigOptions::SanityLevel::kSanityLevelNone;
+ } else {
+ auto match = (flags_ & OptionTypeFlags::kCompareExact);
+ if (match == OptionTypeFlags::kCompareDefault) {
+ return ConfigOptions::SanityLevel::kSanityLevelExactMatch;
+ } else {
+ return (ConfigOptions::SanityLevel)match;
+ }
+ }
+ }
+
+ // Returns true if the option should be serialized.
+ // Options should be serialized if the are not deprecated, aliases,
+ // or marked as "Don't Serialize".
+ bool ShouldSerialize() const {
+ if (IsDeprecated() || IsAlias()) {
+ return false;
+ } else if (IsEnabled(OptionTypeFlags::kDontSerialize)) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ bool ShouldPrepare() const {
+ if (IsDeprecated() || IsAlias()) {
+ return false;
+ } else if (IsEnabled(OptionTypeFlags::kDontPrepare)) {
+ return false;
+ } else {
+ return (prepare_func_ != nullptr || IsConfigurable());
+ }
+ }
+
+ bool ShouldValidate() const {
+ if (IsDeprecated() || IsAlias()) {
+ return false;
+ } else {
+ return (validate_func_ != nullptr || IsConfigurable());
+ }
+ }
+
+ // Returns true if the option is allowed to be null.
+ // Options can be null if the verification type is allow from null
+ // or if the flags specify allow null.
+ bool CanBeNull() const {
+ return (IsEnabled(OptionTypeFlags::kAllowNull) ||
+ IsEnabled(OptionVerificationType::kByNameAllowNull) ||
+ IsEnabled(OptionVerificationType::kByNameAllowFromNull));
+ }
+
+ bool IsSharedPtr() const { return IsEnabled(OptionTypeFlags::kShared); }
+
+ bool IsUniquePtr() const { return IsEnabled(OptionTypeFlags::kUnique); }
+
+ bool IsRawPtr() const { return IsEnabled(OptionTypeFlags::kRawPointer); }
+
+ bool IsByName() const {
+ return (verification_ == OptionVerificationType::kByName ||
+ verification_ == OptionVerificationType::kByNameAllowNull ||
+ verification_ == OptionVerificationType::kByNameAllowFromNull);
+ }
+
+ bool IsStruct() const { return (type_ == OptionType::kStruct); }
+
+ bool IsConfigurable() const {
+ return (type_ == OptionType::kConfigurable ||
+ type_ == OptionType::kCustomizable);
+ }
+
+ bool IsCustomizable() const { return (type_ == OptionType::kCustomizable); }
+
+ inline const void* GetOffset(const void* base) const {
+ return static_cast<const char*>(base) + offset_;
+ }
+
+ inline void* GetOffset(void* base) const {
+ return static_cast<char*>(base) + offset_;
+ }
+
+ template <typename T>
+ const T* GetOffsetAs(const void* base) const {
+ const void* addr = GetOffset(base);
+ return static_cast<const T*>(addr);
+ }
+
+ template <typename T>
+ T* GetOffsetAs(void* base) const {
+ void* addr = GetOffset(base);
+ return static_cast<T*>(addr);
+ }
+
+ // Returns the underlying pointer for the type at base_addr
+ // The value returned is the underlying "raw" pointer, offset from base.
+ template <typename T>
+ const T* AsRawPointer(const void* const base_addr) const {
+ if (base_addr == nullptr) {
+ return nullptr;
+ }
+ if (IsUniquePtr()) {
+ const auto ptr = GetOffsetAs<std::unique_ptr<T>>(base_addr);
+ return ptr->get();
+ } else if (IsSharedPtr()) {
+ const auto ptr = GetOffsetAs<std::shared_ptr<T>>(base_addr);
+ return ptr->get();
+ } else if (IsRawPtr()) {
+ const T* const* ptr = GetOffsetAs<T* const>(base_addr);
+ return *ptr;
+ } else {
+ return GetOffsetAs<T>(base_addr);
+ }
+ }
+
+ // Returns the underlying pointer for the type at base_addr
+ // The value returned is the underlying "raw" pointer, offset from base.
+ template <typename T>
+ T* AsRawPointer(void* base_addr) const {
+ if (base_addr == nullptr) {
+ return nullptr;
+ }
+ if (IsUniquePtr()) {
+ auto ptr = GetOffsetAs<std::unique_ptr<T>>(base_addr);
+ return ptr->get();
+ } else if (IsSharedPtr()) {
+ auto ptr = GetOffsetAs<std::shared_ptr<T>>(base_addr);
+ return ptr->get();
+ } else if (IsRawPtr()) {
+ auto ptr = GetOffsetAs<T*>(base_addr);
+ return *ptr;
+ } else {
+ return GetOffsetAs<T>(base_addr);
+ }
+ }
+
+ // Parses the option in "opt_value" according to the rules of this class
+ // and updates the value at "opt_ptr".
+ // On success, Status::OK() is returned. On failure:
+ // NotFound means the opt_name is not valid for this option
+ // NotSupported means we do not know how to parse the value for this option
+ // InvalidArgument means the opt_value is not valid for this option.
+ Status Parse(const ConfigOptions& config_options, const std::string& opt_name,
+ const std::string& opt_value, void* const opt_ptr) const;
+
+ // Serializes the option in "opt_addr" according to the rules of this class
+ // into the value at "opt_value".
+ Status Serialize(const ConfigOptions& config_options,
+ const std::string& opt_name, const void* const opt_ptr,
+ std::string* opt_value) const;
+
+ // Compares the "addr1" and "addr2" values according to the rules of this
+ // class and returns true if they match. On a failed match, mismatch is the
+ // name of the option that failed to match.
+ bool AreEqual(const ConfigOptions& config_options,
+ const std::string& opt_name, const void* const addr1,
+ const void* const addr2, std::string* mismatch) const;
+
+ // Used to override the match rules for "ByName" options.
+ bool AreEqualByName(const ConfigOptions& config_options,
+ const std::string& opt_name, const void* const this_ptr,
+ const void* const that_ptr) const;
+ bool AreEqualByName(const ConfigOptions& config_options,
+ const std::string& opt_name, const void* const this_ptr,
+ const std::string& that_value) const;
+
+ Status Prepare(const ConfigOptions& config_options, const std::string& name,
+ void* opt_ptr) const;
+ Status Validate(const DBOptions& db_opts, const ColumnFamilyOptions& cf_opts,
+ const std::string& name, const void* opt_ptr) const;
+
+ // Parses the input opts_map according to the type_map for the opt_addr
+ // For each name-value pair in opts_map, find the corresponding name in
+ // type_map If the name is found:
+ // - set the corresponding value in opt_addr, returning the status on
+ // failure;
+ // If the name is not found:
+ // - If unused is specified, add the name-value to unused and continue
+ // - If ingore_unknown_options is false, return NotFound
+ // Returns OK if all options were either:
+ // - Successfully set
+ // - options were not found and ignore_unknown_options=true
+ // - options were not found and unused was specified
+ // Note that this method is much less sophisticated than the comparable
+ // Configurable::Configure methods. For example, on error, there is no
+ // attempt to return opt_addr to the initial state. Additionally, there
+ // is no effort to initialize (Configurable::PrepareOptions) the object
+ // on success. This method should typically only be used for simpler,
+ // standalone structures and not those that contain shared and embedded
+ // objects.
+ static Status ParseType(
+ const ConfigOptions& config_options, const std::string& opts_str,
+ const std::unordered_map<std::string, OptionTypeInfo>& type_map,
+ void* opt_addr,
+ std::unordered_map<std::string, std::string>* unused = nullptr);
+ static Status ParseType(
+ const ConfigOptions& config_options,
+ const std::unordered_map<std::string, std::string>& opts_map,
+ const std::unordered_map<std::string, OptionTypeInfo>& type_map,
+ void* opt_addr,
+ std::unordered_map<std::string, std::string>* unused = nullptr);
+
+ // Parses the input value according to the map for the struct at opt_addr
+ // struct_name is the name of the struct option as registered
+ // opt_name is the name of the option being evaluated. This may
+ // be the whole struct or a sub-element of it, based on struct_name and
+ // opt_name.
+ static Status ParseStruct(
+ const ConfigOptions& config_options, const std::string& struct_name,
+ const std::unordered_map<std::string, OptionTypeInfo>* map,
+ const std::string& opt_name, const std::string& value, void* opt_addr);
+
+ // Serializes the values from opt_addr using the rules in type_map.
+ // Returns the serialized form in result.
+ // Returns OK on success or non-OK if some option could not be serialized.
+ static Status SerializeType(
+ const ConfigOptions& config_options,
+ const std::unordered_map<std::string, OptionTypeInfo>& type_map,
+ const void* opt_addr, std::string* value);
+
+ // Serializes the input addr according to the map for the struct to value.
+ // struct_name is the name of the struct option as registered
+ // opt_name is the name of the option being evaluated. This may
+ // be the whole struct or a sub-element of it
+ static Status SerializeStruct(
+ const ConfigOptions& config_options, const std::string& struct_name,
+ const std::unordered_map<std::string, OptionTypeInfo>* map,
+ const std::string& opt_name, const void* opt_addr, std::string* value);
+
+ // Compares the values in this_addr and that_addr using the rules in type_map.
+ // If the values are equal, returns true
+ // If the values are not equal, returns false and sets mismatch to the name
+ // of the first value that did not match.
+ static bool TypesAreEqual(
+ const ConfigOptions& config_options,
+ const std::unordered_map<std::string, OptionTypeInfo>& map,
+ const void* this_addr, const void* that_addr, std::string* mismatch);
+
+ // Compares the input offsets according to the map for the struct and returns
+ // true if they are equivalent, false otherwise.
+ // struct_name is the name of the struct option as registered
+ // opt_name is the name of the option being evaluated. This may
+ // be the whole struct or a sub-element of it
+ static bool StructsAreEqual(
+ const ConfigOptions& config_options, const std::string& struct_name,
+ const std::unordered_map<std::string, OptionTypeInfo>* map,
+ const std::string& opt_name, const void* this_offset,
+ const void* that_offset, std::string* mismatch);
+
+ // Finds the entry for the opt_name in the opt_map, returning
+ // nullptr if not found.
+ // If found, elem_name will be the name of option to find.
+ // This may be opt_name, or a substring of opt_name.
+ // For "simple" options, opt_name will be equal to elem_name. Given the
+ // opt_name "opt", elem_name will equal "opt".
+ // For "embedded" options (like structs), elem_name may be opt_name
+ // or a field within the opt_name. For example, given the struct "struct",
+ // and opt_name of "struct.field", elem_name will be "field"
+ static const OptionTypeInfo* Find(
+ const std::string& opt_name,
+ const std::unordered_map<std::string, OptionTypeInfo>& opt_map,
+ std::string* elem_name);
+
+ // Returns the next token marked by the delimiter from "opts" after start in
+ // token and updates end to point to where that token stops. Delimiters inside
+ // of braces are ignored. Returns OK if a token is found and an error if the
+ // input opts string is mis-formatted.
+ // Given "a=AA;b=BB;" start=2 and delimiter=";", token is "AA" and end points
+ // to "b" Given "{a=A;b=B}", the token would be "a=A;b=B"
+ //
+ // @param opts The string in which to find the next token
+ // @param delimiter The delimiter between tokens
+ // @param start The position in opts to start looking for the token
+ // @param ed Returns the end position in opts of the token
+ // @param token Returns the token
+ // @returns OK if a token was found
+ // @return InvalidArgument if the braces mismatch
+ // (e.g. "{a={b=c;}" ) -- missing closing brace
+ // @return InvalidArgument if an expected delimiter is not found
+ // e.g. "{a=b}c=d;" -- missing delimiter before "c"
+ static Status NextToken(const std::string& opts, char delimiter, size_t start,
+ size_t* end, std::string* token);
+
+ constexpr static const char* kIdPropName() { return "id"; }
+ constexpr static const char* kIdPropSuffix() { return ".id"; }
+
+ private:
+ int offset_;
+
+ // The optional function to convert a string to its representation
+ ParseFunc parse_func_;
+
+ // The optional function to convert a value to its string representation
+ SerializeFunc serialize_func_;
+
+ // The optional function to match two option values
+ EqualsFunc equals_func_;
+
+ PrepareFunc prepare_func_;
+ ValidateFunc validate_func_;
+ OptionType type_;
+ OptionVerificationType verification_;
+ OptionTypeFlags flags_;
+};
+
+// Parses the input value into elements of the result array, which has fixed
+// array size. For example, if the value=1:2:3 and elem_info parses integers,
+// the result array will be {1,2,3}. Array size is defined in the OptionTypeInfo
+// the input value has to match with that.
+// @param config_options Controls how the option value is parsed.
+// @param elem_info Controls how individual tokens in value are parsed
+// @param separator Character separating tokens in values (':' in the above
+// example)
+// @param name The name associated with this array option
+// @param value The input string to parse into tokens
+// @param result Returns the results of parsing value into its elements.
+// @return OK if the value was successfully parse
+// @return InvalidArgument if the value is improperly formed or element number
+// doesn't match array size defined in OptionTypeInfo
+// or if the token could not be parsed
+// @return NotFound If the tokenized value contains unknown options for
+// its type
+template <typename T, size_t kSize>
+Status ParseArray(const ConfigOptions& config_options,
+ const OptionTypeInfo& elem_info, char separator,
+ const std::string& name, const std::string& value,
+ std::array<T, kSize>* result) {
+ Status status;
+
+ ConfigOptions copy = config_options;
+ copy.ignore_unsupported_options = false;
+ size_t i = 0, start = 0, end = 0;
+ for (; status.ok() && i < kSize && start < value.size() &&
+ end != std::string::npos;
+ i++, start = end + 1) {
+ std::string token;
+ status = OptionTypeInfo::NextToken(value, separator, start, &end, &token);
+ if (status.ok()) {
+ status = elem_info.Parse(copy, name, token, &((*result)[i]));
+ if (config_options.ignore_unsupported_options &&
+ status.IsNotSupported()) {
+ // If we were ignoring unsupported options and this one should be
+ // ignored, ignore it by setting the status to OK
+ status = Status::OK();
+ }
+ }
+ }
+ if (!status.ok()) {
+ return status;
+ }
+ // make sure the element number matches the array size
+ if (i < kSize) {
+ return Status::InvalidArgument(
+ "Serialized value has less elements than array size", name);
+ }
+ if (start < value.size() && end != std::string::npos) {
+ return Status::InvalidArgument(
+ "Serialized value has more elements than array size", name);
+ }
+ return status;
+}
+
+// Serializes the fixed size input array into its output value. Elements are
+// separated by the separator character. This element will convert all of the
+// elements in array into their serialized form, using elem_info to perform the
+// serialization.
+// For example, if the array contains the integers 1,2,3 and elem_info
+// serializes the output would be 1:2:3 for separator ":".
+// @param config_options Controls how the option value is serialized.
+// @param elem_info Controls how individual tokens in value are serialized
+// @param separator Character separating tokens in value (':' in the above
+// example)
+// @param name The name associated with this array option
+// @param array The input array to serialize
+// @param value The output string of serialized options
+// @return OK if the value was successfully parse
+// @return InvalidArgument if the value is improperly formed or if the token
+// could not be parsed
+// @return NotFound If the tokenized value contains unknown options for
+// its type
+template <typename T, size_t kSize>
+Status SerializeArray(const ConfigOptions& config_options,
+ const OptionTypeInfo& elem_info, char separator,
+ const std::string& name,
+ const std::array<T, kSize>& array, std::string* value) {
+ std::string result;
+ ConfigOptions embedded = config_options;
+ embedded.delimiter = ";";
+ int printed = 0;
+ for (const auto& elem : array) {
+ std::string elem_str;
+ Status s = elem_info.Serialize(embedded, name, &elem, &elem_str);
+ if (!s.ok()) {
+ return s;
+ } else if (!elem_str.empty()) {
+ if (printed++ > 0) {
+ result += separator;
+ }
+ // If the element contains embedded separators, put it inside of brackets
+ if (elem_str.find(separator) != std::string::npos) {
+ result += "{" + elem_str + "}";
+ } else {
+ result += elem_str;
+ }
+ }
+ }
+ if (result.find("=") != std::string::npos) {
+ *value = "{" + result + "}";
+ } else if (printed > 1 && result.at(0) == '{') {
+ *value = "{" + result + "}";
+ } else {
+ *value = result;
+ }
+ return Status::OK();
+}
+
+// Compares the input arrays array1 and array2 for equality
+// Elements of the array are compared one by one using elem_info to perform the
+// comparison.
+//
+// @param config_options Controls how the arrays are compared.
+// @param elem_info Controls how individual elements in the arrays are compared
+// @param name The name associated with this array option
+// @param array1,array2 The arrays to compare.
+// @param mismatch If the arrays are not equivalent, mismatch will point to
+// the first element of the comparison that did not match.
+// @return true If vec1 and vec2 are "equal", false otherwise
+template <typename T, size_t kSize>
+bool ArraysAreEqual(const ConfigOptions& config_options,
+ const OptionTypeInfo& elem_info, const std::string& name,
+ const std::array<T, kSize>& array1,
+ const std::array<T, kSize>& array2, std::string* mismatch) {
+ assert(array1.size() == kSize);
+ assert(array2.size() == kSize);
+ for (size_t i = 0; i < kSize; ++i) {
+ if (!elem_info.AreEqual(config_options, name, &array1[i], &array2[i],
+ mismatch)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// Parses the input value into elements of the result vector. This method
+// will break the input value into the individual tokens (based on the
+// separator), where each of those tokens will be parsed based on the rules of
+// elem_info. The result vector will be populated with elements based on the
+// input tokens. For example, if the value=1:2:3:4:5 and elem_info parses
+// integers, the result vector will contain the integers 1,2,3,4,5
+// @param config_options Controls how the option value is parsed.
+// @param elem_info Controls how individual tokens in value are parsed
+// @param separator Character separating tokens in values (':' in the above
+// example)
+// @param name The name associated with this vector option
+// @param value The input string to parse into tokens
+// @param result Returns the results of parsing value into its elements.
+// @return OK if the value was successfully parse
+// @return InvalidArgument if the value is improperly formed or if the token
+// could not be parsed
+// @return NotFound If the tokenized value contains unknown options for
+// its type
+template <typename T>
+Status ParseVector(const ConfigOptions& config_options,
+ const OptionTypeInfo& elem_info, char separator,
+ const std::string& name, const std::string& value,
+ std::vector<T>* result) {
+ result->clear();
+ Status status;
+
+ // Turn off ignore_unknown_objects so we can tell if the returned
+ // object is valid or not.
+ ConfigOptions copy = config_options;
+ copy.ignore_unsupported_options = false;
+ for (size_t start = 0, end = 0;
+ status.ok() && start < value.size() && end != std::string::npos;
+ start = end + 1) {
+ std::string token;
+ status = OptionTypeInfo::NextToken(value, separator, start, &end, &token);
+ if (status.ok()) {
+ T elem;
+ status = elem_info.Parse(copy, name, token, &elem);
+ if (status.ok()) {
+ result->emplace_back(elem);
+ } else if (config_options.ignore_unsupported_options &&
+ status.IsNotSupported()) {
+ // If we were ignoring unsupported options and this one should be
+ // ignored, ignore it by setting the status to OK
+ status = Status::OK();
+ }
+ }
+ }
+ return status;
+}
+
+// Serializes the input vector into its output value. Elements are
+// separated by the separator character. This element will convert all of the
+// elements in vec into their serialized form, using elem_info to perform the
+// serialization.
+// For example, if the vec contains the integers 1,2,3,4,5 and elem_info
+// serializes the output would be 1:2:3:4:5 for separator ":".
+// @param config_options Controls how the option value is serialized.
+// @param elem_info Controls how individual tokens in value are serialized
+// @param separator Character separating tokens in value (':' in the above
+// example)
+// @param name The name associated with this vector option
+// @param vec The input vector to serialize
+// @param value The output string of serialized options
+// @return OK if the value was successfully parse
+// @return InvalidArgument if the value is improperly formed or if the token
+// could not be parsed
+// @return NotFound If the tokenized value contains unknown options for
+// its type
+template <typename T>
+Status SerializeVector(const ConfigOptions& config_options,
+ const OptionTypeInfo& elem_info, char separator,
+ const std::string& name, const std::vector<T>& vec,
+ std::string* value) {
+ std::string result;
+ ConfigOptions embedded = config_options;
+ embedded.delimiter = ";";
+ int printed = 0;
+ for (const auto& elem : vec) {
+ std::string elem_str;
+ Status s = elem_info.Serialize(embedded, name, &elem, &elem_str);
+ if (!s.ok()) {
+ return s;
+ } else if (!elem_str.empty()) {
+ if (printed++ > 0) {
+ result += separator;
+ }
+ // If the element contains embedded separators, put it inside of brackets
+ if (elem_str.find(separator) != std::string::npos) {
+ result += "{" + elem_str + "}";
+ } else {
+ result += elem_str;
+ }
+ }
+ }
+ if (result.find("=") != std::string::npos) {
+ *value = "{" + result + "}";
+ } else if (printed > 1 && result.at(0) == '{') {
+ *value = "{" + result + "}";
+ } else {
+ *value = result;
+ }
+ return Status::OK();
+}
+
+// Compares the input vectors vec1 and vec2 for equality
+// If the vectors are the same size, elements of the vectors are compared one by
+// one using elem_info to perform the comparison.
+//
+// @param config_options Controls how the vectors are compared.
+// @param elem_info Controls how individual elements in the vectors are compared
+// @param name The name associated with this vector option
+// @param vec1,vec2 The vectors to compare.
+// @param mismatch If the vectors are not equivalent, mismatch will point to
+// the first
+// element of the comparison that did not match.
+// @return true If vec1 and vec2 are "equal", false otherwise
+template <typename T>
+bool VectorsAreEqual(const ConfigOptions& config_options,
+ const OptionTypeInfo& elem_info, const std::string& name,
+ const std::vector<T>& vec1, const std::vector<T>& vec2,
+ std::string* mismatch) {
+ if (vec1.size() != vec2.size()) {
+ *mismatch = name;
+ return false;
+ } else {
+ for (size_t i = 0; i < vec1.size(); ++i) {
+ if (!elem_info.AreEqual(
+ config_options, name, reinterpret_cast<const char*>(&vec1[i]),
+ reinterpret_cast<const char*>(&vec2[i]), mismatch)) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
+} // namespace ROCKSDB_NAMESPACE