Added GetFactoryCount/Names/Types to ObjectRegistry (#9358)

Summary:
These methods allow for more thorough testing of the ObjectRegistry and Customizable infrastructure in a simpler manner.  With this change, the Customizable tests can now check what factories are registered and attempt to create each of them in a systematic fashion.

With this change, I think all of the factories registered with the ObjectRegistry/CreateFromString are now tested via the customizable_test classes.

Note that there were a few other minor changes.  There was a "posix://*" register with the ObjectRegistry which was missed during the PatternEntry conversion -- these changes found that.  The nickname and default names for the FileSystem classes was also inverted.

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

Reviewed By: pdillinger

Differential Revision: D33433542

Pulled By: mrambacher

fbshipit-source-id: 9a32da74e6620745b4eeffb2712be70eeeadfa7e
This commit is contained in:
mrambacher 2022-05-16 09:44:43 -07:00 committed by Facebook GitHub Bot
parent c4cd8e1acc
commit 204a42ca97
13 changed files with 596 additions and 336 deletions

View File

@ -1139,6 +1139,15 @@ CTREncryptionProvider::CTREncryptionProvider(
RegisterOptions("Cipher", &cipher_, &ctr_encryption_provider_type_info); RegisterOptions("Cipher", &cipher_, &ctr_encryption_provider_type_info);
} }
bool CTREncryptionProvider::IsInstanceOf(const std::string& name) const {
// Special case for test purposes.
if (name == "1://test" && cipher_ != nullptr) {
return cipher_->IsInstanceOf(ROT13BlockCipher::kClassName());
} else {
return EncryptionProvider::IsInstanceOf(name);
}
}
// GetPrefixLength returns the length of the prefix that is added to every file // GetPrefixLength returns the length of the prefix that is added to every file
// and used for storing encryption options. // and used for storing encryption options.
// For optimal performance, the prefix length should be a multiple of // For optimal performance, the prefix length should be a multiple of

View File

