Compare commits
86 Commits
26bd8b94cc
...
v0.0.1
Author | SHA1 | Date | |
---|---|---|---|
71c39f9955 | |||
8cc17158fd | |||
ab211c646a | |||
7af961f141 | |||
a91df62608 | |||
0a1843a161 | |||
4edf0315d9 | |||
14515e186a | |||
b0085df5ad | |||
76a7e17b29 | |||
5cf43d1bfa | |||
25cc427ec5 | |||
c15c2e7b44 | |||
a4d1f91670 | |||
b7cdecaf71 | |||
cda28643a6 | |||
cdb5360b9a | |||
ef224a60f4 | |||
6222b74787 | |||
19edc6f78f | |||
3f9d01c46a | |||
db03c6f901 | |||
c1698b040b | |||
2e08b54785 | |||
aa6f237d50 | |||
becfd25139 | |||
d78b36821b | |||
ce79b47fbe | |||
727b7e642a | |||
cb4c2b7e1e | |||
ef9b789745 | |||
edd7bcaa1e | |||
be8ac879c5 | |||
83c7f66d67 | |||
a5710b8282 | |||
c31eebd5de | |||
ddeb059968 | |||
5a0bcf9a5a | |||
97717cec86 | |||
6a13c43a78 | |||
c6c438bae2 | |||
7d4f832b43 | |||
5b0c3c2428 | |||
f2b5e9b0bf | |||
8e0e65dac6 | |||
5aab76847a | |||
1a51aa00e5 | |||
3975bada0c | |||
a5330b6e23 | |||
2e246ec6a4 | |||
6d7e3c9849 | |||
671da5d096 | |||
303b368fc5 | |||
9f5a68e2c0 | |||
dfbb3ce5f1 | |||
e7719b6e0b | |||
83fedf1f9e | |||
8556caf360 | |||
9d13ca84f5 | |||
a79436ee9b | |||
e9c8537cf2 | |||
5b988efe6f | |||
e35d698b21 | |||
30496d14e7 | |||
eb93157ddf | |||
9cafef8bbb | |||
6f81580953 | |||
429fe5baed | |||
a0451e4423 | |||
a9b3d3d1c9 | |||
b817e3c749 | |||
ee36bda8f8 | |||
a8f4bd91c8 | |||
35086ee66a | |||
0f795cf163 | |||
a07c93ffff | |||
c68f563017 | |||
6b6a9bace9 | |||
3cb0765fdd | |||
351ff3df3b | |||
e818648cdc | |||
12540b8713 | |||
c2606cd26a | |||
4b72fc0b7b | |||
a9caa0249e | |||
08b2b7f41a |
2
.clangd
2
.clangd
@@ -1,2 +1,2 @@
|
|||||||
CompileFlags:
|
CompileFlags:
|
||||||
Add: [-DENABLE_MAIN, -UNDEBUG, -DENABLE_FUZZ, -fexceptions]
|
Add: [-DENABLE_MAIN, -UNDEBUG, -DENABLE_FUZZ, -DTHREAD_TEST, -fexceptions]
|
||||||
|
@@ -34,7 +34,7 @@ ConflictSet::ReadRange singleton(Arena &arena, std::span<const uint8_t> key) {
|
|||||||
std::span<uint8_t>(new (arena) uint8_t[key.size() + 1], key.size() + 1);
|
std::span<uint8_t>(new (arena) uint8_t[key.size() + 1], key.size() + 1);
|
||||||
memcpy(r.data(), key.data(), key.size());
|
memcpy(r.data(), key.data(), key.size());
|
||||||
r[key.size()] = 0;
|
r[key.size()] = 0;
|
||||||
return {key.data(), int(key.size()), r.data(), int(r.size())};
|
return {{key.data(), int(key.size())}, {r.data(), int(r.size())}, 0};
|
||||||
}
|
}
|
||||||
|
|
||||||
ConflictSet::ReadRange prefixRange(Arena &arena, std::span<const uint8_t> key) {
|
ConflictSet::ReadRange prefixRange(Arena &arena, std::span<const uint8_t> key) {
|
||||||
@@ -52,7 +52,7 @@ ConflictSet::ReadRange prefixRange(Arena &arena, std::span<const uint8_t> key) {
|
|||||||
auto r = std::span<uint8_t>(new (arena) uint8_t[index + 1], index + 1);
|
auto r = std::span<uint8_t>(new (arena) uint8_t[index + 1], index + 1);
|
||||||
memcpy(r.data(), key.data(), index + 1);
|
memcpy(r.data(), key.data(), index + 1);
|
||||||
r[r.size() - 1]++;
|
r[r.size() - 1]++;
|
||||||
return {key.data(), int(key.size()), r.data(), int(r.size())};
|
return {{key.data(), int(key.size())}, {r.data(), int(r.size())}, 0};
|
||||||
}
|
}
|
||||||
|
|
||||||
void benchConflictSet() {
|
void benchConflictSet() {
|
||||||
@@ -258,4 +258,4 @@ void benchConflictSet() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void) { benchConflictSet(); }
|
int main(void) { benchConflictSet(); }
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
cmake_minimum_required(VERSION 3.18)
|
cmake_minimum_required(VERSION 3.18)
|
||||||
project(
|
project(
|
||||||
conflict_set
|
conflict-set
|
||||||
VERSION 0.0.1
|
VERSION 0.0.1
|
||||||
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."
|
||||||
@@ -22,7 +22,11 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
|||||||
"MinSizeRel" "RelWithDebInfo")
|
"MinSizeRel" "RelWithDebInfo")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_compile_options(-fdata-sections -ffunction-sections)
|
add_compile_options(-fdata-sections -ffunction-sections -Wswitch-enum
|
||||||
|
-Werror=switch-enum)
|
||||||
|
|
||||||
|
option(USE_SIMD_FALLBACK
|
||||||
|
"Use fallback implementations of functions that use SIMD" 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
|
||||||
@@ -42,18 +46,20 @@ endif()
|
|||||||
include(CheckIncludeFileCXX)
|
include(CheckIncludeFileCXX)
|
||||||
include(CMakePushCheckState)
|
include(CMakePushCheckState)
|
||||||
|
|
||||||
cmake_push_check_state()
|
if(NOT USE_SIMD_FALLBACK)
|
||||||
list(APPEND CMAKE_REQUIRED_FLAGS -mavx)
|
cmake_push_check_state()
|
||||||
check_include_file_cxx("immintrin.h" HAS_AVX)
|
list(APPEND CMAKE_REQUIRED_FLAGS -mavx)
|
||||||
if(HAS_AVX)
|
check_include_file_cxx("immintrin.h" HAS_AVX)
|
||||||
add_compile_options(-mavx)
|
if(HAS_AVX)
|
||||||
add_compile_definitions(HAS_AVX)
|
add_compile_options(-mavx)
|
||||||
endif()
|
add_compile_definitions(HAS_AVX)
|
||||||
cmake_pop_check_state()
|
endif()
|
||||||
|
cmake_pop_check_state()
|
||||||
|
|
||||||
check_include_file_cxx("arm_neon.h" HAS_ARM_NEON)
|
check_include_file_cxx("arm_neon.h" HAS_ARM_NEON)
|
||||||
if(HAS_ARM_NEON)
|
if(HAS_ARM_NEON)
|
||||||
add_compile_definitions(HAS_ARM_NEON)
|
add_compile_definitions(HAS_ARM_NEON)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "")
|
set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "")
|
||||||
@@ -77,19 +83,19 @@ if(NOT APPLE)
|
|||||||
LINKER:--version-script=${CMAKE_SOURCE_DIR}/linker.map)
|
LINKER:--version-script=${CMAKE_SOURCE_DIR}/linker.map)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_library(${PROJECT_NAME}_static STATIC
|
add_library(${PROJECT_NAME}-static STATIC
|
||||||
$<TARGET_OBJECTS:${PROJECT_NAME}_object>)
|
$<TARGET_OBJECTS:${PROJECT_NAME}_object>)
|
||||||
if(NOT CMAKE_BUILD_TYPE STREQUAL Debug)
|
if(NOT CMAKE_BUILD_TYPE STREQUAL Debug)
|
||||||
set_target_properties(${PROJECT_NAME}_static PROPERTIES LINKER_LANGUAGE C)
|
set_target_properties(${PROJECT_NAME}-static PROPERTIES LINKER_LANGUAGE C)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT APPLE AND CMAKE_OBJCOPY)
|
if(NOT APPLE AND CMAKE_OBJCOPY)
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
TARGET conflict_set_static
|
TARGET conflict-set-static
|
||||||
POST_BUILD
|
POST_BUILD
|
||||||
COMMAND
|
COMMAND
|
||||||
${CMAKE_OBJCOPY} --keep-global-symbols=${CMAKE_SOURCE_DIR}/symbols.txt
|
${CMAKE_OBJCOPY} --keep-global-symbols=${CMAKE_SOURCE_DIR}/symbols.txt
|
||||||
$<TARGET_FILE:${PROJECT_NAME}_static>)
|
$<TARGET_FILE:${PROJECT_NAME}-static>)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(TEST_FLAGS -Wall -Wextra -Wunreachable-code -Wpedantic -UNDEBUG)
|
set(TEST_FLAGS -Wall -Wextra -Wunreachable-code -Wpedantic -UNDEBUG)
|
||||||
@@ -154,6 +160,10 @@ if(BUILD_TESTING)
|
|||||||
|
|
||||||
add_executable(fuzz_driver ConflictSet.cpp FuzzTestDriver.cpp)
|
add_executable(fuzz_driver ConflictSet.cpp FuzzTestDriver.cpp)
|
||||||
target_compile_options(fuzz_driver PRIVATE ${TEST_FLAGS})
|
target_compile_options(fuzz_driver PRIVATE ${TEST_FLAGS})
|
||||||
|
if(NOT CMAKE_CROSSCOMPILING)
|
||||||
|
target_compile_options(fuzz_driver PRIVATE -fsanitize=address,undefined)
|
||||||
|
target_link_options(fuzz_driver PRIVATE -fsanitize=address,undefined)
|
||||||
|
endif()
|
||||||
target_compile_definitions(fuzz_driver PRIVATE ENABLE_FUZZ)
|
target_compile_definitions(fuzz_driver PRIVATE ENABLE_FUZZ)
|
||||||
target_include_directories(fuzz_driver
|
target_include_directories(fuzz_driver
|
||||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
@@ -162,10 +172,35 @@ if(BUILD_TESTING)
|
|||||||
add_test(NAME conflict_set_fuzz_${hash} COMMAND fuzz_driver ${TEST})
|
add_test(NAME conflict_set_fuzz_${hash} COMMAND fuzz_driver ${TEST})
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
# tsan
|
||||||
|
|
||||||
|
if(NOT CMAKE_CROSSCOMPILING AND NOT CMAKE_BUILD_TYPE STREQUAL Debug)
|
||||||
|
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)
|
||||||
|
target_compile_definitions(tsan_driver PRIVATE ENABLE_FUZZ THREAD_TEST)
|
||||||
|
target_include_directories(tsan_driver
|
||||||
|
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
|
foreach(TEST ${CORPUS_TESTS})
|
||||||
|
get_filename_component(hash ${TEST} NAME)
|
||||||
|
add_test(NAME conflict_set_tsan_${hash} COMMAND tsan_driver ${TEST})
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
|
||||||
add_executable(driver TestDriver.cpp)
|
add_executable(driver TestDriver.cpp)
|
||||||
target_compile_options(driver PRIVATE ${TEST_FLAGS})
|
target_compile_options(driver PRIVATE ${TEST_FLAGS})
|
||||||
target_link_libraries(driver PRIVATE ${PROJECT_NAME})
|
target_link_libraries(driver PRIVATE ${PROJECT_NAME})
|
||||||
|
|
||||||
|
add_executable(script_test ScriptTest.cpp)
|
||||||
|
target_compile_options(script_test PRIVATE ${TEST_FLAGS})
|
||||||
|
target_link_libraries(script_test PRIVATE ${PROJECT_NAME})
|
||||||
|
|
||||||
|
file(GLOB SCRIPT_TESTS ${CMAKE_SOURCE_DIR}/script_tests/*)
|
||||||
|
foreach(TEST ${SCRIPT_TESTS})
|
||||||
|
get_filename_component(name ${TEST} NAME)
|
||||||
|
add_test(NAME conflict_set_script_${name} COMMAND script_test ${TEST})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
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)
|
||||||
@@ -212,7 +247,7 @@ if(BUILD_TESTING)
|
|||||||
NAME conflict_set_static_symbols
|
NAME conflict_set_static_symbols
|
||||||
COMMAND
|
COMMAND
|
||||||
${CMAKE_SOURCE_DIR}/test_symbols.sh
|
${CMAKE_SOURCE_DIR}/test_symbols.sh
|
||||||
$<TARGET_FILE:${PROJECT_NAME}_static> ${CMAKE_SOURCE_DIR}/symbols.txt)
|
$<TARGET_FILE:${PROJECT_NAME}-static> ${CMAKE_SOURCE_DIR}/symbols.txt)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# bench
|
# bench
|
||||||
@@ -237,6 +272,10 @@ set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
|
|||||||
set(CPACK_RPM_PACKAGE_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR})
|
set(CPACK_RPM_PACKAGE_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR})
|
||||||
set(CPACK_RPM_SPEC_INSTALL_POST "/bin/true") # avoid stripping
|
set(CPACK_RPM_SPEC_INSTALL_POST "/bin/true") # avoid stripping
|
||||||
set(CPACK_RPM_PACKAGE_LICENSE "Apache 2.0")
|
set(CPACK_RPM_PACKAGE_LICENSE "Apache 2.0")
|
||||||
|
set(CPACK_RPM_FILE_NAME RPM-DEFAULT)
|
||||||
|
|
||||||
|
# deb
|
||||||
|
set(CPACK_DEBIAN_FILE_NAME DEB-DEFAULT)
|
||||||
|
|
||||||
include(CPack)
|
include(CPack)
|
||||||
|
|
||||||
@@ -248,7 +287,7 @@ target_include_directories(
|
|||||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}>)
|
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}>)
|
||||||
|
|
||||||
target_include_directories(
|
target_include_directories(
|
||||||
${PROJECT_NAME}_static
|
${PROJECT_NAME}-static
|
||||||
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}>)
|
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}>)
|
||||||
|
|
||||||
@@ -257,13 +296,13 @@ set_target_properties(
|
|||||||
SOVERSION ${PROJECT_VERSION_MAJOR})
|
SOVERSION ${PROJECT_VERSION_MAJOR})
|
||||||
|
|
||||||
install(
|
install(
|
||||||
TARGETS ${PROJECT_NAME} ${PROJECT_NAME}_static
|
TARGETS ${PROJECT_NAME} ${PROJECT_NAME}-static
|
||||||
EXPORT ConflictSetConfig
|
EXPORT conflict-setConfig
|
||||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
install(DIRECTORY include/
|
install(DIRECTORY include/
|
||||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME})
|
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME})
|
||||||
|
|
||||||
install(EXPORT ConflictSetConfig
|
install(EXPORT conflict-setConfig
|
||||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/ConflictSet/cmake)
|
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/conflict-set/cmake)
|
||||||
|
1323
ConflictSet.cpp
1323
ConflictSet.cpp
File diff suppressed because it is too large
Load Diff
@@ -2,15 +2,25 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
for (int i = 1; i < argc; ++i) {
|
auto doTest = [&]() {
|
||||||
std::ifstream t(argv[i], std::ios::binary);
|
for (int i = 1; i < argc; ++i) {
|
||||||
std::stringstream buffer;
|
std::ifstream t(argv[i], std::ios::binary);
|
||||||
buffer << t.rdbuf();
|
std::stringstream buffer;
|
||||||
auto str = buffer.str();
|
buffer << t.rdbuf();
|
||||||
LLVMFuzzerTestOneInput((const uint8_t *)str.data(), str.size());
|
auto str = buffer.str();
|
||||||
}
|
LLVMFuzzerTestOneInput((const uint8_t *)str.data(), str.size());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#ifdef THREAD_TEST
|
||||||
|
std::thread thread2{doTest};
|
||||||
|
#endif
|
||||||
|
doTest();
|
||||||
|
#ifdef THREAD_TEST
|
||||||
|
thread2.join();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
@@ -96,13 +96,15 @@ void ConflictSet::setOldestVersion(int64_t oldestVersion) {
|
|||||||
return impl->setOldestVersion(oldestVersion);
|
return impl->setOldestVersion(oldestVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t ConflictSet::getBytes() const { return -1; }
|
||||||
|
|
||||||
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}) {}
|
||||||
|
|
||||||
ConflictSet::~ConflictSet() {
|
ConflictSet::~ConflictSet() {
|
||||||
if (impl) {
|
if (impl) {
|
||||||
impl->~Impl();
|
impl->~Impl();
|
||||||
free(impl);
|
safe_free(impl, sizeof(Impl));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,6 +144,11 @@ ConflictSet_create(int64_t oldestVersion) {
|
|||||||
__attribute__((__visibility__("default"))) void ConflictSet_destroy(void *cs) {
|
__attribute__((__visibility__("default"))) void ConflictSet_destroy(void *cs) {
|
||||||
using Impl = ConflictSet::Impl;
|
using Impl = ConflictSet::Impl;
|
||||||
((Impl *)cs)->~Impl();
|
((Impl *)cs)->~Impl();
|
||||||
free(cs);
|
safe_free(cs, sizeof(Impl));
|
||||||
|
}
|
||||||
|
__attribute__((__visibility__("default"))) int64_t
|
||||||
|
ConflictSet_getBytes(void *cs) {
|
||||||
|
using Impl = ConflictSet::Impl;
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
190
Internal.h
190
Internal.h
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include "ConflictSet.h"
|
#include "ConflictSet.h"
|
||||||
|
|
||||||
|
using namespace weaselab;
|
||||||
|
|
||||||
#include <bit>
|
#include <bit>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <compare>
|
#include <compare>
|
||||||
@@ -10,10 +12,12 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
#include <latch>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -35,16 +39,76 @@ operator<=>(const std::span<const uint8_t> &lhs,
|
|||||||
return lhs.size() <=> rhs.size();
|
return lhs.size() <=> rhs.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline auto operator<=>(const std::span<const uint8_t> &lhs,
|
||||||
|
const ConflictSet::Key &rhs) noexcept {
|
||||||
|
int cl = std::min<int>(lhs.size(), rhs.len);
|
||||||
|
if (cl > 0) {
|
||||||
|
if (auto c = memcmp(lhs.data(), rhs.p, cl) <=> 0; c != 0) {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lhs.size() <=> size_t(rhs.len);
|
||||||
|
}
|
||||||
|
|
||||||
// This header contains code that we want to reuse outside of ConflictSet.cpp or
|
// This header contains code that we want to reuse outside of ConflictSet.cpp or
|
||||||
// want to exclude from coverage since it's only testing related.
|
// want to exclude from coverage since it's only testing related.
|
||||||
|
|
||||||
// GCOVR_EXCL_START
|
// GCOVR_EXCL_START
|
||||||
|
|
||||||
|
#if SHOW_MEMORY
|
||||||
|
inline int64_t mallocBytes = 0;
|
||||||
|
inline int64_t peakMallocBytes = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inline thread_local int64_t mallocBytesDelta = 0;
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
constexpr auto kMallocHeaderSize = 16;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// malloc that aborts on OOM and thus always returns a non-null pointer. Must be
|
||||||
|
// paired with `safe_free`.
|
||||||
__attribute__((always_inline)) inline void *safe_malloc(size_t s) {
|
__attribute__((always_inline)) inline void *safe_malloc(size_t s) {
|
||||||
if (void *p = malloc(s)) {
|
mallocBytesDelta += s;
|
||||||
return p;
|
#if SHOW_MEMORY
|
||||||
|
mallocBytes += s;
|
||||||
|
if (mallocBytes > peakMallocBytes) {
|
||||||
|
peakMallocBytes = mallocBytes;
|
||||||
}
|
}
|
||||||
abort();
|
#endif
|
||||||
|
void *p = malloc(s
|
||||||
|
#ifndef NDEBUG
|
||||||
|
+ kMallocHeaderSize
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
if (p == nullptr) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
#ifndef NDEBUG
|
||||||
|
memcpy(p, &s, sizeof(s));
|
||||||
|
(char *&)p += kMallocHeaderSize;
|
||||||
|
#endif
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must be paired with `safe_malloc`.
|
||||||
|
//
|
||||||
|
// There's nothing safer about this than free. Only called safe_free for
|
||||||
|
// symmetry with safe_malloc.
|
||||||
|
__attribute__((always_inline)) inline void safe_free(void *p, size_t s) {
|
||||||
|
mallocBytesDelta -= s;
|
||||||
|
#if SHOW_MEMORY
|
||||||
|
mallocBytes -= s;
|
||||||
|
free(p);
|
||||||
|
#else
|
||||||
|
#ifndef NDEBUG
|
||||||
|
(char *&)p -= kMallocHeaderSize;
|
||||||
|
size_t expected;
|
||||||
|
memcpy(&expected, p, sizeof(expected));
|
||||||
|
assert(s == expected);
|
||||||
|
#endif
|
||||||
|
free(p);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== BEGIN ARENA IMPL ====================
|
// ==================== BEGIN ARENA IMPL ====================
|
||||||
@@ -129,7 +193,7 @@ inline Arena::Arena(int initialSize) : impl(nullptr) {
|
|||||||
inline void onDestroy(Arena::ArenaImpl *impl) {
|
inline void onDestroy(Arena::ArenaImpl *impl) {
|
||||||
while (impl) {
|
while (impl) {
|
||||||
auto *prev = impl->prev;
|
auto *prev = impl->prev;
|
||||||
free(impl);
|
safe_free(impl, sizeof(Arena::ArenaImpl) + impl->capacity);
|
||||||
impl = prev;
|
impl = prev;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -349,34 +413,6 @@ inline uint32_t Arbitrary::bounded(uint32_t s) {
|
|||||||
|
|
||||||
// ==================== END ARBITRARY IMPL ====================
|
// ==================== END ARBITRARY IMPL ====================
|
||||||
|
|
||||||
// ==================== BEGIN UTILITIES IMPL ====================
|
|
||||||
|
|
||||||
// Call Stepwise::step for each element of remaining until it returns true.
|
|
||||||
// Applies a permutation to `remaining` as a side effect.
|
|
||||||
template <class Stepwise> void runInterleaved(std::span<Stepwise> remaining) {
|
|
||||||
while (remaining.size() > 0) {
|
|
||||||
for (int i = 0; i < int(remaining.size());) {
|
|
||||||
bool done = remaining[i].step();
|
|
||||||
if (done) {
|
|
||||||
if (i != int(remaining.size()) - 1) {
|
|
||||||
using std::swap;
|
|
||||||
swap(remaining[i], remaining.back());
|
|
||||||
}
|
|
||||||
remaining = remaining.subspan(0, remaining.size() - 1);
|
|
||||||
} else {
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class Stepwise> void runSequential(std::span<Stepwise> remaining) {
|
|
||||||
for (auto &r : remaining) {
|
|
||||||
while (!r.step()) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ReferenceImpl {
|
struct ReferenceImpl {
|
||||||
explicit ReferenceImpl(int64_t oldestVersion) : oldestVersion(oldestVersion) {
|
explicit ReferenceImpl(int64_t oldestVersion) : oldestVersion(oldestVersion) {
|
||||||
writeVersionMap[""] = oldestVersion;
|
writeVersionMap[""] = oldestVersion;
|
||||||
@@ -470,6 +506,18 @@ inline std::string printable(std::span<const uint8_t> key) {
|
|||||||
return printable(std::string_view((const char *)key.data(), key.size()));
|
return printable(std::string_view((const char *)key.data(), key.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline const char *resultToStr(ConflictSet::Result r) {
|
||||||
|
switch (r) {
|
||||||
|
case ConflictSet::Commit:
|
||||||
|
return "commit";
|
||||||
|
case ConflictSet::Conflict:
|
||||||
|
return "conflict";
|
||||||
|
case ConflictSet::TooOld:
|
||||||
|
return "too old";
|
||||||
|
}
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
template <class ConflictSetImpl> struct TestDriver {
|
template <class ConflictSetImpl> struct TestDriver {
|
||||||
@@ -482,22 +530,10 @@ template <class ConflictSetImpl> struct TestDriver {
|
|||||||
ConflictSetImpl cs{oldestVersion};
|
ConflictSetImpl cs{oldestVersion};
|
||||||
ReferenceImpl refImpl{oldestVersion};
|
ReferenceImpl refImpl{oldestVersion};
|
||||||
|
|
||||||
constexpr static auto kMaxKeyLen = 128;
|
constexpr static auto kMaxKeyLen = 8;
|
||||||
|
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
|
|
||||||
static const char *resultToStr(ConflictSet::Result r) {
|
|
||||||
switch (r) {
|
|
||||||
case ConflictSet::Commit:
|
|
||||||
return "commit";
|
|
||||||
case ConflictSet::Conflict:
|
|
||||||
return "conflict";
|
|
||||||
case ConflictSet::TooOld:
|
|
||||||
return "too old";
|
|
||||||
}
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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() {
|
||||||
@@ -632,32 +668,60 @@ template <class ConflictSetImpl> struct TestDriver {
|
|||||||
auto *results2 =
|
auto *results2 =
|
||||||
new (arena) ConflictSet::Result[numPointReads + numRangeReads];
|
new (arena) ConflictSet::Result[numPointReads + numRangeReads];
|
||||||
|
|
||||||
|
#ifdef THREAD_TEST
|
||||||
|
auto *results3 =
|
||||||
|
new (arena) ConflictSet::Result[numPointReads + numRangeReads];
|
||||||
|
std::latch ready{1};
|
||||||
|
std::thread thread2{[&]() {
|
||||||
|
ready.count_down();
|
||||||
|
cs.check(reads, results3, numPointReads + numRangeReads);
|
||||||
|
}};
|
||||||
|
ready.wait();
|
||||||
|
#endif
|
||||||
|
|
||||||
CALLGRIND_START_INSTRUMENTATION;
|
CALLGRIND_START_INSTRUMENTATION;
|
||||||
cs.check(reads, results1, numPointReads + numRangeReads);
|
cs.check(reads, results1, numPointReads + numRangeReads);
|
||||||
CALLGRIND_STOP_INSTRUMENTATION;
|
CALLGRIND_STOP_INSTRUMENTATION;
|
||||||
|
|
||||||
refImpl.check(reads, results2, numPointReads + numRangeReads);
|
refImpl.check(reads, results2, numPointReads + numRangeReads);
|
||||||
for (int i = 0; i < numPointReads + numRangeReads; ++i) {
|
|
||||||
if (results1[i] != results2[i]) {
|
auto compareResults = [reads](ConflictSet::Result *results1,
|
||||||
if (reads[i].end.len == 0) {
|
ConflictSet::Result *results2, int count) {
|
||||||
fprintf(stderr,
|
for (int i = 0; i < count; ++i) {
|
||||||
"Expected %s, got %s for read of {%s} at version %" PRId64
|
if (results1[i] != results2[i]) {
|
||||||
"\n",
|
if (reads[i].end.len == 0) {
|
||||||
resultToStr(results2[i]), resultToStr(results1[i]),
|
fprintf(stderr,
|
||||||
printable(reads[i].begin).c_str(), reads[i].readVersion);
|
"Expected %s, got %s for read of {%s} at version %" PRId64
|
||||||
} else {
|
"\n",
|
||||||
fprintf(
|
resultToStr(results2[i]), resultToStr(results1[i]),
|
||||||
stderr,
|
printable(reads[i].begin).c_str(), reads[i].readVersion);
|
||||||
"Expected %s, got %s for read of [%s, %s) at version %" PRId64
|
} else {
|
||||||
"\n",
|
fprintf(
|
||||||
resultToStr(results2[i]), resultToStr(results1[i]),
|
stderr,
|
||||||
printable(reads[i].begin).c_str(),
|
"Expected %s, got %s for read of [%s, %s) at version %" PRId64
|
||||||
printable(reads[i].end).c_str(), reads[i].readVersion);
|
"\n",
|
||||||
|
resultToStr(results2[i]), resultToStr(results1[i]),
|
||||||
|
printable(reads[i].begin).c_str(),
|
||||||
|
printable(reads[i].end).c_str(), reads[i].readVersion);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
ok = false;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!compareResults(results1, results2, numPointReads + numRangeReads)) {
|
||||||
|
ok = false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef THREAD_TEST
|
||||||
|
thread2.join();
|
||||||
|
if (!compareResults(results3, results2, numPointReads + numRangeReads)) {
|
||||||
|
ok = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
29
Jenkinsfile
vendored
29
Jenkinsfile
vendored
@@ -36,6 +36,29 @@ pipeline {
|
|||||||
sh 'pre-commit run --all-files --show-diff-on-failure'
|
sh 'pre-commit run --all-files --show-diff-on-failure'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
stage('Clang') {
|
||||||
|
agent {
|
||||||
|
dockerfile {
|
||||||
|
args '-v /home/jenkins/ccache:/ccache'
|
||||||
|
reuseNode true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
CleanBuildAndTest("")
|
||||||
|
recordIssues(tools: [clang()])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('SIMD fallback') {
|
||||||
|
agent {
|
||||||
|
dockerfile {
|
||||||
|
args '-v /home/jenkins/ccache:/ccache'
|
||||||
|
reuseNode true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
CleanBuildAndTest("-DUSE_SIMD_FALLBACK=ON")
|
||||||
|
}
|
||||||
|
}
|
||||||
stage('Release [gcc]') {
|
stage('Release [gcc]') {
|
||||||
agent {
|
agent {
|
||||||
dockerfile {
|
dockerfile {
|
||||||
@@ -44,7 +67,7 @@ pipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
steps {
|
steps {
|
||||||
CleanBuildAndTest("-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_BUILD_TYPE=Release")
|
CleanBuildAndTest("-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_CXX_FLAGS=-DNVALGRIND")
|
||||||
recordIssues(tools: [gcc()])
|
recordIssues(tools: [gcc()])
|
||||||
sh '''
|
sh '''
|
||||||
cd build
|
cd build
|
||||||
@@ -66,7 +89,7 @@ pipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
steps {
|
steps {
|
||||||
CleanBuildAndTest("-DCMAKE_TOOLCHAIN_FILE=../aarch64-toolchain.cmake")
|
CleanBuildAndTest("-DCMAKE_TOOLCHAIN_FILE=../aarch64-toolchain.cmake -DCMAKE_CXX_FLAGS=-DNVALGRIND")
|
||||||
sh '''
|
sh '''
|
||||||
cd build
|
cd build
|
||||||
cpack -G DEB
|
cpack -G DEB
|
||||||
@@ -85,7 +108,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")
|
||||||
sh '''
|
sh '''
|
||||||
gcovr --exclude '.*third_party.*' --cobertura > build/coverage.xml
|
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
|
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
|
||||||
}
|
}
|
||||||
|
110
README.md
110
README.md
@@ -2,54 +2,56 @@ A data structure for optimistic concurrency control on ranges of bitwise-lexicog
|
|||||||
|
|
||||||
Intended to replace FoundationDB's skip list.
|
Intended to replace FoundationDB's skip list.
|
||||||
|
|
||||||
|
Hardware for all benchmarks is a mac m1 2020.
|
||||||
|
|
||||||
# FoundationDB's benchmark
|
# FoundationDB's benchmark
|
||||||
|
|
||||||
## Skip list
|
## Skip list
|
||||||
|
|
||||||
```
|
```
|
||||||
New conflict set: 2.404 sec
|
New conflict set: 1.957 sec
|
||||||
0.520 Mtransactions/sec
|
0.639 Mtransactions/sec
|
||||||
2.080 Mkeys/sec
|
2.555 Mkeys/sec
|
||||||
Detect only: 2.266 sec
|
Detect only: 1.845 sec
|
||||||
0.552 Mtransactions/sec
|
0.678 Mtransactions/sec
|
||||||
2.207 Mkeys/sec
|
2.710 Mkeys/sec
|
||||||
Skiplist only: 1.594 sec
|
Skiplist only: 1.263 sec
|
||||||
0.784 Mtransactions/sec
|
0.990 Mtransactions/sec
|
||||||
3.137 Mkeys/sec
|
3.960 Mkeys/sec
|
||||||
Performance counters:
|
Performance counters:
|
||||||
Build: 0.071
|
Build: 0.0546
|
||||||
Add: 0.0641
|
Add: 0.0563
|
||||||
Detect: 2.27
|
Detect: 1.84
|
||||||
D.Sort: 0.44
|
D.Sort: 0.412
|
||||||
D.Combine: 0.018
|
D.Combine: 0.0141
|
||||||
D.CheckRead: 0.855
|
D.CheckRead: 0.671
|
||||||
D.CheckIntraBatch: 0.00903
|
D.CheckIntraBatch: 0.0068
|
||||||
D.MergeWrite: 0.739
|
D.MergeWrite: 0.592
|
||||||
D.RemoveBefore: 0.201
|
D.RemoveBefore: 0.146
|
||||||
```
|
```
|
||||||
|
|
||||||
## Radix tree (this implementation)
|
## Radix tree (this implementation)
|
||||||
|
|
||||||
```
|
```
|
||||||
New conflict set: 1.743 sec
|
New conflict set: 1.366 sec
|
||||||
0.717 Mtransactions/sec
|
0.915 Mtransactions/sec
|
||||||
2.869 Mkeys/sec
|
3.660 Mkeys/sec
|
||||||
Detect only: 1.611 sec
|
Detect only: 1.248 sec
|
||||||
0.776 Mtransactions/sec
|
1.002 Mtransactions/sec
|
||||||
3.103 Mkeys/sec
|
4.007 Mkeys/sec
|
||||||
Skiplist only: 0.919 sec
|
Skiplist only: 0.573 sec
|
||||||
1.360 Mtransactions/sec
|
2.182 Mtransactions/sec
|
||||||
5.440 Mkeys/sec
|
8.730 Mkeys/sec
|
||||||
Performance counters:
|
Performance counters:
|
||||||
Build: 0.0657
|
Build: 0.0594
|
||||||
Add: 0.0628
|
Add: 0.0572
|
||||||
Detect: 1.61
|
Detect: 1.25
|
||||||
D.Sort: 0.442
|
D.Sort: 0.418
|
||||||
D.Combine: 0.0178
|
D.Combine: 0.0149
|
||||||
D.CheckRead: 0.395
|
D.CheckRead: 0.232
|
||||||
D.CheckIntraBatch: 0.00776
|
D.CheckIntraBatch: 0.0067
|
||||||
D.MergeWrite: 0.524
|
D.MergeWrite: 0.341
|
||||||
D.RemoveBefore: 0.221
|
D.RemoveBefore: 0.232
|
||||||
```
|
```
|
||||||
|
|
||||||
# Our benchmark
|
# Our benchmark
|
||||||
@@ -58,25 +60,25 @@ Performance counters:
|
|||||||
|
|
||||||
| ns/op | op/s | err% | total | benchmark
|
| ns/op | op/s | err% | total | benchmark
|
||||||
|--------------------:|--------------------:|--------:|----------:|:----------
|
|--------------------:|--------------------:|--------:|----------:|:----------
|
||||||
| 270.07 | 3,702,706.03 | 0.4% | 0.01 | `point reads`
|
| 246.99 | 4,048,700.59 | 0.2% | 0.01 | `point reads`
|
||||||
| 285.76 | 3,499,437.03 | 1.5% | 0.01 | `prefix reads`
|
| 260.16 | 3,843,784.65 | 0.1% | 0.01 | `prefix reads`
|
||||||
| 532.54 | 1,877,794.90 | 0.7% | 0.01 | `range reads`
|
| 493.35 | 2,026,953.19 | 0.1% | 0.01 | `range reads`
|
||||||
| 528.50 | 1,892,132.94 | 0.7% | 0.01 | `point writes`
|
| 462.05 | 2,164,289.23 | 0.6% | 0.01 | `point writes`
|
||||||
| 516.53 | 1,935,978.22 | 0.9% | 0.01 | `prefix writes`
|
| 448.19 | 2,231,205.25 | 0.9% | 0.01 | `prefix writes`
|
||||||
| 303.34 | 3,296,630.84 | 3.6% | 0.05 | `range writes`
|
| 255.83 | 3,908,845.72 | 1.5% | 0.02 | `range writes`
|
||||||
| 502.88 | 1,988,553.24 | 2.0% | 0.01 | `monotonic increasing point writes`
|
| 582.63 | 1,716,349.02 | 1.3% | 0.01 | `monotonic increasing point writes`
|
||||||
|
|
||||||
## Radix tree (this implementation)
|
## Radix tree (this implementation)
|
||||||
|
|
||||||
| ns/op | op/s | err% | total | benchmark
|
| ns/op | op/s | err% | total | benchmark
|
||||||
|--------------------:|--------------------:|--------:|----------:|:----------
|
|--------------------:|--------------------:|--------:|----------:|:----------
|
||||||
| 14.52 | 68,850,842.99 | 1.2% | 0.01 | `point reads`
|
| 19.42 | 51,483,206.67 | 0.3% | 0.01 | `point reads`
|
||||||
| 60.89 | 16,422,538.22 | 1.5% | 0.01 | `prefix reads`
|
| 58.43 | 17,115,612.57 | 0.1% | 0.01 | `prefix reads`
|
||||||
| 226.89 | 4,407,362.98 | 0.5% | 0.01 | `range reads`
|
| 216.09 | 4,627,766.60 | 0.2% | 0.01 | `range reads`
|
||||||
| 22.99 | 43,498,198.49 | 0.2% | 0.01 | `point writes`
|
| 28.35 | 35,267,567.72 | 0.2% | 0.01 | `point writes`
|
||||||
| 50.51 | 19,799,864.54 | 1.0% | 0.01 | `prefix writes`
|
| 43.43 | 23,026,226.17 | 0.2% | 0.01 | `prefix writes`
|
||||||
| 82.50 | 12,121,212.12 | 2.6% | 0.03 | `range writes`
|
| 50.00 | 20,000,000.00 | 0.0% | 0.01 | `range writes`
|
||||||
| 119.94 | 8,337,354.54 | 2.1% | 0.01 | `monotonic increasing point writes`
|
| 92.38 | 10,824,863.69 | 4.1% | 0.01 | `monotonic increasing point writes`
|
||||||
|
|
||||||
# "Real data" test
|
# "Real data" test
|
||||||
|
|
||||||
@@ -85,13 +87,13 @@ Point queries only, best of three runs. Gc ratio is the ratio of time spent doin
|
|||||||
## skip list
|
## skip list
|
||||||
|
|
||||||
```
|
```
|
||||||
Check: 12.7863 seconds, 292.384 MB/s, Add: 19.8276 seconds, 35.4071 MB/s, Gc ratio: 23.5314%
|
Check: 11.3385 seconds, 329.718 MB/s, Add: 5.35612 seconds, 131.072 MB/s, Gc ratio: 45.7173%
|
||||||
```
|
```
|
||||||
|
|
||||||
## radix tree
|
## radix tree
|
||||||
|
|
||||||
```
|
```
|
||||||
Check: 3.60187 seconds, 1037.94 MB/s, Add: 3.03958 seconds, 230.966 MB/s, Gc ratio: 52.3876%
|
Check: 2.48583 seconds, 1503.93 MB/s, Add: 2.12768 seconds, 329.954 MB/s, Gc ratio: 41.7943%
|
||||||
```
|
```
|
||||||
|
|
||||||
## hash table
|
## hash table
|
||||||
@@ -99,5 +101,5 @@ Check: 3.60187 seconds, 1037.94 MB/s, Add: 3.03958 seconds, 230.966 MB/s, Gc rat
|
|||||||
(The hash table implementation doesn't work on range queries, and its purpose is to provide an idea of how fast point queries can be)
|
(The hash table implementation doesn't work on range queries, and its purpose is to provide an idea of how fast point queries can be)
|
||||||
|
|
||||||
```
|
```
|
||||||
Check: 2.15925 seconds, 1731.4 MB/s, Add: 1.08519 seconds, 646.926 MB/s, Gc ratio: 52.1526%
|
Check: 1.83386 seconds, 2038.6 MB/s, Add: 0.601411 seconds, 1167.32 MB/s, Gc ratio: 48.9776%
|
||||||
```
|
```
|
||||||
|
@@ -8,6 +8,8 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
using namespace weaselab;
|
||||||
|
|
||||||
double now() {
|
double now() {
|
||||||
return std::chrono::duration_cast<std::chrono::nanoseconds>(
|
return std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||||
std::chrono::steady_clock::now().time_since_epoch())
|
std::chrono::steady_clock::now().time_since_epoch())
|
||||||
@@ -28,7 +30,7 @@ constexpr inline size_t rightAlign(size_t offset, size_t alignment) {
|
|||||||
|
|
||||||
int main(int argc, const char **argv) {
|
int main(int argc, const char **argv) {
|
||||||
// Use with this dataset https://snap.stanford.edu/data/memetracker9.html
|
// Use with this dataset https://snap.stanford.edu/data/memetracker9.html
|
||||||
// Preprocess the files with `sed -i '' '/^Q/d'`
|
// Preprocess the files with `sed -i'' '/^Q/d'`
|
||||||
|
|
||||||
double checkTime = 0;
|
double checkTime = 0;
|
||||||
double addTime = 0;
|
double addTime = 0;
|
||||||
@@ -40,6 +42,8 @@ int main(int argc, const char **argv) {
|
|||||||
int64_t version = 0;
|
int64_t version = 0;
|
||||||
double timer = 0;
|
double timer = 0;
|
||||||
|
|
||||||
|
int64_t peakMemory = 0;
|
||||||
|
|
||||||
for (int i = 1; i < argc; ++i) {
|
for (int i = 1; i < argc; ++i) {
|
||||||
int fd = open(argv[i], O_RDONLY);
|
int fd = open(argv[i], O_RDONLY);
|
||||||
struct stat st;
|
struct stat st;
|
||||||
@@ -109,6 +113,10 @@ int main(int argc, const char **argv) {
|
|||||||
write = {};
|
write = {};
|
||||||
reads.clear();
|
reads.clear();
|
||||||
|
|
||||||
|
if (cs.getBytes() > peakMemory) {
|
||||||
|
peakMemory = cs.getBytes();
|
||||||
|
}
|
||||||
|
|
||||||
timer = now();
|
timer = now();
|
||||||
cs.setOldestVersion(version - 10000);
|
cs.setOldestVersion(version - 10000);
|
||||||
gcTime += now() - timer;
|
gcTime += now() - timer;
|
||||||
@@ -118,8 +126,9 @@ int main(int argc, const char **argv) {
|
|||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(
|
printf("Check: %g seconds, %g MB/s, Add: %g seconds, %g MB/s, Gc ratio: "
|
||||||
"Check: %g seconds, %g MB/s, Add: %g seconds, %g MB/s, Gc ratio: %g%%\n",
|
"%g%%, Peak idle memory: %g\n",
|
||||||
checkTime, checkBytes / checkTime * 1e-6, addTime,
|
checkTime, checkBytes / checkTime * 1e-6, addTime,
|
||||||
addBytes / addTime * 1e-6, gcTime / (gcTime + addTime) * 1e2);
|
addBytes / addTime * 1e-6, gcTime / (gcTime + addTime) * 1e2,
|
||||||
|
double(peakMemory));
|
||||||
}
|
}
|
155
ScriptTest.cpp
Normal file
155
ScriptTest.cpp
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
#include "Internal.h"
|
||||||
|
#include <ConflictSet.h>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <cstring>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
inline size_t getPageSize() {
|
||||||
|
static size_t kPageSize = sysconf(_SC_PAGESIZE);
|
||||||
|
return kPageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper for rounding up to page size (or some other alignment)
|
||||||
|
constexpr inline size_t rightAlign(size_t offset, size_t alignment) {
|
||||||
|
return offset % alignment == 0 ? offset
|
||||||
|
: ((offset / alignment) + 1) * alignment;
|
||||||
|
}
|
||||||
|
|
||||||
|
using StringView = std::basic_string_view<uint8_t>;
|
||||||
|
|
||||||
|
inline StringView operator"" _v(const char *str, size_t size) {
|
||||||
|
return {reinterpret_cast<const uint8_t *>(str), size};
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, const char **argv) {
|
||||||
|
|
||||||
|
ConflictSet cs{0};
|
||||||
|
ReferenceImpl ref{0};
|
||||||
|
|
||||||
|
for (int i = 1; i < argc; ++i) {
|
||||||
|
int fd = open(argv[i], O_RDONLY);
|
||||||
|
struct stat st;
|
||||||
|
if (fstat(fd, &st) == -1) {
|
||||||
|
int err = errno;
|
||||||
|
fprintf(stderr, "stat error %s - %s\n", argv[i], strerror(err));
|
||||||
|
fflush(stderr);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t size = rightAlign(st.st_size, getPageSize());
|
||||||
|
const uint8_t *begin =
|
||||||
|
(uint8_t *)mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||||
|
madvise((void *)begin, size, MADV_SEQUENTIAL);
|
||||||
|
auto *const mapOriginal = begin;
|
||||||
|
const auto sizeOriginal = size;
|
||||||
|
|
||||||
|
StringView b;
|
||||||
|
StringView e;
|
||||||
|
int64_t v = 0;
|
||||||
|
int64_t lastWriteVersion = 0;
|
||||||
|
int64_t lastOldestVersion = 0;
|
||||||
|
std::vector<ConflictSet::WriteRange> writeRanges;
|
||||||
|
std::vector<ConflictSet::ReadRange> readRanges;
|
||||||
|
std::vector<ConflictSet::Result> results;
|
||||||
|
|
||||||
|
for (uint8_t *end = (uint8_t *)memchr(begin, '\n', size); end != nullptr;) {
|
||||||
|
StringView line{begin, static_cast<size_t>(end - begin)};
|
||||||
|
size -= end - begin + 1;
|
||||||
|
begin = end + 1;
|
||||||
|
end = (uint8_t *)memchr(begin, '\n', size);
|
||||||
|
|
||||||
|
if (line.starts_with("begin"_v)) {
|
||||||
|
b = line.substr("begin "_v.size(), line.size());
|
||||||
|
printf("b <- %.*s\n", int(b.size()), b.data());
|
||||||
|
} else if (line.starts_with("end"_v)) {
|
||||||
|
e = line.substr("end "_v.size(), line.size());
|
||||||
|
printf("e <- %.*s\n", int(e.size()), e.data());
|
||||||
|
} else if (line.starts_with("version"_v)) {
|
||||||
|
line = line.substr("version "_v.size(), line.size());
|
||||||
|
v = 0;
|
||||||
|
for (auto c : line) {
|
||||||
|
v = v * 10 + int(c) - int('0');
|
||||||
|
}
|
||||||
|
printf("v <- %" PRId64 "\n", v);
|
||||||
|
} else if (line.starts_with("pointread"_v)) {
|
||||||
|
printf("pointread\n");
|
||||||
|
ConflictSet::ReadRange r;
|
||||||
|
r.begin.p = b.data();
|
||||||
|
r.begin.len = b.size();
|
||||||
|
r.end.len = 0;
|
||||||
|
r.readVersion = v;
|
||||||
|
readRanges.push_back(r);
|
||||||
|
} else if (line.starts_with("pointwrite"_v)) {
|
||||||
|
printf("pointwrite\n");
|
||||||
|
assert(writeRanges.empty() ||
|
||||||
|
(writeRanges.back().end.len == 0 ? writeRanges.back().begin
|
||||||
|
: writeRanges.back().end) < b);
|
||||||
|
ConflictSet::WriteRange w;
|
||||||
|
w.begin.p = b.data();
|
||||||
|
w.begin.len = b.size();
|
||||||
|
w.end.len = 0;
|
||||||
|
writeRanges.push_back(w);
|
||||||
|
} else if (line.starts_with("rangeread"_v)) {
|
||||||
|
printf("rangeread\n");
|
||||||
|
ConflictSet::ReadRange r;
|
||||||
|
r.begin.p = b.data();
|
||||||
|
r.begin.len = b.size();
|
||||||
|
r.end.p = e.data();
|
||||||
|
r.end.len = e.size();
|
||||||
|
r.readVersion = v;
|
||||||
|
readRanges.push_back(r);
|
||||||
|
} else if (line.starts_with("rangewrite"_v)) {
|
||||||
|
printf("rangewrite\n");
|
||||||
|
assert(b < e);
|
||||||
|
assert(writeRanges.empty() ||
|
||||||
|
(writeRanges.back().end.len == 0 ? writeRanges.back().begin
|
||||||
|
: writeRanges.back().end) < b);
|
||||||
|
ConflictSet::WriteRange w;
|
||||||
|
w.begin.p = b.data();
|
||||||
|
w.begin.len = b.size();
|
||||||
|
w.end.p = e.data();
|
||||||
|
w.end.len = e.size();
|
||||||
|
writeRanges.push_back(w);
|
||||||
|
} else if (line.starts_with("check"_v)) {
|
||||||
|
printf("check\n");
|
||||||
|
Arena arena;
|
||||||
|
auto *expected = new (arena) ConflictSet::Result[readRanges.size()];
|
||||||
|
auto *actual = new (arena) ConflictSet::Result[readRanges.size()];
|
||||||
|
ref.check(readRanges.data(), expected, readRanges.size());
|
||||||
|
cs.check(readRanges.data(), actual, readRanges.size());
|
||||||
|
for (int i = 0; i < int(readRanges.size()); ++i) {
|
||||||
|
if (expected[i] != actual[i]) {
|
||||||
|
fprintf(stderr, "Expected %s, got %s at index %d\n",
|
||||||
|
resultToStr(expected[i]), resultToStr(actual[i]), i);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
readRanges = {};
|
||||||
|
} else if (line.starts_with("addwrites"_v)) {
|
||||||
|
printf("addwrites\n");
|
||||||
|
assert(v > lastWriteVersion);
|
||||||
|
lastWriteVersion = v;
|
||||||
|
cs.addWrites(writeRanges.data(), writeRanges.size(), v);
|
||||||
|
ref.addWrites(writeRanges.data(), writeRanges.size(), v);
|
||||||
|
writeRanges = {};
|
||||||
|
} else if (line.starts_with("setoldest"_v)) {
|
||||||
|
printf("setoldest\n");
|
||||||
|
assert(v > lastOldestVersion);
|
||||||
|
lastOldestVersion = v;
|
||||||
|
cs.setOldestVersion(v);
|
||||||
|
ref.setOldestVersion(v);
|
||||||
|
} else if (line.empty() || line.starts_with(";"_v)) {
|
||||||
|
// skip
|
||||||
|
} else {
|
||||||
|
printf("Unrecognized line: %.*s\n", int(line.size()), line.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
munmap((void *)mapOriginal, sizeOriginal);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
}
|
55
SkipList.cpp
55
SkipList.cpp
@@ -149,7 +149,7 @@ private:
|
|||||||
setMaxVersion(level, v);
|
setMaxVersion(level, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroy() { free(this); }
|
void destroy() { safe_free(this, getNodeSize()); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int getNodeSize() const {
|
int getNodeSize() const {
|
||||||
@@ -607,7 +607,7 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
|||||||
values[i * 2 + 1] = w.end.len > 0
|
values[i * 2 + 1] = w.end.len > 0
|
||||||
? StringRef{w.end.p, size_t(w.end.len)}
|
? StringRef{w.end.p, size_t(w.end.len)}
|
||||||
: keyAfter(arena, values[i * 2]);
|
: keyAfter(arena, values[i * 2]);
|
||||||
keyUpdates += 2;
|
keyUpdates += 3;
|
||||||
}
|
}
|
||||||
skipList.find(values, fingers, temp, ss);
|
skipList.find(values, fingers, temp, ss);
|
||||||
skipList.addConflictRanges(fingers, ss / 2, writeVersion);
|
skipList.addConflictRanges(fingers, ss / 2, writeVersion);
|
||||||
@@ -621,14 +621,16 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
|||||||
int temp;
|
int temp;
|
||||||
std::span<const uint8_t> key = removalKey;
|
std::span<const uint8_t> key = removalKey;
|
||||||
skipList.find(&key, &finger, &temp, 1);
|
skipList.find(&key, &finger, &temp, 1);
|
||||||
skipList.removeBefore(oldestVersion, finger, std::exchange(keyUpdates, 0));
|
skipList.removeBefore(oldestVersion, finger, std::exchange(keyUpdates, 10));
|
||||||
removalArena = Arena();
|
removalArena = Arena();
|
||||||
removalKey = copyToArena(
|
removalKey = copyToArena(
|
||||||
removalArena, {finger.getValue().data(), finger.getValue().size()});
|
removalArena, {finger.getValue().data(), finger.getValue().size()});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t totalBytes = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int64_t keyUpdates = 0;
|
int64_t keyUpdates = 10;
|
||||||
Arena removalArena;
|
Arena removalArena;
|
||||||
std::span<const uint8_t> removalKey;
|
std::span<const uint8_t> removalKey;
|
||||||
int64_t oldestVersion;
|
int64_t oldestVersion;
|
||||||
@@ -637,25 +639,44 @@ private:
|
|||||||
|
|
||||||
void ConflictSet::check(const ReadRange *reads, Result *results,
|
void ConflictSet::check(const ReadRange *reads, Result *results,
|
||||||
int count) const {
|
int count) const {
|
||||||
return impl->check(reads, results, count);
|
impl->check(reads, results, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConflictSet::addWrites(const WriteRange *writes, int count,
|
void ConflictSet::addWrites(const WriteRange *writes, int count,
|
||||||
int64_t writeVersion) {
|
int64_t writeVersion) {
|
||||||
return impl->addWrites(writes, count, writeVersion);
|
mallocBytesDelta = 0;
|
||||||
|
impl->addWrites(writes, count, writeVersion);
|
||||||
|
impl->totalBytes += mallocBytesDelta;
|
||||||
|
#if SHOW_MEMORY
|
||||||
|
if (impl->totalBytes != mallocBytes) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConflictSet::setOldestVersion(int64_t oldestVersion) {
|
void ConflictSet::setOldestVersion(int64_t oldestVersion) {
|
||||||
return impl->setOldestVersion(oldestVersion);
|
mallocBytesDelta = 0;
|
||||||
|
impl->setOldestVersion(oldestVersion);
|
||||||
|
impl->totalBytes += mallocBytesDelta;
|
||||||
|
#if SHOW_MEMORY
|
||||||
|
if (impl->totalBytes != mallocBytes) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t ConflictSet::getBytes() const { return impl->totalBytes; }
|
||||||
|
|
||||||
ConflictSet::ConflictSet(int64_t oldestVersion)
|
ConflictSet::ConflictSet(int64_t oldestVersion)
|
||||||
: impl(new (safe_malloc(sizeof(Impl))) Impl{oldestVersion}) {}
|
: impl((mallocBytesDelta = 0,
|
||||||
|
new (safe_malloc(sizeof(Impl))) Impl{oldestVersion})) {
|
||||||
|
impl->totalBytes += mallocBytesDelta;
|
||||||
|
}
|
||||||
|
|
||||||
ConflictSet::~ConflictSet() {
|
ConflictSet::~ConflictSet() {
|
||||||
if (impl) {
|
if (impl) {
|
||||||
impl->~Impl();
|
impl->~Impl();
|
||||||
free(impl);
|
safe_free(impl, sizeof(Impl));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -695,6 +716,20 @@ ConflictSet_create(int64_t oldestVersion) {
|
|||||||
__attribute__((__visibility__("default"))) void ConflictSet_destroy(void *cs) {
|
__attribute__((__visibility__("default"))) void ConflictSet_destroy(void *cs) {
|
||||||
using Impl = ConflictSet::Impl;
|
using Impl = ConflictSet::Impl;
|
||||||
((Impl *)cs)->~Impl();
|
((Impl *)cs)->~Impl();
|
||||||
free(cs);
|
safe_free(cs, sizeof(Impl));
|
||||||
|
}
|
||||||
|
__attribute__((__visibility__("default"))) int64_t
|
||||||
|
ConflictSet_getBytes(void *cs) {
|
||||||
|
using Impl = ConflictSet::Impl;
|
||||||
|
return ((Impl *)cs)->totalBytes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SHOW_MEMORY
|
||||||
|
struct __attribute__((visibility("default"))) PeakPrinter {
|
||||||
|
~PeakPrinter() {
|
||||||
|
printf("malloc bytes: %g\n", double(mallocBytes));
|
||||||
|
printf("Peak malloc bytes: %g\n", double(peakMallocBytes));
|
||||||
|
}
|
||||||
|
} peakPrinter;
|
||||||
|
#endif
|
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
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) {
|
||||||
printf("Running: %s\n", argv[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();
|
||||||
|
@@ -7,6 +7,7 @@ int main(void) {
|
|||||||
ConflictSet_WriteRange w;
|
ConflictSet_WriteRange w;
|
||||||
ConflictSet_Result result;
|
ConflictSet_Result result;
|
||||||
ConflictSet_ReadRange r;
|
ConflictSet_ReadRange r;
|
||||||
|
int64_t bytes;
|
||||||
w.begin.p = (const uint8_t *)"0000";
|
w.begin.p = (const uint8_t *)"0000";
|
||||||
w.begin.len = 4;
|
w.begin.len = 4;
|
||||||
w.end.len = 0;
|
w.end.len = 0;
|
||||||
@@ -17,6 +18,8 @@ int main(void) {
|
|||||||
r.readVersion = 0;
|
r.readVersion = 0;
|
||||||
ConflictSet_check(cs, &r, &result, 1);
|
ConflictSet_check(cs, &r, &result, 1);
|
||||||
assert(result == ConflictSet_Conflict);
|
assert(result == ConflictSet_Conflict);
|
||||||
|
bytes = ConflictSet_getBytes(cs);
|
||||||
|
assert(bytes > 0);
|
||||||
ConflictSet_destroy(cs);
|
ConflictSet_destroy(cs);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
using namespace weaselab;
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
ConflictSet cs(0);
|
ConflictSet cs(0);
|
||||||
ConflictSet::WriteRange w;
|
ConflictSet::WriteRange w;
|
||||||
@@ -17,4 +19,6 @@ int main(void) {
|
|||||||
r.readVersion = 0;
|
r.readVersion = 0;
|
||||||
cs.check(&r, &result, 1);
|
cs.check(&r, &result, 1);
|
||||||
assert(result == ConflictSet::Conflict);
|
assert(result == ConflictSet::Conflict);
|
||||||
|
int64_t bytes = cs.getBytes();
|
||||||
|
assert(bytes > 0);
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
BIN
corpus/00cc0f31d9e079e5c10967791cbfc214c876da48
Normal file
BIN
corpus/00cc0f31d9e079e5c10967791cbfc214c876da48
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/02057227d6245d09b874d53295f14ddb87ee54ff
Normal file
BIN
corpus/02057227d6245d09b874d53295f14ddb87ee54ff
Normal file
Binary file not shown.
BIN
corpus/0258a68ab599675ffb6639a7e1e3cea2879c79cf
Normal file
BIN
corpus/0258a68ab599675ffb6639a7e1e3cea2879c79cf
Normal file
Binary file not shown.
BIN
corpus/0325dc4513367ff3f788d540a3d5037cd8422645
Normal file
BIN
corpus/0325dc4513367ff3f788d540a3d5037cd8422645
Normal file
Binary file not shown.
BIN
corpus/0415011bcf7b79337a7fb013d85f9b840b8d2050
Normal file
BIN
corpus/0415011bcf7b79337a7fb013d85f9b840b8d2050
Normal file
Binary file not shown.
BIN
corpus/0503541cc3e72b44e61518ff3d525f226c64ace7
Normal file
BIN
corpus/0503541cc3e72b44e61518ff3d525f226c64ace7
Normal file
Binary file not shown.
@@ -1 +0,0 @@
|
|||||||
:
|
|
BIN
corpus/05bef24faf30d29da5b7caa52f80302985c00e8c
Normal file
BIN
corpus/05bef24faf30d29da5b7caa52f80302985c00e8c
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/063d680d490143cf5fbcb7414f97affed2f66493
Normal file
BIN
corpus/063d680d490143cf5fbcb7414f97affed2f66493
Normal file
Binary file not shown.
BIN
corpus/064b20fcb90c53503dbb803dc85ff3c5427fe469
Normal file
BIN
corpus/064b20fcb90c53503dbb803dc85ff3c5427fe469
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/072efe2ef3d857c2a7d417e010933d496386ea2b
Normal file
BIN
corpus/072efe2ef3d857c2a7d417e010933d496386ea2b
Normal file
Binary file not shown.
BIN
corpus/07caf39a29c8f5f703a85dabf1069073f1155f9a
Normal file
BIN
corpus/07caf39a29c8f5f703a85dabf1069073f1155f9a
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/080c4a75f5549a222909e354ac0d00c63f11701a
Normal file
BIN
corpus/080c4a75f5549a222909e354ac0d00c63f11701a
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/09577892321d14b660c77955dc05ba4cf9bcc05c
Normal file
BIN
corpus/09577892321d14b660c77955dc05ba4cf9bcc05c
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/0b2b81913b5ef8e7dc1c0d9486f5dd1df578069c
Normal file
BIN
corpus/0b2b81913b5ef8e7dc1c0d9486f5dd1df578069c
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/0cab3671b418e023a9b955a5bcdb339a5d80885d
Normal file
BIN
corpus/0cab3671b418e023a9b955a5bcdb339a5d80885d
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/0d668e5a8e3e3fc505d99bb1b0fb2633bc8e616c
Normal file
BIN
corpus/0d668e5a8e3e3fc505d99bb1b0fb2633bc8e616c
Normal file
Binary file not shown.
BIN
corpus/0dd7586cd48024a419c0ab49808b958d6540becc
Normal file
BIN
corpus/0dd7586cd48024a419c0ab49808b958d6540becc
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/0e8030a76f0434cddf6b81ca053e3cc208c2ea03
Normal file
BIN
corpus/0e8030a76f0434cddf6b81ca053e3cc208c2ea03
Normal file
Binary file not shown.
BIN
corpus/0ebb5811e76d95913a595fdeb53d8d440c84d027
Normal file
BIN
corpus/0ebb5811e76d95913a595fdeb53d8d440c84d027
Normal file
Binary file not shown.
BIN
corpus/0f5349817b85b03ef24015b1cda7aa69c06e53d9
Normal file
BIN
corpus/0f5349817b85b03ef24015b1cda7aa69c06e53d9
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/0f8b6a2d4ebe4472b25b81d4e8d35586c75af9f9
Normal file
BIN
corpus/0f8b6a2d4ebe4472b25b81d4e8d35586c75af9f9
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/13f781904a9065579d637731c787998f305cc860
Normal file
BIN
corpus/13f781904a9065579d637731c787998f305cc860
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/15d58ff012753e558bfc8e5ff95e456a24654fe1
Normal file
BIN
corpus/15d58ff012753e558bfc8e5ff95e456a24654fe1
Normal file
Binary file not shown.
BIN
corpus/15ff9acbb757117edbc8fcafa13a902f8dfad08d
Normal file
BIN
corpus/15ff9acbb757117edbc8fcafa13a902f8dfad08d
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/18a37da332a8fc0b894fb32da8aa17e981a20e16
Normal file
BIN
corpus/18a37da332a8fc0b894fb32da8aa17e981a20e16
Normal file
Binary file not shown.
BIN
corpus/18e0a1a32d1dfac596258d76367fe3d072863cab
Normal file
BIN
corpus/18e0a1a32d1dfac596258d76367fe3d072863cab
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/199a623aac6456b63c51775bfc307f92af877ee9
Normal file
BIN
corpus/199a623aac6456b63c51775bfc307f92af877ee9
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/1b1ee095f24377da663057a4c055795fac40bfda
Normal file
BIN
corpus/1b1ee095f24377da663057a4c055795fac40bfda
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/1ca245aada69d5d286c8e8782f03b2b5503a26f5
Normal file
BIN
corpus/1ca245aada69d5d286c8e8782f03b2b5503a26f5
Normal file
Binary file not shown.
BIN
corpus/1e24a4e9325031dadafecedb99f15b87e97a1812
Normal file
BIN
corpus/1e24a4e9325031dadafecedb99f15b87e97a1812
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/1e33bf9cb1d0e84d9c9780608b43444495c4d8bf
Normal file
BIN
corpus/1e33bf9cb1d0e84d9c9780608b43444495c4d8bf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/1fcf4bf1173d1054a5e85375ff7667f392508faa
Normal file
BIN
corpus/1fcf4bf1173d1054a5e85375ff7667f392508faa
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/20a353ee3251c2f27b27794c4118cebb24d16b59
Normal file
BIN
corpus/20a353ee3251c2f27b27794c4118cebb24d16b59
Normal file
Binary file not shown.
BIN
corpus/20df7c1e5e3acf2e9d7b050a7dd591b4ace6819e
Normal file
BIN
corpus/20df7c1e5e3acf2e9d7b050a7dd591b4ace6819e
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/218f8656038aeb0bfd406d7abf7908501243a181
Normal file
BIN
corpus/218f8656038aeb0bfd406d7abf7908501243a181
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/234e5cd85e9ffa7fa5a4ae6491025898ac412ac5
Normal file
BIN
corpus/234e5cd85e9ffa7fa5a4ae6491025898ac412ac5
Normal file
Binary file not shown.
BIN
corpus/23f00c1ae1c35400efbbeb2156f6e9d45f6bfcce
Normal file
BIN
corpus/23f00c1ae1c35400efbbeb2156f6e9d45f6bfcce
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