Added SimpleConfigDatabase compaction (not yet tested)

This commit is contained in:
sfc-gh-tclinkenbeard 2021-04-23 09:22:47 -07:00
parent e3be3bd90c
commit 1a6dcd6677
4 changed files with 67 additions and 15 deletions

View File

@ -84,6 +84,10 @@ struct VersionedMutationRef {
VersionedMutationRef()=default;
explicit VersionedMutationRef(Arena &arena, Version version, MutationRef mutation) : version(version), mutation(arena, mutation) {}
explicit VersionedMutationRef(Arena& arena, VersionedMutationRef const& rhs)
: version(rhs.version), mutation(arena, rhs.mutation) {}
size_t expectedSize() const { return sizeof(Version) + mutation.expectedSize(); }
template<class Ar>
void serialize(Ar &ar) {
@ -125,12 +129,12 @@ struct ConfigFollowerGetChangesRequest {
struct ConfigFollowerCompactRequest {
static constexpr FileIdentifier file_identifier = 568910;
Version lastTruncatedVersion;
Version version;
ReplyPromise<Void> reply;
template <class Ar>
void serialize(Ar& ar) {
serializer(ar, lastTruncatedVersion, reply);
serializer(ar, version, reply);
}
};

View File

@ -22,8 +22,9 @@
class SimpleConfigBroadcasterImpl {
Reference<ConfigFollowerInterface> subscriber;
std::map<Key, Value> fullDatabase;
Standalone<VectorRef<VersionedMutationRef>> versionedMutations;
std::map<Key, Value> database;
// TODO: Should create fewer arenas
std::deque<Standalone<VersionedMutationRef>> versionedMutations;
Version lastCompactedVersion;
Version mostRecentVersion;
ActorCollection actors{ false };
@ -35,7 +36,7 @@ class SimpleConfigBroadcasterImpl {
ConfigFollowerGetChangesReply reply = wait(
self->subscriber->getChanges.getReply(ConfigFollowerGetChangesRequest{ self->mostRecentVersion, {} }));
for (const auto &versionedMutation : reply.versionedMutations) {
self->versionedMutations.push_back(self->versionedMutations.arena(), versionedMutation);
self->versionedMutations.push_back(versionedMutation);
}
self->mostRecentVersion = reply.mostRecentVersion;
wait(delay(POLLING_INTERVAL));
@ -61,7 +62,7 @@ class SimpleConfigBroadcasterImpl {
self->mostRecentVersion = versionReply.version;
ConfigFollowerGetFullDatabaseReply reply = wait(self->subscriber->getFullDatabase.getReply(
ConfigFollowerGetFullDatabaseRequest{ self->mostRecentVersion, Optional<Value>{} }));
self->fullDatabase = reply.database;
self->database = reply.database;
self->actors.add(fetchUpdates(self));
loop {
//self->traceQueuedMutations();
@ -71,7 +72,7 @@ class SimpleConfigBroadcasterImpl {
}
when(ConfigFollowerGetFullDatabaseRequest req = waitNext(publisher->getFullDatabase.getFuture())) {
ConfigFollowerGetFullDatabaseReply reply;
reply.database = self->fullDatabase;
reply.database = self->database;
for (const auto &versionedMutation : self->versionedMutations) {
const auto &version = versionedMutation.version;
const auto &mutation = versionedMutation.mutation;
@ -82,22 +83,41 @@ class SimpleConfigBroadcasterImpl {
reply.database[mutation.param1] = mutation.param2;
} else if (mutation.type == MutationRef::ClearRange) {
reply.database.erase(reply.database.find(mutation.param1), reply.database.find(mutation.param2));
} else {
ASSERT(false);
}
}
req.reply.send(ConfigFollowerGetFullDatabaseReply{self->fullDatabase});
req.reply.send(ConfigFollowerGetFullDatabaseReply{ self->database });
}
when(ConfigFollowerGetChangesRequest req = waitNext(publisher->getChanges.getFuture())) {
ConfigFollowerGetChangesReply reply;
reply.mostRecentVersion = self->mostRecentVersion;
for (const auto &versionedMutation : self->versionedMutations) {
if (versionedMutation.version > req.lastSeenVersion) {
reply.versionedMutations.push_back(reply.versionedMutations.arena(), versionedMutation);
reply.versionedMutations.push_back_deep(reply.versionedMutations.arena(),
versionedMutation);
}
}
req.reply.send(reply);
}
when(ConfigFollowerCompactRequest req = waitNext(publisher->compact.getFuture())) {
// TODO: Implement
while (!self->versionedMutations.empty()) {
const auto& versionedMutation = self->versionedMutations.front();
const auto& version = versionedMutation.version;
const auto& mutation = versionedMutation.mutation;
if (version > req.version) {
break;
} else if (mutation.type == MutationRef::SetValue) {
self->database[mutation.param1] = mutation.param2;
} else if (mutation.type == MutationRef::ClearRange) {
self->database.erase(self->database.find(mutation.param1),
self->database.find(mutation.param2));
} else {
ASSERT(false);
}
self->lastCompactedVersion = version;
self->versionedMutations.pop_front();
}
req.reply.send(Void());
}
when(wait(self->actors.getResult())) { ASSERT(false); }

View File

@ -35,7 +35,6 @@ const KeyRef committedVersionKey = LiteralStringRef("committedVersion");
const KeyRangeRef kvKeys = KeyRangeRef(LiteralStringRef("kv/"), LiteralStringRef("kv0"));
const KeyRangeRef mutationKeys = KeyRangeRef(LiteralStringRef("mutation/"), LiteralStringRef("mutation0"));
// FIXME: negative versions break ordering
Key versionedMutationKey(Version version, uint32_t index) {
ASSERT(version >= 0);
BinaryWriter bw(IncludeVersion());
@ -84,6 +83,7 @@ class SimpleConfigDatabaseNodeImpl {
IKeyValueStore* kvStore; // FIXME: Prevent leak
std::map<std::string, std::string> config;
ActorCollection actors{ false };
Version lastCompactedVersion{ 0 };
FlowLock globalLock;
ACTOR static Future<Version> getLiveTransactionVersion(SimpleConfigDatabaseNodeImpl *self) {
@ -253,6 +253,31 @@ class SimpleConfigDatabaseNodeImpl {
return Void();
}
ACTOR static Future<Void> compact(SimpleConfigDatabaseNodeImpl* self, ConfigFollowerCompactRequest req) {
// TODO: Lock
Standalone<VectorRef<VersionedMutationRef>> versionedMutations = wait(getMutations(self, 0, req.version));
self->kvStore->clear(
KeyRangeRef(mutationKeys.begin, versionedMutationKey(req.version, 100000))); // FIXME: This is a hack
for (const auto& versionedMutation : versionedMutations) {
const auto& version = versionedMutation.version;
const auto& mutation = versionedMutation.mutation;
if (version > req.version) {
req.reply.send(Void());
return Void();
} else if (mutation.type == MutationRef::SetValue) {
self->kvStore->set(KeyValueRef(mutation.param1, mutation.param2));
} else if (mutation.type == MutationRef::ClearRange) {
self->kvStore->clear(KeyRangeRef(mutation.param1, mutation.param2));
} else {
ASSERT(false);
}
}
wait(self->kvStore->commit());
req.reply.send(Void());
self->lastCompactedVersion = req.version;
return Void();
}
ACTOR static Future<Void> serve(SimpleConfigDatabaseNodeImpl* self, ConfigFollowerInterface* cfi) {
loop {
choose {
@ -266,7 +291,7 @@ class SimpleConfigDatabaseNodeImpl {
self->actors.add(getChanges(self, req));
}
when(ConfigFollowerCompactRequest req = waitNext(cfi->compact.getFuture())) {
// TODO: Implement
self->actors.add(compact(self, req));
req.reply.send(Void());
}
when(wait(self->actors.getResult())) { ASSERT(false); }

View File

@ -109,15 +109,18 @@ class ConfigurationDatabaseWorkload : public TestWorkload {
state Future<int> expectedTotal = self->expectedTotal.getFuture();
state int currentValue = 0;
loop {
state ConfigFollowerGetChangesReply reply =
state ConfigFollowerGetChangesReply changesReply =
wait(cfi->getChanges.getReply(ConfigFollowerGetChangesRequest{ mostRecentVersion, {} }));
mostRecentVersion = reply.mostRecentVersion;
for (const auto& versionedMutation : reply.versionedMutations) {
mostRecentVersion = changesReply.mostRecentVersion;
// wait(cfi->compact.getReply(ConfigFollowerCompactRequest{ mostRecentVersion }));
for (const auto& versionedMutation : changesReply.versionedMutations) {
const auto& mutation = versionedMutation.mutation;
if (mutation.type == MutationRef::SetValue) {
database[mutation.param1] = mutation.param2;
} else if (mutation.type == MutationRef::ClearRange) {
database.erase(database.find(mutation.param1), database.find(mutation.param2));
} else {
ASSERT(false);
}
}
if (database.count(self->key)) {