Prepare for firstGeq to be safe on foreign threads

This commit is contained in:
2024-05-03 16:17:06 -07:00
parent 99760176a6
commit 971aabea6e
5 changed files with 281 additions and 98 deletions

View File

@@ -1,4 +1,5 @@
#include "VersionedMap.h"
#include "RootSet.h"
#include <assert.h>
#include <atomic>
@@ -315,98 +316,6 @@ private:
uint32_t freeList = 0;
};
struct RootSet {
/// Register the root node for version after adding mutations
void add(uint32_t node, int64_t version) {
if (end == 0) {
nodes[end] = node;
versions[end] = version;
++end;
return;
}
if (nodes[end - 1] == node) {
return;
}
if (end == capacity) {
capacity *= 2;
nodes = (uint32_t *)realloc(nodes, capacity * sizeof(uint32_t));
versions = (int64_t *)realloc(versions, capacity * sizeof(int64_t));
}
nodes[end] = node;
versions[end] = version;
++end;
}
/// Inform that there will be no calls to rootForVersion with a version less
/// than `oldestVersion`
void setOldestVersion(int64_t oldestVersion) {
const uint32_t firstToKeep = lastLeq(oldestVersion);
if (firstToKeep != 0) {
memmove(nodes, nodes + firstToKeep,
(end - firstToKeep) * sizeof(uint32_t));
memmove(versions, versions + firstToKeep,
(end - firstToKeep) * sizeof(int64_t));
end -= firstToKeep;
}
assert(end > 0);
assert(versions[0] <= oldestVersion);
}
/// Get a root node that can correctly be used for `version`
uint32_t rootForVersion(int64_t version) const {
return nodes[lastLeq(version)];
}
const uint32_t *roots() const { return nodes; }
int rootCount() const { return end; }
RootSet() {
nodes = (uint32_t *)malloc(kMinCapacity * sizeof(uint32_t));
versions = (int64_t *)malloc(kMinCapacity * sizeof(int64_t));
capacity = kMinCapacity;
nodes[0] = 0;
versions[0] = 0;
end = 1;
}
~RootSet() {
free(versions);
free(nodes);
}
private:
uint32_t lastLeq(int64_t version) const {
assert(end > 0);
assert(versions[0] <= version);
// Find the last version <= oldestVersion
int left = 1;
int right = end - 1;
int result = 0;
while (left <= right) {
int mid = left + (right - left) / 2;
if (versions[mid] <= version) {
result = mid;
left = mid + 1;
} else {
right = mid - 1;
}
}
assert(result < end);
return result;
}
uint32_t *nodes;
// versions[i] is the version of nodes[i]
int64_t *versions;
constexpr static uint32_t kMinCapacity = 16;
uint32_t capacity;
uint32_t end;
};
auto operator<=>(const VersionedMap::Mutation &lhs, const Node &rhs) {
int cl = std::min(lhs.param1Length, rhs.entry->keyLen);
if (cl > 0) {
@@ -593,7 +502,8 @@ struct VersionedMap::Impl {
}
void printInOrder(int64_t version) {
printInOrderHelper(version, roots.rootForVersion(version));
printInOrderHelper(version,
roots.getThreadSafeHandle().rootForVersion(version));
}
void printInOrderHelper(int64_t version, uint32_t node) {
@@ -675,7 +585,7 @@ int main() {
{
int i = 0;
constexpr int kNumVersions = 1000;
weaselab::RootSet roots;
RootSet roots;
for (; i < kNumVersions; i += 2) {
roots.add(i, i);
roots.add(i, i + 1);
@@ -686,7 +596,8 @@ int main() {
++i;
});
bench.run("roots - rootForVersion", [&]() {
bench.doNotOptimizeAway(roots.rootForVersion(i - kNumVersions / 2));
bench.doNotOptimizeAway(
roots.getThreadSafeHandle().rootForVersion(i - kNumVersions / 2));
});
}