Compare commits

..
Author SHA1 Message Date
andrew c46f633dbf Skip sorting if already sorted for skip list 2024-11-12 13:25:29 -08:00
andrew 400350946c Point read/write workload for server_bench 2024-11-12 10:50:03 -08:00
andrew 607a4ef6e2 Require musttail and preserve_none for interleaved 2024-11-11 21:40:05 -08:00
andrew b0750772ec Don't do hardening check if cross compiling 2024-11-11 16:56:28 -08:00
andrew 86abc02188 Build binaries compatible with cf-protection 2024-11-11 16:17:57 -08:00
andrew a90e353fcd Use llvm-objcopy if using clang and it's available
This works around a weird error I was getting when trying to link a
translation unit that included Internal.h with libconflict-set-static.a
with clang + gnu objcopy
2024-11-11 12:09:36 -08:00
236 changed files with 956 additions and 3354 deletions
-322
View File
@@ -1,322 +0,0 @@
name: CI
on: [push, pull_request]
env:
CC: clang
CXX: clang++
jobs:
pre-commit:
runs-on: ubuntu-latest-amd64
steps:
- uses: actions/checkout@v4
- uses: actions/cache@v4
with:
path: /var/cache/apt/archives
key: apt-amd64-${{ hashFiles('.gitea/workflows/ci.yml') }}
- name: Install dependencies
run: |
sudo apt-get update -qq
sudo apt-get install -y git nodejs pre-commit
- uses: actions/cache@v4
with:
path: ~/.cache/pre-commit
key: pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
- name: Run pre-commit
run: |
git config --global --add safe.directory "$PWD"
pre-commit run --all-files --show-diff-on-failure
test:
strategy:
fail-fast: false
matrix:
include:
- name: 64-bit-versions
cmake_args: -DCMAKE_CXX_FLAGS=-DUSE_64_BIT=1
- name: debug
cmake_args: -DCMAKE_BUILD_TYPE=Debug -DMSAN_TOOLCHAIN_PATH=/opt/msan
- name: simd-fallback
cmake_args: -DUSE_SIMD_FALLBACK=ON
- name: gcc
cmake_args: -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++
runs-on: ubuntu-latest-amd64
steps:
- uses: actions/checkout@v4
- uses: actions/cache@v4
with:
path: /var/cache/apt/archives
key: apt-amd64-${{ hashFiles('.gitea/workflows/ci.yml') }}
- name: Install common dependencies
run: |
sudo apt-get update -qq
sudo apt-get install -y \
build-essential ccache cmake gcc g++ libc6-dbg \
ninja-build python3 valgrind zstd
sudo curl -Ls "https://minio.weaselab.dev/public/$(uname -m)/mc.RELEASE.2025-08-13T08-35-41Z" \
-o /usr/local/bin/mc && sudo chmod +x /usr/local/bin/mc
- name: Install LLVM toolchain
if: matrix.name != 'gcc'
run: |
. /etc/os-release
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc
echo "deb http://apt.llvm.org/${VERSION_CODENAME}/ llvm-toolchain-${VERSION_CODENAME}-21 main" | sudo tee /etc/apt/sources.list.d/llvm.list
sudo apt-get update -qq
sudo apt-get install -y \
clang-21 llvm-21 lld-21 mold
for tool in clang clang++ llvm-ar llvm-nm llvm-ranlib llvm-objcopy llvm-cov llvm-symbolizer lld ld.lld; do
sudo update-alternatives --install /usr/bin/${tool} ${tool} /usr/bin/${tool}-21 100
done
- name: Download MSan toolchain
if: matrix.name == 'debug'
run: |
curl -Ls "https://minio.weaselab.dev/public/x86_64/msan-toolchain-21.1.8.tar.zst" -o /tmp/msan-toolchain.tar.zst
sudo mkdir -p /opt/msan
sudo tar --zstd -xf /tmp/msan-toolchain.tar.zst -C /opt/msan
- name: Build
run: |
export CCACHE_DIR="$GITHUB_WORKSPACE/.ccache"
rm -rf build
cmake -S . -B build -G Ninja -DCMAKE_CXX_COMPILER_LAUNCHER=ccache ${{ matrix.cmake_args }}
ninja -C build
ccache -s
- name: Test
run: |
cd build
ctest --no-compress-output --test-output-size-passed 100000 --test-output-size-failed 100000 -T Test -j "$(nproc)" --timeout 90 > /dev/null
- name: Upload test results to MinIO
if: always()
env:
MINIO_ACCESS_KEY: ${{ secrets.MINIO_ACCESS_KEY }}
MC_HOST_minio: https://${{ secrets.MINIO_ACCESS_KEY }}:${{ secrets.MINIO_SECRET_KEY }}@minio.weaselab.dev
run: |
if [ -z "$MINIO_ACCESS_KEY" ]; then
echo "MinIO credentials not configured; skipping upload"
exit 0
fi
zstd build/Testing/*/Test.xml
mc cp build/Testing/*/Test.xml.zst "minio/jenkins/conflict-set/${{ gitea.run_number }}/${{ matrix.name }}/"
- name: Test summary
if: always()
run: |
python3 ctest_summary.py build/Testing/*/Test.xml \
--link "https://minio.weaselab.dev/jenkins/conflict-set/${{ gitea.run_number }}/${{ matrix.name }}/Test.xml.zst" \
| tee -a "$GITHUB_STEP_SUMMARY"
release:
strategy:
fail-fast: false
matrix:
include:
- runner: ubuntu-latest-amd64
arch: amd64
cmake_args: -DMSAN_TOOLCHAIN_PATH=/opt/msan
- runner: ubuntu-latest-arm64
arch: arm64
cmake_args: ""
runs-on: ${{ matrix.runner }}
steps:
- uses: actions/checkout@v4
- uses: actions/cache@v4
with:
path: /var/cache/apt/archives
key: apt-${{ matrix.arch }}-${{ hashFiles('.gitea/workflows/ci.yml') }}
- name: Install dependencies
run: |
. /etc/os-release
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc
echo "deb http://apt.llvm.org/${VERSION_CODENAME}/ llvm-toolchain-${VERSION_CODENAME}-21 main" | sudo tee /etc/apt/sources.list.d/llvm.list
sudo apt-get update -qq
sudo apt-get install -y \
build-essential ccache clang-21 cmake devscripts \
libc6-dbg llvm-21 lld-21 mold ninja-build rpm \
valgrind zstd
sudo curl -Ls "https://minio.weaselab.dev/public/$(uname -m)/mc.RELEASE.2025-08-13T08-35-41Z" \
-o /usr/local/bin/mc && sudo chmod +x /usr/local/bin/mc
for tool in clang clang++ llvm-ar llvm-nm llvm-ranlib llvm-objcopy llvm-cov llvm-symbolizer lld ld.lld; do
sudo update-alternatives --install /usr/bin/${tool} ${tool} /usr/bin/${tool}-21 100
done
- name: Install paper build dependencies
if: matrix.arch == 'amd64'
run: |
sudo apt-get install -y \
biber latexmk \
texlive-bibtex-extra texlive-fonts-recommended \
texlive-latex-extra texlive-pictures
- uses: actions/cache@v4
with:
path: .ccache
key: ccache-release-${{ matrix.arch }}-${{ gitea.sha }}
restore-keys: |
ccache-release-${{ matrix.arch }}-
- name: Download MSan toolchain
if: matrix.arch == 'amd64'
run: |
curl -Ls "https://minio.weaselab.dev/public/x86_64/msan-toolchain-21.1.8.tar.zst" -o /tmp/msan-toolchain.tar.zst
sudo mkdir -p /opt/msan
sudo tar --zstd -xf /tmp/msan-toolchain.tar.zst -C /opt/msan
- name: Build
run: |
export CCACHE_DIR="$GITHUB_WORKSPACE/.ccache"
rm -rf build
cmake -S . -B build -G Ninja -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_FLAGS=-DNVALGRIND ${{ matrix.cmake_args }}
ninja -C build
ccache -s
- name: Test
run: |
cd build
# On arm64, valgrind needs the MAKE_MEM_DEFINED client requests for
# https://git.weaselab.dev/weaselab/conflict-set/issues/39, but this
# build has -DNVALGRIND, which compiles them out. Skip valgrind
# tests here; they run annotated in the test job.
ctest --no-compress-output --test-output-size-passed 100000 --test-output-size-failed 100000 ${{ matrix.arch == 'arm64' && '-E valgrind' || '' }} -T Test -j "$(nproc)" --timeout 90 > /dev/null
- name: Package
run: |
cd build
cpack -G DEB
cpack -G RPM
- name: Build paper
if: matrix.arch == 'amd64'
run: |
cd paper
make
- name: Upload artifacts to MinIO
if: always()
shell: bash
env:
MINIO_ACCESS_KEY: ${{ secrets.MINIO_ACCESS_KEY }}
MC_HOST_minio: https://${{ secrets.MINIO_ACCESS_KEY }}:${{ secrets.MINIO_SECRET_KEY }}@minio.weaselab.dev
run: |
if [ -z "$MINIO_ACCESS_KEY" ]; then
echo "MinIO credentials not configured; skipping upload"
exit 0
fi
dest="minio/jenkins/conflict-set/${{ gitea.run_number }}/release-${{ matrix.arch }}/"
zstd build/Testing/*/Test.xml
mc cp build/Testing/*/Test.xml.zst "$dest"
if compgen -G "build/*.deb" > /dev/null; then
mc cp build/*.deb "$dest"
fi
if compgen -G "build/*.rpm" > /dev/null; then
mc cp build/*.rpm "$dest"
fi
if compgen -G "paper/*.pdf" > /dev/null; then
mc cp paper/*.pdf "$dest"
fi
- name: Test summary
if: always()
run: |
python3 ctest_summary.py build/Testing/*/Test.xml \
--link "https://minio.weaselab.dev/jenkins/conflict-set/${{ gitea.run_number }}/release-${{ matrix.arch }}/Test.xml.zst" \
| tee -a "$GITHUB_STEP_SUMMARY"
coverage:
runs-on: ubuntu-latest-amd64
steps:
- uses: actions/checkout@v4
- uses: actions/cache@v4
with:
path: /var/cache/apt/archives
key: apt-amd64-${{ hashFiles('.gitea/workflows/ci.yml') }}
- name: Install dependencies
run: |
. /etc/os-release
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc
echo "deb http://apt.llvm.org/${VERSION_CODENAME}/ llvm-toolchain-${VERSION_CODENAME}-21 main" | sudo tee /etc/apt/sources.list.d/llvm.list
sudo apt-get update -qq
sudo apt-get install -y \
build-essential ccache clang-21 cmake gcovr \
libc6-dbg llvm-21 lld-21 mold ninja-build python3 valgrind zstd
sudo curl -Ls "https://minio.weaselab.dev/public/$(uname -m)/mc.RELEASE.2025-08-13T08-35-41Z" \
-o /usr/local/bin/mc && sudo chmod +x /usr/local/bin/mc
for tool in clang clang++ llvm-ar llvm-nm llvm-ranlib llvm-objcopy llvm-cov llvm-symbolizer lld ld.lld; do
sudo update-alternatives --install /usr/bin/${tool} ${tool} /usr/bin/${tool}-21 100
done
- uses: actions/cache@v4
with:
path: .ccache
key: ccache-coverage-${{ gitea.sha }}
restore-keys: |
ccache-coverage-
- name: Build
run: |
export CCACHE_DIR="$GITHUB_WORKSPACE/.ccache"
rm -rf build
cmake -S . -B build -G Ninja -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_C_FLAGS=--coverage -DCMAKE_CXX_FLAGS=--coverage \
-DCMAKE_BUILD_TYPE=Debug -DDISABLE_TSAN=ON
ninja -C build
ccache -s
- name: Test
run: |
cd build
ctest --no-compress-output --test-output-size-passed 100000 --test-output-size-failed 100000 -T Test -j "$(nproc)" --timeout 90 > /dev/null
- name: Coverage report
shell: bash
run: |
gcov_args=(-f ConflictSet.cpp -f LongestCommonPrefix.h -f Metrics.h
--gcov-executable "llvm-cov gcov" --exclude-noncode-lines)
gcovr "${gcov_args[@]}" --cobertura > build/coverage.xml
gcovr "${gcov_args[@]}"
mkdir -p build/coverage_html
gcovr "${gcov_args[@]}" --html-details build/coverage_html/index.html
gcovr "${gcov_args[@]}" --fail-under-line 100 > /dev/null
- name: Upload results to MinIO
if: always()
env:
MINIO_ACCESS_KEY: ${{ secrets.MINIO_ACCESS_KEY }}
MC_HOST_minio: https://${{ secrets.MINIO_ACCESS_KEY }}:${{ secrets.MINIO_SECRET_KEY }}@minio.weaselab.dev
run: |
if [ -z "$MINIO_ACCESS_KEY" ]; then
echo "MinIO credentials not configured; skipping upload"
exit 0
fi
dest="minio/jenkins/conflict-set/${{ gitea.run_number }}/coverage/"
zstd build/Testing/*/Test.xml
mc cp build/Testing/*/Test.xml.zst "$dest"
if [ -e build/coverage.xml ]; then
mc cp build/coverage.xml "$dest"
fi
if [ -d build/coverage_html ]; then
mc cp -r build/coverage_html "$dest"
fi
- name: Test summary
if: always()
run: |
python3 ctest_summary.py build/Testing/*/Test.xml \
--link "https://minio.weaselab.dev/jenkins/conflict-set/${{ gitea.run_number }}/coverage/Test.xml.zst" \
| tee -a "$GITHUB_STEP_SUMMARY"
echo "" | tee -a "$GITHUB_STEP_SUMMARY"
echo "📊 [Coverage report](https://minio.weaselab.dev/jenkins/conflict-set/${{ gitea.run_number }}/coverage/coverage_html/index.html)" | tee -a "$GITHUB_STEP_SUMMARY"
+4 -6
View File
@@ -37,16 +37,15 @@ ConflictSet::ReadRange singleton(Arena &arena, TrivialSpan key) {
} }
ConflictSet::ReadRange prefixRange(Arena &arena, TrivialSpan key) { ConflictSet::ReadRange prefixRange(Arena &arena, TrivialSpan key) {
int index = key.size() - 1; int index;
for (; index >= 0; index--) for (index = key.size() - 1; index >= 0; index--)
if (key[index] != 255) if ((key[index]) != 255)
break; break;
// Must not be called with a string that consists only of zero or more '\xff' // Must not be called with a string that consists only of zero or more '\xff'
// bytes, or with an empty string (which has no finite upper bound). // bytes.
if (index < 0) { if (index < 0) {
assert(false); assert(false);
std::abort();
} }
uint8_t *buf = new (arena) uint8_t[index + 1]; uint8_t *buf = new (arena) uint8_t[index + 1];
@@ -58,7 +57,6 @@ ConflictSet::ReadRange prefixRange(Arena &arena, TrivialSpan key) {
void benchConflictSet() { void benchConflictSet() {
ankerl::nanobench::Bench bench; ankerl::nanobench::Bench bench;
bench.minEpochIterations(10000);
ConflictSet cs{0}; ConflictSet cs{0};
bench.batch(kOpsPerTx); bench.batch(kOpsPerTx);
+31 -100
View File
@@ -1,11 +1,11 @@
cmake_minimum_required(VERSION 3.18) cmake_minimum_required(VERSION 3.18)
project( project(
conflict-set conflict-set
VERSION 0.1.0 VERSION 0.0.14
DESCRIPTION DESCRIPTION
"A data structure for optimistic concurrency control on ranges of bitwise-lexicographically-ordered keys." "A data structure for optimistic concurrency control on ranges of bitwise-lexicographically-ordered keys."
HOMEPAGE_URL "https://git.weaselab.dev/weaselab/conflict-set" HOMEPAGE_URL "https://git.weaselab.dev/weaselab/conflict-set"
LANGUAGES C CXX ASM) LANGUAGES C CXX)
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 20)
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/version.txt ${PROJECT_VERSION}) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/version.txt ${PROJECT_VERSION})
@@ -32,12 +32,7 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
endif() endif()
add_compile_options( add_compile_options(
-Werror=switch-enum -Werror=switch-enum -Wswitch-enum -fPIC -fdata-sections -ffunction-sections
-Wswitch-enum
-Wunused-variable
-fPIC
-fdata-sections
-ffunction-sections
-fno-jump-tables # https://github.com/llvm/llvm-project/issues/54247 -fno-jump-tables # https://github.com/llvm/llvm-project/issues/54247
) )
@@ -53,7 +48,6 @@ endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
add_compile_options("-Wno-maybe-uninitialized") add_compile_options("-Wno-maybe-uninitialized")
add_compile_options("-Wno-maybe-musttail-local-addr")
endif() endif()
if(NOT APPLE) if(NOT APPLE)
@@ -61,21 +55,16 @@ if(NOT APPLE)
add_compile_options(-g -fno-omit-frame-pointer) add_compile_options(-g -fno-omit-frame-pointer)
endif() endif()
set(relro_flags "LINKER:-z,relro,-z,now,-z,noexecstack") set(full_relro_flags "-pie;LINKER:-z,relro,-z,now,-z,noexecstack")
set(full_relro_flags "-pie;${relro_flags}")
cmake_push_check_state() cmake_push_check_state()
list(APPEND CMAKE_REQUIRED_LINK_OPTIONS ${full_relro_flags}) list(APPEND CMAKE_REQUIRED_LINK_OPTIONS ${full_relro_flags})
check_cxx_source_compiles("int main(){}" HAS_FULL_RELRO FAIL_REGEX "warning:") check_cxx_source_compiles("int main(){}" HAS_FULL_RELRO FAIL_REGEX "warning:")
if(HAS_FULL_RELRO) if(HAS_FULL_RELRO)
# -pie only applies to executables; passing it when linking a shared library add_link_options(${full_relro_flags})
# makes the driver pull in Scrt1.o, which requires main.
add_link_options("$<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>:-pie>"
${relro_flags})
endif() endif()
cmake_pop_check_state() cmake_pop_check_state()
if(CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64 OR CMAKE_SYSTEM_PROCESSOR STREQUAL if(CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64)
arm64)
add_compile_options(-mbranch-protection=standard) add_compile_options(-mbranch-protection=standard)
else() else()
add_compile_options(-fcf-protection) add_compile_options(-fcf-protection)
@@ -103,42 +92,37 @@ option(USE_SIMD_FALLBACK
option(DISABLE_TSAN "Disable TSAN" OFF) option(DISABLE_TSAN "Disable TSAN" OFF)
set(MSAN_TOOLCHAIN_PATH
""
CACHE
PATH
"Path to an MSan-instrumented libc++ toolchain. When set, an MSan fuzz_driver target is added. Must contain include/c++/v1 and lib. See build_msan_toolchain.sh to produce one."
)
# This is encouraged according to # This is encouraged according to
# https://valgrind.org/docs/manual/manual-core-adv.html#manual-core-adv.clientreq # https://valgrind.org/docs/manual/manual-core-adv.html#manual-core-adv.clientreq
include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/valgrind) include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/valgrind)
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-Wno-invalid-offsetof>)
if(APPLE) if(APPLE)
add_link_options(-Wl,-dead_strip) add_link_options(-Wl,-dead_strip)
else() else()
add_link_options(-Wl,--gc-sections) add_link_options(-Wl,--gc-sections)
endif() endif()
if(USE_SIMD_FALLBACK) if(NOT USE_SIMD_FALLBACK)
add_compile_definitions(USE_SIMD_FALLBACK) cmake_push_check_state()
else() list(APPEND CMAKE_REQUIRED_FLAGS -mavx)
if(CMAKE_SYSTEM_PROCESSOR STREQUAL x86_64) check_include_file_cxx("immintrin.h" HAS_AVX)
if(HAS_AVX)
add_compile_options(-mavx) add_compile_options(-mavx)
add_compile_definitions(HAS_AVX)
endif()
cmake_pop_check_state()
check_include_file_cxx("arm_neon.h" HAS_ARM_NEON)
if(HAS_ARM_NEON)
add_compile_definitions(HAS_ARM_NEON)
endif() endif()
endif() endif()
set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "") set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "")
# Architecture-specific SIMD assembly. These functions operate on add_library(${PROJECT_NAME}-object OBJECT ConflictSet.cpp)
# potentially-indeterminate memory, which is UB in C++ but well-defined in
# assembly.
set(SIMD_ASM_FILES)
if(CMAKE_SYSTEM_PROCESSOR STREQUAL x86_64 AND NOT USE_SIMD_FALLBACK)
set(SIMD_ASM_FILES ${CMAKE_CURRENT_SOURCE_DIR}/simd_x86_64.S)
endif()
add_library(${PROJECT_NAME}-object OBJECT ConflictSet.cpp ${SIMD_ASM_FILES})
target_compile_options(${PROJECT_NAME}-object PRIVATE -fno-exceptions target_compile_options(${PROJECT_NAME}-object PRIVATE -fno-exceptions
-fvisibility=hidden) -fvisibility=hidden)
target_include_directories(${PROJECT_NAME}-object target_include_directories(${PROJECT_NAME}-object
@@ -154,7 +138,6 @@ add_custom_command(
COMMAND_EXPAND_LISTS) COMMAND_EXPAND_LISTS)
add_library(${PROJECT_NAME} SHARED ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.o) add_library(${PROJECT_NAME} SHARED ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.o)
add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}-object)
set_target_properties( set_target_properties(
${PROJECT_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PROJECT_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY
"${CMAKE_CURRENT_BINARY_DIR}/radix_tree") "${CMAKE_CURRENT_BINARY_DIR}/radix_tree")
@@ -171,7 +154,6 @@ if(HAS_VERSION_SCRIPT)
endif() endif()
add_library(${PROJECT_NAME}-static STATIC ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.o) add_library(${PROJECT_NAME}-static STATIC ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.o)
add_dependencies(${PROJECT_NAME}-static ${PROJECT_NAME}-object)
if(CMAKE_BUILD_TYPE STREQUAL Debug) if(CMAKE_BUILD_TYPE STREQUAL Debug)
set_target_properties(${PROJECT_NAME}-static PROPERTIES LINKER_LANGUAGE CXX) set_target_properties(${PROJECT_NAME}-static PROPERTIES LINKER_LANGUAGE CXX)
else() else()
@@ -241,7 +223,7 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND BUILD_TESTING)
endif() endif()
# ad hoc testing # ad hoc testing
add_executable(conflict_set_main ConflictSet.cpp ${SIMD_ASM_FILES}) add_executable(conflict_set_main ConflictSet.cpp)
target_include_directories(conflict_set_main target_include_directories(conflict_set_main
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include) PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_compile_definitions(conflict_set_main PRIVATE ENABLE_MAIN) target_compile_definitions(conflict_set_main PRIVATE ENABLE_MAIN)
@@ -257,7 +239,7 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND BUILD_TESTING)
cmake_pop_check_state() cmake_pop_check_state()
if(HAS_LIB_FUZZER) if(HAS_LIB_FUZZER)
add_executable(conflict_set_fuzz_test ConflictSet.cpp ${SIMD_ASM_FILES}) add_executable(conflict_set_fuzz_test ConflictSet.cpp)
target_include_directories(conflict_set_fuzz_test target_include_directories(conflict_set_fuzz_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include) PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_compile_definitions(conflict_set_fuzz_test PRIVATE ENABLE_FUZZ) target_compile_definitions(conflict_set_fuzz_test PRIVATE ENABLE_FUZZ)
@@ -268,9 +250,8 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND BUILD_TESTING)
endif() endif()
endif() endif()
# whitebox tests asan+ubsan # whitebox tests
add_executable(fuzz_driver ConflictSet.cpp FuzzTestDriver.cpp add_executable(fuzz_driver ConflictSet.cpp FuzzTestDriver.cpp)
${SIMD_ASM_FILES})
target_compile_options(fuzz_driver PRIVATE ${TEST_FLAGS}) target_compile_options(fuzz_driver PRIVATE ${TEST_FLAGS})
if(NOT CMAKE_CROSSCOMPILING) if(NOT CMAKE_CROSSCOMPILING)
target_compile_options(fuzz_driver PRIVATE -fsanitize=address,undefined) target_compile_options(fuzz_driver PRIVATE -fsanitize=address,undefined)
@@ -284,39 +265,9 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND 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()
# whitebox tests msan
if(MSAN_TOOLCHAIN_PATH)
add_executable(fuzz_driver_msan ConflictSet.cpp FuzzTestDriver.cpp
${SIMD_ASM_FILES})
target_compile_options(fuzz_driver_msan PRIVATE ${TEST_FLAGS})
if(NOT CMAKE_CROSSCOMPILING)
target_compile_options(
fuzz_driver_msan
PRIVATE -fsanitize=memory -fsanitize-memory-track-origins=2
$<$<COMPILE_LANGUAGE:CXX>:-stdlib=libc++>
-I${MSAN_TOOLCHAIN_PATH}/include/c++/v1)
target_link_options(
fuzz_driver_msan
PRIVATE
-fsanitize=memory
-fsanitize-memory-track-origins=2
-stdlib=libc++
-L${MSAN_TOOLCHAIN_PATH}/lib
LINKER:-rpath,${MSAN_TOOLCHAIN_PATH}/lib)
endif()
target_compile_definitions(fuzz_driver_msan PRIVATE ENABLE_FUZZ)
target_include_directories(fuzz_driver_msan
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
foreach(TEST ${CORPUS_TESTS})
get_filename_component(hash ${TEST} NAME)
add_test(NAME conflict_set_msan_${hash} COMMAND fuzz_driver_msan ${TEST})
endforeach()
endif()
# tsan tests # tsan tests
if(NOT CMAKE_CROSSCOMPILING AND NOT DISABLE_TSAN) if(NOT CMAKE_CROSSCOMPILING AND NOT DISABLE_TSAN)
add_executable(tsan_driver ConflictSet.cpp FuzzTestDriver.cpp add_executable(tsan_driver ConflictSet.cpp FuzzTestDriver.cpp)
${SIMD_ASM_FILES})
target_compile_options(tsan_driver PRIVATE ${TEST_FLAGS} -fsanitize=thread) target_compile_options(tsan_driver PRIVATE ${TEST_FLAGS} -fsanitize=thread)
target_link_options(tsan_driver PRIVATE -fsanitize=thread) target_link_options(tsan_driver PRIVATE -fsanitize=thread)
target_compile_definitions(tsan_driver PRIVATE ENABLE_FUZZ THREAD_TEST) target_compile_definitions(tsan_driver PRIVATE ENABLE_FUZZ THREAD_TEST)
@@ -395,7 +346,8 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND BUILD_TESTING)
# c++98 # c++98
add_executable(conflict_set_cxx_api_test conflict_set_cxx_api_test.cpp) add_executable(conflict_set_cxx_api_test conflict_set_cxx_api_test.cpp)
target_compile_options(conflict_set_cxx_api_test PRIVATE ${TEST_FLAGS}) target_compile_options(conflict_set_cxx_api_test PRIVATE ${TEST_FLAGS})
target_link_libraries(conflict_set_cxx_api_test PRIVATE ${PROJECT_NAME}) target_link_libraries(conflict_set_cxx_api_test
PRIVATE ${PROJECT_NAME}-static)
set_target_properties(conflict_set_cxx_api_test PROPERTIES CXX_STANDARD 98) set_target_properties(conflict_set_cxx_api_test PROPERTIES CXX_STANDARD 98)
set_target_properties(conflict_set_cxx_api_test set_target_properties(conflict_set_cxx_api_test
PROPERTIES CXX_STANDARD_REQUIRED ON) PROPERTIES CXX_STANDARD_REQUIRED ON)
@@ -431,30 +383,9 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND BUILD_TESTING)
if(NOT CMAKE_CROSSCOMPILING) if(NOT CMAKE_CROSSCOMPILING)
find_program(HARDENING_CHECK hardening-check) find_program(HARDENING_CHECK hardening-check)
if(HARDENING_CHECK) if(HARDENING_CHECK)
# Not all versions of hardening-check support the same options, so query add_test(NAME hardening_check
# the help output before using architecture-specific skips. COMMAND ${HARDENING_CHECK} $<TARGET_FILE:${PROJECT_NAME}>
execute_process( --nofortify --nostackprotector)
COMMAND ${HARDENING_CHECK} --help
OUTPUT_VARIABLE hardening_check_help
ERROR_VARIABLE hardening_check_help
OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_STRIP_TRAILING_WHITESPACE)
set(hardening_check_arch_flags "")
# Control flow integrity (CET) is x86-only and branch protection (PAC/BTI)
# is arm64-only, so ignore whichever doesn't apply.
if(CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64 OR CMAKE_SYSTEM_PROCESSOR
STREQUAL arm64)
if(hardening_check_help MATCHES "nocfprotection")
list(APPEND hardening_check_arch_flags --nocfprotection)
endif()
else()
if(hardening_check_help MATCHES "nobranchprotection")
list(APPEND hardening_check_arch_flags --nobranchprotection)
endif()
endif()
add_test(
NAME hardening_check
COMMAND ${HARDENING_CHECK} $<TARGET_FILE:${PROJECT_NAME}> --nofortify
--nostackprotector ${hardening_check_arch_flags})
endif() endif()
endif() endif()
+605 -473
View File
File diff suppressed because it is too large Load Diff
+58
View File
@@ -0,0 +1,58 @@
FROM ubuntu:rolling
WORKDIR /tmp
ENV HOME=/tmp
RUN chmod -R 777 /tmp
# Install apt dependencies
RUN apt-get update
RUN apt-get upgrade -y
RUN TZ=America/Los_Angeles DEBIAN_FRONTEND=noninteractive apt-get install -y \
binutils-aarch64-linux-gnu \
build-essential \
ccache \
cmake \
curl \
devscripts \
g++-aarch64-linux-gnu \
gcovr \
git \
gnupg \
libc6-dbg \
lsb-release \
mold \
ninja-build \
pre-commit \
python3-requests \
qemu-user \
rpm \
software-properties-common \
texlive-full \
wget \
zstd
# Install recent valgrind from source
RUN curl -Ls https://sourceware.org/pub/valgrind/valgrind-3.22.0.tar.bz2 -o valgrind.tar.bz2 && \
echo "c811db5add2c5f729944caf47c4e7a65dcaabb9461e472b578765dd7bf6d2d4c valgrind.tar.bz2" > valgrind-sha.txt && \
sha256sum --quiet -c valgrind-sha.txt && \
mkdir valgrind && \
tar --strip-components 1 --no-same-owner --no-same-permissions --directory valgrind -xjf valgrind.tar.bz2 && \
cd valgrind && \
./configure --enable-only64bit --enable-lto && \
make -j`nproc` && \
make install && \
cd .. && \
rm -rf /tmp/*
# Recent clang
RUN wget https://apt.llvm.org/llvm.sh && chmod +x ./llvm.sh && ./llvm.sh 20
RUN apt-get -y install clang llvm
# Set after building valgrind, which doesn't build with clang for some reason
ENV CC=clang
ENV CXX=clang++
# Try to have all the pre-commit hooks we'll need already initialized
COPY .pre-commit-config.yaml /tmp/
RUN git init && pre-commit install-hooks
+4 -15
View File
@@ -96,9 +96,7 @@ void ConflictSet::setOldestVersion(int64_t oldestVersion) {
return impl->setOldestVersion(oldestVersion); return impl->setOldestVersion(oldestVersion);
} }
// The hash_table implementation does not track memory usage, so return 0 to int64_t ConflictSet::getBytes() const { return -1; }
// satisfy the API contract that getBytes() returns a non-negative value.
int64_t ConflictSet::getBytes() const { return 0; }
void ConflictSet::getMetricsV1(MetricsV1 **metrics, int *count) const { void ConflictSet::getMetricsV1(MetricsV1 **metrics, int *count) const {
*metrics = nullptr; *metrics = nullptr;
@@ -121,13 +119,7 @@ ConflictSet::ConflictSet(ConflictSet &&other) noexcept
: impl(std::exchange(other.impl, nullptr)) {} : impl(std::exchange(other.impl, nullptr)) {}
ConflictSet &ConflictSet::operator=(ConflictSet &&other) noexcept { ConflictSet &ConflictSet::operator=(ConflictSet &&other) noexcept {
if (this != &other) { impl = std::exchange(other.impl, nullptr);
if (impl) {
impl->~Impl();
safe_free(impl, sizeof(Impl));
}
impl = std::exchange(other.impl, nullptr);
}
return *this; return *this;
} }
@@ -163,10 +155,7 @@ __attribute__((__visibility__("default"))) void ConflictSet_destroy(void *cs) {
} }
__attribute__((__visibility__("default"))) int64_t __attribute__((__visibility__("default"))) int64_t
ConflictSet_getBytes(void *cs) { ConflictSet_getBytes(void *cs) {
(void)cs; using Impl = ConflictSet::Impl;
// The hash_table implementation does not track memory usage, so return 0 to return -1;
// satisfy the API contract that ConflictSet_getBytes returns a non-negative
// value.
return 0;
} }
} }
+18
View File
@@ -18,6 +18,7 @@ using namespace weaselab;
#include <span> #include <span>
#include <string> #include <string>
#include <thread> #include <thread>
#include <unordered_set>
#include <utility> #include <utility>
#include <callgrind.h> #include <callgrind.h>
@@ -367,6 +368,23 @@ template <class T, class C = std::less<T>> auto set(Arena &arena) {
return Set<T, C>(ArenaAlloc<T>(&arena)); return Set<T, C>(ArenaAlloc<T>(&arena));
} }
template <class T> struct MyHash;
template <class T> struct MyHash<T *> {
size_t operator()(const T *t) const noexcept {
size_t result;
memcpy(&result, &t, sizeof(result));
return result;
}
};
template <class T>
using HashSet =
std::unordered_set<T, MyHash<T>, std::equal_to<T>, ArenaAlloc<T>>;
template <class T> auto hashSet(Arena &arena) {
return HashSet<T>(ArenaAlloc<T>(&arena));
}
template <class T, class U> template <class T, class U>
bool operator==(const ArenaAlloc<T> &lhs, const ArenaAlloc<U> &rhs) { bool operator==(const ArenaAlloc<T> &lhs, const ArenaAlloc<U> &rhs) {
return lhs.arena == rhs.arena; return lhs.arena == rhs.arena;
Vendored
+151
View File
@@ -0,0 +1,151 @@
def CleanBuildAndTest(String cmakeArgs) {
sh """
export CCACHE_DIR=/ccache
rm -rf build
mkdir build
cd build
cmake .. -G Ninja -DCMAKE_CXX_COMPILER_LAUNCHER=ccache ${cmakeArgs}
ninja
ccache -s
"""
catchError {
sh '''
cd build
ctest --no-compress-output --test-output-size-passed 100000 --test-output-size-failed 100000 -T Test -j `nproc` --timeout 90 > /dev/null
zstd Testing/*/Test.xml
'''
}
xunit tools: [CTest(pattern: 'build/Testing/*/Test.xml')], skipPublishingChecks: false
minio bucket: 'jenkins', credentialsId: 'jenkins-minio', excludes: '', host: 'minio.weaselab.dev', includes: 'build/Testing/*/Test.xml.zst', targetFolder: '${JOB_NAME}/${BUILD_NUMBER}/${STAGE_NAME}/'
}
pipeline {
agent any
stages {
stage('Pre-commit') {
agent {
dockerfile {
args '-v /home/jenkins/ccache:/ccache'
reuseNode true
}
}
steps {
script {
env.HOME = env.WORKSPACE
}
sh 'pre-commit run --all-files --show-diff-on-failure'
}
}
stage('64 bit versions') {
agent {
dockerfile {
args '-v /home/jenkins/ccache:/ccache'
reuseNode true
}
}
steps {
CleanBuildAndTest("-DCMAKE_CXX_FLAGS=-DUSE_64_BIT=1")
}
}
stage('Debug') {
agent {
dockerfile {
args '-v /home/jenkins/ccache:/ccache'
reuseNode true
}
}
steps {
CleanBuildAndTest("-DCMAKE_BUILD_TYPE=Debug")
}
}
stage('SIMD fallback') {
agent {
dockerfile {
args '-v /home/jenkins/ccache:/ccache'
reuseNode true
}
}
steps {
CleanBuildAndTest("-DUSE_SIMD_FALLBACK=ON")
}
}
stage('Release [clang]') {
agent {
dockerfile {
args '-v /home/jenkins/ccache:/ccache'
reuseNode true
}
}
steps {
CleanBuildAndTest("-DCMAKE_CXX_FLAGS=-DNVALGRIND")
recordIssues(tools: [clang()])
sh '''
cd build
cpack -G DEB
cpack -G RPM
'''
sh '''
cd paper
make
'''
minio bucket: 'jenkins', credentialsId: 'jenkins-minio', excludes: '', host: 'minio.weaselab.dev', includes: 'build/*.deb,build/*.rpm,paper/*.pdf', targetFolder: '${JOB_NAME}/${BUILD_NUMBER}/${STAGE_NAME}/'
}
}
stage('Release [gcc]') {
agent {
dockerfile {
args '-v /home/jenkins/ccache:/ccache'
reuseNode true
}
}
steps {
CleanBuildAndTest("-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_CXX_FLAGS=-DNVALGRIND")
recordIssues(tools: [gcc()])
}
}
stage('Release [clang,aarch64]') {
agent {
dockerfile {
args '-v /home/jenkins/ccache:/ccache'
reuseNode true
}
}
steps {
CleanBuildAndTest("-DCMAKE_TOOLCHAIN_FILE=../aarch64-toolchain.cmake -DCMAKE_CXX_FLAGS=-DNVALGRIND")
sh '''
cd build
cpack -G DEB
cpack -G RPM
'''
minio bucket: 'jenkins', credentialsId: 'jenkins-minio', excludes: '', host: 'minio.weaselab.dev', includes: 'build/*.deb,build/*.rpm', targetFolder: '${JOB_NAME}/${BUILD_NUMBER}/${STAGE_NAME}'
}
}
stage('Coverage') {
agent {
dockerfile {
args '-v /home/jenkins/ccache:/ccache'
reuseNode true
}
}
steps {
script {
gcov_args = "-f ConflictSet.cpp -f LongestCommonPrefix.h -f Metrics.h --gcov-executable 'llvm-cov gcov' --exclude-noncode-lines"
}
CleanBuildAndTest("-DCMAKE_C_FLAGS=--coverage -DCMAKE_CXX_FLAGS=--coverage -DCMAKE_BUILD_TYPE=Debug -DDISABLE_TSAN=ON")
sh """
gcovr ${gcov_args} --cobertura > build/coverage.xml
"""
recordCoverage qualityGates: [[criticality: 'NOTE', metric: 'MODULE']], tools: [[parser: 'COBERTURA', pattern: 'build/coverage.xml']]
sh """
gcovr ${gcov_args}
gcovr ${gcov_args} --fail-under-line 100 > /dev/null
"""
}
}
}
post {
always {
emailext mimeType: 'text/html', body: '${SCRIPT, template="groovy-html.template"}', subject: "${env.JOB_NAME} - Build# ${env.BUILD_NUMBER} - ${currentBuild.currentResult}", to: 'andrew@weaselab.dev'
}
}
}
+23 -32
View File
@@ -4,14 +4,7 @@ Intended as an alternative to FoundationDB's skip list.
Hardware for all benchmarks is an AMD Ryzen 9 7900 with (2x32GB) 5600MT/s CL28-34-34-89 1.35V RAM. Hardware for all benchmarks is an AMD Ryzen 9 7900 with (2x32GB) 5600MT/s CL28-34-34-89 1.35V RAM.
``` Compiler is `Ubuntu clang version 20.0.0 (++20241029082144+7544d3af0e28-1~exp1~20241029082307.506)`.
$ clang++ --version
Ubuntu clang version 21.1.8 (6ubuntu1)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/lib/llvm-21/bin
```
# Microbenchmark # Microbenchmark
@@ -19,45 +12,44 @@ InstalledDir: /usr/lib/llvm-21/bin
| ns/op | op/s | err% | ins/op | cyc/op | IPC | bra/op | miss% | total | benchmark | ns/op | op/s | err% | ins/op | cyc/op | IPC | bra/op | miss% | total | benchmark
|--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:---------- |--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:----------
| 164.29 | 6,086,873.38 | 0.0% | 3,107.03 | 604.19 | 5.142 | 558.59 | 0.0% | 1.96 | `point reads` | 159.65 | 6,263,576.52 | 1.6% | 2,972.36 | 820.37 | 3.623 | 504.59 | 0.0% | 0.01 | `point reads`
| 161.05 | 6,209,395.38 | 0.1% | 3,036.76 | 592.21 | 5.128 | 539.35 | 0.0% | 1.93 | `prefix reads` | 156.32 | 6,397,320.65 | 0.7% | 2,913.62 | 806.87 | 3.611 | 490.19 | 0.0% | 0.01 | `prefix reads`
| 239.55 | 4,174,539.38 | 0.1% | 3,722.71 | 880.68 | 4.227 | 692.00 | 0.0% | 2.86 | `range reads` | 229.18 | 4,363,293.65 | 1.2% | 3,541.05 | 1,219.75 | 2.903 | 629.33 | 0.0% | 0.01 | `range reads`
| 354.75 | 2,818,919.14 | 0.7% | 4,523.64 | 1,304.75 | 3.467 | 720.22 | 2.0% | 4.23 | `point writes` | 363.37 | 2,752,026.30 | 0.3% | 5,273.63 | 1,951.54 | 2.702 | 851.66 | 1.7% | 0.01 | `point writes`
| 345.32 | 2,895,878.47 | 0.1% | 4,484.57 | 1,270.31 | 3.530 | 705.00 | 1.8% | 4.12 | `prefix writes` | 364.99 | 2,739,787.02 | 0.3% | 5,250.92 | 1,958.54 | 2.681 | 839.24 | 1.7% | 0.01 | `prefix writes`
| 193.48 | 5,168,547.42 | 0.1% | 2,224.10 | 711.72 | 3.125 | 377.17 | 3.3% | 2.32 | `range writes` | 242.26 | 4,127,796.58 | 2.9% | 3,117.33 | 1,304.41 | 2.390 | 541.07 | 2.8% | 0.02 | `range writes`
| 404.89 | 2,469,777.50 | 2.4% | 6,855.96 | 1,489.70 | 4.602 | 1,227.82 | 1.3% | 0.05 | `monotonic increasing point writes` | 562.48 | 1,777,855.27 | 0.8% | 7,305.21 | 3,034.34 | 2.408 | 1,329.30 | 1.3% | 0.01 | `monotonic increasing point writes`
| 134,231.80 | 7,449.80 | 1.9% | 812,045.25 | 495,770.40 | 1.638 | 151,246.50 | 0.9% | 0.01 | `worst case for radix tree` | 122,688.57 | 8,150.72 | 0.7% | 798,766.00 | 666,842.00 | 1.198 | 144,584.50 | 0.1% | 0.01 | `worst case for radix tree`
| 37.80 | 26,454,311.17 | 0.4% | 701.00 | 139.14 | 5.038 | 102.00 | 0.0% | 0.01 | `create and destroy` | 41.71 | 23,976,459.34 | 1.7% | 885.00 | 219.17 | 4.038 | 132.00 | 0.0% | 0.01 | `create and destroy`
## Radix tree (this implementation) ## Radix tree (this implementation)
| ns/op | op/s | err% | ins/op | cyc/op | IPC | bra/op | miss% | total | benchmark | ns/op | op/s | err% | ins/op | cyc/op | IPC | bra/op | miss% | total | benchmark
|--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:---------- |--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:----------
| 12.89 | 77,565,115.56 | 0.1% | 244.55 | 47.43 | 5.155 | 34.21 | 0.6% | 0.15 | `point reads` | 12.63 | 79,186,868.18 | 1.4% | 241.61 | 64.76 | 3.731 | 31.64 | 0.8% | 0.01 | `point reads`
| 15.11 | 66,162,047.76 | 0.1% | 297.79 | 55.60 | 5.356 | 43.23 | 0.4% | 0.18 | `prefix reads` | 14.48 | 69,078,073.40 | 0.3% | 292.42 | 74.69 | 3.915 | 41.49 | 0.5% | 0.01 | `prefix reads`
| 36.29 | 27,559,358.29 | 0.1% | 783.16 | 133.44 | 5.869 | 109.52 | 0.2% | 0.43 | `range reads` | 34.37 | 29,094,694.11 | 0.2% | 759.53 | 179.77 | 4.225 | 100.38 | 0.2% | 0.01 | `range reads`
| 20.53 | 48,719,405.55 | 0.1% | 381.81 | 75.51 | 5.057 | 51.04 | 0.5% | 0.25 | `point writes` | 19.34 | 51,713,896.36 | 0.7% | 369.70 | 101.81 | 3.631 | 47.88 | 0.6% | 0.01 | `point writes`
| 39.37 | 25,402,042.40 | 0.1% | 685.00 | 144.83 | 4.730 | 106.72 | 0.3% | 0.47 | `prefix writes` | 39.16 | 25,538,968.61 | 0.2% | 653.16 | 206.77 | 3.159 | 89.62 | 0.8% | 0.01 | `prefix writes`
| 43.78 | 22,843,841.63 | 0.1% | 800.40 | 161.06 | 4.970 | 127.36 | 0.1% | 0.53 | `range writes` | 40.58 | 24,642,681.12 | 4.7% | 718.44 | 216.44 | 3.319 | 99.28 | 0.6% | 0.01 | `range writes`
| 78.37 | 12,760,008.75 | 1.0% | 1,452.61 | 288.24 | 5.040 | 278.69 | 0.1% | 0.01 | `monotonic increasing point writes` | 78.77 | 12,694,520.69 | 3.8% | 1,395.55 | 421.73 | 3.309 | 249.81 | 0.1% | 0.01 | `monotonic increasing point writes`
| 322,885.50 | 3,097.07 | 1.5% | 4,362,382.00 | 1,183,852.00 | 3.685 | 765,301.00 | 0.1% | 0.01 | `worst case for radix tree` | 287,760.50 | 3,475.11 | 0.5% | 3,929,266.50 | 1,550,225.50 | 2.535 | 639,064.00 | 0.0% | 0.01 | `worst case for radix tree`
| 99.99 | 10,000,718.79 | 0.4% | 1,775.00 | 367.93 | 4.824 | 288.00 | 0.0% | 0.01 | `create and destroy` | 104.76 | 9,545,250.65 | 3.1% | 2,000.00 | 552.82 | 3.618 | 342.00 | 0.0% | 0.01 | `create and destroy`
# "Real data" test # "Real data" test
Point queries only. Gc ratio is the ratio of time spent doing garbage collection to time spent adding writes or doing garbage collection. Lower is better. Point queries only, best of three runs. Gc ratio is the ratio of time spent doing garbage collection to time spent adding writes or doing garbage collection. Lower is better.
## skip list ## skip list
``` ```
Check: 4.62967 seconds, 352.195 MB/s, Add: 3.34177 seconds, 167.771 MB/s, Gc ratio: 37.9399%, Peak idle memory: 5.51852e+06 Check: 4.39702 seconds, 370.83 MB/s, Add: 4.50025 seconds, 124.583 MB/s, Gc ratio: 29.1333%, Peak idle memory: 5.51852e+06
``` ```
## radix tree ## radix tree
``` ```
Check: 1.00477 seconds, 1622.8 MB/s, Add: 1.21142 seconds, 462.808 MB/s, Gc ratio: 39.4716%, Peak idle memory: 2.0226e+06 Check: 0.987757 seconds, 1650.76 MB/s, Add: 1.24815 seconds, 449.186 MB/s, Gc ratio: 41.4675%, Peak idle memory: 2.02872e+06
``` ```
## hash table ## hash table
@@ -65,6 +57,5 @@ Check: 1.00477 seconds, 1622.8 MB/s, Add: 1.21142 seconds, 462.808 MB/s, Gc rati
(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: 0.854254 seconds, 1908.74 MB/s, Add: 0.632626 seconds, 886.232 MB/s, Gc ratio: 41.0827%, Peak idle memory: 0 Check: 0.84256 seconds, 1935.23 MB/s, Add: 0.697204 seconds, 804.146 MB/s, Gc ratio: 35.4091%
``` ```
+12 -13
View File
@@ -1,12 +1,11 @@
#include <ConflictSet.h> #include <ConflictSet.h>
#include <algorithm>
#include <cerrno> #include <cerrno>
#include <chrono> #include <chrono>
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#include <fcntl.h> #include <fcntl.h>
#include <span> #include <string_view>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
@@ -65,7 +64,7 @@ int main(int argc, const char **argv) {
auto *const mapOriginal = begin; auto *const mapOriginal = begin;
const auto sizeOriginal = size; const auto sizeOriginal = size;
using StringView = std::span<const uint8_t>; using StringView = std::basic_string_view<uint8_t>;
StringView write; StringView write;
std::vector<StringView> reads; std::vector<StringView> reads;
@@ -78,10 +77,10 @@ int main(int argc, const char **argv) {
begin = end + 1; begin = end + 1;
end = (uint8_t *)memchr(begin, '\n', size); end = (uint8_t *)memchr(begin, '\n', size);
if (line.size() >= 2 && line[0] == 'P') { if (line.size() > 0 && line[0] == 'P') {
write = line.subspan(2, line.size() - 2); write = line.substr(2, line.size());
} else if (line.size() >= 2 && line[0] == 'L') { } else if (line.size() > 0 && line[0] == 'L') {
reads.push_back(line.subspan(2, line.size() - 2)); reads.push_back(line.substr(2, line.size()));
} else if (line.empty()) { } else if (line.empty()) {
{ {
readRanges.resize(reads.size()); readRanges.resize(reads.size());
@@ -91,7 +90,7 @@ int main(int argc, const char **argv) {
iter->begin.len = read.size(); iter->begin.len = read.size();
checkBytes += read.size(); checkBytes += read.size();
iter->end.len = 0; iter->end.len = 0;
iter->readVersion = std::max<int64_t>(0, version - 100); iter->readVersion = version - 100;
++iter; ++iter;
} }
} }
@@ -122,7 +121,7 @@ int main(int argc, const char **argv) {
} }
timer = now(); timer = now();
cs.setOldestVersion(std::max<int64_t>(0, version - 10000)); cs.setOldestVersion(version - 10000);
gcTime += now() - timer; gcTime += now() - timer;
} }
} }
@@ -134,10 +133,10 @@ int main(int argc, const char **argv) {
int metricsCount; int metricsCount;
cs.getMetricsV1(&metrics, &metricsCount); cs.getMetricsV1(&metrics, &metricsCount);
for (int i = 0; i < metricsCount; ++i) { for (int i = 0; i < metricsCount; ++i) {
fprintf(stderr, "# HELP %s %s\n", metrics[i].name, metrics[i].help); printf("# HELP %s %s\n", metrics[i].name, metrics[i].help);
fprintf(stderr, "# TYPE %s %s\n", metrics[i].name, printf("# TYPE %s %s\n", metrics[i].name,
metrics[i].type == metrics[i].Counter ? "counter" : "gauge"); metrics[i].type == metrics[i].Counter ? "counter" : "gauge");
fprintf(stderr, "%s %g\n", metrics[i].name, metrics[i].getValue()); printf("%s %g\n", metrics[i].name, metrics[i].getValue());
} }
printf("Check: %g seconds, %g MB/s, Add: %g seconds, %g MB/s, Gc ratio: " printf("Check: %g seconds, %g MB/s, Add: %g seconds, %g MB/s, Gc ratio: "
+31 -163
View File
@@ -12,7 +12,6 @@
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/resource.h> #include <sys/resource.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/uio.h> #include <sys/uio.h>
#include <thread> #include <thread>
@@ -24,97 +23,6 @@
#include "Internal.h" #include "Internal.h"
#include "third_party/nadeau.h" #include "third_party/nadeau.h"
constexpr int kCacheLine = 64; // TODO mac m1 is 128
template <class T> struct TxQueue {
explicit TxQueue(int lgSlotCount)
: slotCount(1 << lgSlotCount), slotCountMask(slotCount - 1),
slots(new T[slotCount]) {
// Otherwise we can't tell the difference between full and empty.
assert(!(slotCountMask & 0x80000000));
}
/// Call from producer thread, after ensuring consumer is no longer accessing
/// it somehow
~TxQueue() { delete[] slots; }
/// Must be called from the producer thread
void push(T t) {
if (wouldBlock()) {
// Wait for pops to change and try again
consumer.pops.wait(producer.lastPopRead, std::memory_order_relaxed);
producer.lastPopRead = consumer.pops.load(std::memory_order_acquire);
}
slots[producer.pushesNonAtomic++ & slotCountMask] = std::move(t);
// seq_cst so that the notify can't be ordered before the store
producer.pushes.store(producer.pushesNonAtomic, std::memory_order_seq_cst);
// We have to notify every time, since we don't know if this is the last
// push ever
producer.pushes.notify_one();
}
/// Must be called from the producer thread
uint32_t outstanding() {
return producer.pushesNonAtomic -
consumer.pops.load(std::memory_order_relaxed);
}
/// Returns true if a call to push might block. Must be called from the
/// producer thread.
bool wouldBlock() {
// See if we can determine that overflow won't happen entirely from state
// local to the producer
if (producer.pushesNonAtomic - producer.lastPopRead == slotCount - 1) {
// Re-read pops with memory order
producer.lastPopRead = consumer.pops.load(std::memory_order_acquire);
return producer.pushesNonAtomic - producer.lastPopRead == slotCount - 1;
}
return false;
}
/// Valid until the next pop, or until this queue is destroyed.
T *pop() {
// See if we can determine that there's an entry we can pop entirely from
// state local to the consumer
if (consumer.lastPushRead - consumer.popsNonAtomic == 0) {
// Re-read pushes with memory order and try again
consumer.lastPushRead = producer.pushes.load(std::memory_order_acquire);
if (consumer.lastPushRead - consumer.popsNonAtomic == 0) {
// Wait for pushes to change and try again
producer.pushes.wait(consumer.lastPushRead, std::memory_order_relaxed);
consumer.lastPushRead = producer.pushes.load(std::memory_order_acquire);
}
}
auto result = &slots[consumer.popsNonAtomic++ & slotCountMask];
// We only have to write pops with memory order if we've run out of items.
// We know that we'll eventually run out.
if (consumer.lastPushRead - consumer.popsNonAtomic == 0) {
// seq_cst so that the notify can't be ordered before the store
consumer.pops.store(consumer.popsNonAtomic, std::memory_order_seq_cst);
consumer.pops.notify_one();
}
return result;
}
private:
const uint32_t slotCount;
const uint32_t slotCountMask;
T *slots;
struct alignas(kCacheLine) ProducerState {
std::atomic<uint32_t> pushes{0};
uint32_t pushesNonAtomic{0};
uint32_t lastPopRead{0};
};
struct alignas(kCacheLine) ConsumerState {
std::atomic<uint32_t> pops{0};
uint32_t popsNonAtomic{0};
uint32_t lastPushRead{0};
};
ProducerState producer;
ConsumerState consumer;
};
std::atomic<int64_t> transactions; std::atomic<int64_t> transactions;
int64_t safeUnaryMinus(int64_t x) { int64_t safeUnaryMinus(int64_t x) {
@@ -139,17 +47,13 @@ void tupleAppend(std::string &output, int64_t value) {
void tupleAppend(std::string &output, std::string_view value) { void tupleAppend(std::string &output, std::string_view value) {
output.push_back('\x02'); output.push_back('\x02');
if (memchr(value.data(), '\x00', value.size()) != nullptr) { for (auto c : value) {
for (auto c : value) { if (c == '\x00') {
if (c == '\x00') { output.push_back('\x00');
output.push_back('\x00'); output.push_back('\xff');
output.push_back('\xff'); } else {
} else { output.push_back(c);
output.push_back(c);
}
} }
} else {
output.insert(output.end(), value.begin(), value.end());
} }
output.push_back('\x00'); output.push_back('\x00');
} }
@@ -162,69 +66,49 @@ template <class... Ts> std::string tupleKey(const Ts &...ts) {
constexpr int kTotalKeyRange = 1'000'000'000; constexpr int kTotalKeyRange = 1'000'000'000;
constexpr int kWindowSize = 1'000'000; constexpr int kWindowSize = 1'000'000;
constexpr int kNumReadKeysPerTx = 5; constexpr int kNumKeys = 10;
constexpr int kNumWriteKeysPerTx = 10;
struct Transaction { void workload(weaselab::ConflictSet *cs) {
std::vector<std::string> keys; int64_t version = kWindowSize;
std::vector<weaselab::ConflictSet::ReadRange> reads; for (;; transactions.fetch_add(1, std::memory_order_relaxed)) {
std::vector<weaselab::ConflictSet::WriteRange> writes;
int64_t version;
int64_t oldestVersion;
Transaction() = default;
explicit Transaction(int64_t version)
: version(version), oldestVersion(version - kWindowSize) {
std::vector<int64_t> keyIndices; std::vector<int64_t> keyIndices;
for (int i = 0; i < std::max(kNumReadKeysPerTx, kNumWriteKeysPerTx); ++i) { for (int i = 0; i < kNumKeys; ++i) {
keyIndices.push_back(rand() % kTotalKeyRange); keyIndices.push_back(rand() % kTotalKeyRange);
} }
std::sort(keyIndices.begin(), keyIndices.end()); std::sort(keyIndices.begin(), keyIndices.end());
std::vector<std::string> keys;
constexpr std::string_view fullString = constexpr std::string_view fullString =
"this is a string, where a prefix of it is used as an element of the " "this is a string, where a prefix of it is used as an element of the "
"tuple forming the key"; "tuple forming the key";
for (int i = 0; i < int(keyIndices.size()); ++i) { for (int i = 0; i < kNumKeys; ++i) {
keys.push_back( keys.push_back(
tupleKey(0x100, keyIndices[i] / fullString.size(), tupleKey(0x100, keyIndices[i] / fullString.size(),
fullString.substr(0, keyIndices[i] % fullString.size()))); fullString.substr(0, keyIndices[i] % fullString.size())));
// printf("%s\n", printable(keys.back()).c_str()); // printf("%s\n", printable(keys.back()).c_str());
} }
for (int i = 0; i < kNumWriteKeysPerTx; ++i) {
std::vector<weaselab::ConflictSet::ReadRange> reads;
std::vector<weaselab::ConflictSet::WriteRange> writes;
std::vector<weaselab::ConflictSet::Result> results;
for (int i = 0; i < kNumKeys; ++i) {
writes.push_back({{(const uint8_t *)keys[i].data(), int(keys[i].size())}, writes.push_back({{(const uint8_t *)keys[i].data(), int(keys[i].size())},
{nullptr, 0}}); {nullptr, 0}});
}
reads.push_back({{(const uint8_t *)keys[0].data(), int(keys[0].size())},
{(const uint8_t *)keys[1].data(), int(keys[1].size())},
version - std::min(10, kWindowSize)});
static_assert(kNumReadKeysPerTx >= 3);
for (int i = 2; i < kNumReadKeysPerTx; ++i) {
reads.push_back({{(const uint8_t *)keys[i].data(), int(keys[i].size())}, reads.push_back({{(const uint8_t *)keys[i].data(), int(keys[i].size())},
{nullptr, 0}, {nullptr, 0},
version - kWindowSize}); version - kWindowSize});
} }
results.resize(reads.size());
cs->check(reads.data(), results.data(), reads.size());
bool ok = true;
for (auto result : results) {
ok &= result == weaselab::ConflictSet::Commit;
}
cs->addWrites(writes.data(), ok ? writes.size() : 0, version);
cs->setOldestVersion(version - kWindowSize);
++version;
} }
}
Transaction(Transaction &&) = default;
Transaction &operator=(Transaction &&) = default;
Transaction(Transaction const &) = delete;
Transaction const &operator=(Transaction const &) = delete;
};
struct Resolver {
void resolve(const weaselab::ConflictSet::ReadRange *reads, int readCount,
const weaselab::ConflictSet::WriteRange *writes, int writeCount,
int64_t newVersion, int64_t newOldestVersion) {
results.resize(readCount);
cs.check(reads, results.data(), readCount);
cs.addWrites(writes, writeCount, newVersion);
cs.setOldestVersion(newOldestVersion);
}
ConflictSet cs{0};
private:
std::vector<weaselab::ConflictSet::Result> results;
};
// Adapted from getaddrinfo man page // Adapted from getaddrinfo man page
int getListenFd(const char *node, const char *service) { int getListenFd(const char *node, const char *service) {
@@ -367,8 +251,7 @@ int main(int argc, char **argv) {
{ {
int listenFd = getListenFd(argv[1], argv[2]); int listenFd = getListenFd(argv[1], argv[2]);
Resolver resolver; weaselab::ConflictSet cs{0};
auto &cs = resolver.cs;
weaselab::ConflictSet::MetricsV1 *metrics; weaselab::ConflictSet::MetricsV1 *metrics;
int metricsCount; int metricsCount;
cs.getMetricsV1(&metrics, &metricsCount); cs.getMetricsV1(&metrics, &metricsCount);
@@ -417,22 +300,7 @@ int main(int argc, char **argv) {
} }
#endif #endif
TxQueue<Transaction> queue{10}; auto w = std::thread{workload, &cs};
auto workloadThread = std::thread{[&]() {
for (int64_t version = kWindowSize;;
++version, transactions.fetch_add(1, std::memory_order_relaxed)) {
queue.push(Transaction(version));
}
}};
auto resolverThread = std::thread{[&]() {
for (;;) {
auto tx = queue.pop();
resolver.resolve(tx->reads.data(), tx->reads.size(), tx->writes.data(),
tx->writes.size(), tx->version, tx->oldestVersion);
}
}};
for (;;) { for (;;) {
struct sockaddr_storage peer_addr = {}; struct sockaddr_storage peer_addr = {};
+5 -14
View File
@@ -38,9 +38,6 @@ std::span<const uint8_t> keyAfter(Arena &arena, std::span<const uint8_t> key) {
std::span<const uint8_t> copyToArena(Arena &arena, std::span<const uint8_t> copyToArena(Arena &arena,
std::span<const uint8_t> key) { std::span<const uint8_t> key) {
if (key.size() == 0) {
return std::span<const uint8_t>();
}
auto result = std::span<uint8_t>(new (arena) uint8_t[key.size()], key.size()); auto result = std::span<uint8_t>(new (arena) uint8_t[key.size()], key.size());
memcpy(result.data(), key.data(), key.size()); memcpy(result.data(), key.data(), key.size());
return result; return result;
@@ -100,7 +97,7 @@ force_inline bool getCharacter(const KeyInfo &ki, int character,
bool operator<(const KeyInfo &lhs, const KeyInfo &rhs) { bool operator<(const KeyInfo &lhs, const KeyInfo &rhs) {
int i = std::min(lhs.key.size(), rhs.key.size()); int i = std::min(lhs.key.size(), rhs.key.size());
int c = i > 0 ? memcmp(lhs.key.data(), rhs.key.data(), i) : 0; int c = memcmp(lhs.key.data(), rhs.key.data(), i);
if (c != 0) if (c != 0)
return c < 0; return c < 0;
@@ -290,8 +287,7 @@ private:
static force_inline bool less(const uint8_t *a, int aLen, const uint8_t *b, static force_inline bool less(const uint8_t *a, int aLen, const uint8_t *b,
int bLen) { int bLen) {
int n = std::min(aLen, bLen); int c = memcmp(a, b, std::min(aLen, bLen));
int c = n > 0 ? memcmp(a, b, n) : 0;
if (c < 0) if (c < 0)
return true; return true;
if (c > 0) if (c > 0)
@@ -758,8 +754,7 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
void addWrites(const ConflictSet::WriteRange *writes, int count, void addWrites(const ConflictSet::WriteRange *writes, int count,
int64_t writeVersion) { int64_t writeVersion) {
auto points = std::vector<KeyInfo>(); auto points = std::vector<KeyInfo>(count * 2);
points.reserve(count * 2);
Arena arena; Arena arena;
for (int r = 0; r < count; r++) { for (int r = 0; r < count; r++) {
@@ -801,6 +796,7 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
int temp[stripeSize]; int temp[stripeSize];
int stripes = (stringCount + stripeSize - 1) / stripeSize; int stripes = (stringCount + stripeSize - 1) / stripeSize;
StringRef values[stripeSize]; StringRef values[stripeSize];
int64_t writeVersions[stripeSize / 2];
int ss = stringCount - (stripes - 1) * stripeSize; int ss = stringCount - (stripes - 1) * stripeSize;
int64_t entryDelta = 0; int64_t entryDelta = 0;
for (int s = stripes - 1; s >= 0; s--) { for (int s = stripes - 1; s >= 0; s--) {
@@ -986,12 +982,7 @@ ConflictSet::ConflictSet(ConflictSet &&other) noexcept
: impl(std::exchange(other.impl, nullptr)) {} : impl(std::exchange(other.impl, nullptr)) {}
ConflictSet &ConflictSet::operator=(ConflictSet &&other) noexcept { ConflictSet &ConflictSet::operator=(ConflictSet &&other) noexcept {
if (this != &other) { impl = std::exchange(other.impl, nullptr);
if (impl) {
internal_destroy(impl);
}
impl = std::exchange(other.impl, nullptr);
}
return *this; return *this;
} }
-2
View File
@@ -1,4 +1,3 @@
___chkstk_darwin
___stack_chk_fail ___stack_chk_fail
___stack_chk_guard ___stack_chk_guard
__tlv_bootstrap __tlv_bootstrap
@@ -6,7 +5,6 @@ _abort
_bzero _bzero
_free _free
_malloc _malloc
_memcmp
_memcpy _memcpy
_memmove _memmove
dyld_stub_binder dyld_stub_binder
-43
View File
@@ -1,43 +0,0 @@
#!/bin/bash
set -euxo pipefail
LLVM_VERSION="${LLVM_VERSION:-21}"
MSAN_PREFIX="${MSAN_PREFIX:-$PWD/msan}"
JOBS="${JOBS:-$(nproc)}"
cd /tmp
rm -rf libcxx-msan
mkdir libcxx-msan
cd libcxx-msan
git clone --depth=1 "https://github.com/llvm/llvm-project.git" -b "release/${LLVM_VERSION}.x"
cmake -S llvm-project/runtimes -B build_msan \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_COMPILER="clang++-${LLVM_VERSION}" \
-DCMAKE_C_COMPILER="clang-${LLVM_VERSION}" \
-DCMAKE_INSTALL_PREFIX="${MSAN_PREFIX}" \
-DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind" \
-DLLVM_USE_SANITIZER=MemoryWithOrigins
cmake --build build_msan -j"${JOBS}"
cmake --install build_msan
cmake -S llvm-project/runtimes -B build_nomsan \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_COMPILER="clang++-${LLVM_VERSION}" \
-DCMAKE_C_COMPILER="clang-${LLVM_VERSION}" \
-DCMAKE_INSTALL_PREFIX="${MSAN_PREFIX}" \
-DLLVM_ENABLE_RUNTIMES="libunwind"
cmake --build build_nomsan -j"${JOBS}"
cmake --install build_nomsan
VERSION="$(clang-"${LLVM_VERSION}" --version | head -n1 | sed -E 's/.*clang version ([0-9.]+).*/\1/')"
TARBALL="msan-toolchain-${VERSION}.tar.zst"
tar --zstd -cf "${TARBALL}" -C "${MSAN_PREFIX}" .
TARBALL_PATH="$(pwd)/${TARBALL}"
echo "Created: ${TARBALL_PATH}"
+9 -27
View File
@@ -27,37 +27,23 @@ class Result(enum.Enum):
TOO_OLD = 2 TOO_OLD = 2
def _make_key(buf: bytes) -> tuple[_Key, bytearray]:
"""Create a _Key and a backing bytearray that must be kept alive."""
backing = bytearray(buf)
array = (ctypes.c_ubyte * len(backing)).from_buffer(backing)
return _Key(array, len(array)), backing
def write(begin: bytes, end: Optional[bytes] = None) -> WriteRange: def write(begin: bytes, end: Optional[bytes] = None) -> WriteRange:
begin_key, begin_buf = _make_key(begin) b = (ctypes.c_ubyte * len(begin)).from_buffer(bytearray(begin))
if end is None: if end is None:
end_key = _Key((ctypes.c_ubyte * 0)(), 0) e = (ctypes.c_ubyte * 0)()
end_buf = None
else: else:
end_key, end_buf = _make_key(end) e = (ctypes.c_ubyte * len(end)).from_buffer(bytearray(end))
result = WriteRange(begin_key, end_key) return WriteRange(_Key(b, len(b)), _Key(e, len(e)))
result._begin_buf = begin_buf
result._end_buf = end_buf
return result
def read(version: int, begin: bytes, end: Optional[bytes] = None) -> ReadRange: def read(version: int, begin: bytes, end: Optional[bytes] = None) -> ReadRange:
begin_key, begin_buf = _make_key(begin) b = (ctypes.c_ubyte * len(begin)).from_buffer(bytearray(begin))
if end is None: if end is None:
end_key = _Key((ctypes.c_ubyte * 0)(), 0) e = (ctypes.c_ubyte * 0)()
end_buf = None
else: else:
end_key, end_buf = _make_key(end) e = (ctypes.c_ubyte * len(end)).from_buffer(bytearray(end))
result = ReadRange(begin_key, end_key, version) return ReadRange(_Key(b, len(b)), _Key(e, len(e)), version)
result._begin_buf = begin_buf
result._end_buf = end_buf
return result
class ConflictSet: class ConflictSet:
@@ -102,7 +88,6 @@ class ConflictSet:
ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int),
ctypes.c_int, ctypes.c_int,
) )
self._lib.ConflictSet_check.restype = None
self._lib.ConflictSet_addWrites.argtypes = ( self._lib.ConflictSet_addWrites.argtypes = (
ctypes.c_void_p, ctypes.c_void_p,
@@ -110,16 +95,13 @@ class ConflictSet:
ctypes.c_int, ctypes.c_int,
ctypes.c_int64, ctypes.c_int64,
) )
self._lib.ConflictSet_addWrites.restype = None
self._lib.ConflictSet_setOldestVersion.argtypes = ( self._lib.ConflictSet_setOldestVersion.argtypes = (
ctypes.c_void_p, ctypes.c_void_p,
ctypes.c_int64, ctypes.c_int64,
) )
self._lib.ConflictSet_setOldestVersion.restype = None
self._lib.ConflictSet_destroy.argtypes = (ctypes.c_void_p,) self._lib.ConflictSet_destroy.argtypes = (ctypes.c_void_p,)
self._lib.ConflictSet_destroy.restype = None
self._lib.ConflictSet_getBytes.argtypes = (ctypes.c_void_p,) self._lib.ConflictSet_getBytes.argtypes = (ctypes.c_void_p,)
self._lib.ConflictSet_getBytes.restype = ctypes.c_int64 self._lib.ConflictSet_getBytes.restype = ctypes.c_int64
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More