Interface change! addWrites now takes a single write version
All checks were successful
Tests / Release [gcc] total: 704, passed: 704
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/57//gcc">weaselab » conflict-set » main #57</a>
Tests / Release [gcc,aarch64] total: 703, passed: 703
Tests / Coverage total: 702, passed: 702
weaselab/conflict-set/pipeline/head This commit looks good

This commit is contained in:
2024-03-05 16:50:53 -08:00
parent ec3aec4dff
commit be5f1b67c8
10 changed files with 71 additions and 95 deletions

View File

@@ -2,7 +2,6 @@
#include "Internal.h" #include "Internal.h"
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
#include <string>
#if SHOW_MEMORY #if SHOW_MEMORY
void showMemory(const ConflictSet &cs); void showMemory(const ConflictSet &cs);
@@ -78,10 +77,9 @@ void benchConflictSet() {
w.begin.len = r.begin.len; w.begin.len = r.begin.len;
w.end.p = r.end.p; w.end.p = r.end.p;
w.end.len = 0; w.end.len = 0;
w.writeVersion = version + 1;
writes.push_back(w); writes.push_back(w);
} }
cs.addWrites(writes.data(), writes.size()); cs.addWrites(writes.data(), writes.size(), version + 1);
++version; ++version;
} }
@@ -112,11 +110,10 @@ void benchConflictSet() {
w.begin.len = begin.size(); w.begin.len = begin.size();
w.end.p = end.data(); w.end.p = end.data();
w.end.len = end.size(); w.end.len = end.size();
w.writeVersion = version + 1;
writes.push_back(w); writes.push_back(w);
} }
cs.addWrites(writes.data(), kOpsPerTx, version + 1);
++version; ++version;
cs.addWrites(writes.data(), kOpsPerTx);
} }
{ {
@@ -189,16 +186,12 @@ void benchConflictSet() {
while (version < kMvccWindow) { while (version < kMvccWindow) {
auto v = ++version; auto v = ++version;
writes[0].writeVersion = v; cs.addWrites(writes.data(), 1, v);
cs.addWrites(writes.data(), 1);
} }
bench.run("point writes", [&]() { bench.run("point writes", [&]() {
auto v = ++version; auto v = ++version;
for (auto &w : writes) { cs.addWrites(writes.data(), writes.size(), v);
w.writeVersion = v;
}
cs.addWrites(writes.data(), writes.size());
cs.setOldestVersion(version - kMvccWindow); cs.setOldestVersion(version - kMvccWindow);
}); });
} }
@@ -219,10 +212,7 @@ void benchConflictSet() {
bench.run("prefix writes", [&]() { bench.run("prefix writes", [&]() {
auto v = ++version; auto v = ++version;
for (auto &w : writes) { cs.addWrites(writes.data(), writes.size(), v);
w.writeVersion = v;
}
cs.addWrites(writes.data(), writes.size());
cs.setOldestVersion(version - kMvccWindow); cs.setOldestVersion(version - kMvccWindow);
}); });
} }
@@ -243,10 +233,7 @@ void benchConflictSet() {
bench.run("range writes", [&]() { bench.run("range writes", [&]() {
auto v = ++version; auto v = ++version;
for (auto &w : writes) { cs.addWrites(writes.data(), writes.size(), v);
w.writeVersion = v;
}
cs.addWrites(writes.data(), writes.size());
cs.setOldestVersion(version - kMvccWindow); cs.setOldestVersion(version - kMvccWindow);
}); });
} }
@@ -263,12 +250,11 @@ void benchConflictSet() {
auto x = __builtin_bswap64(version); auto x = __builtin_bswap64(version);
memcpy(b, &x, 8); memcpy(b, &x, 8);
w.writeVersion = v;
w.begin.p = b; w.begin.p = b;
w.begin.len = 8; w.begin.len = 8;
w.end.len = 0; w.end.len = 0;
w.end.p = b; w.end.p = b;
cs.addWrites(&w, 1); cs.addWrites(&w, 1, v);
cs.setOldestVersion(version - kMvccWindow); cs.setOldestVersion(version - kMvccWindow);
}); });
} }

