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"
|
2021-05-18 06:31:03 +08:00
|
|
|
#include "fdbclient/IConfigTransaction.h"
|
2021-05-14 02:22:25 +08:00
|
|
|
#include "fdbserver/ConfigBroadcaster.h"
|
2021-05-15 14:02:40 +08:00
|
|
|
#include "fdbserver/IConfigDatabaseNode.h"
|
2021-05-14 02:22:25 +08:00
|
|
|
#include "fdbserver/LocalConfiguration.h"
|
|
|
|
#include "fdbclient/Tuple.h"
|
|
|
|
#include "flow/UnitTest.h"
|
|
|
|
#include "flow/actorcompiler.h" // must be last include
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2021-05-16 11:38:41 +08:00
|
|
|
Key encodeConfigKey(Optional<KeyRef> configClass, KeyRef knobName) {
|
2021-05-14 02:22:25 +08:00
|
|
|
Tuple tuple;
|
2021-05-15 10:34:21 +08:00
|
|
|
if (configClass.present()) {
|
|
|
|
tuple.append(configClass.get());
|
|
|
|
} else {
|
|
|
|
tuple.appendNull();
|
|
|
|
}
|
2021-05-14 02:22:25 +08:00
|
|
|
tuple << knobName;
|
2021-05-16 11:38:41 +08:00
|
|
|
return tuple.pack();
|
2021-05-14 02:22:25 +08:00
|
|
|
}
|
|
|
|
|
2021-05-24 03:34:10 +08:00
|
|
|
// TODO: Use newly public ConfigMutationRef constructor
|
2021-05-16 11:38:41 +08:00
|
|
|
void appendVersionedMutation(Standalone<VectorRef<VersionedConfigMutationRef>>& versionedMutations,
|
|
|
|
Version version,
|
|
|
|
Optional<KeyRef> configClass,
|
|
|
|
KeyRef knobName,
|
|
|
|
Optional<ValueRef> knobValue) {
|
|
|
|
auto mutation = ConfigMutationRef::createConfigMutation(encodeConfigKey(configClass, knobName), knobValue);
|
|
|
|
versionedMutations.emplace_back_deep(versionedMutations.arena(), version, mutation);
|
2021-05-14 02:22:25 +08:00
|
|
|
}
|
|
|
|
|
2021-05-16 11:38:41 +08:00
|
|
|
Value longToValue(int64_t v) {
|
|
|
|
auto s = format("%ld", v);
|
2021-05-15 06:05:33 +08:00
|
|
|
return StringRef(reinterpret_cast<uint8_t const*>(s.c_str()), s.size());
|
|
|
|
}
|
|
|
|
|
2021-05-24 03:34:10 +08:00
|
|
|
class WriteToTransactionEnvironment {
|
2021-05-24 12:03:15 +08:00
|
|
|
UID id;
|
2021-05-24 03:34:10 +08:00
|
|
|
ConfigTransactionInterface cti;
|
|
|
|
ConfigFollowerInterface cfi;
|
|
|
|
Reference<IConfigDatabaseNode> node;
|
|
|
|
Future<Void> ctiServer;
|
|
|
|
Future<Void> cfiServer;
|
2021-05-24 07:44:06 +08:00
|
|
|
Version lastWrittenVersion{ 0 };
|
2021-05-14 02:22:25 +08:00
|
|
|
|
2021-05-29 18:58:18 +08:00
|
|
|
ACTOR template <class T>
|
|
|
|
static Future<Void> set(WriteToTransactionEnvironment* self,
|
|
|
|
Optional<KeyRef> configClass,
|
|
|
|
T value,
|
|
|
|
KeyRef knobName) {
|
2021-05-24 03:34:10 +08:00
|
|
|
state Reference<IConfigTransaction> tr = IConfigTransaction::createSimple(self->cti);
|
2021-05-29 18:58:18 +08:00
|
|
|
auto configKey = encodeConfigKey(configClass, knobName);
|
2021-05-24 03:34:10 +08:00
|
|
|
tr->set(configKey, longToValue(value));
|
|
|
|
wait(tr->commit());
|
2021-05-24 07:44:06 +08:00
|
|
|
self->lastWrittenVersion = tr->getCommittedVersion();
|
2021-05-24 03:34:10 +08:00
|
|
|
return Void();
|
|
|
|
}
|
2021-05-23 15:41:15 +08:00
|
|
|
|
2021-05-24 03:34:10 +08:00
|
|
|
ACTOR static Future<Void> clear(WriteToTransactionEnvironment* self, Optional<KeyRef> configClass) {
|
|
|
|
state Reference<IConfigTransaction> tr = IConfigTransaction::createSimple(self->cti);
|
|
|
|
auto configKey = encodeConfigKey(configClass, "test_long"_sr);
|
|
|
|
tr->clear(configKey);
|
|
|
|
wait(tr->commit());
|
2021-05-24 07:44:06 +08:00
|
|
|
self->lastWrittenVersion = tr->getCommittedVersion();
|
2021-05-24 03:34:10 +08:00
|
|
|
return Void();
|
|
|
|
}
|
2021-05-14 03:55:33 +08:00
|
|
|
|
2021-05-24 09:01:50 +08:00
|
|
|
void setup() {
|
|
|
|
ctiServer = node->serve(cti);
|
|
|
|
cfiServer = node->serve(cfi);
|
|
|
|
}
|
2021-05-14 02:22:25 +08:00
|
|
|
|
2021-05-24 09:01:50 +08:00
|
|
|
public:
|
2021-05-24 12:03:15 +08:00
|
|
|
WriteToTransactionEnvironment()
|
|
|
|
: id(deterministicRandom()->randomUniqueID()), node(IConfigDatabaseNode::createSimple("./", id)) {
|
|
|
|
setup();
|
|
|
|
}
|
2021-05-14 02:22:25 +08:00
|
|
|
|
2021-05-29 18:58:18 +08:00
|
|
|
template <class T>
|
|
|
|
Future<Void> set(Optional<KeyRef> configClass, T value, KeyRef knobName = "test_long"_sr) {
|
|
|
|
return set(this, configClass, value, knobName);
|
|
|
|
}
|
2021-05-24 03:34:10 +08:00
|
|
|
|
|
|
|
Future<Void> clear(Optional<KeyRef> configClass) { return clear(this, configClass); }
|
|
|
|
|
2021-05-24 07:44:06 +08:00
|
|
|
Future<Void> compact() { return cfi.compact.getReply(ConfigFollowerCompactRequest{ lastWrittenVersion }); }
|
|
|
|
|
2021-05-24 09:01:50 +08:00
|
|
|
void restartNode() {
|
2021-05-24 03:34:10 +08:00
|
|
|
cfiServer.cancel();
|
|
|
|
ctiServer.cancel();
|
2021-05-24 12:03:15 +08:00
|
|
|
node = IConfigDatabaseNode::createSimple("./", id);
|
2021-05-24 09:01:50 +08:00
|
|
|
setup();
|
2021-05-16 11:38:41 +08:00
|
|
|
}
|
2021-05-15 06:37:14 +08:00
|
|
|
|
2021-05-24 03:34:10 +08:00
|
|
|
ConfigTransactionInterface getTransactionInterface() const { return cti; }
|
2021-05-18 06:31:03 +08:00
|
|
|
|
2021-05-24 03:34:10 +08:00
|
|
|
ConfigFollowerInterface getFollowerInterface() const { return cfi; }
|
|
|
|
|
|
|
|
Future<Void> getError() const { return cfiServer || ctiServer; }
|
|
|
|
};
|
|
|
|
|
|
|
|
class ReadFromLocalConfigEnvironment {
|
2021-05-24 12:03:15 +08:00
|
|
|
UID id;
|
2021-05-24 03:34:10 +08:00
|
|
|
LocalConfiguration localConfiguration;
|
|
|
|
Reference<IDependentAsyncVar<ConfigBroadcastFollowerInterface> const> cbfi;
|
|
|
|
Future<Void> consumer;
|
|
|
|
|
|
|
|
ACTOR static Future<Void> checkEventually(LocalConfiguration const* localConfiguration,
|
|
|
|
Optional<int64_t> expected) {
|
|
|
|
loop {
|
|
|
|
if (localConfiguration->getTestKnobs().TEST_LONG == (expected.present() ? expected.get() : 0)) {
|
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
wait(delayJittered(0.1));
|
|
|
|
}
|
2021-05-16 11:38:41 +08:00
|
|
|
}
|
2021-05-15 10:34:21 +08:00
|
|
|
|
2021-05-24 03:34:10 +08:00
|
|
|
ACTOR static Future<Void> setup(ReadFromLocalConfigEnvironment* self) {
|
2021-05-24 12:03:15 +08:00
|
|
|
wait(self->localConfiguration.initialize());
|
2021-05-24 03:34:10 +08:00
|
|
|
if (self->cbfi) {
|
|
|
|
self->consumer = self->localConfiguration.consume(self->cbfi);
|
2021-05-17 14:14:46 +08:00
|
|
|
}
|
2021-05-24 03:34:10 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
ReadFromLocalConfigEnvironment(std::string const& configPath,
|
|
|
|
std::map<std::string, std::string> const& manualKnobOverrides)
|
2021-05-24 12:03:15 +08:00
|
|
|
: id(deterministicRandom()->randomUniqueID()), localConfiguration("./", configPath, manualKnobOverrides, id),
|
2021-05-24 03:34:10 +08:00
|
|
|
consumer(Never()) {}
|
|
|
|
|
|
|
|
Future<Void> setup() { return setup(this); }
|
|
|
|
|
|
|
|
Future<Void> restartLocalConfig(std::string const& newConfigPath) {
|
2021-05-24 12:03:15 +08:00
|
|
|
localConfiguration = LocalConfiguration("./", newConfigPath, {}, id);
|
2021-05-24 03:34:10 +08:00
|
|
|
return setup();
|
|
|
|
}
|
|
|
|
|
|
|
|
void connectToBroadcaster(Reference<IDependentAsyncVar<ConfigBroadcastFollowerInterface> const> const& cbfi) {
|
|
|
|
ASSERT(!this->cbfi);
|
|
|
|
this->cbfi = cbfi;
|
|
|
|
consumer = localConfiguration.consume(cbfi);
|
|
|
|
}
|
|
|
|
|
|
|
|
void checkImmediate(Optional<int64_t> expected) const {
|
|
|
|
if (expected.present()) {
|
|
|
|
ASSERT_EQ(localConfiguration.getTestKnobs().TEST_LONG, expected.get());
|
|
|
|
} else {
|
|
|
|
ASSERT_EQ(localConfiguration.getTestKnobs().TEST_LONG, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<Void> checkEventually(Optional<int64_t> expected) const {
|
|
|
|
return checkEventually(&localConfiguration, expected);
|
2021-05-17 14:14:46 +08:00
|
|
|
}
|
2021-05-24 03:34:10 +08:00
|
|
|
|
|
|
|
LocalConfiguration& getMutableLocalConfiguration() { return localConfiguration; }
|
|
|
|
|
|
|
|
Future<Void> getError() const { return consumer; }
|
|
|
|
};
|
2021-05-15 06:37:14 +08:00
|
|
|
|
2021-05-17 05:36:52 +08:00
|
|
|
class LocalConfigEnvironment {
|
2021-05-24 03:34:10 +08:00
|
|
|
ReadFromLocalConfigEnvironment readFrom;
|
2021-05-17 14:14:46 +08:00
|
|
|
Version lastWrittenVersion{ 0 };
|
2021-05-17 05:36:52 +08:00
|
|
|
|
2021-05-24 03:34:10 +08:00
|
|
|
Future<Void> addMutation(Optional<KeyRef> configClass, Optional<ValueRef> value) {
|
|
|
|
Standalone<VectorRef<VersionedConfigMutationRef>> versionedMutations;
|
|
|
|
appendVersionedMutation(versionedMutations, ++lastWrittenVersion, configClass, "test_long"_sr, value);
|
|
|
|
return readFrom.getMutableLocalConfiguration().addChanges(versionedMutations, lastWrittenVersion);
|
|
|
|
}
|
|
|
|
|
2021-05-17 05:36:52 +08:00
|
|
|
public:
|
2021-05-19 14:50:01 +08:00
|
|
|
LocalConfigEnvironment(std::string const& configPath,
|
|
|
|
std::map<std::string, std::string> const& manualKnobOverrides = {})
|
2021-05-24 03:34:10 +08:00
|
|
|
: readFrom(configPath, manualKnobOverrides) {}
|
|
|
|
Future<Void> setup() { return readFrom.setup(); }
|
2021-05-19 14:50:01 +08:00
|
|
|
Future<Void> restartLocalConfig(std::string const& newConfigPath) {
|
2021-05-24 03:34:10 +08:00
|
|
|
return readFrom.restartLocalConfig(newConfigPath);
|
2021-05-17 08:25:41 +08:00
|
|
|
}
|
2021-05-17 14:14:46 +08:00
|
|
|
Future<Void> getError() const { return Never(); }
|
2021-05-24 03:34:10 +08:00
|
|
|
Future<Void> clear(Optional<KeyRef> configClass) { return addMutation(configClass, {}); }
|
2021-05-17 14:14:46 +08:00
|
|
|
Future<Void> set(Optional<KeyRef> configClass, int64_t value) {
|
2021-05-24 03:34:10 +08:00
|
|
|
return addMutation(configClass, longToValue(value));
|
2021-05-17 05:36:52 +08:00
|
|
|
}
|
2021-05-24 03:34:10 +08:00
|
|
|
void check(Optional<int64_t> value) const { return readFrom.checkImmediate(value); }
|
2021-05-17 05:36:52 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
class BroadcasterToLocalConfigEnvironment {
|
2021-05-24 03:34:10 +08:00
|
|
|
ReadFromLocalConfigEnvironment readFrom;
|
2021-05-23 15:41:15 +08:00
|
|
|
Reference<AsyncVar<ConfigBroadcastFollowerInterface>> cbfi;
|
2021-05-24 03:34:10 +08:00
|
|
|
ConfigBroadcaster broadcaster;
|
2021-05-17 14:14:46 +08:00
|
|
|
Version lastWrittenVersion{ 0 };
|
|
|
|
Future<Void> broadcastServer;
|
2021-05-17 05:36:52 +08:00
|
|
|
|
|
|
|
ACTOR static Future<Void> setup(BroadcasterToLocalConfigEnvironment* self) {
|
2021-05-24 03:34:10 +08:00
|
|
|
wait(self->readFrom.setup());
|
|
|
|
self->readFrom.connectToBroadcaster(IDependentAsyncVar<ConfigBroadcastFollowerInterface>::create(self->cbfi));
|
2021-05-23 15:41:15 +08:00
|
|
|
self->broadcastServer = self->broadcaster.serve(self->cbfi->get());
|
2021-05-19 12:29:40 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-05-24 03:34:10 +08:00
|
|
|
void addMutation(Optional<KeyRef> configClass, Optional<ValueRef> value) {
|
|
|
|
Standalone<VectorRef<VersionedConfigMutationRef>> versionedMutations;
|
|
|
|
appendVersionedMutation(versionedMutations, ++lastWrittenVersion, configClass, "test_long"_sr, value);
|
2021-05-24 16:25:50 +08:00
|
|
|
broadcaster.applyChanges(versionedMutations, lastWrittenVersion, {});
|
2021-05-14 15:41:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
2021-05-17 14:14:46 +08:00
|
|
|
BroadcasterToLocalConfigEnvironment(std::string const& configPath)
|
2021-05-23 15:41:15 +08:00
|
|
|
: broadcaster(ConfigFollowerInterface{}), cbfi(makeReference<AsyncVar<ConfigBroadcastFollowerInterface>>()),
|
2021-05-24 03:34:10 +08:00
|
|
|
readFrom(configPath, {}) {}
|
2021-05-17 05:36:52 +08:00
|
|
|
|
|
|
|
Future<Void> setup() { return setup(this); }
|
|
|
|
|
2021-05-24 03:34:10 +08:00
|
|
|
void set(Optional<KeyRef> configClass, int64_t value) { addMutation(configClass, longToValue(value)); }
|
2021-05-19 12:29:40 +08:00
|
|
|
|
2021-05-24 03:34:10 +08:00
|
|
|
void clear(Optional<KeyRef> configClass) { addMutation(configClass, {}); }
|
2021-05-19 12:29:40 +08:00
|
|
|
|
2021-05-24 03:34:10 +08:00
|
|
|
Future<Void> check(Optional<int64_t> value) const { return readFrom.checkEventually(value); }
|
2021-05-19 12:29:40 +08:00
|
|
|
|
2021-05-17 14:14:46 +08:00
|
|
|
void changeBroadcaster() {
|
2021-05-19 06:28:44 +08:00
|
|
|
broadcastServer.cancel();
|
2021-05-23 15:41:15 +08:00
|
|
|
cbfi->set(ConfigBroadcastFollowerInterface{});
|
|
|
|
broadcastServer = broadcaster.serve(cbfi->get());
|
2021-05-17 14:14:46 +08:00
|
|
|
}
|
2021-05-19 12:29:40 +08:00
|
|
|
|
2021-05-24 03:34:10 +08:00
|
|
|
Future<Void> restartLocalConfig(std::string const& newConfigPath) {
|
|
|
|
return readFrom.restartLocalConfig(newConfigPath);
|
2021-05-19 14:50:01 +08:00
|
|
|
}
|
2021-05-19 12:29:40 +08:00
|
|
|
|
2021-05-24 16:25:50 +08:00
|
|
|
void compact() { broadcaster.compact(lastWrittenVersion); }
|
2021-05-17 14:14:46 +08:00
|
|
|
|
2021-05-24 03:34:10 +08:00
|
|
|
Future<Void> getError() const { return readFrom.getError() || broadcastServer; }
|
2021-05-14 15:41:02 +08:00
|
|
|
};
|
|
|
|
|
2021-05-17 05:36:52 +08:00
|
|
|
class TransactionEnvironment {
|
2021-05-24 03:34:10 +08:00
|
|
|
WriteToTransactionEnvironment writeTo;
|
|
|
|
|
|
|
|
ACTOR static Future<Void> check(TransactionEnvironment* self,
|
|
|
|
Optional<KeyRef> configClass,
|
|
|
|
Optional<int64_t> expected) {
|
|
|
|
state Reference<IConfigTransaction> tr =
|
|
|
|
IConfigTransaction::createSimple(self->writeTo.getTransactionInterface());
|
|
|
|
state Key configKey = encodeConfigKey(configClass, "test_long"_sr);
|
|
|
|
state Optional<Value> value = wait(tr->get(configKey));
|
|
|
|
if (expected.present()) {
|
|
|
|
ASSERT(value.get() == longToValue(expected.get()));
|
|
|
|
} else {
|
|
|
|
ASSERT(!value.present());
|
|
|
|
}
|
2021-05-17 05:36:52 +08:00
|
|
|
return Void();
|
|
|
|
}
|
2021-05-15 04:30:04 +08:00
|
|
|
|
2021-05-29 18:58:18 +08:00
|
|
|
ACTOR static Future<Standalone<VectorRef<KeyRef>>> getConfigClasses(TransactionEnvironment* self) {
|
|
|
|
state Reference<IConfigTransaction> tr =
|
|
|
|
IConfigTransaction::createSimple(self->writeTo.getTransactionInterface());
|
|
|
|
state KeySelector begin = firstGreaterOrEqual("\xff\xff/configClasses/"_sr);
|
|
|
|
state KeySelector end = firstGreaterOrEqual("\xff\xff/configClasses0"_sr);
|
|
|
|
Standalone<RangeResultRef> range = wait(tr->getRange(begin, end, 1000));
|
|
|
|
Standalone<VectorRef<KeyRef>> result;
|
|
|
|
for (const auto& kv : range) {
|
|
|
|
result.push_back_deep(result.arena(), kv.key);
|
|
|
|
ASSERT(kv.value == ""_sr);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
ACTOR static Future<Standalone<VectorRef<KeyRef>>> getKnobNames(TransactionEnvironment* self, KeyRef configClass) {
|
|
|
|
state Reference<IConfigTransaction> tr =
|
|
|
|
IConfigTransaction::createSimple(self->writeTo.getTransactionInterface());
|
|
|
|
state KeyRange keys = singleKeyRange(configClass.withPrefix("\xff\xff/knobs/"_sr));
|
|
|
|
KeySelector begin = firstGreaterOrEqual(keys.begin);
|
|
|
|
KeySelector end = firstGreaterOrEqual(keys.end);
|
|
|
|
Standalone<RangeResultRef> range = wait(tr->getRange(begin, end, 1000));
|
|
|
|
Standalone<VectorRef<KeyRef>> result;
|
|
|
|
for (const auto& kv : range) {
|
|
|
|
result.push_back_deep(result.arena(), kv.key);
|
|
|
|
ASSERT(kv.value == ""_sr);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
ACTOR static Future<Void> badRangeRead(TransactionEnvironment* self) {
|
|
|
|
state Reference<IConfigTransaction> tr =
|
|
|
|
IConfigTransaction::createSimple(self->writeTo.getTransactionInterface());
|
|
|
|
KeySelector begin = firstGreaterOrEqual(normalKeys.begin);
|
|
|
|
KeySelector end = firstGreaterOrEqual(normalKeys.end);
|
|
|
|
wait(success(tr->getRange(begin, end, 1000)));
|
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-05-17 05:36:52 +08:00
|
|
|
public:
|
2021-05-24 09:01:50 +08:00
|
|
|
// TODO: Remove this?
|
|
|
|
Future<Void> setup() { return Void(); }
|
2021-05-16 11:38:41 +08:00
|
|
|
|
2021-05-24 09:01:50 +08:00
|
|
|
void restartNode() { writeTo.restartNode(); }
|
2021-05-29 18:58:18 +08:00
|
|
|
Future<Void> set(Optional<KeyRef> configClass, int64_t value, KeyRef knobName = "test_long"_sr) {
|
|
|
|
return writeTo.set(configClass, value, knobName);
|
|
|
|
}
|
2021-05-24 03:34:10 +08:00
|
|
|
Future<Void> clear(Optional<KeyRef> configClass) { return writeTo.clear(configClass); }
|
2021-05-17 14:14:46 +08:00
|
|
|
Future<Void> check(Optional<KeyRef> configClass, Optional<int64_t> expected) {
|
2021-05-24 03:34:10 +08:00
|
|
|
return check(this, configClass, expected);
|
2021-05-16 11:38:41 +08:00
|
|
|
}
|
2021-05-29 18:58:18 +08:00
|
|
|
Future<Void> badRangeRead() { return badRangeRead(this); }
|
|
|
|
|
|
|
|
Future<Standalone<VectorRef<KeyRef>>> getConfigClasses() { return getConfigClasses(this); }
|
|
|
|
Future<Standalone<VectorRef<KeyRef>>> getKnobNames(KeyRef configClass) { return getKnobNames(this, configClass); }
|
|
|
|
|
2021-05-24 07:44:06 +08:00
|
|
|
Future<Void> compact() { return writeTo.compact(); }
|
2021-05-24 03:34:10 +08:00
|
|
|
Future<Void> getError() const { return writeTo.getError(); }
|
2021-05-17 05:36:52 +08:00
|
|
|
};
|
2021-05-16 11:38:41 +08:00
|
|
|
|
2021-05-17 05:36:52 +08:00
|
|
|
class TransactionToLocalConfigEnvironment {
|
2021-05-24 03:34:10 +08:00
|
|
|
WriteToTransactionEnvironment writeTo;
|
|
|
|
ReadFromLocalConfigEnvironment readFrom;
|
|
|
|
Reference<AsyncVar<ConfigBroadcastFollowerInterface>> cbfi;
|
2021-05-19 14:50:01 +08:00
|
|
|
ConfigBroadcaster broadcaster;
|
|
|
|
Future<Void> broadcastServer;
|
2021-05-17 05:36:52 +08:00
|
|
|
|
2021-05-17 15:52:24 +08:00
|
|
|
ACTOR static Future<Void> setup(TransactionToLocalConfigEnvironment* self) {
|
2021-05-24 03:34:10 +08:00
|
|
|
wait(self->readFrom.setup());
|
|
|
|
self->readFrom.connectToBroadcaster(IDependentAsyncVar<ConfigBroadcastFollowerInterface>::create(self->cbfi));
|
|
|
|
self->broadcastServer = self->broadcaster.serve(self->cbfi->get());
|
2021-05-17 05:36:52 +08:00
|
|
|
return Void();
|
|
|
|
}
|
2021-05-16 11:38:41 +08:00
|
|
|
|
2021-05-17 05:36:52 +08:00
|
|
|
public:
|
2021-05-17 14:14:46 +08:00
|
|
|
TransactionToLocalConfigEnvironment(std::string const& configPath)
|
2021-05-24 03:34:10 +08:00
|
|
|
: readFrom(configPath, {}), broadcaster(writeTo.getFollowerInterface()),
|
|
|
|
cbfi(makeReference<AsyncVar<ConfigBroadcastFollowerInterface>>()) {}
|
2021-05-17 05:36:52 +08:00
|
|
|
|
|
|
|
Future<Void> setup() { return setup(this); }
|
|
|
|
|
2021-05-24 09:01:50 +08:00
|
|
|
void restartNode() { writeTo.restartNode(); }
|
2021-05-17 15:52:24 +08:00
|
|
|
|
2021-05-19 14:50:01 +08:00
|
|
|
void changeBroadcaster() {
|
|
|
|
broadcastServer.cancel();
|
2021-05-24 03:34:10 +08:00
|
|
|
cbfi->set(ConfigBroadcastFollowerInterface{});
|
|
|
|
broadcastServer = broadcaster.serve(cbfi->get());
|
2021-05-19 14:50:01 +08:00
|
|
|
}
|
|
|
|
|
2021-05-24 03:34:10 +08:00
|
|
|
Future<Void> restartLocalConfig(std::string const& newConfigPath) {
|
|
|
|
return readFrom.restartLocalConfig(newConfigPath);
|
2021-05-19 14:50:01 +08:00
|
|
|
}
|
|
|
|
|
2021-05-24 07:44:06 +08:00
|
|
|
Future<Void> compact() { return writeTo.compact(); }
|
|
|
|
|
2021-05-24 03:34:10 +08:00
|
|
|
Future<Void> set(Optional<KeyRef> configClass, int64_t value) { return writeTo.set(configClass, value); }
|
|
|
|
Future<Void> clear(Optional<KeyRef> configClass) { return writeTo.clear(configClass); }
|
|
|
|
Future<Void> check(Optional<int64_t> value) const { return readFrom.checkEventually(value); }
|
|
|
|
Future<Void> getError() const { return writeTo.getError() || readFrom.getError() || broadcastServer; }
|
2021-05-17 05:36:52 +08:00
|
|
|
};
|
|
|
|
|
2021-05-17 14:14:46 +08:00
|
|
|
template <class Env, class... Args>
|
|
|
|
Future<Void> set(Env& env, Args&&... args) {
|
|
|
|
return waitOrError(env.set(std::forward<Args>(args)...), env.getError());
|
|
|
|
}
|
2021-05-23 15:41:15 +08:00
|
|
|
template <class... Args>
|
|
|
|
Future<Void> set(BroadcasterToLocalConfigEnvironment& env, Args&&... args) {
|
|
|
|
env.set(std::forward<Args>(args)...);
|
|
|
|
return Void();
|
|
|
|
}
|
2021-05-17 14:14:46 +08:00
|
|
|
template <class Env, class... Args>
|
|
|
|
Future<Void> clear(Env& env, Args&&... args) {
|
|
|
|
return waitOrError(env.clear(std::forward<Args>(args)...), env.getError());
|
|
|
|
}
|
2021-05-23 15:41:15 +08:00
|
|
|
template <class... Args>
|
|
|
|
Future<Void> clear(BroadcasterToLocalConfigEnvironment& env, Args&&... args) {
|
|
|
|
env.clear(std::forward<Args>(args)...);
|
|
|
|
return Void();
|
|
|
|
}
|
2021-05-17 14:14:46 +08:00
|
|
|
template <class Env, class... Args>
|
|
|
|
Future<Void> check(Env& env, Args&&... args) {
|
|
|
|
return waitOrError(env.check(std::forward<Args>(args)...), env.getError());
|
|
|
|
}
|
2021-05-19 14:50:01 +08:00
|
|
|
template <class... Args>
|
|
|
|
Future<Void> check(LocalConfigEnvironment& env, Args&&... args) {
|
|
|
|
env.check(std::forward<Args>(args)...);
|
|
|
|
return Void();
|
|
|
|
}
|
2021-05-24 07:44:06 +08:00
|
|
|
template <class Env>
|
|
|
|
Future<Void> compact(Env& env) {
|
|
|
|
return waitOrError(env.compact(), env.getError());
|
|
|
|
}
|
|
|
|
Future<Void> compact(BroadcasterToLocalConfigEnvironment& env) {
|
|
|
|
env.compact();
|
|
|
|
return Void();
|
|
|
|
}
|
2021-05-17 05:36:52 +08:00
|
|
|
|
2021-05-19 14:50:01 +08:00
|
|
|
ACTOR template <class Env>
|
|
|
|
Future<Void> testRestartLocalConfig() {
|
|
|
|
state Env env("class-A");
|
2021-05-17 14:14:46 +08:00
|
|
|
wait(env.setup());
|
|
|
|
wait(set(env, "class-A"_sr, 1));
|
2021-05-19 14:50:01 +08:00
|
|
|
wait(check(env, 1));
|
|
|
|
wait(env.restartLocalConfig("class-A"));
|
|
|
|
wait(check(env, 1));
|
|
|
|
wait(set(env, "class-A"_sr, 2));
|
|
|
|
wait(check(env, 2));
|
2021-05-17 14:14:46 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-05-19 14:50:01 +08:00
|
|
|
ACTOR template <class Env>
|
|
|
|
Future<Void> testRestartLocalConfigAndChangeClass() {
|
|
|
|
state Env env("class-A");
|
2021-05-17 14:14:46 +08:00
|
|
|
wait(env.setup());
|
|
|
|
wait(set(env, "class-A"_sr, 1));
|
2021-05-19 14:50:01 +08:00
|
|
|
wait(check(env, 1));
|
|
|
|
wait(env.restartLocalConfig("class-B"));
|
|
|
|
wait(check(env, 0));
|
|
|
|
wait(set(env, "class-B"_sr, 2));
|
|
|
|
wait(check(env, 2));
|
2021-05-17 14:14:46 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-05-19 14:50:01 +08:00
|
|
|
ACTOR template <class Env>
|
|
|
|
Future<Void> testSet() {
|
|
|
|
state LocalConfigEnvironment env("class-A", {});
|
2021-05-17 14:14:46 +08:00
|
|
|
wait(env.setup());
|
|
|
|
wait(set(env, "class-A"_sr, 1));
|
2021-05-19 14:50:01 +08:00
|
|
|
wait(check(env, 1));
|
2021-05-16 11:38:41 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-05-19 14:50:01 +08:00
|
|
|
ACTOR template <class Env>
|
|
|
|
Future<Void> testClear() {
|
2021-05-17 14:14:46 +08:00
|
|
|
state LocalConfigEnvironment env("class-A", {});
|
|
|
|
wait(env.setup());
|
|
|
|
wait(set(env, "class-A"_sr, 1));
|
|
|
|
wait(clear(env, "class-A"_sr));
|
2021-05-19 14:50:01 +08:00
|
|
|
wait(check(env, Optional<int64_t>{}));
|
2021-05-17 05:36:52 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-05-19 14:50:01 +08:00
|
|
|
ACTOR template <class Env>
|
|
|
|
Future<Void> testGlobalSet() {
|
|
|
|
state Env env("class-A");
|
2021-05-17 14:14:46 +08:00
|
|
|
wait(env.setup());
|
2021-05-22 07:21:31 +08:00
|
|
|
wait(set(env, Optional<KeyRef>{}, 1));
|
|
|
|
env.check(1);
|
|
|
|
wait(set(env, "class-A"_sr, 10));
|
2021-05-17 14:14:46 +08:00
|
|
|
env.check(10);
|
2021-05-17 05:36:52 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-05-19 14:50:01 +08:00
|
|
|
ACTOR template <class Env>
|
|
|
|
Future<Void> testIgnore() {
|
|
|
|
state Env env("class-A");
|
|
|
|
wait(env.setup());
|
|
|
|
wait(set(env, "class-B"_sr, 1));
|
|
|
|
choose {
|
|
|
|
when(wait(delay(5))) {}
|
|
|
|
when(wait(check(env, 1))) { ASSERT(false); }
|
|
|
|
}
|
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
|
|
|
ACTOR template <class Env>
|
|
|
|
Future<Void> testCompact() {
|
|
|
|
state Env env("class-A");
|
|
|
|
wait(env.setup());
|
|
|
|
wait(set(env, "class-A"_sr, 1));
|
2021-05-24 07:44:06 +08:00
|
|
|
wait(compact(env));
|
2021-05-19 14:50:01 +08:00
|
|
|
wait(check(env, 1));
|
2021-05-24 07:44:06 +08:00
|
|
|
wait(set(env, "class-A"_sr, 2));
|
|
|
|
wait(check(env, 2));
|
2021-05-19 14:50:01 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
|
|
|
ACTOR template <class Env>
|
|
|
|
Future<Void> testChangeBroadcaster() {
|
|
|
|
state Env env("class-A");
|
|
|
|
wait(env.setup());
|
|
|
|
wait(set(env, "class-A"_sr, 1));
|
|
|
|
wait(check(env, 1));
|
|
|
|
env.changeBroadcaster();
|
|
|
|
wait(set(env, "class-A"_sr, 2));
|
|
|
|
wait(check(env, 2));
|
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-05-29 18:58:18 +08:00
|
|
|
bool matches(Standalone<VectorRef<KeyRef>> const& vec, std::set<Key> const& compareTo) {
|
|
|
|
std::set<Key> s;
|
|
|
|
for (const auto& value : vec) {
|
|
|
|
s.insert(value);
|
|
|
|
}
|
|
|
|
return (s == compareTo);
|
|
|
|
}
|
|
|
|
|
|
|
|
ACTOR Future<Void> testGetConfigClasses(bool doCompact) {
|
|
|
|
state TransactionEnvironment env;
|
|
|
|
wait(set(env, "class-A"_sr, 1));
|
|
|
|
wait(set(env, "class-B"_sr, 1));
|
|
|
|
if (doCompact) {
|
|
|
|
wait(compact(env));
|
|
|
|
}
|
|
|
|
Standalone<VectorRef<KeyRef>> configClasses = wait(env.getConfigClasses());
|
|
|
|
ASSERT(matches(configClasses, { "class-A"_sr, "class-B"_sr }));
|
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
|
|
|
ACTOR Future<Void> testGetKnobs(bool doCompact) {
|
|
|
|
state TransactionEnvironment env;
|
|
|
|
wait(set(env, "class-A"_sr, 1, "test_long"_sr));
|
|
|
|
wait(set(env, "class-A"_sr, 1, "test_int"_sr));
|
|
|
|
wait(set(env, "class-B"_sr, 1.0, "test_double"_sr));
|
|
|
|
if (doCompact) {
|
|
|
|
wait(compact(env));
|
|
|
|
}
|
|
|
|
Standalone<VectorRef<KeyRef>> knobNames = wait(env.getKnobNames("class-A"_sr));
|
|
|
|
ASSERT(matches(knobNames, { "test_long"_sr, "test_int"_sr }));
|
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-05-19 14:50:01 +08:00
|
|
|
} // namespace
|
|
|
|
|
|
|
|
TEST_CASE("/fdbserver/ConfigDB/LocalConfiguration/Set") {
|
|
|
|
wait(testSet<LocalConfigEnvironment>());
|
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("/fdbserver/ConfigDB/LocalConfiguration/Restart") {
|
|
|
|
wait(testRestartLocalConfig<LocalConfigEnvironment>());
|
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("/fdbserver/ConfigDB/LocalConfiguration/RestartFresh") {
|
|
|
|
wait(testRestartLocalConfigAndChangeClass<LocalConfigEnvironment>());
|
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("/fdbserver/ConfigDB/LocalConfiguration/Clear") {
|
|
|
|
wait(testClear<LocalConfigEnvironment>());
|
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("/fdbserver/ConfigDB/LocalConfiguration/GlobalSet") {
|
|
|
|
wait(testGlobalSet<LocalConfigEnvironment>());
|
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-05-17 14:14:46 +08:00
|
|
|
TEST_CASE("/fdbserver/ConfigDB/LocalConfiguration/ConflictingOverrides") {
|
|
|
|
state LocalConfigEnvironment env("class-A/class-B", {});
|
|
|
|
wait(env.setup());
|
|
|
|
wait(set(env, "class-A"_sr, 1));
|
|
|
|
wait(set(env, "class-B"_sr, 10));
|
|
|
|
env.check(10);
|
2021-05-16 11:38:41 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-05-17 14:14:46 +08:00
|
|
|
TEST_CASE("/fdbserver/ConfigDB/LocalConfiguration/Manual") {
|
2021-05-18 10:14:32 +08:00
|
|
|
state LocalConfigEnvironment env("class-A", { { "test_long", "1000" } });
|
2021-05-17 14:14:46 +08:00
|
|
|
wait(env.setup());
|
|
|
|
wait(set(env, "class-A"_sr, 1));
|
|
|
|
env.check(1000);
|
2021-05-16 11:38:41 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("/fdbserver/ConfigDB/BroadcasterToLocalConfig/Set") {
|
2021-05-19 14:50:01 +08:00
|
|
|
wait(testSet<BroadcasterToLocalConfigEnvironment>());
|
2021-05-16 11:38:41 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("/fdbserver/ConfigDB/BroadcasterToLocalConfig/Clear") {
|
2021-05-19 14:50:01 +08:00
|
|
|
wait(testClear<BroadcasterToLocalConfigEnvironment>());
|
2021-05-17 05:36:52 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-05-17 14:14:46 +08:00
|
|
|
TEST_CASE("/fdbserver/ConfigDB/BroadcasterToLocalConfig/Ignore") {
|
2021-05-19 14:50:01 +08:00
|
|
|
wait(testIgnore<BroadcasterToLocalConfigEnvironment>());
|
2021-05-16 11:38:41 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-05-17 14:14:46 +08:00
|
|
|
TEST_CASE("/fdbserver/ConfigDB/BroadcasterToLocalConfig/GlobalSet") {
|
2021-05-19 14:50:01 +08:00
|
|
|
wait(testGlobalSet<BroadcasterToLocalConfigEnvironment>());
|
2021-05-16 11:38:41 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-05-24 12:03:15 +08:00
|
|
|
// TEST_CASE("/fdbserver/ConfigDB/BroadcasterToLocalConfig/ChangeBroadcaster") {
|
|
|
|
// wait(testChangeBroadcaster<BroadcasterToLocalConfigEnvironment>());
|
|
|
|
// return Void();
|
|
|
|
//}
|
2021-05-16 13:28:12 +08:00
|
|
|
|
2021-05-19 12:29:40 +08:00
|
|
|
TEST_CASE("/fdbserver/ConfigDB/BroadcasterToLocalConfig/RestartLocalConfig") {
|
2021-05-19 14:50:01 +08:00
|
|
|
wait(testRestartLocalConfig<BroadcasterToLocalConfigEnvironment>());
|
2021-05-19 12:29:40 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-05-24 12:03:15 +08:00
|
|
|
// TEST_CASE("/fdbserver/ConfigDB/BroadcasterToLocalConfig/RestartLocalConfigAndChangeClass") {
|
|
|
|
// wait(testRestartLocalConfigAndChangeClass<BroadcasterToLocalConfigEnvironment>());
|
|
|
|
// return Void();
|
|
|
|
//}
|
2021-05-19 12:29:40 +08:00
|
|
|
|
2021-05-17 15:52:24 +08:00
|
|
|
TEST_CASE("/fdbserver/ConfigDB/BroadcasterToLocalConfig/Compact") {
|
2021-05-19 14:50:01 +08:00
|
|
|
wait(testCompact<BroadcasterToLocalConfigEnvironment>());
|
2021-05-17 15:52:24 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-05-16 13:28:12 +08:00
|
|
|
TEST_CASE("/fdbserver/ConfigDB/TransactionToLocalConfig/Set") {
|
2021-05-19 14:50:01 +08:00
|
|
|
wait(testSet<TransactionToLocalConfigEnvironment>());
|
2021-05-16 13:28:12 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("/fdbserver/ConfigDB/TransactionToLocalConfig/Clear") {
|
2021-05-19 14:50:01 +08:00
|
|
|
wait(testClear<TransactionToLocalConfigEnvironment>());
|
2021-05-17 14:14:46 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("/fdbserver/ConfigDB/TransactionToLocalConfig/GlobalSet") {
|
2021-05-19 14:50:01 +08:00
|
|
|
wait(testGlobalSet<TransactionToLocalConfigEnvironment>());
|
2021-05-17 14:14:46 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-05-17 15:52:24 +08:00
|
|
|
TEST_CASE("/fdbserver/ConfigDB/TransactionToLocalConfig/RestartNode") {
|
|
|
|
state TransactionToLocalConfigEnvironment env("class-A");
|
|
|
|
wait(env.setup());
|
|
|
|
wait(set(env, "class-A"_sr, 1));
|
2021-05-24 09:01:50 +08:00
|
|
|
env.restartNode();
|
2021-05-17 15:52:24 +08:00
|
|
|
wait(check(env, 1));
|
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-05-19 14:50:01 +08:00
|
|
|
TEST_CASE("/fdbserver/ConfigDB/TransactionToLocalConfig/ChangeBroadcaster") {
|
|
|
|
wait(testChangeBroadcaster<TransactionToLocalConfigEnvironment>());
|
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("/fdbserver/ConfigDB/TransactionToLocalConfig/RestartLocalConfigAndChangeClass") {
|
|
|
|
wait(testRestartLocalConfigAndChangeClass<TransactionToLocalConfigEnvironment>());
|
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-05-24 07:44:06 +08:00
|
|
|
TEST_CASE("/fdbserver/ConfigDB/TransactionToLocalConfig/CompactNode") {
|
|
|
|
wait(testCompact<TransactionToLocalConfigEnvironment>());
|
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-05-17 14:14:46 +08:00
|
|
|
TEST_CASE("/fdbserver/ConfigDB/Transaction/Set") {
|
2021-05-19 14:50:01 +08:00
|
|
|
wait(testSet<TransactionEnvironment>());
|
2021-05-17 14:14:46 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("/fdbserver/ConfigDB/Transaction/Clear") {
|
2021-05-19 14:50:01 +08:00
|
|
|
wait(testClear<TransactionEnvironment>());
|
2021-05-16 13:28:12 +08:00
|
|
|
return Void();
|
|
|
|
}
|
2021-05-17 15:52:24 +08:00
|
|
|
|
|
|
|
TEST_CASE("/fdbserver/ConfigDB/Transaction/Restart") {
|
|
|
|
state TransactionEnvironment env;
|
|
|
|
wait(set(env, "class-A"_sr, 1));
|
2021-05-24 09:01:50 +08:00
|
|
|
env.restartNode();
|
2021-05-17 15:52:24 +08:00
|
|
|
wait(check(env, "class-A"_sr, 1));
|
|
|
|
return Void();
|
|
|
|
}
|
2021-05-24 07:44:06 +08:00
|
|
|
|
|
|
|
TEST_CASE("/fdbserver/ConfigDB/Transaction/CompactNode") {
|
|
|
|
state TransactionEnvironment env;
|
|
|
|
wait(set(env, "class-A"_sr, 1));
|
|
|
|
wait(env.compact());
|
|
|
|
wait(env.check("class-A"_sr, 1));
|
|
|
|
wait(set(env, "class-A"_sr, 2));
|
|
|
|
wait(env.check("class-A"_sr, 2));
|
|
|
|
return Void();
|
|
|
|
}
|
2021-05-29 18:58:18 +08:00
|
|
|
|
|
|
|
TEST_CASE("/fdbserver/ConfigDB/Transaction/GetConfigClasses") {
|
|
|
|
wait(testGetConfigClasses(false));
|
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("/fdbserver/ConfigDB/Transaction/CompactThenGetConfigClasses") {
|
|
|
|
wait(testGetConfigClasses(true));
|
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("/fdbserver/ConfigDB/Transaction/GetKnobs") {
|
|
|
|
wait(testGetKnobs(false));
|
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("/fdbserver/ConfigDB/Transaction/CompactThenGetKnobs") {
|
|
|
|
wait(testGetKnobs(true));
|
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("/fdbserver/ConfigDB/Transaction/BadRangeRead") {
|
|
|
|
state TransactionEnvironment env;
|
|
|
|
try {
|
|
|
|
wait(env.badRangeRead() || env.getError());
|
|
|
|
ASSERT(false);
|
|
|
|
} catch (Error& e) {
|
|
|
|
ASSERT_EQ(e.code(), error_code_invalid_config_db_range_read);
|
|
|
|
}
|
|
|
|
return Void();
|
|
|
|
}
|