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:
parent
bac399449d
commit
89f66d4484
@ -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.
|
||||
|
@ -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
|
||||
|
293
include/rocksdb/utilities/customizable_util.h
Normal file
293
include/rocksdb/utilities/customizable_util.h
Normal 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
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user