View File

@@ -1847,18 +1847,18 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
} }
} }
void addWrites(const WriteRange *writes, int count) { void addWrites(const WriteRange *writes, int count, int64_t writeVersion) {
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
const auto &w = writes[i]; const auto &w = writes[i];
auto begin = std::span<const uint8_t>(w.begin.p, w.begin.len); auto begin = std::span<const uint8_t>(w.begin.p, w.begin.len);
auto end = std::span<const uint8_t>(w.end.p, w.end.len); auto end = std::span<const uint8_t>(w.end.p, w.end.len);
if (w.end.len > 0) { if (w.end.len > 0) {
keyUpdates += 3; keyUpdates += 3;
addWriteRange(root, oldestVersion, begin, end, w.writeVersion, addWriteRange(root, oldestVersion, begin, end, writeVersion,
&allocators, this); &allocators, this);
} else { } else {
keyUpdates += 2; keyUpdates += 2;
addPointWrite(root, oldestVersion, begin, w.writeVersion, &allocators, addPointWrite(root, oldestVersion, begin, writeVersion, &allocators,
this); this);
} }
} }
@@ -1954,8 +1954,9 @@ void ConflictSet::check(const ReadRange *reads, Result *results,
return impl->check(reads, results, count); return impl->check(reads, results, count);
} }
void ConflictSet::addWrites(const WriteRange *writes, int count) { void ConflictSet::addWrites(const WriteRange *writes, int count,
return impl->addWrites(writes, count); int64_t writeVersion) {
return impl->addWrites(writes, count, writeVersion);
} }
void ConflictSet::setOldestVersion(int64_t oldestVersion) { void ConflictSet::setOldestVersion(int64_t oldestVersion) {
@@ -2009,9 +2010,9 @@ ConflictSet_check(void *cs, const ConflictSet_ReadRange *reads,
((ConflictSet::Impl *)cs)->check(reads, results, count); ((ConflictSet::Impl *)cs)->check(reads, results, count);
} }
__attribute__((__visibility__("default"))) void __attribute__((__visibility__("default"))) void
ConflictSet_addWrites(void *cs, const ConflictSet_WriteRange *writes, ConflictSet_addWrites(void *cs, const ConflictSet_WriteRange *writes, int count,
int count) { int64_t writeVersion) {
((ConflictSet::Impl *)cs)->addWrites(writes, count); ((ConflictSet::Impl *)cs)->addWrites(writes, count, writeVersion);
} }
__attribute__((__visibility__("default"))) void __attribute__((__visibility__("default"))) void
ConflictSet_setOldestVersion(void *cs, int64_t oldestVersion) { ConflictSet_setOldestVersion(void *cs, int64_t oldestVersion) {
@@ -2239,29 +2240,19 @@ void printTree() {
ConflictSet::Impl cs{writeVersion}; ConflictSet::Impl cs{writeVersion};
ReferenceImpl refImpl{writeVersion}; ReferenceImpl refImpl{writeVersion};
Arena arena; Arena arena;
constexpr int kNumKeys = 4; ConflictSet::WriteRange write;
auto *write = new (arena) ConflictSet::WriteRange[kNumKeys]; write.begin = "and"_s;
write[0].begin = "and"_s; write.end = "ant"_s;
write[0].end = "ant"_s; cs.addWrites(&write, 1, ++writeVersion);
write[0].writeVersion = 1; write.begin = "any"_s;
write.end = ""_s;
write[1].begin = "any"_s; cs.addWrites(&write, 1, ++writeVersion);
write[1].end.len = 0; write.begin = "are"_s;
write[1].writeVersion = 2; write.end = ""_s;
cs.addWrites(&write, 1, ++writeVersion);
write[2].begin = "are"_s; write.begin = "art"_s;
write[2].end.len = 0; write.end = ""_s;
write[2].writeVersion = 3; cs.addWrites(&write, 1, ++writeVersion);
write[3].begin = "art"_s;
write[3].end.len = 0;
write[3].writeVersion = 4;
cs.addWrites(write, kNumKeys);
for (int i = 0; i < kNumKeys; ++i) {
write[i].writeVersion = ++writeVersion;
}
cs.addWrites(write, kNumKeys);
debugPrintDot(stdout, cs.root, &cs); debugPrintDot(stdout, cs.root, &cs);
} }

View File

@@ -36,11 +36,13 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
} }
} }
void addWrites(const ConflictSet::WriteRange *writes, int count) { void addWrites(const ConflictSet::WriteRange *writes, int count,
int64_t writeVersion) {
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
auto &max = map[std::string((const char *)writes[i].begin.p, auto &max = map[std::string((const char *)writes[i].begin.p,
writes[i].begin.len)]; writes[i].begin.len)];
max = std::max(max, writes[i].writeVersion); assert(writeVersion >= max);
max = writeVersion;
keyUpdates += 2; keyUpdates += 2;
} }
} }
@@ -83,8 +85,9 @@ void ConflictSet::check(const ReadRange *reads, Result *results,
return impl->check(reads, results, count); return impl->check(reads, results, count);
} }
void ConflictSet::addWrites(const WriteRange *writes, int count) { void ConflictSet::addWrites(const WriteRange *writes, int count,
return impl->addWrites(writes, count); int64_t writeVersion) {
return impl->addWrites(writes, count, writeVersion);
} }
void ConflictSet::setOldestVersion(int64_t oldestVersion) { void ConflictSet::setOldestVersion(int64_t oldestVersion) {
@@ -121,9 +124,9 @@ ConflictSet_check(void *cs, const ConflictSet_ReadRange *reads,
((ConflictSet::Impl *)cs)->check(reads, results, count); ((ConflictSet::Impl *)cs)->check(reads, results, count);
} }
__attribute__((__visibility__("default"))) void __attribute__((__visibility__("default"))) void
ConflictSet_addWrites(void *cs, const ConflictSet_WriteRange *writes, ConflictSet_addWrites(void *cs, const ConflictSet_WriteRange *writes, int count,
int count) { int64_t writeVersion) {
((ConflictSet::Impl *)cs)->addWrites(writes, count); ((ConflictSet::Impl *)cs)->addWrites(writes, count, writeVersion);
} }
__attribute__((__visibility__("default"))) void __attribute__((__visibility__("default"))) void
ConflictSet_setOldestVersion(void *cs, int64_t oldestVersion) { ConflictSet_setOldestVersion(void *cs, int64_t oldestVersion) {

View File

@@ -404,7 +404,8 @@ struct ReferenceImpl {
: ConflictSet::Commit; : ConflictSet::Commit;
} }
} }
void addWrites(const ConflictSet::WriteRange *writes, int count) { void addWrites(const ConflictSet::WriteRange *writes, int count,
int64_t writeVersion) {
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
auto begin = auto begin =
std::string((const char *)writes[i].begin.p, writes[i].begin.len); std::string((const char *)writes[i].begin.p, writes[i].begin.len);
@@ -412,7 +413,6 @@ struct ReferenceImpl {
writes[i].end.len == 0 writes[i].end.len == 0
? begin + std::string("\x00", 1) ? begin + std::string("\x00", 1)
: std::string((const char *)writes[i].end.p, writes[i].end.len); : std::string((const char *)writes[i].end.p, writes[i].end.len);
auto writeVersion = writes[i].writeVersion;
auto prevVersion = (--writeVersionMap.upper_bound(end))->second; auto prevVersion = (--writeVersionMap.upper_bound(end))->second;
for (auto iter = writeVersionMap.lower_bound(begin), for (auto iter = writeVersionMap.lower_bound(begin),
endIter = writeVersionMap.lower_bound(end); endIter = writeVersionMap.lower_bound(end);
@@ -547,7 +547,6 @@ template <class ConflictSetImpl> struct TestDriver {
++iter; ++iter;
--rangesRemaining; --rangesRemaining;
} }
writes[i].writeVersion = v;
#if DEBUG_VERBOSE && !defined(NDEBUG) #if DEBUG_VERBOSE && !defined(NDEBUG)
if (writes[i].end.len == 0) { if (writes[i].end.len == 0) {
fprintf(stderr, "Write: {%s} -> %d\n", fprintf(stderr, "Write: {%s} -> %d\n",
@@ -565,10 +564,10 @@ template <class ConflictSetImpl> struct TestDriver {
assert(i == numPointWrites + numRangeWrites); assert(i == numPointWrites + numRangeWrites);
CALLGRIND_START_INSTRUMENTATION; CALLGRIND_START_INSTRUMENTATION;
cs.addWrites(writes, numPointWrites + numRangeWrites); cs.addWrites(writes, numPointWrites + numRangeWrites, v);
CALLGRIND_STOP_INSTRUMENTATION; CALLGRIND_STOP_INSTRUMENTATION;
refImpl.addWrites(writes, numPointWrites + numRangeWrites); refImpl.addWrites(writes, numPointWrites + numRangeWrites, v);
oldestVersion = std::max<int64_t>(writeVersion - arbitrary.bounded(10), oldestVersion = std::max<int64_t>(writeVersion - arbitrary.bounded(10),
oldestVersion); oldestVersion);

View File

@@ -96,7 +96,6 @@ int main(int argc, const char **argv) {
// Add unconditionally so that the load doesn't actually depend on the // Add unconditionally so that the load doesn't actually depend on the
// conflict rate // conflict rate
ConflictSet::WriteRange w; ConflictSet::WriteRange w;
w.writeVersion = ++version;
w.begin.p = (const uint8_t *)write.data(); w.begin.p = (const uint8_t *)write.data();
w.begin.len = write.size(); w.begin.len = write.size();
w.end.len = 0; w.end.len = 0;
@@ -104,7 +103,7 @@ int main(int argc, const char **argv) {
addBytes += write.size(); addBytes += write.size();
timer = now(); timer = now();
cs.addWrites(&w, 1); cs.addWrites(&w, 1, ++version);
addTime += now() - timer; addTime += now() - timer;
write = {}; write = {};

View File

@@ -286,7 +286,7 @@ public:
void swap(SkipList &other) { std::swap(header, other.header); } void swap(SkipList &other) { std::swap(header, other.header); }
void addConflictRanges(const Finger *fingers, int rangeCount, void addConflictRanges(const Finger *fingers, int rangeCount,
Version *version) { Version version) {
for (int r = rangeCount - 1; r >= 0; r--) { for (int r = rangeCount - 1; r >= 0; r--) {
const Finger &startF = fingers[r * 2]; const Finger &startF = fingers[r * 2];
const Finger &endF = fingers[r * 2 + 1]; const Finger &endF = fingers[r * 2 + 1];
@@ -295,7 +295,7 @@ public:
insert(endF, endF.finger[0]->getMaxVersion(0)); insert(endF, endF.finger[0]->getMaxVersion(0));
remove(startF, endF); remove(startF, endF);
insert(startF, version[r]); insert(startF, version);
} }
} }
@@ -588,7 +588,8 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
} }
} }
void addWrites(const ConflictSet::WriteRange *writes, int count) { void addWrites(const ConflictSet::WriteRange *writes, int count,
int64_t writeVersion) {
Arena arena; Arena arena;
const int stringCount = count * 2; const int stringCount = count * 2;
@@ -606,11 +607,10 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
values[i * 2 + 1] = w.end.len > 0 values[i * 2 + 1] = w.end.len > 0
? StringRef{w.end.p, size_t(w.end.len)} ? StringRef{w.end.p, size_t(w.end.len)}
: keyAfter(arena, values[i * 2]); : keyAfter(arena, values[i * 2]);
writeVersions[i] = w.writeVersion;
keyUpdates += 2; keyUpdates += 2;
} }
skipList.find(values, fingers, temp, ss); skipList.find(values, fingers, temp, ss);
skipList.addConflictRanges(fingers, ss / 2, writeVersions); skipList.addConflictRanges(fingers, ss / 2, writeVersion);
ss = stripeSize; ss = stripeSize;
} }
} }
@@ -640,8 +640,9 @@ void ConflictSet::check(const ReadRange *reads, Result *results,
return impl->check(reads, results, count); return impl->check(reads, results, count);
} }
void ConflictSet::addWrites(const WriteRange *writes, int count) { void ConflictSet::addWrites(const WriteRange *writes, int count,
return impl->addWrites(writes, count); int64_t writeVersion) {
return impl->addWrites(writes, count, writeVersion);
} }
void ConflictSet::setOldestVersion(int64_t oldestVersion) { void ConflictSet::setOldestVersion(int64_t oldestVersion) {
@@ -678,9 +679,9 @@ ConflictSet_check(void *cs, const ConflictSet_ReadRange *reads,
((ConflictSet::Impl *)cs)->check(reads, results, count); ((ConflictSet::Impl *)cs)->check(reads, results, count);
} }
__attribute__((__visibility__("default"))) void __attribute__((__visibility__("default"))) void
ConflictSet_addWrites(void *cs, const ConflictSet_WriteRange *writes, ConflictSet_addWrites(void *cs, const ConflictSet_WriteRange *writes, int count,
int count) { int64_t writeVersion) {
((ConflictSet::Impl *)cs)->addWrites(writes, count); ((ConflictSet::Impl *)cs)->addWrites(writes, count, writeVersion);
} }
__attribute__((__visibility__("default"))) void __attribute__((__visibility__("default"))) void
ConflictSet_setOldestVersion(void *cs, int64_t oldestVersion) { ConflictSet_setOldestVersion(void *cs, int64_t oldestVersion) {

View File

@@ -10,8 +10,7 @@ int main(void) {
w.begin.p = (const uint8_t *)"0000"; w.begin.p = (const uint8_t *)"0000";
w.begin.len = 4; w.begin.len = 4;
w.end.len = 0; w.end.len = 0;
w.writeVersion = 1; ConflictSet_addWrites(cs, &w, 1, 1);
ConflictSet_addWrites(cs, &w, 1);
r.begin.p = (const uint8_t *)"0000"; r.begin.p = (const uint8_t *)"0000";
r.begin.len = 4; r.begin.len = 4;
r.end.len = 0; r.end.len = 0;

View File

@@ -8,8 +8,7 @@ int main(void) {
w.begin.p = (const uint8_t *)"0000"; w.begin.p = (const uint8_t *)"0000";
w.begin.len = 4; w.begin.len = 4;
w.end.len = 0; w.end.len = 0;
w.writeVersion = 1; cs.addWrites(&w, 1, 1);
cs.addWrites(&w, 1);
ConflictSet::Result result; ConflictSet::Result result;
ConflictSet::ReadRange r; ConflictSet::ReadRange r;
r.begin.p = (const uint8_t *)"0000"; r.begin.p = (const uint8_t *)"0000";

View File

@@ -44,22 +44,21 @@ struct __attribute__((__visibility__("default"))) ConflictSet {
Key end; Key end;
int64_t readVersion; int64_t readVersion;
}; };
/** Denotes a set of keys to be considered written at `writeVersion` */ /** Denotes a set of keys to be written at `writeVersion` */
struct WriteRange { struct WriteRange {
Key begin; Key begin;
/** `end` having length 0 denotes that this range is the single key {begin}. /** `end` having length 0 denotes that this range is the single key {begin}.
* Otherwise this denotes the range [begin, end) */ * Otherwise this denotes the range [begin, end) */
Key end; Key end;
/** Write version must be greater than all write versions in all previous
* calls to `addWrites` */
int64_t writeVersion;
}; };
/** The result of checking reads[i] is written in results[i]. */ /** The result of checking reads[i] is written in results[i]. */
void check(const ReadRange *reads, Result *results, int count) const; void check(const ReadRange *reads, Result *results, int count) const;
/** `writes` must be sorted ascending, and must not have adjacent or /** `writes` must be sorted ascending, and must not have adjacent or
* overlapping ranges. Reads intersecting writes where readVersion < * overlapping ranges. Reads intersecting writes where readVersion <
* writeVersion will result in `Conflict` (or `TooOld`, eventually) */ * `writeVersion` will result in `Conflict` (or `TooOld`, eventually).
void addWrites(const WriteRange *writes, int count); * `writeVersion must be greater than all write versions in all previous
* calls to `addWrites` */
void addWrites(const WriteRange *writes, int count, int64_t writeVersion);
/** Reads where readVersion < oldestVersion will result in `TooOld`. Must be /** Reads where readVersion < oldestVersion will result in `TooOld`. Must be
* greater than any previous oldestVersion. */ * greater than any previous oldestVersion. */
void setOldestVersion(int64_t oldestVersion); void setOldestVersion(int64_t oldestVersion);
@@ -110,25 +109,25 @@ typedef struct {
ConflictSet_Key end; ConflictSet_Key end;
int64_t readVersion; int64_t readVersion;
} ConflictSet_ReadRange; } ConflictSet_ReadRange;
/** Denotes a set of keys to be considered written at `writeVersion` */ /** Denotes a set of keys to be written at `writeVersion` */
typedef struct { typedef struct {
ConflictSet_Key begin; ConflictSet_Key begin;
/** `end` having length 0 denotes that this range is the single key {begin}. /** `end` having length 0 denotes that this range is the single key {begin}.
* Otherwise this denotes the range [begin, end) */ * Otherwise this denotes the range [begin, end) */
ConflictSet_Key end; ConflictSet_Key end;
/** Write version must be greater than all write versions in all previous
* calls to `addWrites` */
int64_t writeVersion;
} ConflictSet_WriteRange; } ConflictSet_WriteRange;
/** The result of checking reads[i] is written in results[i]. */ /** The result of checking reads[i] is written in results[i]. */
void ConflictSet_check(ConflictSet *cs, const ConflictSet_ReadRange *reads, void ConflictSet_check(ConflictSet *cs, const ConflictSet_ReadRange *reads,
ConflictSet_Result *results, int count); ConflictSet_Result *results, int count);
/** `writes` must be sorted ascending, and must not have adjacent or overlapping /** `writes` must be sorted ascending, and must not have adjacent or
* ranges. Reads intersecting writes where readVersion < writeVersion will * overlapping ranges. Reads intersecting writes where readVersion <
* result in `Conflict` (or `TooOld`, eventually) */ * `writeVersion` will result in `Conflict` (or `TooOld`, eventually).
* `writeVersion must be greater than all write versions in all previous
* calls to `addWrites` */
void ConflictSet_addWrites(ConflictSet *cs, void ConflictSet_addWrites(ConflictSet *cs,
const ConflictSet_WriteRange *writes, int count); const ConflictSet_WriteRange *writes, int count,
int64_t writeVersion);
/** Reads where readVersion < oldestVersion will result in `TooOld`. Must be /** Reads where readVersion < oldestVersion will result in `TooOld`. Must be
* greater than any previous oldestVersion. */ * greater than any previous oldestVersion. */
void ConflictSet_setOldestVersion(ConflictSet *cs, int64_t oldestVersion); void ConflictSet_setOldestVersion(ConflictSet *cs, int64_t oldestVersion);

View File

@@ -4,7 +4,7 @@ ConflictSet_create
ConflictSet_destroy ConflictSet_destroy
ConflictSet_setOldestVersion ConflictSet_setOldestVersion
_ZN11ConflictSet16setOldestVersionEl _ZN11ConflictSet16setOldestVersionEl
_ZN11ConflictSet9addWritesEPKNS_10WriteRangeEi _ZN11ConflictSet9addWritesEPKNS_10WriteRangeEil
_ZN11ConflictSetaSEOS_ _ZN11ConflictSetaSEOS_
_ZN11ConflictSetC1El _ZN11ConflictSetC1El
_ZN11ConflictSetC1EOS_ _ZN11ConflictSetC1EOS_