Add atomic knob unit test

This commit is contained in:
Lukas Joswiak 2021-08-18 17:55:47 -07:00
parent ad5fb39e68
commit 4107c35538
8 changed files with 77 additions and 46 deletions

View File

@ -77,7 +77,7 @@ void ConfigTransactionCommitRequest::set(KeyRef key, ValueRef value) {
} else {
ConfigKey configKey = ConfigKeyRef::decodeKey(key);
auto knobValue = IKnobCollection::parseKnobValue(
configKey.knobName.toString(), value.toString(), IKnobCollection::Type::TEST);
configKey.knobName.toString(), value.toString(), IKnobCollection::Type::NONATOMIC_TEST);
mutations.emplace_back_deep(arena, configKey, knobValue.contents());
}
}

View File

@ -28,8 +28,10 @@ std::unique_ptr<IKnobCollection> IKnobCollection::create(Type type, Randomize ra
return std::make_unique<ClientKnobCollection>(randomize, isSimulated);
} else if (type == Type::SERVER) {
return std::make_unique<ServerKnobCollection>(randomize, isSimulated);
} else if (type == Type::TEST) {
return std::make_unique<TestKnobCollection>(randomize, isSimulated);
} else if (type == Type::ATOMIC_TEST) {
return std::make_unique<TestKnobCollection>(randomize, isSimulated, Atomic::YES);
} else if (type == Type::NONATOMIC_TEST) {
return std::make_unique<TestKnobCollection>(randomize, isSimulated, Atomic::NO);
}
UNSTOPPABLE_ASSERT(false);
}
@ -64,7 +66,7 @@ KnobValue IKnobCollection::parseKnobValue(std::string const& knobName, std::stri
serverKnobCollection = create(type, Randomize::False, IsSimulated::False);
}
return serverKnobCollection->parseKnobValue(knobName, knobValue);
} else if (type == Type::TEST) {
} else if (type == Type::ATOMIC_TEST || type == Type::NONATOMIC_TEST) {
if (!testKnobCollection) {
testKnobCollection = create(type, Randomize::False, IsSimulated::False);
}

View File

@ -44,7 +44,8 @@ public:
enum class Type {
CLIENT,
SERVER,
TEST,
ATOMIC_TEST,
NONATOMIC_TEST,
};
static std::unique_ptr<IKnobCollection> create(Type, Randomize, IsSimulated);

View File

@ -20,19 +20,19 @@
#include "fdbclient/TestKnobCollection.h"
TestKnobCollection::TestKnobCollection(Randomize randomize, IsSimulated isSimulated)
: serverKnobCollection(randomize, isSimulated) {
TestKnobCollection::TestKnobCollection(Randomize randomize, IsSimulated isSimulated, Atomic atomic)
: serverKnobCollection(randomize, isSimulated), atomic(atomic) {
initialize(randomize, isSimulated);
}
void TestKnobCollection::initialize(Randomize randomize, IsSimulated isSimulated) {
serverKnobCollection.initialize(randomize, isSimulated);
testKnobs.initialize();
testKnobs.initialize(atomic);
}
void TestKnobCollection::reset(Randomize randomize, IsSimulated isSimulated) {
serverKnobCollection.reset(randomize, isSimulated);
testKnobs.reset();
testKnobs.reset(atomic);
}
void TestKnobCollection::clearTestKnobs() {
@ -60,18 +60,18 @@ bool TestKnobCollection::isAtomic(std::string const& knobName) const {
return serverKnobCollection.isAtomic(knobName) || testKnobs.isAtomic(knobName);
}
#define init(knob, value) initKnob(knob, value, #knob, Atomic::NO)
#define init(knob, value, atomic) initKnob(knob, value, #knob, atomic)
TestKnobs::TestKnobs() {
initialize();
initialize(Atomic::NO);
}
void TestKnobs::initialize() {
init(TEST_LONG, 0);
init(TEST_INT, 0);
init(TEST_DOUBLE, 0.0);
init(TEST_BOOL, false);
init(TEST_STRING, "");
void TestKnobs::initialize(Atomic atomic) {
init(TEST_LONG, 0, atomic);
init(TEST_INT, 0, atomic);
init(TEST_DOUBLE, 0.0, atomic);
init(TEST_BOOL, false, atomic);
init(TEST_STRING, "", atomic);
}
bool TestKnobs::operator==(TestKnobs const& rhs) const {

View File

@ -33,19 +33,20 @@ public:
std::string TEST_STRING;
bool operator==(TestKnobs const&) const;
bool operator!=(TestKnobs const&) const;
void initialize();
void initialize(Atomic);
};
/*
* Stores both flow knobs, client knobs, server knobs, and test knobs. As the name implies, this class is only meant to
* be used for testing
* Stores both flow knobs, client knobs, server knobs, and test knobs. As the
* name implies, this class is only meant to be used for testing.
*/
class TestKnobCollection : public IKnobCollection {
ServerKnobCollection serverKnobCollection;
TestKnobs testKnobs;
Atomic atomic;
public:
TestKnobCollection(Randomize randomize, IsSimulated isSimulated);
TestKnobCollection(Randomize randomize, IsSimulated isSimulated, Atomic atomic);
void initialize(Randomize randomize, IsSimulated isSimulated) override;
void reset(Randomize randomize, IsSimulated isSimulated) override;
FlowKnobs const& getFlowKnobs() const override { return serverKnobCollection.getFlowKnobs(); }

View File

@ -163,17 +163,18 @@ class ReadFromLocalConfigEnvironment {
public:
ReadFromLocalConfigEnvironment(std::string const& dataDir,
std::string const& configPath,
std::map<std::string, std::string> const& manualKnobOverrides)
std::map<std::string, std::string> const& manualKnobOverrides,
TestKnobType testKnobType = TestKnobType::NONATOMIC)
: dataDir(dataDir),
localConfiguration(makeReference<LocalConfiguration>(dataDir, configPath, manualKnobOverrides, IsTest::True)),
localConfiguration(makeReference<LocalConfiguration>(dataDir, configPath, manualKnobOverrides, testKnobType)),
consumer(Never()) {}
Future<Void> setup() { return setup(this); }
Future<Void> restartLocalConfig(std::string const& newConfigPath) {
Future<Void> restartLocalConfig(std::string const& newConfigPath, TestKnobType testKnobType) {
std::map<std::string, std::string> manualKnobOverrides = {};
localConfiguration =
makeReference<LocalConfiguration>(dataDir, newConfigPath, manualKnobOverrides, IsTest::True);
makeReference<LocalConfiguration>(dataDir, newConfigPath, manualKnobOverrides, testKnobType);
return setup();
}
@ -216,11 +217,13 @@ class LocalConfigEnvironment {
public:
LocalConfigEnvironment(std::string const& dataDir,
std::string const& configPath,
std::map<std::string, std::string> const& manualKnobOverrides = {})
: readFrom(dataDir, configPath, manualKnobOverrides) {}
std::map<std::string, std::string> const& manualKnobOverrides = {},
TestKnobType testKnobType = TestKnobType::NONATOMIC)
: readFrom(dataDir, configPath, manualKnobOverrides, testKnobType) {}
Future<Void> setup(ConfigClassSet const& configClassSet) { return readFrom.setup(); }
Future<Void> restartLocalConfig(std::string const& newConfigPath) {
return readFrom.restartLocalConfig(newConfigPath);
Future<Void> restartLocalConfig(std::string const& newConfigPath,
TestKnobType testKnobType = TestKnobType::NONATOMIC) {
return readFrom.restartLocalConfig(newConfigPath, testKnobType);
}
Future<Void> getError() const { return Never(); }
Future<Void> clear(Optional<KeyRef> configClass) { return addMutation(configClass, {}); }
@ -276,8 +279,9 @@ public:
broadcaster.registerWorker(readFrom.lastSeenVersion(), readFrom.configClassSet(), Never(), cbi->get());
}
Future<Void> restartLocalConfig(std::string const& newConfigPath) {
return readFrom.restartLocalConfig(newConfigPath);
Future<Void> restartLocalConfig(std::string const& newConfigPath,
TestKnobType testKnobType = TestKnobType::NONATOMIC) {
return readFrom.restartLocalConfig(newConfigPath, testKnobType);
}
void compact() { broadcaster.compact(lastWrittenVersion); }
@ -402,8 +406,9 @@ public:
broadcaster.registerWorker(readFrom.lastSeenVersion(), readFrom.configClassSet(), Never(), cbi->get());
}
Future<Void> restartLocalConfig(std::string const& newConfigPath) {
return readFrom.restartLocalConfig(newConfigPath);
Future<Void> restartLocalConfig(std::string const& newConfigPath,
TestKnobType testKnobType = TestKnobType::NONATOMIC) {
return readFrom.restartLocalConfig(newConfigPath, testKnobType);
}
Future<Void> compact() { return writeTo.compact(); }
@ -509,6 +514,23 @@ Future<Void> testSet(UnitTestParameters params) {
return Void();
}
ACTOR template <class Env>
Future<Void> testAtomicSet(UnitTestParameters params) {
state Env env(params.getDataDir(), "class-A", {}, TestKnobType::ATOMIC);
wait(env.setup(ConfigClassSet({ "class-A"_sr })));
state bool restarted = false;
try {
wait(set(env, "class-A"_sr, int64_t{ 1 }));
} catch (Error& e) {
ASSERT(e.code() == error_code_knob_restart_required);
restarted = true;
}
ASSERT(restarted);
wait(env.restartLocalConfig("class-A", TestKnobType::ATOMIC));
wait(check(env, int64_t{ 1 }));
return Void();
}
ACTOR template <class Env>
Future<Void> testClear(UnitTestParameters params) {
state Env env(params.getDataDir(), "class-A");
@ -611,6 +633,12 @@ TEST_CASE("/fdbserver/ConfigDB/LocalConfiguration/Set") {
return Void();
}
// TODO: Add more atomic knob unit tests
TEST_CASE("/fdbserver/ConfigDB/LocalConfiguration/AtomicSet") {
wait(testAtomicSet<LocalConfigEnvironment>(params));
return Void();
}
TEST_CASE("/fdbserver/ConfigDB/LocalConfiguration/Restart") {
wait(testRestartLocalConfig<LocalConfigEnvironment>(params));
return Void();

View File

@ -27,8 +27,6 @@
#include "flow/actorcompiler.h" // This must be the last #include.
FDB_DEFINE_BOOLEAN_PARAM(IsTest);
namespace {
const KeyRef configPathKey = "configPath"_sr;
@ -121,8 +119,8 @@ class LocalConfigurationImpl {
explicit ManualKnobOverrides(std::map<std::string, std::string> const& overrides) {
for (const auto& [knobName, knobValueString] : overrides) {
try {
auto knobValue =
IKnobCollection::parseKnobValue(knobName, knobValueString, IKnobCollection::Type::TEST);
auto knobValue = IKnobCollection::parseKnobValue(
knobName, knobValueString, IKnobCollection::Type::NONATOMIC_TEST);
this->overrides[stringToKeyRef(knobName)] = knobValue;
} catch (Error& e) {
if (e.code() == error_code_invalid_option) {
@ -337,13 +335,14 @@ public:
LocalConfigurationImpl(std::string const& dataFolder,
std::string const& configPath,
std::map<std::string, std::string> const& manualKnobOverrides,
IsTest isTest)
TestKnobType testKnobType)
: id(deterministicRandom()->randomUniqueID()), kvStore(dataFolder, id, "localconf-"),
configKnobOverrides(configPath), manualKnobOverrides(manualKnobOverrides), cc("LocalConfiguration"),
snapshots("Snapshots", cc), changeRequestsFetched("ChangeRequestsFetched", cc), mutations("Mutations", cc) {
if (isTest) {
if (testKnobType != TestKnobType::DISABLED) {
testKnobCollection =
IKnobCollection::create(IKnobCollection::Type::TEST,
IKnobCollection::create(testKnobType == TestKnobType::NONATOMIC ? IKnobCollection::Type::NONATOMIC_TEST
: IKnobCollection::Type::ATOMIC_TEST,
Randomize::False,
g_network->isSimulated() ? IsSimulated::True : IsSimulated::False);
}
@ -416,7 +415,7 @@ public:
configKnobOverrides.set(
{}, "knob_name_that_does_not_exist"_sr, KnobValueRef::create(ParsedKnobValue(int{ 1 })));
auto testKnobCollection =
IKnobCollection::create(IKnobCollection::Type::TEST, Randomize::False, IsSimulated::False);
IKnobCollection::create(IKnobCollection::Type::NONATOMIC_TEST, Randomize::False, IsSimulated::False);
// Should only trace and not throw an error:
configKnobOverrides.update(*testKnobCollection);
}
@ -425,7 +424,7 @@ public:
ConfigKnobOverrides configKnobOverrides;
configKnobOverrides.set({}, "test_int"_sr, KnobValueRef::create(ParsedKnobValue("not_an_int")));
auto testKnobCollection =
IKnobCollection::create(IKnobCollection::Type::TEST, Randomize::False, IsSimulated::False);
IKnobCollection::create(IKnobCollection::Type::NONATOMIC_TEST, Randomize::False, IsSimulated::False);
// Should only trace and not throw an error:
configKnobOverrides.update(*testKnobCollection);
}
@ -434,8 +433,8 @@ public:
LocalConfiguration::LocalConfiguration(std::string const& dataFolder,
std::string const& configPath,
std::map<std::string, std::string> const& manualKnobOverrides,
IsTest isTest)
: impl(PImpl<LocalConfigurationImpl>::create(dataFolder, configPath, manualKnobOverrides, isTest)) {}
TestKnobType testKnobType)
: impl(PImpl<LocalConfigurationImpl>::create(dataFolder, configPath, manualKnobOverrides, testKnobType)) {}
LocalConfiguration::~LocalConfiguration() = default;

View File

@ -30,7 +30,7 @@
#include "flow/Arena.h"
#include "flow/Knobs.h"
FDB_DECLARE_BOOLEAN_PARAM(IsTest);
enum class TestKnobType { DISABLED, ATOMIC, NONATOMIC };
/*
* Each worker maintains a LocalConfiguration object used to update its knob collection.
@ -50,7 +50,7 @@ public:
LocalConfiguration(std::string const& dataFolder,
std::string const& configPath,
std::map<std::string, std::string> const& manualKnobOverrides,
IsTest = IsTest::False);
TestKnobType = TestKnobType::DISABLED);
~LocalConfiguration();
FlowKnobs const& getFlowKnobs() const;
ClientKnobs const& getClientKnobs() const;