Compare commits
56 Commits
v0.0.7
...
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 |
@@ -358,7 +358,14 @@ void benchWorstCaseForRadixRangeRead() {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void benchCreateAndDestroy() {
|
||||||
|
ankerl::nanobench::Bench bench;
|
||||||
|
|
||||||
|
bench.run("create and destroy", [&]() { ConflictSet cs{0}; });
|
||||||
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
benchConflictSet();
|
benchConflictSet();
|
||||||
benchWorstCaseForRadixRangeRead();
|
benchWorstCaseForRadixRangeRead();
|
||||||
|
benchCreateAndDestroy();
|
||||||
}
|
}
|
||||||
|
@@ -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.10
|
||||||
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"
|
||||||
@@ -19,12 +19,6 @@ include(CheckCXXSourceCompiles)
|
|||||||
|
|
||||||
set(DEFAULT_BUILD_TYPE "Release")
|
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)
|
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||||
message(
|
message(
|
||||||
STATUS
|
STATUS
|
||||||
@@ -60,6 +54,8 @@ 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(DISABLE_TSAN "Disable TSAN" 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
|
||||||
include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/valgrind)
|
include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/valgrind)
|
||||||
@@ -79,15 +75,6 @@ if(EMSCRIPTEN)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT USE_SIMD_FALLBACK)
|
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()
|
cmake_push_check_state()
|
||||||
list(APPEND CMAKE_REQUIRED_FLAGS -mavx)
|
list(APPEND CMAKE_REQUIRED_FLAGS -mavx)
|
||||||
check_include_file_cxx("immintrin.h" HAS_AVX)
|
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/*)
|
file(GLOB CORPUS_TESTS ${CMAKE_CURRENT_SOURCE_DIR}/corpus/*)
|
||||||
|
|
||||||
# extra testing that relies on shared libraries, which aren't available with
|
# Shared library version of FoundationDB's skip list implementation
|
||||||
# wasm
|
add_library(skip_list SHARED SkipList.cpp)
|
||||||
if(NOT WASM)
|
target_compile_options(skip_list PRIVATE -fno-exceptions -fvisibility=hidden)
|
||||||
# Shared library version of FoundationDB's skip list implementation
|
target_include_directories(skip_list
|
||||||
add_library(skip_list SHARED SkipList.cpp)
|
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
target_compile_options(skip_list PRIVATE -fno-exceptions
|
set_target_properties(
|
||||||
-fvisibility=hidden)
|
skip_list PROPERTIES LIBRARY_OUTPUT_DIRECTORY
|
||||||
target_include_directories(skip_list
|
"${CMAKE_CURRENT_BINARY_DIR}/skip_list")
|
||||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
set_target_properties(skip_list PROPERTIES OUTPUT_NAME ${PROJECT_NAME})
|
||||||
set_target_properties(
|
set_target_properties(skip_list PROPERTIES VERSION ${PROJECT_VERSION}
|
||||||
skip_list PROPERTIES LIBRARY_OUTPUT_DIRECTORY
|
SOVERSION ${PROJECT_VERSION_MAJOR})
|
||||||
"${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
|
# Shared library version of a std::unordered_map-based conflict set (point
|
||||||
# queries only)
|
# queries only)
|
||||||
add_library(hash_table SHARED HashTable.cpp)
|
add_library(hash_table SHARED HashTable.cpp)
|
||||||
target_compile_options(hash_table PRIVATE -fno-exceptions
|
target_compile_options(hash_table PRIVATE -fno-exceptions -fvisibility=hidden)
|
||||||
-fvisibility=hidden)
|
target_include_directories(hash_table
|
||||||
target_include_directories(hash_table
|
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
set_target_properties(
|
||||||
set_target_properties(
|
hash_table PROPERTIES LIBRARY_OUTPUT_DIRECTORY
|
||||||
hash_table PROPERTIES LIBRARY_OUTPUT_DIRECTORY
|
"${CMAKE_CURRENT_BINARY_DIR}/hash_table")
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/hash_table")
|
set_target_properties(hash_table PROPERTIES OUTPUT_NAME ${PROJECT_NAME})
|
||||||
set_target_properties(hash_table PROPERTIES OUTPUT_NAME ${PROJECT_NAME})
|
set_target_properties(
|
||||||
set_target_properties(
|
hash_table PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION
|
||||||
hash_table PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION
|
${PROJECT_VERSION_MAJOR})
|
||||||
${PROJECT_VERSION_MAJOR})
|
|
||||||
|
|
||||||
add_executable(driver_skip_list TestDriver.cpp)
|
add_executable(driver_skip_list TestDriver.cpp)
|
||||||
target_compile_options(driver_skip_list PRIVATE ${TEST_FLAGS})
|
target_compile_options(driver_skip_list PRIVATE ${TEST_FLAGS})
|
||||||
target_link_libraries(driver_skip_list PRIVATE skip_list)
|
target_link_libraries(driver_skip_list PRIVATE skip_list)
|
||||||
|
|
||||||
foreach(TEST ${CORPUS_TESTS})
|
foreach(TEST ${CORPUS_TESTS})
|
||||||
get_filename_component(hash ${TEST} NAME)
|
get_filename_component(hash ${TEST} NAME)
|
||||||
add_test(NAME skip_list_${hash} COMMAND driver_skip_list ${TEST})
|
add_test(NAME skip_list_${hash} COMMAND driver_skip_list ${TEST})
|
||||||
endforeach()
|
endforeach()
|
||||||
endif()
|
|
||||||
|
|
||||||
# ad hoc testing
|
# ad hoc testing
|
||||||
add_executable(conflict_set_main ConflictSet.cpp)
|
add_executable(conflict_set_main ConflictSet.cpp)
|
||||||
@@ -245,7 +225,7 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND BUILD_TESTING)
|
|||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
# tsan tests
|
# 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)
|
add_executable(tsan_driver ConflictSet.cpp FuzzTestDriver.cpp)
|
||||||
target_compile_options(tsan_driver PRIVATE ${TEST_FLAGS} -fsanitize=thread)
|
target_compile_options(tsan_driver PRIVATE ${TEST_FLAGS} -fsanitize=thread)
|
||||||
target_link_options(tsan_driver PRIVATE -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)
|
add_test(NAME conflict_set_cxx_api_test COMMAND conflict_set_cxx_api_test)
|
||||||
|
|
||||||
# symbol visibility tests
|
# symbol visibility tests
|
||||||
if(NOT WASM AND NOT CMAKE_BUILD_TYPE STREQUAL Debug)
|
if(NOT CMAKE_BUILD_TYPE STREQUAL Debug)
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
set(symbol_exports ${CMAKE_CURRENT_SOURCE_DIR}/apple-symbol-exports.txt)
|
set(symbol_exports ${CMAKE_CURRENT_SOURCE_DIR}/apple-symbol-exports.txt)
|
||||||
set(symbol_imports ${CMAKE_CURRENT_SOURCE_DIR}/apple-symbol-imports.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)
|
add_executable(real_data_bench RealDataBench.cpp)
|
||||||
target_link_libraries(real_data_bench PRIVATE ${PROJECT_NAME})
|
target_link_libraries(real_data_bench PRIVATE ${PROJECT_NAME})
|
||||||
set_target_properties(real_data_bench PROPERTIES SKIP_BUILD_RPATH ON)
|
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()
|
endif()
|
||||||
|
|
||||||
# packaging
|
# packaging
|
||||||
|
562
ConflictSet.cpp
562
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; }
|
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)
|
ConflictSet::ConflictSet(int64_t oldestVersion)
|
||||||
: impl(new(safe_malloc(sizeof(Impl))) Impl{oldestVersion}) {}
|
: impl(new(safe_malloc(sizeof(Impl))) Impl{oldestVersion}) {}
|
||||||
|
|
||||||
|
212
Internal.h
212
Internal.h
@@ -578,12 +578,16 @@ inline const char *resultToStr(ConflictSet::Result r) {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
template <class ConflictSetImpl> struct TestDriver {
|
template <class ConflictSetImpl, bool kEnableAssertions = true>
|
||||||
Arbitrary arbitrary;
|
struct TestDriver {
|
||||||
explicit TestDriver(const uint8_t *data, size_t size)
|
Arbitrary *arbitrary;
|
||||||
: arbitrary({data, size}) {}
|
explicit TestDriver(Arbitrary &a) : arbitrary(&a) {
|
||||||
|
#if DEBUG_VERBOSE && !defined(NDEBUG)
|
||||||
|
fprintf(stderr, "%p Initial version: {%" PRId64 "}\n", this, writeVersion);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
int64_t oldestVersion = arbitrary.next();
|
int64_t oldestVersion = arbitrary->next();
|
||||||
int64_t writeVersion = oldestVersion;
|
int64_t writeVersion = oldestVersion;
|
||||||
ConflictSetImpl cs{oldestVersion};
|
ConflictSetImpl cs{oldestVersion};
|
||||||
ReferenceImpl refImpl{oldestVersion};
|
ReferenceImpl refImpl{oldestVersion};
|
||||||
@@ -592,33 +596,34 @@ template <class ConflictSetImpl> struct TestDriver {
|
|||||||
|
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
|
|
||||||
const int prefixLen = arbitrary.bounded(512);
|
const int prefixLen = arbitrary->bounded(512);
|
||||||
const int prefixByte = arbitrary.randT<uint8_t>();
|
const int prefixByte = arbitrary->randT<uint8_t>();
|
||||||
|
|
||||||
// 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);
|
assert(cs.getBytes() >= 0);
|
||||||
if (!arbitrary.hasEntropy()) {
|
if (!arbitrary->hasEntropy()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
Arena arena;
|
Arena arena;
|
||||||
{
|
{
|
||||||
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) ? arbitrary.bounded(10)
|
int64_t v =
|
||||||
: arbitrary.next());
|
(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);
|
||||||
while (int(keys.size()) < numPointWrites + numRangeWrites * 2) {
|
while (int(keys.size()) < numPointWrites + numRangeWrites * 2) {
|
||||||
if (!arbitrary.hasEntropy()) {
|
if (!arbitrary->hasEntropy()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
int keyLen = prefixLen + arbitrary.bounded(kMaxKeySuffixLen);
|
int keyLen = prefixLen + arbitrary->bounded(kMaxKeySuffixLen);
|
||||||
auto *begin = new (arena) uint8_t[keyLen];
|
auto *begin = new (arena) uint8_t[keyLen];
|
||||||
memset(begin, prefixByte, prefixLen);
|
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));
|
keys.insert(std::string_view((const char *)begin, keyLen));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -628,7 +633,7 @@ template <class ConflictSetImpl> struct TestDriver {
|
|||||||
rangesRemaining = numRangeWrites;
|
rangesRemaining = numRangeWrites;
|
||||||
pointsRemaining > 0 || rangesRemaining > 0; ++i) {
|
pointsRemaining > 0 || rangesRemaining > 0; ++i) {
|
||||||
bool pointRead = pointsRemaining > 0 && rangesRemaining > 0
|
bool pointRead = pointsRemaining > 0 && rangesRemaining > 0
|
||||||
? bool(arbitrary.bounded(2))
|
? bool(arbitrary->bounded(2))
|
||||||
: pointsRemaining > 0;
|
: pointsRemaining > 0;
|
||||||
if (pointRead) {
|
if (pointRead) {
|
||||||
assert(pointsRemaining > 0);
|
assert(pointsRemaining > 0);
|
||||||
@@ -647,54 +652,120 @@ template <class ConflictSetImpl> struct TestDriver {
|
|||||||
++iter;
|
++iter;
|
||||||
--rangesRemaining;
|
--rangesRemaining;
|
||||||
}
|
}
|
||||||
#if DEBUG_VERBOSE && !defined(NDEBUG)
|
|
||||||
if (writes[i].end.len == 0) {
|
|
||||||
fprintf(stderr, "Write: {%s}\n", printable(writes[i].begin).c_str());
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Write: [%s, %s)\n",
|
|
||||||
printable(writes[i].begin).c_str(),
|
|
||||||
printable(writes[i].end).c_str());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
assert(iter == keys.end());
|
assert(iter == keys.end());
|
||||||
assert(i == numPointWrites + numRangeWrites);
|
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)
|
#if DEBUG_VERBOSE && !defined(NDEBUG)
|
||||||
fprintf(stderr, "Write @ %" PRId64 "\n", v);
|
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
|
#endif
|
||||||
|
|
||||||
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);
|
if constexpr (kEnableAssertions) {
|
||||||
|
refImpl.addWrites(writes, numPointWrites + numRangeWrites, v);
|
||||||
|
}
|
||||||
|
|
||||||
oldestVersion +=
|
#if DEBUG_VERBOSE && !defined(NDEBUG)
|
||||||
arbitrary.bounded(10) ? arbitrary.bounded(10) : arbitrary.next();
|
fprintf(stderr, "%p Set oldest version: %" PRId64 "\n", this,
|
||||||
oldestVersion = std::min(oldestVersion, writeVersion);
|
oldestVersion);
|
||||||
|
#endif
|
||||||
cs.setOldestVersion(oldestVersion);
|
cs.setOldestVersion(oldestVersion);
|
||||||
refImpl.setOldestVersion(oldestVersion);
|
if constexpr (kEnableAssertions) {
|
||||||
|
refImpl.setOldestVersion(oldestVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef THREAD_TEST
|
||||||
|
thread2.join();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
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)
|
int64_t v = std::max<int64_t>(writeVersion - (arbitrary->bounded(10)
|
||||||
? arbitrary.bounded(10)
|
? arbitrary->bounded(10)
|
||||||
: arbitrary.next()),
|
: arbitrary->next()),
|
||||||
0);
|
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);
|
||||||
while (int(keys.size()) < numPointReads + numRangeReads * 2) {
|
while (int(keys.size()) < numPointReads + numRangeReads * 2) {
|
||||||
if (!arbitrary.hasEntropy()) {
|
if (!arbitrary->hasEntropy()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
int keyLen = prefixLen + arbitrary.bounded(kMaxKeySuffixLen);
|
int keyLen = prefixLen + arbitrary->bounded(kMaxKeySuffixLen);
|
||||||
auto *begin = new (arena) uint8_t[keyLen];
|
auto *begin = new (arena) uint8_t[keyLen];
|
||||||
memset(begin, prefixByte, prefixLen);
|
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));
|
keys.insert(std::string_view((const char *)begin, keyLen));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -703,7 +774,7 @@ template <class ConflictSetImpl> struct TestDriver {
|
|||||||
for (int pointsRemaining = numPointReads, rangesRemaining = numRangeReads;
|
for (int pointsRemaining = numPointReads, rangesRemaining = numRangeReads;
|
||||||
pointsRemaining > 0 || rangesRemaining > 0; ++i) {
|
pointsRemaining > 0 || rangesRemaining > 0; ++i) {
|
||||||
bool pointRead = pointsRemaining > 0 && rangesRemaining > 0
|
bool pointRead = pointsRemaining > 0 && rangesRemaining > 0
|
||||||
? bool(arbitrary.bounded(2))
|
? bool(arbitrary->bounded(2))
|
||||||
: pointsRemaining > 0;
|
: pointsRemaining > 0;
|
||||||
if (pointRead) {
|
if (pointRead) {
|
||||||
assert(pointsRemaining > 0);
|
assert(pointsRemaining > 0);
|
||||||
@@ -725,10 +796,10 @@ 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} @ %" PRId64 "\n",
|
fprintf(stderr, "%p Read: {%s} @ %" PRId64 "\n", this,
|
||||||
printable(reads[i].begin).c_str(), reads[i].readVersion);
|
printable(reads[i].begin).c_str(), reads[i].readVersion);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Read: [%s, %s) @ %" PRId64 "\n",
|
fprintf(stderr, "%p Read: [%s, %s) @ %" PRId64 "\n", this,
|
||||||
printable(reads[i].begin).c_str(),
|
printable(reads[i].begin).c_str(),
|
||||||
printable(reads[i].end).c_str(), reads[i].readVersion);
|
printable(reads[i].end).c_str(), reads[i].readVersion);
|
||||||
}
|
}
|
||||||
@@ -747,7 +818,15 @@ template <class ConflictSetImpl> struct TestDriver {
|
|||||||
std::latch ready{1};
|
std::latch ready{1};
|
||||||
std::thread thread2{[&]() {
|
std::thread thread2{[&]() {
|
||||||
ready.count_down();
|
ready.count_down();
|
||||||
|
// Call all const methods
|
||||||
cs.check(reads, results3, numPointReads + numRangeReads);
|
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();
|
ready.wait();
|
||||||
#endif
|
#endif
|
||||||
@@ -756,26 +835,40 @@ template <class ConflictSetImpl> struct TestDriver {
|
|||||||
cs.check(reads, results1, numPointReads + numRangeReads);
|
cs.check(reads, results1, numPointReads + numRangeReads);
|
||||||
CALLGRIND_STOP_INSTRUMENTATION;
|
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,
|
refImpl.check(reads, results2, numPointReads + numRangeReads);
|
||||||
ConflictSet::Result *results2, int count) {
|
}
|
||||||
|
|
||||||
|
auto compareResults = [reads, this](ConflictSet::Result *results1,
|
||||||
|
ConflictSet::Result *results2,
|
||||||
|
int count) {
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
if (results1[i] != results2[i]) {
|
if (results1[i] != results2[i]) {
|
||||||
if (reads[i].end.len == 0) {
|
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(
|
fprintf(
|
||||||
stderr,
|
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",
|
"\n",
|
||||||
resultToStr(results2[i]), resultToStr(results1[i]),
|
(void *)this, resultToStr(results2[i]),
|
||||||
printable(reads[i].begin).c_str(),
|
resultToStr(results1[i]), printable(reads[i].begin).c_str(),
|
||||||
printable(reads[i].end).c_str(), reads[i].readVersion);
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -783,9 +876,12 @@ template <class ConflictSetImpl> struct TestDriver {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!compareResults(results1, results2, numPointReads + numRangeReads)) {
|
if constexpr (kEnableAssertions) {
|
||||||
ok = false;
|
if (!compareResults(results1, results2,
|
||||||
return true;
|
numPointReads + numRangeReads)) {
|
||||||
|
ok = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef THREAD_TEST
|
#ifdef THREAD_TEST
|
||||||
|
24
Jenkinsfile
vendored
24
Jenkinsfile
vendored
@@ -48,6 +48,17 @@ pipeline {
|
|||||||
recordIssues(tools: [clang()])
|
recordIssues(tools: [clang()])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
stage('Debug') {
|
||||||
|
agent {
|
||||||
|
dockerfile {
|
||||||
|
args '-v /home/jenkins/ccache:/ccache'
|
||||||
|
reuseNode true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
CleanBuildAndTest("-DCMAKE_BUILD_TYPE=Debug")
|
||||||
|
}
|
||||||
|
}
|
||||||
stage('SIMD fallback') {
|
stage('SIMD fallback') {
|
||||||
agent {
|
agent {
|
||||||
dockerfile {
|
dockerfile {
|
||||||
@@ -59,17 +70,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 {
|
||||||
@@ -117,7 +117,7 @@ pipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
steps {
|
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 '''
|
sh '''
|
||||||
gcovr -f ConflictSet.cpp --cobertura > build/coverage.xml
|
gcovr -f ConflictSet.cpp --cobertura > build/coverage.xml
|
||||||
'''
|
'''
|
||||||
|
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
|
||||||
|
|
||||||
|
@@ -129,6 +129,16 @@ int main(int argc, const char **argv) {
|
|||||||
close(fd);
|
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: "
|
printf("Check: %g seconds, %g MB/s, Add: %g seconds, %g MB/s, Gc ratio: "
|
||||||
"%g%%, Peak idle memory: %g\n",
|
"%g%%, Peak idle memory: %g\n",
|
||||||
checkTime, checkBytes / checkTime * 1e-6, addTime,
|
checkTime, checkBytes / checkTime * 1e-6, addTime,
|
||||||
|
197
SkipList.cpp
197
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) {
|
||||||
@@ -40,7 +42,7 @@ std::span<const uint8_t> copyToArena(Arena &arena,
|
|||||||
}
|
}
|
||||||
|
|
||||||
using Version = int64_t;
|
using Version = int64_t;
|
||||||
#define force_inline __attribute__((always_inline))
|
#define force_inline inline __attribute__((always_inline))
|
||||||
using StringRef = std::span<const uint8_t>;
|
using StringRef = std::span<const uint8_t>;
|
||||||
|
|
||||||
struct KeyRangeRef {
|
struct KeyRangeRef {
|
||||||
@@ -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,9 @@ 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
|
values[i * 2] = w.first;
|
||||||
printf("Write begin: %s\n", printable(w.begin).c_str());
|
values[i * 2 + 1] = w.second;
|
||||||
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]);
|
|
||||||
keyUpdates += 3;
|
keyUpdates += 3;
|
||||||
}
|
}
|
||||||
skipList.find(values, fingers, temp, ss);
|
skipList.find(values, fingers, temp, ss);
|
||||||
@@ -702,6 +857,16 @@ void internal_destroy(ConflictSet::Impl *impl) {
|
|||||||
|
|
||||||
int64_t internal_getBytes(ConflictSet::Impl *impl) { return impl->totalBytes; }
|
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,
|
void ConflictSet::check(const ReadRange *reads, Result *results,
|
||||||
int count) const {
|
int count) const {
|
||||||
internal_check(impl, reads, results, count);
|
internal_check(impl, reads, results, count);
|
||||||
@@ -718,6 +883,14 @@ void ConflictSet::setOldestVersion(int64_t oldestVersion) {
|
|||||||
|
|
||||||
int64_t ConflictSet::getBytes() const { return internal_getBytes(impl); }
|
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)
|
ConflictSet::ConflictSet(int64_t oldestVersion)
|
||||||
: impl(internal_create(oldestVersion)) {}
|
: impl(internal_create(oldestVersion)) {}
|
||||||
|
|
||||||
|
@@ -3,17 +3,68 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
#ifndef PERF_TEST
|
||||||
|
#define PERF_TEST 0
|
||||||
|
#endif
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
for (int i = 1; i < argc; ++i) {
|
for (int i = 1; i < argc; ++i) {
|
||||||
std::ifstream t(argv[i], std::ios::binary);
|
std::ifstream t(argv[i], std::ios::binary);
|
||||||
std::stringstream buffer;
|
std::stringstream buffer;
|
||||||
buffer << t.rdbuf();
|
buffer << t.rdbuf();
|
||||||
auto str = buffer.str();
|
auto str = buffer.str();
|
||||||
TestDriver<ConflictSet> driver{(const uint8_t *)str.data(), str.size()};
|
Arbitrary arbitrary({(const uint8_t *)str.data(), str.size()});
|
||||||
while (!driver.next())
|
TestDriver<ConflictSet, !PERF_TEST> driver1{arbitrary};
|
||||||
;
|
TestDriver<ConflictSet, !PERF_TEST> driver2{arbitrary};
|
||||||
if (!driver.ok) {
|
bool done1 = false;
|
||||||
abort();
|
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_fail@GLIBC_2.17
|
||||||
__stack_chk_guard@GLIBC_2.17
|
__stack_chk_guard@GLIBC_2.17
|
||||||
abort@GLIBC_2.17
|
abort@GLIBC_2.17
|
||||||
|
@@ -13,5 +13,7 @@ __ZN8weaselab11ConflictSetC2Ex
|
|||||||
__ZN8weaselab11ConflictSetD1Ev
|
__ZN8weaselab11ConflictSetD1Ev
|
||||||
__ZN8weaselab11ConflictSetD2Ev
|
__ZN8weaselab11ConflictSetD2Ev
|
||||||
__ZN8weaselab11ConflictSetaSEOS0_
|
__ZN8weaselab11ConflictSetaSEOS0_
|
||||||
|
__ZNK8weaselab11ConflictSet12getMetricsV1EPPNS0_9MetricsV1EPi
|
||||||
__ZNK8weaselab11ConflictSet5checkEPKNS0_9ReadRangeEPNS0_6ResultEi
|
__ZNK8weaselab11ConflictSet5checkEPKNS0_9ReadRangeEPNS0_6ResultEi
|
||||||
__ZNK8weaselab11ConflictSet8getBytesEv
|
__ZNK8weaselab11ConflictSet8getBytesEv
|
||||||
|
__ZNK8weaselab11ConflictSet9MetricsV18getValueEv
|
@@ -1,6 +1,7 @@
|
|||||||
#include "ConflictSet.h"
|
#include "ConflictSet.h"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
using namespace weaselab;
|
using namespace weaselab;
|
||||||
|
|
||||||
@@ -21,4 +22,14 @@ int main(void) {
|
|||||||
assert(result == ConflictSet::Conflict);
|
assert(result == ConflictSet::Conflict);
|
||||||
int64_t bytes = cs.getBytes();
|
int64_t bytes = cs.getBytes();
|
||||||
assert(bytes > 0);
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
BIN
corpus/004a3d124875e031f4c28421b43c131abda8f376
Normal file
BIN
corpus/004a3d124875e031f4c28421b43c131abda8f376
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/0092e9f642b6f4d2cc1f3e6a16bf59624107aa1d
Normal file
BIN
corpus/0092e9f642b6f4d2cc1f3e6a16bf59624107aa1d
Normal file
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.
Binary file not shown.
BIN
corpus/02fa9006f44b0d14655ffc31635a1a9df302225f
Normal file
BIN
corpus/02fa9006f44b0d14655ffc31635a1a9df302225f
Normal file
Binary file not shown.
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.
Binary file not shown.
Binary file not shown.
BIN
corpus/06a3915af45c58d5edad76f7192d00dc71aefdc3
Normal file
BIN
corpus/06a3915af45c58d5edad76f7192d00dc71aefdc3
Normal file
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.
Binary file not shown.
Binary file not shown.
BIN
corpus/08a5364e7da8be32f3dbffcb5ad9fc636cdfb461
Normal file
BIN
corpus/08a5364e7da8be32f3dbffcb5ad9fc636cdfb461
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/09f7205079111282e06b972b7b0148077c780a15
Normal file
BIN
corpus/09f7205079111282e06b972b7b0148077c780a15
Normal file
Binary file not shown.
Binary file not shown.
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.
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.
Binary file not shown.
Binary file not shown.
BIN
corpus/0d99bee638044b26e13b57a0db5ee82740dfd312
Normal file
BIN
corpus/0d99bee638044b26e13b57a0db5ee82740dfd312
Normal file
Binary file not shown.
BIN
corpus/0e1e4a2e118140a221e4bbc9251059c7a0e34f49
Normal file
BIN
corpus/0e1e4a2e118140a221e4bbc9251059c7a0e34f49
Normal file
Binary file not shown.
Binary file not shown.
@@ -1,4 +0,0 @@
|
|||||||
*
|
|
||||||
|
|
||||||
|
|
||||||
|
|
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.
Binary file not shown.
BIN
corpus/123d84d187ef92218bcb439255db737cae375151
Normal file
BIN
corpus/123d84d187ef92218bcb439255db737cae375151
Normal file
Binary file not shown.
BIN
corpus/129a26abd16441eb995a2fad52fbce02112e4d20
Normal file
BIN
corpus/129a26abd16441eb995a2fad52fbce02112e4d20
Normal file
Binary file not shown.
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.
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.
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.
BIN
corpus/159a974ac30ebe83f44dea1d43b6cdd45bcb56b3
Normal file
BIN
corpus/159a974ac30ebe83f44dea1d43b6cdd45bcb56b3
Normal file
Binary file not shown.
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.
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.
BIN
corpus/1dace1035ef72ca4dd3f0c9c217634e2ac837c48
Normal file
BIN
corpus/1dace1035ef72ca4dd3f0c9c217634e2ac837c48
Normal file
Binary file not shown.
Binary file not shown.
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