Compare commits
146 Commits
v0.0.6
...
2b11650589
Author | SHA1 | Date | |
---|---|---|---|
2b11650589 | |||
fce998460f | |||
6da3125719 | |||
79410d071f | |||
1fcca6450d | |||
55271ad06c | |||
e675612599 | |||
42b5d50492 | |||
6394995def | |||
c649bc7964 | |||
ec85a06d01 | |||
fb9f5ce6f4 | |||
2b1c710953 | |||
ebf281220b | |||
6051b2fb2e | |||
11c3ca6766 | |||
b45dec2f1f | |||
c5e9f18c47 | |||
cebbf89cbe | |||
abb791d86b | |||
12f361f33a | |||
640c1ca9dd | |||
b7d54d44e1 | |||
95596f831f | |||
542371d562 | |||
958a4e2d0e | |||
8ce14c58a4 | |||
56e847b63c | |||
7fd1c9e140 | |||
ebaac253e2 | |||
9b470a367c | |||
e7806a36d1 | |||
ffd1dfe74d | |||
c39af9117f | |||
ed274c24d7 | |||
cecfcc0da7 | |||
f6edde0e50 | |||
04ac41a7e7 | |||
354920f86f | |||
bfd02503e7 | |||
d0bd293f8d | |||
41e887c358 | |||
e394e3d96a | |||
3288c583e4 | |||
ef14003781 | |||
3ac16bc966 | |||
1e82f7fe22 | |||
4182d904c5 | |||
bd8ed4e7bd | |||
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 | |||
9dec45317e | |||
a68ad5dd17 | |||
8e3eacb54f | |||
0184e1d7f6 | |||
c52d50f4f9 | |||
447da11d59 | |||
daa8e02d4f | |||
fd3ea2c2a8 | |||
0b839b9d7e | |||
11a022dcf7 | |||
94da4c72a5 | |||
461e07822a | |||
75499543e7 | |||
81f44d352f | |||
45da8fb996 | |||
4958a4cced | |||
587874841f | |||
648b0b9238 | |||
d3f4afa167 | |||
f762add4d6 | |||
b311e5f1f0 | |||
ff81890921 | |||
0e96177f5c | |||
efb0e52a0a | |||
2df7000090 | |||
5378a06c39 | |||
12c6ed2568 | |||
a2bf839b19 | |||
c065b185ae | |||
639518bed4 | |||
7de983cc15 | |||
1b4b61ddc6 | |||
bff7b85de2 | |||
9108ee209a | |||
f8bf1c6eb4 | |||
4da2a01614 | |||
bb0e654040 | |||
cce7d29410 | |||
13f8d3fa8a | |||
02866a8cae | |||
fa86d3e707 | |||
7d1d1d7b2a | |||
789ecc29b3 | |||
08f2998a85 | |||
c882d7663d | |||
bfea4384ba | |||
6520e3d734 | |||
23ace8aac5 | |||
62e35de320 | |||
22e4ab01a1 | |||
b3aeed0caa | |||
5f3833e965 | |||
8b1cd9c052 | |||
bb9bc3d7b5 | |||
89b3354a80 | |||
488c723726 | |||
76d0785b33 | |||
add0af11ad | |||
2c0adf4a8b | |||
e8ac78cce6 |
112
Bench.cpp
112
Bench.cpp
@@ -258,4 +258,114 @@ void benchConflictSet() {
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) { benchConflictSet(); }
|
||||
constexpr int kKeyLenForWorstCase = 50;
|
||||
|
||||
ConflictSet worstCaseConflictSetForRadixRangeRead(int cardinality) {
|
||||
ConflictSet cs{0};
|
||||
|
||||
for (int i = 0; i < kKeyLenForWorstCase; ++i) {
|
||||
for (int j = 0; j < cardinality; ++j) {
|
||||
auto b = std::vector<uint8_t>(i, 0);
|
||||
b.push_back(j);
|
||||
auto e = std::vector<uint8_t>(i, 255);
|
||||
e.push_back(255 - j);
|
||||
weaselab::ConflictSet::WriteRange w[] = {{
|
||||
{b.data(), int(b.size())},
|
||||
{nullptr, 0},
|
||||
},
|
||||
{
|
||||
{e.data(), int(e.size())},
|
||||
{nullptr, 0},
|
||||
}};
|
||||
std::sort(std::begin(w), std::end(w),
|
||||
[](const auto &lhs, const auto &rhs) {
|
||||
int cl = std::min(lhs.begin.len, rhs.begin.len);
|
||||
if (cl > 0) {
|
||||
int c = memcmp(lhs.begin.p, rhs.begin.p, cl);
|
||||
if (c != 0) {
|
||||
return c < 0;
|
||||
}
|
||||
}
|
||||
return lhs.begin.len < rhs.begin.len;
|
||||
});
|
||||
cs.addWrites(w, sizeof(w) / sizeof(w[0]), 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Defeat short-circuiting on the left
|
||||
{
|
||||
auto k = std::vector<uint8_t>(kKeyLenForWorstCase, 0);
|
||||
weaselab::ConflictSet::WriteRange w[] = {
|
||||
{
|
||||
{k.data(), int(k.size())},
|
||||
{nullptr, 0},
|
||||
},
|
||||
};
|
||||
cs.addWrites(w, sizeof(w) / sizeof(w[0]), 1);
|
||||
}
|
||||
|
||||
// Defeat short-circuiting on the right
|
||||
{
|
||||
auto k = std::vector<uint8_t>(kKeyLenForWorstCase, 255);
|
||||
weaselab::ConflictSet::WriteRange w[] = {
|
||||
{
|
||||
{k.data(), int(k.size())},
|
||||
{nullptr, 0},
|
||||
},
|
||||
};
|
||||
cs.addWrites(w, sizeof(w) / sizeof(w[0]), 1);
|
||||
}
|
||||
|
||||
return cs;
|
||||
}
|
||||
|
||||
void benchWorstCaseForRadixRangeRead() {
|
||||
ankerl::nanobench::Bench bench;
|
||||
|
||||
std::unique_ptr<ConflictSet> cs[256];
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
cs[i] =
|
||||
std::make_unique<ConflictSet>(worstCaseConflictSetForRadixRangeRead(i));
|
||||
}
|
||||
|
||||
auto begin = std::vector<uint8_t>(kKeyLenForWorstCase - 1, 0);
|
||||
begin.push_back(1);
|
||||
auto end = std::vector<uint8_t>(kKeyLenForWorstCase - 1, 255);
|
||||
end.push_back(254);
|
||||
|
||||
weaselab::ConflictSet::Result result;
|
||||
weaselab::ConflictSet::ReadRange r{
|
||||
{begin.data(), int(begin.size())}, {end.data(), int(end.size())}, 0};
|
||||
|
||||
bench.run("worst case for radix tree", [&]() {
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
result = weaselab::ConflictSet::TooOld;
|
||||
cs[i]->check(&r, &result, 1);
|
||||
if (result != weaselab::ConflictSet::Commit) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// for (int i = 0; i < 256; ++i) {
|
||||
// bench.run("worst case for radix tree, span " + std::to_string(i), [&]() {
|
||||
// result = weaselab::ConflictSet::TooOld;
|
||||
// cs[i]->check(&r, &result, 1);
|
||||
// if (result != weaselab::ConflictSet::Commit) {
|
||||
// abort();
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
||||
void benchCreateAndDestroy() {
|
||||
ankerl::nanobench::Bench bench;
|
||||
|
||||
bench.run("create and destroy", [&]() { ConflictSet cs{0}; });
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
benchConflictSet();
|
||||
benchWorstCaseForRadixRangeRead();
|
||||
benchCreateAndDestroy();
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.18)
|
||||
project(
|
||||
conflict-set
|
||||
VERSION 0.0.6
|
||||
VERSION 0.0.10
|
||||
DESCRIPTION
|
||||
"A data structure for optimistic concurrency control on ranges of bitwise-lexicographically-ordered keys."
|
||||
HOMEPAGE_URL "https://git.weaselab.dev/weaselab/conflict-set"
|
||||
@@ -19,12 +19,6 @@ include(CheckCXXSourceCompiles)
|
||||
|
||||
set(DEFAULT_BUILD_TYPE "Release")
|
||||
|
||||
if(EMSCRIPTEN OR CMAKE_SYSTEM_NAME STREQUAL WASI)
|
||||
set(WASM ON)
|
||||
else()
|
||||
set(WASM OFF)
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
message(
|
||||
STATUS
|
||||
@@ -60,6 +54,8 @@ cmake_pop_check_state()
|
||||
option(USE_SIMD_FALLBACK
|
||||
"Use fallback implementations of functions that use SIMD" OFF)
|
||||
|
||||
option(DISABLE_TSAN "Disable TSAN" OFF)
|
||||
|
||||
# This is encouraged according to
|
||||
# https://valgrind.org/docs/manual/manual-core-adv.html#manual-core-adv.clientreq
|
||||
include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/valgrind)
|
||||
@@ -79,15 +75,6 @@ if(EMSCRIPTEN)
|
||||
endif()
|
||||
|
||||
if(NOT USE_SIMD_FALLBACK)
|
||||
cmake_push_check_state()
|
||||
list(APPEND CMAKE_REQUIRED_FLAGS -msimd128)
|
||||
check_include_file_cxx("wasm_simd128.h" HAS_WASM_SIMD)
|
||||
if(HAS_WASM_SIMD)
|
||||
add_compile_options(-msimd128)
|
||||
add_compile_definitions(HAS_WASM_SIMD)
|
||||
endif()
|
||||
cmake_pop_check_state()
|
||||
|
||||
cmake_push_check_state()
|
||||
list(APPEND CMAKE_REQUIRED_FLAGS -mavx)
|
||||
check_include_file_cxx("immintrin.h" HAS_AVX)
|
||||
@@ -160,47 +147,40 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND BUILD_TESTING)
|
||||
|
||||
file(GLOB CORPUS_TESTS ${CMAKE_CURRENT_SOURCE_DIR}/corpus/*)
|
||||
|
||||
# extra testing that relies on shared libraries, which aren't available with
|
||||
# wasm
|
||||
if(NOT WASM)
|
||||
# Shared library version of FoundationDB's skip list implementation
|
||||
add_library(skip_list SHARED SkipList.cpp)
|
||||
target_compile_options(skip_list PRIVATE -fno-exceptions
|
||||
-fvisibility=hidden)
|
||||
target_include_directories(skip_list
|
||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
set_target_properties(
|
||||
skip_list PROPERTIES LIBRARY_OUTPUT_DIRECTORY
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/skip_list")
|
||||
set_target_properties(skip_list PROPERTIES OUTPUT_NAME ${PROJECT_NAME})
|
||||
set_target_properties(
|
||||
skip_list PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION
|
||||
${PROJECT_VERSION_MAJOR})
|
||||
# Shared library version of FoundationDB's skip list implementation
|
||||
add_library(skip_list SHARED SkipList.cpp)
|
||||
target_compile_options(skip_list PRIVATE -fno-exceptions -fvisibility=hidden)
|
||||
target_include_directories(skip_list
|
||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
set_target_properties(
|
||||
skip_list PROPERTIES LIBRARY_OUTPUT_DIRECTORY
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/skip_list")
|
||||
set_target_properties(skip_list PROPERTIES OUTPUT_NAME ${PROJECT_NAME})
|
||||
set_target_properties(skip_list PROPERTIES VERSION ${PROJECT_VERSION}
|
||||
SOVERSION ${PROJECT_VERSION_MAJOR})
|
||||
|
||||
# Shared library version of a std::unordered_map-based conflict set (point
|
||||
# queries only)
|
||||
add_library(hash_table SHARED HashTable.cpp)
|
||||
target_compile_options(hash_table PRIVATE -fno-exceptions
|
||||
-fvisibility=hidden)
|
||||
target_include_directories(hash_table
|
||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
set_target_properties(
|
||||
hash_table PROPERTIES LIBRARY_OUTPUT_DIRECTORY
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/hash_table")
|
||||
set_target_properties(hash_table PROPERTIES OUTPUT_NAME ${PROJECT_NAME})
|
||||
set_target_properties(
|
||||
hash_table PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION
|
||||
${PROJECT_VERSION_MAJOR})
|
||||
# Shared library version of a std::unordered_map-based conflict set (point
|
||||
# queries only)
|
||||
add_library(hash_table SHARED HashTable.cpp)
|
||||
target_compile_options(hash_table PRIVATE -fno-exceptions -fvisibility=hidden)
|
||||
target_include_directories(hash_table
|
||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
set_target_properties(
|
||||
hash_table PROPERTIES LIBRARY_OUTPUT_DIRECTORY
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/hash_table")
|
||||
set_target_properties(hash_table PROPERTIES OUTPUT_NAME ${PROJECT_NAME})
|
||||
set_target_properties(
|
||||
hash_table PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION
|
||||
${PROJECT_VERSION_MAJOR})
|
||||
|
||||
add_executable(driver_skip_list TestDriver.cpp)
|
||||
target_compile_options(driver_skip_list PRIVATE ${TEST_FLAGS})
|
||||
target_link_libraries(driver_skip_list PRIVATE skip_list)
|
||||
add_executable(driver_skip_list TestDriver.cpp)
|
||||
target_compile_options(driver_skip_list PRIVATE ${TEST_FLAGS})
|
||||
target_link_libraries(driver_skip_list PRIVATE skip_list)
|
||||
|
||||
foreach(TEST ${CORPUS_TESTS})
|
||||
get_filename_component(hash ${TEST} NAME)
|
||||
add_test(NAME skip_list_${hash} COMMAND driver_skip_list ${TEST})
|
||||
endforeach()
|
||||
endif()
|
||||
foreach(TEST ${CORPUS_TESTS})
|
||||
get_filename_component(hash ${TEST} NAME)
|
||||
add_test(NAME skip_list_${hash} COMMAND driver_skip_list ${TEST})
|
||||
endforeach()
|
||||
|
||||
# ad hoc testing
|
||||
add_executable(conflict_set_main ConflictSet.cpp)
|
||||
@@ -245,7 +225,7 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND BUILD_TESTING)
|
||||
endforeach()
|
||||
|
||||
# tsan tests
|
||||
if(NOT CMAKE_CROSSCOMPILING AND NOT CMAKE_BUILD_TYPE STREQUAL Debug)
|
||||
if(NOT CMAKE_CROSSCOMPILING AND NOT DISABLE_TSAN)
|
||||
add_executable(tsan_driver ConflictSet.cpp FuzzTestDriver.cpp)
|
||||
target_compile_options(tsan_driver PRIVATE ${TEST_FLAGS} -fsanitize=thread)
|
||||
target_link_options(tsan_driver PRIVATE -fsanitize=thread)
|
||||
@@ -318,7 +298,7 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND BUILD_TESTING)
|
||||
add_test(NAME conflict_set_cxx_api_test COMMAND conflict_set_cxx_api_test)
|
||||
|
||||
# symbol visibility tests
|
||||
if(NOT WASM AND NOT CMAKE_BUILD_TYPE STREQUAL Debug)
|
||||
if(NOT CMAKE_BUILD_TYPE STREQUAL Debug)
|
||||
if(APPLE)
|
||||
set(symbol_exports ${CMAKE_CURRENT_SOURCE_DIR}/apple-symbol-exports.txt)
|
||||
set(symbol_imports ${CMAKE_CURRENT_SOURCE_DIR}/apple-symbol-imports.txt)
|
||||
@@ -351,6 +331,11 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND BUILD_TESTING)
|
||||
add_executable(real_data_bench RealDataBench.cpp)
|
||||
target_link_libraries(real_data_bench PRIVATE ${PROJECT_NAME})
|
||||
set_target_properties(real_data_bench PROPERTIES SKIP_BUILD_RPATH ON)
|
||||
|
||||
# fuzzer-based perf
|
||||
add_executable(driver_perf TestDriver.cpp)
|
||||
target_compile_definitions(driver_perf PRIVATE PERF_TEST=1)
|
||||
target_link_libraries(driver_perf PRIVATE ${PROJECT_NAME})
|
||||
endif()
|
||||
|
||||
# packaging
|
||||
|
2221
ConflictSet.cpp
2221
ConflictSet.cpp
File diff suppressed because it is too large
Load Diff
@@ -98,6 +98,13 @@ void ConflictSet::setOldestVersion(int64_t oldestVersion) {
|
||||
|
||||
int64_t ConflictSet::getBytes() const { return -1; }
|
||||
|
||||
void ConflictSet::getMetricsV1(MetricsV1 **metrics, int *count) const {
|
||||
*metrics = nullptr;
|
||||
*count = 0;
|
||||
}
|
||||
|
||||
double ConflictSet::MetricsV1::getValue() const { return 0; }
|
||||
|
||||
ConflictSet::ConflictSet(int64_t oldestVersion)
|
||||
: impl(new(safe_malloc(sizeof(Impl))) Impl{oldestVersion}) {}
|
||||
|
||||
|
231
Internal.h
231
Internal.h
@@ -467,13 +467,15 @@ inline uint32_t Arbitrary::bounded(uint32_t s) {
|
||||
// ==================== END ARBITRARY IMPL ====================
|
||||
|
||||
struct ReferenceImpl {
|
||||
explicit ReferenceImpl(int64_t oldestVersion) : oldestVersion(oldestVersion) {
|
||||
explicit ReferenceImpl(int64_t oldestVersion)
|
||||
: oldestVersion(oldestVersion), newestVersion(oldestVersion) {
|
||||
writeVersionMap[""] = oldestVersion;
|
||||
}
|
||||
void check(const ConflictSet::ReadRange *reads, ConflictSet::Result *results,
|
||||
int count) const {
|
||||
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;
|
||||
continue;
|
||||
}
|
||||
@@ -495,6 +497,8 @@ struct ReferenceImpl {
|
||||
}
|
||||
void addWrites(const ConflictSet::WriteRange *writes, int count,
|
||||
int64_t writeVersion) {
|
||||
assert(writeVersion >= newestVersion);
|
||||
newestVersion = writeVersion;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
auto begin =
|
||||
std::string((const char *)writes[i].begin.p, writes[i].begin.len);
|
||||
@@ -514,11 +518,12 @@ struct ReferenceImpl {
|
||||
}
|
||||
|
||||
void setOldestVersion(int64_t oldestVersion) {
|
||||
assert(oldestVersion >= oldestVersion);
|
||||
assert(oldestVersion >= this->oldestVersion);
|
||||
this->oldestVersion = oldestVersion;
|
||||
}
|
||||
|
||||
int64_t oldestVersion;
|
||||
int64_t newestVersion;
|
||||
std::map<std::string, int64_t> writeVersionMap;
|
||||
};
|
||||
|
||||
@@ -573,13 +578,17 @@ inline const char *resultToStr(ConflictSet::Result r) {
|
||||
|
||||
namespace {
|
||||
|
||||
template <class ConflictSetImpl> struct TestDriver {
|
||||
Arbitrary arbitrary;
|
||||
explicit TestDriver(const uint8_t *data, size_t size)
|
||||
: arbitrary({data, size}) {}
|
||||
template <class ConflictSetImpl, bool kEnableAssertions = true>
|
||||
struct TestDriver {
|
||||
Arbitrary *arbitrary;
|
||||
explicit TestDriver(Arbitrary &a) : arbitrary(&a) {
|
||||
#if DEBUG_VERBOSE && !defined(NDEBUG)
|
||||
fprintf(stderr, "%p Initial version: {%" PRId64 "}\n", this, writeVersion);
|
||||
#endif
|
||||
}
|
||||
|
||||
int64_t writeVersion = 100;
|
||||
int64_t oldestVersion = 0;
|
||||
int64_t oldestVersion = arbitrary->next();
|
||||
int64_t writeVersion = oldestVersion;
|
||||
ConflictSetImpl cs{oldestVersion};
|
||||
ReferenceImpl refImpl{oldestVersion};
|
||||
|
||||
@@ -587,31 +596,34 @@ template <class ConflictSetImpl> struct TestDriver {
|
||||
|
||||
bool ok = true;
|
||||
|
||||
const int prefixLen = arbitrary.bounded(512);
|
||||
const int prefixByte = arbitrary.randT<uint8_t>();
|
||||
const int prefixLen = arbitrary->bounded(512);
|
||||
const int prefixByte = arbitrary->randT<uint8_t>();
|
||||
|
||||
// Call until it returns true, for "done". Check internal invariants etc
|
||||
// between calls to next.
|
||||
bool next() {
|
||||
if (!arbitrary.hasEntropy()) {
|
||||
assert(cs.getBytes() >= 0);
|
||||
if (!arbitrary->hasEntropy()) {
|
||||
return true;
|
||||
}
|
||||
Arena arena;
|
||||
{
|
||||
int numPointWrites = arbitrary.bounded(100);
|
||||
int numRangeWrites = arbitrary.bounded(100);
|
||||
int64_t v = (writeVersion += arbitrary.bounded(10));
|
||||
int numPointWrites = arbitrary->bounded(100);
|
||||
int numRangeWrites = arbitrary->bounded(100);
|
||||
int64_t v =
|
||||
(writeVersion +=
|
||||
arbitrary->bounded(10) ? arbitrary->bounded(10) : arbitrary->next());
|
||||
auto *writes =
|
||||
new (arena) ConflictSet::WriteRange[numPointWrites + numRangeWrites];
|
||||
auto keys = set<std::string_view>(arena);
|
||||
while (int(keys.size()) < numPointWrites + numRangeWrites * 2) {
|
||||
if (!arbitrary.hasEntropy()) {
|
||||
if (!arbitrary->hasEntropy()) {
|
||||
return true;
|
||||
}
|
||||
int keyLen = prefixLen + arbitrary.bounded(kMaxKeySuffixLen);
|
||||
int keyLen = prefixLen + arbitrary->bounded(kMaxKeySuffixLen);
|
||||
auto *begin = new (arena) uint8_t[keyLen];
|
||||
memset(begin, prefixByte, prefixLen);
|
||||
arbitrary.randomBytes(begin + prefixLen, keyLen - prefixLen);
|
||||
arbitrary->randomBytes(begin + prefixLen, keyLen - prefixLen);
|
||||
keys.insert(std::string_view((const char *)begin, keyLen));
|
||||
}
|
||||
|
||||
@@ -621,7 +633,7 @@ template <class ConflictSetImpl> struct TestDriver {
|
||||
rangesRemaining = numRangeWrites;
|
||||
pointsRemaining > 0 || rangesRemaining > 0; ++i) {
|
||||
bool pointRead = pointsRemaining > 0 && rangesRemaining > 0
|
||||
? bool(arbitrary.bounded(2))
|
||||
? bool(arbitrary->bounded(2))
|
||||
: pointsRemaining > 0;
|
||||
if (pointRead) {
|
||||
assert(pointsRemaining > 0);
|
||||
@@ -640,46 +652,120 @@ template <class ConflictSetImpl> struct TestDriver {
|
||||
++iter;
|
||||
--rangesRemaining;
|
||||
}
|
||||
#if DEBUG_VERBOSE && !defined(NDEBUG)
|
||||
if (writes[i].end.len == 0) {
|
||||
fprintf(stderr, "Write: {%s} -> %" PRId64 "\n",
|
||||
printable(writes[i].begin).c_str(), writeVersion);
|
||||
} else {
|
||||
fprintf(stderr, "Write: [%s, %s) -> %" PRId64 "\n",
|
||||
printable(writes[i].begin).c_str(),
|
||||
printable(writes[i].end).c_str(), writeVersion);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
assert(iter == keys.end());
|
||||
assert(i == numPointWrites + numRangeWrites);
|
||||
|
||||
// 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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
oldestVersion +=
|
||||
arbitrary->bounded(10) ? arbitrary->bounded(10) : arbitrary->next();
|
||||
oldestVersion = std::min(oldestVersion, writeVersion);
|
||||
|
||||
#ifdef THREAD_TEST
|
||||
std::latch ready{1};
|
||||
std::thread thread2{[&]() {
|
||||
ready.count_down();
|
||||
ConflictSet::MetricsV1 *m;
|
||||
int count;
|
||||
cs.getMetricsV1(&m, &count);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
m[i].getValue();
|
||||
}
|
||||
}};
|
||||
ready.wait();
|
||||
#endif
|
||||
|
||||
#if DEBUG_VERBOSE && !defined(NDEBUG)
|
||||
for (int i = 0; i < numPointWrites + numRangeWrites; ++i) {
|
||||
if (writes[i].end.len == 0) {
|
||||
fprintf(stderr, "%p Write: {%s}\n", this,
|
||||
printable(writes[i].begin).c_str());
|
||||
} else {
|
||||
fprintf(stderr, "%p Write: [%s, %s)\n", this,
|
||||
printable(writes[i].begin).c_str(),
|
||||
printable(writes[i].end).c_str());
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "%p Write @ %" PRId64 "\n", this, v);
|
||||
#endif
|
||||
|
||||
CALLGRIND_START_INSTRUMENTATION;
|
||||
cs.addWrites(writes, numPointWrites + numRangeWrites, v);
|
||||
CALLGRIND_STOP_INSTRUMENTATION;
|
||||
|
||||
refImpl.addWrites(writes, numPointWrites + numRangeWrites, v);
|
||||
if constexpr (kEnableAssertions) {
|
||||
refImpl.addWrites(writes, numPointWrites + numRangeWrites, v);
|
||||
}
|
||||
|
||||
oldestVersion =
|
||||
std::min(writeVersion - 10, oldestVersion + arbitrary.bounded(10));
|
||||
#if DEBUG_VERBOSE && !defined(NDEBUG)
|
||||
fprintf(stderr, "%p Set oldest version: %" PRId64 "\n", this,
|
||||
oldestVersion);
|
||||
#endif
|
||||
cs.setOldestVersion(oldestVersion);
|
||||
refImpl.setOldestVersion(oldestVersion);
|
||||
if constexpr (kEnableAssertions) {
|
||||
refImpl.setOldestVersion(oldestVersion);
|
||||
}
|
||||
|
||||
#ifdef THREAD_TEST
|
||||
thread2.join();
|
||||
#endif
|
||||
}
|
||||
{
|
||||
int numPointReads = arbitrary.bounded(100);
|
||||
int numRangeReads = arbitrary.bounded(100);
|
||||
int64_t v = std::max<int64_t>(writeVersion - arbitrary.bounded(10), 0);
|
||||
int numPointReads = arbitrary->bounded(100);
|
||||
int numRangeReads = arbitrary->bounded(100);
|
||||
|
||||
int64_t v = std::max<int64_t>(writeVersion - (arbitrary->bounded(10)
|
||||
? arbitrary->bounded(10)
|
||||
: arbitrary->next()),
|
||||
0);
|
||||
auto *reads =
|
||||
new (arena) ConflictSet::ReadRange[numPointReads + numRangeReads];
|
||||
auto keys = set<std::string_view>(arena);
|
||||
while (int(keys.size()) < numPointReads + numRangeReads * 2) {
|
||||
if (!arbitrary.hasEntropy()) {
|
||||
if (!arbitrary->hasEntropy()) {
|
||||
return true;
|
||||
}
|
||||
int keyLen = prefixLen + arbitrary.bounded(kMaxKeySuffixLen);
|
||||
int keyLen = prefixLen + arbitrary->bounded(kMaxKeySuffixLen);
|
||||
auto *begin = new (arena) uint8_t[keyLen];
|
||||
memset(begin, prefixByte, prefixLen);
|
||||
arbitrary.randomBytes(begin + prefixLen, keyLen - prefixLen);
|
||||
arbitrary->randomBytes(begin + prefixLen, keyLen - prefixLen);
|
||||
keys.insert(std::string_view((const char *)begin, keyLen));
|
||||
}
|
||||
|
||||
@@ -688,7 +774,7 @@ template <class ConflictSetImpl> struct TestDriver {
|
||||
for (int pointsRemaining = numPointReads, rangesRemaining = numRangeReads;
|
||||
pointsRemaining > 0 || rangesRemaining > 0; ++i) {
|
||||
bool pointRead = pointsRemaining > 0 && rangesRemaining > 0
|
||||
? bool(arbitrary.bounded(2))
|
||||
? bool(arbitrary->bounded(2))
|
||||
: pointsRemaining > 0;
|
||||
if (pointRead) {
|
||||
assert(pointsRemaining > 0);
|
||||
@@ -710,12 +796,12 @@ template <class ConflictSetImpl> struct TestDriver {
|
||||
reads[i].readVersion = v;
|
||||
#if DEBUG_VERBOSE && !defined(NDEBUG)
|
||||
if (reads[i].end.len == 0) {
|
||||
fprintf(stderr, "Read: {%s} @ %d\n",
|
||||
printable(reads[i].begin).c_str(), int(reads[i].readVersion));
|
||||
fprintf(stderr, "%p Read: {%s} @ %" PRId64 "\n", this,
|
||||
printable(reads[i].begin).c_str(), reads[i].readVersion);
|
||||
} else {
|
||||
fprintf(stderr, "Read: [%s, %s) @ %d\n",
|
||||
fprintf(stderr, "%p Read: [%s, %s) @ %" PRId64 "\n", this,
|
||||
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
|
||||
}
|
||||
@@ -732,7 +818,15 @@ template <class ConflictSetImpl> struct TestDriver {
|
||||
std::latch ready{1};
|
||||
std::thread thread2{[&]() {
|
||||
ready.count_down();
|
||||
// Call all const methods
|
||||
cs.check(reads, results3, numPointReads + numRangeReads);
|
||||
cs.getBytes();
|
||||
ConflictSet::MetricsV1 *m;
|
||||
int count;
|
||||
cs.getMetricsV1(&m, &count);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
m[i].getValue();
|
||||
}
|
||||
}};
|
||||
ready.wait();
|
||||
#endif
|
||||
@@ -741,26 +835,40 @@ template <class ConflictSetImpl> struct TestDriver {
|
||||
cs.check(reads, results1, numPointReads + numRangeReads);
|
||||
CALLGRIND_STOP_INSTRUMENTATION;
|
||||
|
||||
refImpl.check(reads, results2, numPointReads + numRangeReads);
|
||||
if constexpr (kEnableAssertions) {
|
||||
// Call remaining const methods
|
||||
cs.getBytes();
|
||||
ConflictSet::MetricsV1 *m;
|
||||
int count;
|
||||
cs.getMetricsV1(&m, &count);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
m[i].getValue();
|
||||
}
|
||||
|
||||
auto compareResults = [reads](ConflictSet::Result *results1,
|
||||
ConflictSet::Result *results2, int count) {
|
||||
refImpl.check(reads, results2, numPointReads + numRangeReads);
|
||||
}
|
||||
|
||||
auto compareResults = [reads, this](ConflictSet::Result *results1,
|
||||
ConflictSet::Result *results2,
|
||||
int count) {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (results1[i] != results2[i]) {
|
||||
if (reads[i].end.len == 0) {
|
||||
fprintf(stderr,
|
||||
"Expected %s, got %s for read of {%s} at version %" PRId64
|
||||
"\n",
|
||||
resultToStr(results2[i]), resultToStr(results1[i]),
|
||||
printable(reads[i].begin).c_str(), reads[i].readVersion);
|
||||
} else {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Expected %s, got %s for read of [%s, %s) at version %" PRId64
|
||||
"%p Expected %s, got %s for read of {%s} at version %" PRId64
|
||||
"\n",
|
||||
resultToStr(results2[i]), resultToStr(results1[i]),
|
||||
printable(reads[i].begin).c_str(),
|
||||
printable(reads[i].end).c_str(), reads[i].readVersion);
|
||||
(void *)this, resultToStr(results2[i]),
|
||||
resultToStr(results1[i]), printable(reads[i].begin).c_str(),
|
||||
reads[i].readVersion);
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"%p Expected %s, got %s for read of [%s, %s) at version "
|
||||
"%" PRId64 "\n",
|
||||
(void *)this, resultToStr(results2[i]),
|
||||
resultToStr(results1[i]),
|
||||
printable(reads[i].begin).c_str(),
|
||||
printable(reads[i].end).c_str(), reads[i].readVersion);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -768,9 +876,12 @@ template <class ConflictSetImpl> struct TestDriver {
|
||||
return true;
|
||||
};
|
||||
|
||||
if (!compareResults(results1, results2, numPointReads + numRangeReads)) {
|
||||
ok = false;
|
||||
return true;
|
||||
if constexpr (kEnableAssertions) {
|
||||
if (!compareResults(results1, results2,
|
||||
numPointReads + numRangeReads)) {
|
||||
ok = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef THREAD_TEST
|
||||
|
18
Jenkinsfile
vendored
18
Jenkinsfile
vendored
@@ -48,6 +48,17 @@ pipeline {
|
||||
recordIssues(tools: [clang()])
|
||||
}
|
||||
}
|
||||
stage('Debug') {
|
||||
agent {
|
||||
dockerfile {
|
||||
args '-v /home/jenkins/ccache:/ccache'
|
||||
reuseNode true
|
||||
}
|
||||
}
|
||||
steps {
|
||||
CleanBuildAndTest("-DCMAKE_BUILD_TYPE=Debug")
|
||||
}
|
||||
}
|
||||
stage('SIMD fallback') {
|
||||
agent {
|
||||
dockerfile {
|
||||
@@ -106,13 +117,14 @@ pipeline {
|
||||
}
|
||||
}
|
||||
steps {
|
||||
CleanBuildAndTest("-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_C_FLAGS=--coverage -DCMAKE_CXX_FLAGS=--coverage -DCMAKE_BUILD_TYPE=Debug")
|
||||
CleanBuildAndTest("-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_C_FLAGS=--coverage -DCMAKE_CXX_FLAGS=--coverage -DCMAKE_BUILD_TYPE=Debug -DDISABLE_TSAN=ON")
|
||||
sh '''
|
||||
gcovr -f ConflictSet.cpp --cobertura > build/coverage.xml
|
||||
'''
|
||||
cobertura autoUpdateHealth: false, autoUpdateStability: false, coberturaReportFile: 'build/coverage.xml', conditionalCoverageTargets: '70, 0, 0', failUnhealthy: false, failUnstable: false, lineCoverageTargets: '80, 0, 0', maxNumberOfBuilds: 0, methodCoverageTargets: '80, 0, 0', onlyStable: false, sourceEncoding: 'ASCII', zoomCoverageChart: false
|
||||
recordCoverage qualityGates: [[criticality: 'NOTE', metric: 'MODULE']], tools: [[parser: 'COBERTURA', pattern: 'build/coverage.xml']]
|
||||
sh '''
|
||||
gcovr -f ConflictSet.cpp --fail-under-line 100 > /dev/null
|
||||
# Suppress again, because we haven't dealt with function multi-versioning for x86 yet
|
||||
# gcovr -f ConflictSet.cpp --fail-under-line 100 > /dev/null
|
||||
'''
|
||||
}
|
||||
}
|
||||
|
38
README.md
38
README.md
@@ -58,27 +58,29 @@ Performance counters:
|
||||
|
||||
## Skip list
|
||||
|
||||
| ns/op | op/s | err% | total | benchmark |
|
||||
| -----: | -----------: | ---: | ----: | :---------------------------------- |
|
||||
| 246.99 | 4,048,700.59 | 0.2% | 0.01 | `point reads` |
|
||||
| 260.16 | 3,843,784.65 | 0.1% | 0.01 | `prefix reads` |
|
||||
| 493.35 | 2,026,953.19 | 0.1% | 0.01 | `range reads` |
|
||||
| 462.05 | 2,164,289.23 | 0.6% | 0.01 | `point writes` |
|
||||
| 448.19 | 2,231,205.25 | 0.9% | 0.01 | `prefix writes` |
|
||||
| 255.83 | 3,908,845.72 | 1.5% | 0.02 | `range writes` |
|
||||
| 582.63 | 1,716,349.02 | 1.3% | 0.01 | `monotonic increasing point writes` |
|
||||
| ns/op | op/s | err% | total | benchmark
|
||||
|--------------------:|--------------------:|--------:|----------:|:----------
|
||||
| 245.99 | 4,065,232.81 | 0.3% | 0.01 | `point reads`
|
||||
| 265.93 | 3,760,430.49 | 0.2% | 0.01 | `prefix reads`
|
||||
| 485.30 | 2,060,569.50 | 0.2% | 0.01 | `range reads`
|
||||
| 449.60 | 2,224,195.17 | 0.4% | 0.01 | `point writes`
|
||||
| 441.76 | 2,263,688.18 | 1.1% | 0.01 | `prefix writes`
|
||||
| 245.42 | 4,074,647.54 | 2.4% | 0.02 | `range writes`
|
||||
| 572.80 | 1,745,810.06 | 1.3% | 0.01 | `monotonic increasing point writes`
|
||||
| 154,819.33 | 6,459.14 | 0.9% | 0.01 | `worst case for radix tree`
|
||||
|
||||
## Radix tree (this implementation)
|
||||
|
||||
| ns/op | op/s | err% | total | benchmark |
|
||||
| -----: | ------------: | ---: | ----: | :---------------------------------- |
|
||||
| 19.42 | 51,483,206.67 | 0.3% | 0.01 | `point reads` |
|
||||
| 58.43 | 17,115,612.57 | 0.1% | 0.01 | `prefix reads` |
|
||||
| 216.09 | 4,627,766.60 | 0.2% | 0.01 | `range reads` |
|
||||
| 28.35 | 35,267,567.72 | 0.2% | 0.01 | `point writes` |
|
||||
| 43.43 | 23,026,226.17 | 0.2% | 0.01 | `prefix writes` |
|
||||
| 50.00 | 20,000,000.00 | 0.0% | 0.01 | `range writes` |
|
||||
| 92.38 | 10,824,863.69 | 4.1% | 0.01 | `monotonic increasing point writes` |
|
||||
| ns/op | op/s | err% | total | benchmark
|
||||
|--------------------:|--------------------:|--------:|----------:|:----------
|
||||
| 19.17 | 52,163,930.66 | 0.1% | 0.01 | `point reads`
|
||||
| 23.68 | 42,224,388.21 | 0.7% | 0.01 | `prefix reads`
|
||||
| 63.30 | 15,797,506.06 | 0.9% | 0.01 | `range reads`
|
||||
| 29.66 | 33,720,994.74 | 0.3% | 0.01 | `point writes`
|
||||
| 43.50 | 22,987,781.25 | 1.0% | 0.01 | `prefix writes`
|
||||
| 50.00 | 20,000,000.00 | 0.8% | 0.01 | `range writes`
|
||||
| 103.25 | 9,684,786.47 | 2.9% | 0.01 | `monotonic increasing point writes`
|
||||
| 1,181,500.00 | 846.38 | 2.3% | 0.01 | `worst case for radix tree`
|
||||
|
||||
# "Real data" test
|
||||
|
||||
|
@@ -129,6 +129,16 @@ int main(int argc, const char **argv) {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
ConflictSet::MetricsV1 *metrics;
|
||||
int metricsCount;
|
||||
cs.getMetricsV1(&metrics, &metricsCount);
|
||||
for (int i = 0; i < metricsCount; ++i) {
|
||||
printf("# HELP %s %s\n", metrics[i].name, metrics[i].help);
|
||||
printf("# TYPE %s %s\n", metrics[i].name,
|
||||
metrics[i].type == metrics[i].Counter ? "counter" : "gauge");
|
||||
printf("%s %g\n", metrics[i].name, metrics[i].getValue());
|
||||
}
|
||||
|
||||
printf("Check: %g seconds, %g MB/s, Add: %g seconds, %g MB/s, Gc ratio: "
|
||||
"%g%%, Peak idle memory: %g\n",
|
||||
checkTime, checkBytes / checkTime * 1e-6, addTime,
|
||||
|
205
SkipList.cpp
205
SkipList.cpp
@@ -22,6 +22,8 @@
|
||||
|
||||
#include "ConflictSet.h"
|
||||
#include "Internal.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <span>
|
||||
|
||||
std::span<const uint8_t> keyAfter(Arena &arena, std::span<const uint8_t> key) {
|
||||
@@ -40,7 +42,7 @@ std::span<const uint8_t> copyToArena(Arena &arena,
|
||||
}
|
||||
|
||||
using Version = int64_t;
|
||||
#define force_inline __attribute__((always_inline))
|
||||
#define force_inline inline __attribute__((always_inline))
|
||||
using StringRef = std::span<const uint8_t>;
|
||||
|
||||
struct KeyRangeRef {
|
||||
@@ -52,6 +54,135 @@ struct KeyRangeRef {
|
||||
: 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 inline int skfastrand() {
|
||||
@@ -577,7 +708,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 +724,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,8 +733,40 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
|
||||
void addWrites(const ConflictSet::WriteRange *writes, int count,
|
||||
int64_t writeVersion) {
|
||||
auto points = std::vector<KeyInfo>(count * 2);
|
||||
Arena arena;
|
||||
const int stringCount = count * 2;
|
||||
|
||||
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);
|
||||
newestVersion = writeVersion;
|
||||
const int stringCount = combinedWriteConflictRanges.size() * 2;
|
||||
|
||||
const int stripeSize = 16;
|
||||
SkipList::Finger fingers[stripeSize];
|
||||
@@ -612,15 +777,9 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
int ss = stringCount - (stripes - 1) * stripeSize;
|
||||
for (int s = stripes - 1; s >= 0; s--) {
|
||||
for (int i = 0; i * 2 < ss; ++i) {
|
||||
const auto &w = writes[s * stripeSize / 2 + i];
|
||||
#if DEBUG_VERBOSE
|
||||
printf("Write begin: %s\n", printable(w.begin).c_str());
|
||||
fflush(stdout);
|
||||
#endif
|
||||
values[i * 2] = {w.begin.p, size_t(w.begin.len)};
|
||||
values[i * 2 + 1] = w.end.len > 0
|
||||
? StringRef{w.end.p, size_t(w.end.len)}
|
||||
: keyAfter(arena, values[i * 2]);
|
||||
const auto &w = combinedWriteConflictRanges[s * stripeSize / 2 + i];
|
||||
values[i * 2] = w.first;
|
||||
values[i * 2 + 1] = w.second;
|
||||
keyUpdates += 3;
|
||||
}
|
||||
skipList.find(values, fingers, temp, ss);
|
||||
@@ -630,6 +789,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 +808,7 @@ private:
|
||||
Arena removalArena;
|
||||
std::span<const uint8_t> removalKey;
|
||||
int64_t oldestVersion;
|
||||
int64_t newestVersion;
|
||||
SkipList skipList;
|
||||
};
|
||||
|
||||
@@ -696,6 +857,16 @@ void internal_destroy(ConflictSet::Impl *impl) {
|
||||
|
||||
int64_t internal_getBytes(ConflictSet::Impl *impl) { return impl->totalBytes; }
|
||||
|
||||
void internal_getMetricsV1(ConflictSet::Impl *impl,
|
||||
ConflictSet::MetricsV1 **metrics, int *count) {
|
||||
*metrics = nullptr;
|
||||
*count = 0;
|
||||
}
|
||||
|
||||
double internal_getMetricValue(const ConflictSet::MetricsV1 *metric) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ConflictSet::check(const ReadRange *reads, Result *results,
|
||||
int count) const {
|
||||
internal_check(impl, reads, results, count);
|
||||
@@ -712,6 +883,14 @@ void ConflictSet::setOldestVersion(int64_t oldestVersion) {
|
||||
|
||||
int64_t ConflictSet::getBytes() const { return internal_getBytes(impl); }
|
||||
|
||||
void ConflictSet::getMetricsV1(MetricsV1 **metrics, int *count) const {
|
||||
return internal_getMetricsV1(impl, metrics, count);
|
||||
}
|
||||
|
||||
double ConflictSet::MetricsV1::getValue() const {
|
||||
return internal_getMetricValue(this);
|
||||
}
|
||||
|
||||
ConflictSet::ConflictSet(int64_t oldestVersion)
|
||||
: impl(internal_create(oldestVersion)) {}
|
||||
|
||||
|
@@ -3,17 +3,68 @@
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#ifndef PERF_TEST
|
||||
#define PERF_TEST 0
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
std::ifstream t(argv[i], std::ios::binary);
|
||||
std::stringstream buffer;
|
||||
buffer << t.rdbuf();
|
||||
auto str = buffer.str();
|
||||
TestDriver<ConflictSet> driver{(const uint8_t *)str.data(), str.size()};
|
||||
while (!driver.next())
|
||||
;
|
||||
if (!driver.ok) {
|
||||
abort();
|
||||
Arbitrary arbitrary({(const uint8_t *)str.data(), str.size()});
|
||||
TestDriver<ConflictSet, !PERF_TEST> driver1{arbitrary};
|
||||
TestDriver<ConflictSet, !PERF_TEST> driver2{arbitrary};
|
||||
bool done1 = false;
|
||||
bool done2 = false;
|
||||
for (;;) {
|
||||
if (!done1) {
|
||||
done1 = driver1.next();
|
||||
if (!driver1.ok) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
if (!done2) {
|
||||
done2 = driver2.next();
|
||||
if (!driver2.ok) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
if (done1 && done2) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
ConflictSet::MetricsV1 *metrics;
|
||||
int metricsCount;
|
||||
driver1.cs.getMetricsV1(&metrics, &metricsCount);
|
||||
printf("#################### METRICS for ConflictSet 1 for %s "
|
||||
"####################\n",
|
||||
argv[i]);
|
||||
for (int i = 0; i < metricsCount; ++i) {
|
||||
printf("# HELP %s %s\n", metrics[i].name, metrics[i].help);
|
||||
printf("# TYPE %s %s\n", metrics[i].name,
|
||||
metrics[i].type == metrics[i].Counter ? "counter" : "gauge");
|
||||
printf("%s %g\n", metrics[i].name, metrics[i].getValue());
|
||||
}
|
||||
puts("");
|
||||
}
|
||||
{
|
||||
ConflictSet::MetricsV1 *metrics;
|
||||
int metricsCount;
|
||||
driver2.cs.getMetricsV1(&metrics, &metricsCount);
|
||||
printf("#################### METRICS for ConflictSet 2 for %s "
|
||||
"####################\n",
|
||||
argv[i]);
|
||||
for (int i = 0; i < metricsCount; ++i) {
|
||||
printf("# HELP %s %s\n", metrics[i].name, metrics[i].help);
|
||||
printf("# TYPE %s %s\n", metrics[i].name,
|
||||
metrics[i].type == metrics[i].Counter ? "counter" : "gauge");
|
||||
printf("%s %g\n", metrics[i].name, metrics[i].getValue());
|
||||
}
|
||||
puts("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,3 +1,5 @@
|
||||
__aarch64_ldadd8_relax
|
||||
__getauxval@GLIBC_2.17
|
||||
__stack_chk_fail@GLIBC_2.17
|
||||
__stack_chk_guard@GLIBC_2.17
|
||||
abort@GLIBC_2.17
|
||||
|
@@ -13,5 +13,7 @@ __ZN8weaselab11ConflictSetC2Ex
|
||||
__ZN8weaselab11ConflictSetD1Ev
|
||||
__ZN8weaselab11ConflictSetD2Ev
|
||||
__ZN8weaselab11ConflictSetaSEOS0_
|
||||
__ZNK8weaselab11ConflictSet12getMetricsV1EPPNS0_9MetricsV1EPi
|
||||
__ZNK8weaselab11ConflictSet5checkEPKNS0_9ReadRangeEPNS0_6ResultEi
|
||||
__ZNK8weaselab11ConflictSet8getBytesEv
|
||||
__ZNK8weaselab11ConflictSet9MetricsV18getValueEv
|
@@ -1,3 +1,5 @@
|
||||
___stack_chk_fail
|
||||
___stack_chk_guard
|
||||
__tlv_bootstrap
|
||||
_abort
|
||||
_bzero
|
||||
|
@@ -115,7 +115,9 @@ class ConflictSet:
|
||||
|
||||
def check(self, *reads: ReadRange) -> list[Result]:
|
||||
r = (ctypes.c_int * len(reads))()
|
||||
self._lib.ConflictSet_check(self.p, *reads, r, 1)
|
||||
self._lib.ConflictSet_check(
|
||||
self.p, (ReadRange * len(reads))(*reads), r, len(reads)
|
||||
)
|
||||
return [Result(x) for x in r]
|
||||
|
||||
def setOldestVersion(self, version: int) -> None:
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#include "ConflictSet.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
|
||||
using namespace weaselab;
|
||||
|
||||
@@ -21,4 +22,14 @@ int main(void) {
|
||||
assert(result == ConflictSet::Conflict);
|
||||
int64_t bytes = cs.getBytes();
|
||||
assert(bytes > 0);
|
||||
|
||||
ConflictSet::MetricsV1 *metrics;
|
||||
int metricsCount;
|
||||
cs.getMetricsV1(&metrics, &metricsCount);
|
||||
for (int i = 0; i < metricsCount; ++i) {
|
||||
printf("# HELP %s %s\n", metrics[i].name, metrics[i].help);
|
||||
printf("# TYPE %s %s\n", metrics[i].name,
|
||||
metrics[i].type == metrics[i].Counter ? "counter" : "gauge");
|
||||
printf("%s %g\n", metrics[i].name, metrics[i].getValue());
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
BIN
corpus/004a3d124875e031f4c28421b43c131abda8f376
Normal file
BIN
corpus/004a3d124875e031f4c28421b43c131abda8f376
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/0092e9f642b6f4d2cc1f3e6a16bf59624107aa1d
Normal file
BIN
corpus/0092e9f642b6f4d2cc1f3e6a16bf59624107aa1d
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/0112c3723c9ab42395c0f74e446998c0c63e8aef
Normal file
BIN
corpus/0112c3723c9ab42395c0f74e446998c0c63e8aef
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/01a8d6a44f22aa06b638a795f8a2dffd1ba9b0a8
Normal file
BIN
corpus/01a8d6a44f22aa06b638a795f8a2dffd1ba9b0a8
Normal file
Binary file not shown.
BIN
corpus/01ce88737ddc4d23f78bd6fe13dfbb5e1c5ffb18
Normal file
BIN
corpus/01ce88737ddc4d23f78bd6fe13dfbb5e1c5ffb18
Normal file
Binary file not shown.
BIN
corpus/021f64c6c477dc26894e5bc701554b1187fd3d0b
Normal file
BIN
corpus/021f64c6c477dc26894e5bc701554b1187fd3d0b
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/02fa9006f44b0d14655ffc31635a1a9df302225f
Normal file
BIN
corpus/02fa9006f44b0d14655ffc31635a1a9df302225f
Normal file
Binary file not shown.
BIN
corpus/04113be6af30d9ce06aa1da99259f797dee4b827
Normal file
BIN
corpus/04113be6af30d9ce06aa1da99259f797dee4b827
Normal file
Binary file not shown.
BIN
corpus/046d2c5bf09695809fe03ce5e8650ee03c86e767
Normal file
BIN
corpus/046d2c5bf09695809fe03ce5e8650ee03c86e767
Normal file
Binary file not shown.
BIN
corpus/048559df8c0ed2fdf38a177d7fe1afb40f3d034d
Normal file
BIN
corpus/048559df8c0ed2fdf38a177d7fe1afb40f3d034d
Normal file
Binary file not shown.
BIN
corpus/04cf08496c406ee4442f596a87000a1768cd0a94
Normal file
BIN
corpus/04cf08496c406ee4442f596a87000a1768cd0a94
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/06a3915af45c58d5edad76f7192d00dc71aefdc3
Normal file
BIN
corpus/06a3915af45c58d5edad76f7192d00dc71aefdc3
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/06dcf68e4bdbe913d3b272e3d4b1dc6f77309f2d
Normal file
BIN
corpus/06dcf68e4bdbe913d3b272e3d4b1dc6f77309f2d
Normal file
Binary file not shown.
BIN
corpus/06e7021fcbe50e9fd239738577bc87e54ac491b2
Normal file
BIN
corpus/06e7021fcbe50e9fd239738577bc87e54ac491b2
Normal file
Binary file not shown.
BIN
corpus/076402dbe642f66076a44d56c79034eeec433142
Normal file
BIN
corpus/076402dbe642f66076a44d56c79034eeec433142
Normal file
Binary file not shown.
BIN
corpus/08a5364e7da8be32f3dbffcb5ad9fc636cdfb461
Normal file
BIN
corpus/08a5364e7da8be32f3dbffcb5ad9fc636cdfb461
Normal file
Binary file not shown.
BIN
corpus/09f7205079111282e06b972b7b0148077c780a15
Normal file
BIN
corpus/09f7205079111282e06b972b7b0148077c780a15
Normal file
Binary file not shown.
BIN
corpus/0a95ed480d47305499128ff09afba6bbdbec5a5c
Normal file
BIN
corpus/0a95ed480d47305499128ff09afba6bbdbec5a5c
Normal file
Binary file not shown.
BIN
corpus/0ab276238fb98a371fafe99e7c98558c07baef7e
Normal file
BIN
corpus/0ab276238fb98a371fafe99e7c98558c07baef7e
Normal file
Binary file not shown.
BIN
corpus/0b471bdfb0cf6af786adf2cf8bc3fc1bae62860c
Normal file
BIN
corpus/0b471bdfb0cf6af786adf2cf8bc3fc1bae62860c
Normal file
Binary file not shown.
BIN
corpus/0b4ba4b5f7cc077a6f0ef5d48bcea80118ef7aa2
Normal file
BIN
corpus/0b4ba4b5f7cc077a6f0ef5d48bcea80118ef7aa2
Normal file
Binary file not shown.
BIN
corpus/0b4c470b5893ca01dd32e15b8082d48f48617fd1
Normal file
BIN
corpus/0b4c470b5893ca01dd32e15b8082d48f48617fd1
Normal file
Binary file not shown.
BIN
corpus/0b741f462204a40a55522bc307fcafa4099530cc
Normal file
BIN
corpus/0b741f462204a40a55522bc307fcafa4099530cc
Normal file
Binary file not shown.
BIN
corpus/0b90760335f1b17bc108bcff27a95ad88231d5e4
Normal file
BIN
corpus/0b90760335f1b17bc108bcff27a95ad88231d5e4
Normal file
Binary file not shown.
BIN
corpus/0ba4f637960e9e2696f9415be7bc6c5759bf927e
Normal file
BIN
corpus/0ba4f637960e9e2696f9415be7bc6c5759bf927e
Normal file
Binary file not shown.
BIN
corpus/0c93df22a52831a77be1e65a1d3c56d80825940b
Normal file
BIN
corpus/0c93df22a52831a77be1e65a1d3c56d80825940b
Normal file
Binary file not shown.
BIN
corpus/0d99bee638044b26e13b57a0db5ee82740dfd312
Normal file
BIN
corpus/0d99bee638044b26e13b57a0db5ee82740dfd312
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/0e1e4a2e118140a221e4bbc9251059c7a0e34f49
Normal file
BIN
corpus/0e1e4a2e118140a221e4bbc9251059c7a0e34f49
Normal file
Binary file not shown.
BIN
corpus/0ed829974af554e6c3b5ed9fb845333ccf5d8c1d
Normal file
BIN
corpus/0ed829974af554e6c3b5ed9fb845333ccf5d8c1d
Normal file
Binary file not shown.
BIN
corpus/0eebea0577f503e082c47691fec2651467eeaf5f
Normal file
BIN
corpus/0eebea0577f503e082c47691fec2651467eeaf5f
Normal file
Binary file not shown.
5
corpus/0f5c5f28c31e44ee0ec085fec09adf0981065771
Normal file
5
corpus/0f5c5f28c31e44ee0ec085fec09adf0981065771
Normal file
@@ -0,0 +1,5 @@
|
||||
|
||||
<EFBFBD><EFBFBD>
|
||||
|
||||
|
||||
2
|
BIN
corpus/104fd2d945317d09b2c44ea57e9e333f49115c76
Normal file
BIN
corpus/104fd2d945317d09b2c44ea57e9e333f49115c76
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/123d84d187ef92218bcb439255db737cae375151
Normal file
BIN
corpus/123d84d187ef92218bcb439255db737cae375151
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/129a26abd16441eb995a2fad52fbce02112e4d20
Normal file
BIN
corpus/129a26abd16441eb995a2fad52fbce02112e4d20
Normal file
Binary file not shown.
1
corpus/12bdd00fd4038756cbcf8ecdad1b0cd862603cd8
Normal file
1
corpus/12bdd00fd4038756cbcf8ecdad1b0cd862603cd8
Normal file
@@ -0,0 +1 @@
|
||||
<EFBFBD>
|
BIN
corpus/12cea490706f122949fa348f9de2a3ace31d56d2
Normal file
BIN
corpus/12cea490706f122949fa348f9de2a3ace31d56d2
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/12ecc1deca18dccdf8459fe63905bf51ced8b776
Normal file
BIN
corpus/12ecc1deca18dccdf8459fe63905bf51ced8b776
Normal file
Binary file not shown.
BIN
corpus/131c2ff7d2742dc4f468d6c87c4e3964a95db144
Normal file
BIN
corpus/131c2ff7d2742dc4f468d6c87c4e3964a95db144
Normal file
Binary file not shown.
BIN
corpus/1363c70a6cb83cf8f0d79c316449b7b59aebf68d
Normal file
BIN
corpus/1363c70a6cb83cf8f0d79c316449b7b59aebf68d
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/147776bc8ae88fe97d2d51a00d5868a981cdd44d
Normal file
BIN
corpus/147776bc8ae88fe97d2d51a00d5868a981cdd44d
Normal file
Binary file not shown.
BIN
corpus/1478958bdc54001cb65507dc6b98bfd35d00c3b2
Normal file
BIN
corpus/1478958bdc54001cb65507dc6b98bfd35d00c3b2
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/159a974ac30ebe83f44dea1d43b6cdd45bcb56b3
Normal file
BIN
corpus/159a974ac30ebe83f44dea1d43b6cdd45bcb56b3
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/16638187a55c2c126a8b6f46cbb708e83573c1ea
Normal file
BIN
corpus/16638187a55c2c126a8b6f46cbb708e83573c1ea
Normal file
Binary file not shown.
BIN
corpus/169a539673da8f98fd8a6941b36bdb80622e5d68
Normal file
BIN
corpus/169a539673da8f98fd8a6941b36bdb80622e5d68
Normal file
Binary file not shown.
BIN
corpus/16bae93ce7f55257f650cc0e095b613191e07e0c
Normal file
BIN
corpus/16bae93ce7f55257f650cc0e095b613191e07e0c
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/18e24277a0bc2a47e9262fd2282ca68f5aa5c09b
Normal file
BIN
corpus/18e24277a0bc2a47e9262fd2282ca68f5aa5c09b
Normal file
Binary file not shown.
BIN
corpus/19149503d26fa7a5add35147a8b77dd436213003
Normal file
BIN
corpus/19149503d26fa7a5add35147a8b77dd436213003
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/1a9cbbcb6e0d6ea624ac16e0e72a420056f60885
Normal file
BIN
corpus/1a9cbbcb6e0d6ea624ac16e0e72a420056f60885
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/1bdd11c6a929e0695d33db2b25136d11b786747a
Normal file
BIN
corpus/1bdd11c6a929e0695d33db2b25136d11b786747a
Normal file
Binary file not shown.
BIN
corpus/1be0b3f143ffa33fae34725306c6c07d6175e01a
Normal file
BIN
corpus/1be0b3f143ffa33fae34725306c6c07d6175e01a
Normal file
Binary file not shown.
BIN
corpus/1c3b103b6b47a392401f1354f2fd53f882e81541
Normal file
BIN
corpus/1c3b103b6b47a392401f1354f2fd53f882e81541
Normal file
Binary file not shown.
BIN
corpus/1c999c8cb335e3cc099a6220bab1a43d69164540
Normal file
BIN
corpus/1c999c8cb335e3cc099a6220bab1a43d69164540
Normal file
Binary file not shown.
BIN
corpus/1d41b59576afaad2b0e6171aa048e13c5600a558
Normal file
BIN
corpus/1d41b59576afaad2b0e6171aa048e13c5600a558
Normal file
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 1.6 KiB |
BIN
corpus/1dace1035ef72ca4dd3f0c9c217634e2ac837c48
Normal file
BIN
corpus/1dace1035ef72ca4dd3f0c9c217634e2ac837c48
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/1e63a3b3aeec146191fbbaad648701cd41bc97ef
Normal file
BIN
corpus/1e63a3b3aeec146191fbbaad648701cd41bc97ef
Normal file
Binary file not shown.
BIN
corpus/1e70de3ac55fc099d0dd133bd0248ed91401988b
Normal file
BIN
corpus/1e70de3ac55fc099d0dd133bd0248ed91401988b
Normal file
Binary file not shown.
BIN
corpus/1f0e2ccc9377b5e95e6a748d0e5112d2e0407a60
Normal file
BIN
corpus/1f0e2ccc9377b5e95e6a748d0e5112d2e0407a60
Normal file
Binary file not shown.
BIN
corpus/1fe46a88229ae619464d25a56d9f85e14c997f70
Normal file
BIN
corpus/1fe46a88229ae619464d25a56d9f85e14c997f70
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/208815c5ad2a89aef3198b279a8cf313246607a1
Normal file
BIN
corpus/208815c5ad2a89aef3198b279a8cf313246607a1
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