diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b2f3fb13f..9f3e728734 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1003,6 +1003,7 @@ set(SOURCES utilities/transactions/write_unprepared_txn.cc utilities/transactions/write_unprepared_txn_db.cc utilities/ttl/db_ttl_impl.cc + utilities/use_cases.cc utilities/wal_filter.cc utilities/write_batch_with_index/write_batch_with_index.cc utilities/write_batch_with_index/write_batch_with_index_internal.cc) diff --git a/utilities/use_cases.cc b/utilities/use_cases.cc new file mode 100644 index 0000000000..3be6f1613e --- /dev/null +++ b/utilities/use_cases.cc @@ -0,0 +1,169 @@ +#include +#include +#include +#include +#include + +#include "rocksdb/db_crashtest_use_case.h" +#include "rocksdb/options.h" +#include "rocksdb/use_case.h" +#include "rocksdb/utilities/customizable_util.h" +#include "rocksdb/utilities/options_type.h" + +namespace ROCKSDB_NAMESPACE { +Status ToUseCases(const ConfigOptions& cfg_opts, const std::string& value, + std::vector>& use_cases) { + Status status; + for (size_t start = 0, end = 0; + status.ok() && start < value.size() && end != std::string::npos; + start = end + 1) { + std::string token; + status = OptionTypeInfo::NextToken(value, ',', start, &end, &token); + if (status.ok()) { + if (token.find('*') == std::string::npos) { + std::shared_ptr use_case; + status = UseCase::CreateFromString(cfg_opts, token, &use_case); + if (status.ok() && use_case) { + use_cases.push_back(use_case); + } + } else { + // TODO: Pattern match on the factory names in factories to match the + // token + // std::vector factories; + // ObjectRegistry::Default()->GetFactoryNames(UseCase::Type(), &factories); + // return bad status (some sort) + } + } + } + return status; +} + +static int RegisterBuiltinDBCrashtestUseCases(ObjectLibrary& library, + const std::string& arg) { + library.AddFactory( + SimpleDefaultParams::kClassName(), + [](const std::string& /*uri*/, + std::unique_ptr* guard, + std::string* /*errmsg*/) { + guard->reset(new SimpleDefaultParams()); + return guard->get(); + }); + library.AddFactory( + TxnParams::kClassName(), + [](const std::string& /*uri*/, + std::unique_ptr* guard, + std::string* /*errmsg*/) { + guard->reset(new TxnParams()); + return guard->get(); + }); + library.AddFactory( + BestEffortsRecoveryParams::kClassName(), + [](const std::string& /*uri*/, + std::unique_ptr* guard, + std::string* /*errmsg*/) { + guard->reset(new BestEffortsRecoveryParams()); + return guard->get(); + }); + library.AddFactory( + BlobParams::kClassName(), + [](const std::string& /*uri*/, + std::unique_ptr* guard, + std::string* /*errmsg*/) { + guard->reset(new BlobParams()); + return guard->get(); + }); + library.AddFactory( + TieredParams::kClassName(), + [](const std::string& /*uri*/, + std::unique_ptr* guard, + std::string* /*errmsg*/) { + guard->reset(new TieredParams()); + return guard->get(); + }); + library.AddFactory( + MultiopsTxnDefaultParams::kClassName(), + [](const std::string& /*uri*/, + std::unique_ptr* guard, + std::string* /*errmsg*/) { + guard->reset(new MultiopsTxnDefaultParams()); + return guard->get(); + }); + return 1; +} + +static int RegisterBuiltinUseCases(ObjectLibrary& library, + const std::string& arg) { + library.AddFactory( + DBCrashtestUseCase::kClassName(), + [](const std::string& /*uri*/, + std::unique_ptr* guard, + std::string* /*errmsg*/) { + guard->reset(new DBCrashtestUseCase()); + return guard->get(); + }); + RegisterBuiltinDBCrashtestUseCases(library, arg); + return 1; +} + +Status UseCase::CreateFromString(const ConfigOptions& cfg_opts, + const std::string& value, + std::shared_ptr* result) { + static std::once_flag once; + std::call_once(once, [&]() { + RegisterBuiltinUseCases(*(ObjectLibrary::Default().get()), ""); + }); + Status status = + LoadSharedObject(cfg_opts, value, result); + return status; +} + +Status UseCase::ValidateOptions(const ConfigOptions& cfg_opts, + const std::string& validate_against, + const DBOptions& db_opts, + std::set& valid_opts, + std::set& invalid_opts) { + std::vector> use_cases; + Status s = ToUseCases(cfg_opts, validate_against, use_cases); + if (s.ok()) { + for (const auto& use_case : use_cases) { + use_case->Validate(cfg_opts, db_opts, valid_opts, invalid_opts); + } + if (!invalid_opts.empty()) { + s = Status::InvalidArgument(); + } + } + return s; +} + +Status UseCase::ValidateOptions(const ConfigOptions& cfg_opts, + const std::string& validate_against, + const ColumnFamilyOptions& cf_opts, + std::set& valid_opts, + std::set& invalid_opts) { + std::vector> use_cases; + Status s = ToUseCases(cfg_opts, validate_against, use_cases); + if (s.ok()) { + for (const auto& use_case : use_cases) { + use_case->Validate(cfg_opts, cf_opts, valid_opts, invalid_opts); + } + if (!invalid_opts.empty()) { + s = Status::InvalidArgument(); + } + } + return s; +} + +Status UseCase::ValidateOptions(const ConfigOptions& cfg_opts, + const std::string& validate_against, + const Options& opts, + std::set& valid_opts, + std::set& invalid_opts) { + const DBOptions* db_opts = &opts; + const ColumnFamilyOptions* cf_opts = &opts; + Status s = ValidateOptions(cfg_opts, validate_against, *db_opts, valid_opts, invalid_opts); + if (s.ok()) { + s = ValidateOptions(cfg_opts, validate_against, *cf_opts, valid_opts, invalid_opts); + } + return s; +} +} // namespace ROCKSDB_NAMESPACE \ No newline at end of file