Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 479b39d055 | |||
| 482408d725 | |||
| 45995e3307 | |||
| 359b0b29ff | |||
| 54e47ebd40 | |||
| 1c9dda68a6 | |||
| 142455dd28 | |||
| 567d385fbd | |||
| 8a44055533 |
+95
-88
@@ -40,11 +40,13 @@ limitations under the License.
|
|||||||
#include <arm_neon.h>
|
#include <arm_neon.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef __SANITIZE_THREAD__
|
||||||
#if defined(__has_feature)
|
#if defined(__has_feature)
|
||||||
#if __has_feature(thread_sanitizer)
|
#if __has_feature(thread_sanitizer)
|
||||||
#define __SANITIZE_THREAD__
|
#define __SANITIZE_THREAD__
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <memcheck.h>
|
#include <memcheck.h>
|
||||||
|
|
||||||
@@ -1123,12 +1125,68 @@ Node *getFirstChildExists(Node *self) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Caller is responsible for assigning a non-null pointer to the returned
|
void consumePartialKeyFull(Node *&self, std::span<const uint8_t> &key,
|
||||||
// reference if null. Updates child's max version to `newMaxVersion` if child
|
InternalVersionT writeVersion, WriteContext *tls) {
|
||||||
// exists but does not have a partial key.
|
// Handle an existing partial key
|
||||||
Node *&getOrCreateChild(Node *&self, uint8_t index,
|
int commonLen = std::min<int>(self->partialKeyLen, key.size());
|
||||||
|
int partialKeyIndex =
|
||||||
|
longestCommonPrefix(self->partialKey(), key.data(), commonLen);
|
||||||
|
if (partialKeyIndex < self->partialKeyLen) {
|
||||||
|
auto *old = self;
|
||||||
|
// Since root cannot have a partial key
|
||||||
|
assert(old->parent != nullptr);
|
||||||
|
InternalVersionT oldMaxVersion = exchangeMaxVersion(old, writeVersion);
|
||||||
|
|
||||||
|
// *self will have one child (old)
|
||||||
|
auto *newSelf = tls->allocate<Node3>(partialKeyIndex);
|
||||||
|
|
||||||
|
newSelf->parent = old->parent;
|
||||||
|
newSelf->parentsIndex = old->parentsIndex;
|
||||||
|
newSelf->partialKeyLen = partialKeyIndex;
|
||||||
|
newSelf->entryPresent = false;
|
||||||
|
newSelf->numChildren = 1;
|
||||||
|
|
||||||
|
memcpy(newSelf->partialKey(), old->partialKey(), newSelf->partialKeyLen);
|
||||||
|
|
||||||
|
uint8_t oldDistinguishingByte = old->partialKey()[partialKeyIndex];
|
||||||
|
old->parent = newSelf;
|
||||||
|
old->parentsIndex = oldDistinguishingByte;
|
||||||
|
newSelf->index[0] = oldDistinguishingByte;
|
||||||
|
newSelf->children[0] = old;
|
||||||
|
newSelf->childMaxVersion[0] = oldMaxVersion;
|
||||||
|
self = newSelf;
|
||||||
|
|
||||||
|
memmove(old->partialKey(), old->partialKey() + partialKeyIndex + 1,
|
||||||
|
old->partialKeyLen - (partialKeyIndex + 1));
|
||||||
|
old->partialKeyLen -= partialKeyIndex + 1;
|
||||||
|
|
||||||
|
// We would consider decreasing capacity here, but we can't invalidate
|
||||||
|
// old since it's not on the search path. setOldestVersion will clean it
|
||||||
|
// up.
|
||||||
|
}
|
||||||
|
key = key.subspan(partialKeyIndex, key.size() - partialKeyIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consume any partial key of `self`, and update `self` and
|
||||||
|
// `key` such that `self` is along the search path of `key`
|
||||||
|
inline __attribute__((always_inline)) void
|
||||||
|
consumePartialKey(Node *&self, std::span<const uint8_t> &key,
|
||||||
|
InternalVersionT writeVersion, WriteContext *tls) {
|
||||||
|
if (self->partialKeyLen > 0) {
|
||||||
|
consumePartialKeyFull(self, key, writeVersion, tls);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the next node along the search path of key, consuming bytes of key
|
||||||
|
// such that the search path of the result + key is the same as the search path
|
||||||
|
// of self + key before the call. Creates a node if necessary. Updates
|
||||||
|
// `maxVersion` for result.
|
||||||
|
Node *&getOrCreateChild(Node *&self, std::span<const uint8_t> &key,
|
||||||
InternalVersionT newMaxVersion, WriteContext *tls) {
|
InternalVersionT newMaxVersion, WriteContext *tls) {
|
||||||
|
|
||||||
|
int index = key.front();
|
||||||
|
key = key.subspan(1, key.size() - 1);
|
||||||
|
|
||||||
// Fast path for if it exists already
|
// Fast path for if it exists already
|
||||||
switch (self->getType()) {
|
switch (self->getType()) {
|
||||||
case Type_Node0:
|
case Type_Node0:
|
||||||
@@ -1137,9 +1195,8 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
|
|||||||
auto *self3 = static_cast<Node3 *>(self);
|
auto *self3 = static_cast<Node3 *>(self);
|
||||||
int i = getNodeIndex(self3, index);
|
int i = getNodeIndex(self3, index);
|
||||||
if (i >= 0) {
|
if (i >= 0) {
|
||||||
if (self3->children[i]->partialKeyLen == 0) {
|
consumePartialKey(self3->children[i], key, newMaxVersion, tls);
|
||||||
self3->childMaxVersion[i] = newMaxVersion;
|
self3->childMaxVersion[i] = newMaxVersion;
|
||||||
}
|
|
||||||
return self3->children[i];
|
return self3->children[i];
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
@@ -1147,9 +1204,8 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
|
|||||||
auto *self16 = static_cast<Node16 *>(self);
|
auto *self16 = static_cast<Node16 *>(self);
|
||||||
int i = getNodeIndex(self16, index);
|
int i = getNodeIndex(self16, index);
|
||||||
if (i >= 0) {
|
if (i >= 0) {
|
||||||
if (self16->children[i]->partialKeyLen == 0) {
|
consumePartialKey(self16->children[i], key, newMaxVersion, tls);
|
||||||
self16->childMaxVersion[i] = newMaxVersion;
|
self16->childMaxVersion[i] = newMaxVersion;
|
||||||
}
|
|
||||||
return self16->children[i];
|
return self16->children[i];
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
@@ -1157,23 +1213,21 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
|
|||||||
auto *self48 = static_cast<Node48 *>(self);
|
auto *self48 = static_cast<Node48 *>(self);
|
||||||
int secondIndex = self48->index[index];
|
int secondIndex = self48->index[index];
|
||||||
if (secondIndex >= 0) {
|
if (secondIndex >= 0) {
|
||||||
if (self48->children[secondIndex]->partialKeyLen == 0) {
|
consumePartialKey(self48->children[secondIndex], key, newMaxVersion, tls);
|
||||||
self48->childMaxVersion[secondIndex] = newMaxVersion;
|
self48->childMaxVersion[secondIndex] = newMaxVersion;
|
||||||
self48->maxOfMax[secondIndex >> Node48::kMaxOfMaxShift] =
|
self48->maxOfMax[secondIndex >> Node48::kMaxOfMaxShift] =
|
||||||
std::max(self48->maxOfMax[secondIndex >> Node48::kMaxOfMaxShift],
|
std::max(self48->maxOfMax[secondIndex >> Node48::kMaxOfMaxShift],
|
||||||
newMaxVersion);
|
newMaxVersion);
|
||||||
}
|
|
||||||
return self48->children[secondIndex];
|
return self48->children[secondIndex];
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case Type_Node256: {
|
case Type_Node256: {
|
||||||
auto *self256 = static_cast<Node256 *>(self);
|
auto *self256 = static_cast<Node256 *>(self);
|
||||||
if (auto &result = self256->children[index]; result != nullptr) {
|
if (auto &result = self256->children[index]; result != nullptr) {
|
||||||
if (self256->children[index]->partialKeyLen == 0) {
|
consumePartialKey(result, key, newMaxVersion, tls);
|
||||||
self256->childMaxVersion[index] = newMaxVersion;
|
self256->childMaxVersion[index] = newMaxVersion;
|
||||||
self256->maxOfMax[index >> Node256::kMaxOfMaxShift] = std::max(
|
self256->maxOfMax[index >> Node256::kMaxOfMaxShift] = std::max(
|
||||||
self256->maxOfMax[index >> Node256::kMaxOfMaxShift], newMaxVersion);
|
self256->maxOfMax[index >> Node256::kMaxOfMaxShift], newMaxVersion);
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
@@ -1181,6 +1235,14 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
|
|||||||
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto *newChild = tls->allocate<Node0>(key.size());
|
||||||
|
newChild->numChildren = 0;
|
||||||
|
newChild->entryPresent = false;
|
||||||
|
newChild->partialKeyLen = key.size();
|
||||||
|
newChild->parentsIndex = index;
|
||||||
|
memcpy(newChild->partialKey(), key.data(), key.size());
|
||||||
|
key = {};
|
||||||
|
|
||||||
switch (self->getType()) {
|
switch (self->getType()) {
|
||||||
case Type_Node0: {
|
case Type_Node0: {
|
||||||
auto *self0 = static_cast<Node0 *>(self);
|
auto *self0 = static_cast<Node0 *>(self);
|
||||||
@@ -1215,8 +1277,10 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
|
|||||||
}
|
}
|
||||||
self3->index[i + 1] = index;
|
self3->index[i + 1] = index;
|
||||||
auto &result = self3->children[i + 1];
|
auto &result = self3->children[i + 1];
|
||||||
result = nullptr;
|
self3->childMaxVersion[i + 1] = newMaxVersion;
|
||||||
|
result = newChild;
|
||||||
++self->numChildren;
|
++self->numChildren;
|
||||||
|
newChild->parent = self;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
case Type_Node16: {
|
case Type_Node16: {
|
||||||
@@ -1243,8 +1307,10 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
|
|||||||
}
|
}
|
||||||
self16->index[i + 1] = index;
|
self16->index[i + 1] = index;
|
||||||
auto &result = self16->children[i + 1];
|
auto &result = self16->children[i + 1];
|
||||||
result = nullptr;
|
self16->childMaxVersion[i + 1] = newMaxVersion;
|
||||||
|
result = newChild;
|
||||||
++self->numChildren;
|
++self->numChildren;
|
||||||
|
newChild->parent = self;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
case Type_Node48: {
|
case Type_Node48: {
|
||||||
@@ -1267,7 +1333,11 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
|
|||||||
self48->index[index] = nextFree;
|
self48->index[index] = nextFree;
|
||||||
self48->reverseIndex[nextFree] = index;
|
self48->reverseIndex[nextFree] = index;
|
||||||
auto &result = self48->children[nextFree];
|
auto &result = self48->children[nextFree];
|
||||||
result = nullptr;
|
self48->childMaxVersion[nextFree] = newMaxVersion;
|
||||||
|
self48->maxOfMax[nextFree >> Node48::kMaxOfMaxShift] = std::max(
|
||||||
|
newMaxVersion, self48->maxOfMax[nextFree >> Node48::kMaxOfMaxShift]);
|
||||||
|
result = newChild;
|
||||||
|
newChild->parent = self;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
case Type_Node256: {
|
case Type_Node256: {
|
||||||
@@ -1276,7 +1346,13 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
|
|||||||
auto *self256 = static_cast<Node256 *>(self);
|
auto *self256 = static_cast<Node256 *>(self);
|
||||||
++self->numChildren;
|
++self->numChildren;
|
||||||
self256->bitSet.set(index);
|
self256->bitSet.set(index);
|
||||||
return self256->children[index];
|
auto &result = self256->children[index];
|
||||||
|
self256->childMaxVersion[index] = newMaxVersion;
|
||||||
|
self256->maxOfMax[index >> Node256::kMaxOfMaxShift] = std::max(
|
||||||
|
newMaxVersion, self256->maxOfMax[index >> Node256::kMaxOfMaxShift]);
|
||||||
|
result = newChild;
|
||||||
|
newChild->parent = self;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
default: // GCOVR_EXCL_LINE
|
default: // GCOVR_EXCL_LINE
|
||||||
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
||||||
@@ -2716,51 +2792,6 @@ checkMaxBetweenExclusiveImpl<true>(Node *n, int begin, int end,
|
|||||||
InternalVersionT readVersion, ReadContext *);
|
InternalVersionT readVersion, ReadContext *);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Consume the partial key of `self` (which must exist), and update `self` and
|
|
||||||
// `key` such that `self` is along the search path of `key`
|
|
||||||
void consumePartialKey(Node *&self, std::span<const uint8_t> &key,
|
|
||||||
InternalVersionT writeVersion, WriteContext *tls) {
|
|
||||||
assert(self->partialKeyLen > 0);
|
|
||||||
// Handle an existing partial key
|
|
||||||
int commonLen = std::min<int>(self->partialKeyLen, key.size());
|
|
||||||
int partialKeyIndex =
|
|
||||||
longestCommonPrefix(self->partialKey(), key.data(), commonLen);
|
|
||||||
if (partialKeyIndex < self->partialKeyLen) {
|
|
||||||
auto *old = self;
|
|
||||||
// Since root cannot have a partial key
|
|
||||||
assert(old->parent != nullptr);
|
|
||||||
InternalVersionT oldMaxVersion = exchangeMaxVersion(old, writeVersion);
|
|
||||||
|
|
||||||
// *self will have one child (old)
|
|
||||||
auto *newSelf = tls->allocate<Node3>(partialKeyIndex);
|
|
||||||
|
|
||||||
newSelf->parent = old->parent;
|
|
||||||
newSelf->parentsIndex = old->parentsIndex;
|
|
||||||
newSelf->partialKeyLen = partialKeyIndex;
|
|
||||||
newSelf->entryPresent = false;
|
|
||||||
newSelf->numChildren = 1;
|
|
||||||
|
|
||||||
memcpy(newSelf->partialKey(), old->partialKey(), newSelf->partialKeyLen);
|
|
||||||
|
|
||||||
uint8_t oldDistinguishingByte = old->partialKey()[partialKeyIndex];
|
|
||||||
old->parent = newSelf;
|
|
||||||
old->parentsIndex = oldDistinguishingByte;
|
|
||||||
newSelf->index[0] = oldDistinguishingByte;
|
|
||||||
newSelf->children[0] = old;
|
|
||||||
newSelf->childMaxVersion[0] = oldMaxVersion;
|
|
||||||
self = newSelf;
|
|
||||||
|
|
||||||
memmove(old->partialKey(), old->partialKey() + partialKeyIndex + 1,
|
|
||||||
old->partialKeyLen - (partialKeyIndex + 1));
|
|
||||||
old->partialKeyLen -= partialKeyIndex + 1;
|
|
||||||
|
|
||||||
// We would consider decreasing capacity here, but we can't invalidate
|
|
||||||
// old since it's not on the search path. setOldestVersion will clean it
|
|
||||||
// up.
|
|
||||||
}
|
|
||||||
key = key.subspan(partialKeyIndex, key.size() - partialKeyIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns a pointer the pointer to the newly inserted node in the tree. Caller
|
// Returns a pointer the pointer to the newly inserted node in the tree. Caller
|
||||||
// must set `entryPresent`, and `entry` fields. All nodes along the search path
|
// must set `entryPresent`, and `entry` fields. All nodes along the search path
|
||||||
// of the result will have `maxVersion` set to `writeVersion` as a
|
// of the result will have `maxVersion` set to `writeVersion` as a
|
||||||
@@ -2773,34 +2804,10 @@ Node **insert(Node **self, std::span<const uint8_t> key,
|
|||||||
assert(maxVersion(*self, impl) <= writeVersion);
|
assert(maxVersion(*self, impl) <= writeVersion);
|
||||||
setMaxVersion(*self, impl, writeVersion);
|
setMaxVersion(*self, impl, writeVersion);
|
||||||
|
|
||||||
for (;; ++tls->accum.insert_iterations) {
|
for (; key.size() != 0; ++tls->accum.insert_iterations) {
|
||||||
|
self = &getOrCreateChild(*self, key, writeVersion, tls);
|
||||||
if (key.size() == 0) {
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
|
||||||
|
|
||||||
auto &child = getOrCreateChild(*self, key.front(), writeVersion, tls);
|
|
||||||
if (!child) {
|
|
||||||
child = tls->allocate<Node0>(key.size() - 1);
|
|
||||||
child->numChildren = 0;
|
|
||||||
child->entryPresent = false;
|
|
||||||
child->partialKeyLen = key.size() - 1;
|
|
||||||
child->parent = *self;
|
|
||||||
child->parentsIndex = key.front();
|
|
||||||
setMaxVersion(child, impl, writeVersion);
|
|
||||||
memcpy(child->partialKey(), key.data() + 1, child->partialKeyLen);
|
|
||||||
return &child;
|
|
||||||
}
|
|
||||||
|
|
||||||
self = &child;
|
|
||||||
key = key.subspan(1, key.size() - 1);
|
|
||||||
|
|
||||||
if ((*self)->partialKeyLen > 0) {
|
|
||||||
consumePartialKey(*self, key, writeVersion, tls);
|
|
||||||
assert(maxVersion(*self, impl) <= writeVersion);
|
|
||||||
setMaxVersion(*self, impl, writeVersion);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroyTree(Node *root) {
|
void destroyTree(Node *root) {
|
||||||
|
|||||||
@@ -11,6 +11,14 @@
|
|||||||
#include <arm_neon.h>
|
#include <arm_neon.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef __SANITIZE_THREAD__
|
||||||
|
#if defined(__has_feature)
|
||||||
|
#if __has_feature(thread_sanitizer)
|
||||||
|
#define __SANITIZE_THREAD__
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(HAS_AVX) || defined(HAS_ARM_NEON)
|
#if defined(HAS_AVX) || defined(HAS_ARM_NEON)
|
||||||
constexpr int kStride = 64;
|
constexpr int kStride = 64;
|
||||||
#else
|
#else
|
||||||
@@ -117,7 +125,7 @@ __attribute__((target("default")))
|
|||||||
inline int
|
inline int
|
||||||
longestCommonPrefix(const uint8_t *ap, const uint8_t *bp, int cl) {
|
longestCommonPrefix(const uint8_t *ap, const uint8_t *bp, int cl) {
|
||||||
if (!(cl >= 0)) {
|
if (!(cl >= 0)) {
|
||||||
__builtin_unreachable();
|
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
||||||
}
|
}
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
|||||||
|
n滑滑滑滑2nn��ム
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user