diff --git a/ConflictSet.cpp b/ConflictSet.cpp index 08a67af..2848244 100644 --- a/ConflictSet.cpp +++ b/ConflictSet.cpp @@ -552,6 +552,12 @@ int getChildGeq(Node *self, int child) { return -1; } +void setChildrenParents(Node4 *n) { + for (int i = 0; i < n->numChildren; ++i) { + n->children[i].child->parent = n; + } +} + void setChildrenParents(Node16 *n) { for (int i = 0; i < n->numChildren; ++i) { n->children[i].child->parent = n; @@ -706,8 +712,95 @@ Node *&getOrCreateChild(Node *&self, uint8_t index, } } +// TODO fuse into erase child so we don't need to repeat branches on type +void maybeDownsize(Node *self, Node *&root, NodeAllocators *allocators) { + switch (self->type) { + case Type::Node0: + __builtin_unreachable(); // GCOVR_EXCL_LINE + case Type::Node4: + if (self->numChildren < kMinChildrenNode4) { + // Merge partial key with child + } + break; + case Type::Node16: + if (self->numChildren < kMinChildrenNode16) { + auto *self16 = (Node16 *)self; + auto *newSelf = allocators->node4.allocate(self->partialKeyLen); + memcpy((char *)newSelf + kNodeCopyBegin, (char *)self + kNodeCopyBegin, + kNodeCopySize); + memcpy(newSelf->partialKey(), self16->partialKey(), self->partialKeyLen); + // TODO replace with memcpy? + for (int i = 0; i < 4; ++i) { + newSelf->index[i] = self16->index[i]; + newSelf->children[i] = self16->children[i]; + } + allocators->node16.release(self16); + setChildrenParents(newSelf); + if (newSelf->parent == nullptr) { + root = newSelf; + } else { + getChildExists(newSelf->parent, newSelf->parentsIndex) = newSelf; + } + } + break; + case Type::Node48: + if (self->numChildren < kMinChildrenNode48) { + auto *self48 = (Node48 *)self; + auto *newSelf = allocators->node16.allocate(self->partialKeyLen); + memcpy((char *)newSelf + kNodeCopyBegin, (char *)self + kNodeCopyBegin, + kNodeCopySize); + memcpy(newSelf->partialKey(), self48->partialKey(), self->partialKeyLen); + + int i = 0; + self48->bitSet.forEachInRange( + [&](int c) { + newSelf->index[i] = c; + newSelf->children[i] = self48->children[self48->index[c]]; + ++i; + }, + 0, 256); + + allocators->node48.release(self48); + setChildrenParents(newSelf); + if (newSelf->parent == nullptr) { + root = newSelf; + } else { + getChildExists(newSelf->parent, newSelf->parentsIndex) = newSelf; + } + } + break; + case Type::Node256: + if (self->numChildren < kMinChildrenNode256) { + auto *self256 = (Node256 *)self; + auto *newSelf = allocators->node48.allocate(self->partialKeyLen); + memcpy((char *)newSelf + kNodeCopyBegin, (char *)self + kNodeCopyBegin, + kNodeCopySize); + memcpy(newSelf->partialKey(), self256->partialKey(), self->partialKeyLen); + + newSelf->bitSet = self256->bitSet; + newSelf->bitSet.forEachInRange( + [&](int c) { + newSelf->index[c] = newSelf->nextFree; + newSelf->children[newSelf->nextFree] = self256->children[c]; + ++newSelf->nextFree; + }, + 0, 256); + + allocators->node256.release(self256); + setChildrenParents(newSelf); + if (newSelf->parent == nullptr) { + root = newSelf; + } else { + getChildExists(newSelf->parent, newSelf->parentsIndex) = newSelf; + } + } + break; + } +} + // Precondition - an entry for index must exist in the node -void eraseChild(Node *self, uint8_t index, NodeAllocators *allocators) { +void eraseChild(Node *self, uint8_t index, NodeAllocators *allocators, + Node *&root) { auto *child = getChildExists(self, index); switch (child->type) { case Type::Node0: @@ -733,7 +826,7 @@ void eraseChild(Node *self, uint8_t index, NodeAllocators *allocators) { memmove(self16->index + nodeIndex, self16->index + nodeIndex + 1, sizeof(self16->index[0]) * (self->numChildren - (nodeIndex + 1))); memmove(self16->children + nodeIndex, self16->children + nodeIndex + 1, - sizeof(self16->children[0]) * // NOLINT + sizeof(self16->children[0]) * (self->numChildren - (nodeIndex + 1))); } else if (self->type == Type::Node48) { auto *self48 = static_cast(self); @@ -757,7 +850,9 @@ void eraseChild(Node *self, uint8_t index, NodeAllocators *allocators) { --self->numChildren; if (self->numChildren == 0 && !self->entryPresent && self->parent != nullptr) { - eraseChild(self->parent, self->parentsIndex, allocators); + eraseChild(self->parent, self->parentsIndex, allocators, root); + } else { + maybeDownsize(self, root, allocators); } } @@ -1773,7 +1868,7 @@ void addWriteRange(Node *&root, int64_t oldestVersion, beginNode = nextLogical(beginNode); old->entryPresent = false; if (old->numChildren == 0 && old->parent != nullptr) { - eraseChild(old->parent, old->parentsIndex, allocators); + eraseChild(old->parent, old->parentsIndex, allocators, root); } } } @@ -1904,7 +1999,7 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl { assert(n->entry.rangeVersion <= oldestVersion); prev->entryPresent = false; if (prev->numChildren == 0 && prev->parent != nullptr) { - eraseChild(prev->parent, prev->parentsIndex, &allocators); + eraseChild(prev->parent, prev->parentsIndex, &allocators, root); } }