Compare commits
37 Commits
9dec45317e
...
v0.0.8
Author | SHA1 | Date | |
---|---|---|---|
60cb274a15 | |||
687bc9c935 | |||
d50bb8bc80 | |||
f19b403f19 | |||
34cd210907 | |||
1a5da9e899 | |||
8ba9b04d8c | |||
d895be36d2 | |||
65f8462e88 | |||
46e01af027 | |||
c9d0d72684 | |||
9046dc5a8f | |||
e2927bf0fa | |||
75a2b8d06c | |||
76df63a9d7 | |||
9c5b38b09a | |||
7142dab7ae | |||
3db3d975fc | |||
982b31af34 | |||
cc716ef16b | |||
88bcc7b75c | |||
3e6be6bd83 | |||
e59fee39c7 | |||
3e2c8310bb | |||
8264f1342d | |||
5d7e9c6f85 | |||
cdf42fcb34 | |||
cbe40b5dba | |||
a04e81b3ff | |||
0be97a34b6 | |||
68ab9a9f08 | |||
01488880ef | |||
bb84792cff | |||
1f421e95ff | |||
66bd799f05 | |||
2646d5eaf1 | |||
0367ba9856 |
@@ -1,7 +1,7 @@
|
|||||||
cmake_minimum_required(VERSION 3.18)
|
cmake_minimum_required(VERSION 3.18)
|
||||||
project(
|
project(
|
||||||
conflict-set
|
conflict-set
|
||||||
VERSION 0.0.7
|
VERSION 0.0.8
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
"A data structure for optimistic concurrency control on ranges of bitwise-lexicographically-ordered keys."
|
"A data structure for optimistic concurrency control on ranges of bitwise-lexicographically-ordered keys."
|
||||||
HOMEPAGE_URL "https://git.weaselab.dev/weaselab/conflict-set"
|
HOMEPAGE_URL "https://git.weaselab.dev/weaselab/conflict-set"
|
||||||
@@ -59,10 +59,6 @@ cmake_pop_check_state()
|
|||||||
|
|
||||||
option(USE_SIMD_FALLBACK
|
option(USE_SIMD_FALLBACK
|
||||||
"Use fallback implementations of functions that use SIMD" OFF)
|
"Use fallback implementations of functions that use SIMD" OFF)
|
||||||
option(
|
|
||||||
USE_32_BIT_VERSIONS
|
|
||||||
"Store 32 bit versions internally, and rely on versions never being different by more than 2e9"
|
|
||||||
OFF)
|
|
||||||
|
|
||||||
# This is encouraged according to
|
# This is encouraged according to
|
||||||
# https://valgrind.org/docs/manual/manual-core-adv.html#manual-core-adv.clientreq
|
# https://valgrind.org/docs/manual/manual-core-adv.html#manual-core-adv.clientreq
|
||||||
@@ -107,10 +103,6 @@ if(NOT USE_SIMD_FALLBACK)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(USE_32_BIT_VERSIONS)
|
|
||||||
add_compile_definitions(INTERNAL_VERSION_32_BIT=1)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "")
|
set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "")
|
||||||
|
|
||||||
add_library(${PROJECT_NAME}-object OBJECT ConflictSet.cpp)
|
add_library(${PROJECT_NAME}-object OBJECT ConflictSet.cpp)
|
||||||
|
713
ConflictSet.cpp
713
ConflictSet.cpp
File diff suppressed because it is too large
Load Diff
87
Internal.h
87
Internal.h
@@ -467,13 +467,15 @@ inline uint32_t Arbitrary::bounded(uint32_t s) {
|
|||||||
// ==================== END ARBITRARY IMPL ====================
|
// ==================== END ARBITRARY IMPL ====================
|
||||||
|
|
||||||
struct ReferenceImpl {
|
struct ReferenceImpl {
|
||||||
explicit ReferenceImpl(int64_t oldestVersion) : oldestVersion(oldestVersion) {
|
explicit ReferenceImpl(int64_t oldestVersion)
|
||||||
|
: oldestVersion(oldestVersion), newestVersion(oldestVersion) {
|
||||||
writeVersionMap[""] = oldestVersion;
|
writeVersionMap[""] = oldestVersion;
|
||||||
}
|
}
|
||||||
void check(const ConflictSet::ReadRange *reads, ConflictSet::Result *results,
|
void check(const ConflictSet::ReadRange *reads, ConflictSet::Result *results,
|
||||||
int count) const {
|
int count) const {
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
if (reads[i].readVersion < oldestVersion) {
|
if (reads[i].readVersion < oldestVersion ||
|
||||||
|
reads[i].readVersion < newestVersion - 2e9) {
|
||||||
results[i] = ConflictSet::TooOld;
|
results[i] = ConflictSet::TooOld;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -495,6 +497,8 @@ struct ReferenceImpl {
|
|||||||
}
|
}
|
||||||
void addWrites(const ConflictSet::WriteRange *writes, int count,
|
void addWrites(const ConflictSet::WriteRange *writes, int count,
|
||||||
int64_t writeVersion) {
|
int64_t writeVersion) {
|
||||||
|
assert(writeVersion >= newestVersion);
|
||||||
|
newestVersion = 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);
|
||||||
@@ -514,11 +518,12 @@ struct ReferenceImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setOldestVersion(int64_t oldestVersion) {
|
void setOldestVersion(int64_t oldestVersion) {
|
||||||
assert(oldestVersion >= oldestVersion);
|
assert(oldestVersion >= this->oldestVersion);
|
||||||
this->oldestVersion = oldestVersion;
|
this->oldestVersion = oldestVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t oldestVersion;
|
int64_t oldestVersion;
|
||||||
|
int64_t newestVersion;
|
||||||
std::map<std::string, int64_t> writeVersionMap;
|
std::map<std::string, int64_t> writeVersionMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -578,8 +583,8 @@ template <class ConflictSetImpl> struct TestDriver {
|
|||||||
explicit TestDriver(const uint8_t *data, size_t size)
|
explicit TestDriver(const uint8_t *data, size_t size)
|
||||||
: arbitrary({data, size}) {}
|
: arbitrary({data, size}) {}
|
||||||
|
|
||||||
int64_t oldestVersion = arbitrary.bounded(2) ? 0 : 0xfffffff0;
|
int64_t oldestVersion = arbitrary.next();
|
||||||
int64_t writeVersion = oldestVersion + 100;
|
int64_t writeVersion = oldestVersion;
|
||||||
ConflictSetImpl cs{oldestVersion};
|
ConflictSetImpl cs{oldestVersion};
|
||||||
ReferenceImpl refImpl{oldestVersion};
|
ReferenceImpl refImpl{oldestVersion};
|
||||||
|
|
||||||
@@ -593,6 +598,7 @@ template <class ConflictSetImpl> struct TestDriver {
|
|||||||
// Call until it returns true, for "done". Check internal invariants etc
|
// Call until it returns true, for "done". Check internal invariants etc
|
||||||
// between calls to next.
|
// between calls to next.
|
||||||
bool next() {
|
bool next() {
|
||||||
|
assert(cs.getBytes() >= 0);
|
||||||
if (!arbitrary.hasEntropy()) {
|
if (!arbitrary.hasEntropy()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -600,7 +606,8 @@ template <class ConflictSetImpl> struct TestDriver {
|
|||||||
{
|
{
|
||||||
int numPointWrites = arbitrary.bounded(100);
|
int numPointWrites = arbitrary.bounded(100);
|
||||||
int numRangeWrites = arbitrary.bounded(100);
|
int numRangeWrites = arbitrary.bounded(100);
|
||||||
int64_t v = (writeVersion += arbitrary.bounded(10));
|
int64_t v = (writeVersion += arbitrary.bounded(10) ? arbitrary.bounded(10)
|
||||||
|
: arbitrary.next());
|
||||||
auto *writes =
|
auto *writes =
|
||||||
new (arena) ConflictSet::WriteRange[numPointWrites + numRangeWrites];
|
new (arena) ConflictSet::WriteRange[numPointWrites + numRangeWrites];
|
||||||
auto keys = set<std::string_view>(arena);
|
auto keys = set<std::string_view>(arena);
|
||||||
@@ -642,33 +649,79 @@ template <class ConflictSetImpl> struct TestDriver {
|
|||||||
}
|
}
|
||||||
#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} -> %" PRId64 "\n",
|
fprintf(stderr, "Write: {%s}\n", printable(writes[i].begin).c_str());
|
||||||
printable(writes[i].begin).c_str(), writeVersion);
|
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Write: [%s, %s) -> %" PRId64 "\n",
|
fprintf(stderr, "Write: [%s, %s)\n",
|
||||||
printable(writes[i].begin).c_str(),
|
printable(writes[i].begin).c_str(),
|
||||||
printable(writes[i].end).c_str(), writeVersion);
|
printable(writes[i].end).c_str());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
assert(iter == keys.end());
|
assert(iter == keys.end());
|
||||||
assert(i == numPointWrites + numRangeWrites);
|
assert(i == numPointWrites + numRangeWrites);
|
||||||
|
|
||||||
|
#if DEBUG_VERBOSE && !defined(NDEBUG)
|
||||||
|
fprintf(stderr, "Write @ %" PRId64 "\n", v);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Test non-canonical writes
|
||||||
|
if (numPointWrites > 0) {
|
||||||
|
int overlaps = arbitrary.bounded(numPointWrites);
|
||||||
|
for (int i = 0; i < numPointWrites + numRangeWrites && overlaps > 0;
|
||||||
|
++i) {
|
||||||
|
if (writes[i].end.len == 0) {
|
||||||
|
int keyLen = prefixLen + arbitrary.bounded(kMaxKeySuffixLen);
|
||||||
|
auto *begin = new (arena) uint8_t[keyLen];
|
||||||
|
memset(begin, prefixByte, prefixLen);
|
||||||
|
arbitrary.randomBytes(begin + prefixLen, keyLen - prefixLen);
|
||||||
|
writes[i].end.len = keyLen;
|
||||||
|
writes[i].end.p = begin;
|
||||||
|
auto c =
|
||||||
|
std::span<const uint8_t>(writes[i].begin.p,
|
||||||
|
writes[i].begin.len) <=>
|
||||||
|
std::span<const uint8_t>(writes[i].end.p, writes[i].end.len);
|
||||||
|
if (c > 0) {
|
||||||
|
using std::swap;
|
||||||
|
swap(writes[i].begin, writes[i].end);
|
||||||
|
} else if (c == 0) {
|
||||||
|
// It's a point write after all, I guess
|
||||||
|
writes[i].end.len = 0;
|
||||||
|
}
|
||||||
|
--overlaps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (arbitrary.bounded(2)) {
|
||||||
|
// Shuffle writes
|
||||||
|
for (int i = numPointWrites + numRangeWrites - 1; i > 0; --i) {
|
||||||
|
int j = arbitrary.bounded(i + 1);
|
||||||
|
if (i != j) {
|
||||||
|
using std::swap;
|
||||||
|
swap(writes[i], writes[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CALLGRIND_START_INSTRUMENTATION;
|
CALLGRIND_START_INSTRUMENTATION;
|
||||||
cs.addWrites(writes, numPointWrites + numRangeWrites, v);
|
cs.addWrites(writes, numPointWrites + numRangeWrites, v);
|
||||||
CALLGRIND_STOP_INSTRUMENTATION;
|
CALLGRIND_STOP_INSTRUMENTATION;
|
||||||
|
|
||||||
refImpl.addWrites(writes, numPointWrites + numRangeWrites, v);
|
refImpl.addWrites(writes, numPointWrites + numRangeWrites, v);
|
||||||
|
|
||||||
oldestVersion =
|
oldestVersion +=
|
||||||
std::min(writeVersion - 10, oldestVersion + arbitrary.bounded(10));
|
arbitrary.bounded(10) ? arbitrary.bounded(10) : arbitrary.next();
|
||||||
|
oldestVersion = std::min(oldestVersion, writeVersion);
|
||||||
cs.setOldestVersion(oldestVersion);
|
cs.setOldestVersion(oldestVersion);
|
||||||
refImpl.setOldestVersion(oldestVersion);
|
refImpl.setOldestVersion(oldestVersion);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
int numPointReads = arbitrary.bounded(100);
|
int numPointReads = arbitrary.bounded(100);
|
||||||
int numRangeReads = arbitrary.bounded(100);
|
int numRangeReads = arbitrary.bounded(100);
|
||||||
int64_t v = std::max<int64_t>(writeVersion - arbitrary.bounded(10), 0);
|
|
||||||
|
int64_t v = std::max<int64_t>(writeVersion - (arbitrary.bounded(10)
|
||||||
|
? arbitrary.bounded(10)
|
||||||
|
: arbitrary.next()),
|
||||||
|
0);
|
||||||
auto *reads =
|
auto *reads =
|
||||||
new (arena) ConflictSet::ReadRange[numPointReads + numRangeReads];
|
new (arena) ConflictSet::ReadRange[numPointReads + numRangeReads];
|
||||||
auto keys = set<std::string_view>(arena);
|
auto keys = set<std::string_view>(arena);
|
||||||
@@ -710,12 +763,12 @@ template <class ConflictSetImpl> struct TestDriver {
|
|||||||
reads[i].readVersion = v;
|
reads[i].readVersion = v;
|
||||||
#if DEBUG_VERBOSE && !defined(NDEBUG)
|
#if DEBUG_VERBOSE && !defined(NDEBUG)
|
||||||
if (reads[i].end.len == 0) {
|
if (reads[i].end.len == 0) {
|
||||||
fprintf(stderr, "Read: {%s} @ %d\n",
|
fprintf(stderr, "Read: {%s} @ %" PRId64 "\n",
|
||||||
printable(reads[i].begin).c_str(), int(reads[i].readVersion));
|
printable(reads[i].begin).c_str(), reads[i].readVersion);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Read: [%s, %s) @ %d\n",
|
fprintf(stderr, "Read: [%s, %s) @ %" PRId64 "\n",
|
||||||
printable(reads[i].begin).c_str(),
|
printable(reads[i].begin).c_str(),
|
||||||
printable(reads[i].end).c_str(), int(reads[i].readVersion));
|
printable(reads[i].end).c_str(), reads[i].readVersion);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
13
Jenkinsfile
vendored
13
Jenkinsfile
vendored
@@ -59,17 +59,6 @@ pipeline {
|
|||||||
CleanBuildAndTest("-DUSE_SIMD_FALLBACK=ON")
|
CleanBuildAndTest("-DUSE_SIMD_FALLBACK=ON")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage('32-bit versions') {
|
|
||||||
agent {
|
|
||||||
dockerfile {
|
|
||||||
args '-v /home/jenkins/ccache:/ccache'
|
|
||||||
reuseNode true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
CleanBuildAndTest("-DUSE_32_BIT_VERSIONS=ON")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Release [gcc]') {
|
stage('Release [gcc]') {
|
||||||
agent {
|
agent {
|
||||||
dockerfile {
|
dockerfile {
|
||||||
@@ -123,7 +112,7 @@ pipeline {
|
|||||||
'''
|
'''
|
||||||
recordCoverage qualityGates: [[criticality: 'NOTE', metric: 'MODULE']], tools: [[parser: 'COBERTURA', pattern: 'build/coverage.xml']]
|
recordCoverage qualityGates: [[criticality: 'NOTE', metric: 'MODULE']], tools: [[parser: 'COBERTURA', pattern: 'build/coverage.xml']]
|
||||||
sh '''
|
sh '''
|
||||||
# Temporarily remove until we finish the transition to 32-bit versions
|
# Suppress again, because we haven't dealt with function multi-versioning for x86 yet
|
||||||
# gcovr -f ConflictSet.cpp --fail-under-line 100 > /dev/null
|
# gcovr -f ConflictSet.cpp --fail-under-line 100 > /dev/null
|
||||||
'''
|
'''
|
||||||
}
|
}
|
||||||
|
32
README.md
32
README.md
@@ -60,27 +60,27 @@ Performance counters:
|
|||||||
|
|
||||||
| ns/op | op/s | err% | total | benchmark
|
| ns/op | op/s | err% | total | benchmark
|
||||||
|--------------------:|--------------------:|--------:|----------:|:----------
|
|--------------------:|--------------------:|--------:|----------:|:----------
|
||||||
| 256.89 | 3,892,784.92 | 0.3% | 0.01 | `point reads`
|
| 245.99 | 4,065,232.81 | 0.3% | 0.01 | `point reads`
|
||||||
| 272.90 | 3,664,395.04 | 0.2% | 0.01 | `prefix reads`
|
| 265.93 | 3,760,430.49 | 0.2% | 0.01 | `prefix reads`
|
||||||
| 507.22 | 1,971,549.50 | 0.7% | 0.01 | `range reads`
|
| 485.30 | 2,060,569.50 | 0.2% | 0.01 | `range reads`
|
||||||
| 452.66 | 2,209,181.91 | 0.5% | 0.01 | `point writes`
|
| 449.60 | 2,224,195.17 | 0.4% | 0.01 | `point writes`
|
||||||
| 438.09 | 2,282,619.96 | 0.4% | 0.01 | `prefix writes`
|
| 441.76 | 2,263,688.18 | 1.1% | 0.01 | `prefix writes`
|
||||||
| 253.33 | 3,947,420.36 | 2.5% | 0.02 | `range writes`
|
| 245.42 | 4,074,647.54 | 2.4% | 0.02 | `range writes`
|
||||||
| 574.07 | 1,741,936.71 | 0.3% | 0.01 | `monotonic increasing point writes`
|
| 572.80 | 1,745,810.06 | 1.3% | 0.01 | `monotonic increasing point writes`
|
||||||
| 151,562.50 | 6,597.94 | 1.5% | 0.01 | `worst case for radix tree`
|
| 154,819.33 | 6,459.14 | 0.9% | 0.01 | `worst case for radix tree`
|
||||||
|
|
||||||
## Radix tree (this implementation)
|
## Radix tree (this implementation)
|
||||||
|
|
||||||
| ns/op | op/s | err% | total | benchmark
|
| ns/op | op/s | err% | total | benchmark
|
||||||
|--------------------:|--------------------:|--------:|----------:|:----------
|
|--------------------:|--------------------:|--------:|----------:|:----------
|
||||||
| 19.83 | 50,420,955.28 | 0.1% | 0.01 | `point reads`
|
| 19.17 | 52,163,930.66 | 0.1% | 0.01 | `point reads`
|
||||||
| 55.95 | 17,872,542.40 | 0.5% | 0.01 | `prefix reads`
|
| 23.68 | 42,224,388.21 | 0.7% | 0.01 | `prefix reads`
|
||||||
| 88.28 | 11,327,709.50 | 0.4% | 0.01 | `range reads`
|
| 63.30 | 15,797,506.06 | 0.9% | 0.01 | `range reads`
|
||||||
| 29.15 | 34,309,531.64 | 0.5% | 0.01 | `point writes`
|
| 29.66 | 33,720,994.74 | 0.3% | 0.01 | `point writes`
|
||||||
| 42.36 | 23,607,424.27 | 1.1% | 0.01 | `prefix writes`
|
| 43.50 | 22,987,781.25 | 1.0% | 0.01 | `prefix writes`
|
||||||
| 50.00 | 20,000,000.00 | 0.0% | 0.01 | `range writes`
|
| 50.00 | 20,000,000.00 | 0.8% | 0.01 | `range writes`
|
||||||
| 93.52 | 10,692,413.79 | 3.3% | 0.01 | `monotonic increasing point writes`
|
| 103.25 | 9,684,786.47 | 2.9% | 0.01 | `monotonic increasing point writes`
|
||||||
| 2,388,417.00 | 418.69 | 0.4% | 0.03 | `worst case for radix tree`
|
| 1,181,500.00 | 846.38 | 2.3% | 0.01 | `worst case for radix tree`
|
||||||
|
|
||||||
# "Real data" test
|
# "Real data" test
|
||||||
|
|
||||||
|
173
SkipList.cpp
173
SkipList.cpp
@@ -22,6 +22,8 @@
|
|||||||
|
|
||||||
#include "ConflictSet.h"
|
#include "ConflictSet.h"
|
||||||
#include "Internal.h"
|
#include "Internal.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <span>
|
#include <span>
|
||||||
|
|
||||||
std::span<const uint8_t> keyAfter(Arena &arena, std::span<const uint8_t> key) {
|
std::span<const uint8_t> keyAfter(Arena &arena, std::span<const uint8_t> key) {
|
||||||
@@ -52,6 +54,135 @@ struct KeyRangeRef {
|
|||||||
: begin(begin), end(keyAfter(arena, begin)) {}
|
: begin(begin), end(keyAfter(arena, begin)) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct KeyInfo {
|
||||||
|
StringRef key;
|
||||||
|
bool begin;
|
||||||
|
bool write;
|
||||||
|
|
||||||
|
KeyInfo() = default;
|
||||||
|
KeyInfo(StringRef key, bool begin, bool write)
|
||||||
|
: key(key), begin(begin), write(write) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
force_inline int extra_ordering(const KeyInfo &ki) {
|
||||||
|
return ki.begin * 2 + (ki.write ^ ki.begin);
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns true if done with string
|
||||||
|
force_inline bool getCharacter(const KeyInfo &ki, int character,
|
||||||
|
int &outputCharacter) {
|
||||||
|
// normal case
|
||||||
|
if (character < ki.key.size()) {
|
||||||
|
outputCharacter = 5 + ki.key.begin()[character];
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// termination
|
||||||
|
if (character == ki.key.size()) {
|
||||||
|
outputCharacter = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (character == ki.key.size() + 1) {
|
||||||
|
// end/begin+read/write relative sorting
|
||||||
|
outputCharacter = extra_ordering(ki);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
outputCharacter = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(const KeyInfo &lhs, const KeyInfo &rhs) {
|
||||||
|
int i = std::min(lhs.key.size(), rhs.key.size());
|
||||||
|
int c = memcmp(lhs.key.data(), rhs.key.data(), i);
|
||||||
|
if (c != 0)
|
||||||
|
return c < 0;
|
||||||
|
|
||||||
|
// Always sort shorter keys before longer keys.
|
||||||
|
if (lhs.key.size() < rhs.key.size()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (lhs.key.size() > rhs.key.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When the keys are the same length, use the extra ordering constraint.
|
||||||
|
return extra_ordering(lhs) < extra_ordering(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const KeyInfo &lhs, const KeyInfo &rhs) {
|
||||||
|
return !(lhs < rhs || rhs < lhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void swapSort(std::vector<KeyInfo> &points, int a, int b) {
|
||||||
|
if (points[b] < points[a]) {
|
||||||
|
KeyInfo temp;
|
||||||
|
temp = points[a];
|
||||||
|
points[a] = points[b];
|
||||||
|
points[b] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SortTask {
|
||||||
|
int begin;
|
||||||
|
int size;
|
||||||
|
int character;
|
||||||
|
SortTask(int begin, int size, int character)
|
||||||
|
: begin(begin), size(size), character(character) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
void sortPoints(std::vector<KeyInfo> &points) {
|
||||||
|
std::vector<SortTask> tasks;
|
||||||
|
std::vector<KeyInfo> newPoints;
|
||||||
|
std::vector<int> counts;
|
||||||
|
|
||||||
|
tasks.emplace_back(0, points.size(), 0);
|
||||||
|
|
||||||
|
while (tasks.size()) {
|
||||||
|
SortTask st = tasks.back();
|
||||||
|
tasks.pop_back();
|
||||||
|
|
||||||
|
if (st.size < 10) {
|
||||||
|
std::sort(points.begin() + st.begin, points.begin() + st.begin + st.size);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
newPoints.resize(st.size);
|
||||||
|
counts.assign(256 + 5, 0);
|
||||||
|
|
||||||
|
// get counts
|
||||||
|
int c;
|
||||||
|
bool allDone = true;
|
||||||
|
for (int i = st.begin; i < st.begin + st.size; i++) {
|
||||||
|
allDone &= getCharacter(points[i], st.character, c);
|
||||||
|
counts[c]++;
|
||||||
|
}
|
||||||
|
if (allDone)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// calculate offsets from counts and build next level of tasks
|
||||||
|
int total = 0;
|
||||||
|
for (int i = 0; i < counts.size(); i++) {
|
||||||
|
int temp = counts[i];
|
||||||
|
if (temp > 1)
|
||||||
|
tasks.emplace_back(st.begin + total, temp, st.character + 1);
|
||||||
|
counts[i] = total;
|
||||||
|
total += temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// put in their places
|
||||||
|
for (int i = st.begin; i < st.begin + st.size; i++) {
|
||||||
|
getCharacter(points[i], st.character, c);
|
||||||
|
newPoints[counts[c]++] = points[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy back into original points array
|
||||||
|
for (int i = 0; i < st.size; i++)
|
||||||
|
points[st.begin + i] = newPoints[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static thread_local uint32_t g_seed = 0;
|
static thread_local uint32_t g_seed = 0;
|
||||||
|
|
||||||
static inline int skfastrand() {
|
static inline int skfastrand() {
|
||||||
@@ -602,10 +733,40 @@ 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) {
|
int64_t writeVersion) {
|
||||||
|
auto points = std::vector<KeyInfo>(count * 2);
|
||||||
|
Arena arena;
|
||||||
|
|
||||||
|
for (int r = 0; r < count; r++) {
|
||||||
|
points.emplace_back(StringRef(writes[r].begin.p, writes[r].begin.len),
|
||||||
|
true, true);
|
||||||
|
points.emplace_back(
|
||||||
|
writes[r].end.len > 0
|
||||||
|
? StringRef{writes[r].end.p, size_t(writes[r].end.len)}
|
||||||
|
: keyAfter(arena, points.back().key),
|
||||||
|
false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
sortPoints(points);
|
||||||
|
|
||||||
|
int activeWriteCount = 0;
|
||||||
|
std::vector<std::pair<StringRef, StringRef>> combinedWriteConflictRanges;
|
||||||
|
for (const KeyInfo &point : points) {
|
||||||
|
if (point.write) {
|
||||||
|
if (point.begin) {
|
||||||
|
activeWriteCount++;
|
||||||
|
if (activeWriteCount == 1)
|
||||||
|
combinedWriteConflictRanges.emplace_back(point.key, StringRef());
|
||||||
|
} else /*if (point.end)*/ {
|
||||||
|
activeWriteCount--;
|
||||||
|
if (activeWriteCount == 0)
|
||||||
|
combinedWriteConflictRanges.back().second = point.key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
assert(writeVersion >= newestVersion);
|
assert(writeVersion >= newestVersion);
|
||||||
newestVersion = writeVersion;
|
newestVersion = writeVersion;
|
||||||
Arena arena;
|
const int stringCount = combinedWriteConflictRanges.size() * 2;
|
||||||
const int stringCount = count * 2;
|
|
||||||
|
|
||||||
const int stripeSize = 16;
|
const int stripeSize = 16;
|
||||||
SkipList::Finger fingers[stripeSize];
|
SkipList::Finger fingers[stripeSize];
|
||||||
@@ -616,15 +777,13 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
|||||||
int ss = stringCount - (stripes - 1) * stripeSize;
|
int ss = stringCount - (stripes - 1) * stripeSize;
|
||||||
for (int s = stripes - 1; s >= 0; s--) {
|
for (int s = stripes - 1; s >= 0; s--) {
|
||||||
for (int i = 0; i * 2 < ss; ++i) {
|
for (int i = 0; i * 2 < ss; ++i) {
|
||||||
const auto &w = writes[s * stripeSize / 2 + i];
|
const auto &w = combinedWriteConflictRanges[s * stripeSize / 2 + i];
|
||||||
#if DEBUG_VERBOSE
|
#if DEBUG_VERBOSE
|
||||||
printf("Write begin: %s\n", printable(w.begin).c_str());
|
printf("Write begin: %s\n", printable(w.begin).c_str());
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
#endif
|
#endif
|
||||||
values[i * 2] = {w.begin.p, size_t(w.begin.len)};
|
values[i * 2] = w.first;
|
||||||
values[i * 2 + 1] = w.end.len > 0
|
values[i * 2 + 1] = w.second;
|
||||||
? StringRef{w.end.p, size_t(w.end.len)}
|
|
||||||
: keyAfter(arena, values[i * 2]);
|
|
||||||
keyUpdates += 3;
|
keyUpdates += 3;
|
||||||
}
|
}
|
||||||
skipList.find(values, fingers, temp, ss);
|
skipList.find(values, fingers, temp, ss);
|
||||||
|
BIN
corpus/005e2b0059b0261bc2288a5843a31e098d31013b
Normal file
BIN
corpus/005e2b0059b0261bc2288a5843a31e098d31013b
Normal file
Binary file not shown.
BIN
corpus/0164498b5d5fbc2a3a5979deec1a0446c0e1abb6
Normal file
BIN
corpus/0164498b5d5fbc2a3a5979deec1a0446c0e1abb6
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/01cab80c8efd804c267cc9242a12a4dac2959f98
Normal file
BIN
corpus/01cab80c8efd804c267cc9242a12a4dac2959f98
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/027cb1a49430f1677a7bb0510841e2078c69a40e
Normal file
BIN
corpus/027cb1a49430f1677a7bb0510841e2078c69a40e
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/037a852532d83bba4b2a366b1c2e88902ec43a62
Normal file
BIN
corpus/037a852532d83bba4b2a366b1c2e88902ec43a62
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/04cddf0d0e2f0466d26efa1595a76858bcde4c94
Normal file
BIN
corpus/04cddf0d0e2f0466d26efa1595a76858bcde4c94
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/076b27f409c8bda741fb719e5d10681e5ae1db31
Normal file
BIN
corpus/076b27f409c8bda741fb719e5d10681e5ae1db31
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/091f1883731c2f0ba9d3705b44bfcd6dd3bf88db
Normal file
BIN
corpus/091f1883731c2f0ba9d3705b44bfcd6dd3bf88db
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/0ae06dc325d95c19967ac97b3de10c2fc8983b1b
Normal file
BIN
corpus/0ae06dc325d95c19967ac97b3de10c2fc8983b1b
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/0b626de7d1730e4a677757381713ba32ddbc943c
Normal file
BIN
corpus/0b626de7d1730e4a677757381713ba32ddbc943c
Normal file
Binary file not shown.
BIN
corpus/0b6558613333c201962d579fad084b280bd96aa7
Normal file
BIN
corpus/0b6558613333c201962d579fad084b280bd96aa7
Normal file
Binary file not shown.
BIN
corpus/0b82dea314f067dc8fd7b52459c1b855c784fde4
Normal file
BIN
corpus/0b82dea314f067dc8fd7b52459c1b855c784fde4
Normal file
Binary file not shown.
BIN
corpus/0bc38a2aff322bfcf5ca402f996ba12f8daf31d1
Normal file
BIN
corpus/0bc38a2aff322bfcf5ca402f996ba12f8daf31d1
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/0cabceb6692bc5ad27cffc1f00d412e6c1b0afc0
Normal file
BIN
corpus/0cabceb6692bc5ad27cffc1f00d412e6c1b0afc0
Normal file
Binary file not shown.
BIN
corpus/0cb1c7a2c5ad6f089cd3b2d48c658974aa338b2c
Normal file
BIN
corpus/0cb1c7a2c5ad6f089cd3b2d48c658974aa338b2c
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/0da6dc7ca616a5de655f860192079e4859382371
Normal file
BIN
corpus/0da6dc7ca616a5de655f860192079e4859382371
Normal file
Binary file not shown.
BIN
corpus/0ef85a238153205a34565c63f4ad6c373a90b73e
Normal file
BIN
corpus/0ef85a238153205a34565c63f4ad6c373a90b73e
Normal file
Binary file not shown.
BIN
corpus/0f045e5e1a36ee449803f31d0ec334fb1218cc33
Normal file
BIN
corpus/0f045e5e1a36ee449803f31d0ec334fb1218cc33
Normal file
Binary file not shown.
BIN
corpus/0f2e401e0fe0e1d6267142355cc156ee7d2c3c87
Normal file
BIN
corpus/0f2e401e0fe0e1d6267142355cc156ee7d2c3c87
Normal file
Binary file not shown.
BIN
corpus/0fc692696f94afbb5d2027bc12fa3dc4a19ac3a9
Normal file
BIN
corpus/0fc692696f94afbb5d2027bc12fa3dc4a19ac3a9
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/113ddcf047b2f8c3684853b0f086ead6f056fac2
Normal file
BIN
corpus/113ddcf047b2f8c3684853b0f086ead6f056fac2
Normal file
Binary file not shown.
BIN
corpus/11510f8502ab47f7d57cc205f3d6af50f36eb98c
Normal file
BIN
corpus/11510f8502ab47f7d57cc205f3d6af50f36eb98c
Normal file
Binary file not shown.
BIN
corpus/11919ca53b7efc88c8501dddde8fad916197f54c
Normal file
BIN
corpus/11919ca53b7efc88c8501dddde8fad916197f54c
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 11 B |
BIN
corpus/12a815319620aa136dd77ceb9f6389fd74765f8d
Normal file
BIN
corpus/12a815319620aa136dd77ceb9f6389fd74765f8d
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/133c0de112bdcb419b188a1fe8574941517764e8
Normal file
BIN
corpus/133c0de112bdcb419b188a1fe8574941517764e8
Normal file
Binary file not shown.
BIN
corpus/135debe2b0cde6a9d63eb07116d7c85c8dbcc268
Normal file
BIN
corpus/135debe2b0cde6a9d63eb07116d7c85c8dbcc268
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/14ba3bc0137f0791498781c534a4a81c41e5f565
Normal file
BIN
corpus/14ba3bc0137f0791498781c534a4a81c41e5f565
Normal file
Binary file not shown.
BIN
corpus/1534c7f0f2bac8015e9df650deb62fe383c58440
Normal file
BIN
corpus/1534c7f0f2bac8015e9df650deb62fe383c58440
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/1681caabc3d5e8d79b4dd79a465a3678bc6ab498
Normal file
BIN
corpus/1681caabc3d5e8d79b4dd79a465a3678bc6ab498
Normal file
Binary file not shown.
BIN
corpus/16da9b15792f7c488d3d9f8354199cc512cd012f
Normal file
BIN
corpus/16da9b15792f7c488d3d9f8354199cc512cd012f
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/17f44a42bb6e083988b3eb00ee6f14dccc10bcbf
Normal file
BIN
corpus/17f44a42bb6e083988b3eb00ee6f14dccc10bcbf
Normal file
Binary file not shown.
BIN
corpus/180e912ab1eee5ccaa1cab79c9fd4d81d2009b6a
Normal file
BIN
corpus/180e912ab1eee5ccaa1cab79c9fd4d81d2009b6a
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/1906d18823ade0beb690c68d8585dfb3b565956f
Normal file
BIN
corpus/1906d18823ade0beb690c68d8585dfb3b565956f
Normal file
Binary file not shown.
BIN
corpus/199d8d206d74e0e77ac21334cfe398a3885d84a2
Normal file
BIN
corpus/199d8d206d74e0e77ac21334cfe398a3885d84a2
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/1ae168891529281e4d601dbbe83a064fb330e722
Normal file
BIN
corpus/1ae168891529281e4d601dbbe83a064fb330e722
Normal file
Binary file not shown.
BIN
corpus/1af2516afd85fafa8a6c40dae32059f8b60536b0
Normal file
BIN
corpus/1af2516afd85fafa8a6c40dae32059f8b60536b0
Normal file
Binary file not shown.
BIN
corpus/1af26a82f432e06da3d093435c1baa2251955ee7
Normal file
BIN
corpus/1af26a82f432e06da3d093435c1baa2251955ee7
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/1c2b4d5da82dc79063550e5cf0c15b867098b47c
Normal file
BIN
corpus/1c2b4d5da82dc79063550e5cf0c15b867098b47c
Normal file
Binary file not shown.
BIN
corpus/1cbd253ecbe54b30051695216915f273716fb7eb
Normal file
BIN
corpus/1cbd253ecbe54b30051695216915f273716fb7eb
Normal file
Binary file not shown.
BIN
corpus/1d4c3da489e29554871120e2f9eb1227c92e9737
Normal file
BIN
corpus/1d4c3da489e29554871120e2f9eb1227c92e9737
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/1f03804706499daec8988095a00faa51cffa139f
Normal file
BIN
corpus/1f03804706499daec8988095a00faa51cffa139f
Normal file
Binary file not shown.
BIN
corpus/1f3e8fba12eab3f4019d41a4818bf20599af0f20
Normal file
BIN
corpus/1f3e8fba12eab3f4019d41a4818bf20599af0f20
Normal file
Binary file not shown.
BIN
corpus/2002d20caa25f4a189811044fc8605ded3b8e7de
Normal file
BIN
corpus/2002d20caa25f4a189811044fc8605ded3b8e7de
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/2170d4c6e441dff70a24d5dc3de7229afc2a0450
Normal file
BIN
corpus/2170d4c6e441dff70a24d5dc3de7229afc2a0450
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/21dc5306743b5c81261800b3a8bb65e9a42c0738
Normal file
BIN
corpus/21dc5306743b5c81261800b3a8bb65e9a42c0738
Normal file
Binary file not shown.
BIN
corpus/221318f0be1a1ad5ada43568dcc677405ade50fd
Normal file
BIN
corpus/221318f0be1a1ad5ada43568dcc677405ade50fd
Normal file
Binary file not shown.
BIN
corpus/222a983c4f1ab6b78288e51da692baecbc662928
Normal file
BIN
corpus/222a983c4f1ab6b78288e51da692baecbc662928
Normal file
Binary file not shown.
BIN
corpus/2235efbdee0d8983c7a37e67e02b514d223bab70
Normal file
BIN
corpus/2235efbdee0d8983c7a37e67e02b514d223bab70
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user