2021-05-14 02:22:25 +08:00
|
|
|
/*
|
|
|
|
* ConfigBroadcaster.actor.cpp
|
|
|
|
*
|
|
|
|
* This source file is part of the FoundationDB open source project
|
|
|
|
*
|
|
|
|
* Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "fdbclient/CoordinationInterface.h"
|
|
|
|
#include "fdbserver/ConfigBroadcaster.h"
|
|
|
|
#include "fdbserver/LocalConfiguration.h"
|
|
|
|
#include "fdbclient/Tuple.h"
|
|
|
|
#include "flow/UnitTest.h"
|
|
|
|
#include "flow/actorcompiler.h" // must be last include
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2021-05-14 05:17:52 +08:00
|
|
|
std::map<Key, Value> const testManualKnobOverrides = {
|
|
|
|
{ "test_double"_sr, "1.0"_sr },
|
|
|
|
};
|
|
|
|
|
|
|
|
TestKnobs const& getExpectedTestKnobsEmptyConfig() {
|
|
|
|
static std::unique_ptr<TestKnobs> knobs;
|
|
|
|
if (!knobs) {
|
|
|
|
knobs = std::make_unique<TestKnobs>();
|
|
|
|
knobs->setKnob("test_double", "1.0");
|
2021-05-14 03:55:33 +08:00
|
|
|
}
|
2021-05-14 05:17:52 +08:00
|
|
|
return *knobs;
|
|
|
|
}
|
|
|
|
|
|
|
|
TestKnobs const& getExpectedTestKnobsFinal() {
|
|
|
|
static std::unique_ptr<TestKnobs> knobs;
|
|
|
|
if (!knobs) {
|
|
|
|
knobs = std::make_unique<TestKnobs>();
|
|
|
|
knobs->setKnob("test_long", "100");
|
|
|
|
knobs->setKnob("test_int", "2");
|
|
|
|
knobs->setKnob("test_bool", "true");
|
|
|
|
knobs->setKnob("test_string", "x");
|
|
|
|
knobs->setKnob("test_double", "1.0");
|
|
|
|
}
|
|
|
|
return *knobs;
|
2021-05-14 03:55:33 +08:00
|
|
|
}
|
|
|
|
|
2021-05-14 02:22:25 +08:00
|
|
|
ACTOR template <class ConfigStore>
|
2021-05-14 15:41:02 +08:00
|
|
|
Future<Void> setTestSnapshot(ConfigStore* configStore, Version* lastWrittenVersion) {
|
|
|
|
TraceEvent("WritingTestSnapshot").detail("LastWrittenVersion", *lastWrittenVersion);
|
2021-05-14 02:22:25 +08:00
|
|
|
std::map<ConfigKey, Value> snapshot = {
|
|
|
|
{ ConfigKeyRef("class-A"_sr, "test_int"_sr), "1"_sr },
|
|
|
|
{ ConfigKeyRef("class-B"_sr, "test_int"_sr), "2"_sr },
|
|
|
|
{ ConfigKeyRef("class-C"_sr, "test_int"_sr), "3"_sr },
|
2021-05-14 05:17:52 +08:00
|
|
|
{ ConfigKeyRef("class-B"_sr, "test_double"_sr), "4.0"_sr },
|
2021-05-14 02:22:25 +08:00
|
|
|
{ ConfigKeyRef("class-A"_sr, "test_string"_sr), "x"_sr },
|
|
|
|
};
|
2021-05-14 15:41:02 +08:00
|
|
|
wait(configStore->setSnapshot(std::move(snapshot), ++(*lastWrittenVersion)));
|
2021-05-14 02:22:25 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
|
|
|
void appendVersionedMutation(Standalone<VectorRef<VersionedConfigMutationRef>>& versionedMutations,
|
|
|
|
Version version,
|
|
|
|
KeyRef configClass,
|
|
|
|
KeyRef knobName,
|
|
|
|
ValueRef knobValue) {
|
|
|
|
Tuple tuple;
|
|
|
|
tuple << configClass;
|
|
|
|
tuple << knobName;
|
|
|
|
auto mutation = ConfigMutationRef::createConfigMutation(tuple.pack(), knobValue);
|
|
|
|
versionedMutations.emplace_back_deep(versionedMutations.arena(), version, mutation);
|
|
|
|
}
|
|
|
|
|
|
|
|
ACTOR template <class ConfigStore>
|
2021-05-14 15:41:02 +08:00
|
|
|
Future<Void> addTestUpdates(ConfigStore* configStore, Version* lastWrittenVersion) {
|
2021-05-14 02:22:25 +08:00
|
|
|
Standalone<VectorRef<VersionedConfigMutationRef>> versionedMutations;
|
2021-05-14 15:41:02 +08:00
|
|
|
++(*lastWrittenVersion);
|
|
|
|
appendVersionedMutation(versionedMutations, *lastWrittenVersion, "class-A"_sr, "test_bool"_sr, "true"_sr);
|
|
|
|
appendVersionedMutation(versionedMutations, *lastWrittenVersion, "class-B"_sr, "test_long"_sr, "100"_sr);
|
|
|
|
appendVersionedMutation(versionedMutations, *lastWrittenVersion, "class-C"_sr, "test_double"_sr, "10.0"_sr);
|
|
|
|
appendVersionedMutation(versionedMutations, *lastWrittenVersion, "class-A"_sr, "test_int"_sr, "10"_sr);
|
|
|
|
wait(configStore->addVersionedMutations(versionedMutations, *lastWrittenVersion));
|
2021-05-14 02:22:25 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-05-15 06:05:33 +08:00
|
|
|
Value versionToValue(Version version) {
|
|
|
|
auto s = format("%ld", version);
|
|
|
|
return StringRef(reinterpret_cast<uint8_t const*>(s.c_str()), s.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class ConfigStore>
|
|
|
|
Future<Void> addSequentialTestUpdates(ConfigStore &configStore, Version &lastWrittenVersion) {
|
|
|
|
Standalone<VectorRef<VersionedConfigMutationRef>> versionedMutations;
|
|
|
|
++lastWrittenVersion;
|
|
|
|
appendVersionedMutation(versionedMutations, lastWrittenVersion, "class-A"_sr, "test_long"_sr, versionToValue(lastWrittenVersion));
|
|
|
|
appendVersionedMutation(versionedMutations, lastWrittenVersion, "class-B"_sr, "test_long"_sr, versionToValue(lastWrittenVersion * 10));
|
|
|
|
return configStore.addVersionedMutations(versionedMutations, lastWrittenVersion);
|
|
|
|
}
|
|
|
|
|
2021-05-14 02:22:25 +08:00
|
|
|
ACTOR template <class ConfigStore>
|
2021-05-14 15:41:02 +08:00
|
|
|
Future<Void> runTestUpdates(ConfigStore* configStore, Version* lastWrittenVersion) {
|
|
|
|
wait(setTestSnapshot(configStore, lastWrittenVersion));
|
|
|
|
wait(addTestUpdates(configStore, lastWrittenVersion));
|
2021-05-14 02:22:25 +08:00
|
|
|
// TODO: Clean up on-disk state
|
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-05-14 07:08:02 +08:00
|
|
|
ACTOR Future<Void> runFirstLocalConfiguration(std::string configPath, UID id) {
|
|
|
|
state LocalConfiguration localConfiguration(configPath, testManualKnobOverrides);
|
2021-05-14 15:41:02 +08:00
|
|
|
state Version lastWrittenVersion = 0;
|
2021-05-14 07:08:02 +08:00
|
|
|
wait(localConfiguration.initialize("./", id));
|
2021-05-14 15:41:02 +08:00
|
|
|
wait(runTestUpdates(&localConfiguration, &lastWrittenVersion));
|
2021-05-15 06:05:33 +08:00
|
|
|
{
|
|
|
|
auto const *conf = &localConfiguration;
|
|
|
|
wait(waitUntil([conf] {
|
|
|
|
return conf->getTestKnobs() == getExpectedTestKnobsFinal();
|
|
|
|
}));
|
|
|
|
}
|
2021-05-14 02:22:25 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-05-14 07:08:02 +08:00
|
|
|
ACTOR Future<Void> runSecondLocalConfiguration(std::string configPath, UID id, TestKnobs const* expectedTestKnobs) {
|
|
|
|
state LocalConfiguration localConfiguration(configPath, testManualKnobOverrides);
|
|
|
|
wait(localConfiguration.initialize("./", id));
|
2021-05-14 03:55:33 +08:00
|
|
|
ASSERT(localConfiguration.getTestKnobs() == *expectedTestKnobs);
|
2021-05-15 06:05:33 +08:00
|
|
|
{
|
|
|
|
auto const *conf = &localConfiguration;
|
|
|
|
auto const *expected = expectedTestKnobs;
|
|
|
|
wait(waitUntil([conf, expected] {
|
|
|
|
return conf->getTestKnobs() == *expected;
|
|
|
|
}));
|
2021-05-14 03:55:33 +08:00
|
|
|
}
|
2021-05-15 06:05:33 +08:00
|
|
|
return Void();
|
2021-05-14 03:55:33 +08:00
|
|
|
}
|
|
|
|
|
2021-05-14 02:22:25 +08:00
|
|
|
} // namespace
|
|
|
|
|
|
|
|
TEST_CASE("/fdbserver/ConfigDB/LocalConfiguration/Simple") {
|
|
|
|
wait(runFirstLocalConfiguration("class-A/class-B", deterministicRandom()->randomUniqueID()));
|
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("/fdbserver/ConfigDB/LocalConfiguration/Restart") {
|
2021-05-14 07:08:02 +08:00
|
|
|
state UID id = deterministicRandom()->randomUniqueID();
|
|
|
|
wait(runFirstLocalConfiguration("class-A/class-B", id));
|
|
|
|
wait(runSecondLocalConfiguration("class-A/class-B", id, &getExpectedTestKnobsFinal()));
|
2021-05-14 02:22:25 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("/fdbserver/ConfigDB/LocalConfiguration/FreshRestart") {
|
2021-05-14 07:08:02 +08:00
|
|
|
state UID id = deterministicRandom()->randomUniqueID();
|
|
|
|
wait(runFirstLocalConfiguration("class-A/class-B", id));
|
|
|
|
wait(runSecondLocalConfiguration("class-B/class-A", id, &getExpectedTestKnobsEmptyConfig()));
|
2021-05-14 02:22:25 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-05-14 15:41:02 +08:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
class DummyConfigSource {
|
|
|
|
ConfigFollowerInterface cfi;
|
|
|
|
ACTOR static Future<Void> serve(DummyConfigSource* self) {
|
|
|
|
loop {
|
|
|
|
choose {
|
|
|
|
when(ConfigFollowerGetVersionRequest req = waitNext(self->cfi.getVersion.getFuture())) {
|
|
|
|
req.reply.send(0);
|
|
|
|
}
|
|
|
|
when(ConfigFollowerGetSnapshotRequest req = waitNext(self->cfi.getSnapshot.getFuture())) {
|
|
|
|
req.reply.send(ConfigFollowerGetSnapshotReply{});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
Future<Void> serve() { return serve(this); }
|
|
|
|
ConfigFollowerInterface const& getInterface() { return cfi; }
|
|
|
|
};
|
|
|
|
|
2021-05-15 06:05:33 +08:00
|
|
|
ACTOR template<class F>
|
|
|
|
Future<Void> waitUntil(F isReady) {
|
|
|
|
loop {
|
|
|
|
if (isReady()) { return Void(); }
|
|
|
|
wait(delayJittered(0.1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<Void> waitUntilConfigsMatch(LocalConfiguration const &fst, LocalConfiguration const &snd) {
|
|
|
|
return waitUntil([&fst, &snd] {
|
|
|
|
return fst.getTestKnobs() == snd.getTestKnobs();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<Void> waitUntilTestLongMatches(LocalConfiguration const &conf, int64_t expectedValue) {
|
|
|
|
return waitUntil([&conf, expectedValue]{
|
|
|
|
return conf.getTestKnobs().TEST_LONG == expectedValue;
|
|
|
|
});
|
2021-05-15 01:38:01 +08:00
|
|
|
}
|
|
|
|
|
2021-05-14 15:41:02 +08:00
|
|
|
} // namespace
|
|
|
|
|
2021-05-15 01:38:01 +08:00
|
|
|
TEST_CASE("/fdbserver/ConfigDB/ConfigBroadcaster/CheckpointedUpdates") {
|
|
|
|
state DummyConfigSource dummyConfigSource;
|
2021-05-15 04:30:04 +08:00
|
|
|
state ConfigBroadcaster broadcaster1(dummyConfigSource.getInterface(), deterministicRandom()->randomUniqueID());
|
|
|
|
state ConfigBroadcaster broadcaster2(dummyConfigSource.getInterface(), deterministicRandom()->randomUniqueID());
|
|
|
|
state Reference<AsyncVar<ConfigFollowerInterface>> cfi = makeReference<AsyncVar<ConfigFollowerInterface>>();
|
2021-05-15 02:28:00 +08:00
|
|
|
state LocalConfiguration localConfigurationA("class-A", testManualKnobOverrides);
|
|
|
|
state LocalConfiguration localConfigurationB("class-B", testManualKnobOverrides);
|
2021-05-15 06:05:33 +08:00
|
|
|
state Version version = 0;
|
2021-05-15 01:38:01 +08:00
|
|
|
state ActorCollection actors(false);
|
|
|
|
state Standalone<VectorRef<VersionedConfigMutationRef>> versionedMutations;
|
2021-05-15 02:28:00 +08:00
|
|
|
wait(localConfigurationA.initialize("./", deterministicRandom()->randomUniqueID()));
|
|
|
|
wait(localConfigurationB.initialize("./", deterministicRandom()->randomUniqueID()));
|
|
|
|
TraceEvent("StartedTestBroadcasterAndLocalConfigs")
|
2021-05-15 04:30:04 +08:00
|
|
|
.detail("Broadcaster1", broadcaster1.getID())
|
|
|
|
.detail("Broadcaster2", broadcaster2.getID())
|
2021-05-15 02:28:00 +08:00
|
|
|
.detail("LocalConfigurationA", localConfigurationA.getID())
|
|
|
|
.detail("LocalConfigurationB", localConfigurationB.getID());
|
2021-05-15 01:38:01 +08:00
|
|
|
actors.add(dummyConfigSource.serve());
|
2021-05-15 04:30:04 +08:00
|
|
|
actors.add(broadcaster1.serve(cfi->get()));
|
|
|
|
actors.add(localConfigurationA.consume(IDependentAsyncVar<ConfigFollowerInterface>::create(cfi)));
|
|
|
|
actors.add(localConfigurationB.consume(IDependentAsyncVar<ConfigFollowerInterface>::create(cfi)));
|
2021-05-15 06:05:33 +08:00
|
|
|
while (version < 10) {
|
|
|
|
wait(addSequentialTestUpdates(broadcaster1, version));
|
2021-05-15 03:30:17 +08:00
|
|
|
versionedMutations = Standalone<VectorRef<VersionedConfigMutationRef>>{};
|
2021-05-15 06:05:33 +08:00
|
|
|
wait(waitUntilTestLongMatches(localConfigurationA, version));
|
|
|
|
wait(waitUntilTestLongMatches(localConfigurationB, version * 10));
|
2021-05-15 01:38:01 +08:00
|
|
|
}
|
2021-05-15 03:30:17 +08:00
|
|
|
|
2021-05-15 04:30:04 +08:00
|
|
|
// Test changing broadcaster
|
|
|
|
cfi->set(ConfigFollowerInterface{});
|
|
|
|
actors.add(broadcaster2.serve(cfi->get()));
|
2021-05-15 06:05:33 +08:00
|
|
|
while (version < 20) {
|
|
|
|
wait(addSequentialTestUpdates(broadcaster2, version));
|
|
|
|
wait(waitUntilTestLongMatches(localConfigurationA, version));
|
|
|
|
wait(waitUntilTestLongMatches(localConfigurationB, version * 10));
|
2021-05-15 04:30:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Test compaction
|
2021-05-15 06:05:33 +08:00
|
|
|
while (version < 30) {
|
|
|
|
wait(addSequentialTestUpdates(broadcaster2, version));
|
2021-05-15 03:30:17 +08:00
|
|
|
}
|
|
|
|
wait(cfi->get().compact.getReply(ConfigFollowerCompactRequest{ version }));
|
2021-05-15 06:05:33 +08:00
|
|
|
wait(waitUntilTestLongMatches(localConfigurationA, 30));
|
|
|
|
wait(waitUntilTestLongMatches(localConfigurationB, 300));
|
2021-05-15 04:30:04 +08:00
|
|
|
return Void();
|
2021-05-15 03:30:17 +08:00
|
|
|
}
|