Make Get/SetOption available in LITE mode

This commit is contained in:
mrambacher 2022-03-07 10:23:18 -05:00
parent d74468e348
commit db99c59de5
7 changed files with 145 additions and 75 deletions

View File

@ -207,6 +207,7 @@ class WritableFileWriter {
});
#else // !ROCKSDB_LITE
(void)listeners;
(void)temperature_;
#endif
if (file_checksum_gen_factory != nullptr) {
FileChecksumGenContext checksum_gen_context;

View File

@ -121,7 +121,6 @@ class Configurable {
const std::unordered_map<std::string, std::string>& opt_map,
std::unordered_map<std::string, std::string>* unused);
#ifndef ROCKSDB_LITE
// Updates the named option to the input value, returning OK if successful.
// Note that ConfigureOption does not cause PrepareOptions to be invoked.
// @param config_options Controls how the name/value is processed.
@ -133,9 +132,9 @@ class Configurable {
// 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 the value cannot be successfully parsed.
Status ConfigureOption(const ConfigOptions& config_options,
const std::string& name, const std::string& value);
#endif // ROCKSDB_LITE
virtual Status ConfigureOption(const ConfigOptions& config_options,
const std::string& name,
const std::string& value);
// Configures the options for this class based on the input parameters.
// On successful completion, the object is updated with the settings from
@ -190,6 +189,7 @@ class Configurable {
// @return OK on success.
Status GetOptionNames(const ConfigOptions& config_options,
std::unordered_set<std::string>* result) const;
#endif // ROCKSDB_LITE
// Returns the value of the option associated with the input name
// This method is the functional inverse of ConfigureOption
@ -202,7 +202,6 @@ class Configurable {
// its value cannot be serialized.
virtual Status GetOption(const ConfigOptions& config_options,
const std::string& name, std::string* value) const;
#endif // ROCKSDB_LITE
// Checks to see if this Configurable is equivalent to other.
// This method assumes that the two objects are of the same class.

View File

@ -144,6 +144,7 @@ bool SerializeEnum(const std::unordered_map<std::string, T>& type_map,
return false;
}
#ifndef ROCKSDB_LITE
template <typename T>
Status ParseVector(const ConfigOptions& config_options,
const OptionTypeInfo& elem_info, char separator,
@ -195,11 +196,13 @@ using SerializeFunc = std::function<Status(
using EqualsFunc = std::function<bool(
const ConfigOptions& /*opts*/, const std::string& /*name*/,
const void* /*addr1*/, const void* /*addr2*/, std::string* mismatch)>;
#endif // ROCKSDB_LITE
// A struct for storing constant option information such as option name,
// option type, and offset.
class OptionTypeInfo {
public:
#ifndef ROCKSDB_LITE
// A simple "normal", non-mutable Type "type" at offset
OptionTypeInfo(int offset, OptionType type)
: offset_(offset),
@ -784,6 +787,7 @@ class OptionTypeInfo {
// (e.g. "{a={b=c;}" ) -- missing closing brace
// @return InvalidArgument if an expected delimiter is not found
// e.g. "{a=b}c=d;" -- missing delimiter before "c"
#endif // ROCSDB_LITE
static Status NextToken(const std::string& opts, char delimiter, size_t start,
size_t* end, std::string* token);
@ -791,6 +795,7 @@ class OptionTypeInfo {
constexpr static const char* kIdPropSuffix() { return ".id"; }
private:
#ifndef ROCKSDB_LITE
int offset_;
// The optional function to convert a string to its representation
@ -805,8 +810,10 @@ class OptionTypeInfo {
OptionType type_;
OptionVerificationType verification_;
OptionTypeFlags flags_;
#endif // ROCKSDB_LITE
};
#ifndef ROCKSDB_LITE
// Parses the input value into elements of the result vector. This method
// will break the input value into the individual tokens (based on the
// separator), where each of those tokens will be parsed based on the rules of
@ -943,4 +950,5 @@ bool VectorsAreEqual(const ConfigOptions& config_options,
return true;
}
}
#endif // ROCKSDB_LITE
} // namespace ROCKSDB_NAMESPACE

View File

@ -211,23 +211,18 @@ Status Configurable::ConfigureFromString(const ConfigOptions& config_options,
const std::string& opts_str) {
Status s;
if (!opts_str.empty()) {
#ifndef ROCKSDB_LITE
if (opts_str.find(';') != std::string::npos ||
opts_str.find('=') != std::string::npos) {
if (opts_str.find_first_of(";=") != std::string::npos) {
std::unordered_map<std::string, std::string> opt_map;
s = StringToMap(opts_str, &opt_map);
if (s.ok()) {
s = ConfigureFromMap(config_options, opt_map, nullptr);
}
} else {
#endif // ROCKSDB_LITE
s = ParseStringOptions(config_options, opts_str);
if (s.ok() && config_options.invoke_prepare_options) {
s = PrepareOptions(config_options);
}
#ifndef ROCKSDB_LITE
}
#endif // ROCKSDB_LITE
} else if (config_options.invoke_prepare_options) {
s = PrepareOptions(config_options);
} else {
@ -236,7 +231,6 @@ Status Configurable::ConfigureFromString(const ConfigOptions& config_options,
return s;
}
#ifndef ROCKSDB_LITE
/**
* Sets the value of the named property to the input value, returning OK on
* succcess.
@ -244,10 +238,21 @@ Status Configurable::ConfigureFromString(const ConfigOptions& config_options,
Status Configurable::ConfigureOption(const ConfigOptions& config_options,
const std::string& name,
const std::string& value) {
#ifndef ROCKSDB_LITE
return ConfigurableHelper::ConfigureSingleOption(config_options, *this, name,
value);
#else
(void)value;
if (config_options.ignore_unknown_options) {
return Status::OK();
} else {
return Status::NotSupported("ConfigureOption not supported in LITE mode ",
name);
}
#endif // ROCKSDB_LITE
}
#ifndef ROCKSDB_LITE
/**
* Looks for the named option amongst the options for this type and sets
* the value for it to be the input value.
@ -297,9 +302,19 @@ Status ConfigurableHelper::ConfigureOptions(
}
}
#else
(void)configurable;
if (!config_options.ignore_unknown_options) {
s = Status::NotSupported("ConfigureFromMap not supported in LITE mode");
for (auto opt_it = remaining.begin(); opt_it != remaining.end();) {
Status st = configurable.ConfigureOption(config_options, opt_it->first,
opt_it->second);
if (st.ok()) {
opt_it = remaining.erase(opt_it);
} else {
++opt_it;
if (s.ok() || s.IsNotSupported()) {
s = st;
} else if (!st.IsNotSupported() || !st.IsNotFound()) {
s = st;
}
}
}
#endif // ROCKSDB_LITE
}
@ -519,6 +534,19 @@ Status Configurable::GetOptionString(const ConfigOptions& config_options,
#endif // ROCKSDB_LITE
}
Status Configurable::GetOption(const ConfigOptions& config_options,
const std::string& name,
std::string* value) const {
#ifndef ROCKSDB_LITE
return ConfigurableHelper::GetOption(config_options, *this,
GetOptionName(name), value);
#else
(void)config_options;
*value = "";
return Status::NotFound("Cannot find option: ", name);
#endif // ROCKSDB_LITE
}
#ifndef ROCKSDB_LITE
std::string Configurable::ToString(const ConfigOptions& config_options,
const std::string& prefix) const {
@ -539,12 +567,6 @@ std::string Configurable::SerializeOptions(const ConfigOptions& config_options,
return result;
}
Status Configurable::GetOption(const ConfigOptions& config_options,
const std::string& name,
std::string* value) const {
return ConfigurableHelper::GetOption(config_options, *this,
GetOptionName(name), value);
}
Status ConfigurableHelper::GetOption(const ConfigOptions& config_options,
const Configurable& configurable,

View File

@ -89,7 +89,28 @@ class SimpleConfigurable : public TestConfigurable<Configurable> {
RegisterOptions(name_ + "Pointer", &pointer_, &pointer_option_info);
}
}
#ifdef ROCKSDB_LITE
Status ConfigureOption(const ConfigOptions& options, const std::string& name,
const std::string& value) override {
if (name == "int") {
options_.i = ParseInt(value);
return Status::OK();
} else {
return TestConfigurable::ConfigureOption(options, name, value);
}
}
Status GetOption(const ConfigOptions& options, const std::string& name,
std::string* value) const override {
if (name == "int") {
*value = ROCKSDB_NAMESPACE::ToString(options_.i);
return Status::OK();
} else {
return TestConfigurable::GetOption(options, name, value);
}
}
#endif // ROCKSDB_LITE
}; // End class SimpleConfigurable
using ConfigTestFactoryFunc = std::function<Configurable*()>;
@ -113,13 +134,16 @@ TEST_F(ConfigurableTest, ConfigureFromMapTest) {
auto* opts = configurable->GetOptions<TestOptions>("simple");
ASSERT_OK(configurable->ConfigureFromMap(config_options_, {}));
ASSERT_NE(opts, nullptr);
#ifndef ROCKSDB_LITE
std::unordered_map<std::string, std::string> options_map = {
{"int", "1"}, {"bool", "true"}, {"string", "string"}};
ASSERT_OK(configurable->ConfigureFromMap(config_options_, options_map));
Status st = configurable->ConfigureFromMap(config_options_, options_map);
#ifndef ROCKSDB_LITE
ASSERT_OK(st);
ASSERT_EQ(opts->i, 1);
ASSERT_EQ(opts->b, true);
ASSERT_EQ(opts->s, "string");
#else
ASSERT_TRUE(st.IsNotSupported());
#endif
}
@ -128,16 +152,18 @@ TEST_F(ConfigurableTest, ConfigureFromStringTest) {
auto* opts = configurable->GetOptions<TestOptions>("simple");
ASSERT_OK(configurable->ConfigureFromString(config_options_, ""));
ASSERT_NE(opts, nullptr);
#ifndef ROCKSDB_LITE // GetOptionsFromMap is not supported in ROCKSDB_LITE
ASSERT_OK(configurable->ConfigureFromString(config_options_,
"int=1;bool=true;string=s"));
Status st = configurable->ConfigureFromString(config_options_,
"int=1;bool=true;string=s");
#ifndef ROCKSDB_LITE
ASSERT_OK(st);
ASSERT_EQ(opts->i, 1);
ASSERT_EQ(opts->b, true);
ASSERT_EQ(opts->s, "s");
#else
ASSERT_TRUE(st.IsNotSupported());
#endif
}
#ifndef ROCKSDB_LITE // GetOptionsFromMap is not supported in ROCKSDB_LITE
TEST_F(ConfigurableTest, ConfigureIgnoreTest) {
std::unique_ptr<Configurable> configurable(SimpleConfigurable::Create());
std::unordered_map<std::string, std::string> options_map = {{"unused", "u"}};
@ -149,6 +175,7 @@ TEST_F(ConfigurableTest, ConfigureIgnoreTest) {
ASSERT_OK(configurable->ConfigureFromString(ignore, "unused=u"));
}
#ifndef ROCKSDB_LITE // GetOptionsFromMap is not supported in ROCKSDB_LITE
TEST_F(ConfigurableTest, ConfigureNestedOptionsTest) {
std::unique_ptr<Configurable> base, copy;
std::string opt_str;
@ -164,12 +191,13 @@ TEST_F(ConfigurableTest, ConfigureNestedOptionsTest) {
ASSERT_OK(copy->ConfigureFromString(config_options_, opt_str));
ASSERT_TRUE(base->AreEquivalent(config_options_, copy.get(), &mismatch));
}
#endif // ROCKSDB_LITE
TEST_F(ConfigurableTest, GetOptionsTest) {
std::unique_ptr<Configurable> simple;
simple.reset(
SimpleConfigurable::Create("simple", TestConfigMode::kAllOptMode));
#ifndef ROCKSDB_LITE // LITE mode does not support the x.y options
int i = 11;
for (auto opt : {"", "shared.", "unique.", "pointer."}) {
std::string value;
@ -183,15 +211,25 @@ TEST_F(ConfigurableTest, GetOptionsTest) {
expected));
ASSERT_OK(simple->GetOption(config_options_, opt_name + "string", &value));
ASSERT_EQ(expected, value);
ASSERT_NOK(
simple->ConfigureOption(config_options_, opt_name + "bad", expected));
ASSERT_NOK(simple->GetOption(config_options_, "bad option", &value));
ASSERT_TRUE(value.empty());
i += 11;
}
#endif // ROCKSDB_LITE
{
std::string value;
ASSERT_OK(simple->ConfigureOption(config_options_, "int", "42"));
ASSERT_OK(simple->GetOption(config_options_, "int", &value));
ASSERT_EQ("42", value);
ASSERT_NOK(simple->ConfigureOption(config_options_, "bad", "bad"));
ASSERT_NOK(simple->GetOption(config_options_, "bad", &value));
ASSERT_TRUE(value.empty());
}
}
#ifndef ROCKSDB_LITE // Reset and invalid format not handled by this test
TEST_F(ConfigurableTest, ConfigureBadOptionsTest) {
std::unique_ptr<Configurable> configurable(SimpleConfigurable::Create());
auto* opts = configurable->GetOptions<TestOptions>("simple");
@ -204,6 +242,7 @@ TEST_F(ConfigurableTest, ConfigureBadOptionsTest) {
configurable->ConfigureFromString(config_options_, "int=33;unused=u"));
ASSERT_EQ(opts->i, 42);
}
#endif // ROCKSDB_LITE
TEST_F(ConfigurableTest, InvalidOptionTest) {
std::unique_ptr<Configurable> configurable(SimpleConfigurable::Create());
@ -216,6 +255,7 @@ TEST_F(ConfigurableTest, InvalidOptionTest) {
configurable->ConfigureOption(config_options_, "bad-option", "bad"));
}
#ifndef ROCKSDB_LITE
static std::unordered_map<std::string, OptionTypeInfo> validated_option_info = {
#ifndef ROCKSDB_LITE
{"validated",

View File

@ -43,6 +43,49 @@ ConfigOptions::ConfigOptions(const DBOptions& db_opts) : env(db_opts.env) {
#endif
}
Status StringToMap(const std::string& opts_str,
std::unordered_map<std::string, std::string>* opts_map) {
assert(opts_map);
// Example:
// opts_str = "write_buffer_size=1024;max_write_buffer_number=2;"
// "nested_opt={opt1=1;opt2=2};max_bytes_for_level_base=100"
size_t pos = 0;
std::string opts = trim(opts_str);
// If the input string starts and ends with "{...}", strip off the brackets
while (opts.size() > 2 && opts[0] == '{' && opts[opts.size() - 1] == '}') {
opts = trim(opts.substr(1, opts.size() - 2));
}
while (pos < opts.size()) {
size_t eq_pos = opts.find_first_of("={};", pos);
if (eq_pos == std::string::npos) {
return Status::InvalidArgument("Mismatched key value pair, '=' expected");
} else if (opts[eq_pos] != '=') {
return Status::InvalidArgument("Unexpected char in key");
}
std::string key = trim(opts.substr(pos, eq_pos - pos));
if (key.empty()) {
return Status::InvalidArgument("Empty key found");
}
std::string value;
Status s = OptionTypeInfo::NextToken(opts, ';', eq_pos + 1, &pos, &value);
if (!s.ok()) {
return s;
} else {
(*opts_map)[key] = value;
if (pos == std::string::npos) {
break;
} else {
pos++;
}
}
}
return Status::OK();
}
Status ValidateOptions(const DBOptions& db_opts,
const ColumnFamilyOptions& cf_opts) {
Status s;
@ -552,51 +595,6 @@ Status ConfigureFromMap(
return s;
}
Status StringToMap(const std::string& opts_str,
std::unordered_map<std::string, std::string>* opts_map) {
assert(opts_map);
// Example:
// opts_str = "write_buffer_size=1024;max_write_buffer_number=2;"
// "nested_opt={opt1=1;opt2=2};max_bytes_for_level_base=100"
size_t pos = 0;
std::string opts = trim(opts_str);
// If the input string starts and ends with "{...}", strip off the brackets
while (opts.size() > 2 && opts[0] == '{' && opts[opts.size() - 1] == '}') {
opts = trim(opts.substr(1, opts.size() - 2));
}
while (pos < opts.size()) {
size_t eq_pos = opts.find_first_of("={};", pos);
if (eq_pos == std::string::npos) {
return Status::InvalidArgument("Mismatched key value pair, '=' expected");
} else if (opts[eq_pos] != '=') {
return Status::InvalidArgument("Unexpected char in key");
}
std::string key = trim(opts.substr(pos, eq_pos - pos));
if (key.empty()) {
return Status::InvalidArgument("Empty key found");
}
std::string value;
Status s = OptionTypeInfo::NextToken(opts, ';', eq_pos + 1, &pos, &value);
if (!s.ok()) {
return s;
} else {
(*opts_map)[key] = value;
if (pos == std::string::npos) {
break;
} else {
pos++;
}
}
}
return Status::OK();
}
Status GetStringFromDBOptions(std::string* opt_string,
const DBOptions& db_options,
const std::string& delimiter) {
@ -831,6 +829,7 @@ std::unordered_map<std::string, Temperature>
{"kHot", Temperature::kHot},
{"kWarm", Temperature::kWarm},
{"kCold", Temperature::kCold}};
#endif // ROCKSDB_LITE
Status OptionTypeInfo::NextToken(const std::string& opts, char delimiter,
size_t pos, size_t* end, std::string* token) {
@ -885,6 +884,7 @@ Status OptionTypeInfo::NextToken(const std::string& opts, char delimiter,
return Status::OK();
}
#ifndef ROCKSDB_LITE
Status OptionTypeInfo::Parse(const ConfigOptions& config_options,
const std::string& opt_name,
const std::string& value, void* opt_ptr) const {

View File

@ -64,11 +64,11 @@ std::unique_ptr<Configurable> CFOptionsAsConfigurable(
std::unique_ptr<Configurable> CFOptionsAsConfigurable(
const ColumnFamilyOptions& opts,
const std::unordered_map<std::string, std::string>* opt_map = nullptr);
#endif // !ROCKSDB_LITE
extern Status StringToMap(
const std::string& opts_str,
std::unordered_map<std::string, std::string>* opts_map);
#endif // !ROCKSDB_LITE
struct OptionsHelper {
static const std::string kCFOptionsName /*= "ColumnFamilyOptions"*/;