Short circuit point reads based on maxVersion
All checks were successful
Tests / Release [gcc] total: 337, passed: 337
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend
|:-:|:-:|:-:|:-:|:-:
|0|0|0|0|:clap:
Reference build: <a href="https://jenkins.weaselab.dev/job/weaselab/job/conflict-set/job/main/5//gcc">weaselab » conflict-set » main #5</a>
Tests / Coverage total: 335, passed: 335
weaselab/conflict-set/pipeline/head This commit looks good
All checks were successful
Tests / Release [gcc] total: 337, passed: 337
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend
|:-:|:-:|:-:|:-:|:-:
|0|0|0|0|:clap:
Reference build: <a href="https://jenkins.weaselab.dev/job/weaselab/job/conflict-set/job/main/5//gcc">weaselab » conflict-set » main #5</a>
Tests / Coverage total: 335, passed: 335
weaselab/conflict-set/pipeline/head This commit looks good
This commit is contained in:
110
ConflictSet.cpp
110
ConflictSet.cpp
@@ -602,20 +602,6 @@ Node *prevPhysical(Node *node) {
|
||||
}
|
||||
}
|
||||
|
||||
Node *nextSibling(Node *node) {
|
||||
for (;;) {
|
||||
if (node->parent == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
auto next = getChildGeq(node->parent, node->parentsIndex + 1);
|
||||
if (next < 0) {
|
||||
node = node->parent;
|
||||
} else {
|
||||
return getChildExists(node->parent, next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Node *prevLogical(Node *node) {
|
||||
for (node = prevPhysical(node); node != nullptr && !node->entryPresent;
|
||||
node = prevPhysical(node))
|
||||
@@ -724,6 +710,88 @@ downLeftSpine:
|
||||
}
|
||||
}
|
||||
|
||||
// Logically this is the same as performing firstGeq and then checking against
|
||||
// point or range version according to cmp, but this version short circuits if
|
||||
// it can prove that both point and range versions of firstGeq are <=
|
||||
// readVersion.
|
||||
bool checkPointRead(Node *n, const std::span<const uint8_t> key,
|
||||
int64_t readVersion) {
|
||||
auto remaining = key;
|
||||
Node *nextSib = nullptr;
|
||||
for (;;) {
|
||||
if (std::max(nextSib != nullptr ? nextSib->maxVersion
|
||||
: std::numeric_limits<int64_t>::lowest(),
|
||||
n->maxVersion) <= readVersion) {
|
||||
return true;
|
||||
}
|
||||
if (n->partialKeyLen > 0) {
|
||||
int commonLen = std::min<int>(n->partialKeyLen, remaining.size());
|
||||
for (int i = 0; i < commonLen; ++i) {
|
||||
auto c = n->partialKey[i] <=> remaining[i];
|
||||
if (c == 0) {
|
||||
continue;
|
||||
}
|
||||
if (c > 0) {
|
||||
goto downLeftSpine;
|
||||
} else {
|
||||
n = nextSib;
|
||||
goto downLeftSpine;
|
||||
}
|
||||
}
|
||||
if (commonLen == n->partialKeyLen) {
|
||||
// partial key matches
|
||||
remaining = remaining.subspan(commonLen, remaining.size() - commonLen);
|
||||
} else if (n->partialKeyLen > int(remaining.size())) {
|
||||
// n is the first physical node greater than remaining, and there's no
|
||||
// eq node
|
||||
goto downLeftSpine;
|
||||
}
|
||||
}
|
||||
if (remaining.size() == 0) {
|
||||
if (n->entryPresent) {
|
||||
return n->entry.pointVersion <= readVersion;
|
||||
}
|
||||
int c = getChildGeq(n, 0);
|
||||
assert(c >= 0);
|
||||
n = getChildExists(n, c);
|
||||
goto downLeftSpine;
|
||||
} else {
|
||||
int c = getChildGeq(n, remaining[0]);
|
||||
int c2 = getChildGeq(n, int(remaining[0]) + 1);
|
||||
if (c2 >= 0) {
|
||||
nextSib = getChildExists(n, c2);
|
||||
}
|
||||
if (c == remaining[0]) {
|
||||
n = getChildExists(n, c);
|
||||
remaining = remaining.subspan(1, remaining.size() - 1);
|
||||
} else {
|
||||
if (c >= 0) {
|
||||
n = getChildExists(n, c);
|
||||
goto downLeftSpine;
|
||||
} else {
|
||||
n = nextSib;
|
||||
goto downLeftSpine;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
downLeftSpine:
|
||||
if (n == nullptr) {
|
||||
return true;
|
||||
}
|
||||
for (;;) {
|
||||
if (n->maxVersion <= readVersion) {
|
||||
return true;
|
||||
}
|
||||
if (n->entryPresent) {
|
||||
return n->entry.rangeVersion <= readVersion;
|
||||
}
|
||||
int c = getChildGeq(n, 0);
|
||||
assert(c >= 0);
|
||||
n = getChildExists(n, c);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a pointer to the newly inserted node. caller is reponsible for
|
||||
// setting 'entry' fields on the result, which may have !entryPresent. The
|
||||
// search path for `key` will have maxVersion at least `writeVersion` as a
|
||||
@@ -852,14 +920,12 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
auto iter = firstGeq(root, std::span<const uint8_t>(
|
||||
reads[i].begin.p, reads[i].begin.len));
|
||||
result[i] = (iter.n == nullptr ? oldestVersion
|
||||
: iter.cmp == 0
|
||||
? iter.n->entry.pointVersion
|
||||
: iter.n->entry.rangeVersion) > reads[i].readVersion
|
||||
? Conflict
|
||||
: Commit;
|
||||
result[i] = checkPointRead(root,
|
||||
std::span<const uint8_t>(reads[i].begin.p,
|
||||
reads[i].begin.len),
|
||||
reads[i].readVersion)
|
||||
? Commit
|
||||
: Conflict;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user