Skip to content

Commit

Permalink
options: Add generic validation implementation for use cases
Browse files Browse the repository at this point in the history
A UseCase class is a Configurable class which represents a specific use case
in rocksdb/speedb which we can use to populate options according to the
specification of that use case, and/or validate the user's options against
the expected possible configurations which fit that use case.

As such, we add here 2 methods in Configurable which essentially take
a UseCase and a set of options, and validates that the values
of these options matches the values that the use case requires.
  • Loading branch information
AmnonHanuhov committed Sep 19, 2023
1 parent 86a315d commit 41363d6
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 0 deletions.
63 changes: 63 additions & 0 deletions options/configurable.cc
Original file line number Diff line number Diff line change
Expand Up @@ -709,4 +709,67 @@ Status Configurable::GetOptionsMap(
}
return status;
}

int ConfigurableHelper::CheckSomeUseCases(
const ConfigOptions& config_options, const Configurable& configurable,
const std::unordered_map<std::string, OptionTypeInfo>& type_map,
const void* opt_ptr,
std::vector<std::pair<std::string, UseCaseConfig>>& uses,
std::set<std::string>& valid, std::set<std::string>& invalid) {
int found = 1;
std::string elem_name;
while (found > 0 && !uses.empty()) {
found = 0;
for (size_t idx = 0; idx < uses.size();) {
const auto& it = uses[idx];
const std::string& opt_name = configurable.GetOptionName(it.first);
const auto opt_info =
OptionTypeInfo::Find(opt_name, type_map, &elem_name);
if (opt_info == nullptr) { // Did not find the option. Skip it
++idx;
} else {
const void* addr = opt_info->GetOffset(opt_ptr);
if (it.second.IsValid(addr)) {
printf("MJR: Option[%s] is valid\n", opt_name.c_str());
valid.insert(it.first);
} else {
printf("MJR: Option[%s] is invalid\n", opt_name.c_str());
invalid.insert(it.first);
}
// Remove it from the list. Swap it with the last one
// and remove the last one
uses[idx] = uses.back();
uses.pop_back();
found++;
}
}
}
return static_cast<int>(invalid.size());
}

bool ConfigurableHelper::CheckUseCases(
const ConfigOptions& config_options, const Configurable& configurable,
const std::vector<std::unordered_map<std::string, UseCaseConfig>*>& uses,
std::set<std::string>& valid, std::set<std::string>& invalid,
std::unordered_map<std::string, UseCaseConfig>* unused) {
std::vector<std::pair<std::string, UseCaseConfig>> remaining;
if (!uses.empty()) {
for (const auto& uc_map : uses) {
remaining.assign(uc_map->begin(), uc_map->end());
}
for (const auto& iter : configurable.options_) {
if (iter.type_map != nullptr) {
CheckSomeUseCases(config_options, configurable, *(iter.type_map),
iter.opt_ptr, remaining, valid, invalid);
if (remaining.empty()) { // Are there more options left?
break;
}
}
}
}
if (unused != nullptr && !remaining.empty()) {
unused->insert(remaining.begin(), remaining.end());
}
return static_cast<int>(invalid.size());
}
} // namespace ROCKSDB_NAMESPACE
16 changes: 16 additions & 0 deletions options/configurable_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@
#pragma once

#include <map>
#include <set>
#include <stdexcept>
#include <string>
#include <vector>

#include "rocksdb/configurable.h"
#include "rocksdb/convenience.h"
#include "rocksdb/use_case.h"

namespace ROCKSDB_NAMESPACE {
class UseCaseConfig;
// Helper class defining static methods for supporting the Configurable
// class. The purpose of this class is to keep the Configurable class
// as tight as possible and provide methods for doing the actual work
Expand Down Expand Up @@ -159,6 +162,19 @@ class ConfigurableHelper {
const Configurable& that_one,
std::string* mismatch);

static bool CheckUseCases(
const ConfigOptions& config_options, const Configurable& configurable,
const std::vector<std::unordered_map<std::string, UseCaseConfig>*>& uses,
std::set<std::string>& valid, std::set<std::string>& invalid,
std::unordered_map<std::string, UseCaseConfig>* unused);

static int CheckSomeUseCases(
const ConfigOptions& config_options, const Configurable& configurable,
const std::unordered_map<std::string, OptionTypeInfo>& type_map,
const void* opt_ptr,
std::vector<std::pair<std::string, UseCaseConfig>>& uses,
std::set<std::string>& valid, std::set<std::string>& invalid);

private:
// Looks for the option specified by name in the RegisteredOptions.
// This method traverses the types in the input options vector. If an entry
Expand Down

0 comments on commit 41363d6

Please sign in to comment.