Compare commits
9 Commits
0a850f22e9
...
359f6f0042
Author | SHA1 | Date | |
---|---|---|---|
359f6f0042 | |||
aa8504ddba | |||
fb7cf18f9b | |||
b808b97940 | |||
e480f66846 | |||
d5bc9221a0 | |||
9d23b81d6f | |||
0740dcad43 | |||
176df61321 |
475
ConflictSet.cpp
475
ConflictSet.cpp
@@ -524,6 +524,8 @@ std::string getSearchPath(Node *n);
|
||||
// Induction hypothesis is that each node's surplus is >= kMinNodeSurplus
|
||||
constexpr int kBytesPerKey = 112;
|
||||
constexpr int kMinNodeSurplus = 80;
|
||||
// Cound the entry itself as a child
|
||||
constexpr int kMinChildrenNode0 = 1;
|
||||
constexpr int kMinChildrenNode3 = 2;
|
||||
constexpr int kMinChildrenNode16 = 4;
|
||||
constexpr int kMinChildrenNode48 = 17;
|
||||
@@ -903,10 +905,115 @@ Node *&getChildExists(Node *self, uint8_t index) {
|
||||
}
|
||||
}
|
||||
|
||||
InternalVersionT maxVersion(Node *n, ConflictSet::Impl *);
|
||||
InternalVersionT exchangeMaxVersion(Node *n, InternalVersionT newMax);
|
||||
// Precondition `n` is not the root
|
||||
InternalVersionT maxVersion(Node *n) {
|
||||
int index = n->parentsIndex;
|
||||
n = n->parent;
|
||||
assert(n != nullptr);
|
||||
switch (n->getType()) {
|
||||
case Type_Node0: // GCOVR_EXCL_LINE
|
||||
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
||||
case Type_Node3: {
|
||||
auto *n3 = static_cast<Node3 *>(n);
|
||||
int i = getNodeIndex(n3, index);
|
||||
return n3->childMaxVersion[i];
|
||||
}
|
||||
case Type_Node16: {
|
||||
auto *n16 = static_cast<Node16 *>(n);
|
||||
int i = getNodeIndex(n16, index);
|
||||
return n16->childMaxVersion[i];
|
||||
}
|
||||
case Type_Node48: {
|
||||
auto *n48 = static_cast<Node48 *>(n);
|
||||
assert(n48->bitSet.test(index));
|
||||
return n48->childMaxVersion[n48->index[index]];
|
||||
}
|
||||
case Type_Node256: {
|
||||
auto *n256 = static_cast<Node256 *>(n);
|
||||
assert(n256->bitSet.test(index));
|
||||
return n256->childMaxVersion[index];
|
||||
}
|
||||
default: // GCOVR_EXCL_LINE
|
||||
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
||||
}
|
||||
}
|
||||
|
||||
void setMaxVersion(Node *n, ConflictSet::Impl *, InternalVersionT maxVersion);
|
||||
// Precondition `n` is not the root
|
||||
InternalVersionT exchangeMaxVersion(Node *n, InternalVersionT newMax) {
|
||||
int index = n->parentsIndex;
|
||||
n = n->parent;
|
||||
assert(n != nullptr);
|
||||
switch (n->getType()) {
|
||||
case Type_Node0: // GCOVR_EXCL_LINE
|
||||
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
||||
case Type_Node3: {
|
||||
auto *n3 = static_cast<Node3 *>(n);
|
||||
int i = getNodeIndex(n3, index);
|
||||
return std::exchange(n3->childMaxVersion[i], newMax);
|
||||
}
|
||||
case Type_Node16: {
|
||||
auto *n16 = static_cast<Node16 *>(n);
|
||||
int i = getNodeIndex(n16, index);
|
||||
return std::exchange(n16->childMaxVersion[i], newMax);
|
||||
}
|
||||
case Type_Node48: {
|
||||
auto *n48 = static_cast<Node48 *>(n);
|
||||
assert(n48->bitSet.test(index));
|
||||
return std::exchange(n48->childMaxVersion[n48->index[index]], newMax);
|
||||
}
|
||||
case Type_Node256: {
|
||||
auto *n256 = static_cast<Node256 *>(n);
|
||||
assert(n256->bitSet.test(index));
|
||||
return std::exchange(n256->childMaxVersion[index], newMax);
|
||||
}
|
||||
default: // GCOVR_EXCL_LINE
|
||||
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
||||
}
|
||||
}
|
||||
|
||||
// Precondition `n` is not the root
|
||||
void setMaxVersion(Node *n, InternalVersionT newMax) {
|
||||
assert(newMax >= InternalVersionT::zero);
|
||||
int index = n->parentsIndex;
|
||||
n = n->parent;
|
||||
assert(n != nullptr);
|
||||
switch (n->getType()) {
|
||||
case Type_Node0: // GCOVR_EXCL_LINE
|
||||
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
||||
case Type_Node3: {
|
||||
auto *n3 = static_cast<Node3 *>(n);
|
||||
int i = getNodeIndex(n3, index);
|
||||
n3->childMaxVersion[i] = newMax;
|
||||
return;
|
||||
}
|
||||
case Type_Node16: {
|
||||
auto *n16 = static_cast<Node16 *>(n);
|
||||
int i = getNodeIndex(n16, index);
|
||||
n16->childMaxVersion[i] = newMax;
|
||||
return;
|
||||
}
|
||||
case Type_Node48: {
|
||||
auto *n48 = static_cast<Node48 *>(n);
|
||||
assert(n48->bitSet.test(index));
|
||||
int i = n48->index[index];
|
||||
n48->childMaxVersion[i] = newMax;
|
||||
n48->maxOfMax[i >> Node48::kMaxOfMaxShift] = std::max<InternalVersionT>(
|
||||
n48->maxOfMax[i >> Node48::kMaxOfMaxShift], newMax);
|
||||
return;
|
||||
}
|
||||
case Type_Node256: {
|
||||
auto *n256 = static_cast<Node256 *>(n);
|
||||
assert(n256->bitSet.test(index));
|
||||
n256->childMaxVersion[index] = newMax;
|
||||
n256->maxOfMax[index >> Node256::kMaxOfMaxShift] =
|
||||
std::max<InternalVersionT>(
|
||||
n256->maxOfMax[index >> Node256::kMaxOfMaxShift], newMax);
|
||||
return;
|
||||
}
|
||||
default: // GCOVR_EXCL_LINE
|
||||
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
||||
}
|
||||
}
|
||||
|
||||
Node *&getInTree(Node *n, ConflictSet::Impl *);
|
||||
|
||||
@@ -1542,6 +1649,47 @@ void rezero(Node *n, InternalVersionT z) {
|
||||
}
|
||||
}
|
||||
|
||||
void mergeWithChild(Node *&self, WriteContext *tls, ConflictSet::Impl *impl,
|
||||
Node *&dontInvalidate, Node3 *self3) {
|
||||
assert(!self3->entryPresent);
|
||||
auto *child = self3->children[0];
|
||||
int minCapacity = self3->partialKeyLen + 1 + child->partialKeyLen;
|
||||
|
||||
if (minCapacity > child->getCapacity()) {
|
||||
const bool update = child == dontInvalidate;
|
||||
freeAndMakeCapacityAtLeast(child, minCapacity, tls, impl, true);
|
||||
if (update) {
|
||||
dontInvalidate = child;
|
||||
}
|
||||
}
|
||||
|
||||
// Merge partial key with child
|
||||
#if DEBUG_VERBOSE && !defined(NDEBUG)
|
||||
fprintf(stderr, "Merge %s into %s\n", getSearchPathPrintable(self).c_str(),
|
||||
getSearchPathPrintable(child).c_str());
|
||||
#endif
|
||||
|
||||
InternalVersionT childMaxVersion = self3->childMaxVersion[0];
|
||||
|
||||
// Construct new partial key for child
|
||||
memmove(child->partialKey() + self3->partialKeyLen + 1, child->partialKey(),
|
||||
child->partialKeyLen);
|
||||
memcpy(child->partialKey(), self3->partialKey(), self->partialKeyLen);
|
||||
child->partialKey()[self3->partialKeyLen] = self3->index[0];
|
||||
child->partialKeyLen += 1 + self3->partialKeyLen;
|
||||
|
||||
child->parent = self->parent;
|
||||
child->parentsIndex = self->parentsIndex;
|
||||
|
||||
// Max versions are stored in the parent, so we need to update it now
|
||||
// that we have a new parent. Safe we call since the root never has a partial
|
||||
// key.
|
||||
setMaxVersion(child, std::max(childMaxVersion, tls->zero));
|
||||
|
||||
self = child;
|
||||
tls->release(self3);
|
||||
}
|
||||
|
||||
void maybeDownsize(Node *self, WriteContext *tls, ConflictSet::Impl *impl,
|
||||
Node *&dontInvalidate) {
|
||||
|
||||
@@ -1560,45 +1708,7 @@ void maybeDownsize(Node *self, WriteContext *tls, ConflictSet::Impl *impl,
|
||||
getInTree(self, impl) = newSelf;
|
||||
tls->release(self3);
|
||||
} else if (self->numChildren == 1 && !self->entryPresent) {
|
||||
auto *child = self3->children[0];
|
||||
int minCapacity = self3->partialKeyLen + 1 + child->partialKeyLen;
|
||||
|
||||
if (minCapacity > child->getCapacity()) {
|
||||
const bool update = child == dontInvalidate;
|
||||
freeAndMakeCapacityAtLeast(child, minCapacity, tls, impl, true);
|
||||
if (update) {
|
||||
dontInvalidate = child;
|
||||
}
|
||||
}
|
||||
|
||||
// Merge partial key with child
|
||||
#if DEBUG_VERBOSE && !defined(NDEBUG)
|
||||
fprintf(stderr, "Merge %s into %s\n",
|
||||
getSearchPathPrintable(self).c_str(),
|
||||
getSearchPathPrintable(child).c_str());
|
||||
#endif
|
||||
|
||||
InternalVersionT childMaxVersion = maxVersion(child, impl);
|
||||
|
||||
// Construct new partial key for child
|
||||
memmove(child->partialKey() + self3->partialKeyLen + 1,
|
||||
child->partialKey(), child->partialKeyLen);
|
||||
memcpy(child->partialKey(), self3->partialKey(), self->partialKeyLen);
|
||||
child->partialKey()[self3->partialKeyLen] = self3->index[0];
|
||||
child->partialKeyLen += 1 + self3->partialKeyLen;
|
||||
|
||||
child->parent = self->parent;
|
||||
child->parentsIndex = self->parentsIndex;
|
||||
|
||||
// Max versions are stored in the parent, so we need to update it now
|
||||
// that we have a new parent.
|
||||
setMaxVersion(child, impl, childMaxVersion);
|
||||
if (child->parent) {
|
||||
rezero(child->parent, tls->zero);
|
||||
}
|
||||
|
||||
getInTree(self, impl) = child;
|
||||
tls->release(self3);
|
||||
mergeWithChild(getInTree(self, impl), tls, impl, dontInvalidate, self3);
|
||||
}
|
||||
} break;
|
||||
case Type_Node16:
|
||||
@@ -1846,10 +1956,10 @@ bool checkPrefixRead(Node *n, const std::span<const uint8_t> key,
|
||||
fprintf(stderr, "Check prefix read: %s\n", printable(key).c_str());
|
||||
#endif
|
||||
auto remaining = key;
|
||||
auto *impl = tls->impl;
|
||||
for (;; ++tls->prefix_read_iterations_accum) {
|
||||
if (remaining.size() == 0) {
|
||||
return maxVersion(n, impl) <= readVersion;
|
||||
// There's no way to encode a prefix read of "", so n is not the root
|
||||
return maxVersion(n) <= readVersion;
|
||||
}
|
||||
|
||||
auto [child, maxV] = getChildAndMaxVersion(n, remaining[0]);
|
||||
@@ -1892,7 +2002,7 @@ bool checkPrefixRead(Node *n, const std::span<const uint8_t> key,
|
||||
// n is the first physical node greater than remaining, and there's no
|
||||
// eq node. All physical nodes that start with prefix are reachable from
|
||||
// n.
|
||||
if (maxVersion(n, impl) > readVersion) {
|
||||
if (maxVersion(n) > readVersion) {
|
||||
return false;
|
||||
}
|
||||
goto downLeftSpine;
|
||||
@@ -2371,7 +2481,6 @@ bool checkRangeStartsWith(Node *n, std::span<const uint8_t> key, int begin,
|
||||
fprintf(stderr, "%s(%02x,%02x)*\n", printable(key).c_str(), begin, end);
|
||||
#endif
|
||||
auto remaining = key;
|
||||
auto *impl = tls->impl;
|
||||
if (remaining.size() == 0) {
|
||||
return checkMaxBetweenExclusive(n, begin, end, readVersion, tls);
|
||||
}
|
||||
@@ -2416,7 +2525,7 @@ bool checkRangeStartsWith(Node *n, std::span<const uint8_t> key, int begin,
|
||||
if (n->entryPresent && n->entry.rangeVersion > readVersion) {
|
||||
return false;
|
||||
}
|
||||
return maxVersion(n, impl) <= readVersion;
|
||||
return maxVersion(n) <= readVersion;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -2456,7 +2565,7 @@ struct CheckRangeLeftSide {
|
||||
bool step() {
|
||||
if (remaining.size() == 0) {
|
||||
assert(searchPathLen >= prefixLen);
|
||||
ok = maxVersion(n, impl) <= readVersion;
|
||||
ok = maxVersion(n) <= readVersion;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2476,7 +2585,7 @@ struct CheckRangeLeftSide {
|
||||
return downLeftSpine();
|
||||
}
|
||||
n = c;
|
||||
ok = maxVersion(n, impl) <= readVersion;
|
||||
ok = maxVersion(n) <= readVersion;
|
||||
return true;
|
||||
} else {
|
||||
n = nextSibling(n);
|
||||
@@ -2506,7 +2615,7 @@ struct CheckRangeLeftSide {
|
||||
ok = false;
|
||||
return true;
|
||||
}
|
||||
ok = maxVersion(n, impl) <= readVersion;
|
||||
ok = maxVersion(n) <= readVersion;
|
||||
return true;
|
||||
} else {
|
||||
n = nextSibling(n);
|
||||
@@ -2526,7 +2635,7 @@ struct CheckRangeLeftSide {
|
||||
ok = false;
|
||||
return true;
|
||||
}
|
||||
ok = maxVersion(n, impl) <= readVersion;
|
||||
ok = maxVersion(n) <= readVersion;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -2647,7 +2756,8 @@ struct CheckRangeRightSide {
|
||||
|
||||
bool backtrack() {
|
||||
for (;;) {
|
||||
if (searchPathLen > prefixLen && maxVersion(n, impl) > readVersion) {
|
||||
// searchPathLen > prefixLen implies n is not the root
|
||||
if (searchPathLen > prefixLen && maxVersion(n) > readVersion) {
|
||||
ok = false;
|
||||
return true;
|
||||
}
|
||||
@@ -2748,6 +2858,9 @@ bool checkRangeRead(Node *n, std::span<const uint8_t> begin,
|
||||
return false;
|
||||
}
|
||||
|
||||
// This makes it safe to check maxVersion within CheckRangeLeftSide. If this
|
||||
// were false, then we would have returned above since lcp == begin.size().
|
||||
assert(!(n->parent == nullptr && begin.size() == 0));
|
||||
CheckRangeLeftSide checkRangeLeftSide{n, begin, lcp + 1, readVersion, tls};
|
||||
CheckRangeRightSide checkRangeRightSide{n, end, lcp + 1, readVersion, tls};
|
||||
|
||||
@@ -2795,14 +2908,11 @@ checkMaxBetweenExclusiveImpl<true>(Node *n, int begin, int end,
|
||||
// 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
|
||||
// postcondition. Nodes along the search path may be invalidated.
|
||||
// postcondition. Nodes along the search path may be invalidated. Callers must
|
||||
// ensure that the max version of the self argument is updated.
|
||||
[[nodiscard]]
|
||||
Node **insert(Node **self, std::span<const uint8_t> key,
|
||||
InternalVersionT writeVersion, WriteContext *tls,
|
||||
ConflictSet::Impl *impl) {
|
||||
|
||||
assert(maxVersion(*self, impl) <= writeVersion);
|
||||
setMaxVersion(*self, impl, writeVersion);
|
||||
InternalVersionT writeVersion, WriteContext *tls) {
|
||||
|
||||
for (; key.size() != 0; ++tls->accum.insert_iterations) {
|
||||
self = &getOrCreateChild(*self, key, writeVersion, tls);
|
||||
@@ -2810,36 +2920,57 @@ Node **insert(Node **self, std::span<const uint8_t> key,
|
||||
return self;
|
||||
}
|
||||
|
||||
void destroyTree(Node *root) {
|
||||
void eraseTree(Node *root, WriteContext *tls) {
|
||||
Arena arena;
|
||||
auto toFree = vector<Node *>(arena);
|
||||
toFree.push_back(root);
|
||||
|
||||
#if SHOW_MEMORY
|
||||
for (auto *iter = root; iter != nullptr; iter = nextPhysical(iter)) {
|
||||
removeNode(iter);
|
||||
removeKey(iter);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (toFree.size() > 0) {
|
||||
auto *n = toFree.back();
|
||||
toFree.pop_back();
|
||||
// Add all children to toFree
|
||||
for (auto c = getChildGeq(n, 0); c != nullptr;
|
||||
c = getChildGeq(n, c->parentsIndex + 1)) {
|
||||
assert(c != nullptr);
|
||||
toFree.push_back(c);
|
||||
tls->accum.entries_erased += n->entryPresent;
|
||||
++tls->accum.nodes_released;
|
||||
|
||||
removeNode(n);
|
||||
removeKey(n);
|
||||
|
||||
switch (n->getType()) {
|
||||
case Type_Node0: {
|
||||
auto *n0 = static_cast<Node0 *>(n);
|
||||
tls->release(n0);
|
||||
} break;
|
||||
case Type_Node3: {
|
||||
auto *n3 = static_cast<Node3 *>(n);
|
||||
toFree.append(std::span<Node *>(n3->children, n3->numChildren));
|
||||
tls->release(n3);
|
||||
} break;
|
||||
case Type_Node16: {
|
||||
auto *n16 = static_cast<Node16 *>(n);
|
||||
toFree.append(std::span<Node *>(n16->children, n16->numChildren));
|
||||
tls->release(n16);
|
||||
} break;
|
||||
case Type_Node48: {
|
||||
auto *n48 = static_cast<Node48 *>(n);
|
||||
toFree.append(std::span<Node *>(n48->children, n48->numChildren));
|
||||
tls->release(n48);
|
||||
} break;
|
||||
case Type_Node256: {
|
||||
auto *n256 = static_cast<Node256 *>(n);
|
||||
auto *out = toFree.unsafePrepareAppend(n256->numChildren).data();
|
||||
n256->bitSet.forEachSet([&](int i) { *out++ = n256->children[i]; });
|
||||
assert(out == toFree.end());
|
||||
tls->release(n256);
|
||||
} break;
|
||||
default: // GCOVR_EXCL_LINE
|
||||
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
||||
}
|
||||
safe_free(n, n->size());
|
||||
}
|
||||
}
|
||||
|
||||
void addPointWrite(Node *&root, std::span<const uint8_t> key,
|
||||
InternalVersionT writeVersion, WriteContext *tls,
|
||||
ConflictSet::Impl *impl) {
|
||||
InternalVersionT writeVersion, WriteContext *tls) {
|
||||
++tls->accum.point_writes;
|
||||
auto *n = *insert(&root, key, writeVersion, tls, impl);
|
||||
auto *n = *insert(&root, key, writeVersion, tls);
|
||||
if (!n->entryPresent) {
|
||||
++tls->accum.entries_inserted;
|
||||
auto *p = nextLogical(n);
|
||||
@@ -2856,8 +2987,9 @@ void addPointWrite(Node *&root, std::span<const uint8_t> key,
|
||||
}
|
||||
}
|
||||
|
||||
// Precondition: `node->entryPresent`
|
||||
void fixupMaxVersion(Node *node, ConflictSet::Impl *impl, WriteContext *tls) {
|
||||
// Precondition: `node->entryPresent`, and node is not the root
|
||||
void fixupMaxVersion(Node *node, WriteContext *tls) {
|
||||
assert(node->parent);
|
||||
InternalVersionT max;
|
||||
assert(node->entryPresent);
|
||||
max = std::max(node->entry.pointVersion, tls->zero);
|
||||
@@ -2891,7 +3023,7 @@ void fixupMaxVersion(Node *node, ConflictSet::Impl *impl, WriteContext *tls) {
|
||||
default: // GCOVR_EXCL_LINE
|
||||
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
||||
}
|
||||
setMaxVersion(node, impl, max);
|
||||
setMaxVersion(node, max);
|
||||
}
|
||||
|
||||
void addWriteRange(Node *&root, std::span<const uint8_t> begin,
|
||||
@@ -2902,64 +3034,50 @@ void addWriteRange(Node *&root, std::span<const uint8_t> begin,
|
||||
std::min(begin.size(), end.size()));
|
||||
if (lcp == int(begin.size()) && end.size() == begin.size() + 1 &&
|
||||
end.back() == 0) {
|
||||
return addPointWrite(root, begin, writeVersion, tls, impl);
|
||||
return addPointWrite(root, begin, writeVersion, tls);
|
||||
}
|
||||
++tls->accum.range_writes;
|
||||
const bool beginIsPrefix = lcp == int(begin.size());
|
||||
|
||||
Node **useAsRoot =
|
||||
insert(&root, begin.subspan(0, lcp), writeVersion, tls, impl);
|
||||
Node **useAsRoot = insert(&root, begin.subspan(0, lcp), writeVersion, tls);
|
||||
|
||||
int consumed = lcp;
|
||||
|
||||
begin = begin.subspan(consumed, begin.size() - consumed);
|
||||
end = end.subspan(consumed, end.size() - consumed);
|
||||
|
||||
auto *beginNode = *insert(useAsRoot, begin, writeVersion, tls, impl);
|
||||
|
||||
const bool insertedBegin = !beginNode->entryPresent;
|
||||
begin = begin.subspan(lcp, begin.size() - lcp);
|
||||
end = end.subspan(lcp, end.size() - lcp);
|
||||
|
||||
auto *beginNode = *insert(useAsRoot, begin, writeVersion, tls);
|
||||
addKey(beginNode);
|
||||
beginNode->entryPresent = true;
|
||||
|
||||
if (insertedBegin) {
|
||||
if (!beginNode->entryPresent) {
|
||||
++tls->accum.entries_inserted;
|
||||
auto *p = nextLogical(beginNode);
|
||||
beginNode->entry.rangeVersion =
|
||||
p == nullptr ? tls->zero : std::max(p->entry.rangeVersion, tls->zero);
|
||||
beginNode->entry.pointVersion = writeVersion;
|
||||
beginNode->entryPresent = true;
|
||||
}
|
||||
assert(writeVersion >= beginNode->entry.pointVersion);
|
||||
beginNode->entry.pointVersion = writeVersion;
|
||||
|
||||
auto *endNode = *insert(useAsRoot, end, writeVersion, tls, impl);
|
||||
|
||||
const bool insertedEnd = !endNode->entryPresent;
|
||||
|
||||
auto *endNode = *insert(useAsRoot, end, writeVersion, tls);
|
||||
addKey(endNode);
|
||||
endNode->entryPresent = true;
|
||||
|
||||
if (insertedEnd) {
|
||||
if (!endNode->entryPresent) {
|
||||
++tls->accum.entries_inserted;
|
||||
auto *p = nextLogical(endNode);
|
||||
endNode->entry.pointVersion =
|
||||
p == nullptr ? tls->zero : std::max(p->entry.rangeVersion, tls->zero);
|
||||
if (beginIsPrefix) {
|
||||
// beginNode may have been invalidated when inserting end
|
||||
beginNode = *useAsRoot;
|
||||
assert(beginNode->entryPresent);
|
||||
}
|
||||
endNode->entryPresent = true;
|
||||
}
|
||||
endNode->entry.rangeVersion = writeVersion;
|
||||
|
||||
if (beginIsPrefix && insertedEnd) {
|
||||
// beginNode may have been invalidated when inserting end. TODO can we do
|
||||
// better?
|
||||
beginNode = *insert(useAsRoot, begin, writeVersion, tls, impl);
|
||||
assert(beginNode->entryPresent);
|
||||
}
|
||||
|
||||
for (beginNode = nextLogical(beginNode); beginNode != endNode;
|
||||
beginNode = erase(beginNode, tls, impl, /*logical*/ true, endNode)) {
|
||||
}
|
||||
|
||||
// Inserting end trashed endNode's maxVersion. Fix that
|
||||
fixupMaxVersion(endNode, impl, tls);
|
||||
// Inserting end trashed endNode's maxVersion. Fix that. Safe to call since
|
||||
// the end key always has non-zero size.
|
||||
fixupMaxVersion(endNode, tls);
|
||||
}
|
||||
|
||||
Node *firstGeqPhysical(Node *n, const std::span<const uint8_t> key) {
|
||||
@@ -3070,7 +3188,7 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
if (oldestExtantVersion < writeVersion - kMaxCorrectVersionWindow)
|
||||
[[unlikely]] {
|
||||
if (writeVersion > newestVersionFullPrecision + kNominalVersionWindow) {
|
||||
destroyTree(root);
|
||||
eraseTree(root, &tls);
|
||||
init(writeVersion - kNominalVersionWindow);
|
||||
}
|
||||
|
||||
@@ -3096,7 +3214,7 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
addWriteRange(root, begin, end, InternalVersionT(writeVersion), &tls,
|
||||
this);
|
||||
} else {
|
||||
addPointWrite(root, begin, InternalVersionT(writeVersion), &tls, this);
|
||||
addPointWrite(root, begin, InternalVersionT(writeVersion), &tls);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3127,7 +3245,6 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
// Don't erase the root
|
||||
if (n == root) {
|
||||
rezero(n, oldestVersion);
|
||||
rootMaxVersion = std::max(rootMaxVersion, oldestVersion);
|
||||
n = nextPhysical(n);
|
||||
}
|
||||
int64_t set_oldest_iterations_accum = 0;
|
||||
@@ -3218,7 +3335,6 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
root = tls.allocate<Node0>(0);
|
||||
root->numChildren = 0;
|
||||
root->parent = nullptr;
|
||||
rootMaxVersion = this->oldestVersion;
|
||||
root->entryPresent = false;
|
||||
root->partialKeyLen = 0;
|
||||
|
||||
@@ -3238,7 +3354,7 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
initMetrics();
|
||||
}
|
||||
~Impl() {
|
||||
destroyTree(root);
|
||||
eraseTree(root, &tls);
|
||||
safe_free(metrics, metricsCount * sizeof(metrics[0]));
|
||||
}
|
||||
|
||||
@@ -3249,7 +3365,6 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
int64_t keyUpdates;
|
||||
|
||||
Node *root;
|
||||
InternalVersionT rootMaxVersion;
|
||||
InternalVersionT oldestVersion;
|
||||
int64_t oldestVersionFullPrecision;
|
||||
int64_t oldestExtantVersion;
|
||||
@@ -3348,118 +3463,6 @@ Metric::Metric(ConflictSet::Impl *impl, const char *name, const char *help,
|
||||
++impl->metricsCount;
|
||||
}
|
||||
|
||||
InternalVersionT maxVersion(Node *n, ConflictSet::Impl *impl) {
|
||||
int index = n->parentsIndex;
|
||||
n = n->parent;
|
||||
if (n == nullptr) {
|
||||
return impl->rootMaxVersion;
|
||||
}
|
||||
switch (n->getType()) {
|
||||
case Type_Node0: // GCOVR_EXCL_LINE
|
||||
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
||||
case Type_Node3: {
|
||||
auto *n3 = static_cast<Node3 *>(n);
|
||||
int i = getNodeIndex(n3, index);
|
||||
return n3->childMaxVersion[i];
|
||||
}
|
||||
case Type_Node16: {
|
||||
auto *n16 = static_cast<Node16 *>(n);
|
||||
int i = getNodeIndex(n16, index);
|
||||
return n16->childMaxVersion[i];
|
||||
}
|
||||
case Type_Node48: {
|
||||
auto *n48 = static_cast<Node48 *>(n);
|
||||
assert(n48->bitSet.test(index));
|
||||
return n48->childMaxVersion[n48->index[index]];
|
||||
}
|
||||
case Type_Node256: {
|
||||
auto *n256 = static_cast<Node256 *>(n);
|
||||
assert(n256->bitSet.test(index));
|
||||
return n256->childMaxVersion[index];
|
||||
}
|
||||
default: // GCOVR_EXCL_LINE
|
||||
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
||||
}
|
||||
}
|
||||
|
||||
// Precondition `n` is not the root
|
||||
InternalVersionT exchangeMaxVersion(Node *n, InternalVersionT newMax) {
|
||||
int index = n->parentsIndex;
|
||||
n = n->parent;
|
||||
assert(n != nullptr);
|
||||
switch (n->getType()) {
|
||||
case Type_Node0: // GCOVR_EXCL_LINE
|
||||
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
||||
case Type_Node3: {
|
||||
auto *n3 = static_cast<Node3 *>(n);
|
||||
int i = getNodeIndex(n3, index);
|
||||
return std::exchange(n3->childMaxVersion[i], newMax);
|
||||
}
|
||||
case Type_Node16: {
|
||||
auto *n16 = static_cast<Node16 *>(n);
|
||||
int i = getNodeIndex(n16, index);
|
||||
return std::exchange(n16->childMaxVersion[i], newMax);
|
||||
}
|
||||
case Type_Node48: {
|
||||
auto *n48 = static_cast<Node48 *>(n);
|
||||
assert(n48->bitSet.test(index));
|
||||
return std::exchange(n48->childMaxVersion[n48->index[index]], newMax);
|
||||
}
|
||||
case Type_Node256: {
|
||||
auto *n256 = static_cast<Node256 *>(n);
|
||||
assert(n256->bitSet.test(index));
|
||||
return std::exchange(n256->childMaxVersion[index], newMax);
|
||||
}
|
||||
default: // GCOVR_EXCL_LINE
|
||||
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
||||
}
|
||||
}
|
||||
|
||||
void setMaxVersion(Node *n, ConflictSet::Impl *impl, InternalVersionT newMax) {
|
||||
int index = n->parentsIndex;
|
||||
n = n->parent;
|
||||
if (n == nullptr) {
|
||||
impl->rootMaxVersion = newMax;
|
||||
return;
|
||||
}
|
||||
switch (n->getType()) {
|
||||
case Type_Node0: // GCOVR_EXCL_LINE
|
||||
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
||||
case Type_Node3: {
|
||||
auto *n3 = static_cast<Node3 *>(n);
|
||||
int i = getNodeIndex(n3, index);
|
||||
n3->childMaxVersion[i] = newMax;
|
||||
return;
|
||||
}
|
||||
case Type_Node16: {
|
||||
auto *n16 = static_cast<Node16 *>(n);
|
||||
int i = getNodeIndex(n16, index);
|
||||
n16->childMaxVersion[i] = newMax;
|
||||
return;
|
||||
}
|
||||
case Type_Node48: {
|
||||
auto *n48 = static_cast<Node48 *>(n);
|
||||
assert(n48->bitSet.test(index));
|
||||
int i = n48->index[index];
|
||||
n48->childMaxVersion[i] = newMax;
|
||||
n48->maxOfMax[i >> Node48::kMaxOfMaxShift] = std::max<InternalVersionT>(
|
||||
n48->maxOfMax[i >> Node48::kMaxOfMaxShift], newMax);
|
||||
return;
|
||||
}
|
||||
case Type_Node256: {
|
||||
auto *n256 = static_cast<Node256 *>(n);
|
||||
assert(n256->bitSet.test(index));
|
||||
n256->childMaxVersion[index] = newMax;
|
||||
n256->maxOfMax[index >> Node256::kMaxOfMaxShift] =
|
||||
std::max<InternalVersionT>(
|
||||
n256->maxOfMax[index >> Node256::kMaxOfMaxShift], newMax);
|
||||
return;
|
||||
}
|
||||
default: // GCOVR_EXCL_LINE
|
||||
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
||||
}
|
||||
}
|
||||
|
||||
Node *&getInTree(Node *n, ConflictSet::Impl *impl) {
|
||||
return n->parent == nullptr ? impl->root
|
||||
: getChildExists(n->parent, n->parentsIndex);
|
||||
@@ -3741,13 +3744,13 @@ std::string getSearchPath(Node *n) {
|
||||
fprintf(file,
|
||||
" k_%p [label=\"m=%" PRId64 " p=%" PRId64 " r=%" PRId64
|
||||
"\n%s\", pos=\"%d,%d!\"];\n",
|
||||
(void *)n, maxVersion(n, impl).toInt64(),
|
||||
(void *)n, maxVersion(n).toInt64(),
|
||||
n->entry.pointVersion.toInt64(),
|
||||
n->entry.rangeVersion.toInt64(),
|
||||
getPartialKeyPrintable(n).c_str(), x, y);
|
||||
} else {
|
||||
fprintf(file, " k_%p [label=\"m=%" PRId64 "\n%s\", pos=\"%d,%d!\"];\n",
|
||||
(void *)n, maxVersion(n, impl).toInt64(),
|
||||
(void *)n, maxVersion(n).toInt64(),
|
||||
getPartialKeyPrintable(n).c_str(), x, y);
|
||||
}
|
||||
x += kSeparation;
|
||||
@@ -3858,11 +3861,11 @@ checkMaxVersion(Node *root, Node *node, InternalVersionT oldestVersion,
|
||||
expected = std::max(expected, borrowed->entry.rangeVersion);
|
||||
}
|
||||
}
|
||||
if (maxVersion(node, impl) > oldestVersion &&
|
||||
maxVersion(node, impl) != expected) {
|
||||
if (node->parent && maxVersion(node) > oldestVersion &&
|
||||
maxVersion(node) != expected) {
|
||||
fprintf(stderr, "%s has max version %" PRId64 " . Expected %" PRId64 "\n",
|
||||
getSearchPathPrintable(node).c_str(),
|
||||
maxVersion(node, impl).toInt64(), expected.toInt64());
|
||||
getSearchPathPrintable(node).c_str(), maxVersion(node).toInt64(),
|
||||
expected.toInt64());
|
||||
success = false;
|
||||
}
|
||||
return expected;
|
||||
@@ -3888,7 +3891,7 @@ checkMaxVersion(Node *root, Node *node, InternalVersionT oldestVersion,
|
||||
int minNumChildren;
|
||||
switch (node->getType()) {
|
||||
case Type_Node0:
|
||||
minNumChildren = 0;
|
||||
minNumChildren = kMinChildrenNode0;
|
||||
break;
|
||||
case Type_Node3:
|
||||
minNumChildren = kMinChildrenNode3;
|
||||
@@ -3926,7 +3929,7 @@ checkMaxVersion(Node *root, Node *node, InternalVersionT oldestVersion,
|
||||
bool success = true;
|
||||
|
||||
if (node->partialKeyLen > 0) {
|
||||
fprintf(stderr, "Root cannot have a partial key");
|
||||
fprintf(stderr, "Root cannot have a partial key\n");
|
||||
success = false;
|
||||
}
|
||||
checkParentPointers(node, success);
|
||||
|
10
Internal.h
10
Internal.h
@@ -273,6 +273,16 @@ template <class T> struct Vector {
|
||||
size_ += slice.size();
|
||||
}
|
||||
|
||||
// Caller must write to the returned slice
|
||||
std::span<T> unsafePrepareAppend(int appendSize) {
|
||||
if (size_ + appendSize > capacity) {
|
||||
grow(std::max<int>(size_ + appendSize, capacity * 2));
|
||||
}
|
||||
auto result = std::span<T>(t + size_, appendSize);
|
||||
size_ += appendSize;
|
||||
return result;
|
||||
}
|
||||
|
||||
void push_back(const T &t) { append(std::span<const T>(&t, 1)); }
|
||||
|
||||
T *begin() { return t; }
|
||||
|
21
README.md
21
README.md
@@ -24,16 +24,15 @@ Hardware for all benchmarks is an AMD Ryzen 9 7900 with (2x32GB) 5600MT/s CL28-3
|
||||
|
||||
| ns/op | op/s | err% | ins/op | cyc/op | IPC | bra/op | miss% | total | benchmark
|
||||
|--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:----------
|
||||
| 10.80 | 92,600,541.52 | 0.6% | 180.38 | 54.49 | 3.310 | 41.51 | 0.4% | 0.01 | `point reads`
|
||||
| 15.00 | 66,687,691.68 | 0.4% | 278.44 | 76.44 | 3.642 | 55.56 | 0.3% | 0.01 | `prefix reads`
|
||||
| 36.81 | 27,163,394.61 | 0.4% | 795.06 | 187.91 | 4.231 | 142.67 | 0.2% | 0.01 | `range reads`
|
||||
| 18.14 | 55,137,674.01 | 1.2% | 338.19 | 92.86 | 3.642 | 42.81 | 0.4% | 0.01 | `point writes`
|
||||
| 33.19 | 30,127,119.71 | 0.1% | 681.03 | 170.05 | 4.005 | 98.68 | 0.2% | 0.01 | `prefix writes`
|
||||
| 37.37 | 26,759,432.70 | 1.9% | 779.70 | 195.45 | 3.989 | 114.21 | 0.0% | 0.01 | `range writes`
|
||||
| 74.36 | 13,448,582.47 | 1.9% | 1,425.68 | 389.08 | 3.664 | 258.88 | 0.1% | 0.01 | `monotonic increasing point writes`
|
||||
| 316,928.00 | 3,155.29 | 1.5% | 3,992,986.00 | 1,699,813.00 | 2.349 | 806,226.50 | 0.0% | 0.01 | `worst case for radix tree`
|
||||
| 75.26 | 13,286,517.16 | 0.5% | 1,590.01 | 386.67 | 4.112 | 258.00 | 0.0% | 0.01 | `create and destroy`
|
||||
|
||||
| 11.04 | 90,614,308.12 | 0.8% | 180.38 | 55.13 | 3.272 | 41.51 | 0.4% | 0.01 | `point reads`
|
||||
| 14.96 | 66,843,629.12 | 0.4% | 274.41 | 74.73 | 3.672 | 55.05 | 0.3% | 0.01 | `prefix reads`
|
||||
| 37.06 | 26,982,847.61 | 0.2% | 791.04 | 185.28 | 4.269 | 142.67 | 0.2% | 0.01 | `range reads`
|
||||
| 17.89 | 55,887,365.73 | 0.6% | 335.54 | 89.79 | 3.737 | 43.84 | 0.4% | 0.01 | `point writes`
|
||||
| 31.85 | 31,394,336.65 | 0.3% | 615.32 | 159.63 | 3.855 | 87.69 | 0.2% | 0.01 | `prefix writes`
|
||||
| 36.17 | 27,647,221.45 | 0.6% | 705.11 | 182.80 | 3.857 | 100.62 | 0.1% | 0.01 | `range writes`
|
||||
| 79.01 | 12,656,457.78 | 0.7% | 1,498.35 | 402.46 | 3.723 | 270.50 | 0.1% | 0.01 | `monotonic increasing point writes`
|
||||
| 303,667.50 | 3,293.08 | 1.1% | 3,931,273.00 | 1,612,702.50 | 2.438 | 806,223.33 | 0.0% | 0.01 | `worst case for radix tree`
|
||||
| 83.70 | 11,947,443.83 | 0.7% | 1,738.03 | 429.06 | 4.051 | 270.01 | 0.0% | 0.01 | `create and destroy`
|
||||
|
||||
# "Real data" test
|
||||
|
||||
@@ -48,7 +47,7 @@ Check: 4.47891 seconds, 364.05 MB/s, Add: 4.55599 seconds, 123.058 MB/s, Gc rati
|
||||
## radix tree
|
||||
|
||||
```
|
||||
Check: 0.910234 seconds, 1791.35 MB/s, Add: 1.25908 seconds, 445.287 MB/s, Gc ratio: 44.0415%
|
||||
Check: 0.958985 seconds, 1700.28 MB/s, Add: 1.35083 seconds, 415.044 MB/s, Gc ratio: 44.4768%, Peak idle memory: 2.33588e+06
|
||||
```
|
||||
|
||||
## hash table
|
||||
|
@@ -164,6 +164,63 @@ double toSeconds(timeval t) {
|
||||
return double(t.tv_sec) + double(t.tv_usec) * 1e-6;
|
||||
}
|
||||
|
||||
#include <linux/perf_event.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __linux__
|
||||
struct PerfCounter {
|
||||
explicit PerfCounter(int event) {
|
||||
struct perf_event_attr pe;
|
||||
|
||||
memset(&pe, 0, sizeof(pe));
|
||||
pe.type = PERF_TYPE_HARDWARE;
|
||||
pe.size = sizeof(pe);
|
||||
pe.config = event;
|
||||
pe.inherit = 1;
|
||||
pe.exclude_kernel = 1;
|
||||
pe.exclude_hv = 1;
|
||||
|
||||
fd = perf_event_open(&pe, 0, -1, -1, 0);
|
||||
if (fd == -1) {
|
||||
fprintf(stderr, "Error opening leader %llx\n", pe.config);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
int64_t total() {
|
||||
int64_t count;
|
||||
if (read(fd, &count, sizeof(count)) != sizeof(count)) {
|
||||
perror("read instructions from perf");
|
||||
abort();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
~PerfCounter() { close(fd); }
|
||||
|
||||
private:
|
||||
int fd;
|
||||
static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
|
||||
int cpu, int group_fd, unsigned long flags) {
|
||||
int ret;
|
||||
|
||||
ret = syscall(SYS_perf_event_open, hw_event, pid, cpu, group_fd, flags);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
#else
|
||||
struct PerfCounter {
|
||||
explicit PerPerfCounter(int) {}
|
||||
int64_t total() { return 0; }
|
||||
};
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc != 3) {
|
||||
goto fail;
|
||||
@@ -176,6 +233,8 @@ int main(int argc, char **argv) {
|
||||
int metricsCount;
|
||||
cs.getMetricsV1(&metrics, &metricsCount);
|
||||
|
||||
PerfCounter instructions{PERF_COUNT_HW_INSTRUCTIONS};
|
||||
PerfCounter cycles{PERF_COUNT_HW_CPU_CYCLES};
|
||||
auto w = std::thread{workload, &cs};
|
||||
|
||||
for (;;) {
|
||||
@@ -203,6 +262,16 @@ int main(int argc, char **argv) {
|
||||
"transactions_total ";
|
||||
body += std::to_string(transactions.load(std::memory_order_relaxed));
|
||||
body += "\n";
|
||||
body += "# HELP instructions_total Total number of instructions\n"
|
||||
"# TYPE instructions_total counter\n"
|
||||
"instructions_total ";
|
||||
body += std::to_string(instructions.total());
|
||||
body += "\n";
|
||||
body += "# HELP cycles_total Total number of cycles\n"
|
||||
"# TYPE cycles_total counter\n"
|
||||
"cycles_total ";
|
||||
body += std::to_string(cycles.total());
|
||||
body += "\n";
|
||||
|
||||
for (int i = 0; i < metricsCount; ++i) {
|
||||
body += "# HELP ";
|
||||
|
BIN
corpus/0164e1ae452d063faa26b90d924f52189f268011
Normal file
BIN
corpus/0164e1ae452d063faa26b90d924f52189f268011
Normal file
Binary file not shown.
BIN
corpus/0325e533cf35c1e7ac95326c9b189911deffb27e
Normal file
BIN
corpus/0325e533cf35c1e7ac95326c9b189911deffb27e
Normal file
Binary file not shown.
BIN
corpus/05a091a7d5e921098504585a4201967860d310c6
Normal file
BIN
corpus/05a091a7d5e921098504585a4201967860d310c6
Normal file
Binary file not shown.
BIN
corpus/0da7d6000805c1f25907f3a2e8499ee119673f28
Normal file
BIN
corpus/0da7d6000805c1f25907f3a2e8499ee119673f28
Normal file
Binary file not shown.
BIN
corpus/15f6e61dd6edef971d7c79bef0d14069b0a75c77
Normal file
BIN
corpus/15f6e61dd6edef971d7c79bef0d14069b0a75c77
Normal file
Binary file not shown.
BIN
corpus/1e656ebd6c39b9fd6bea8c1bdaf12fe92642d507
Normal file
BIN
corpus/1e656ebd6c39b9fd6bea8c1bdaf12fe92642d507
Normal file
Binary file not shown.
BIN
corpus/2141828fbf5049e21a703dac83d5726fdf32aaaf
Normal file
BIN
corpus/2141828fbf5049e21a703dac83d5726fdf32aaaf
Normal file
Binary file not shown.
BIN
corpus/21540fec17d78467a6fe450592da42ca03e8e268
Normal file
BIN
corpus/21540fec17d78467a6fe450592da42ca03e8e268
Normal file
Binary file not shown.
BIN
corpus/29ae192a6404273b14be44d0f06d354e9eb5084b
Normal file
BIN
corpus/29ae192a6404273b14be44d0f06d354e9eb5084b
Normal file
Binary file not shown.
BIN
corpus/2a32a3d39a663771bda1be99ecfbe55ff780d2b2
Normal file
BIN
corpus/2a32a3d39a663771bda1be99ecfbe55ff780d2b2
Normal file
Binary file not shown.
BIN
corpus/31bf521be5d9f9e7d99e1384b9ffe26197324c37
Normal file
BIN
corpus/31bf521be5d9f9e7d99e1384b9ffe26197324c37
Normal file
Binary file not shown.
BIN
corpus/351af0b05e0c3f3c74954de9f5aa64d292d1dcab
Normal file
BIN
corpus/351af0b05e0c3f3c74954de9f5aa64d292d1dcab
Normal file
Binary file not shown.
BIN
corpus/35df5d1e51e37343461d1246ea693ea55ae46413
Normal file
BIN
corpus/35df5d1e51e37343461d1246ea693ea55ae46413
Normal file
Binary file not shown.
BIN
corpus/3ba58d43a24139a702c6d5c83ce3cc9f82bac804
Normal file
BIN
corpus/3ba58d43a24139a702c6d5c83ce3cc9f82bac804
Normal file
Binary file not shown.
BIN
corpus/3c07b3837fed49692b1fe1b9c1f878d135f3ecda
Normal file
BIN
corpus/3c07b3837fed49692b1fe1b9c1f878d135f3ecda
Normal file
Binary file not shown.
BIN
corpus/3e0b0439c9bd2b077379f35731c86f15d1ad67e6
Normal file
BIN
corpus/3e0b0439c9bd2b077379f35731c86f15d1ad67e6
Normal file
Binary file not shown.
BIN
corpus/4151500a97ee02841d558a8d5a366a2a8ba679b2
Normal file
BIN
corpus/4151500a97ee02841d558a8d5a366a2a8ba679b2
Normal file
Binary file not shown.
BIN
corpus/41539eb8863f7459144f13a027c931229d744349
Normal file
BIN
corpus/41539eb8863f7459144f13a027c931229d744349
Normal file
Binary file not shown.
BIN
corpus/46e31ef9b45b3ad66b33b2ff28b6357b7c9836d2
Normal file
BIN
corpus/46e31ef9b45b3ad66b33b2ff28b6357b7c9836d2
Normal file
Binary file not shown.
BIN
corpus/4d8ad2784eaf3d6a3ddeb2424d5c75a95e417252
Normal file
BIN
corpus/4d8ad2784eaf3d6a3ddeb2424d5c75a95e417252
Normal file
Binary file not shown.
BIN
corpus/54807c2d37bb3e47f6042beee1b508bb022699ca
Normal file
BIN
corpus/54807c2d37bb3e47f6042beee1b508bb022699ca
Normal file
Binary file not shown.
BIN
corpus/561bd20b55c4467ba932999b8a5a7a73ebb77b09
Normal file
BIN
corpus/561bd20b55c4467ba932999b8a5a7a73ebb77b09
Normal file
Binary file not shown.
BIN
corpus/572de429bbad5360c133ee2eb609d19db2d62e9c
Normal file
BIN
corpus/572de429bbad5360c133ee2eb609d19db2d62e9c
Normal file
Binary file not shown.
BIN
corpus/5954b3b4be666cc702277edb0e50d0f2bcfef42f
Normal file
BIN
corpus/5954b3b4be666cc702277edb0e50d0f2bcfef42f
Normal file
Binary file not shown.
BIN
corpus/5e0c4292ae5deebeddb5dfafbca8910de4d47f4c
Normal file
BIN
corpus/5e0c4292ae5deebeddb5dfafbca8910de4d47f4c
Normal file
Binary file not shown.
BIN
corpus/5e9f11a3626a4fffc92c226f41bb16745f91708c
Normal file
BIN
corpus/5e9f11a3626a4fffc92c226f41bb16745f91708c
Normal file
Binary file not shown.
BIN
corpus/6383fbe0cd35f501116fa8325165a7f8e2c06ee1
Normal file
BIN
corpus/6383fbe0cd35f501116fa8325165a7f8e2c06ee1
Normal file
Binary file not shown.
BIN
corpus/66412d9a19faa194559619f741d7a5d889c09bcb
Normal file
BIN
corpus/66412d9a19faa194559619f741d7a5d889c09bcb
Normal file
Binary file not shown.
BIN
corpus/6f264e10a7118afa70bf09c4c41eeba3a7ca8830
Normal file
BIN
corpus/6f264e10a7118afa70bf09c4c41eeba3a7ca8830
Normal file
Binary file not shown.
BIN
corpus/6f5d60d25770f597a46853f7b851c93b6b07817b
Normal file
BIN
corpus/6f5d60d25770f597a46853f7b851c93b6b07817b
Normal file
Binary file not shown.
BIN
corpus/741499f04b663d651df0969791c1b9d84f8257a0
Normal file
BIN
corpus/741499f04b663d651df0969791c1b9d84f8257a0
Normal file
Binary file not shown.
BIN
corpus/787c062d8bc33ebfa4b713a15c40c112e645388b
Normal file
BIN
corpus/787c062d8bc33ebfa4b713a15c40c112e645388b
Normal file
Binary file not shown.
BIN
corpus/85071ebfc498d2efef56ddab909c7b620150f06f
Normal file
BIN
corpus/85071ebfc498d2efef56ddab909c7b620150f06f
Normal file
Binary file not shown.
BIN
corpus/8536fc6a83a01ddf77b6b9ed3c42c43068ab9bce
Normal file
BIN
corpus/8536fc6a83a01ddf77b6b9ed3c42c43068ab9bce
Normal file
Binary file not shown.
BIN
corpus/8db6490863a8b4287d702480d565aabe9789b971
Normal file
BIN
corpus/8db6490863a8b4287d702480d565aabe9789b971
Normal file
Binary file not shown.
BIN
corpus/91c838cb372d5023474bc9c15ea5aa3e48a30414
Normal file
BIN
corpus/91c838cb372d5023474bc9c15ea5aa3e48a30414
Normal file
Binary file not shown.
BIN
corpus/97b7b08317abc0847ff8bc24df5dca33a553b805
Normal file
BIN
corpus/97b7b08317abc0847ff8bc24df5dca33a553b805
Normal file
Binary file not shown.
BIN
corpus/a8e2d3d290c934c832fa405fb4f3c9fb3a54919a
Normal file
BIN
corpus/a8e2d3d290c934c832fa405fb4f3c9fb3a54919a
Normal file
Binary file not shown.
BIN
corpus/ad471e8eebe223c1afc13d172fb3c8c39746f9b0
Normal file
BIN
corpus/ad471e8eebe223c1afc13d172fb3c8c39746f9b0
Normal file
Binary file not shown.
BIN
corpus/b44b9971ef924a12d393b4dfbe149c6270b6e3c6
Normal file
BIN
corpus/b44b9971ef924a12d393b4dfbe149c6270b6e3c6
Normal file
Binary file not shown.
BIN
corpus/b6546e8ce829f9032920603f45ffe969cf46ab42
Normal file
BIN
corpus/b6546e8ce829f9032920603f45ffe969cf46ab42
Normal file
Binary file not shown.
BIN
corpus/b6e34d0828f2113d75fc4d8223f7ce0d6f808199
Normal file
BIN
corpus/b6e34d0828f2113d75fc4d8223f7ce0d6f808199
Normal file
Binary file not shown.
BIN
corpus/c0c35545f24afb1bad2ad4f225a3de11aa10c532
Normal file
BIN
corpus/c0c35545f24afb1bad2ad4f225a3de11aa10c532
Normal file
Binary file not shown.
BIN
corpus/c6054ba4c80a543fadc119f3aa3193a797d32bb9
Normal file
BIN
corpus/c6054ba4c80a543fadc119f3aa3193a797d32bb9
Normal file
Binary file not shown.
BIN
corpus/cb0e598d2a5c3604371540f854ffe6475d2cc30e
Normal file
BIN
corpus/cb0e598d2a5c3604371540f854ffe6475d2cc30e
Normal file
Binary file not shown.
BIN
corpus/cb5c1ae4758ada5488b0da806b92e0b96363f7a6
Normal file
BIN
corpus/cb5c1ae4758ada5488b0da806b92e0b96363f7a6
Normal file
Binary file not shown.
BIN
corpus/cc0af1aa2b4414007f764e827f7f6a273d4e45fa
Normal file
BIN
corpus/cc0af1aa2b4414007f764e827f7f6a273d4e45fa
Normal file
Binary file not shown.
BIN
corpus/ce99657a71215223b038c7fe204a44e18efb9914
Normal file
BIN
corpus/ce99657a71215223b038c7fe204a44e18efb9914
Normal file
Binary file not shown.
BIN
corpus/d37d2795b555040c9d133027e6ad21be37eef5d2
Normal file
BIN
corpus/d37d2795b555040c9d133027e6ad21be37eef5d2
Normal file
Binary file not shown.
BIN
corpus/d5c0badb87670b4c8b3f69132f6181b77e30b547
Normal file
BIN
corpus/d5c0badb87670b4c8b3f69132f6181b77e30b547
Normal file
Binary file not shown.
BIN
corpus/d88b0d861be9f6487a94bc851f810650c443a322
Normal file
BIN
corpus/d88b0d861be9f6487a94bc851f810650c443a322
Normal file
Binary file not shown.
BIN
corpus/d9e3b04d684fd81612e89c4df4b6ea4fba28c551
Normal file
BIN
corpus/d9e3b04d684fd81612e89c4df4b6ea4fba28c551
Normal file
Binary file not shown.
BIN
corpus/dc5cfa2e3393eae88ddb853cce48dd9dd5b3ea5b
Normal file
BIN
corpus/dc5cfa2e3393eae88ddb853cce48dd9dd5b3ea5b
Normal file
Binary file not shown.
BIN
corpus/e6c53e2ce3900206ee5cbc9b412fa0f3a0bdc06b
Normal file
BIN
corpus/e6c53e2ce3900206ee5cbc9b412fa0f3a0bdc06b
Normal file
Binary file not shown.
BIN
corpus/ead41617afe5f204c9bff8013ebdec61ca3eb78a
Normal file
BIN
corpus/ead41617afe5f204c9bff8013ebdec61ca3eb78a
Normal file
Binary file not shown.
BIN
corpus/eb097d0cf0b8c08f61afde1e55086382641c7a45
Normal file
BIN
corpus/eb097d0cf0b8c08f61afde1e55086382641c7a45
Normal file
Binary file not shown.
BIN
corpus/ec28d45e6226d89bcfa1a0d721d1d8abde8fc938
Normal file
BIN
corpus/ec28d45e6226d89bcfa1a0d721d1d8abde8fc938
Normal file
Binary file not shown.
BIN
corpus/f6bcb347784d7c538b991970f4ebf10fa8bb1533
Normal file
BIN
corpus/f6bcb347784d7c538b991970f4ebf10fa8bb1533
Normal file
Binary file not shown.
BIN
corpus/ffd75ab88261864051be4a884a9c2fa2797b36a0
Normal file
BIN
corpus/ffd75ab88261864051be4a884a9c2fa2797b36a0
Normal file
Binary file not shown.
Reference in New Issue
Block a user