Add customizable_util.h to the public API (#8301)

Summary:
Useful for allowing new classes to create and manage Customizable objects without using internal APIs.

Pull Request resolved: https://github.com/facebook/rocksdb/pull/8301

Reviewed By: zhichao-cao

Differential Revision: D29428303

Pulled By: mrambacher

fbshipit-source-id: 3d33d5197cc8379fe35b54d3d169f91f0dfe7a47
This commit is contained in:
mrambacher 2021-06-29 09:07:10 -07:00 committed by Facebook GitHub Bot
parent bac399449d
commit 89f66d4484
10 changed files with 398 additions and 306 deletions

View File

@ -12,6 +12,8 @@
* The new BlobDB implementation now tracks the amount of garbage in each blob file in the MANIFEST.
* Integrated BlobDB now supports Merge with base values (Put/Delete etc.).
### Public API change
* Added APIs to the Customizable class to allow developers to create their own Customizable classes. Created the utilities/customizable_util.h file to contain helper methods for developing new Customizable classes.
## 6.22.0 (2021-06-18)
### Behavior Changes
* Added two additional tickers, MEMTABLE_PAYLOAD_BYTES_AT_FLUSH and MEMTABLE_GARBAGE_BYTES_AT_FLUSH. These stats can be used to estimate the ratio of "garbage" (outdated) bytes in the memtable that are discarded at flush time.

View File

@ -138,6 +138,29 @@ class Customizable : public Configurable {
Status GetOption(const ConfigOptions& config_options, const std::string& name,
std::string* value) const override;
#endif // ROCKSDB_LITE
// Helper method for getting for parsing the opt_value into the corresponding
// options for use in potentially creating a new Customizable object (this
// method is primarily a support method for LoadSharedObject et al for new
// Customizable objects). The opt_value may be either name-value pairs
// separated by ";" (a=b; c=d), or a simple name (a). In order to create a new
// Customizable, the ID is determined by:
// - If the value is a simple name (e.g. "BlockBasedTable"), the id is this
// name;
// - Otherwise, if there is a "id=value", the id is set to "value"
// - Otherwise, if the input customizable is not null, custom->GetId is used
// - Otherwise, an error is returned.
//
// If the opt_value is name-value pairs, these pairs will be returned in
// options (without the id pair). If the ID being returned matches the ID of
// the input custom object, then the options from the input object will also
// be added to the returned options.
//
// This method returns non-OK if the ID could not be found, or if the
// opt_value could not be parsed into name-value pairs.
static Status GetOptionsMap(
const ConfigOptions& config_options, const Customizable* custom,
const std::string& opt_value, std::string* id,
std::unordered_map<std::string, std::string>* options);
// Returns the inner class when a Customizable implements a has-a (wrapped)
// relationship. Derived classes that implement a has-a must override this

View File

@ -0,0 +1,293 @@
// 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 <functional>
#include <memory>
#include <unordered_map>
#include "options/configurable_helper.h"
#include "rocksdb/convenience.h"
#include "rocksdb/customizable.h"
#include "rocksdb/status.h"
#include "rocksdb/utilities/object_registry.h"
namespace ROCKSDB_NAMESPACE {
// The FactoryFunc functions are used to create a new customizable object
// without going through the ObjectRegistry. This methodology is especially
// useful in LITE mode, where there is no ObjectRegistry. The methods take
// in an ID of the object to create and a pointer to store the created object.
// If the factory successfully recognized the input ID, the method should return
// success; otherwise false should be returned. On success, the object
// parameter contains the new object.
template <typename T>
using SharedFactoryFunc =
std::function<bool(const std::string&, std::shared_ptr<T>*)>;
template <typename T>
using UniqueFactoryFunc =
std::function<bool(const std::string&, std::unique_ptr<T>*)>;
template <typename T>
using StaticFactoryFunc = std::function<bool(const std::string&, T**)>;
// Creates a new shared customizable instance object based on the
// input parameters using the object registry.
//
// The id parameter specifies the instance class of the object to create.
// The opt_map parameter specifies the configuration of the new instance.
//
// The config_options parameter controls the process and how errors are
// returned. If ignore_unknown_options=true, unknown values are ignored during
// the configuration. If ignore_unsupported_options=true, unknown instance types
// are ignored. If invoke_prepare_options=true, the resulting instance will be
// initialized (via PrepareOptions)
//
// @param config_options Controls how the instance is created and errors are
// handled
// @param id The identifier of the new object being created. This string
// will be used by the object registry to locate the appropriate object to
// create.
// @param opt_map Optional name-value pairs of properties to set for the newly
// created object
// @param result The newly created and configured instance.
template <typename T>
static Status NewSharedObject(
const ConfigOptions& config_options, const std::string& id,
const std::unordered_map<std::string, std::string>& opt_map,
std::shared_ptr<T>* result) {
Status status;
if (!id.empty()) {
#ifndef ROCKSDB_LITE
status = config_options.registry->NewSharedObject(id, result);
#else
status = Status::NotSupported("Cannot load object in LITE mode ", id);
#endif // ROCKSDB_LITE
if (config_options.ignore_unsupported_options && status.IsNotSupported()) {
return Status::OK();
}
} else {
status = Status::NotSupported("Cannot reset object ");
}
if (!status.ok() || opt_map.empty()) {
return status;
} else if (result->get() != nullptr) {
return result->get()->ConfigureFromMap(config_options, opt_map);
} else {
return Status::InvalidArgument("Cannot configure null object ", id);
}
}
// Creates a new shared Customizable object based on the input parameters.
// This method parses the input value to determine the type of instance to
// create. If there is an existing instance (in result) and it is the same ID
// as the object being created, the existing configuration is stored and used as
// the default for the new object.
//
// The value parameter specified the instance class of the object to create.
// If it is a simple string (e.g. BlockBasedTable), then the instance will be
// created using the default settings. If the value is a set of name-value
// pairs, then the "id" value is used to determine the instance to create and
// the remaining parameters are used to configure the object. Id name-value
// pairs are specified, there should be an "id=value" pairing or an error may
// result.
//
// The config_options parameter controls the process and how errors are
// returned. If ignore_unknown_options=true, unknown values are ignored during
// the configuration. If ignore_unsupported_options=true, unknown instance types
// are ignored. If invoke_prepare_options=true, the resulting instance will be
// initialized (via PrepareOptions)
//
// @param config_options Controls how the instance is created and errors are
// handled
// @param value Either the simple name of the instance to create, or a set of
// name-value pairs to create and initailize the object
// @param func Optional function to call to attempt to create an instance
// @param result The newly created instance.
template <typename T>
static Status LoadSharedObject(const ConfigOptions& config_options,
const std::string& value,
const SharedFactoryFunc<T>& func,
std::shared_ptr<T>* result) {
std::string id;
std::unordered_map<std::string, std::string> opt_map;
Status status = Customizable::GetOptionsMap(config_options, result->get(),
value, &id, &opt_map);
if (!status.ok()) { // GetOptionsMap failed
return status;
} else if (func == nullptr ||
!func(id, result)) { // No factory, or it failed
if (value.empty()) { // No Id and no options. Clear the object
*result = nullptr;
return Status::OK();
} else {
return NewSharedObject(config_options, id, opt_map, result);
}
} else if (opt_map.empty()) {
return status;
} else if (result->get() != nullptr) {
return result->get()->ConfigureFromMap(config_options, opt_map);
} else {
return Status::InvalidArgument("Cannot configure null object ");
}
}
// Creates a new unique pointer customizable instance object based on the
// input parameters using the object registry.
// @see NewSharedObject for more information on the inner workings of this
// method.
//
// @param config_options Controls how the instance is created and errors are
// handled
// @param id The identifier of the new object being created. This string
// will be used by the object registry to locate the appropriate object to
// create.
// @param opt_map Optional name-value pairs of properties to set for the newly
// created object
// @param result The newly created and configured instance.
template <typename T>
static Status NewUniqueObject(
const ConfigOptions& config_options, const std::string& id,
const std::unordered_map<std::string, std::string>& opt_map,
std::unique_ptr<T>* result) {
Status status;
if (id.empty()) {
status = Status::NotSupported("Cannot reset object ");
} else {
#ifndef ROCKSDB_LITE
status = config_options.registry->NewUniqueObject(id, result);
#else
status = Status::NotSupported("Cannot load object in LITE mode ", id);
#endif // ROCKSDB_LITE
if (config_options.ignore_unsupported_options && status.IsNotSupported()) {
return Status::OK();
}
}
if (!status.ok() || opt_map.empty()) {
return status;
} else if (result->get() != nullptr) {
return result->get()->ConfigureFromMap(config_options, opt_map);
} else {
return Status::InvalidArgument("Cannot configure null object ");
}
}
// Creates a new unique customizable instance object based on the input
// parameters.
// @see LoadSharedObject for more information on the inner workings of this
// method.
//
// @param config_options Controls how the instance is created and errors are
// handled
// @param value Either the simple name of the instance to create, or a set of
// name-value pairs to create and initailize the object
// @param func Optional function to call to attempt to create an instance
// @param result The newly created instance.
template <typename T>
static Status LoadUniqueObject(const ConfigOptions& config_options,
const std::string& value,
const UniqueFactoryFunc<T>& func,
std::unique_ptr<T>* result) {
std::string id;
std::unordered_map<std::string, std::string> opt_map;
Status status = Customizable::GetOptionsMap(config_options, result->get(),
value, &id, &opt_map);
if (!status.ok()) { // GetOptionsMap failed
return status;
} else if (func == nullptr ||
!func(id, result)) { // No factory, or it failed
if (value.empty()) { // No Id and no options. Clear the object
*result = nullptr;
return Status::OK();
} else {
return NewUniqueObject(config_options, id, opt_map, result);
}
} else if (opt_map.empty()) {
return status;
} else if (result->get() != nullptr) {
return result->get()->ConfigureFromMap(config_options, opt_map);
} else {
return Status::InvalidArgument("Cannot configure null object ");
}
}
// Creates a new static (raw pointer) customizable instance object based on the
// input parameters using the object registry.
// @see NewSharedObject for more information on the inner workings of this
// method.
//
// @param config_options Controls how the instance is created and errors are
// handled
// @param id The identifier of the new object being created. This string
// will be used by the object registry to locate the appropriate object to
// create.
// @param opt_map Optional name-value pairs of properties to set for the newly
// created object
// @param result The newly created and configured instance.
template <typename T>
static Status NewStaticObject(
const ConfigOptions& config_options, const std::string& id,
const std::unordered_map<std::string, std::string>& opt_map, T** result) {
Status status;
if (id.empty()) {
status = Status::NotSupported("Cannot reset object ");
} else {
#ifndef ROCKSDB_LITE
status = config_options.registry->NewStaticObject(id, result);
#else
status = Status::NotSupported("Cannot load object in LITE mode ", id);
#endif // ROCKSDB_LITE
if (config_options.ignore_unsupported_options && status.IsNotSupported()) {
return Status::OK();
}
}
if (!status.ok() || opt_map.empty()) {
return status;
} else if (*result != nullptr) {
return (*result)->ConfigureFromMap(config_options, opt_map);
} else {
return Status::InvalidArgument("Cannot configure null object ");
}
}
// Creates a new static (raw pointer) customizable instance object based on the
// input parameters.
// @see LoadSharedObject for more information on the inner workings of this
// method.
//
// @param config_options Controls how the instance is created and errors are
// handled
// @param value Either the simple name of the instance to create, or a set of
// name-value pairs to create and initailize the object
// @param func Optional function to call to attempt to create an instance
// @param result The newly created instance.
template <typename T>
static Status LoadStaticObject(const ConfigOptions& config_options,
const std::string& value,
const StaticFactoryFunc<T>& func, T** result) {
std::string id;
std::unordered_map<std::string, std::string> opt_map;
Status status = Customizable::GetOptionsMap(config_options, *result, value,
&id, &opt_map);
if (!status.ok()) { // GetOptionsMap failed
return status;
} else if (func == nullptr ||
!func(id, result)) { // No factory, or it failed
if (value.empty()) { // No Id and no options. Clear the object
*result = nullptr;
return Status::OK();
} else {
return NewStaticObject(config_options, id, opt_map, result);
}
} else if (opt_map.empty()) {
return status;
} else if (*result != nullptr) {
return (*result)->ConfigureFromMap(config_options, opt_map);
} else {
return Status::InvalidArgument("Cannot configure null object ");
}
}
} // namespace ROCKSDB_NAMESPACE

View File

@ -398,10 +398,9 @@ Status ConfigurableHelper::ConfigureCustomizableOption(
if (opt_info.IsMutable() || !config_options.mutable_options_only) {
// Either the option is mutable, or we are processing all of the options
if (opt_name == name ||
EndsWith(opt_name, ConfigurableHelper::kIdPropSuffix) ||
name == ConfigurableHelper::kIdPropName) {
return configurable.ParseOption(copy, opt_info, opt_name, value, opt_ptr);
if (opt_name == name || name == ConfigurableHelper::kIdPropName ||
EndsWith(opt_name, ConfigurableHelper::kIdPropSuffix)) {
return configurable.ParseOption(copy, opt_info, name, value, opt_ptr);
} else if (value.empty()) {
return Status::OK();
} else if (custom == nullptr || !StartsWith(name, custom->GetId() + ".")) {
@ -480,32 +479,6 @@ Status ConfigurableHelper::ConfigureOption(
}
#endif // ROCKSDB_LITE
Status ConfigurableHelper::ConfigureNewObject(
const ConfigOptions& config_options_in, Configurable* object,
const std::string& id, const std::string& base_opts,
const std::unordered_map<std::string, std::string>& opts) {
if (object != nullptr) {
ConfigOptions config_options = config_options_in;
config_options.invoke_prepare_options = false;
if (!base_opts.empty()) {
#ifndef ROCKSDB_LITE
// Don't run prepare options on the base, as we would do that on the
// overlay opts instead
Status status = object->ConfigureFromString(config_options, base_opts);
if (!status.ok()) {
return status;
}
#endif // ROCKSDB_LITE
}
if (!opts.empty()) {
return object->ConfigureFromMap(config_options, opts);
}
} else if (!opts.empty()) { // No object but no map. This is OK
return Status::InvalidArgument("Cannot configure null object ", id);
}
return Status::OK();
}
//*******************************************************************************
//
// Methods for Converting Options into strings
@ -744,16 +717,6 @@ bool ConfigurableHelper::AreEquivalent(const ConfigOptions& config_options,
}
#endif // ROCKSDB_LITE
Status ConfigurableHelper::GetOptionsMap(
const std::string& value, const Customizable* customizable, std::string* id,
std::unordered_map<std::string, std::string>* props) {
if (customizable != nullptr) {
return GetOptionsMap(value, customizable->GetId(), id, props);
} else {
return GetOptionsMap(value, "", id, props);
}
}
Status ConfigurableHelper::GetOptionsMap(
const std::string& value, const std::string& default_id, std::string* id,
std::unordered_map<std::string, std::string>* props) {

View File

@ -48,22 +48,6 @@ class ConfigurableHelper {
const std::unordered_map<std::string, std::string>& options,
std::unordered_map<std::string, std::string>* unused);
// Helper method for configuring a new customizable object.
// If base_opts are set, this is the "default" options to use for the new
// object. Then any values in "new_opts" are applied to the object.
// Returns OK if the object could be successfully configured
// @return NotFound If any of the names in the base or new opts were not valid
// for this object.
// @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.
static Status ConfigureNewObject(
const ConfigOptions& config_options, Configurable* object,
const std::string& id, const std::string& base_opts,
const std::unordered_map<std::string, std::string>& new_opts);
// 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
@ -78,9 +62,6 @@ class ConfigurableHelper {
// 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 Customizable* custom, std::string* id,
std::unordered_map<std::string, std::string>* options);
static Status GetOptionsMap(
const std::string& opt_value, const std::string& default_id,
std::string* id, std::unordered_map<std::string, std::string>* options);

View File

@ -6,6 +6,7 @@
#include "rocksdb/customizable.h"
#include "options/configurable_helper.h"
#include "options/options_helper.h"
#include "rocksdb/convenience.h"
#include "rocksdb/status.h"
#include "util/string_util.h"
@ -74,4 +75,33 @@ bool Customizable::AreEquivalent(const ConfigOptions& config_options,
return true;
}
Status Customizable::GetOptionsMap(
const ConfigOptions& config_options, const Customizable* customizable,
const std::string& value, std::string* id,
std::unordered_map<std::string, std::string>* props) {
if (customizable != nullptr) {
Status status = ConfigurableHelper::GetOptionsMap(
value, customizable->GetId(), id, props);
#ifdef ROCKSDB_LITE
(void)config_options;
#else
if (status.ok() && customizable->IsInstanceOf(*id)) {
// The new ID and the old ID match, so the objects are the same type.
// Try to get the existing options, ignoring any errors
ConfigOptions embedded = config_options;
embedded.delimiter = ";";
std::string curr_opts;
if (customizable->GetOptionString(embedded, &curr_opts).ok()) {
std::unordered_map<std::string, std::string> curr_props;
if (StringToMap(curr_opts, &curr_props).ok()) {
props->insert(curr_props.begin(), curr_props.end());
}
}
}
#endif // ROCKSDB_LITE
return status;
} else {
return ConfigurableHelper::GetOptionsMap(value, "", id, props);
}
}
} // namespace ROCKSDB_NAMESPACE

View File

@ -1,221 +0,0 @@
// 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 <functional>
#include <memory>
#include <unordered_map>
#include "options/configurable_helper.h"
#include "rocksdb/convenience.h"
#include "rocksdb/customizable.h"
#include "rocksdb/status.h"
#include "rocksdb/utilities/object_registry.h"
namespace ROCKSDB_NAMESPACE {
template <typename T>
using SharedFactoryFunc =
std::function<bool(const std::string&, std::shared_ptr<T>*)>;
template <typename T>
using UniqueFactoryFunc =
std::function<bool(const std::string&, std::unique_ptr<T>*)>;
template <typename T>
using StaticFactoryFunc = std::function<bool(const std::string&, T**)>;
// Creates a new shared Customizable object based on the input parameters.
// This method parses the input value to determine the type of instance to
// create. If there is an existing instance (in result) and it is the same type
// as the object being created, the existing configuration is stored and used as
// the default for the new object.
//
// The value parameter specified the instance class of the object to create.
// If it is a simple string (e.g. BlockBasedTable), then the instance will be
// created using the default settings. If the value is a set of name-value
// pairs, then the "id" value is used to determine the instance to create and
// the remaining parameters are used to configure the object. Id name-value
// pairs are specified, there must be an "id=value" pairing or an error will
// result.
//
// The config_options parameter controls the process and how errors are
// returned. If ignore_unknown_options=true, unknown values are ignored during
// the configuration If ignore_unsupported_options=true, unknown instance types
// are ignored If invoke_prepare_options=true, the resulting instance wll be
// initialized (via PrepareOptions
//
// @param config_options Controls how the instance is created and errors are
// handled
// @param value Either the simple name of the instance to create, or a set of
// name-value pairs to
// create and initailzie the object
// @param func Optional function to call to attempt to create an instance
// @param result The newly created instance.
template <typename T>
static Status LoadSharedObject(const ConfigOptions& config_options,
const std::string& value,
const SharedFactoryFunc<T>& func,
std::shared_ptr<T>* result) {
std::string id;
std::unordered_map<std::string, std::string> opt_map;
Status status =
ConfigurableHelper::GetOptionsMap(value, result->get(), &id, &opt_map);
if (!status.ok()) { // GetOptionsMap failed
return status;
}
std::string curr_opts;
#ifndef ROCKSDB_LITE
if (result->get() != nullptr && result->get()->GetId() == id) {
// Try to get the existing options, ignoring any errors
ConfigOptions embedded = config_options;
embedded.delimiter = ";";
result->get()->GetOptionString(embedded, &curr_opts).PermitUncheckedError();
}
#endif
if (func == nullptr || !func(id, result)) { // No factory, or it failed
if (value.empty()) {
// No Id and no options. Clear the object
result->reset();
return Status::OK();
} else if (id.empty()) { // We have no Id but have options. Not good
return Status::NotSupported("Cannot reset object ", id);
} else {
#ifndef ROCKSDB_LITE
status = config_options.registry->NewSharedObject(id, result);
#else
status = Status::NotSupported("Cannot load object in LITE mode ", id);
#endif
if (!status.ok()) {
if (config_options.ignore_unsupported_options &&
status.IsNotSupported()) {
return Status::OK();
} else {
return status;
}
}
}
}
return ConfigurableHelper::ConfigureNewObject(config_options, result->get(),
id, curr_opts, opt_map);
}
// Creates a new unique customizable instance object based on the input
// parameters.
// @see LoadSharedObject for more information on the inner workings of this
// method.
//
// @param config_options Controls how the instance is created and errors are
// handled
// @param value Either the simple name of the instance to create, or a set of
// name-value pairs to
// create and initailzie the object
// @param func Optional function to call to attempt to create an instance
// @param result The newly created instance.
template <typename T>
static Status LoadUniqueObject(const ConfigOptions& config_options,
const std::string& value,
const UniqueFactoryFunc<T>& func,
std::unique_ptr<T>* result) {
std::string id;
std::unordered_map<std::string, std::string> opt_map;
Status status =
ConfigurableHelper::GetOptionsMap(value, result->get(), &id, &opt_map);
if (!status.ok()) { // GetOptionsMap failed
return status;
}
std::string curr_opts;
#ifndef ROCKSDB_LITE
if (result->get() != nullptr && result->get()->GetId() == id) {
// Try to get the existing options, ignoring any errors
ConfigOptions embedded = config_options;
embedded.delimiter = ";";
result->get()->GetOptionString(embedded, &curr_opts).PermitUncheckedError();
}
#endif
if (func == nullptr || !func(id, result)) { // No factory, or it failed
if (value.empty()) {
// No Id and no options. Clear the object
result->reset();
return Status::OK();
} else if (id.empty()) { // We have no Id but have options. Not good
return Status::NotSupported("Cannot reset object ", id);
} else {
#ifndef ROCKSDB_LITE
status = config_options.registry->NewUniqueObject(id, result);
#else
status = Status::NotSupported("Cannot load object in LITE mode ", id);
#endif // ROCKSDB_LITE
if (!status.ok()) {
if (config_options.ignore_unsupported_options &&
status.IsNotSupported()) {
return Status::OK();
} else {
return status;
}
}
}
}
return ConfigurableHelper::ConfigureNewObject(config_options, result->get(),
id, curr_opts, opt_map);
}
// Creates a new static (raw pointer) customizable instance object based on the
// input parameters.
// @see LoadSharedObject for more information on the inner workings of this
// method.
//
// @param config_options Controls how the instance is created and errors are
// handled
// @param value Either the simple name of the instance to create, or a set of
// name-value pairs to
// create and initailzie the object
// @param func Optional function to call to attempt to create an instance
// @param result The newly created instance.
template <typename T>
static Status LoadStaticObject(const ConfigOptions& config_options,
const std::string& value,
const StaticFactoryFunc<T>& func, T** result) {
std::string id;
std::unordered_map<std::string, std::string> opt_map;
Status status =
ConfigurableHelper::GetOptionsMap(value, *result, &id, &opt_map);
if (!status.ok()) { // GetOptionsMap failed
return status;
}
std::string curr_opts;
#ifndef ROCKSDB_LITE
if (*result != nullptr && (*result)->GetId() == id) {
// Try to get the existing options, ignoring any errors
ConfigOptions embedded = config_options;
embedded.delimiter = ";";
(*result)->GetOptionString(embedded, &curr_opts).PermitUncheckedError();
}
#endif
if (func == nullptr || !func(id, result)) { // No factory, or it failed
if (value.empty()) {
// No Id and no options. Clear the object
*result = nullptr;
return Status::OK();
} else if (id.empty()) { // We have no Id but have options. Not good
return Status::NotSupported("Cannot reset object ", id);
} else {
#ifndef ROCKSDB_LITE
status = config_options.registry->NewStaticObject(id, result);
#else
status = Status::NotSupported("Cannot load object in LITE mode ", id);
#endif // ROCKSDB_LITE
if (!status.ok()) {
if (config_options.ignore_unsupported_options &&
status.IsNotSupported()) {
return Status::OK();
} else {
return status;
}
}
}
}
return ConfigurableHelper::ConfigureNewObject(config_options, *result, id,
curr_opts, opt_map);
}
} // namespace ROCKSDB_NAMESPACE

View File

@ -15,10 +15,10 @@
#include <unordered_map>
#include "options/configurable_helper.h"
#include "options/customizable_helper.h"
#include "options/options_helper.h"
#include "options/options_parser.h"
#include "rocksdb/convenience.h"
#include "rocksdb/utilities/customizable_util.h"
#include "rocksdb/utilities/object_registry.h"
#include "rocksdb/utilities/options_type.h"
#include "table/mock_table.h"
@ -607,6 +607,9 @@ TEST_F(CustomizableTest, NewCustomizableTest) {
ASSERT_OK(base->ConfigureFromString(config_options_,
"unique={id=A_1;int=1;bool=false}"));
ASSERT_EQ(A_count, 2); // Create another A_1
ASSERT_OK(base->ConfigureFromString(config_options_, "unique={id=}"));
ASSERT_EQ(simple->cu, nullptr);
ASSERT_EQ(A_count, 2);
ASSERT_OK(base->ConfigureFromString(config_options_,
"unique={id=A_2;int=1;bool=false}"));
ASSERT_EQ(A_count, 3); // Created another A

View File

@ -3,35 +3,62 @@
// 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/customizable_helper.h"
#include <mutex>
#include "rocksdb/convenience.h"
#include "rocksdb/table.h"
#include "rocksdb/utilities/customizable_util.h"
#include "rocksdb/utilities/object_registry.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 {
static void RegisterTableFactories(const std::string& /*arg*/) {
#ifndef ROCKSDB_LITE
static std::once_flag loaded;
std::call_once(loaded, []() {
auto library = ObjectLibrary::Default();
library->Register<TableFactory>(
TableFactory::kBlockBasedTableName(),
[](const std::string& /*uri*/, std::unique_ptr<TableFactory>* guard,
std::string* /* errmsg */) {
guard->reset(new BlockBasedTableFactory());
return guard->get();
});
library->Register<TableFactory>(
TableFactory::kPlainTableName(),
[](const std::string& /*uri*/, std::unique_ptr<TableFactory>* guard,
std::string* /* errmsg */) {
guard->reset(new PlainTableFactory());
return guard->get();
});
library->Register<TableFactory>(
TableFactory::kCuckooTableName(),
[](const std::string& /*uri*/, std::unique_ptr<TableFactory>* guard,
std::string* /* errmsg */) {
guard->reset(new CuckooTableFactory());
return guard->get();
});
});
#endif // ROCKSDB_LITE
}
static bool LoadFactory(const std::string& name,
std::shared_ptr<TableFactory>* factory) {
bool success = true;
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
return true;
} else {
success = false;
return false;
}
return success;
}
Status TableFactory::CreateFromString(const ConfigOptions& config_options,
const std::string& value,
std::shared_ptr<TableFactory>* factory) {
RegisterTableFactories("");
return LoadSharedObject<TableFactory>(config_options, value, LoadFactory,
factory);
}

View File

@ -15,9 +15,10 @@
#include <memory>
#include <mutex>
#include "options/configurable_helper.h"
#include "port/port.h"
#include "rocksdb/convenience.h"
#include "rocksdb/slice.h"
#include "rocksdb/utilities/customizable_util.h"
#include "rocksdb/utilities/object_registry.h"
namespace ROCKSDB_NAMESPACE {
@ -255,20 +256,11 @@ Status Comparator::CreateFromString(const ConfigOptions& config_options,
#endif // ROCKSDB_LITE
std::string id;
std::unordered_map<std::string, std::string> opt_map;
Status status =
ConfigurableHelper::GetOptionsMap(value, *result, &id, &opt_map);
Status status = Customizable::GetOptionsMap(config_options, *result, value,
&id, &opt_map);
if (!status.ok()) { // GetOptionsMap failed
return status;
}
std::string curr_opts;
#ifndef ROCKSDB_LITE
if (*result != nullptr && (*result)->GetId() == id) {
// Try to get the existing options, ignoring any errors
ConfigOptions embedded = config_options;
embedded.delimiter = ";";
(*result)->GetOptionString(embedded, &curr_opts).PermitUncheckedError();
}
#endif
if (id == BytewiseComparatorImpl::kClassName()) {
*result = BytewiseComparator();
} else if (id == ReverseBytewiseComparatorImpl::kClassName()) {
@ -292,10 +284,9 @@ Status Comparator::CreateFromString(const ConfigOptions& config_options,
} else {
return status;
}
} else if (!curr_opts.empty() || !opt_map.empty()) {
} else if (!opt_map.empty()) {
Comparator* comparator = const_cast<Comparator*>(*result);
status = ConfigurableHelper::ConfigureNewObject(
config_options, comparator, id, curr_opts, opt_map);
status = comparator->ConfigureFromMap(config_options, opt_map);
}
}
return status;