Skip to content

The Customizable Class

mrambacher edited this page Nov 5, 2020 · 9 revisions

RocksDB provides a robust plugin architecture, allowing the developers and community to create custom extensions to various classes. For example, RocksDB supports different versions of the TableFactory (PlainTable, BlockBasedTable, CuckooTable) and Env (PosixEnv, MemoryEnv, HDFSEnv, EncryptedEnv, etc). The developer is encouraged to write plugins for various RocksDB features, such as CompactionFilter, MergeOperator, and Comparator.

What has been lacking up until now is a standard way of creating and configuring these various object classes. The Customizable class is meant to address many of those issues. By inheriting from the Configurable class, Customizable objects are naturally configurable, giving the ability to configure and serialize customizable objects to the Options file without additional effort. The Customizable class provides a common framework for identifying and creating instances of these objects.

Over time, more of these classes will be converted into Customizable classes. This conversion will allow more and more alternative implementations to be available to the user and developer via simple configuration changes.

The Interface Class

An Interface class inherits from Customizable class and provides a set of often abstract methods for the functionality of the class. Examples of interface classes include TableFactory and Env.

In addition to inheriting from Customizable, customizable interface classes must implement a static Type and CreateFromString method.

The Interface Type Method

The static const char *Type method returns a string uniquely identifying this interface class (often this string will be the name of the interface, (e.g. static const char *Type() { return "TableFactory"; }. Each interface must provide a unique type name. The Type method is used by the ObjectRegistry to locate potential factories for instances of this class.

CreateFromString

The Status CreateFromString(const ConfigOptions&, const std::string& id, T*) method is the factory method used to create a new instance of an object of this type. The CreateFromString method can create a configure a new instance of the given interface based on the input id. All Customizable interface classes should have a CreateFromString method with this signature, only varying the type of the final argument.

The input id string can be a simple string (e.g. BlockBasedTable) identifying the name of the instance class to be created. Alternatively, the id could be a set of name-value properties -- separated by a ";" -- that denote which instance class to create and configuration parameters. For example, 'id=BlockBasedTable; block_size=8192', would create a BlockBasedTableFactory and initialize the BlockBasedTableOptions.block_size=8192.

The final argument to CreateFromString returns the newly created object. Depending on the interface, this may be a raw (T** result), shared (std::shared_ptr<T> *result), or unique (std::unique_ptr<T*>) pointer. On success, this will be the newly created object.

The ConfigOptions parameter controls the behavior of the CreateFromString method. For example, if `ignore_unknown_options=true', then errors will not be reported if the options.

The CreateFromString method should support both "built-in" and "registered" objects. The "built-in" types are built into RocksDB and are always available. The "registered" types are factories registered with the ObjectRegistry known at run-time. Helper methods are defined in options/customizable_helper.h to make it easier to write the CreateFromString factories.

Instance Classes

Instance classes provide the implementation of the methods in the Interface classes (e.g. BlockBasedTableFactory and PlainTableFactory are instances of the TableFactory interface. In addition to providing the functionality required by the interface, Instance classes must implement the const char *Name() const method. This method specifies the name of this instance class (e.g., "BlockBasedTable") and is used for creating an instance of this class and will be found in the options files.

Instance classes are strongly encouraged to provide a static const char *kClassName() method. This method returns the name of the class for this instance and is used by the reflection classes, described below. A good programming practice would be to write the kName and kClassName methods with respect to each other: static const char *kClassName() { return "PosixEnv"; } const char *kName() const override { return kClassName(); }

For some interfaces, the instance names may be required more globally (and not simply be members of the instance class). For those names, it is recommended that a static name method be added to the interface class and referred to in the instance class: class TableFactory .... static const char *kBlockBasedTableName() { return "BlockBasedTable"; } }; class BlockBasedTableFactory ... static const char *kClassName() { return kBlockBasedTableName(); } const char *kName() const override { return kClassName(); } }; Note that because of issues with C++ initialization and compilation units, the use of static const char* member variables is not recommended and may not be portable.

Advanced Customizable Properties

The Customizable class provides a GetId() method. By default, the GetId() method returns the Name() of the instance class. This method can be overridden by classes that wish to provide something different. For example, an HDFSEnv might specify its id to also include information about the environment. Note that the Id is written to the Options file and is what is used by CreateFromString, so the Id must be recognizable to create new instances.

The IsInstanceOf' method can be used to tell if a given object is an instance of the input name. Typically, this is equivalent to checking if the instance name is equivalent to the class name. However, there may be some classes that are intermediary classes (like a LRUCacheis an instance of aShardedCacheas well). In this case, the intermediary class should implementIsInstanceOf` to add itself to the check.

The Customizable base class provides reflection-like functionality via the CastAs<T> method. This method is useful if a specific implementation of the customizable is required. For example: std::shared_ptr table_factory; Status s = TableFactory::CreateFromString(ConfigOptions(), "BlockBasedTable", &table_factory); auto bbtf = table_factory->CastAs(); This example will set bbtf to the BlockBasedTableFactory. Of the table_factory was not block-based, bbtf would be set to nullptr.

Contents

Clone this wiki locally