Compare commits
28 Commits
Author | SHA1 | Date | |
---|---|---|---|
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
|
||||
|
@@ -1,13 +1,15 @@
|
||||
cmake_minimum_required(VERSION 3.18)
|
||||
project(
|
||||
conflict-set
|
||||
VERSION 0.0.2
|
||||
VERSION 0.0.4
|
||||
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_BINARY_DIR}/version.txt ${PROJECT_VERSION})
|
||||
|
||||
include(CMakePushCheckState)
|
||||
include(CheckCXXCompilerFlag)
|
||||
include(CheckIncludeFileCXX)
|
||||
@@ -128,7 +130,7 @@ endif()
|
||||
if(APPLE)
|
||||
add_custom_command(
|
||||
TARGET ${PROJECT_NAME}-static
|
||||
PRE_BUILD
|
||||
PRE_LINK
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/privatize_symbols_macos.sh
|
||||
$<TARGET_OBJECTS:${PROJECT_NAME}-object>)
|
||||
else()
|
||||
@@ -259,14 +261,22 @@ 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_SOURCE_DIR}/test_conflict_set.py)
|
||||
execute_process(
|
||||
COMMAND ${Python3_EXECUTABLE} ${CMAKE_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_SOURCE_DIR}/test_conflict_set.py
|
||||
test ${TEST} --build-dir ${CMAKE_BINARY_DIR})
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
find_program(VALGRIND_EXE valgrind)
|
||||
if(VALGRIND_EXE AND NOT CMAKE_CROSSCOMPILING)
|
||||
@@ -333,6 +343,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 +364,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_SOURCE_DIR}/README.md -o
|
||||
${CMAKE_BINARY_DIR}/README.txt)
|
||||
set(CPACK_RESOURCE_FILE_README ${CMAKE_BINARY_DIR}/README.txt)
|
||||
endif()
|
||||
configure_file(${CMAKE_SOURCE_DIR}/LICENSE ${CMAKE_BINARY_DIR}/LICENSE.txt
|
||||
COPYONLY)
|
||||
set(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_BINARY_DIR}/LICENSE.txt)
|
||||
endif()
|
||||
|
||||
include(CPack)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
@@ -377,8 +402,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)
|
||||
|
@@ -770,7 +770,7 @@ template <class NodeT> int getChildGeqSimd(NodeT *self, int child) {
|
||||
|
||||
// cachegrind says the plain loop is fewer instructions and more mis-predicted
|
||||
// branches. Microbenchmark says plain loop is faster. It's written in this
|
||||
// weird "generic" way though in case someday we can use the simd
|
||||
// weird "generic" way though so that someday we can use the simd
|
||||
// implementation easily if we want.
|
||||
if constexpr (std::is_same_v<NodeT, Node3>) {
|
||||
Node3 *n = (Node3 *)self;
|
||||
@@ -1146,8 +1146,14 @@ void freeAndMakeCapacityAtLeast(Node *&self, int capacity,
|
||||
// capacity.
|
||||
void maybeDecreaseCapacity(Node *&self, NodeAllocators *allocators,
|
||||
ConflictSet::Impl *impl) {
|
||||
|
||||
const int maxCapacity =
|
||||
(self->numChildren + int(self->entryPresent)) * (self->partialKeyLen + 1);
|
||||
#if DEBUG_VERBOSE && !defined(NDEBUG)
|
||||
fprintf(stderr, "maybeDecreaseCapacity: current: %d, max: %d, key: %s\n",
|
||||
self->getCapacity(), maxCapacity,
|
||||
getSearchPathPrintable(self).c_str());
|
||||
#endif
|
||||
if (self->getCapacity() <= maxCapacity) {
|
||||
return;
|
||||
}
|
||||
@@ -2389,7 +2395,11 @@ Iterator firstGeq(Node *n, const std::span<const uint8_t> key) {
|
||||
} else {
|
||||
n = nextSibling(n);
|
||||
if (n == nullptr) {
|
||||
return {nullptr, 1};
|
||||
// This line is genuinely unreachable from any entry point of the
|
||||
// final library, since we can't remove a key without introducing a
|
||||
// key after it, and the only production caller of firstGeq is for
|
||||
// resuming the setOldestVersion scan.
|
||||
return {nullptr, 1}; // GCOVR_EXCL_LINE
|
||||
}
|
||||
goto downLeftSpine;
|
||||
}
|
||||
@@ -2510,6 +2520,10 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
}
|
||||
|
||||
explicit Impl(int64_t oldestVersion) : oldestVersion(oldestVersion) {
|
||||
#if DEBUG_VERBOSE
|
||||
fprintf(stderr, "radix_tree: create\n");
|
||||
#endif
|
||||
|
||||
// Insert ""
|
||||
root = allocators.node0.allocate(0);
|
||||
root->numChildren = 0;
|
||||
@@ -2524,7 +2538,12 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
root->entry.pointVersion = oldestVersion;
|
||||
root->entry.rangeVersion = oldestVersion;
|
||||
}
|
||||
~Impl() { destroyTree(root); }
|
||||
~Impl() {
|
||||
#if DEBUG_VERBOSE
|
||||
fprintf(stderr, "radix_tree: destroy\n");
|
||||
#endif
|
||||
destroyTree(root);
|
||||
}
|
||||
|
||||
NodeAllocators allocators;
|
||||
|
||||
@@ -2647,17 +2666,27 @@ ConflictSet_check(void *cs, const ConflictSet_ReadRange *reads,
|
||||
__attribute__((__visibility__("default"))) void
|
||||
ConflictSet_addWrites(void *cs, const ConflictSet_WriteRange *writes, int count,
|
||||
int64_t writeVersion) {
|
||||
auto *impl = ((ConflictSet::Impl *)cs);
|
||||
auto *impl = (ConflictSet::Impl *)cs;
|
||||
mallocBytesDelta = 0;
|
||||
impl->addWrites(writes, count, writeVersion);
|
||||
impl->totalBytes += mallocBytesDelta;
|
||||
#if SHOW_MEMORY
|
||||
if (impl->totalBytes != mallocBytes) {
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
__attribute__((__visibility__("default"))) void
|
||||
ConflictSet_setOldestVersion(void *cs, int64_t oldestVersion) {
|
||||
auto *impl = ((ConflictSet::Impl *)cs);
|
||||
auto *impl = (ConflictSet::Impl *)cs;
|
||||
mallocBytesDelta = 0;
|
||||
impl->setOldestVersion(oldestVersion);
|
||||
impl->totalBytes += mallocBytesDelta;
|
||||
#if SHOW_MEMORY
|
||||
if (impl->totalBytes != mallocBytes) {
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
__attribute__((__visibility__("default"))) void *
|
||||
ConflictSet_create(int64_t oldestVersion) {
|
||||
@@ -2995,6 +3024,7 @@ void removeKey(Node *n) {
|
||||
|
||||
struct __attribute__((visibility("default"))) PeakPrinter {
|
||||
~PeakPrinter() {
|
||||
printf("--- radix_tree ---\n");
|
||||
printf("malloc bytes: %g\n", double(mallocBytes));
|
||||
printf("Peak malloc bytes: %g\n", double(peakMallocBytes));
|
||||
printf("Node bytes: %g\n", double(nodeBytes));
|
||||
|
15
Internal.h
15
Internal.h
@@ -530,10 +530,13 @@ template <class ConflictSetImpl> struct TestDriver {
|
||||
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() {
|
||||
@@ -552,9 +555,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));
|
||||
}
|
||||
|
||||
@@ -619,9 +623,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));
|
||||
}
|
||||
|
||||
|
3
Jenkinsfile
vendored
3
Jenkinsfile
vendored
@@ -111,6 +111,9 @@ pipeline {
|
||||
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
|
||||
sh '''
|
||||
gcovr -f ConflictSet.cpp --fail-under-line 100 > /dev/null
|
||||
'''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
36
README.md
36
README.md
@@ -58,27 +58,27 @@ Performance counters:
|
||||
|
||||
## Skip list
|
||||
|
||||
| ns/op | op/s | err% | total | benchmark
|
||||
|--------------------:|--------------------:|--------:|----------:|:----------
|
||||
| 246.99 | 4,048,700.59 | 0.2% | 0.01 | `point reads`
|
||||
| 260.16 | 3,843,784.65 | 0.1% | 0.01 | `prefix reads`
|
||||
| 493.35 | 2,026,953.19 | 0.1% | 0.01 | `range reads`
|
||||
| 462.05 | 2,164,289.23 | 0.6% | 0.01 | `point writes`
|
||||
| 448.19 | 2,231,205.25 | 0.9% | 0.01 | `prefix writes`
|
||||
| 255.83 | 3,908,845.72 | 1.5% | 0.02 | `range writes`
|
||||
| 582.63 | 1,716,349.02 | 1.3% | 0.01 | `monotonic increasing point writes`
|
||||
| ns/op | op/s | err% | total | benchmark |
|
||||
| -----: | -----------: | ---: | ----: | :---------------------------------- |
|
||||
| 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` |
|
||||
|
||||
## Radix tree (this implementation)
|
||||
|
||||
| ns/op | op/s | err% | total | benchmark
|
||||
|--------------------:|--------------------:|--------:|----------:|:----------
|
||||
| 19.42 | 51,483,206.67 | 0.3% | 0.01 | `point reads`
|
||||
| 58.43 | 17,115,612.57 | 0.1% | 0.01 | `prefix reads`
|
||||
| 216.09 | 4,627,766.60 | 0.2% | 0.01 | `range reads`
|
||||
| 28.35 | 35,267,567.72 | 0.2% | 0.01 | `point writes`
|
||||
| 43.43 | 23,026,226.17 | 0.2% | 0.01 | `prefix writes`
|
||||
| 50.00 | 20,000,000.00 | 0.0% | 0.01 | `range writes`
|
||||
| 92.38 | 10,824,863.69 | 4.1% | 0.01 | `monotonic increasing point writes`
|
||||
| ns/op | op/s | err% | total | benchmark |
|
||||
| -----: | ------------: | ---: | ----: | :---------------------------------- |
|
||||
| 19.42 | 51,483,206.67 | 0.3% | 0.01 | `point reads` |
|
||||
| 58.43 | 17,115,612.57 | 0.1% | 0.01 | `prefix reads` |
|
||||
| 216.09 | 4,627,766.60 | 0.2% | 0.01 | `range reads` |
|
||||
| 28.35 | 35,267,567.72 | 0.2% | 0.01 | `point writes` |
|
||||
| 43.43 | 23,026,226.17 | 0.2% | 0.01 | `prefix writes` |
|
||||
| 50.00 | 20,000,000.00 | 0.0% | 0.01 | `range writes` |
|
||||
| 92.38 | 10,824,863.69 | 4.1% | 0.01 | `monotonic increasing point writes` |
|
||||
|
||||
# "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);
|
||||
}
|
||||
}
|
42
SkipList.cpp
42
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;
|
||||
}
|
||||
@@ -603,6 +613,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)}
|
||||
@@ -702,16 +716,35 @@ ConflictSet_check(void *cs, const ConflictSet_ReadRange *reads,
|
||||
__attribute__((__visibility__("default"))) void
|
||||
ConflictSet_addWrites(void *cs, const ConflictSet_WriteRange *writes, int count,
|
||||
int64_t writeVersion) {
|
||||
((ConflictSet::Impl *)cs)->addWrites(writes, count, writeVersion);
|
||||
auto *impl = (ConflictSet::Impl *)cs;
|
||||
mallocBytesDelta = 0;
|
||||
impl->addWrites(writes, count, writeVersion);
|
||||
impl->totalBytes += mallocBytesDelta;
|
||||
#if SHOW_MEMORY
|
||||
if (impl->totalBytes != mallocBytes) {
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
__attribute__((__visibility__("default"))) void
|
||||
ConflictSet_setOldestVersion(void *cs, int64_t oldestVersion) {
|
||||
((ConflictSet::Impl *)cs)->setOldestVersion(oldestVersion);
|
||||
auto *impl = (ConflictSet::Impl *)cs;
|
||||
mallocBytesDelta = 0;
|
||||
impl->setOldestVersion(oldestVersion);
|
||||
impl->totalBytes += mallocBytesDelta;
|
||||
#if SHOW_MEMORY
|
||||
if (impl->totalBytes != mallocBytes) {
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
__attribute__((__visibility__("default"))) void *
|
||||
ConflictSet_create(int64_t oldestVersion) {
|
||||
return new (safe_malloc(sizeof(ConflictSet::Impl)))
|
||||
mallocBytesDelta = 0;
|
||||
auto *result = new (safe_malloc(sizeof(ConflictSet::Impl)))
|
||||
ConflictSet::Impl{oldestVersion};
|
||||
result->totalBytes += mallocBytesDelta;
|
||||
return result;
|
||||
}
|
||||
__attribute__((__visibility__("default"))) void ConflictSet_destroy(void *cs) {
|
||||
using Impl = ConflictSet::Impl;
|
||||
@@ -728,6 +761,7 @@ ConflictSet_getBytes(void *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));
|
||||
}
|
||||
|
@@ -4,4 +4,5 @@ _bzero
|
||||
_free
|
||||
_malloc
|
||||
_memcpy
|
||||
_memmove
|
||||
_memmove
|
||||
dyld_stub_binder
|
136
conflict_set.py
Normal file
136
conflict_set.py
Normal file
@@ -0,0 +1,136 @@
|
||||
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, *reads, r, 1)
|
||||
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/000d72883139e535b50cc5872c57e73db3f10f97
Normal file
BIN
corpus/000d72883139e535b50cc5872c57e73db3f10f97
Normal file
Binary file not shown.
BIN
corpus/001a4385cfd31070dd75eaa3e1ad21d0b25687d6
Normal file
BIN
corpus/001a4385cfd31070dd75eaa3e1ad21d0b25687d6
Normal file
Binary file not shown.
BIN
corpus/007b28db8fbd69dba10657e88e2db37747818c02
Normal file
BIN
corpus/007b28db8fbd69dba10657e88e2db37747818c02
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/017fe0001e79270892ec9a596580883273a1e4a2
Normal file
BIN
corpus/017fe0001e79270892ec9a596580883273a1e4a2
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/02a1f402f107a5dc508b212da227d87b4ffa8904
Normal file
BIN
corpus/02a1f402f107a5dc508b212da227d87b4ffa8904
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/03262648f007cc440c36b2bef091dd76295074c5
Normal file
BIN
corpus/03262648f007cc440c36b2bef091dd76295074c5
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/0418013be6b44b43621f5c46a3487212c0f91a40
Normal file
BIN
corpus/0418013be6b44b43621f5c46a3487212c0f91a40
Normal file
Binary file not shown.
BIN
corpus/044269ca54d9557b8b91f3b47ec32d7afd9f6a87
Normal file
BIN
corpus/044269ca54d9557b8b91f3b47ec32d7afd9f6a87
Normal file
Binary file not shown.
BIN
corpus/0467f1f20c94c212ead6664b420e31e39159f437
Normal file
BIN
corpus/0467f1f20c94c212ead6664b420e31e39159f437
Normal file
Binary file not shown.
BIN
corpus/048484b4d6cf7bacce667023dea09dd052d74b6d
Normal file
BIN
corpus/048484b4d6cf7bacce667023dea09dd052d74b6d
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/07e675857aae0f133f253f146685f4c8e7492114
Normal file
BIN
corpus/07e675857aae0f133f253f146685f4c8e7492114
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/09328b5c92e0e4875e2f150ee2a013e765998a13
Normal file
BIN
corpus/09328b5c92e0e4875e2f150ee2a013e765998a13
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/099cd4e9ec7dfd33064b54ab678ccf2d0724b6ae
Normal file
BIN
corpus/099cd4e9ec7dfd33064b54ab678ccf2d0724b6ae
Normal file
Binary file not shown.
BIN
corpus/09e702c2f99064a568d4bc7ba5d8581fdc6f2071
Normal file
BIN
corpus/09e702c2f99064a568d4bc7ba5d8581fdc6f2071
Normal file
Binary file not shown.
BIN
corpus/09e7f7a7e9967f1d744fca5a2e10c0e6514a3551
Normal file
BIN
corpus/09e7f7a7e9967f1d744fca5a2e10c0e6514a3551
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/0b4deead0afd2d2cf7bb0cd7bf56259b5f484dcb
Normal file
BIN
corpus/0b4deead0afd2d2cf7bb0cd7bf56259b5f484dcb
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/0cf423dcbda59e334384410c83cf003aaf6afca1
Normal file
BIN
corpus/0cf423dcbda59e334384410c83cf003aaf6afca1
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/0e21b3fc3c827043685bfb846df055c5f03aae96
Normal file
BIN
corpus/0e21b3fc3c827043685bfb846df055c5f03aae96
Normal file
Binary file not shown.
BIN
corpus/0e31aad966875f897220c2437c69326443675fc7
Normal file
BIN
corpus/0e31aad966875f897220c2437c69326443675fc7
Normal file
Binary file not shown.
BIN
corpus/0e4de14128ec7b61ae2cb2835fddd641845ee743
Normal file
BIN
corpus/0e4de14128ec7b61ae2cb2835fddd641845ee743
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/0f2768b4a7a65be84db67f2d6cebe5fe04bce172
Normal file
BIN
corpus/0f2768b4a7a65be84db67f2d6cebe5fe04bce172
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/10cc69d9013596429f0912712c0137591973c2d7
Normal file
BIN
corpus/10cc69d9013596429f0912712c0137591973c2d7
Normal file
Binary file not shown.
BIN
corpus/11e033caa0ce581acf472931b02588a6b2faa55d
Normal file
BIN
corpus/11e033caa0ce581acf472931b02588a6b2faa55d
Normal file
Binary file not shown.
BIN
corpus/12128a5bddff249ab102e679bb40da952bb94b5c
Normal file
BIN
corpus/12128a5bddff249ab102e679bb40da952bb94b5c
Normal file
Binary file not shown.
BIN
corpus/12ae1e1ff00a8c79f7a687e2aa70e94aca1dc34d
Normal file
BIN
corpus/12ae1e1ff00a8c79f7a687e2aa70e94aca1dc34d
Normal file
Binary file not shown.
BIN
corpus/13227d7d1bc7355aed3df9a4ea012d4a391764e7
Normal file
BIN
corpus/13227d7d1bc7355aed3df9a4ea012d4a391764e7
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/147990fa0ada11fb7025a8534f1e4f85164869b1
Normal file
BIN
corpus/147990fa0ada11fb7025a8534f1e4f85164869b1
Normal file
Binary file not shown.
BIN
corpus/156b43edfd8dc756184017bf78e382e4d129e33a
Normal file
BIN
corpus/156b43edfd8dc756184017bf78e382e4d129e33a
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/1607b170ded5a8458ab9b1514d34f8ed4ddd2975
Normal file
BIN
corpus/1607b170ded5a8458ab9b1514d34f8ed4ddd2975
Normal file
Binary file not shown.
BIN
corpus/160b10e0be9ea9eedfc99f5e3dc106bf50fc5f6d
Normal file
BIN
corpus/160b10e0be9ea9eedfc99f5e3dc106bf50fc5f6d
Normal file
Binary file not shown.
BIN
corpus/1632064eae678ef9865ef9eeb43c7ebeca71422d
Normal file
BIN
corpus/1632064eae678ef9865ef9eeb43c7ebeca71422d
Normal file
Binary file not shown.
BIN
corpus/17a4cd288c819b380f7995273ad0414dbfcaffba
Normal file
BIN
corpus/17a4cd288c819b380f7995273ad0414dbfcaffba
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/18b6eaeb039242f729c8e3f90ea702dd2584e768
Normal file
BIN
corpus/18b6eaeb039242f729c8e3f90ea702dd2584e768
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/19101c188a484270f33420caa342612d44681616
Normal file
BIN
corpus/19101c188a484270f33420caa342612d44681616
Normal file
Binary file not shown.
BIN
corpus/197cb73b1a29e35935973aae7ae26b6c7ab92d07
Normal file
BIN
corpus/197cb73b1a29e35935973aae7ae26b6c7ab92d07
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/1a69474ab8ba1187063bd0eb5d4899a203050917
Normal file
BIN
corpus/1a69474ab8ba1187063bd0eb5d4899a203050917
Normal file
Binary file not shown.
BIN
corpus/1a821dc4f6299984feff1ef1e7db28fe185158a4
Normal file
BIN
corpus/1a821dc4f6299984feff1ef1e7db28fe185158a4
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/1b8a5ae93daf3a194087cc9747295352d7bb906b
Normal file
BIN
corpus/1b8a5ae93daf3a194087cc9747295352d7bb906b
Normal file
Binary file not shown.
BIN
corpus/1bd30a30823419a12d004729baa96734e410cbed
Normal file
BIN
corpus/1bd30a30823419a12d004729baa96734e410cbed
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/1ce8fc23367508b9c141f66976e888910298d64e
Normal file
BIN
corpus/1ce8fc23367508b9c141f66976e888910298d64e
Normal file
Binary file not shown.
BIN
corpus/1d85043e4ef57d7d173ab3995f414fffc293f806
Normal file
BIN
corpus/1d85043e4ef57d7d173ab3995f414fffc293f806
Normal file
Binary file not shown.
BIN
corpus/1deefa50797a868862a42b0a5123bca56ac6dda3
Normal file
BIN
corpus/1deefa50797a868862a42b0a5123bca56ac6dda3
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/1f0ed103e089f3d8e1677f2584de062e749325c9
Normal file
BIN
corpus/1f0ed103e089f3d8e1677f2584de062e749325c9
Normal file
Binary file not shown.
BIN
corpus/1f7df9092b27aac286e6b6083ea3a36fdc5de0dc
Normal file
BIN
corpus/1f7df9092b27aac286e6b6083ea3a36fdc5de0dc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/20fbe40374050cc9baa7a98db1f38ab72fa93f56
Normal file
BIN
corpus/20fbe40374050cc9baa7a98db1f38ab72fa93f56
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/21d28bbe4e26ea1106971daa2dfc29e5494e96f5
Normal file
BIN
corpus/21d28bbe4e26ea1106971daa2dfc29e5494e96f5
Normal file
Binary file not shown.
BIN
corpus/220ff7bdf7c3beb959d74588e3a62adaea87c03a
Normal file
BIN
corpus/220ff7bdf7c3beb959d74588e3a62adaea87c03a
Normal file
Binary file not shown.
BIN
corpus/229083b7df25fc8eeacee67f6ba65970cef8d0af
Normal file
BIN
corpus/229083b7df25fc8eeacee67f6ba65970cef8d0af
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/237d34786b161ee598038c271a1fa3a97ff6ee01
Normal file
BIN
corpus/237d34786b161ee598038c271a1fa3a97ff6ee01
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/24d85ce287a697c17b89707716426f44170e163a
Normal file
BIN
corpus/24d85ce287a697c17b89707716426f44170e163a
Normal file
Binary file not shown.
BIN
corpus/253516d6e1ae30b2f888e3fd9f4a445e6d84e46e
Normal file
BIN
corpus/253516d6e1ae30b2f888e3fd9f4a445e6d84e46e
Normal file
Binary file not shown.
BIN
corpus/262b670b224f9eef2f4c481d44bae411506d44b1
Normal file
BIN
corpus/262b670b224f9eef2f4c481d44bae411506d44b1
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