9 Commits

Author SHA1 Message Date
479b39d055 Add to corpus
Some checks reported errors
Tests / Clang total: 2264, passed: 2264
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Debug total: 2262, passed: 2262
Tests / SIMD fallback total: 2264, passed: 2264
Tests / Release [gcc] total: 2264, passed: 2264
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 1690, passed: 1690
Tests / Coverage total: 1700, passed: 1700
Code Coverage #### Project Overview No changes detected, that affect the code coverage. * Line Coverage: 99.34% (1809/1821) * Branch Coverage: 67.61% (1476/2183) * Complexity Density: 0.00 * Lines of Code: 1821 #### Quality Gates Summary Output truncated.
weaselab/conflict-set/pipeline/head Something is wrong with the build of this commit
2024-08-12 17:28:19 -07:00
482408d725 Add GCOVR_EXCL_LINE to __builtin_unreachable 2024-08-12 17:07:55 -07:00
45995e3307 Update comments 2024-08-12 17:05:21 -07:00
359b0b29ff Avoid function call if no partial key 2024-08-12 16:33:03 -07:00
54e47ebd40 Simplify insert loop 2024-08-12 16:25:12 -07:00
1c9dda68a6 Call consumePartialKey from getOrCreateChild 2024-08-12 16:24:05 -07:00
142455dd28 Move consumePartialKey, and allow empty partial key 2024-08-12 16:18:58 -07:00
567d385fbd WIP create child in getOrCreateChild 2024-08-12 16:11:16 -07:00
8a44055533 Consume first byte in insert iteration 2024-08-12 15:39:09 -07:00
44 changed files with 114 additions and 98 deletions

View File

@@ -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) {
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) {
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) {
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) {
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,36 +2804,12 @@ 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) {
for (; key.size() != 0; ++tls->accum.insert_iterations) {
self = &getOrCreateChild(*self, key, writeVersion, tls);
}
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) {
Arena arena;
auto toFree = vector<Node *>(arena);

View File

@@ -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.

View File

@@ -0,0 +1 @@
n<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2nn<EFBFBD><EFBFBD><EFBFBD>

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.