Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 479b39d055 | |||
| 482408d725 | |||
| 45995e3307 | |||
| 359b0b29ff | |||
| 54e47ebd40 | |||
| 1c9dda68a6 | |||
| 142455dd28 | |||
| 567d385fbd | |||
| 8a44055533 |
+104
-97
@@ -40,11 +40,13 @@ limitations under the License.
|
||||
#include <arm_neon.h>
|
||||
#endif
|
||||
|
||||
#ifndef __SANITIZE_THREAD__
|
||||
#if defined(__has_feature)
|
||||
#if __has_feature(thread_sanitizer)
|
||||
#define __SANITIZE_THREAD__
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <memcheck.h>
|
||||
|
||||
@@ -1123,12 +1125,68 @@ Node *getFirstChildExists(Node *self) {
|
||||
}
|
||||
}
|
||||
|
||||
// Caller is responsible for assigning a non-null pointer to the returned
|
||||
// reference if null. Updates child's max version to `newMaxVersion` if child
|
||||
// exists but does not have a partial key.
|
||||
Node *&getOrCreateChild(Node *&self, uint8_t index,
|
||||
void consumePartialKeyFull(Node *&self, std::span<const uint8_t> &key,
|
||||
InternalVersionT writeVersion, WriteContext *tls) {
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
||||
int index = key.front();
|
||||
key = key.subspan(1, key.size() - 1);
|
||||
|
||||
// Fast path for if it exists already
|
||||
switch (self->getType()) {
|
||||
case Type_Node0:
|
||||
@@ -1137,9 +1195,8 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
|
||||
auto *self3 = static_cast<Node3 *>(self);
|
||||
int i = getNodeIndex(self3, index);
|
||||
if (i >= 0) {
|
||||
if (self3->children[i]->partialKeyLen == 0) {
|
||||
self3->childMaxVersion[i] = newMaxVersion;
|
||||
}
|
||||
consumePartialKey(self3->children[i], key, newMaxVersion, tls);
|
||||
self3->childMaxVersion[i] = newMaxVersion;
|
||||
return self3->children[i];
|
||||
}
|
||||
} break;
|
||||
@@ -1147,9 +1204,8 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
|
||||
auto *self16 = static_cast<Node16 *>(self);
|
||||
int i = getNodeIndex(self16, index);
|
||||
if (i >= 0) {
|
||||
if (self16->children[i]->partialKeyLen == 0) {
|
||||
self16->childMaxVersion[i] = newMaxVersion;
|
||||
}
|
||||
consumePartialKey(self16->children[i], key, newMaxVersion, tls);
|
||||
self16->childMaxVersion[i] = newMaxVersion;
|
||||
return self16->children[i];
|
||||
}
|
||||
} break;
|
||||
@@ -1157,23 +1213,21 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
|
||||
auto *self48 = static_cast<Node48 *>(self);
|
||||
int secondIndex = self48->index[index];
|
||||
if (secondIndex >= 0) {
|
||||
if (self48->children[secondIndex]->partialKeyLen == 0) {
|
||||
self48->childMaxVersion[secondIndex] = newMaxVersion;
|
||||
self48->maxOfMax[secondIndex >> Node48::kMaxOfMaxShift] =
|
||||
std::max(self48->maxOfMax[secondIndex >> Node48::kMaxOfMaxShift],
|
||||
newMaxVersion);
|
||||
}
|
||||
consumePartialKey(self48->children[secondIndex], key, newMaxVersion, tls);
|
||||
self48->childMaxVersion[secondIndex] = newMaxVersion;
|
||||
self48->maxOfMax[secondIndex >> Node48::kMaxOfMaxShift] =
|
||||
std::max(self48->maxOfMax[secondIndex >> Node48::kMaxOfMaxShift],
|
||||
newMaxVersion);
|
||||
return self48->children[secondIndex];
|
||||
}
|
||||
} break;
|
||||
case Type_Node256: {
|
||||
auto *self256 = static_cast<Node256 *>(self);
|
||||
if (auto &result = self256->children[index]; result != nullptr) {
|
||||
if (self256->children[index]->partialKeyLen == 0) {
|
||||
self256->childMaxVersion[index] = newMaxVersion;
|
||||
self256->maxOfMax[index >> Node256::kMaxOfMaxShift] = std::max(
|
||||
self256->maxOfMax[index >> Node256::kMaxOfMaxShift], newMaxVersion);
|
||||
}
|
||||
consumePartialKey(result, key, newMaxVersion, tls);
|
||||
self256->childMaxVersion[index] = newMaxVersion;
|
||||
self256->maxOfMax[index >> Node256::kMaxOfMaxShift] = std::max(
|
||||
self256->maxOfMax[index >> Node256::kMaxOfMaxShift], newMaxVersion);
|
||||
return result;
|
||||
}
|
||||
} break;
|
||||
@@ -1181,6 +1235,14 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
|
||||
__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()) {
|
||||
case Type_Node0: {
|
||||
auto *self0 = static_cast<Node0 *>(self);
|
||||
@@ -1215,8 +1277,10 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
|
||||
}
|
||||
self3->index[i + 1] = index;
|
||||
auto &result = self3->children[i + 1];
|
||||
result = nullptr;
|
||||
self3->childMaxVersion[i + 1] = newMaxVersion;
|
||||
result = newChild;
|
||||
++self->numChildren;
|
||||
newChild->parent = self;
|
||||
return result;
|
||||
}
|
||||
case Type_Node16: {
|
||||
@@ -1243,8 +1307,10 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
|
||||
}
|
||||
self16->index[i + 1] = index;
|
||||
auto &result = self16->children[i + 1];
|
||||
result = nullptr;
|
||||
self16->childMaxVersion[i + 1] = newMaxVersion;
|
||||
result = newChild;
|
||||
++self->numChildren;
|
||||
newChild->parent = self;
|
||||
return result;
|
||||
}
|
||||
case Type_Node48: {
|
||||
@@ -1267,7 +1333,11 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
|
||||
self48->index[index] = nextFree;
|
||||
self48->reverseIndex[nextFree] = index;
|
||||
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;
|
||||
}
|
||||
case Type_Node256: {
|
||||
@@ -1276,7 +1346,13 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
|
||||
auto *self256 = static_cast<Node256 *>(self);
|
||||
++self->numChildren;
|
||||
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
|
||||
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
||||
@@ -2716,51 +2792,6 @@ checkMaxBetweenExclusiveImpl<true>(Node *n, int begin, int end,
|
||||
InternalVersionT readVersion, ReadContext *);
|
||||
#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
|
||||
// must set `entryPresent`, and `entry` fields. All nodes along the search path
|
||||
// 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);
|
||||
setMaxVersion(*self, impl, writeVersion);
|
||||
|
||||
for (;; ++tls->accum.insert_iterations) {
|
||||
|
||||
if (key.size() == 0) {
|
||||
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);
|
||||
}
|
||||
for (; key.size() != 0; ++tls->accum.insert_iterations) {
|
||||
self = &getOrCreateChild(*self, key, writeVersion, tls);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
void destroyTree(Node *root) {
|
||||
|
||||
@@ -11,6 +11,14 @@
|
||||
#include <arm_neon.h>
|
||||
#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)
|
||||
constexpr int kStride = 64;
|
||||
#else
|
||||
@@ -117,7 +125,7 @@ __attribute__((target("default")))
|
||||
inline int
|
||||
longestCommonPrefix(const uint8_t *ap, const uint8_t *bp, int cl) {
|
||||
if (!(cl >= 0)) {
|
||||
__builtin_unreachable();
|
||||
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
||||
}
|
||||
|
||||
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