Compare commits
107 Commits
v0.0.2
...
2646d5eaf1
Author | SHA1 | Date | |
---|---|---|---|
2646d5eaf1 | |||
0367ba9856 | |||
9dec45317e | |||
a68ad5dd17 | |||
8e3eacb54f | |||
0184e1d7f6 | |||
c52d50f4f9 | |||
447da11d59 | |||
daa8e02d4f | |||
fd3ea2c2a8 | |||
0b839b9d7e | |||
11a022dcf7 | |||
94da4c72a5 | |||
461e07822a | |||
75499543e7 | |||
81f44d352f | |||
45da8fb996 | |||
4958a4cced | |||
587874841f | |||
648b0b9238 | |||
d3f4afa167 | |||
f762add4d6 | |||
b311e5f1f0 | |||
ff81890921 | |||
0e96177f5c | |||
efb0e52a0a | |||
2df7000090 | |||
5378a06c39 | |||
12c6ed2568 | |||
a2bf839b19 | |||
c065b185ae | |||
639518bed4 | |||
7de983cc15 | |||
1b4b61ddc6 | |||
bff7b85de2 | |||
9108ee209a | |||
f8bf1c6eb4 | |||
4da2a01614 | |||
bb0e654040 | |||
cce7d29410 | |||
13f8d3fa8a | |||
02866a8cae | |||
fa86d3e707 | |||
7d1d1d7b2a | |||
789ecc29b3 | |||
08f2998a85 | |||
c882d7663d | |||
bfea4384ba | |||
6520e3d734 | |||
23ace8aac5 | |||
62e35de320 | |||
22e4ab01a1 | |||
b3aeed0caa | |||
5f3833e965 | |||
8b1cd9c052 | |||
bb9bc3d7b5 | |||
89b3354a80 | |||
488c723726 | |||
76d0785b33 | |||
add0af11ad | |||
2c0adf4a8b | |||
e8ac78cce6 | |||
13d447c9fe | |||
da7523c5cf | |||
a074bc6f72 | |||
1553a44986 | |||
859ac352e6 | |||
2eb461b8ea | |||
e2e92f4ef5 | |||
f6f25cfcce | |||
c13dc88ff4 | |||
aa5dbb2887 | |||
ea76e04cda | |||
452007e079 | |||
37c75f747b | |||
c96d682483 | |||
6e63fd5126 | |||
f2678de811 | |||
4d7ad075b2 | |||
d2e1863593 | |||
bf91bca16d | |||
08ed17f47b | |||
76a45f16ad | |||
c15d296432 | |||
64a98c529c | |||
ed1388ed21 | |||
309d315956 | |||
eab2e46a56 | |||
85db1a8786 | |||
717f9d6829 | |||
fd93300ce8 | |||
b7e16b31ff | |||
a324d31518 | |||
fdb05e0e33 | |||
7c27d4a972 | |||
738de01cb4 | |||
325cab6a95 | |||
0b2821941a | |||
a40b5dcd74 | |||
193b1926ff | |||
1c900c5a8c | |||
90fdcdd51a | |||
eb3f6823eb | |||
1534e10b75 | |||
3c100ccee8 | |||
5cf45d1c35 | |||
4f97932893 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
.cache
|
||||
__pycache__
|
||||
build
|
||||
|
@@ -1,11 +1,11 @@
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: 6d365699efc33b1b432eab5b4ae331a19e1857de # frozen: v18.1.2
|
||||
rev: 6d365699efc33b1b432eab5b4ae331a19e1857de # frozen: v18.1.2
|
||||
hooks:
|
||||
- id: clang-format
|
||||
exclude: ".*third_party/.*"
|
||||
- repo: https://github.com/cheshirekow/cmake-format-precommit
|
||||
rev: e2c2116d86a80e72e7146a06e68b7c228afc6319 # frozen: v0.6.13
|
||||
rev: e2c2116d86a80e72e7146a06e68b7c228afc6319 # frozen: v0.6.13
|
||||
hooks:
|
||||
- id: cmake-format
|
||||
- repo: local
|
||||
@@ -13,7 +13,7 @@ repos:
|
||||
- id: debug verbose check
|
||||
name: disallow checking in DEBUG_VERBOSE=1
|
||||
description: disallow checking in DEBUG_VERBOSE=1
|
||||
entry: '^#define DEBUG_VERBOSE 1$'
|
||||
entry: "^#define DEBUG_VERBOSE 1$"
|
||||
language: pygrep
|
||||
types: [c++]
|
||||
- repo: local
|
||||
@@ -21,10 +21,14 @@ repos:
|
||||
- id: debug verbose check
|
||||
name: disallow checking in SHOW_MEMORY=1
|
||||
description: disallow checking in SHOW_MEMORY=1
|
||||
entry: '^#define SHOW_MEMORY 1$'
|
||||
entry: "^#define SHOW_MEMORY 1$"
|
||||
language: pygrep
|
||||
types: [c++]
|
||||
- repo: https://github.com/shellcheck-py/shellcheck-py
|
||||
rev: a23f6b85d0fdd5bb9d564e2579e678033debbdff # frozen: v0.10.0.1
|
||||
rev: a23f6b85d0fdd5bb9d564e2579e678033debbdff # frozen: v0.10.0.1
|
||||
hooks:
|
||||
- id: shellcheck
|
||||
- id: shellcheck
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 552baf822992936134cbd31a38f69c8cfe7c0f05 # frozen: 24.3.0
|
||||
hooks:
|
||||
- id: black
|
||||
|
105
Bench.cpp
105
Bench.cpp
@@ -258,4 +258,107 @@ void benchConflictSet() {
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) { benchConflictSet(); }
|
||||
constexpr int kKeyLenForWorstCase = 50;
|
||||
|
||||
ConflictSet worstCaseConflictSetForRadixRangeRead(int cardinality) {
|
||||
ConflictSet cs{0};
|
||||
|
||||
for (int i = 0; i < kKeyLenForWorstCase; ++i) {
|
||||
for (int j = 0; j < cardinality; ++j) {
|
||||
auto b = std::vector<uint8_t>(i, 0);
|
||||
b.push_back(j);
|
||||
auto e = std::vector<uint8_t>(i, 255);
|
||||
e.push_back(255 - j);
|
||||
weaselab::ConflictSet::WriteRange w[] = {{
|
||||
{b.data(), int(b.size())},
|
||||
{nullptr, 0},
|
||||
},
|
||||
{
|
||||
{e.data(), int(e.size())},
|
||||
{nullptr, 0},
|
||||
}};
|
||||
std::sort(std::begin(w), std::end(w),
|
||||
[](const auto &lhs, const auto &rhs) {
|
||||
int cl = std::min(lhs.begin.len, rhs.begin.len);
|
||||
if (cl > 0) {
|
||||
int c = memcmp(lhs.begin.p, rhs.begin.p, cl);
|
||||
if (c != 0) {
|
||||
return c < 0;
|
||||
}
|
||||
}
|
||||
return lhs.begin.len < rhs.begin.len;
|
||||
});
|
||||
cs.addWrites(w, sizeof(w) / sizeof(w[0]), 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Defeat short-circuiting on the left
|
||||
{
|
||||
auto k = std::vector<uint8_t>(kKeyLenForWorstCase, 0);
|
||||
weaselab::ConflictSet::WriteRange w[] = {
|
||||
{
|
||||
{k.data(), int(k.size())},
|
||||
{nullptr, 0},
|
||||
},
|
||||
};
|
||||
cs.addWrites(w, sizeof(w) / sizeof(w[0]), 1);
|
||||
}
|
||||
|
||||
// Defeat short-circuiting on the right
|
||||
{
|
||||
auto k = std::vector<uint8_t>(kKeyLenForWorstCase, 255);
|
||||
weaselab::ConflictSet::WriteRange w[] = {
|
||||
{
|
||||
{k.data(), int(k.size())},
|
||||
{nullptr, 0},
|
||||
},
|
||||
};
|
||||
cs.addWrites(w, sizeof(w) / sizeof(w[0]), 1);
|
||||
}
|
||||
|
||||
return cs;
|
||||
}
|
||||
|
||||
void benchWorstCaseForRadixRangeRead() {
|
||||
ankerl::nanobench::Bench bench;
|
||||
|
||||
std::unique_ptr<ConflictSet> cs[256];
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
cs[i] =
|
||||
std::make_unique<ConflictSet>(worstCaseConflictSetForRadixRangeRead(i));
|
||||
}
|
||||
|
||||
auto begin = std::vector<uint8_t>(kKeyLenForWorstCase - 1, 0);
|
||||
begin.push_back(1);
|
||||
auto end = std::vector<uint8_t>(kKeyLenForWorstCase - 1, 255);
|
||||
end.push_back(254);
|
||||
|
||||
weaselab::ConflictSet::Result result;
|
||||
weaselab::ConflictSet::ReadRange r{
|
||||
{begin.data(), int(begin.size())}, {end.data(), int(end.size())}, 0};
|
||||
|
||||
bench.run("worst case for radix tree", [&]() {
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
result = weaselab::ConflictSet::TooOld;
|
||||
cs[i]->check(&r, &result, 1);
|
||||
if (result != weaselab::ConflictSet::Commit) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// for (int i = 0; i < 256; ++i) {
|
||||
// bench.run("worst case for radix tree, span " + std::to_string(i), [&]() {
|
||||
// result = weaselab::ConflictSet::TooOld;
|
||||
// cs[i]->check(&r, &result, 1);
|
||||
// if (result != weaselab::ConflictSet::Commit) {
|
||||
// abort();
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
benchConflictSet();
|
||||
benchWorstCaseForRadixRangeRead();
|
||||
}
|
||||
|
119
CMakeLists.txt
119
CMakeLists.txt
@@ -1,13 +1,17 @@
|
||||
cmake_minimum_required(VERSION 3.18)
|
||||
project(
|
||||
conflict-set
|
||||
VERSION 0.0.2
|
||||
VERSION 0.0.7
|
||||
DESCRIPTION
|
||||
"A data structure for optimistic concurrency control on ranges of bitwise-lexicographically-ordered keys."
|
||||
HOMEPAGE_URL "https://git.weaselab.dev/weaselab/conflict-set"
|
||||
LANGUAGES C CXX)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/version.txt ${PROJECT_VERSION})
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.txt.in
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/paper/version.txt)
|
||||
|
||||
include(CMakePushCheckState)
|
||||
include(CheckCXXCompilerFlag)
|
||||
include(CheckIncludeFileCXX)
|
||||
@@ -45,7 +49,8 @@ if(HAS_FULL_RELRO)
|
||||
endif()
|
||||
cmake_pop_check_state()
|
||||
|
||||
set(version_script_flags LINKER:--version-script=${CMAKE_SOURCE_DIR}/linker.map)
|
||||
set(version_script_flags
|
||||
LINKER:--version-script=${CMAKE_CURRENT_SOURCE_DIR}/linker.map)
|
||||
cmake_push_check_state()
|
||||
list(APPEND CMAKE_REQUIRED_LINK_OPTIONS ${version_script_flags})
|
||||
check_cxx_source_compiles("int main(){}" HAS_VERSION_SCRIPT FAIL_REGEX
|
||||
@@ -54,10 +59,14 @@ cmake_pop_check_state()
|
||||
|
||||
option(USE_SIMD_FALLBACK
|
||||
"Use fallback implementations of functions that use SIMD" OFF)
|
||||
option(
|
||||
USE_32_BIT_VERSIONS
|
||||
"Store 32 bit versions internally, and rely on versions never being different by more than 2e9"
|
||||
OFF)
|
||||
|
||||
# This is encouraged according to
|
||||
# https://valgrind.org/docs/manual/manual-core-adv.html#manual-core-adv.clientreq
|
||||
include_directories(SYSTEM ${CMAKE_SOURCE_DIR}/third_party/valgrind)
|
||||
include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/valgrind)
|
||||
|
||||
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-Wno-invalid-offsetof>)
|
||||
|
||||
@@ -98,25 +107,30 @@ if(NOT USE_SIMD_FALLBACK)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(USE_32_BIT_VERSIONS)
|
||||
add_compile_definitions(INTERNAL_VERSION_32_BIT=1)
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "")
|
||||
|
||||
add_library(${PROJECT_NAME}-object OBJECT ConflictSet.cpp)
|
||||
target_compile_options(${PROJECT_NAME}-object PRIVATE -fno-exceptions
|
||||
-fvisibility=hidden)
|
||||
target_include_directories(${PROJECT_NAME}-object
|
||||
PRIVATE ${CMAKE_SOURCE_DIR}/include)
|
||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
add_library(${PROJECT_NAME} SHARED $<TARGET_OBJECTS:${PROJECT_NAME}-object>)
|
||||
set_target_properties(
|
||||
${PROJECT_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY
|
||||
"${CMAKE_BINARY_DIR}/radix_tree")
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/radix_tree")
|
||||
if(NOT CMAKE_BUILD_TYPE STREQUAL Debug)
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE C)
|
||||
endif()
|
||||
|
||||
if(HAS_VERSION_SCRIPT)
|
||||
target_link_options(${PROJECT_NAME} PRIVATE
|
||||
LINKER:--version-script=${CMAKE_SOURCE_DIR}/linker.map)
|
||||
target_link_options(
|
||||
${PROJECT_NAME} PRIVATE
|
||||
LINKER:--version-script=${CMAKE_CURRENT_SOURCE_DIR}/linker.map)
|
||||
endif()
|
||||
|
||||
add_library(${PROJECT_NAME}-static STATIC
|
||||
@@ -128,8 +142,8 @@ endif()
|
||||
if(APPLE)
|
||||
add_custom_command(
|
||||
TARGET ${PROJECT_NAME}-static
|
||||
PRE_BUILD
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/privatize_symbols_macos.sh
|
||||
PRE_LINK
|
||||
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/privatize_symbols_macos.sh
|
||||
$<TARGET_OBJECTS:${PROJECT_NAME}-object>)
|
||||
else()
|
||||
add_custom_command(
|
||||
@@ -137,21 +151,22 @@ else()
|
||||
POST_BUILD
|
||||
COMMAND
|
||||
${CMAKE_OBJCOPY}
|
||||
--keep-global-symbols=${CMAKE_SOURCE_DIR}/symbol-exports.txt
|
||||
--keep-global-symbols=${CMAKE_CURRENT_SOURCE_DIR}/symbol-exports.txt
|
||||
$<TARGET_FILE:${PROJECT_NAME}-static> || echo
|
||||
"Proceeding with all symbols global in static library")
|
||||
endif()
|
||||
|
||||
set(TEST_FLAGS -Wall -Wextra -Wunreachable-code -Wpedantic -UNDEBUG)
|
||||
|
||||
include(CTest)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
# disable tests if this is being used through e.g. FetchContent
|
||||
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND BUILD_TESTING)
|
||||
|
||||
set(TEST_FLAGS -Wall -Wextra -Wunreachable-code -Wpedantic -UNDEBUG)
|
||||
|
||||
# corpus tests, which are tests curated by libfuzzer. The goal is to get broad
|
||||
# coverage with a small number of tests.
|
||||
|
||||
file(GLOB CORPUS_TESTS ${CMAKE_SOURCE_DIR}/corpus/*)
|
||||
file(GLOB CORPUS_TESTS ${CMAKE_CURRENT_SOURCE_DIR}/corpus/*)
|
||||
|
||||
# extra testing that relies on shared libraries, which aren't available with
|
||||
# wasm
|
||||
@@ -160,9 +175,11 @@ if(BUILD_TESTING)
|
||||
add_library(skip_list SHARED SkipList.cpp)
|
||||
target_compile_options(skip_list PRIVATE -fno-exceptions
|
||||
-fvisibility=hidden)
|
||||
target_include_directories(skip_list PUBLIC ${CMAKE_SOURCE_DIR}/include)
|
||||
set_target_properties(skip_list PROPERTIES LIBRARY_OUTPUT_DIRECTORY
|
||||
"${CMAKE_BINARY_DIR}/skip_list")
|
||||
target_include_directories(skip_list
|
||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
set_target_properties(
|
||||
skip_list PROPERTIES LIBRARY_OUTPUT_DIRECTORY
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/skip_list")
|
||||
set_target_properties(skip_list PROPERTIES OUTPUT_NAME ${PROJECT_NAME})
|
||||
set_target_properties(
|
||||
skip_list PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION
|
||||
@@ -173,10 +190,11 @@ if(BUILD_TESTING)
|
||||
add_library(hash_table SHARED HashTable.cpp)
|
||||
target_compile_options(hash_table PRIVATE -fno-exceptions
|
||||
-fvisibility=hidden)
|
||||
target_include_directories(hash_table PUBLIC ${CMAKE_SOURCE_DIR}/include)
|
||||
target_include_directories(hash_table
|
||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
set_target_properties(
|
||||
hash_table PROPERTIES LIBRARY_OUTPUT_DIRECTORY
|
||||
"${CMAKE_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 VERSION ${PROJECT_VERSION} SOVERSION
|
||||
@@ -259,14 +277,26 @@ if(BUILD_TESTING)
|
||||
|
||||
# scripted tests. Written manually to fill in anything libfuzzer couldn't
|
||||
# find.
|
||||
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()
|
||||
if(NOT CMAKE_CROSSCOMPILING)
|
||||
find_package(Python3 REQUIRED COMPONENTS Interpreter)
|
||||
set_property(
|
||||
DIRECTORY
|
||||
APPEND
|
||||
PROPERTY CMAKE_CONFIGURE_DEPENDS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_conflict_set.py)
|
||||
execute_process(
|
||||
COMMAND ${Python3_EXECUTABLE}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_conflict_set.py list
|
||||
OUTPUT_VARIABLE SCRIPT_TESTS)
|
||||
foreach(TEST ${SCRIPT_TESTS})
|
||||
add_test(
|
||||
NAME script_test_${TEST}
|
||||
COMMAND
|
||||
${Python3_EXECUTABLE}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_conflict_set.py test ${TEST}
|
||||
--build-dir ${CMAKE_CURRENT_BINARY_DIR})
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
find_program(VALGRIND_EXE valgrind)
|
||||
if(VALGRIND_EXE AND NOT CMAKE_CROSSCOMPILING)
|
||||
@@ -298,25 +328,26 @@ if(BUILD_TESTING)
|
||||
# symbol visibility tests
|
||||
if(NOT WASM AND NOT CMAKE_BUILD_TYPE STREQUAL Debug)
|
||||
if(APPLE)
|
||||
set(symbol_exports ${CMAKE_SOURCE_DIR}/apple-symbol-exports.txt)
|
||||
set(symbol_imports ${CMAKE_SOURCE_DIR}/apple-symbol-imports.txt)
|
||||
set(symbol_exports ${CMAKE_CURRENT_SOURCE_DIR}/apple-symbol-exports.txt)
|
||||
set(symbol_imports ${CMAKE_CURRENT_SOURCE_DIR}/apple-symbol-imports.txt)
|
||||
else()
|
||||
set(symbol_exports ${CMAKE_SOURCE_DIR}/symbol-exports.txt)
|
||||
set(symbol_exports ${CMAKE_CURRENT_SOURCE_DIR}/symbol-exports.txt)
|
||||
if(CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64)
|
||||
set(symbol_imports ${CMAKE_SOURCE_DIR}/aarch64-symbol-imports.txt)
|
||||
set(symbol_imports
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/aarch64-symbol-imports.txt)
|
||||
else()
|
||||
set(symbol_imports ${CMAKE_SOURCE_DIR}/symbol-imports.txt)
|
||||
set(symbol_imports ${CMAKE_CURRENT_SOURCE_DIR}/symbol-imports.txt)
|
||||
endif()
|
||||
endif()
|
||||
add_test(
|
||||
NAME conflict_set_shared_symbols
|
||||
COMMAND
|
||||
${CMAKE_SOURCE_DIR}/test_symbols.sh $<TARGET_FILE:${PROJECT_NAME}>
|
||||
${symbol_exports} ${symbol_imports})
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_symbols.sh
|
||||
$<TARGET_FILE:${PROJECT_NAME}> ${symbol_exports} ${symbol_imports})
|
||||
add_test(
|
||||
NAME conflict_set_static_symbols
|
||||
COMMAND
|
||||
${CMAKE_SOURCE_DIR}/test_symbols.sh
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_symbols.sh
|
||||
$<TARGET_FILE:${PROJECT_NAME}-static> ${symbol_exports}
|
||||
${symbol_imports})
|
||||
endif()
|
||||
@@ -333,6 +364,7 @@ endif()
|
||||
# packaging
|
||||
|
||||
set(CPACK_PACKAGE_CONTACT andrew@weaselab.dev)
|
||||
set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME all)
|
||||
|
||||
set(CPACK_PACKAGE_VENDOR "Weaselab")
|
||||
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
|
||||
@@ -353,6 +385,20 @@ else()
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.14)")
|
||||
endif()
|
||||
|
||||
# macos
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 11.0)
|
||||
if(APPLE)
|
||||
find_program(PANDOC_EXE pandoc)
|
||||
if(PANDOC_EXE)
|
||||
execute_process(COMMAND ${PANDOC_EXE} ${CMAKE_CURRENT_SOURCE_DIR}/README.md
|
||||
-o ${CMAKE_CURRENT_BINARY_DIR}/README.txt)
|
||||
set(CPACK_RESOURCE_FILE_README ${CMAKE_CURRENT_BINARY_DIR}/README.txt)
|
||||
endif()
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/LICENSE
|
||||
${CMAKE_CURRENT_BINARY_DIR}/LICENSE.txt COPYONLY)
|
||||
set(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_CURRENT_BINARY_DIR}/LICENSE.txt)
|
||||
endif()
|
||||
|
||||
include(CPack)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
@@ -377,8 +423,11 @@ install(
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
install(DIRECTORY include/
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME})
|
||||
|
||||
install(EXPORT ${PROJECT_NAME}Config
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake)
|
||||
|
||||
cpack_add_component(all)
|
||||
|
1420
ConflictSet.cpp
1420
ConflictSet.cpp
File diff suppressed because it is too large
Load Diff
92
Internal.h
92
Internal.h
@@ -99,8 +99,7 @@ __attribute__((always_inline)) inline void safe_free(void *p, size_t s) {
|
||||
mallocBytesDelta -= s;
|
||||
#if SHOW_MEMORY
|
||||
mallocBytes -= s;
|
||||
free(p);
|
||||
#else
|
||||
#endif
|
||||
#ifndef NDEBUG
|
||||
(char *&)p -= kMallocHeaderSize;
|
||||
size_t expected;
|
||||
@@ -108,7 +107,6 @@ __attribute__((always_inline)) inline void safe_free(void *p, size_t s) {
|
||||
assert(s == expected);
|
||||
#endif
|
||||
free(p);
|
||||
#endif
|
||||
}
|
||||
|
||||
// ==================== BEGIN ARENA IMPL ====================
|
||||
@@ -257,10 +255,65 @@ template <class T> struct ArenaAlloc {
|
||||
void deallocate(T *, size_t) noexcept {}
|
||||
};
|
||||
|
||||
template <class T> using Vector = std::vector<T, ArenaAlloc<T>>;
|
||||
template <class T> auto vector(Arena &arena) {
|
||||
return Vector<T>(ArenaAlloc<T>(&arena));
|
||||
}
|
||||
template <class T> struct Vector {
|
||||
static_assert(std::is_trivially_destructible_v<T>);
|
||||
static_assert(std::is_trivially_copyable_v<T>);
|
||||
|
||||
explicit Vector(Arena *arena)
|
||||
: arena(arena), t(nullptr), size_(0), capacity(0) {}
|
||||
|
||||
void append(std::span<const T> slice) {
|
||||
if (size_ + int(slice.size()) > capacity) {
|
||||
grow(std::max<int>(size_ + slice.size(), capacity * 2));
|
||||
}
|
||||
if (slice.size() > 0) {
|
||||
memcpy(const_cast<std::remove_const_t<T> *>(t) + size_, slice.data(),
|
||||
slice.size() * sizeof(T));
|
||||
}
|
||||
size_ += slice.size();
|
||||
}
|
||||
|
||||
void push_back(const T &t) { append(std::span<const T>(&t, 1)); }
|
||||
|
||||
T *begin() { return t; }
|
||||
T *end() { return t + size_; }
|
||||
T *data() { return t; }
|
||||
T &back() {
|
||||
assert(size_ > 0);
|
||||
return t[size_ - 1];
|
||||
}
|
||||
T &operator[](int i) {
|
||||
assert(i >= 0 && i < size_);
|
||||
return t[i];
|
||||
}
|
||||
|
||||
void pop_back() {
|
||||
assert(size_ > 0);
|
||||
--size_;
|
||||
}
|
||||
|
||||
int size() const { return size_; }
|
||||
|
||||
operator std::span<const T>() const { return std::span(t, size_); }
|
||||
|
||||
private:
|
||||
void grow(int newCapacity) {
|
||||
capacity = newCapacity;
|
||||
auto old = std::span<const T>(*this);
|
||||
t = (T *)new (std::align_val_t(alignof(T)), *arena)
|
||||
uint8_t[capacity * sizeof(T)];
|
||||
size_ = 0;
|
||||
append(old);
|
||||
}
|
||||
|
||||
Arena *arena;
|
||||
T *t;
|
||||
int size_;
|
||||
int capacity;
|
||||
};
|
||||
|
||||
template <class T> auto vector(Arena &arena) { return Vector<T>(&arena); }
|
||||
|
||||
template <class T, class C> using Set = std::set<T, C, ArenaAlloc<T>>;
|
||||
template <class T, class C = std::less<T>> auto set(Arena &arena) {
|
||||
return Set<T, C>(ArenaAlloc<T>(&arena));
|
||||
@@ -525,15 +578,18 @@ template <class ConflictSetImpl> struct TestDriver {
|
||||
explicit TestDriver(const uint8_t *data, size_t size)
|
||||
: arbitrary({data, size}) {}
|
||||
|
||||
int64_t writeVersion = 0;
|
||||
int64_t oldestVersion = 0;
|
||||
int64_t oldestVersion = arbitrary.bounded(2) ? 0 : 0xfffffff0;
|
||||
int64_t writeVersion = oldestVersion + 100;
|
||||
ConflictSetImpl cs{oldestVersion};
|
||||
ReferenceImpl refImpl{oldestVersion};
|
||||
|
||||
constexpr static auto kMaxKeyLen = 8;
|
||||
constexpr static auto kMaxKeySuffixLen = 8;
|
||||
|
||||
bool ok = true;
|
||||
|
||||
const int prefixLen = arbitrary.bounded(512);
|
||||
const int prefixByte = arbitrary.randT<uint8_t>();
|
||||
|
||||
// Call until it returns true, for "done". Check internal invariants etc
|
||||
// between calls to next.
|
||||
bool next() {
|
||||
@@ -544,7 +600,7 @@ template <class ConflictSetImpl> struct TestDriver {
|
||||
{
|
||||
int numPointWrites = arbitrary.bounded(100);
|
||||
int numRangeWrites = arbitrary.bounded(100);
|
||||
int64_t v = ++writeVersion;
|
||||
int64_t v = (writeVersion += arbitrary.bounded(10));
|
||||
auto *writes =
|
||||
new (arena) ConflictSet::WriteRange[numPointWrites + numRangeWrites];
|
||||
auto keys = set<std::string_view>(arena);
|
||||
@@ -552,9 +608,10 @@ template <class ConflictSetImpl> struct TestDriver {
|
||||
if (!arbitrary.hasEntropy()) {
|
||||
return true;
|
||||
}
|
||||
int keyLen = arbitrary.bounded(kMaxKeyLen);
|
||||
int keyLen = prefixLen + arbitrary.bounded(kMaxKeySuffixLen);
|
||||
auto *begin = new (arena) uint8_t[keyLen];
|
||||
arbitrary.randomBytes(begin, keyLen);
|
||||
memset(begin, prefixByte, prefixLen);
|
||||
arbitrary.randomBytes(begin + prefixLen, keyLen - prefixLen);
|
||||
keys.insert(std::string_view((const char *)begin, keyLen));
|
||||
}
|
||||
|
||||
@@ -603,8 +660,8 @@ template <class ConflictSetImpl> struct TestDriver {
|
||||
|
||||
refImpl.addWrites(writes, numPointWrites + numRangeWrites, v);
|
||||
|
||||
oldestVersion = std::max<int64_t>(writeVersion - arbitrary.bounded(10),
|
||||
oldestVersion);
|
||||
oldestVersion =
|
||||
std::min(writeVersion - 10, oldestVersion + arbitrary.bounded(10));
|
||||
cs.setOldestVersion(oldestVersion);
|
||||
refImpl.setOldestVersion(oldestVersion);
|
||||
}
|
||||
@@ -619,9 +676,10 @@ template <class ConflictSetImpl> struct TestDriver {
|
||||
if (!arbitrary.hasEntropy()) {
|
||||
return true;
|
||||
}
|
||||
int keyLen = arbitrary.bounded(kMaxKeyLen);
|
||||
int keyLen = prefixLen + arbitrary.bounded(kMaxKeySuffixLen);
|
||||
auto *begin = new (arena) uint8_t[keyLen];
|
||||
arbitrary.randomBytes(begin, keyLen);
|
||||
memset(begin, prefixByte, prefixLen);
|
||||
arbitrary.randomBytes(begin + prefixLen, keyLen - prefixLen);
|
||||
keys.insert(std::string_view((const char *)begin, keyLen));
|
||||
}
|
||||
|
||||
|
16
Jenkinsfile
vendored
16
Jenkinsfile
vendored
@@ -59,6 +59,17 @@ pipeline {
|
||||
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]') {
|
||||
agent {
|
||||
dockerfile {
|
||||
@@ -110,7 +121,10 @@ pipeline {
|
||||
sh '''
|
||||
gcovr -f ConflictSet.cpp --cobertura > build/coverage.xml
|
||||
'''
|
||||
cobertura autoUpdateHealth: false, autoUpdateStability: false, coberturaReportFile: 'build/coverage.xml', conditionalCoverageTargets: '70, 0, 0', failUnhealthy: false, failUnstable: false, lineCoverageTargets: '80, 0, 0', maxNumberOfBuilds: 0, methodCoverageTargets: '80, 0, 0', onlyStable: false, sourceEncoding: 'ASCII', zoomCoverageChart: false
|
||||
recordCoverage qualityGates: [[criticality: 'NOTE', metric: 'MODULE']], tools: [[parser: 'COBERTURA', pattern: 'build/coverage.xml']]
|
||||
sh '''
|
||||
gcovr -f ConflictSet.cpp --fail-under-line 100 > /dev/null
|
||||
'''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
28
README.md
28
README.md
@@ -60,25 +60,27 @@ Performance counters:
|
||||
|
||||
| ns/op | op/s | err% | total | benchmark
|
||||
|--------------------:|--------------------:|--------:|----------:|:----------
|
||||
| 246.99 | 4,048,700.59 | 0.2% | 0.01 | `point reads`
|
||||
| 260.16 | 3,843,784.65 | 0.1% | 0.01 | `prefix reads`
|
||||
| 493.35 | 2,026,953.19 | 0.1% | 0.01 | `range reads`
|
||||
| 462.05 | 2,164,289.23 | 0.6% | 0.01 | `point writes`
|
||||
| 448.19 | 2,231,205.25 | 0.9% | 0.01 | `prefix writes`
|
||||
| 255.83 | 3,908,845.72 | 1.5% | 0.02 | `range writes`
|
||||
| 582.63 | 1,716,349.02 | 1.3% | 0.01 | `monotonic increasing point writes`
|
||||
| 256.89 | 3,892,784.92 | 0.3% | 0.01 | `point reads`
|
||||
| 272.90 | 3,664,395.04 | 0.2% | 0.01 | `prefix reads`
|
||||
| 507.22 | 1,971,549.50 | 0.7% | 0.01 | `range reads`
|
||||
| 452.66 | 2,209,181.91 | 0.5% | 0.01 | `point writes`
|
||||
| 438.09 | 2,282,619.96 | 0.4% | 0.01 | `prefix writes`
|
||||
| 253.33 | 3,947,420.36 | 2.5% | 0.02 | `range writes`
|
||||
| 574.07 | 1,741,936.71 | 0.3% | 0.01 | `monotonic increasing point writes`
|
||||
| 151,562.50 | 6,597.94 | 1.5% | 0.01 | `worst case for radix tree`
|
||||
|
||||
## Radix tree (this implementation)
|
||||
|
||||
| ns/op | op/s | err% | total | benchmark
|
||||
|--------------------:|--------------------:|--------:|----------:|:----------
|
||||
| 19.42 | 51,483,206.67 | 0.3% | 0.01 | `point reads`
|
||||
| 58.43 | 17,115,612.57 | 0.1% | 0.01 | `prefix reads`
|
||||
| 216.09 | 4,627,766.60 | 0.2% | 0.01 | `range reads`
|
||||
| 28.35 | 35,267,567.72 | 0.2% | 0.01 | `point writes`
|
||||
| 43.43 | 23,026,226.17 | 0.2% | 0.01 | `prefix writes`
|
||||
| 19.83 | 50,420,955.28 | 0.1% | 0.01 | `point reads`
|
||||
| 55.95 | 17,872,542.40 | 0.5% | 0.01 | `prefix reads`
|
||||
| 88.28 | 11,327,709.50 | 0.4% | 0.01 | `range reads`
|
||||
| 29.15 | 34,309,531.64 | 0.5% | 0.01 | `point writes`
|
||||
| 42.36 | 23,607,424.27 | 1.1% | 0.01 | `prefix writes`
|
||||
| 50.00 | 20,000,000.00 | 0.0% | 0.01 | `range writes`
|
||||
| 92.38 | 10,824,863.69 | 4.1% | 0.01 | `monotonic increasing point writes`
|
||||
| 93.52 | 10,692,413.79 | 3.3% | 0.01 | `monotonic increasing point writes`
|
||||
| 2,388,417.00 | 418.69 | 0.4% | 0.03 | `worst case for radix tree`
|
||||
|
||||
# "Real data" test
|
||||
|
||||
|
155
ScriptTest.cpp
155
ScriptTest.cpp
@@ -1,155 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
}
|
96
SkipList.cpp
96
SkipList.cpp
@@ -16,6 +16,8 @@
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* This source code is modified to compile outside of FoundationDB
|
||||
*/
|
||||
|
||||
#include "ConflictSet.h"
|
||||
@@ -268,13 +270,21 @@ public:
|
||||
}
|
||||
|
||||
explicit SkipList(Version version = 0) {
|
||||
#if DEBUG_VERBOSE
|
||||
fprintf(stderr, "skip_list: create\n");
|
||||
#endif
|
||||
header = Node::create(StringRef(), MaxLevels - 1);
|
||||
for (int l = 0; l < MaxLevels; l++) {
|
||||
header->setNext(l, nullptr);
|
||||
header->setMaxVersion(l, version);
|
||||
}
|
||||
}
|
||||
~SkipList() { destroy(); }
|
||||
~SkipList() {
|
||||
#if DEBUG_VERBOSE
|
||||
fprintf(stderr, "skip_list: destroy\n");
|
||||
#endif
|
||||
destroy();
|
||||
}
|
||||
SkipList(SkipList &&other) noexcept : header(other.header) {
|
||||
other.header = nullptr;
|
||||
}
|
||||
@@ -567,7 +577,8 @@ struct SkipListConflictSet {};
|
||||
|
||||
struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
Impl(int64_t oldestVersion)
|
||||
: oldestVersion(oldestVersion), skipList(oldestVersion) {}
|
||||
: oldestVersion(oldestVersion), newestVersion(oldestVersion),
|
||||
skipList(oldestVersion) {}
|
||||
void check(const ConflictSet::ReadRange *reads, ConflictSet::Result *results,
|
||||
int count) const {
|
||||
Arena arena;
|
||||
@@ -582,7 +593,8 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
}
|
||||
skipList.detectConflicts(ranges, count, results);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (reads[i].readVersion < oldestVersion) {
|
||||
if (reads[i].readVersion < oldestVersion ||
|
||||
reads[i].readVersion < newestVersion - 2e9) {
|
||||
results[i] = TooOld;
|
||||
}
|
||||
}
|
||||
@@ -590,6 +602,8 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
|
||||
void addWrites(const ConflictSet::WriteRange *writes, int count,
|
||||
int64_t writeVersion) {
|
||||
assert(writeVersion >= newestVersion);
|
||||
newestVersion = writeVersion;
|
||||
Arena arena;
|
||||
const int stringCount = count * 2;
|
||||
|
||||
@@ -603,6 +617,10 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
for (int s = stripes - 1; s >= 0; s--) {
|
||||
for (int i = 0; i * 2 < ss; ++i) {
|
||||
const auto &w = writes[s * stripeSize / 2 + i];
|
||||
#if DEBUG_VERBOSE
|
||||
printf("Write begin: %s\n", printable(w.begin).c_str());
|
||||
fflush(stdout);
|
||||
#endif
|
||||
values[i * 2] = {w.begin.p, size_t(w.begin.len)};
|
||||
values[i * 2 + 1] = w.end.len > 0
|
||||
? StringRef{w.end.p, size_t(w.end.len)}
|
||||
@@ -616,6 +634,7 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
}
|
||||
|
||||
void setOldestVersion(int64_t oldestVersion) {
|
||||
assert(oldestVersion >= this->oldestVersion);
|
||||
this->oldestVersion = oldestVersion;
|
||||
SkipList::Finger finger;
|
||||
int temp;
|
||||
@@ -634,16 +653,20 @@ private:
|
||||
Arena removalArena;
|
||||
std::span<const uint8_t> removalKey;
|
||||
int64_t oldestVersion;
|
||||
int64_t newestVersion;
|
||||
SkipList skipList;
|
||||
};
|
||||
|
||||
void ConflictSet::check(const ReadRange *reads, Result *results,
|
||||
int count) const {
|
||||
// Internal entry points. Public entry points should just delegate to these
|
||||
|
||||
void internal_check(ConflictSet::Impl *impl,
|
||||
const ConflictSet::ReadRange *reads,
|
||||
ConflictSet::Result *results, int count) {
|
||||
impl->check(reads, results, count);
|
||||
}
|
||||
|
||||
void ConflictSet::addWrites(const WriteRange *writes, int count,
|
||||
int64_t writeVersion) {
|
||||
void internal_addWrites(ConflictSet::Impl *impl,
|
||||
const ConflictSet::WriteRange *writes, int count,
|
||||
int64_t writeVersion) {
|
||||
mallocBytesDelta = 0;
|
||||
impl->addWrites(writes, count, writeVersion);
|
||||
impl->totalBytes += mallocBytesDelta;
|
||||
@@ -654,7 +677,7 @@ void ConflictSet::addWrites(const WriteRange *writes, int count,
|
||||
#endif
|
||||
}
|
||||
|
||||
void ConflictSet::setOldestVersion(int64_t oldestVersion) {
|
||||
void internal_setOldestVersion(ConflictSet::Impl *impl, int64_t oldestVersion) {
|
||||
mallocBytesDelta = 0;
|
||||
impl->setOldestVersion(oldestVersion);
|
||||
impl->totalBytes += mallocBytesDelta;
|
||||
@@ -664,19 +687,43 @@ void ConflictSet::setOldestVersion(int64_t oldestVersion) {
|
||||
}
|
||||
#endif
|
||||
}
|
||||
ConflictSet::Impl *internal_create(int64_t oldestVersion) {
|
||||
mallocBytesDelta = 0;
|
||||
auto *result = new (safe_malloc(sizeof(ConflictSet::Impl)))
|
||||
ConflictSet::Impl{oldestVersion};
|
||||
result->totalBytes += mallocBytesDelta;
|
||||
return result;
|
||||
}
|
||||
|
||||
int64_t ConflictSet::getBytes() const { return impl->totalBytes; }
|
||||
void internal_destroy(ConflictSet::Impl *impl) {
|
||||
impl->~Impl();
|
||||
safe_free(impl, sizeof(ConflictSet::Impl));
|
||||
}
|
||||
|
||||
int64_t internal_getBytes(ConflictSet::Impl *impl) { return impl->totalBytes; }
|
||||
|
||||
void ConflictSet::check(const ReadRange *reads, Result *results,
|
||||
int count) const {
|
||||
internal_check(impl, reads, results, count);
|
||||
}
|
||||
|
||||
void ConflictSet::addWrites(const WriteRange *writes, int count,
|
||||
int64_t writeVersion) {
|
||||
internal_addWrites(impl, writes, count, writeVersion);
|
||||
}
|
||||
|
||||
void ConflictSet::setOldestVersion(int64_t oldestVersion) {
|
||||
internal_setOldestVersion(impl, oldestVersion);
|
||||
}
|
||||
|
||||
int64_t ConflictSet::getBytes() const { return internal_getBytes(impl); }
|
||||
|
||||
ConflictSet::ConflictSet(int64_t oldestVersion)
|
||||
: impl((mallocBytesDelta = 0,
|
||||
new(safe_malloc(sizeof(Impl))) Impl{oldestVersion})) {
|
||||
impl->totalBytes += mallocBytesDelta;
|
||||
}
|
||||
: impl(internal_create(oldestVersion)) {}
|
||||
|
||||
ConflictSet::~ConflictSet() {
|
||||
if (impl) {
|
||||
impl->~Impl();
|
||||
safe_free(impl, sizeof(Impl));
|
||||
internal_destroy(impl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -697,37 +744,34 @@ extern "C" {
|
||||
__attribute__((__visibility__("default"))) void
|
||||
ConflictSet_check(void *cs, const ConflictSet_ReadRange *reads,
|
||||
ConflictSet_Result *results, int count) {
|
||||
((ConflictSet::Impl *)cs)->check(reads, results, count);
|
||||
internal_check((ConflictSet::Impl *)cs, reads, results, count);
|
||||
}
|
||||
__attribute__((__visibility__("default"))) void
|
||||
ConflictSet_addWrites(void *cs, const ConflictSet_WriteRange *writes, int count,
|
||||
int64_t writeVersion) {
|
||||
((ConflictSet::Impl *)cs)->addWrites(writes, count, writeVersion);
|
||||
internal_addWrites((ConflictSet::Impl *)cs, writes, count, writeVersion);
|
||||
}
|
||||
__attribute__((__visibility__("default"))) void
|
||||
ConflictSet_setOldestVersion(void *cs, int64_t oldestVersion) {
|
||||
((ConflictSet::Impl *)cs)->setOldestVersion(oldestVersion);
|
||||
internal_setOldestVersion((ConflictSet::Impl *)cs, oldestVersion);
|
||||
}
|
||||
__attribute__((__visibility__("default"))) void *
|
||||
ConflictSet_create(int64_t oldestVersion) {
|
||||
return new (safe_malloc(sizeof(ConflictSet::Impl)))
|
||||
ConflictSet::Impl{oldestVersion};
|
||||
return internal_create(oldestVersion);
|
||||
}
|
||||
__attribute__((__visibility__("default"))) void ConflictSet_destroy(void *cs) {
|
||||
using Impl = ConflictSet::Impl;
|
||||
((Impl *)cs)->~Impl();
|
||||
safe_free(cs, sizeof(Impl));
|
||||
internal_destroy((ConflictSet::Impl *)cs);
|
||||
}
|
||||
__attribute__((__visibility__("default"))) int64_t
|
||||
ConflictSet_getBytes(void *cs) {
|
||||
using Impl = ConflictSet::Impl;
|
||||
return ((Impl *)cs)->totalBytes;
|
||||
return internal_getBytes((ConflictSet::Impl *)cs);
|
||||
}
|
||||
}
|
||||
|
||||
#if SHOW_MEMORY
|
||||
struct __attribute__((visibility("default"))) PeakPrinter {
|
||||
~PeakPrinter() {
|
||||
printf("--- skip_list ---\n");
|
||||
printf("malloc bytes: %g\n", double(mallocBytes));
|
||||
printf("Peak malloc bytes: %g\n", double(peakMallocBytes));
|
||||
}
|
||||
|
@@ -1,7 +1,10 @@
|
||||
___stack_chk_fail
|
||||
___stack_chk_guard
|
||||
__tlv_bootstrap
|
||||
_abort
|
||||
_bzero
|
||||
_free
|
||||
_malloc
|
||||
_memcpy
|
||||
_memmove
|
||||
_memmove
|
||||
dyld_stub_binder
|
138
conflict_set.py
Normal file
138
conflict_set.py
Normal file
@@ -0,0 +1,138 @@
|
||||
import ctypes
|
||||
import enum
|
||||
import os
|
||||
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class _Key(ctypes.Structure):
|
||||
_fields_ = [("p", ctypes.POINTER(ctypes.c_ubyte)), ("len", ctypes.c_int)]
|
||||
|
||||
|
||||
class ReadRange(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("begin", _Key),
|
||||
("end", _Key),
|
||||
("readVersion", ctypes.c_int64),
|
||||
]
|
||||
|
||||
|
||||
class WriteRange(ctypes.Structure):
|
||||
_fields_ = [("begin", _Key), ("end", _Key)]
|
||||
|
||||
|
||||
class Result(enum.Enum):
|
||||
COMMIT = 0
|
||||
CONFLICT = 1
|
||||
TOO_OLD = 2
|
||||
|
||||
|
||||
def write(begin: bytes, end: Optional[bytes] = None) -> WriteRange:
|
||||
b = (ctypes.c_ubyte * len(begin)).from_buffer(bytearray(begin))
|
||||
|
||||
if end is None:
|
||||
e = (ctypes.c_ubyte * 0)()
|
||||
else:
|
||||
e = (ctypes.c_ubyte * len(end)).from_buffer(bytearray(end))
|
||||
return WriteRange(_Key(b, len(b)), _Key(e, len(e)))
|
||||
|
||||
|
||||
def read(version: int, begin: bytes, end: Optional[bytes] = None) -> ReadRange:
|
||||
b = (ctypes.c_ubyte * len(begin)).from_buffer(bytearray(begin))
|
||||
if end is None:
|
||||
e = (ctypes.c_ubyte * 0)()
|
||||
else:
|
||||
e = (ctypes.c_ubyte * len(end)).from_buffer(bytearray(end))
|
||||
return ReadRange(_Key(b, len(b)), _Key(e, len(e)), version)
|
||||
|
||||
|
||||
class ConflictSet:
|
||||
def __init__(
|
||||
self,
|
||||
version: int = 0,
|
||||
build_dir: Optional[str] = None,
|
||||
implementation: Optional[str] = None,
|
||||
) -> None:
|
||||
self._lib = None
|
||||
if build_dir is None:
|
||||
build_dir = os.path.dirname(__file__) + "/build"
|
||||
if implementation is None:
|
||||
implementation = "radix_tree"
|
||||
for f in (
|
||||
build_dir + "/" + implementation + "/libconflict-set.so.0",
|
||||
os.path.dirname(__file__)
|
||||
+ "/build/"
|
||||
+ implementation
|
||||
+ "/libconflict-set.0.dylib",
|
||||
):
|
||||
try:
|
||||
self._lib = ctypes.cdll.LoadLibrary(f)
|
||||
except:
|
||||
pass
|
||||
|
||||
if self._lib is None:
|
||||
import sys
|
||||
|
||||
print(
|
||||
"Could not find libconflict-set implementation " + implementation,
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
self._lib.ConflictSet_create.argtypes = (ctypes.c_int64,)
|
||||
self._lib.ConflictSet_create.restype = ctypes.c_void_p
|
||||
|
||||
self._lib.ConflictSet_check.argtypes = (
|
||||
ctypes.c_void_p,
|
||||
ctypes.POINTER(ReadRange),
|
||||
ctypes.POINTER(ctypes.c_int),
|
||||
ctypes.c_int,
|
||||
)
|
||||
|
||||
self._lib.ConflictSet_addWrites.argtypes = (
|
||||
ctypes.c_void_p,
|
||||
ctypes.POINTER(WriteRange),
|
||||
ctypes.c_int,
|
||||
ctypes.c_int64,
|
||||
)
|
||||
|
||||
self._lib.ConflictSet_setOldestVersion.argtypes = (
|
||||
ctypes.c_void_p,
|
||||
ctypes.c_int64,
|
||||
)
|
||||
|
||||
self._lib.ConflictSet_destroy.argtypes = (ctypes.c_void_p,)
|
||||
|
||||
self._lib.ConflictSet_getBytes.argtypes = (ctypes.c_void_p,)
|
||||
self._lib.ConflictSet_getBytes.restype = ctypes.c_int64
|
||||
|
||||
self.p = self._lib.ConflictSet_create(version)
|
||||
|
||||
def addWrites(self, version: int, *writes: WriteRange):
|
||||
self._lib.ConflictSet_addWrites(
|
||||
self.p, (WriteRange * len(writes))(*writes), len(writes), version
|
||||
)
|
||||
|
||||
def check(self, *reads: ReadRange) -> list[Result]:
|
||||
r = (ctypes.c_int * len(reads))()
|
||||
self._lib.ConflictSet_check(
|
||||
self.p, (ReadRange * len(reads))(*reads), r, len(reads)
|
||||
)
|
||||
return [Result(x) for x in r]
|
||||
|
||||
def setOldestVersion(self, version: int) -> None:
|
||||
self._lib.ConflictSet_setOldestVersion(self.p, version)
|
||||
|
||||
def getBytes(self) -> int:
|
||||
return self._lib.ConflictSet_getBytes(self.p)
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def close(self) -> None:
|
||||
if self.p is not None:
|
||||
self._lib.ConflictSet_destroy(self.p)
|
||||
self.p = None
|
||||
|
||||
def __exit__(self, exception_type, exception_value, exception_traceback):
|
||||
self.close()
|
BIN
corpus/0020a3ab4a0de649bf7b8966c9065405b64229e8
Normal file
BIN
corpus/0020a3ab4a0de649bf7b8966c9065405b64229e8
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/0133cf3a9984eb4e45fd166cdcc136619fcfda32
Normal file
BIN
corpus/0133cf3a9984eb4e45fd166cdcc136619fcfda32
Normal file
Binary file not shown.
BIN
corpus/0185228b4b3455b1a542009007ceb974db6d98af
Normal file
BIN
corpus/0185228b4b3455b1a542009007ceb974db6d98af
Normal file
Binary file not shown.
BIN
corpus/01fbab54a0d97fb88b0ed4863892e56db715656f
Normal file
BIN
corpus/01fbab54a0d97fb88b0ed4863892e56db715656f
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/0208b56e9abfd4f37d871dc89e4801a2eb90fae5
Normal file
BIN
corpus/0208b56e9abfd4f37d871dc89e4801a2eb90fae5
Normal file
Binary file not shown.
BIN
corpus/020f1d7a4ef05f035b7edf9e2bdbf99c4ba038b8
Normal file
BIN
corpus/020f1d7a4ef05f035b7edf9e2bdbf99c4ba038b8
Normal file
Binary file not shown.
BIN
corpus/0242543101d75ef9e557d1c7eeebe639a10620b9
Normal file
BIN
corpus/0242543101d75ef9e557d1c7eeebe639a10620b9
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/02abc409ed03c67e3da635f9db83cbb6b9bd7f3c
Normal file
BIN
corpus/02abc409ed03c67e3da635f9db83cbb6b9bd7f3c
Normal file
Binary file not shown.
BIN
corpus/02c7e951a4ab7f63e1ec1003f4865b93c8f90721
Normal file
BIN
corpus/02c7e951a4ab7f63e1ec1003f4865b93c8f90721
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/03452330deff47b3363f1019379c65b21908b43f
Normal file
BIN
corpus/03452330deff47b3363f1019379c65b21908b43f
Normal file
Binary file not shown.
BIN
corpus/03b588ed7a235250157891230af6de1e04bf006d
Normal file
BIN
corpus/03b588ed7a235250157891230af6de1e04bf006d
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/042799793e7c063b20e0e55bbcc96f01f91bdd04
Normal file
BIN
corpus/042799793e7c063b20e0e55bbcc96f01f91bdd04
Normal file
Binary file not shown.
BIN
corpus/04afb73ee2885691dd2dd62d5b04704b49a90a54
Normal file
BIN
corpus/04afb73ee2885691dd2dd62d5b04704b49a90a54
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/06b483dbba432b8972f9fc89222a41a27f3b8e96
Normal file
BIN
corpus/06b483dbba432b8972f9fc89222a41a27f3b8e96
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/07b6e1f5e080bbcb96f3556ee0162e6289e3c9bc
Normal file
BIN
corpus/07b6e1f5e080bbcb96f3556ee0162e6289e3c9bc
Normal file
Binary file not shown.
BIN
corpus/07b7709b720312478bc91ebc568e035644b006f6
Normal file
BIN
corpus/07b7709b720312478bc91ebc568e035644b006f6
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/08732f5857874285c5bceeb686b33687408ee4af
Normal file
BIN
corpus/08732f5857874285c5bceeb686b33687408ee4af
Normal file
Binary file not shown.
BIN
corpus/093362f8fc387e49a1b0f31a0fe5e82416aeed5b
Normal file
BIN
corpus/093362f8fc387e49a1b0f31a0fe5e82416aeed5b
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/09e2d3949b7c2c68b582a58b69a1fe719fc93edf
Normal file
BIN
corpus/09e2d3949b7c2c68b582a58b69a1fe719fc93edf
Normal file
Binary file not shown.
BIN
corpus/0a0f24698c6b6b548e01b69142e4fe2d248890ba
Normal file
BIN
corpus/0a0f24698c6b6b548e01b69142e4fe2d248890ba
Normal file
Binary file not shown.
BIN
corpus/0b12266d8a7e1a094fd38f2a98bc578d09c418ab
Normal file
BIN
corpus/0b12266d8a7e1a094fd38f2a98bc578d09c418ab
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/0c941ffcc53038e5db60a1cad7a3ad77c5d88fb9
Normal file
BIN
corpus/0c941ffcc53038e5db60a1cad7a3ad77c5d88fb9
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/0d0078bad6b47befd6f8723fcc4babe36b453a4b
Normal file
BIN
corpus/0d0078bad6b47befd6f8723fcc4babe36b453a4b
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/0d7e8c09fd026b7cceb559fe5344183c89a550bc
Normal file
BIN
corpus/0d7e8c09fd026b7cceb559fe5344183c89a550bc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/0f4ecf072e9ae7a01ff27513e770363b0ba926ce
Normal file
BIN
corpus/0f4ecf072e9ae7a01ff27513e770363b0ba926ce
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/0fa39cd3837e6f0d85a67595933336b68f67248a
Normal file
BIN
corpus/0fa39cd3837e6f0d85a67595933336b68f67248a
Normal file
Binary file not shown.
BIN
corpus/0fc04cdbefc601dee20fbf5039669187497ab61e
Normal file
BIN
corpus/0fc04cdbefc601dee20fbf5039669187497ab61e
Normal file
Binary file not shown.
BIN
corpus/10e5d27ffe9630f39a1d4bbf81dfe0186734eebd
Normal file
BIN
corpus/10e5d27ffe9630f39a1d4bbf81dfe0186734eebd
Normal file
Binary file not shown.
BIN
corpus/11516b06b08b92cd3c5eb268fca2c0cb90e825da
Normal file
BIN
corpus/11516b06b08b92cd3c5eb268fca2c0cb90e825da
Normal file
Binary file not shown.
BIN
corpus/1171677231c97f3e153065a460c75176a4dc1efe
Normal file
BIN
corpus/1171677231c97f3e153065a460c75176a4dc1efe
Normal file
Binary file not shown.
BIN
corpus/134de1b68774dbf7169eebc2b1256adf1f4ddf37
Normal file
BIN
corpus/134de1b68774dbf7169eebc2b1256adf1f4ddf37
Normal file
Binary file not shown.
BIN
corpus/1382d742e726802ad6507a0254ea296ed75b0150
Normal file
BIN
corpus/1382d742e726802ad6507a0254ea296ed75b0150
Normal file
Binary file not shown.
BIN
corpus/13a6bd032172db55ad35c19227c0a1e492dc7ed3
Normal file
BIN
corpus/13a6bd032172db55ad35c19227c0a1e492dc7ed3
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/14b2daeea15b6e7cfe4f28f695ace1cffd8bb6d7
Normal file
BIN
corpus/14b2daeea15b6e7cfe4f28f695ace1cffd8bb6d7
Normal file
Binary file not shown.
BIN
corpus/15023dd585a975308d45533e2876d8ca60e48162
Normal file
BIN
corpus/15023dd585a975308d45533e2876d8ca60e48162
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/15efe922dec96e9dc6860a3b5ce45d44a100fef6
Normal file
BIN
corpus/15efe922dec96e9dc6860a3b5ce45d44a100fef6
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/16fd756ed15f1437f143d7b3e8f100be25281649
Normal file
BIN
corpus/16fd756ed15f1437f143d7b3e8f100be25281649
Normal file
Binary file not shown.
BIN
corpus/1796920e2eaaef618eb2100d6db5ac980b9b20a9
Normal file
BIN
corpus/1796920e2eaaef618eb2100d6db5ac980b9b20a9
Normal file
Binary file not shown.
BIN
corpus/17d924f6a27697c66a3fc7ac002b58f78f3e992a
Normal file
BIN
corpus/17d924f6a27697c66a3fc7ac002b58f78f3e992a
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/1a314b8298de08b8988d0bb8b6b1935377c4419f
Normal file
BIN
corpus/1a314b8298de08b8988d0bb8b6b1935377c4419f
Normal file
Binary file not shown.
BIN
corpus/1aa0ac37b1c3e50dc0202951722ce494d0d069c1
Normal file
BIN
corpus/1aa0ac37b1c3e50dc0202951722ce494d0d069c1
Normal file
Binary file not shown.
BIN
corpus/1afad57db40839ad3aa9b9414fc4b3b71886edc8
Normal file
BIN
corpus/1afad57db40839ad3aa9b9414fc4b3b71886edc8
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/1b8be6892fe5c22d64283aab813b5bcaf8ad9e75
Normal file
BIN
corpus/1b8be6892fe5c22d64283aab813b5bcaf8ad9e75
Normal file
Binary file not shown.
BIN
corpus/1ba958676d3e09b4cb15e8792bd72b7707a0f9c2
Normal file
BIN
corpus/1ba958676d3e09b4cb15e8792bd72b7707a0f9c2
Normal file
Binary file not shown.
BIN
corpus/1bbe78e37c9747b7ccd095f78a4419f52e8bc1bf
Normal file
BIN
corpus/1bbe78e37c9747b7ccd095f78a4419f52e8bc1bf
Normal file
Binary file not shown.
BIN
corpus/1c1614a264e5453ce36fd9f6d42a0ae071c08846
Normal file
BIN
corpus/1c1614a264e5453ce36fd9f6d42a0ae071c08846
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/1cb0626d22445fb81a0d80d4c54cbe3b18f72c4f
Normal file
BIN
corpus/1cb0626d22445fb81a0d80d4c54cbe3b18f72c4f
Normal file
Binary file not shown.
BIN
corpus/1d3b21afa6d9f9cc613a4555501d6422f74b23d5
Normal file
BIN
corpus/1d3b21afa6d9f9cc613a4555501d6422f74b23d5
Normal file
Binary file not shown.
BIN
corpus/1dc2879a3704ee419af89db050328c4a07631ec8
Normal file
BIN
corpus/1dc2879a3704ee419af89db050328c4a07631ec8
Normal file
Binary file not shown.
BIN
corpus/1dfeee6660b5b0016a6e57135ad11d0e1c16857b
Normal file
BIN
corpus/1dfeee6660b5b0016a6e57135ad11d0e1c16857b
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/1edd234c122a4138ceec329ee719429aaaeb7997
Normal file
BIN
corpus/1edd234c122a4138ceec329ee719429aaaeb7997
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/20abddb7bc6dbd7fad96b6051841f4d0164ecade
Normal file
BIN
corpus/20abddb7bc6dbd7fad96b6051841f4d0164ecade
Normal file
Binary file not shown.
BIN
corpus/20b85f850510b18de432a5f2d6ea361e943ea073
Normal file
BIN
corpus/20b85f850510b18de432a5f2d6ea361e943ea073
Normal file
Binary file not shown.
BIN
corpus/20cfdb6e4aaf3ae7bfdbc53af64175b7e1da2647
Normal file
BIN
corpus/20cfdb6e4aaf3ae7bfdbc53af64175b7e1da2647
Normal file
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