Implement insert

This commit is contained in:
2024-05-02 15:34:19 -07:00
parent adc376a573
commit 65429ebd0a

View File

@@ -59,6 +59,11 @@ void munmapSafe(void *ptr, size_t size) {
namespace weaselab {
// 96 is enough for an entire search path in a tree with a size that
// overflows int. See
// https://en.wikipedia.org/wiki/Random_binary_tree#The_longest_path
constexpr int kPathLengthUpperBound = 96;
struct Entry {
int64_t insertVersion;
int keyLen;
@@ -216,7 +221,9 @@ struct MemManager {
void gc(const uint32_t *roots, int numRoots, int64_t oldestVersion) {
// Calculate reachable set
BitSet reachable{next};
uint32_t stack[1000]; // Much more than bound imposed by max height of tree
// Each node has at most 3 children and nodes along the search path aren't
// in the stack, so we need 2 * kPathLengthUpperBound
uint32_t stack[2 * kPathLengthUpperBound];
int stackIndex = 0;
auto tryPush = [&](uint32_t p) {
if (!reachable.set(p)) {
@@ -391,11 +398,37 @@ private:
uint32_t end;
};
auto operator<=>(const VersionedMap::Mutation &lhs, const Node &rhs) {
int cl = std::min(lhs.param1Length, rhs.entry->keyLen);
if (cl > 0) {
int c = memcmp(lhs.param1, rhs.entry->getKey(), cl);
if (c != 0) {
return c <=> 0;
}
}
return lhs.param1Length <=> rhs.entry->keyLen;
}
struct Finger {
void push(uint32_t node) { searchPath[searchPathSize_++] = node; }
void pop() { --searchPathSize_; }
uint32_t back() const {
assert(searchPathSize_ > 0);
return searchPath[searchPathSize_ - 1];
}
uint32_t searchPathSize() const { return searchPathSize_; }
private:
uint32_t searchPath[kPathLengthUpperBound];
int searchPathSize_ = 0;
};
struct VersionedMap::Impl {
template <std::memory_order kOrder>
uint32_t child(uint32_t node, bool which, int64_t at) {
static_assert(kOrder == std::memory_order_acquire || kOrder == std::memory_order_relaxed);
static_assert(kOrder == std::memory_order_acquire ||
kOrder == std::memory_order_relaxed);
auto &n = mm.base[node];
if (n.updated.load(kOrder) && n.updateVersion <= at &&
which == n.replacedPointer) {
@@ -469,6 +502,60 @@ struct VersionedMap::Impl {
at);
}
void insert(const Mutation &m) {
Finger finger;
finger.push(latestRoot);
bool directionStack[kPathLengthUpperBound];
int directionStackSize = 0;
// Initialize finger to the search path of `m`
for (;;) {
auto n = finger.back();
if (n == 0) {
break;
}
auto c = m <=> mm.base[n];
if (c == 0) {
// No duplicates
break;
}
finger.push(child<std::memory_order_relaxed>(n, c > 0, latestVersion));
directionStack[directionStackSize++] = c > 0;
}
// Prepare new node
uint32_t node = newNode(latestVersion, m.param1, m.param1Length, m.param2,
m.param2Length, false /* TODO set correctly */);
if (finger.back() != 0) {
auto &n = mm.base[node];
n.pointer[0] =
child<std::memory_order_relaxed>(finger.back(), false, latestVersion);
n.pointer[1] =
child<std::memory_order_relaxed>(finger.back(), true, latestVersion);
}
// Rotate and propagate up the search path
for (;;) {
if (finger.searchPathSize() == 1) {
// Made it to the root
latestRoot = node;
break;
}
finger.pop();
auto parent = finger.back();
const bool direction = directionStack[--directionStackSize];
parent = update(parent, latestVersion, direction, node);
if (mm.base[node].entry->priority > mm.base[parent].entry->priority) {
rotate(parent, latestVersion, direction);
} else {
if (parent == finger.back()) {
break;
}
}
node = parent;
}
}
uint32_t newNode(int64_t version, const uint8_t *key, int keyLen,
const uint8_t *val, int valLen, bool clearTo) {
auto result = mm.allocate();
@@ -513,6 +600,9 @@ struct VersionedMap::Impl {
MemManager mm;
RootSet roots;
// Only meaningful within the callstack of `addMutations`
uint32_t latestRoot;
int64_t latestVersion = 0;
};
} // namespace weaselab
@@ -523,19 +613,21 @@ int main() {
{
weaselab::VersionedMap::Impl impl;
impl.roots.add(impl.newNode(1, (const uint8_t *)"a", 1, nullptr, 0, true),
1);
impl.roots.add(impl.newNode(2, (const uint8_t *)"b", 1, nullptr, -1, false),
2);
impl.roots.add(impl.newNode(3, (const uint8_t *)"c", 1, nullptr, -1, false),
3);
impl.latestRoot = impl.roots.roots()[impl.roots.rootCount() - 1];
impl.latestVersion = 1;
impl.insert(weaselab::VersionedMap::Mutation{
(const uint8_t *)"c", nullptr, 1, 0, weaselab::VersionedMap::Set});
impl.insert(weaselab::VersionedMap::Mutation{
(const uint8_t *)"b", nullptr, 1, 0, weaselab::VersionedMap::Set});
impl.insert(weaselab::VersionedMap::Mutation{
(const uint8_t *)"a", nullptr, 1, 0, weaselab::VersionedMap::Set});
impl.roots.add(impl.latestRoot, impl.latestVersion);
impl.printInOrder(0);
impl.printInOrder(1);
impl.printInOrder(2);
impl.printInOrder(3);
impl.setOldestVersion(3);
}
return 0;
ankerl::nanobench::Bench bench;
bench.minEpochIterations(5000);