// 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 #include #include #include #include #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 representing 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; // The map of options being registered const std::unordered_map* type_map; }; public: 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 const T* GetOptions() const { return GetOptions(T::kName()); } template T* GetOptions() { return GetOptions(T::kName()); } template const T* GetOptions(const std::string& name) const { return reinterpret_cast(GetOptionsPtr(name)); } template T* GetOptions(const std::string& name) { return reinterpret_cast(const_cast(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& opt_map); Status ConfigureFromMap( const ConfigOptions& config_options, const std::unordered_map& opt_map, std::unordered_map* unused); // 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); // 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 were 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; // 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* 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; // 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 successfully // 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; // Splits the input opt_value into the ID field and the remaining options. // The input opt_value can be in the form of "name" or "name=value // [;name=value]". The first form uses the "name" as an id with no options The // latter form converts the input into a map of name=value pairs and sets "id" // to the "id" value from the map. // @param opt_value The value to split into id and options // @param id The id field from the opt_value // @param options The remaining name/value pairs from the opt_value // @param default_id If specified and there is no id field in the map, this // value is returned as the ID // @return OK if the value was converted to a map successfully and an ID was // found. // @return InvalidArgument if the value could not be converted to a map or // there was or there is no id property in the map. static Status GetOptionsMap( const std::string& opt_value, const std::string& default_id, std::string* id, std::unordered_map* options); protected: // 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 implementation 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& opts_map, std::unordered_map* unused); // 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; // 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; // Given a name (e.g. rocksdb.my.type.opt), returns the short name (opt) virtual std::string GetOptionName(const std::string& long_name) const; // 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 void RegisterOptions( T* opt_ptr, const std::unordered_map* opt_map) { RegisterOptions(T::kName(), opt_ptr, opt_map); } void RegisterOptions( const std::string& name, void* opt_ptr, const std::unordered_map* opt_map); // Returns true if there are registered options for this Configurable object inline bool HasRegisteredOptions() const { return !options_.empty(); } 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 options_; }; } // namespace ROCKSDB_NAMESPACE