Add forwarding pointers + deferred release
This commit is contained in:
@@ -262,7 +262,11 @@ private:
|
|||||||
struct Node {
|
struct Node {
|
||||||
|
|
||||||
/* begin section that's copied to the next node */
|
/* begin section that's copied to the next node */
|
||||||
Entry entry;
|
union {
|
||||||
|
Entry entry;
|
||||||
|
/* Set to the forwarding point for this node if deferredReleased is set */
|
||||||
|
Node *forwardTo;
|
||||||
|
};
|
||||||
Node *parent;
|
Node *parent;
|
||||||
int32_t partialKeyLen;
|
int32_t partialKeyLen;
|
||||||
int16_t numChildren;
|
int16_t numChildren;
|
||||||
@@ -272,9 +276,19 @@ struct Node {
|
|||||||
uint8_t parentsIndex;
|
uint8_t parentsIndex;
|
||||||
/* end section that's copied to the next node */
|
/* end section that's copied to the next node */
|
||||||
|
|
||||||
|
/* If set, this node has been replaced and the next node in the forwarding
|
||||||
|
* chain is `forwardTo`*/
|
||||||
|
bool deferredReleased;
|
||||||
|
|
||||||
uint8_t *partialKey();
|
uint8_t *partialKey();
|
||||||
Type getType() const { return type; }
|
Type getType() const {
|
||||||
int32_t getCapacity() const { return partialKeyCapacity; }
|
assert(!deferredReleased);
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
int32_t getCapacity() const {
|
||||||
|
assert(!deferredReleased);
|
||||||
|
return partialKeyCapacity;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <class T> friend struct BoundedFreeListAllocator;
|
template <class T> friend struct BoundedFreeListAllocator;
|
||||||
@@ -305,7 +319,10 @@ constexpr int kNodeCopySize =
|
|||||||
struct Node0 : Node {
|
struct Node0 : Node {
|
||||||
constexpr static auto kType = Type_Node0;
|
constexpr static auto kType = Type_Node0;
|
||||||
|
|
||||||
uint8_t *partialKey() { return (uint8_t *)(this + 1); }
|
uint8_t *partialKey() {
|
||||||
|
assert(!deferredReleased);
|
||||||
|
return (uint8_t *)(this + 1);
|
||||||
|
}
|
||||||
void copyChildrenAndKeyFrom(const Node0 &other);
|
void copyChildrenAndKeyFrom(const Node0 &other);
|
||||||
void copyChildrenAndKeyFrom(const struct Node3 &other);
|
void copyChildrenAndKeyFrom(const struct Node3 &other);
|
||||||
size_t size() const { return sizeof(Node0) + getCapacity(); }
|
size_t size() const { return sizeof(Node0) + getCapacity(); }
|
||||||
@@ -320,7 +337,10 @@ struct Node3 : Node {
|
|||||||
// Sorted
|
// Sorted
|
||||||
uint8_t index[kMaxNodes];
|
uint8_t index[kMaxNodes];
|
||||||
|
|
||||||
uint8_t *partialKey() { return (uint8_t *)(this + 1); }
|
uint8_t *partialKey() {
|
||||||
|
assert(!deferredReleased);
|
||||||
|
return (uint8_t *)(this + 1);
|
||||||
|
}
|
||||||
void copyChildrenAndKeyFrom(const Node0 &other);
|
void copyChildrenAndKeyFrom(const Node0 &other);
|
||||||
void copyChildrenAndKeyFrom(const Node3 &other);
|
void copyChildrenAndKeyFrom(const Node3 &other);
|
||||||
void copyChildrenAndKeyFrom(const struct Node16 &other);
|
void copyChildrenAndKeyFrom(const struct Node16 &other);
|
||||||
@@ -336,7 +356,10 @@ struct Node16 : Node {
|
|||||||
// Sorted
|
// Sorted
|
||||||
uint8_t index[kMaxNodes];
|
uint8_t index[kMaxNodes];
|
||||||
|
|
||||||
uint8_t *partialKey() { return (uint8_t *)(this + 1); }
|
uint8_t *partialKey() {
|
||||||
|
assert(!deferredReleased);
|
||||||
|
return (uint8_t *)(this + 1);
|
||||||
|
}
|
||||||
void copyChildrenAndKeyFrom(const Node3 &other);
|
void copyChildrenAndKeyFrom(const Node3 &other);
|
||||||
void copyChildrenAndKeyFrom(const Node16 &other);
|
void copyChildrenAndKeyFrom(const Node16 &other);
|
||||||
void copyChildrenAndKeyFrom(const struct Node48 &other);
|
void copyChildrenAndKeyFrom(const struct Node48 &other);
|
||||||
@@ -358,7 +381,10 @@ struct Node48 : Node {
|
|||||||
uint8_t reverseIndex[kMaxNodes];
|
uint8_t reverseIndex[kMaxNodes];
|
||||||
int8_t index[256];
|
int8_t index[256];
|
||||||
|
|
||||||
uint8_t *partialKey() { return (uint8_t *)(this + 1); }
|
uint8_t *partialKey() {
|
||||||
|
assert(!deferredReleased);
|
||||||
|
return (uint8_t *)(this + 1);
|
||||||
|
}
|
||||||
void copyChildrenAndKeyFrom(const Node16 &other);
|
void copyChildrenAndKeyFrom(const Node16 &other);
|
||||||
void copyChildrenAndKeyFrom(const Node48 &other);
|
void copyChildrenAndKeyFrom(const Node48 &other);
|
||||||
void copyChildrenAndKeyFrom(const struct Node256 &other);
|
void copyChildrenAndKeyFrom(const struct Node256 &other);
|
||||||
@@ -378,7 +404,10 @@ struct Node256 : Node {
|
|||||||
InternalVersionT childMaxVersion[kMaxNodes];
|
InternalVersionT childMaxVersion[kMaxNodes];
|
||||||
InternalVersionT maxOfMax[kMaxOfMaxTotalPages];
|
InternalVersionT maxOfMax[kMaxOfMaxTotalPages];
|
||||||
|
|
||||||
uint8_t *partialKey() { return (uint8_t *)(this + 1); }
|
uint8_t *partialKey() {
|
||||||
|
assert(!deferredReleased);
|
||||||
|
return (uint8_t *)(this + 1);
|
||||||
|
}
|
||||||
void copyChildrenAndKeyFrom(const Node48 &other);
|
void copyChildrenAndKeyFrom(const Node48 &other);
|
||||||
void copyChildrenAndKeyFrom(const Node256 &other);
|
void copyChildrenAndKeyFrom(const Node256 &other);
|
||||||
size_t size() const { return sizeof(Node256) + getCapacity(); }
|
size_t size() const { return sizeof(Node256) + getCapacity(); }
|
||||||
@@ -679,6 +708,7 @@ template <class T> struct BoundedFreeListAllocator {
|
|||||||
T *allocate(int partialKeyCapacity) {
|
T *allocate(int partialKeyCapacity) {
|
||||||
T *result = allocate_helper(partialKeyCapacity);
|
T *result = allocate_helper(partialKeyCapacity);
|
||||||
result->endOfRange = false;
|
result->endOfRange = false;
|
||||||
|
result->deferredReleased = false;
|
||||||
if constexpr (!std::is_same_v<T, Node0>) {
|
if constexpr (!std::is_same_v<T, Node0>) {
|
||||||
memset(result->children, 0, sizeof(result->children));
|
memset(result->children, 0, sizeof(result->children));
|
||||||
const auto z = InternalVersionT::zero;
|
const auto z = InternalVersionT::zero;
|
||||||
@@ -821,7 +851,42 @@ struct WriteContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Place in a list to be released in the next call to releaseDeferred.
|
||||||
|
void deferRelease(Node *n) {
|
||||||
|
n->parent = deferredList;
|
||||||
|
deferredList = n;
|
||||||
|
}
|
||||||
|
// Release all nodes passed to deferRelease since the last call to
|
||||||
|
// releaseDeferred.
|
||||||
|
void releaseDeferred() {
|
||||||
|
for (Node *n = std::exchange(deferredList, nullptr); n != nullptr;) {
|
||||||
|
auto *tmp = n;
|
||||||
|
n = n->parent;
|
||||||
|
switch (tmp->getType()) {
|
||||||
|
case Type_Node0:
|
||||||
|
release(static_cast<Node0 *>(tmp));
|
||||||
|
break;
|
||||||
|
case Type_Node3:
|
||||||
|
release(static_cast<Node3 *>(tmp));
|
||||||
|
break;
|
||||||
|
case Type_Node16:
|
||||||
|
release(static_cast<Node16 *>(tmp));
|
||||||
|
break;
|
||||||
|
case Type_Node48:
|
||||||
|
release(static_cast<Node48 *>(tmp));
|
||||||
|
break;
|
||||||
|
case Type_Node256:
|
||||||
|
release(static_cast<Node256 *>(tmp));
|
||||||
|
break;
|
||||||
|
default: // GCOVR_EXCL_LINE
|
||||||
|
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Node *deferredList = nullptr;
|
||||||
|
|
||||||
BoundedFreeListAllocator<Node0> node0;
|
BoundedFreeListAllocator<Node0> node0;
|
||||||
BoundedFreeListAllocator<Node3> node3;
|
BoundedFreeListAllocator<Node3> node3;
|
||||||
BoundedFreeListAllocator<Node16> node16;
|
BoundedFreeListAllocator<Node16> node16;
|
||||||
|
Reference in New Issue
Block a user