diff --git a/ConflictSet.cpp b/ConflictSet.cpp index 7a8ba3e..ab74e10 100644 --- a/ConflictSet.cpp +++ b/ConflictSet.cpp @@ -718,10 +718,23 @@ 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 < 2) { + case Type::Node4: { + auto *self4 = (Node4 *)self; + if (self->numChildren == 0) { + auto *newSelf = allocators->node0.allocate(self->partialKeyLen); + memcpy((char *)newSelf + kNodeCopyBegin, (char *)self + kNodeCopyBegin, + kNodeCopySize); + memcpy(newSelf->partialKey(), self4->partialKey(), self->partialKeyLen); + + if (self->parent == nullptr) { + root = newSelf; + } else { + getChildExists(self->parent, self->parentsIndex) = newSelf; + } + + allocators->node4.release(self4); + } else if (self->numChildren == 1) { if (!self->entryPresent) { - auto *self4 = (Node4 *)self; auto *child = self4->children[0].child; int minCapacity = self4->partialKeyLen + 1 + child->partialKeyLen; @@ -763,7 +776,7 @@ void maybeDownsize(Node *self, Node *&root, NodeAllocators *allocators, allocators->node4.release(self4); } } - break; + } break; case Type::Node16: if (self->numChildren < kMinChildrenNode16) { auto *self16 = (Node16 *)self; @@ -2365,6 +2378,39 @@ Iterator firstGeq(Node *n, std::string_view key) { return total; } +[[maybe_unused]] void checkMinChildCount(Node *node, bool &success) { + int minNumChildren; + switch (node->type) { + case Type::Node0: + minNumChildren = 0; + break; + case Type::Node4: + minNumChildren = kMinChildrenNode4; + break; + case Type::Node16: + minNumChildren = kMinChildrenNode16; + break; + case Type::Node48: + minNumChildren = kMinChildrenNode48; + break; + case Type::Node256: + minNumChildren = kMinChildrenNode256; + break; + } + if (node->numChildren < minNumChildren) { + Arena arena; + fprintf(stderr, + "%s has %d children, which is less than the minimum required %d\n", + getSearchPathPrintable(node).c_str(), node->numChildren, + minNumChildren); + success = false; + } + for (int i = getChildGeq(node, 0); i >= 0; i = getChildGeq(node, i + 1)) { + auto *child = getChildExists(node, i); + checkMinChildCount(child, success); + } +} + bool checkCorrectness(Node *node, int64_t oldestVersion, ConflictSet::Impl *impl) { bool success = true; @@ -2372,6 +2418,7 @@ bool checkCorrectness(Node *node, int64_t oldestVersion, checkParentPointers(node, success); checkMaxVersion(node, node, oldestVersion, success, impl); checkEntriesExist(node, success); + checkMinChildCount(node, success); return success; }