Summary: The Env registration framework supports registering client Envs and selecting which one to instantiate according to a text field. This enabled things like adding the -env_uri argument to db_bench, so the same binary could be reused with different Envs just by changing CLI config. Now this problem has come up again in a non-Env context, as I want to instantiate a client Statistics implementation from db_bench, which is configured entirely via text parameters. Also, in the future we may wish to use it for deserializing client objects when loading OPTIONS file. This diff generalizes the Env registration logic to work with arbitrary types. - Generalized registration and instantiation code by templating them - The entire implementation is in a header file as that's Google style guide's recommendation for template definitions - Pattern match with std::regex_match rather than checking prefix, which was the previous behavior - Rename functions/files to be non-Env-specific Closes https://github.com/facebook/rocksdb/pull/1776 Differential Revision: D4421933 Pulled By: ajkr fbshipit-source-id: 34647d1main
parent
07dddd5f7e
commit
17c1180603
@ -1,45 +0,0 @@ |
|||||||
// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
|
|
||||||
// This source code is licensed under the BSD-style license found in the
|
|
||||||
// LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
// of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
|
|
||||||
#pragma once |
|
||||||
|
|
||||||
#ifndef ROCKSDB_LITE |
|
||||||
|
|
||||||
#include <functional> |
|
||||||
#include <memory> |
|
||||||
#include <string> |
|
||||||
|
|
||||||
#include "rocksdb/env.h" |
|
||||||
|
|
||||||
namespace rocksdb { |
|
||||||
|
|
||||||
// Returns a new Env when called with a URI string. Populates the unique_ptr
|
|
||||||
// argument if granting ownership to caller.
|
|
||||||
typedef std::function<Env*(const std::string&, std::unique_ptr<Env>*)> |
|
||||||
EnvFactoryFunc; |
|
||||||
|
|
||||||
// Creates a new Env using the registered factory function corresponding to a
|
|
||||||
// prefix of uri.
|
|
||||||
//
|
|
||||||
// If no prefixes match, returns nullptr. If multiple prefixes match, the
|
|
||||||
// factory function used is unspecified.
|
|
||||||
//
|
|
||||||
// Populates env_guard with result pointer if caller is granted ownership.
|
|
||||||
Env* NewEnvFromUri(const std::string& uri, std::unique_ptr<Env>* env_guard); |
|
||||||
|
|
||||||
// To register an Env factory function, initialize an EnvRegistrar object with
|
|
||||||
// static storage duration. For example:
|
|
||||||
//
|
|
||||||
// static EnvRegistrar hdfs_reg("hdfs://", &CreateHdfsEnv);
|
|
||||||
//
|
|
||||||
// Then, calling NewEnvFromUri("hdfs://some_path", ...) will use CreateHdfsEnv
|
|
||||||
// to make a new Env.
|
|
||||||
class EnvRegistrar { |
|
||||||
public: |
|
||||||
explicit EnvRegistrar(std::string uri_prefix, EnvFactoryFunc env_factory); |
|
||||||
}; |
|
||||||
|
|
||||||
} // namespace rocksdb
|
|
||||||
#endif // ROCKSDB_LITE
|
|
@ -0,0 +1,90 @@ |
|||||||
|
// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
|
||||||
|
// This source code is licensed under the BSD-style license found in the
|
||||||
|
// LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
// of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
|
||||||
|
#pragma once |
||||||
|
|
||||||
|
#ifndef ROCKSDB_LITE |
||||||
|
|
||||||
|
#include <functional> |
||||||
|
#include <memory> |
||||||
|
#include <regex> |
||||||
|
#include <string> |
||||||
|
#include <vector> |
||||||
|
|
||||||
|
#include "rocksdb/env.h" |
||||||
|
|
||||||
|
namespace rocksdb { |
||||||
|
|
||||||
|
// Creates a new T using the factory function that was registered with a pattern
|
||||||
|
// that matches the provided "target" string according to std::regex_match.
|
||||||
|
//
|
||||||
|
// If no registered functions match, returns nullptr. If multiple functions
|
||||||
|
// match, the factory function used is unspecified.
|
||||||
|
//
|
||||||
|
// Populates res_guard with result pointer if caller is granted ownership.
|
||||||
|
template <typename T> |
||||||
|
T* NewCustomObject(const std::string& target, std::unique_ptr<T>* res_guard); |
||||||
|
|
||||||
|
// Returns a new T when called with a string. Populates the unique_ptr argument
|
||||||
|
// if granting ownership to caller.
|
||||||
|
template <typename T> |
||||||
|
using FactoryFunc = std::function<T*(const std::string&, std::unique_ptr<T>*)>; |
||||||
|
|
||||||
|
// To register a factory function for a type T, initialize a Registrar<T> object
|
||||||
|
// with static storage duration. For example:
|
||||||
|
//
|
||||||
|
// static Registrar<Env> hdfs_reg("hdfs://.*", &CreateHdfsEnv);
|
||||||
|
//
|
||||||
|
// Then, calling NewCustomObject<Env>("hdfs://some_path", ...) will match the
|
||||||
|
// regex provided above, so it returns the result of invoking CreateHdfsEnv.
|
||||||
|
template <typename T> |
||||||
|
class Registrar { |
||||||
|
public: |
||||||
|
explicit Registrar(std::string pattern, FactoryFunc<T> factory); |
||||||
|
}; |
||||||
|
|
||||||
|
// Implementation details follow.
|
||||||
|
|
||||||
|
namespace internal { |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
struct RegistryEntry { |
||||||
|
std::regex pattern; |
||||||
|
FactoryFunc<T> factory; |
||||||
|
}; |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
struct Registry { |
||||||
|
static Registry* Get() { |
||||||
|
static Registry<T> instance; |
||||||
|
return &instance; |
||||||
|
} |
||||||
|
std::vector<RegistryEntry<T>> entries; |
||||||
|
|
||||||
|
private: |
||||||
|
Registry() = default; |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
template <typename T> |
||||||
|
T* NewCustomObject(const std::string& target, std::unique_ptr<T>* res_guard) { |
||||||
|
res_guard->reset(); |
||||||
|
for (const auto& entry : internal::Registry<T>::Get()->entries) { |
||||||
|
if (std::regex_match(target, entry.pattern)) { |
||||||
|
return entry.factory(target, res_guard); |
||||||
|
} |
||||||
|
} |
||||||
|
return nullptr; |
||||||
|
} |
||||||
|
|
||||||
|
template <typename T> |
||||||
|
Registrar<T>::Registrar(std::string pattern, FactoryFunc<T> factory) { |
||||||
|
internal::Registry<T>::Get()->entries.emplace_back(internal::RegistryEntry<T>{ |
||||||
|
std::regex(std::move(pattern)), std::move(factory)}); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace rocksdb
|
||||||
|
#endif // ROCKSDB_LITE
|
@ -1,47 +0,0 @@ |
|||||||
// Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
|
|
||||||
// This source code is licensed under the BSD-style license found in the
|
|
||||||
// LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
// of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
|
|
||||||
#ifndef ROCKSDB_LITE |
|
||||||
|
|
||||||
#include "rocksdb/utilities/env_registry.h" |
|
||||||
|
|
||||||
#include <map> |
|
||||||
#include <string> |
|
||||||
|
|
||||||
namespace rocksdb { |
|
||||||
|
|
||||||
struct EnvRegistryEntry { |
|
||||||
std::string prefix; |
|
||||||
EnvFactoryFunc env_factory; |
|
||||||
}; |
|
||||||
|
|
||||||
struct EnvRegistry { |
|
||||||
static EnvRegistry* Get() { |
|
||||||
static EnvRegistry instance; |
|
||||||
return &instance; |
|
||||||
} |
|
||||||
std::vector<EnvRegistryEntry> entries; |
|
||||||
|
|
||||||
private: |
|
||||||
EnvRegistry() = default; |
|
||||||
}; |
|
||||||
|
|
||||||
Env* NewEnvFromUri(const std::string& uri, std::unique_ptr<Env>* env_guard) { |
|
||||||
env_guard->reset(); |
|
||||||
for (const auto& entry : EnvRegistry::Get()->entries) { |
|
||||||
if (uri.compare(0, entry.prefix.size(), entry.prefix) == 0) { |
|
||||||
return entry.env_factory(uri, env_guard); |
|
||||||
} |
|
||||||
} |
|
||||||
return nullptr; |
|
||||||
} |
|
||||||
|
|
||||||
EnvRegistrar::EnvRegistrar(std::string uri_prefix, EnvFactoryFunc env_factory) { |
|
||||||
EnvRegistry::Get()->entries.emplace_back( |
|
||||||
EnvRegistryEntry{std::move(uri_prefix), std::move(env_factory)}); |
|
||||||
} |
|
||||||
|
|
||||||
} // namespace rocksdb
|
|
||||||
#endif // ROCKSDB_LITE
|
|
Loading…
Reference in new issue