Maintain "reverseIndex" in Node48
This commit is contained in:
@@ -294,8 +294,7 @@ struct Node48 : Node {
|
||||
int8_t nextFree;
|
||||
int8_t index[256];
|
||||
Child children[kMaxNodes];
|
||||
// Max of each "page" of 16 children
|
||||
int64_t maxOfMax[16];
|
||||
uint8_t reverseIndex[kMaxNodes];
|
||||
|
||||
uint8_t *partialKey() { return (uint8_t *)(this + 1); }
|
||||
|
||||
@@ -419,7 +418,7 @@ inline void Node48::copyChildrenAndKeyFrom(const Node16 &other) {
|
||||
children[i] = other.children[i];
|
||||
assert(children[i].child->parent == &other);
|
||||
children[i].child->parent = this;
|
||||
maxOfMax[x >> 4] = std::max(maxOfMax[x >> 4], children[i].childMaxVersion);
|
||||
reverseIndex[i] = x;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
@@ -434,7 +433,7 @@ inline void Node48::copyChildrenAndKeyFrom(const Node48 &other) {
|
||||
assert(children[i].child->parent == &other);
|
||||
children[i].child->parent = this;
|
||||
}
|
||||
memcpy(maxOfMax, other.maxOfMax, sizeof(maxOfMax));
|
||||
memcpy(reverseIndex, other.reverseIndex, sizeof(reverseIndex));
|
||||
memcpy(partialKey(), &other + 1, partialKeyLen);
|
||||
}
|
||||
|
||||
@@ -454,10 +453,10 @@ inline void Node48::copyChildrenAndKeyFrom(const Node256 &other) {
|
||||
children[i] = other.children[c];
|
||||
assert(children[i].child->parent == &other);
|
||||
children[i].child->parent = this;
|
||||
reverseIndex[i] = c;
|
||||
++i;
|
||||
},
|
||||
0, 256);
|
||||
memcpy(maxOfMax, other.maxOfMax, sizeof(maxOfMax));
|
||||
memcpy(partialKey(), &other + 1, partialKeyLen);
|
||||
}
|
||||
|
||||
@@ -472,9 +471,10 @@ inline void Node256::copyChildrenAndKeyFrom(const Node48 &other) {
|
||||
children[c] = other.children[other.index[c]];
|
||||
assert(children[c].child->parent == &other);
|
||||
children[c].child->parent = this;
|
||||
maxOfMax[c >> 4] =
|
||||
std::max(maxOfMax[c >> 4], children[c].childMaxVersion);
|
||||
},
|
||||
0, 256);
|
||||
memcpy(maxOfMax, other.maxOfMax, sizeof(maxOfMax));
|
||||
memcpy(partialKey(), &other + 1, partialKeyLen);
|
||||
}
|
||||
|
||||
@@ -575,7 +575,7 @@ template <class T> struct BoundedFreeListAllocator {
|
||||
if constexpr (!std::is_same_v<T, Node0>) {
|
||||
memset(result->children, 0, sizeof(result->children));
|
||||
}
|
||||
if constexpr (std::is_same_v<T, Node48> || std::is_same_v<T, Node256>) {
|
||||
if constexpr (std::is_same_v<T, Node256>) {
|
||||
memset(result->maxOfMax, 0, sizeof(result->maxOfMax));
|
||||
}
|
||||
return result;
|
||||
@@ -1047,6 +1047,7 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
|
||||
assert(self48->nextFree < 48);
|
||||
int nextFree = self48->nextFree++;
|
||||
self48->index[index] = nextFree;
|
||||
self48->reverseIndex[nextFree] = index;
|
||||
auto &result = self48->children[nextFree].child;
|
||||
result = nullptr;
|
||||
return result;
|
||||
@@ -1346,8 +1347,10 @@ Node *erase(Node *self, NodeAllocators *allocators, ConflictSet::Impl *impl,
|
||||
if (toRemoveChildrenIndex != lastChildrenIndex) {
|
||||
parent48->children[toRemoveChildrenIndex] =
|
||||
parent48->children[lastChildrenIndex];
|
||||
parent48->index[parent48->children[toRemoveChildrenIndex]
|
||||
.child->parentsIndex] = toRemoveChildrenIndex;
|
||||
auto parentIndex =
|
||||
parent48->children[toRemoveChildrenIndex].child->parentsIndex;
|
||||
parent48->index[parentIndex] = toRemoveChildrenIndex;
|
||||
parent48->reverseIndex[toRemoveChildrenIndex] = parentIndex;
|
||||
}
|
||||
|
||||
--parent->numChildren;
|
||||
@@ -1692,36 +1695,18 @@ bool checkMaxBetweenExclusive(Node *n, int begin, int end,
|
||||
} break;
|
||||
case Type_Node48: {
|
||||
auto *self = static_cast<Node48 *>(n);
|
||||
// Check the first page
|
||||
if (self->maxOfMax[begin >> 4] > readVersion) {
|
||||
bool result = true;
|
||||
self->bitSet.forEachInRange(
|
||||
[&](int i) {
|
||||
result &=
|
||||
self->children[self->index[i]].childMaxVersion <= readVersion;
|
||||
},
|
||||
begin, std::min((begin & ~15) + 16, end));
|
||||
if (!result) {
|
||||
return result;
|
||||
}
|
||||
bool conflict[Node48::kMaxNodes] = {};
|
||||
assume(self->numChildren >= kMinChildrenNode48 - 1 /* entry present */);
|
||||
assume(self->numChildren <= Node48::kMaxNodes);
|
||||
for (int i = 0; i < self->numChildren; ++i) {
|
||||
assert(self->index[self->reverseIndex[i]] == i);
|
||||
conflict[i] = (begin <= self->reverseIndex[i]) &
|
||||
(self->reverseIndex[i] < end) &
|
||||
(self->children[i].childMaxVersion > readVersion);
|
||||
}
|
||||
// Check the last page
|
||||
if (end >= 1 && self->maxOfMax[(end - 1) >> 4] > readVersion) {
|
||||
bool result = true;
|
||||
self->bitSet.forEachInRange(
|
||||
[&](int i) {
|
||||
result &=
|
||||
self->children[self->index[i]].childMaxVersion <= readVersion;
|
||||
},
|
||||
std::max(begin, end & ~15), end);
|
||||
if (!result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
// Check inner pages
|
||||
bool result = true;
|
||||
for (int i = (begin >> 4) + 1; i < (end - 1) >> 4; ++i) {
|
||||
result &= self->maxOfMax[i] <= readVersion;
|
||||
for (auto c : conflict) {
|
||||
result &= !c;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -2685,7 +2670,6 @@ void setMaxVersion(Node *n, ConflictSet::Impl *impl, int64_t newMax) {
|
||||
auto *n48 = static_cast<Node48 *>(n);
|
||||
assert(n48->bitSet.test(index));
|
||||
n48->children[n48->index[index]].childMaxVersion = newMax;
|
||||
n48->maxOfMax[index >> 4] = std::max(n48->maxOfMax[index >> 4], newMax);
|
||||
return;
|
||||
}
|
||||
case Type_Node256: {
|
||||
|
Reference in New Issue
Block a user