Interface change! Return TooOld after 2e9 versions
Event if setOldestVersion wasn't called
This commit is contained in:
@@ -2765,7 +2765,9 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
auto begin = std::span<const uint8_t>(r.begin.p, r.begin.len);
|
||||
auto end = std::span<const uint8_t>(r.end.p, r.end.len);
|
||||
result[i] =
|
||||
InternalVersionT(reads[i].readVersion) < oldestVersion ? TooOld
|
||||
InternalVersionT(reads[i].readVersion) < oldestVersion ||
|
||||
reads[i].readVersion < newestVersionFullPrecision - 2e9
|
||||
? TooOld
|
||||
: (end.size() > 0
|
||||
? checkRangeRead(root, begin, end,
|
||||
InternalVersionT(reads[i].readVersion), this)
|
||||
@@ -2777,6 +2779,8 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
}
|
||||
|
||||
void addWrites(const WriteRange *writes, int count, int64_t writeVersion) {
|
||||
assert(writeVersion >= newestVersionFullPrecision);
|
||||
newestVersionFullPrecision = writeVersion;
|
||||
#if INTERNAL_VERSION_32_BIT
|
||||
InternalVersionT::zero = oldestVersion;
|
||||
#endif
|
||||
@@ -2798,6 +2802,8 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
|
||||
void setOldestVersion(int64_t o) {
|
||||
InternalVersionT oldestVersion{o};
|
||||
assert(o >= oldestVersionFullPrecision);
|
||||
this->oldestVersionFullPrecision = o;
|
||||
this->oldestVersion = oldestVersion;
|
||||
#if INTERNAL_VERSION_32_BIT
|
||||
InternalVersionT::zero = oldestVersion;
|
||||
@@ -2841,7 +2847,9 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
}
|
||||
}
|
||||
|
||||
explicit Impl(int64_t oldestVersion) : oldestVersion(oldestVersion) {
|
||||
explicit Impl(int64_t oldestVersion)
|
||||
: oldestVersion(oldestVersion), oldestVersionFullPrecision(oldestVersion),
|
||||
newestVersionFullPrecision(oldestVersion) {
|
||||
#if DEBUG_VERBOSE
|
||||
fprintf(stderr, "radix_tree: create\n");
|
||||
#endif
|
||||
@@ -2876,6 +2884,11 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
Node *root;
|
||||
InternalVersionT rootMaxVersion;
|
||||
InternalVersionT oldestVersion;
|
||||
// TODO this doesn't fully mitigate the 32-bit precision issue, since we still
|
||||
// need to make sure we clean up versions in the tree before they fall out of
|
||||
// the 2e9 window.
|
||||
int64_t oldestVersionFullPrecision;
|
||||
int64_t newestVersionFullPrecision;
|
||||
int64_t totalBytes = 0;
|
||||
};
|
||||
|
||||
|
10
SkipList.cpp
10
SkipList.cpp
@@ -577,7 +577,8 @@ struct SkipListConflictSet {};
|
||||
|
||||
struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
Impl(int64_t oldestVersion)
|
||||
: oldestVersion(oldestVersion), skipList(oldestVersion) {}
|
||||
: oldestVersion(oldestVersion), newestVersion(oldestVersion),
|
||||
skipList(oldestVersion) {}
|
||||
void check(const ConflictSet::ReadRange *reads, ConflictSet::Result *results,
|
||||
int count) const {
|
||||
Arena arena;
|
||||
@@ -592,7 +593,8 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
}
|
||||
skipList.detectConflicts(ranges, count, results);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (reads[i].readVersion < oldestVersion) {
|
||||
if (reads[i].readVersion < oldestVersion ||
|
||||
reads[i].readVersion < newestVersion - 2e9) {
|
||||
results[i] = TooOld;
|
||||
}
|
||||
}
|
||||
@@ -600,6 +602,8 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
|
||||
void addWrites(const ConflictSet::WriteRange *writes, int count,
|
||||
int64_t writeVersion) {
|
||||
assert(writeVersion >= newestVersion);
|
||||
newestVersion = writeVersion;
|
||||
Arena arena;
|
||||
const int stringCount = count * 2;
|
||||
|
||||
@@ -630,6 +634,7 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
}
|
||||
|
||||
void setOldestVersion(int64_t oldestVersion) {
|
||||
assert(oldestVersion >= this->oldestVersion);
|
||||
this->oldestVersion = oldestVersion;
|
||||
SkipList::Finger finger;
|
||||
int temp;
|
||||
@@ -648,6 +653,7 @@ private:
|
||||
Arena removalArena;
|
||||
std::span<const uint8_t> removalKey;
|
||||
int64_t oldestVersion;
|
||||
int64_t newestVersion;
|
||||
SkipList skipList;
|
||||
};
|
||||
|
||||
|
@@ -54,6 +54,8 @@ struct __attribute__((__visibility__("default"))) ConflictSet {
|
||||
/** `end` having length 0 denotes that this range is the single key {begin}.
|
||||
* Otherwise this denotes the range [begin, end) */
|
||||
Key end;
|
||||
/** `readVersion` older than the the oldestVersion or the version of the
|
||||
* latest call to `addWrites` minus two billion will result in `TooOld` */
|
||||
int64_t readVersion;
|
||||
};
|
||||
|
||||
@@ -141,6 +143,8 @@ typedef struct {
|
||||
/** `end` having length 0 denotes that this range is the single key {begin}.
|
||||
* Otherwise this denotes the range [begin, end) */
|
||||
ConflictSet_Key end;
|
||||
/** `readVersion` older than the the oldestVersion or the version of the
|
||||
* latest call to `addWrites` minus two billion will result in `TooOld` */
|
||||
int64_t readVersion;
|
||||
} ConflictSet_ReadRange;
|
||||
|
||||
|
@@ -77,6 +77,13 @@ def test_internal_version_zero():
|
||||
cs.check(read(0xFFFFFFF1, b"\x00", b"\xff"))
|
||||
|
||||
|
||||
def test_two_billion_versions():
|
||||
with DebugConflictSet() as cs:
|
||||
cs.addWrites(int(2e9) + 1)
|
||||
cs.check(read(0, b"\x00", b"\xff"))
|
||||
cs.check(read(1, b"\x00", b"\xff"))
|
||||
|
||||
|
||||
def test_decrease_capacity():
|
||||
# make a Node48, then a Node256
|
||||
for count in (17, 49):
|
||||
|
Reference in New Issue
Block a user