@ -66,7 +66,7 @@ class CTREncryptionProvider : public EncryptionProvider {
static const char* kClassName() { return "CTR"; } static const char* kClassName() { return "CTR"; }
const char* Name() const override { return kClassName(); } const char* Name() const override { return kClassName(); }
bool IsInstanceOf(const std::string& name) const override;
// GetPrefixLength returns the length of the prefix that is added to every // GetPrefixLength returns the length of the prefix that is added to every
// file // file
// and used for storing encryption options. // and used for storing encryption options.

4
env/env_posix.cc vendored
View File

@ -130,8 +130,8 @@ class PosixDynamicLibrary : public DynamicLibrary {
class PosixClock : public SystemClock { class PosixClock : public SystemClock {
public: public:
static const char* kClassName() { return "PosixClock"; } static const char* kClassName() { return "PosixClock"; }
const char* Name() const override { return kClassName(); } const char* Name() const override { return kDefaultName(); }
const char* NickName() const override { return kDefaultName(); } const char* NickName() const override { return kClassName(); }
uint64_t NowMicros() override { uint64_t NowMicros() override {
struct timeval tv; struct timeval tv;

7
env/fs_posix.cc vendored
View File

@ -146,6 +146,13 @@ class PosixFileSystem : public FileSystem {
const char* NickName() const override { return kDefaultName(); } const char* NickName() const override { return kDefaultName(); }
~PosixFileSystem() override {} ~PosixFileSystem() override {}
bool IsInstanceOf(const std::string& name) const override {
if (name == "posix") {
return true;
} else {
return FileSystem::IsInstanceOf(name);
}
}
void SetFD_CLOEXEC(int fd, const EnvOptions* options) { void SetFD_CLOEXEC(int fd, const EnvOptions* options) {
if ((options == nullptr || options->set_fd_cloexec) && fd > 0) { if ((options == nullptr || options->set_fd_cloexec) && fd > 0) {

View File

@ -300,6 +300,9 @@ class MemTableRepFactory : public Customizable {
static Status CreateFromString(const ConfigOptions& config_options, static Status CreateFromString(const ConfigOptions& config_options,
const std::string& id, const std::string& id,
std::unique_ptr<MemTableRepFactory>* factory); std::unique_ptr<MemTableRepFactory>* factory);
static Status CreateFromString(const ConfigOptions& config_options,
const std::string& id,
std::shared_ptr<MemTableRepFactory>* factory);
virtual MemTableRep* CreateMemTableRep(const MemTableRep::KeyComparator&, virtual MemTableRep* CreateMemTableRep(const MemTableRep::KeyComparator&,
Allocator*, const SliceTransform*, Allocator*, const SliceTransform*,

View File

@ -13,6 +13,7 @@
#include <mutex> #include <mutex>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <unordered_set>
#include <vector> #include <vector>
#include "rocksdb/status.h" #include "rocksdb/status.h"
@ -217,6 +218,18 @@ class ObjectLibrary {
// @param num_types returns how many unique types are registered. // @param num_types returns how many unique types are registered.
size_t GetFactoryCount(size_t* num_types) const; size_t GetFactoryCount(size_t* num_types) const;
// Returns the number of factories registered for this library
// for the input type.
// @param num_types returns how many unique types are registered.
size_t GetFactoryCount(const std::string& type) const;
// Returns the registered factory names for the input type
// names is updated to include the names for the type
void GetFactoryNames(const std::string& type,
std::vector<std::string>* names) const;
void GetFactoryTypes(std::unordered_set<std::string>* types) const;
void Dump(Logger* logger) const; void Dump(Logger* logger) const;
// Registers the factory with the library for the name. // Registers the factory with the library for the name.
@ -497,6 +510,18 @@ class ObjectRegistry {
} }
} }
// Returns the number of factories registered for this library
// for the input type.
// @param num_types returns how many unique types are registered.
size_t GetFactoryCount(const std::string& type) const;
// Returns the names of registered factories for the input type.
// names is updated to include the names for the type
void GetFactoryNames(const std::string& type,
std::vector<std::string>* names) const;
void GetFactoryTypes(std::unordered_set<std::string>* types) const;
// Dump the contents of the registry to the logger // Dump the contents of the registry to the logger
void Dump(Logger* logger) const; void Dump(Logger* logger) const;

View File

@ -596,10 +596,7 @@ static std::unordered_map<std::string, OptionTypeInfo>
auto* shared = auto* shared =
static_cast<std::shared_ptr<MemTableRepFactory>*>(addr); static_cast<std::shared_ptr<MemTableRepFactory>*>(addr);
Status s = Status s =
MemTableRepFactory::CreateFromString(opts, value, &factory); MemTableRepFactory::CreateFromString(opts, value, shared);
if (factory && s.ok()) {
shared->reset(factory.release());
}
return s; return s;
}}}, }}},
{"memtable", {"memtable",
@ -612,10 +609,7 @@ static std::unordered_map<std::string, OptionTypeInfo>
auto* shared = auto* shared =
static_cast<std::shared_ptr<MemTableRepFactory>*>(addr); static_cast<std::shared_ptr<MemTableRepFactory>*>(addr);
Status s = Status s =
MemTableRepFactory::CreateFromString(opts, value, &factory); MemTableRepFactory::CreateFromString(opts, value, shared);
if (factory && s.ok()) {
shared->reset(factory.release());
}
return s; return s;
}}}, }}},
{"table_factory", {"table_factory",

View File

@ -13,8 +13,11 @@
#include <cinttypes> #include <cinttypes>
#include <cstring> #include <cstring>
#include <unordered_map> #include <unordered_map>
#include <unordered_set>
#include "db/db_test_util.h" #include "db/db_test_util.h"
#include "memory/jemalloc_nodump_allocator.h"
#include "memory/memkind_kmem_allocator.h"
#include "options/options_helper.h" #include "options/options_helper.h"
#include "options/options_parser.h" #include "options/options_parser.h"
#include "port/stack_trace.h" #include "port/stack_trace.h"
@ -1655,6 +1658,190 @@ class LoadCustomizableTest : public testing::Test {
#endif // !ROCKSDB_LITE #endif // !ROCKSDB_LITE
} }
template <typename T, typename U>
Status TestCreateStatic(const std::string& name, U** result,
bool delete_result = false) {
Status s = T::CreateFromString(config_options_, name, result);
if (s.ok()) {
EXPECT_NE(*result, nullptr);
EXPECT_TRUE(*result != nullptr && (*result)->IsInstanceOf(name));
}
if (delete_result) {
delete *result;
*result = nullptr;
}
return s;
}
template <typename T, typename U>
std::shared_ptr<U> ExpectCreateShared(const std::string& name,
std::shared_ptr<U>* object) {
EXPECT_OK(T::CreateFromString(config_options_, name, object));
EXPECT_NE(object->get(), nullptr);
EXPECT_TRUE(object->get()->IsInstanceOf(name));
return *object;
}
template <typename T>
std::shared_ptr<T> ExpectCreateShared(const std::string& name) {
std::shared_ptr<T> result;
return ExpectCreateShared<T>(name, &result);
}
template <typename T, typename U>
Status TestExpectedBuiltins(
const std::string& mock, const std::unordered_set<std::string>& expected,
std::shared_ptr<U>* object, std::vector<std::string>* failed,
const std::function<std::vector<std::string>(const std::string&)>& alt =
nullptr) {
std::unordered_set<std::string> factories = expected;
Status s = T::CreateFromString(config_options_, mock, object);
EXPECT_NOK(s);
#ifndef ROCKSDB_LITE
std::vector<std::string> builtins;
ObjectLibrary::Default()->GetFactoryNames(T::Type(), &builtins);
factories.insert(builtins.begin(), builtins.end());
#endif // ROCKSDB_LITE
Status result;
int created = 0;
for (const auto& name : factories) {
created++;
s = T::CreateFromString(config_options_, name, object);
if (!s.ok() && alt != nullptr) {
for (const auto& alt_name : alt(name)) {
s = T::CreateFromString(config_options_, alt_name, object);
if (s.ok()) {
break;
}
}
}
if (!s.ok()) {
result = s;
failed->push_back(name);
} else {
EXPECT_NE(object->get(), nullptr);
EXPECT_TRUE(object->get()->IsInstanceOf(name));
}
}
#ifndef ROCKSDB_LITE
std::vector<std::string> plugins;
ObjectRegistry::Default()->GetFactoryNames(T::Type(), &plugins);
if (plugins.size() > builtins.size()) {
for (const auto& name : plugins) {
if (factories.find(name) == factories.end()) {
created++;
s = T::CreateFromString(config_options_, name, object);
if (!s.ok() && alt != nullptr) {
for (const auto& alt_name : alt(name)) {
s = T::CreateFromString(config_options_, alt_name, object);
if (s.ok()) {
break;
}
}
}
if (!s.ok()) {
failed->push_back(name);
if (result.ok()) {
result = s;
}
printf("%s: Failed creating plugin[%s]: %s\n", T::Type(),
name.c_str(), s.ToString().c_str());
} else if (object->get() == nullptr ||
!object->get()->IsInstanceOf(name)) {
failed->push_back(name);
printf("%s: Invalid plugin[%s]\n", T::Type(), name.c_str());
}
}
}
}
printf("%s: Created %d (expected+builtins+plugins %d+%d+%d) %d Failed\n",
T::Type(), created, (int)expected.size(),
(int)(factories.size() - expected.size()),
(int)(plugins.size() - builtins.size()), (int)failed->size());
#else
printf("%s: Created %d (expected %d) %d Failed\n", T::Type(), created,
(int)expected.size(), (int)failed->size());
#endif // ROCKSDB_LITE
return result;
}
template <typename T>
Status TestSharedBuiltins(const std::string& mock,
const std::string& expected,
std::vector<std::string>* failed = nullptr) {
std::unordered_set<std::string> values;
if (!expected.empty()) {
values.insert(expected);
}
std::shared_ptr<T> object;
if (failed != nullptr) {
return TestExpectedBuiltins<T>(mock, values, &object, failed);
} else {
std::vector<std::string> failures;
Status s = TestExpectedBuiltins<T>(mock, values, &object, &failures);
EXPECT_EQ(0U, failures.size());
return s;
}
}
template <typename T, typename U>
Status TestStaticBuiltins(const std::string& mock, U** object,
const std::unordered_set<std::string>& expected,
std::vector<std::string>* failed,
bool delete_objects = false) {
std::unordered_set<std::string> factories = expected;
Status s = TestCreateStatic<T>(mock, object, delete_objects);
EXPECT_NOK(s);
#ifndef ROCKSDB_LITE
std::vector<std::string> builtins;
ObjectLibrary::Default()->GetFactoryNames(T::Type(), &builtins);
factories.insert(builtins.begin(), builtins.end());
#endif // ROCKSDB_LITE
int created = 0;
Status result;
for (const auto& name : factories) {
created++;
s = TestCreateStatic<T>(name, object, delete_objects);
if (!s.ok()) {
result = s;
failed->push_back(name);
}
}
#ifndef ROCKSDB_LITE
std::vector<std::string> plugins;
ObjectRegistry::Default()->GetFactoryNames(T::Type(), &plugins);
if (plugins.size() > builtins.size()) {
for (const auto& name : plugins) {
if (factories.find(name) == factories.end()) {
created++;
s = T::CreateFromString(config_options_, name, object);
if (!s.ok() || *object == nullptr ||
!((*object)->IsInstanceOf(name))) {
failed->push_back(name);
if (result.ok() && !s.ok()) {
result = s;
}
printf("%s: Failed creating plugin[%s]: %s\n", T::Type(),
name.c_str(), s.ToString().c_str());
}
if (delete_objects) {
delete *object;
*object = nullptr;
}
}
}
}
printf("%s: Created %d (expected+builtins+plugins %d+%d+%d) %d Failed\n",
T::Type(), created, (int)expected.size(),
(int)(factories.size() - expected.size()),
(int)(plugins.size() - builtins.size()), (int)failed->size());
#else
printf("%s: Created %d (expected %d) %d Failed\n", T::Type(), created,
(int)expected.size(), (int)failed->size());
#endif // ROCKSDB_LITE
return result;
}
protected: protected:
DBOptions db_opts_; DBOptions db_opts_;
ColumnFamilyOptions cf_opts_; ColumnFamilyOptions cf_opts_;
@ -1662,13 +1849,9 @@ class LoadCustomizableTest : public testing::Test {
}; };
TEST_F(LoadCustomizableTest, LoadTableFactoryTest) { TEST_F(LoadCustomizableTest, LoadTableFactoryTest) {
std::shared_ptr<TableFactory> factory; ASSERT_OK(
ASSERT_NOK(TableFactory::CreateFromString( TestSharedBuiltins<TableFactory>(mock::MockTableFactory::kClassName(),
config_options_, mock::MockTableFactory::kClassName(), &factory)); TableFactory::kBlockBasedTableName()));
ASSERT_OK(TableFactory::CreateFromString(
config_options_, TableFactory::kBlockBasedTableName(), &factory));
ASSERT_NE(factory, nullptr);
ASSERT_STREQ(factory->Name(), TableFactory::kBlockBasedTableName());
#ifndef ROCKSDB_LITE #ifndef ROCKSDB_LITE
std::string opts_str = "table_factory="; std::string opts_str = "table_factory=";
ASSERT_OK(GetColumnFamilyOptionsFromString( ASSERT_OK(GetColumnFamilyOptionsFromString(
@ -1679,10 +1862,7 @@ TEST_F(LoadCustomizableTest, LoadTableFactoryTest) {
TableFactory::kBlockBasedTableName()); TableFactory::kBlockBasedTableName());
#endif // ROCKSDB_LITE #endif // ROCKSDB_LITE
if (RegisterTests("Test")) { if (RegisterTests("Test")) {
ASSERT_OK(TableFactory::CreateFromString( ExpectCreateShared<TableFactory>(mock::MockTableFactory::kClassName());
config_options_, mock::MockTableFactory::kClassName(), &factory));
ASSERT_NE(factory, nullptr);
ASSERT_STREQ(factory->Name(), mock::MockTableFactory::kClassName());
#ifndef ROCKSDB_LITE #ifndef ROCKSDB_LITE
ASSERT_OK(GetColumnFamilyOptionsFromString( ASSERT_OK(GetColumnFamilyOptionsFromString(
config_options_, cf_opts_, config_options_, cf_opts_,
@ -1695,83 +1875,44 @@ TEST_F(LoadCustomizableTest, LoadTableFactoryTest) {
} }
TEST_F(LoadCustomizableTest, LoadFileSystemTest) { TEST_F(LoadCustomizableTest, LoadFileSystemTest) {
ColumnFamilyOptions cf_opts; ASSERT_OK(TestSharedBuiltins<FileSystem>(DummyFileSystem::kClassName(),
std::shared_ptr<FileSystem> result; FileSystem::kDefaultName()));
ASSERT_NOK(FileSystem::CreateFromString(
config_options_, DummyFileSystem::kClassName(), &result));
ASSERT_OK(FileSystem::CreateFromString(config_options_,
FileSystem::kDefaultName(), &result));
ASSERT_NE(result, nullptr);
ASSERT_TRUE(result->IsInstanceOf(FileSystem::kDefaultName()));
if (RegisterTests("Test")) { if (RegisterTests("Test")) {
ASSERT_OK(FileSystem::CreateFromString( auto fs = ExpectCreateShared<FileSystem>(DummyFileSystem::kClassName());
config_options_, DummyFileSystem::kClassName(), &result)); ASSERT_FALSE(fs->IsInstanceOf(FileSystem::kDefaultName()));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), DummyFileSystem::kClassName());
ASSERT_FALSE(result->IsInstanceOf(FileSystem::kDefaultName()));
} }
} }
TEST_F(LoadCustomizableTest, LoadSecondaryCacheTest) { TEST_F(LoadCustomizableTest, LoadSecondaryCacheTest) {
std::shared_ptr<SecondaryCache> result; ASSERT_OK(
ASSERT_NOK(SecondaryCache::CreateFromString( TestSharedBuiltins<SecondaryCache>(TestSecondaryCache::kClassName(), ""));
config_options_, TestSecondaryCache::kClassName(), &result));
if (RegisterTests("Test")) { if (RegisterTests("Test")) {
ASSERT_OK(SecondaryCache::CreateFromString( ExpectCreateShared<SecondaryCache>(TestSecondaryCache::kClassName());
config_options_, TestSecondaryCache::kClassName(), &result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), TestSecondaryCache::kClassName());
} }
} }
#ifndef ROCKSDB_LITE #ifndef ROCKSDB_LITE
TEST_F(LoadCustomizableTest, LoadSstPartitionerFactoryTest) { TEST_F(LoadCustomizableTest, LoadSstPartitionerFactoryTest) {
std::shared_ptr<SstPartitionerFactory> factory; ASSERT_OK(TestSharedBuiltins<SstPartitionerFactory>(
ASSERT_NOK(SstPartitionerFactory::CreateFromString(config_options_, "Mock", "Mock", SstPartitionerFixedPrefixFactory::kClassName()));
&factory));
ASSERT_OK(SstPartitionerFactory::CreateFromString(
config_options_, SstPartitionerFixedPrefixFactory::kClassName(),
&factory));
ASSERT_NE(factory, nullptr);
ASSERT_STREQ(factory->Name(), SstPartitionerFixedPrefixFactory::kClassName());
if (RegisterTests("Test")) { if (RegisterTests("Test")) {
ASSERT_OK(SstPartitionerFactory::CreateFromString(config_options_, "Mock", ExpectCreateShared<SstPartitionerFactory>("Mock");
&factory));
ASSERT_NE(factory, nullptr);
ASSERT_STREQ(factory->Name(), "Mock");
} }
} }
#endif // ROCKSDB_LITE #endif // ROCKSDB_LITE
TEST_F(LoadCustomizableTest, LoadChecksumGenFactoryTest) { TEST_F(LoadCustomizableTest, LoadChecksumGenFactoryTest) {
std::shared_ptr<FileChecksumGenFactory> factory; ASSERT_OK(TestSharedBuiltins<FileChecksumGenFactory>("Mock", ""));
ASSERT_NOK(FileChecksumGenFactory::CreateFromString(config_options_, "Mock",
&factory));
ASSERT_OK(FileChecksumGenFactory::CreateFromString(
config_options_, FileChecksumGenCrc32cFactory::kClassName(), &factory));
ASSERT_NE(factory, nullptr);
ASSERT_STREQ(factory->Name(), FileChecksumGenCrc32cFactory::kClassName());
if (RegisterTests("Test")) { if (RegisterTests("Test")) {
ASSERT_OK(FileChecksumGenFactory::CreateFromString(config_options_, "Mock", ExpectCreateShared<FileChecksumGenFactory>("Mock");
&factory));
ASSERT_NE(factory, nullptr);
ASSERT_STREQ(factory->Name(), "Mock");
} }
} }
TEST_F(LoadCustomizableTest, LoadTablePropertiesCollectorFactoryTest) { TEST_F(LoadCustomizableTest, LoadTablePropertiesCollectorFactoryTest) {
std::shared_ptr<TablePropertiesCollectorFactory> factory; ASSERT_OK(TestSharedBuiltins<TablePropertiesCollectorFactory>(
ASSERT_NOK(TablePropertiesCollectorFactory::CreateFromString( MockTablePropertiesCollectorFactory::kClassName(), ""));
config_options_, MockTablePropertiesCollectorFactory::kClassName(),
&factory));
if (RegisterTests("Test")) { if (RegisterTests("Test")) {
ASSERT_OK(TablePropertiesCollectorFactory::CreateFromString( ExpectCreateShared<TablePropertiesCollectorFactory>(
config_options_, MockTablePropertiesCollectorFactory::kClassName(),
&factory));
ASSERT_NE(factory, nullptr);
ASSERT_STREQ(factory->Name(),
MockTablePropertiesCollectorFactory::kClassName()); MockTablePropertiesCollectorFactory::kClassName());
} }
} }
@ -1779,67 +1920,52 @@ TEST_F(LoadCustomizableTest, LoadTablePropertiesCollectorFactoryTest) {
TEST_F(LoadCustomizableTest, LoadComparatorTest) { TEST_F(LoadCustomizableTest, LoadComparatorTest) {
const Comparator* bytewise = BytewiseComparator(); const Comparator* bytewise = BytewiseComparator();
const Comparator* reverse = ReverseBytewiseComparator(); const Comparator* reverse = ReverseBytewiseComparator();
const Comparator* result = nullptr; const Comparator* result = nullptr;
ASSERT_NOK(Comparator::CreateFromString( std::unordered_set<std::string> expected = {bytewise->Name(),
config_options_, test::SimpleSuffixReverseComparator::kClassName(), reverse->Name()};
&result)); std::vector<std::string> failures;
ASSERT_OK( ASSERT_OK(TestStaticBuiltins<Comparator>(
Comparator::CreateFromString(config_options_, bytewise->Name(), &result)); test::SimpleSuffixReverseComparator::kClassName(), &result, expected,
ASSERT_EQ(result, bytewise); &failures));
ASSERT_OK(
Comparator::CreateFromString(config_options_, reverse->Name(), &result));
ASSERT_EQ(result, reverse);
if (RegisterTests("Test")) { if (RegisterTests("Test")) {
ASSERT_OK(Comparator::CreateFromString( ASSERT_OK(TestCreateStatic<Comparator>(
config_options_, test::SimpleSuffixReverseComparator::kClassName(), test::SimpleSuffixReverseComparator::kClassName(), &result));
&result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(),
test::SimpleSuffixReverseComparator::kClassName());
} }
} }
TEST_F(LoadCustomizableTest, LoadSliceTransformFactoryTest) { TEST_F(LoadCustomizableTest, LoadSliceTransformFactoryTest) {
std::shared_ptr<const SliceTransform> result; std::shared_ptr<const SliceTransform> result;
ASSERT_NOK( std::vector<std::string> failures;
SliceTransform::CreateFromString(config_options_, "Mock", &result)); std::unordered_set<std::string> expected = {"rocksdb.Noop", "fixed",
ASSERT_OK( "rocksdb.FixedPrefix", "capped",
SliceTransform::CreateFromString(config_options_, "fixed:16", &result)); "rocksdb.CappedPrefix"};
ASSERT_NE(result.get(), nullptr); ASSERT_OK(TestExpectedBuiltins<SliceTransform>(
ASSERT_TRUE(result->IsInstanceOf("fixed")); "Mock", expected, &result, &failures, [](const std::string& name) {
std::vector<std::string> names = {name + ":22", name + ".22"};
return names;
}));
ASSERT_OK(SliceTransform::CreateFromString( ASSERT_OK(SliceTransform::CreateFromString(
config_options_, "rocksdb.FixedPrefix.22", &result)); config_options_, "rocksdb.FixedPrefix.22", &result));
ASSERT_NE(result.get(), nullptr); ASSERT_NE(result.get(), nullptr);
ASSERT_TRUE(result->IsInstanceOf("fixed")); ASSERT_TRUE(result->IsInstanceOf("fixed"));
ASSERT_OK(
SliceTransform::CreateFromString(config_options_, "capped:16", &result));
ASSERT_NE(result.get(), nullptr);
ASSERT_TRUE(result->IsInstanceOf("capped"));
ASSERT_OK(SliceTransform::CreateFromString( ASSERT_OK(SliceTransform::CreateFromString(
config_options_, "rocksdb.CappedPrefix.11", &result)); config_options_, "rocksdb.CappedPrefix.22", &result));
ASSERT_NE(result.get(), nullptr); ASSERT_NE(result.get(), nullptr);
ASSERT_TRUE(result->IsInstanceOf("capped")); ASSERT_TRUE(result->IsInstanceOf("capped"));
if (RegisterTests("Test")) { if (RegisterTests("Test")) {
ASSERT_OK( ExpectCreateShared<SliceTransform>("Mock", &result);
SliceTransform::CreateFromString(config_options_, "Mock", &result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), "Mock");
} }
} }
TEST_F(LoadCustomizableTest, LoadStatisticsTest) { TEST_F(LoadCustomizableTest, LoadStatisticsTest) {
std::shared_ptr<Statistics> stats; ASSERT_OK(TestSharedBuiltins<Statistics>(TestStatistics::kClassName(),
ASSERT_NOK(Statistics::CreateFromString( "BasicStatistics"));
config_options_, TestStatistics::kClassName(), &stats)); // Empty will create a default BasicStatistics
ASSERT_OK( ASSERT_OK(
Statistics::CreateFromString(config_options_, "BasicStatistics", &stats)); Statistics::CreateFromString(config_options_, "", &db_opts_.statistics));
ASSERT_NE(stats, nullptr); ASSERT_NE(db_opts_.statistics, nullptr);
ASSERT_EQ(stats->Name(), std::string("BasicStatistics")); ASSERT_STREQ(db_opts_.statistics->Name(), "BasicStatistics");
#ifndef ROCKSDB_LITE #ifndef ROCKSDB_LITE
ASSERT_NOK(GetDBOptionsFromString(config_options_, db_opts_, ASSERT_NOK(GetDBOptionsFromString(config_options_, db_opts_,
"statistics=Test", &db_opts_)); "statistics=Test", &db_opts_));
@ -1849,10 +1975,7 @@ TEST_F(LoadCustomizableTest, LoadStatisticsTest) {
ASSERT_STREQ(db_opts_.statistics->Name(), "BasicStatistics"); ASSERT_STREQ(db_opts_.statistics->Name(), "BasicStatistics");
if (RegisterTests("test")) { if (RegisterTests("test")) {
ASSERT_OK(Statistics::CreateFromString( auto stats = ExpectCreateShared<Statistics>(TestStatistics::kClassName());
config_options_, TestStatistics::kClassName(), &stats));
ASSERT_NE(stats, nullptr);
ASSERT_STREQ(stats->Name(), TestStatistics::kClassName());
ASSERT_OK(GetDBOptionsFromString(config_options_, db_opts_, ASSERT_OK(GetDBOptionsFromString(config_options_, db_opts_,
"statistics=Test", &db_opts_)); "statistics=Test", &db_opts_));
@ -1883,167 +2006,90 @@ TEST_F(LoadCustomizableTest, LoadStatisticsTest) {
} }
TEST_F(LoadCustomizableTest, LoadMemTableRepFactoryTest) { TEST_F(LoadCustomizableTest, LoadMemTableRepFactoryTest) {
std::unique_ptr<MemTableRepFactory> result; std::unordered_set<std::string> expected = {
ASSERT_NOK(MemTableRepFactory::CreateFromString( SkipListFactory::kClassName(),
config_options_, "SpecialSkipListFactory", &result)); SkipListFactory::kNickName(),
ASSERT_OK(MemTableRepFactory::CreateFromString( };
config_options_, SkipListFactory::kClassName(), &result));
ASSERT_NE(result.get(), nullptr);
ASSERT_TRUE(result->IsInstanceOf(SkipListFactory::kClassName()));
std::vector<std::string> failures;
std::shared_ptr<MemTableRepFactory> factory;
Status s = TestExpectedBuiltins<MemTableRepFactory>(
"SpecialSkipListFactory", expected, &factory, &failures);
// There is a "cuckoo" factory registered that we expect to fail. Ignore the
// error if this is the one
if (s.ok() || failures.size() > 1 || failures[0] != "cuckoo") {
ASSERT_OK(s);
}
if (RegisterTests("Test")) { if (RegisterTests("Test")) {
ASSERT_OK(MemTableRepFactory::CreateFromString( ExpectCreateShared<MemTableRepFactory>("SpecialSkipListFactory");
config_options_, "SpecialSkipListFactory", &result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), "SpecialSkipListFactory");
} }
} }
TEST_F(LoadCustomizableTest, LoadMergeOperatorTest) { TEST_F(LoadCustomizableTest, LoadMergeOperatorTest) {
std::shared_ptr<MergeOperator> result; std::shared_ptr<MergeOperator> result;
std::vector<std::string> failed;
ASSERT_NOK( std::unordered_set<std::string> expected = {
MergeOperator::CreateFromString(config_options_, "Changling", &result)); "put", "put_v1", "PutOperator", "uint64add", "UInt64AddOperator",
//**TODO: MJR: Use the constants when these names are in public classes "max", "MaxOperator",
ASSERT_OK(MergeOperator::CreateFromString(config_options_, "put", &result)); };
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), "PutOperator");
ASSERT_OK(
MergeOperator::CreateFromString(config_options_, "PutOperator", &result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), "PutOperator");
ASSERT_OK(
MergeOperator::CreateFromString(config_options_, "put_v1", &result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), "PutOperator");
ASSERT_OK(
MergeOperator::CreateFromString(config_options_, "uint64add", &result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), "UInt64AddOperator");
ASSERT_OK(MergeOperator::CreateFromString(config_options_,
"UInt64AddOperator", &result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), "UInt64AddOperator");
ASSERT_OK(MergeOperator::CreateFromString(config_options_, "max", &result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), "MaxOperator");
ASSERT_OK(
MergeOperator::CreateFromString(config_options_, "MaxOperator", &result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), "MaxOperator");
#ifndef ROCKSDB_LITE #ifndef ROCKSDB_LITE
ASSERT_OK(MergeOperator::CreateFromString( expected.insert({
config_options_, StringAppendOperator::kNickName(), &result)); StringAppendOperator::kClassName(),
ASSERT_NE(result, nullptr); StringAppendOperator::kNickName(),
ASSERT_STREQ(result->Name(), StringAppendOperator::kClassName()); StringAppendTESTOperator::kClassName(),
ASSERT_OK(MergeOperator::CreateFromString( StringAppendTESTOperator::kNickName(),
config_options_, StringAppendOperator::kClassName(), &result)); SortList::kClassName(),
ASSERT_NE(result, nullptr); SortList::kNickName(),
ASSERT_STREQ(result->Name(), StringAppendOperator::kClassName()); BytesXOROperator::kClassName(),
BytesXOROperator::kNickName(),
ASSERT_OK(MergeOperator::CreateFromString( });
config_options_, StringAppendTESTOperator::kNickName(), &result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), StringAppendTESTOperator::kClassName());
ASSERT_OK(MergeOperator::CreateFromString(
config_options_, StringAppendTESTOperator::kClassName(), &result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), StringAppendTESTOperator::kClassName());
ASSERT_OK(MergeOperator::CreateFromString(config_options_,
SortList::kNickName(), &result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), SortList::kClassName());
ASSERT_OK(MergeOperator::CreateFromString(config_options_,
SortList::kClassName(), &result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), SortList::kClassName());
ASSERT_OK(MergeOperator::CreateFromString(
config_options_, BytesXOROperator::kNickName(), &result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), BytesXOROperator::kClassName());
ASSERT_OK(MergeOperator::CreateFromString(
config_options_, BytesXOROperator::kClassName(), &result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), BytesXOROperator::kClassName());
#endif // ROCKSDB_LITE #endif // ROCKSDB_LITE
ASSERT_NOK(
MergeOperator::CreateFromString(config_options_, "Changling", &result)); ASSERT_OK(TestExpectedBuiltins<MergeOperator>("Changling", expected, &result,
&failed));
if (RegisterTests("Test")) { if (RegisterTests("Test")) {
ASSERT_OK( ExpectCreateShared<MergeOperator>("Changling");
MergeOperator::CreateFromString(config_options_, "Changling", &result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), "ChanglingMergeOperator");
} }
} }
TEST_F(LoadCustomizableTest, LoadCompactionFilterFactoryTest) { TEST_F(LoadCustomizableTest, LoadCompactionFilterFactoryTest) {
std::shared_ptr<CompactionFilterFactory> result; ASSERT_OK(TestSharedBuiltins<CompactionFilterFactory>("Changling", ""));
ASSERT_NOK(CompactionFilterFactory::CreateFromString(config_options_,
"Changling", &result));
if (RegisterTests("Test")) { if (RegisterTests("Test")) {
ASSERT_OK(CompactionFilterFactory::CreateFromString(config_options_, ExpectCreateShared<CompactionFilterFactory>("Changling");
"Changling", &result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), "ChanglingCompactionFilterFactory");
} }
} }
TEST_F(LoadCustomizableTest, LoadCompactionFilterTest) { TEST_F(LoadCustomizableTest, LoadCompactionFilterTest) {
const CompactionFilter* result = nullptr; const CompactionFilter* result = nullptr;
std::vector<std::string> failures;
ASSERT_NOK(CompactionFilter::CreateFromString(config_options_, "Changling", ASSERT_OK(TestStaticBuiltins<CompactionFilter>("Changling", &result, {},
&result)); &failures, true));
#ifndef ROCKSDB_LITE
ASSERT_OK(CompactionFilter::CreateFromString(
config_options_, RemoveEmptyValueCompactionFilter::kClassName(),
&result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), RemoveEmptyValueCompactionFilter::kClassName());
delete result;
result = nullptr;
if (RegisterTests("Test")) { if (RegisterTests("Test")) {
ASSERT_OK(CompactionFilter::CreateFromString(config_options_, "Changling", ASSERT_OK(TestCreateStatic<CompactionFilter>("Changling", &result, true));
&result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), "ChanglingCompactionFilter");
delete result;
} }
#endif // ROCKSDB_LITE
} }
#ifndef ROCKSDB_LITE #ifndef ROCKSDB_LITE
TEST_F(LoadCustomizableTest, LoadEventListenerTest) { TEST_F(LoadCustomizableTest, LoadEventListenerTest) {
std::shared_ptr<EventListener> result; ASSERT_OK(TestSharedBuiltins<EventListener>(
OnFileDeletionListener::kClassName(), ""));
ASSERT_NOK(EventListener::CreateFromString(
config_options_, OnFileDeletionListener::kClassName(), &result));
ASSERT_NOK(EventListener::CreateFromString(
config_options_, FlushCounterListener::kClassName(), &result));
if (RegisterTests("Test")) { if (RegisterTests("Test")) {
ASSERT_OK(EventListener::CreateFromString( ExpectCreateShared<EventListener>(OnFileDeletionListener::kClassName());
config_options_, OnFileDeletionListener::kClassName(), &result)); ExpectCreateShared<EventListener>(FlushCounterListener::kClassName());
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), OnFileDeletionListener::kClassName());
ASSERT_OK(EventListener::CreateFromString(
config_options_, FlushCounterListener::kClassName(), &result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), FlushCounterListener::kClassName());
} }
} }
TEST_F(LoadCustomizableTest, LoadEncryptionProviderTest) { TEST_F(LoadCustomizableTest, LoadEncryptionProviderTest) {
std::vector<std::string> failures;
std::shared_ptr<EncryptionProvider> result; std::shared_ptr<EncryptionProvider> result;
ASSERT_NOK(
EncryptionProvider::CreateFromString(config_options_, "Mock", &result));
ASSERT_OK( ASSERT_OK(
EncryptionProvider::CreateFromString(config_options_, "CTR", &result)); TestExpectedBuiltins<EncryptionProvider>("Mock", {}, &result, &failures));
ASSERT_NE(result, nullptr); if (!failures.empty()) {
ASSERT_STREQ(result->Name(), "CTR"); ASSERT_EQ(failures[0], "1://test");
ASSERT_EQ(failures.size(), 1U);
}
result = ExpectCreateShared<EncryptionProvider>("CTR");
ASSERT_NOK(result->ValidateOptions(db_opts_, cf_opts_)); ASSERT_NOK(result->ValidateOptions(db_opts_, cf_opts_));
ASSERT_OK(EncryptionProvider::CreateFromString(config_options_, "CTR://test", ASSERT_OK(EncryptionProvider::CreateFromString(config_options_, "CTR://test",
&result)); &result));
@ -2052,10 +2098,7 @@ TEST_F(LoadCustomizableTest, LoadEncryptionProviderTest) {
ASSERT_OK(result->ValidateOptions(db_opts_, cf_opts_)); ASSERT_OK(result->ValidateOptions(db_opts_, cf_opts_));
if (RegisterTests("Test")) { if (RegisterTests("Test")) {
ASSERT_OK( ExpectCreateShared<EncryptionProvider>("Mock");
EncryptionProvider::CreateFromString(config_options_, "Mock", &result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), "Mock");
ASSERT_OK(EncryptionProvider::CreateFromString(config_options_, ASSERT_OK(EncryptionProvider::CreateFromString(config_options_,
"Mock://test", &result)); "Mock://test", &result));
ASSERT_NE(result, nullptr); ASSERT_NE(result, nullptr);
@ -2065,72 +2108,69 @@ TEST_F(LoadCustomizableTest, LoadEncryptionProviderTest) {
} }
TEST_F(LoadCustomizableTest, LoadEncryptionCipherTest) { TEST_F(LoadCustomizableTest, LoadEncryptionCipherTest) {
std::shared_ptr<BlockCipher> result; ASSERT_OK(TestSharedBuiltins<BlockCipher>("Mock", "ROT13"));
ASSERT_NOK(BlockCipher::CreateFromString(config_options_, "Mock", &result));
ASSERT_OK(BlockCipher::CreateFromString(config_options_, "ROT13", &result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), "ROT13");
if (RegisterTests("Test")) { if (RegisterTests("Test")) {
ASSERT_OK(BlockCipher::CreateFromString(config_options_, "Mock", &result)); ExpectCreateShared<BlockCipher>("Mock");
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), "Mock");
} }
} }
#endif // !ROCKSDB_LITE #endif // !ROCKSDB_LITE
TEST_F(LoadCustomizableTest, LoadSystemClockTest) { TEST_F(LoadCustomizableTest, LoadSystemClockTest) {
std::shared_ptr<SystemClock> result; ASSERT_OK(TestSharedBuiltins<SystemClock>(MockSystemClock::kClassName(),
ASSERT_NOK(SystemClock::CreateFromString( SystemClock::kDefaultName()));
config_options_, MockSystemClock::kClassName(), &result));
ASSERT_OK(SystemClock::CreateFromString(
config_options_, SystemClock::kDefaultName(), &result));
ASSERT_NE(result, nullptr);
ASSERT_TRUE(result->IsInstanceOf(SystemClock::kDefaultName()));
if (RegisterTests("Test")) { if (RegisterTests("Test")) {
ASSERT_OK(SystemClock::CreateFromString( auto result =
config_options_, MockSystemClock::kClassName(), &result)); ExpectCreateShared<SystemClock>(MockSystemClock::kClassName());
ASSERT_NE(result, nullptr); ASSERT_FALSE(result->IsInstanceOf(SystemClock::kDefaultName()));
ASSERT_STREQ(result->Name(), MockSystemClock::kClassName());
} }
} }
TEST_F(LoadCustomizableTest, LoadMemoryAllocatorTest) { TEST_F(LoadCustomizableTest, LoadMemoryAllocatorTest) {
std::shared_ptr<MemoryAllocator> result; std::vector<std::string> failures;
ASSERT_NOK(MemoryAllocator::CreateFromString( Status s = TestSharedBuiltins<MemoryAllocator>(
config_options_, MockMemoryAllocator::kClassName(), &result)); MockMemoryAllocator::kClassName(), DefaultMemoryAllocator::kClassName(),
ASSERT_OK(MemoryAllocator::CreateFromString( &failures);
config_options_, DefaultMemoryAllocator::kClassName(), &result)); if (failures.empty()) {
ASSERT_NE(result, nullptr); ASSERT_OK(s);
ASSERT_STREQ(result->Name(), DefaultMemoryAllocator::kClassName()); } else {
ASSERT_NOK(s);
for (const auto& failure : failures) {
if (failure == JemallocNodumpAllocator::kClassName()) {
ASSERT_FALSE(JemallocNodumpAllocator::IsSupported());
} else if (failure == MemkindKmemAllocator::kClassName()) {
ASSERT_FALSE(MemkindKmemAllocator::IsSupported());
} else {
printf("BYPASSED: %s -- %s\n", failure.c_str(), s.ToString().c_str());
}
}
}
if (RegisterTests("Test")) { if (RegisterTests("Test")) {
ASSERT_OK(MemoryAllocator::CreateFromString( ExpectCreateShared<MemoryAllocator>(MockMemoryAllocator::kClassName());
config_options_, MockMemoryAllocator::kClassName(), &result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), MockMemoryAllocator::kClassName());
} }
} }
TEST_F(LoadCustomizableTest, LoadRateLimiterTest) { TEST_F(LoadCustomizableTest, LoadRateLimiterTest) {
#ifndef ROCKSDB_LITE
ASSERT_OK(TestSharedBuiltins<RateLimiter>(MockRateLimiter::kClassName(),
GenericRateLimiter::kClassName()));
#else
ASSERT_OK(TestSharedBuiltins<RateLimiter>(MockRateLimiter::kClassName(), ""));
#endif // ROCKSDB_LITE
std::shared_ptr<RateLimiter> result; std::shared_ptr<RateLimiter> result;
ASSERT_NOK(RateLimiter::CreateFromString(
config_options_, MockRateLimiter::kClassName(), &result));
ASSERT_OK(RateLimiter::CreateFromString( ASSERT_OK(RateLimiter::CreateFromString(
config_options_, std::string(GenericRateLimiter::kClassName()) + ":1234", config_options_, std::string(GenericRateLimiter::kClassName()) + ":1234",
&result)); &result));
ASSERT_NE(result, nullptr); ASSERT_NE(result, nullptr);
ASSERT_TRUE(result->IsInstanceOf(GenericRateLimiter::kClassName()));
#ifndef ROCKSDB_LITE #ifndef ROCKSDB_LITE
ASSERT_OK(RateLimiter::CreateFromString(
config_options_, GenericRateLimiter::kClassName(), &result));
ASSERT_NE(result, nullptr);
ASSERT_OK(GetDBOptionsFromString( ASSERT_OK(GetDBOptionsFromString(
config_options_, db_opts_, config_options_, db_opts_,
std::string("rate_limiter=") + GenericRateLimiter::kClassName(), std::string("rate_limiter=") + GenericRateLimiter::kClassName(),
&db_opts_)); &db_opts_));
ASSERT_NE(db_opts_.rate_limiter, nullptr); ASSERT_NE(db_opts_.rate_limiter, nullptr);
if (RegisterTests("Test")) { if (RegisterTests("Test")) {
ASSERT_OK(RateLimiter::CreateFromString( ExpectCreateShared<RateLimiter>(MockRateLimiter::kClassName());
config_options_, MockRateLimiter::kClassName(), &result));
ASSERT_NE(result, nullptr);
ASSERT_OK(GetDBOptionsFromString( ASSERT_OK(GetDBOptionsFromString(
config_options_, db_opts_, config_options_, db_opts_,
std::string("rate_limiter=") + MockRateLimiter::kClassName(), std::string("rate_limiter=") + MockRateLimiter::kClassName(),
@ -2141,17 +2181,52 @@ TEST_F(LoadCustomizableTest, LoadRateLimiterTest) {
} }
TEST_F(LoadCustomizableTest, LoadFilterPolicyTest) { TEST_F(LoadCustomizableTest, LoadFilterPolicyTest) {
std::shared_ptr<TableFactory> table; const std::string kAutoBloom = BloomFilterPolicy::kClassName();
std::shared_ptr<const FilterPolicy> result; const std::string kAutoRibbon = RibbonFilterPolicy::kClassName();
ASSERT_NOK(FilterPolicy::CreateFromString(
config_options_, MockFilterPolicy::kClassName(), &result));
ASSERT_OK(FilterPolicy::CreateFromString(config_options_, "", &result)); std::shared_ptr<const FilterPolicy> result;
ASSERT_EQ(result, nullptr); std::vector<std::string> failures;
std::unordered_set<std::string> expected = {
ReadOnlyBuiltinFilterPolicy::kClassName(),
};
#ifndef ROCKSDB_LITE
expected.insert({
kAutoBloom,
BloomFilterPolicy::kNickName(),
kAutoRibbon,
RibbonFilterPolicy::kNickName(),
});
#endif // ROCKSDB_LITE
ASSERT_OK(TestExpectedBuiltins<const FilterPolicy>(
"Mock", expected, &result, &failures, [](const std::string& name) {
std::vector<std::string> names = {name + ":1.234"};
return names;
}));
#ifndef ROCKSDB_LITE
ASSERT_OK(FilterPolicy::CreateFromString( ASSERT_OK(FilterPolicy::CreateFromString(
config_options_, ReadOnlyBuiltinFilterPolicy::kClassName(), &result)); config_options_, kAutoBloom + ":1.234:false", &result));
ASSERT_NE(result, nullptr); ASSERT_NE(result.get(), nullptr);
ASSERT_STREQ(result->Name(), ReadOnlyBuiltinFilterPolicy::kClassName()); ASSERT_TRUE(result->IsInstanceOf(kAutoBloom));
ASSERT_OK(FilterPolicy::CreateFromString(
config_options_, kAutoBloom + ":1.234:false", &result));
ASSERT_NE(result.get(), nullptr);
ASSERT_TRUE(result->IsInstanceOf(kAutoBloom));
ASSERT_OK(FilterPolicy::CreateFromString(config_options_,
kAutoRibbon + ":1.234:-1", &result));
ASSERT_NE(result.get(), nullptr);
ASSERT_TRUE(result->IsInstanceOf(kAutoRibbon));
ASSERT_OK(FilterPolicy::CreateFromString(config_options_,
kAutoRibbon + ":1.234:56", &result));
ASSERT_NE(result.get(), nullptr);
ASSERT_TRUE(result->IsInstanceOf(kAutoRibbon));
#endif // ROCKSDB_LITE
if (RegisterTests("Test")) {
ExpectCreateShared<FilterPolicy>(MockFilterPolicy::kClassName(), &result);
}
std::shared_ptr<TableFactory> table;
#ifndef ROCKSDB_LITE #ifndef ROCKSDB_LITE
std::string table_opts = "id=BlockBasedTable; filter_policy="; std::string table_opts = "id=BlockBasedTable; filter_policy=";
@ -2173,42 +2248,30 @@ TEST_F(LoadCustomizableTest, LoadFilterPolicyTest) {
config_options_, table_opts + MockFilterPolicy::kClassName(), &table)); config_options_, table_opts + MockFilterPolicy::kClassName(), &table));
bbto = table->GetOptions<BlockBasedTableOptions>(); bbto = table->GetOptions<BlockBasedTableOptions>();
ASSERT_NE(bbto, nullptr); ASSERT_NE(bbto, nullptr);
ASSERT_EQ(bbto->filter_policy.get(), nullptr);
if (RegisterTests("Test")) {
ASSERT_OK(FilterPolicy::CreateFromString(
config_options_, MockFilterPolicy::kClassName(), &result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), MockFilterPolicy::kClassName());
ASSERT_OK(TableFactory::CreateFromString(
config_options_, table_opts + MockFilterPolicy::kClassName(), &table));
bbto = table->GetOptions<BlockBasedTableOptions>();
ASSERT_NE(bbto, nullptr);
ASSERT_NE(bbto->filter_policy.get(), nullptr); ASSERT_NE(bbto->filter_policy.get(), nullptr);
ASSERT_STREQ(bbto->filter_policy->Name(), MockFilterPolicy::kClassName()); ASSERT_TRUE(
} bbto->filter_policy->IsInstanceOf(MockFilterPolicy::kClassName()));
#endif // ROCKSDB_LITE #endif // ROCKSDB_LITE
} }
TEST_F(LoadCustomizableTest, LoadFlushBlockPolicyFactoryTest) { TEST_F(LoadCustomizableTest, LoadFlushBlockPolicyFactoryTest) {
std::shared_ptr<TableFactory> table;
std::shared_ptr<FlushBlockPolicyFactory> result; std::shared_ptr<FlushBlockPolicyFactory> result;
ASSERT_NOK(FlushBlockPolicyFactory::CreateFromString( std::shared_ptr<TableFactory> table;
config_options_, TestFlushBlockPolicyFactory::kClassName(), &result)); std::vector<std::string> failed;
std::unordered_set<std::string> expected = {
FlushBlockBySizePolicyFactory::kClassName(),
FlushBlockEveryKeyPolicyFactory::kClassName(),
};
ASSERT_OK(TestExpectedBuiltins<FlushBlockPolicyFactory>(
TestFlushBlockPolicyFactory::kClassName(), expected, &result, &failed));
// An empty policy name creates a BySize policy
ASSERT_OK( ASSERT_OK(
FlushBlockPolicyFactory::CreateFromString(config_options_, "", &result)); FlushBlockPolicyFactory::CreateFromString(config_options_, "", &result));
ASSERT_NE(result, nullptr); ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), FlushBlockBySizePolicyFactory::kClassName()); ASSERT_STREQ(result->Name(), FlushBlockBySizePolicyFactory::kClassName());
ASSERT_OK(FlushBlockPolicyFactory::CreateFromString(
config_options_, FlushBlockEveryKeyPolicyFactory::kClassName(), &result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), FlushBlockEveryKeyPolicyFactory::kClassName());
ASSERT_OK(FlushBlockPolicyFactory::CreateFromString(
config_options_, FlushBlockBySizePolicyFactory::kClassName(), &result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), FlushBlockBySizePolicyFactory::kClassName());
#ifndef ROCKSDB_LITE #ifndef ROCKSDB_LITE
std::string table_opts = "id=BlockBasedTable; flush_block_policy_factory="; std::string table_opts = "id=BlockBasedTable; flush_block_policy_factory=";
ASSERT_OK(TableFactory::CreateFromString( ASSERT_OK(TableFactory::CreateFromString(
@ -2220,10 +2283,8 @@ TEST_F(LoadCustomizableTest, LoadFlushBlockPolicyFactoryTest) {
ASSERT_STREQ(bbto->flush_block_policy_factory->Name(), ASSERT_STREQ(bbto->flush_block_policy_factory->Name(),
FlushBlockEveryKeyPolicyFactory::kClassName()); FlushBlockEveryKeyPolicyFactory::kClassName());
if (RegisterTests("Test")) { if (RegisterTests("Test")) {
ASSERT_OK(FlushBlockPolicyFactory::CreateFromString( ExpectCreateShared<FlushBlockPolicyFactory>(
config_options_, TestFlushBlockPolicyFactory::kClassName(), &result)); TestFlushBlockPolicyFactory::kClassName());
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), TestFlushBlockPolicyFactory::kClassName());
ASSERT_OK(TableFactory::CreateFromString( ASSERT_OK(TableFactory::CreateFromString(
config_options_, table_opts + TestFlushBlockPolicyFactory::kClassName(), config_options_, table_opts + TestFlushBlockPolicyFactory::kClassName(),
&table)); &table));

View File

@ -80,8 +80,8 @@ class WinClock : public SystemClock {
virtual ~WinClock() {} virtual ~WinClock() {}
static const char* kClassName() { return "WindowsClock"; } static const char* kClassName() { return "WindowsClock"; }
const char* Name() const override { return kClassName(); } const char* Name() const override { return kDefaultName(); }
const char* NickName() const override { return kDefaultName(); } const char* NickName() const override { return kClassName(); }
uint64_t NowMicros() override; uint64_t NowMicros() override;

View File

@ -275,7 +275,7 @@ Status MemTableRepFactory::CreateFromString(
if (opts_list.empty() || opts_list.size() > 2 || !opt_map.empty()) { if (opts_list.empty() || opts_list.size() > 2 || !opt_map.empty()) {
status = Status::InvalidArgument("Can't parse memtable_factory option ", status = Status::InvalidArgument("Can't parse memtable_factory option ",
value); value);
} else if (opts_list[0] == "skip_list" || } else if (opts_list[0] == SkipListFactory::kNickName() ||
opts_list[0] == SkipListFactory::kClassName()) { opts_list[0] == SkipListFactory::kClassName()) {
// Expecting format // Expecting format
// skip_list:<lookahead> // skip_list:<lookahead>
@ -293,6 +293,17 @@ Status MemTableRepFactory::CreateFromString(
return status; return status;
} }
Status MemTableRepFactory::CreateFromString(
const ConfigOptions& config_options, const std::string& value,
std::shared_ptr<MemTableRepFactory>* result) {
std::unique_ptr<MemTableRepFactory> factory;
Status s = CreateFromString(config_options, value, &factory);
if (factory && s.ok()) {
result->reset(factory.release());
}
return s;
}
#ifndef ROCKSDB_LITE #ifndef ROCKSDB_LITE
Status GetPlainTableOptionsFromMap( Status GetPlainTableOptionsFromMap(
const PlainTableOptions& table_options, const PlainTableOptions& table_options,

View File

@ -714,7 +714,9 @@ class ChanglingMergeOperator : public MergeOperator {
return false; return false;
} }
static const char* kClassName() { return "ChanglingMergeOperator"; } static const char* kClassName() { return "ChanglingMergeOperator"; }
virtual bool IsInstanceOf(const std::string& id) const override { const char* NickName() const override { return kNickName(); }
static const char* kNickName() { return "Changling"; }
bool IsInstanceOf(const std::string& id) const override {
if (id == kClassName()) { if (id == kClassName()) {
return true; return true;
} else { } else {
@ -747,7 +749,10 @@ class ChanglingCompactionFilter : public CompactionFilter {
} }
static const char* kClassName() { return "ChanglingCompactionFilter"; } static const char* kClassName() { return "ChanglingCompactionFilter"; }
virtual bool IsInstanceOf(const std::string& id) const override { const char* NickName() const override { return kNickName(); }
static const char* kNickName() { return "Changling"; }
bool IsInstanceOf(const std::string& id) const override {
if (id == kClassName()) { if (id == kClassName()) {
return true; return true;
} else { } else {
@ -781,7 +786,10 @@ class ChanglingCompactionFilterFactory : public CompactionFilterFactory {
// Returns a name that identifies this compaction filter factory. // Returns a name that identifies this compaction filter factory.
const char* Name() const override { return name_.c_str(); } const char* Name() const override { return name_.c_str(); }
static const char* kClassName() { return "ChanglingCompactionFilterFactory"; } static const char* kClassName() { return "ChanglingCompactionFilterFactory"; }
virtual bool IsInstanceOf(const std::string& id) const override { const char* NickName() const override { return kNickName(); }
static const char* kNickName() { return "Changling"; }
bool IsInstanceOf(const std::string& id) const override {
if (id == kClassName()) { if (id == kClassName()) {
return true; return true;
} else { } else {

View File

@ -157,6 +157,37 @@ size_t ObjectLibrary::GetFactoryCount(size_t *types) const {
return factories; return factories;
} }
size_t ObjectLibrary::GetFactoryCount(const std::string &type) const {
std::unique_lock<std::mutex> lock(mu_);
auto iter = factories_.find(type);
if (iter != factories_.end()) {
return iter->second.size();
} else {
return 0;
}
}
void ObjectLibrary::GetFactoryNames(const std::string &type,
std::vector<std::string> *names) const {
assert(names);
std::unique_lock<std::mutex> lock(mu_);
auto iter = factories_.find(type);
if (iter != factories_.end()) {
for (const auto &f : iter->second) {
names->push_back(f->Name());
}
}
}
void ObjectLibrary::GetFactoryTypes(
std::unordered_set<std::string> *types) const {
assert(types);
std::unique_lock<std::mutex> lock(mu_);
for (const auto &iter : factories_) {
types->insert(iter.first);
}
}
void ObjectLibrary::Dump(Logger *logger) const { void ObjectLibrary::Dump(Logger *logger) const {
std::unique_lock<std::mutex> lock(mu_); std::unique_lock<std::mutex> lock(mu_);
if (logger != nullptr && !factories_.empty()) { if (logger != nullptr && !factories_.empty()) {
@ -276,6 +307,46 @@ Status ObjectRegistry::ListManagedObjects(
} }
} }
// Returns the number of registered types for this registry.
// If specified (not-null), types is updated to include the names of the
// registered types.
size_t ObjectRegistry::GetFactoryCount(const std::string &type) const {
size_t count = 0;
if (parent_ != nullptr) {
count = parent_->GetFactoryCount(type);
}
std::unique_lock<std::mutex> lock(library_mutex_);
for (const auto &library : libraries_) {
count += library->GetFactoryCount(type);
}
return count;
}
void ObjectRegistry::GetFactoryNames(const std::string &type,
std::vector<std::string> *names) const {
assert(names);
names->clear();
if (parent_ != nullptr) {
parent_->GetFactoryNames(type, names);
}
std::unique_lock<std::mutex> lock(library_mutex_);
for (const auto &library : libraries_) {
library->GetFactoryNames(type, names);
}
}
void ObjectRegistry::GetFactoryTypes(
std::unordered_set<std::string> *types) const {
assert(types);
if (parent_ != nullptr) {
parent_->GetFactoryTypes(types);
}
std::unique_lock<std::mutex> lock(library_mutex_);
for (const auto &library : libraries_) {
library->GetFactoryTypes(types);
}
}
void ObjectRegistry::Dump(Logger *logger) const { void ObjectRegistry::Dump(Logger *logger) const {
if (logger != nullptr) { if (logger != nullptr) {
std::unique_lock<std::mutex> lock(library_mutex_); std::unique_lock<std::mutex> lock(library_mutex_);

View File

@ -260,6 +260,77 @@ class MyCustomizable : public Customizable {
std::string name_; std::string name_;
}; };
TEST_F(ObjRegistryTest, TestFactoryCount) {
std::string msg;
auto grand = ObjectRegistry::Default();
auto local = ObjectRegistry::NewInstance();
std::unordered_set<std::string> grand_types, local_types;
std::vector<std::string> grand_names, local_names;
// Check how many types we have on startup.
// Grand should equal local
grand->GetFactoryTypes(&grand_types);
local->GetFactoryTypes(&local_types);
ASSERT_EQ(grand_types, local_types);
size_t grand_count = grand->GetFactoryCount(Env::Type());
size_t local_count = local->GetFactoryCount(Env::Type());
ASSERT_EQ(grand_count, local_count);
grand->GetFactoryNames(Env::Type(), &grand_names);
local->GetFactoryNames(Env::Type(), &local_names);
ASSERT_EQ(grand_names.size(), grand_count);
ASSERT_EQ(local_names.size(), local_count);
ASSERT_EQ(grand_names, local_names);
// Add an Env to the local registry.
// This will add one factory.
auto library = local->AddLibrary("local");
library->AddFactory<Env>(
"A", [](const std::string& /*uri*/, std::unique_ptr<Env>* /*guard */,
std::string* /* errmsg */) { return nullptr; });
ASSERT_EQ(local_count + 1, local->GetFactoryCount(Env::Type()));
ASSERT_EQ(grand_count, grand->GetFactoryCount(Env::Type()));
local->GetFactoryTypes(&local_types);
local->GetFactoryNames(Env::Type(), &local_names);
ASSERT_EQ(grand_names.size() + 1, local_names.size());
ASSERT_EQ(local_names.size(), local->GetFactoryCount(Env::Type()));
if (grand_count == 0) {
// There were no Env when we started. Should have one more type
// than previously
ASSERT_NE(grand_types, local_types);
ASSERT_EQ(grand_types.size() + 1, local_types.size());
} else {
// There was an Env type when we started. The types should match
ASSERT_EQ(grand_types, local_types);
}
// Add a MyCustomizable to the registry. This should be a new type
library->AddFactory<MyCustomizable>(
"MY", [](const std::string& /*uri*/,
std::unique_ptr<MyCustomizable>* /*guard */,
std::string* /* errmsg */) { return nullptr; });
ASSERT_EQ(local_count + 1, local->GetFactoryCount(Env::Type()));
ASSERT_EQ(grand_count, grand->GetFactoryCount(Env::Type()));
ASSERT_EQ(0U, grand->GetFactoryCount(MyCustomizable::Type()));
ASSERT_EQ(1U, local->GetFactoryCount(MyCustomizable::Type()));
local->GetFactoryNames(MyCustomizable::Type(), &local_names);
ASSERT_EQ(1U, local_names.size());
ASSERT_EQ(local_names[0], "MY");
local->GetFactoryTypes(&local_types);
ASSERT_EQ(grand_count == 0 ? 2 : grand_types.size() + 1, local_types.size());
// Add the same name again. We should now have 2 factories.
library->AddFactory<MyCustomizable>(
"MY", [](const std::string& /*uri*/,
std::unique_ptr<MyCustomizable>* /*guard */,
std::string* /* errmsg */) { return nullptr; });
local->GetFactoryNames(MyCustomizable::Type(), &local_names);
ASSERT_EQ(2U, local_names.size());
}
TEST_F(ObjRegistryTest, TestManagedObjects) { TEST_F(ObjRegistryTest, TestManagedObjects) {
auto registry = ObjectRegistry::NewInstance(); auto registry = ObjectRegistry::NewInstance();
auto m_a1 = std::make_shared<MyCustomizable>("", "A"); auto m_a1 = std::make_shared<MyCustomizable>("", "A");