├── .editorconfig ├── .gitignore ├── .gitlab-ci.yml ├── .gitmodules ├── .ignore ├── CHANGELOG.md ├── CMakeLists.txt ├── LICENSE ├── README.md ├── book.json ├── ci ├── c8 │ ├── Dockerfile │ └── prepare.sh ├── canonical-rocksdb-path.sh ├── cc7 │ ├── Dockerfile │ └── prepare.sh ├── fedora │ ├── Dockerfile │ └── prepare.sh ├── install-rocksdb.sh ├── rocksdb-cmake.sh └── ubuntu │ ├── Dockerfile │ ├── asan.sh │ ├── build-xrootd.sh │ ├── packages.sh │ └── prepare.sh ├── cmake ├── FindRocksDB.cmake ├── FindXRootD.cmake ├── Finduuid.cmake ├── GNUInstallDirs.cmake └── buildRocksDB.cmake ├── deps ├── CLI11.hpp ├── StringMatchLen.h └── xxhash │ ├── xxhash.cc │ └── xxhash.hh ├── docs ├── docs │ ├── authentication.md │ ├── backup.md │ ├── bulkload.md │ ├── checklist.md │ ├── configuration.md │ ├── disk-space.md │ ├── failure-scenarios.md │ ├── fsync.md │ ├── index.md │ ├── installation.md │ ├── journal-trimming.md │ ├── membership.md │ ├── raft-extensions.md │ ├── raft.md │ ├── ref │ │ ├── auth.md │ │ ├── hash │ │ │ ├── hexists.md │ │ │ ├── hget.md │ │ │ ├── hgetall.md │ │ │ ├── hkeys.md │ │ │ ├── hmset.md │ │ │ └── hset.md │ │ ├── hmac-signing-challenges.md │ │ └── string │ │ │ ├── get.md │ │ │ └── set.md │ ├── release-notes.md │ ├── resilvering.md │ ├── troubleshooting.md │ ├── upgrading.md │ └── write-path.md └── mkdocs.yml ├── genversion.py ├── packaging ├── gitlab-build.sh ├── make-dist.sh ├── make-srpm.sh ├── quarkdb.spec.in ├── replace-directory.sh └── repo-manager.py ├── src ├── BufferedReader.cc ├── BufferedReader.hh ├── BufferedWriter.cc ├── BufferedWriter.hh ├── CMakeLists.txt ├── Commands.cc ├── Commands.hh ├── Common.hh ├── Configuration.cc ├── Configuration.hh ├── Connection.cc ├── Connection.hh ├── Dispatcher.cc ├── Dispatcher.hh ├── EventFD.hh ├── Formatter.cc ├── Formatter.hh ├── Link.cc ├── Link.hh ├── QuarkDBNode.cc ├── QuarkDBNode.hh ├── RedisParser.cc ├── RedisParser.hh ├── RedisRequest.cc ├── RedisRequest.hh ├── Shard.cc ├── Shard.hh ├── ShardDirectory.cc ├── ShardDirectory.hh ├── StandaloneGroup.cc ├── StandaloneGroup.hh ├── StateMachine.cc ├── StateMachine.hh ├── Status.hh ├── Timekeeper.cc ├── Timekeeper.hh ├── Utils.cc ├── Utils.hh ├── Version.hh.in ├── XrdPlugin.cc ├── XrdQuarkDB.cc ├── XrdQuarkDB.hh ├── auth │ ├── AuthenticationDispatcher.cc │ └── AuthenticationDispatcher.hh ├── config │ ├── ConfigurationReader.cc │ └── ConfigurationReader.hh ├── health │ └── HealthIndicator.hh ├── memory │ ├── PinnedBuffer.hh │ └── RingAllocator.hh ├── netio │ ├── AsioPoller.cc │ └── AsioPoller.hh ├── pubsub │ ├── Publisher.cc │ ├── Publisher.hh │ ├── SimplePatternMatcher.hh │ ├── SubscriptionTracker.cc │ ├── SubscriptionTracker.hh │ └── ThreadSafeMultiMap.hh ├── raft │ ├── RaftBlockedWrites.cc │ ├── RaftBlockedWrites.hh │ ├── RaftCommitTracker.cc │ ├── RaftCommitTracker.hh │ ├── RaftCommon.hh │ ├── RaftConfig.cc │ ├── RaftConfig.hh │ ├── RaftContactDetails.hh │ ├── RaftDirector.cc │ ├── RaftDirector.hh │ ├── RaftDispatcher.cc │ ├── RaftDispatcher.hh │ ├── RaftGroup.cc │ ├── RaftGroup.hh │ ├── RaftJournal.cc │ ├── RaftJournal.hh │ ├── RaftLease.cc │ ├── RaftLease.hh │ ├── RaftMembers.hh │ ├── RaftReplicator.cc │ ├── RaftReplicator.hh │ ├── RaftResilverer.cc │ ├── RaftResilverer.hh │ ├── RaftState.cc │ ├── RaftState.hh │ ├── RaftTalker.cc │ ├── RaftTalker.hh │ ├── RaftTimeouts.cc │ ├── RaftTimeouts.hh │ ├── RaftTrimmer.cc │ ├── RaftTrimmer.hh │ ├── RaftUtils.cc │ ├── RaftUtils.hh │ ├── RaftVoteRegistry.cc │ ├── RaftVoteRegistry.hh │ ├── RaftWriteTracker.cc │ └── RaftWriteTracker.hh ├── recovery │ ├── RecoveryDispatcher.cc │ ├── RecoveryDispatcher.hh │ ├── RecoveryEditor.cc │ ├── RecoveryEditor.hh │ ├── RecoveryRunner.cc │ └── RecoveryRunner.hh ├── redis │ ├── ArrayResponseBuilder.cc │ ├── ArrayResponseBuilder.hh │ ├── Authenticator.cc │ ├── Authenticator.hh │ ├── CommandMonitor.cc │ ├── CommandMonitor.hh │ ├── InternalFilter.cc │ ├── InternalFilter.hh │ ├── LeaseFilter.cc │ ├── LeaseFilter.hh │ ├── MultiHandler.cc │ ├── MultiHandler.hh │ ├── RedisEncodedResponse.hh │ ├── Transaction.cc │ └── Transaction.hh ├── storage │ ├── ConsistencyScanner.cc │ ├── ConsistencyScanner.hh │ ├── ExpirationEventCache.cc │ ├── ExpirationEventCache.hh │ ├── ExpirationEventIterator.cc │ ├── ExpirationEventIterator.hh │ ├── InternalKeyParsing.cc │ ├── InternalKeyParsing.hh │ ├── KeyConstants.cc │ ├── KeyConstants.hh │ ├── KeyDescriptor.hh │ ├── KeyDescriptorBuilder.cc │ ├── KeyDescriptorBuilder.hh │ ├── KeyLocators.hh │ ├── LeaseInfo.hh │ ├── ParanoidManifestChecker.cc │ ├── ParanoidManifestChecker.hh │ ├── PatternMatching.hh │ ├── Randomization.cc │ ├── Randomization.hh │ ├── ReverseLocator.hh │ ├── StagingArea.hh │ ├── VersionedHashRevisionTracker.cc │ ├── VersionedHashRevisionTracker.hh │ ├── WriteStallWarner.cc │ └── WriteStallWarner.hh └── utils │ ├── AssistedThread.hh │ ├── ClockWrapper.hh │ ├── CommandParsing.hh │ ├── CoreLocalArray.hh │ ├── DirectoryIterator.cc │ ├── DirectoryIterator.hh │ ├── FileUtils.cc │ ├── FileUtils.hh │ ├── FsyncThread.cc │ ├── FsyncThread.hh │ ├── InFlightTracker.hh │ ├── IntToBinaryString.hh │ ├── Macros.hh │ ├── ParseUtils.hh │ ├── Random.cc │ ├── Random.hh │ ├── RequestCounter.cc │ ├── RequestCounter.hh │ ├── Resilvering.cc │ ├── Resilvering.hh │ ├── ScopedAdder.hh │ ├── SmartBuffer.hh │ ├── Stacktrace.hh │ ├── StaticBuffer.hh │ ├── Statistics.cc │ ├── Statistics.hh │ ├── StringUtils.cc │ ├── StringUtils.hh │ ├── Synchronized.hh │ ├── TimeFormatting.cc │ ├── TimeFormatting.hh │ ├── Uuid.hh │ └── VectorUtils.hh ├── test ├── CMakeLists.txt ├── auth.cc ├── bench-malloc │ ├── interceptor.cc │ ├── interceptor.hh │ ├── main.cc │ └── measure.cc ├── bench │ ├── bench-utils.hh │ ├── hset.cc │ └── main.cc ├── buffered-reader.cc ├── clock-wrapper.cc ├── config │ ├── test-config.cc │ └── test-config.hh ├── configuration.cc ├── connection.cc ├── dispatcher.cc ├── e2e.cc ├── formatter.cc ├── health.cc ├── link.cc ├── main.cc ├── multi.cc ├── poller.cc ├── qclient.cc ├── raft-journal.cc ├── raft-lease.cc ├── raft-parser.cc ├── raft-state.cc ├── raft-talker.cc ├── raft.cc ├── recovery.cc ├── redis-parser.cc ├── state-machine.cc ├── stress │ ├── background-flusher.cc │ ├── bulkload.cc │ ├── main.cc │ ├── misc.cc │ ├── qclient.cc │ ├── replication.cc │ ├── resilvering.cc │ └── timekeeper.cc ├── sudo │ ├── main.cc │ ├── poweroff.cc │ └── qclient.cc ├── test-reply-macros.hh ├── test-utils.cc ├── test-utils.hh └── utils.cc ├── tools ├── CMakeLists.txt ├── TestUtils.hh ├── quarkdb-create.cc ├── quarkdb-ldb.cc ├── quarkdb-recovery.cc ├── quarkdb-server.cc ├── quarkdb-sst-inspect.cc └── quarkdb-validate-checkpoint.cc └── utils ├── el7-packages.sh ├── tsan-suppressions.txt └── ubuntu-asan.sh /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # all files 7 | [*] 8 | end_of_line = lf 9 | charset = utf-8 10 | insert_final_newline = true 11 | trim_trailing_whitespace = true 12 | indent_style = space 13 | indent_size = 2 14 | 15 | # python 16 | [*.py] 17 | indent_size = 4 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | src/Version.hh 2 | packaging/quarkdb.spec 3 | _book/ 4 | .vscode 5 | *.sublime-project 6 | *.sublime-workspace 7 | docs/site 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "deps/googletest"] 2 | path = deps/googletest 3 | url = https://github.com/google/googletest 4 | [submodule "deps/backward-cpp"] 5 | path = deps/backward-cpp 6 | url = https://github.com/bombela/backward-cpp 7 | [submodule "deps/rocksdb"] 8 | path = deps/rocksdb 9 | url = https://github.com/facebook/rocksdb 10 | [submodule "deps/qclient"] 11 | path = deps/qclient 12 | url = https://gitlab.cern.ch/eos/qclient.git 13 | [submodule "deps/asio"] 14 | path = deps/asio 15 | url = https://github.com/chriskohlhoff/asio 16 | [submodule "deps/mkdocs-material"] 17 | path = deps/mkdocs-material 18 | url = https://github.com/squidfunk/mkdocs-material.git 19 | -------------------------------------------------------------------------------- /.ignore: -------------------------------------------------------------------------------- 1 | build/ 2 | deps/rocksdb/ 3 | deps/backward-cpp/ 4 | deps/googletest/ 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QuarkDB 2 | 3 | [![build status](https://gitlab.cern.ch/eos/quarkdb/badges/master/pipeline.svg)](https://gitlab.cern.ch/eos/quarkdb/commits/master) 4 | [![coverage report](https://gitlab.cern.ch/eos/quarkdb/badges/master/coverage.svg)](https://quarkdb.web.cern.ch/quarkdb/coverage/master/) 5 | 6 | [QuarkDB](https://gitlab.cern.ch/eos/quarkdb) is a highly available datastore that implements a small subset 7 | of the redis command set, developed by IT-ST at CERN. 8 | 9 | # Demo 10 | 11 | Watch this [quick demo](https://asciinema.org/a/NdX791Ah4JVkGQnUQkBVm3dDJ) to see QuarkDB in action. 12 | 13 | # Documentation 14 | 15 | Visit [this page](https://quarkdb.web.cern.ch/quarkdb/docs/master/) for the latest documentation, tracking the master branch. If you need documentation generated by some other branch or tag, have a look [here](https://quarkdb.web.cern.ch/quarkdb/docs/). 16 | -------------------------------------------------------------------------------- /book.json: -------------------------------------------------------------------------------- 1 | { 2 | "root" : "docs", 3 | "title" : "quarkdb documentation" 4 | } 5 | -------------------------------------------------------------------------------- /ci/c8/Dockerfile: -------------------------------------------------------------------------------- 1 | # A C8 image + build dependencies of quarkdb. 2 | # Significantly improves CI build time, since all packages 3 | # are already there. 4 | 5 | FROM gitlab-registry.cern.ch/linuxsupport/c8-base:latest 6 | MAINTAINER Georgios Bitzes, georgios.bitzes@cern.ch, CERN 2020 7 | 8 | RUN dnf clean all 9 | RUN dnf remove -y whois-mkpasswd || true 10 | RUN dnf install -y expect git 11 | RUN dnf install -y https://kojipkgs.fedoraproject.org//packages/zstd/1.4.4/1.el8/x86_64/libzstd-1.4.4-1.el8.x86_64.rpm https://kojipkgs.fedoraproject.org//packages/zstd/1.4.4/1.el8/x86_64/libzstd-devel-1.4.4-1.el8.x86_64.rpm 12 | RUN git clone https://gitlab.cern.ch/eos/quarkdb.git; cd quarkdb; ci/c8/prepare.sh; cd ..; rm -rf quarkdb 13 | -------------------------------------------------------------------------------- /ci/c8/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | ##------------------------------------------------------------------------------ 5 | ## Bootstrap packages - needed to run 'builddep' on quarkdb for the next 6 | ## step. 7 | ##------------------------------------------------------------------------------ 8 | 9 | dnf install -y expect gcc-c++ cmake3 make rpm-build which git yum-utils libtsan dnf-plugins-core python3 epel-release 10 | 11 | ##------------------------------------------------------------------------------ 12 | ## Extract quarkdb build dependencies from its specfile. 13 | ##------------------------------------------------------------------------------ 14 | 15 | ./packaging/make-srpm.sh 16 | dnf builddep -y build/SRPMS/* 17 | 18 | ##------------------------------------------------------------------------------ 19 | ## Install rocksdb 20 | ##------------------------------------------------------------------------------ 21 | ci/install-rocksdb.sh 22 | -------------------------------------------------------------------------------- /ci/canonical-rocksdb-path.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | # Detect if we're using ThreadSanitizer 5 | if [[ "${CXXFLAGS}" == *"-fsanitize=thread"* ]]; then 6 | TSAN_IF_ENABLED="-tsan" 7 | fi 8 | 9 | # Discover rocksdb commit hash 10 | ROCKSDB_COMMIT=$(git --git-dir deps/rocksdb/.git rev-parse HEAD) 11 | 12 | # Emit the system-wide path for this rocksdb commit 13 | printf "/rocksdb/${ROCKSDB_COMMIT}${TSAN_IF_ENABLED}" 14 | -------------------------------------------------------------------------------- /ci/cc7/Dockerfile: -------------------------------------------------------------------------------- 1 | # A cc7-base image + build dependencies of quarkdb. 2 | # Significantly improves CI build time, since all packages 3 | # are already there. 4 | 5 | FROM gitlab-registry.cern.ch/linuxsupport/cc7-base:latest 6 | MAINTAINER Georgios Bitzes, georgios.bitzes@cern.ch, CERN 2018 7 | 8 | RUN yum clean all 9 | RUN yum install -y git 10 | RUN git clone https://gitlab.cern.ch/eos/quarkdb.git; cd quarkdb; ci/cc7/prepare.sh; cd ..; rm -rf quarkdb 11 | -------------------------------------------------------------------------------- /ci/cc7/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | ##------------------------------------------------------------------------------ 5 | ## Bootstrap packages - needed to run 'builddep' on quarkdb for the next 6 | ## step. 7 | ##------------------------------------------------------------------------------ 8 | 9 | yum install -y gcc-c++ cmake3 make rpm-build which git yum-plugin-priorities yum-utils python3 10 | 11 | ##------------------------------------------------------------------------------ 12 | ## Extract quarkdb build dependencies from its specfile. 13 | ##------------------------------------------------------------------------------ 14 | 15 | ./packaging/make-srpm.sh 16 | yum-builddep -y build/SRPMS/* 17 | 18 | ##------------------------------------------------------------------------------ 19 | ## Misc packages, needed for the publishing step. 20 | ##------------------------------------------------------------------------------ 21 | 22 | yum install -y sssd-client sudo createrepo http-parser http-parser-devel npm 23 | 24 | ##------------------------------------------------------------------------------ 25 | ## Install gitbook, needed for publishing docs. 26 | ##------------------------------------------------------------------------------ 27 | 28 | pushd ~/ 29 | npm install -g gitbook-cli 30 | npm install gitbook 31 | popd 32 | gitbook build # Gitbook will install more stuff during its first execution 33 | 34 | ##------------------------------------------------------------------------------ 35 | ## Install rocksdb 36 | ##------------------------------------------------------------------------------ 37 | 38 | scl enable devtoolset-8 "ci/install-rocksdb.sh" 39 | -------------------------------------------------------------------------------- /ci/fedora/Dockerfile: -------------------------------------------------------------------------------- 1 | # A fedora image + build dependencies of quarkdb. 2 | # Significantly improves CI build time, since all packages 3 | # are already there. 4 | 5 | FROM fedora:29 6 | MAINTAINER Georgios Bitzes, georgios.bitzes@cern.ch, CERN 2019 7 | 8 | RUN dnf clean all 9 | RUN dnf remove -y whois-mkpasswd || true 10 | RUN dnf install -y expect git 11 | RUN git clone https://gitlab.cern.ch/eos/quarkdb.git; cd quarkdb; ci/fedora/prepare.sh; cd ..; rm -rf quarkdb 12 | -------------------------------------------------------------------------------- /ci/fedora/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | ##------------------------------------------------------------------------------ 5 | ## Bootstrap packages - needed to run 'builddep' on quarkdb for the next 6 | ## step. 7 | ##------------------------------------------------------------------------------ 8 | 9 | dnf install -y expect gcc-c++ cmake3 make rpm-build which git yum-plugin-priorities yum-utils libtsan dnf-plugins-core 10 | 11 | ##------------------------------------------------------------------------------ 12 | ## Extract quarkdb build dependencies from its specfile. 13 | ##------------------------------------------------------------------------------ 14 | 15 | ./packaging/make-srpm.sh 16 | dnf builddep -y build/SRPMS/* 17 | 18 | ##------------------------------------------------------------------------------ 19 | ## Install rocksdb, both with and without tsan 20 | ##------------------------------------------------------------------------------ 21 | 22 | ci/install-rocksdb.sh 23 | CXXFLAGS='-fsanitize=thread' ci/install-rocksdb.sh 24 | -------------------------------------------------------------------------------- /ci/install-rocksdb.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | # Install RocksDB into the build image, so we don't have to 5 | # re-compile it again and again for each commit. 6 | 7 | # Check: Does the cache directory exist already, and is not empty? 8 | # If so, assume it contains a cached rocksdb build already, and skip. 9 | git submodule update --init --recursive 10 | ROCKSDB_PATH=$(ci/canonical-rocksdb-path.sh) 11 | 12 | if [ "$(ls -A $ROCKSDB_PATH)" ]; then 13 | printf "$ROCKSDB_PATH not empty: assuming rocksdb has been installed already there.\n" 14 | exit 0 15 | fi 16 | 17 | # Make the directory as the first thing, so as to fail fast 18 | mkdir -p $ROCKSDB_PATH 19 | 20 | # Find available cmake command 21 | CMAKE="cmake3" 22 | if ! which $CMAKE; then 23 | CMAKE="cmake" 24 | fi 25 | 26 | # Build RocksDB using the same command that would be used if 27 | # there was no caching. 28 | rm -rf build 29 | mkdir build && cd build 30 | $CMAKE .. -DPACKAGEONLY=1 -DBUILD_ROCKSDB=1 31 | make BuildRocksDB 32 | 33 | # Copy necessary files. 34 | cp deps/rocksdb/src/BuildRocksDB/librocksdb.a $ROCKSDB_PATH/ 35 | cp -r deps/rocksdb/src/BuildRocksDB/include $ROCKSDB_PATH/ 36 | -------------------------------------------------------------------------------- /ci/rocksdb-cmake.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ROCKSDB_PATH=$(ci/canonical-rocksdb-path.sh) 4 | 5 | if [[ "$?" != "0" ]]; then 6 | exit 0 7 | fi 8 | 9 | CONTENTS=$(ls -A "$ROCKSDB_PATH" &> /dev/null) 10 | if [[ "$?" != "0" ]]; then 11 | exit 0 12 | fi 13 | 14 | printf "%s%s" "-DROCKSDB_ROOT_DIR=" "$ROCKSDB_PATH" 15 | -------------------------------------------------------------------------------- /ci/ubuntu/Dockerfile: -------------------------------------------------------------------------------- 1 | # An ubuntu image + build dependencies of quarkdb + precompiled xrootd. 2 | # Used to improve CI build time. 3 | 4 | FROM ubuntu:20.04 5 | MAINTAINER Georgios Bitzes, georgios.bitzes@cern.ch, CERN 2018 6 | 7 | RUN apt-get update; apt-get install -y git 8 | RUN git clone https://gitlab.cern.ch/eos/quarkdb.git; cd quarkdb; ci/ubuntu/prepare.sh; cd ..; rm -rf quarkdb 9 | -------------------------------------------------------------------------------- /ci/ubuntu/asan.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | # This step ought to be a no-op usually, thanks to our custom ubuntu image. 5 | ci/ubuntu/prepare.sh 6 | 7 | # Build QuarkDB with AddressSanitizer 8 | git submodule update --init --recursive 9 | rm -rf build 10 | mkdir build && cd build 11 | CXXFLAGS='-fsanitize=address' cmake -DTESTCOVERAGE=ON -DXROOTD_ROOT_DIR=/xrootd/install -DLIBRARY_PATH_PREFIX=lib .. 12 | make 13 | 14 | export ASAN_OPTIONS='detect_leaks=0' 15 | QDB_TEST_TIMEOUT=default ./test/quarkdb-tests 16 | ./test/quarkdb-stress-tests 17 | make coverage-report 18 | -------------------------------------------------------------------------------- /ci/ubuntu/build-xrootd.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | # Usage: build-xrootd.sh 5 | # xrootd will then be installed into /install 6 | 7 | # If path exists, we assume the contents have been 8 | # cached already, and we quit. 9 | 10 | if [[ "$#" != 1 || "$1" == "" ]]; then 11 | printf "Usage: build-xrootd.sh \n" 12 | exit 1 13 | fi 14 | 15 | BASE_PATH="$1" 16 | 17 | if [ "$(ls -A $BASE_PATH)" ]; then 18 | printf "$BASE_PATH not empty: assuming xrootd has been installed already there.\n" 19 | exit 0 20 | fi 21 | 22 | mkdir -p $BASE_PATH 23 | cd $BASE_PATH 24 | git clone https://github.com/xrootd/xrootd 25 | cd xrootd 26 | git checkout v4.12.0 27 | mkdir build 28 | cd build 29 | cmake .. -DCMAKE_INSTALL_PREFIX="$BASE_PATH/install" 30 | make 31 | make install 32 | -------------------------------------------------------------------------------- /ci/ubuntu/packages.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -ex 3 | 4 | export TZ=Europe/Zurich 5 | export DEBIAN_FRONTEND=noninteractive 6 | 7 | apt-get install -y git g++ cmake zlib1g-dev openssl libssl-dev python python3 libbz2-dev lcov uuid-dev libjemalloc-dev libdw-dev libdw1 liblz4-dev libzstd-dev 8 | -------------------------------------------------------------------------------- /ci/ubuntu/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ci/ubuntu/packages.sh 4 | ci/ubuntu/build-xrootd.sh /xrootd 5 | ci/install-rocksdb.sh 6 | 7 | -------------------------------------------------------------------------------- /cmake/FindRocksDB.cmake: -------------------------------------------------------------------------------- 1 | # Try to find rocksdb 2 | # Once done, this will define 3 | # 4 | # ROCKSDB_FOUND - system has rocksdb 5 | # ROCKSDB_INCLUDE_DIRS - rocksdb include directories 6 | # ROCKSDB_LIBRARY - rocksdb library 7 | # 8 | # ROCKSDB_ROOT_DIR may be defined as a hint for where to look 9 | 10 | include(FindPackageHandleStandardArgs) 11 | 12 | if(ROCKSDB_INCLUDE_DIRS AND ROCKSDB_LIBRARY) 13 | set(ROCKSDB_FIND_QUIETLY TRUE) 14 | else() 15 | find_path( 16 | ROCKSDB_INCLUDE_DIRS 17 | NAMES rocksdb/version.h 18 | HINTS ${ROCKSDB_ROOT_DIR} 19 | PATH_SUFFIXES include 20 | NO_DEFAULT_PATH) 21 | 22 | find_library( 23 | ROCKSDB_LIBRARY 24 | NAMES librocksdb.a 25 | HINTS ${ROCKSDB_ROOT_DIR} 26 | NO_DEFAULT_PATH) 27 | 28 | endif() 29 | 30 | find_package_handle_standard_args( 31 | rocksdb 32 | DEFAULT_MSG 33 | ROCKSDB_LIBRARY 34 | ROCKSDB_INCLUDE_DIRS) 35 | 36 | if(ROCKSDB_FOUND) 37 | add_library(rocksdb STATIC IMPORTED) 38 | set_property(TARGET rocksdb PROPERTY IMPORTED_LOCATION ${ROCKSDB_LIBRARY}) 39 | endif() 40 | -------------------------------------------------------------------------------- /cmake/FindXRootD.cmake: -------------------------------------------------------------------------------- 1 | # Try to find XROOTD 2 | # Once done, this will define 3 | # 4 | # XROOTD_FOUND - system has XRootD 5 | # XROOTD_INCLUDE_DIR - XRootD include directories 6 | # XROOTD_LIB_DIR - libraries needed to use XRootD 7 | # XROOTD_PRIVATE_INCLUDE_DIR - XRootD private include directory 8 | # 9 | # XROOTD_DIR may be defined as a hint for where to look 10 | 11 | include(FindPackageHandleStandardArgs) 12 | 13 | if(XROOTD_INCLUDE_DIRS AND XROOTD_LIBRARIES) 14 | set(XROOTD_FIND_QUIETLY TRUE) 15 | else() 16 | find_path( 17 | XROOTD_INCLUDE_DIR 18 | NAMES XrdVersion.hh 19 | HINTS ${XROOTD_ROOT_DIR} $ENV{XROOTD_ROOT_DIR} 20 | PATH_SUFFIXES include/xrootd) 21 | 22 | find_path( 23 | XROOTD_PRIVATE_INCLUDE_DIR 24 | NAMES XrdOss/XrdOssApi.hh 25 | HINTS ${XROOTD_ROOT_DIR} $ENV{XROOTD_ROOT_DIR} 26 | PATH_SUFFIXES include/xrootd/private) 27 | 28 | find_library( 29 | XROOTD_UTILS_LIBRARY 30 | NAMES XrdUtils 31 | HINTS ${XROOTD_ROOT_DIR} $ENV{XROOTD_ROOT_DIR} 32 | PATH_SUFFIXES ${LIBRARY_PATH_PREFIX}) 33 | 34 | find_library( 35 | XROOTD_SERVER_LIBRARY 36 | NAMES XrdServer 37 | HINTS ${XROOTD_ROOT_DIR} $ENV{XROOTD_ROOT_DIR} 38 | PATH_SUFFIXES ${LIBRARY_PATH_PREFIX}) 39 | 40 | find_library( 41 | XROOTD_CL_LIBRARY 42 | NAMES XrdCl 43 | HINTS ${XROOTD_ROOT_DIR} $ENV{XROOTD_ROOT_DIR} 44 | PATH_SUFFIXES ${LIBRARY_PATH_PREFIX}) 45 | 46 | find_library( 47 | XROOTD_POSIX_LIBRARY 48 | NAMES XrdPosix 49 | HINTS ${XROOTD_ROOT_DIR} $ENV{XROOTD_ROOT_DIR} 50 | PATH_SUFFIXES ${LIBRARY_PATH_PREFIX}) 51 | 52 | set(XROOTD_INCLUDE_DIRS ${XROOTD_INCLUDE_DIR} ${XROOTD_PRIVATE_INCLUDE_DIR}) 53 | 54 | set( 55 | XROOTD_LIBRARIES 56 | ${XROOTD_SERVER_LIBRARY} 57 | ${XROOTD_CL_LIBRARY} 58 | ${XROOTD_UTILS_LIBRARY} 59 | ${XROOTD_POSIX_LIBRARY}) 60 | 61 | find_package_handle_standard_args( 62 | XRootD 63 | DEFAULT_MSG 64 | XROOTD_SERVER_LIBRARY 65 | XROOTD_UTILS_LIBRARY 66 | XROOTD_CL_LIBRARY 67 | XROOTD_INCLUDE_DIR 68 | XROOTD_PRIVATE_INCLUDE_DIR) 69 | 70 | mark_as_advanced( 71 | XROOTD_SERVER_LIBRARY 72 | XROOTD_UTILS_LIBRARY 73 | XROOTD_CL_LIBRARY 74 | XROOTD_INCLUDE_DIR 75 | XROOTD_PRIVATE_INCLUDE_DIR) 76 | endif() 77 | -------------------------------------------------------------------------------- /cmake/Finduuid.cmake: -------------------------------------------------------------------------------- 1 | # Try to find uuid 2 | # Once done, this will define 3 | # 4 | # UUID_FOUND - system has uuid 5 | # UUID_INCLUDE_DIRS - uuid include directories 6 | # UUID_LIBRARIES - libraries needed to use uuid 7 | 8 | include(FindPackageHandleStandardArgs) 9 | 10 | if(UUID_INCLUDE_DIRS AND UUID_LIBRARIES) 11 | set(UUID_FIND_QUIETLY TRUE) 12 | else() 13 | find_path( 14 | UUID_INCLUDE_DIR 15 | NAMES uuid.h 16 | HINTS ${UUID_ROOT_DIR} 17 | PATH_SUFFIXES include uuid) 18 | 19 | find_library( 20 | UUID_LIBRARY 21 | NAMES uuid 22 | HINTS ${UUID_ROOT_DIR} 23 | PATH_SUFFIXES ${LIBRARY_PATH_PREFIX}) 24 | 25 | set(UUID_INCLUDE_DIRS ${UUID_INCLUDE_DIR}) 26 | set(UUID_LIBRARIES ${UUID_LIBRARY}) 27 | 28 | find_package_handle_standard_args( 29 | uuid DEFAULT_MSG UUID_LIBRARY UUID_INCLUDE_DIR) 30 | 31 | mark_as_advanced(UUID_INCLUDE_DIR UUID_LIBRARY) 32 | endif() 33 | -------------------------------------------------------------------------------- /cmake/buildRocksDB.cmake: -------------------------------------------------------------------------------- 1 | macro(buildRocksDB) 2 | include(ExternalProject) 3 | include(CheckCXXCompilerFlag) 4 | 5 | check_cxx_compiler_flag(-Wno-error=deprecated-copy COMPILER_WARNS_DEPRECATED_COPY) 6 | check_cxx_compiler_flag(-Wno-error=pessimizing-move COMPILER_WARNS_PESSIMIZING_MOVE) 7 | 8 | set(EXTRA_OPTIONS " ") 9 | 10 | if(COMPILER_WARNS_DEPRECATED_COPY) 11 | set(EXTRA_OPTIONS " ${EXTRA_OPTIONS} -Wno-error=deprecated-copy") 12 | endif() 13 | 14 | if(COMPILER_WARNS_PESSIMIZING_MOVE) 15 | set(EXTRA_OPTIONS " ${EXTRA_OPTIONS} -Wno-error=pessimizing-move") 16 | endif() 17 | 18 | ExternalProject_Add(BuildRocksDB 19 | URL "${CMAKE_SOURCE_DIR}/deps/rocksdb" 20 | PREFIX "${CMAKE_BINARY_DIR}/deps/rocksdb" 21 | CONFIGURE_COMMAND "" 22 | BUILD_IN_SOURCE 1 23 | BUILD_COMMAND bash -c "export PORTABLE=1 && export DISABLE_JEMALLOC=1 && export OPT='-fPIC -DNDEBUG -O3 ${EXTRA_OPTIONS} ' && export USE_RTTI=1 && make static_lib -j $(cat /proc/cpuinfo | grep 'processor' | wc -l)" 24 | INSTALL_COMMAND "" 25 | ) 26 | 27 | ExternalProject_Get_Property(BuildRocksDB source_dir) 28 | set(ROCKSDB_INCLUDE_DIRS ${source_dir}/include) 29 | ExternalProject_Get_Property(BuildRocksDB binary_dir) 30 | 31 | add_library(rocksdb STATIC IMPORTED) 32 | set_property(TARGET rocksdb PROPERTY IMPORTED_LOCATION ${binary_dir}/librocksdb.a) 33 | add_dependencies(rocksdb BuildRocksDB) 34 | endmacro() 35 | -------------------------------------------------------------------------------- /docs/docs/authentication.md: -------------------------------------------------------------------------------- 1 | # Password authentication 2 | 3 | ## Configuration 4 | 5 | Three configuration options control password authentication in QuarkDB. Please note that 6 | passwords need to contain a minimum of 32 characters. 7 | 8 | * __redis.password__: Ensures that clients need to prove they know this password 9 | in order to be able to connect. This includes other QuarkDB nodes: All QuarkDB 10 | nodes part of the same cluster must be configured with the same password, 11 | otherwise they won't be able to communicate. 12 | 13 | * __redis.password_file__: An alternative to the above, except the password is 14 | read from the specified file -- permissions must be `400` (`r-----`). Note that, any whitespace at the end of the password file contents is completely ignored, including the ending new-line, if any. 15 | 16 | This means, the three following password files will, in fact, give identical 17 | passwords: 18 | 19 | ``` 20 | $ cat file1 21 | pickles\n\n 22 | ``` 23 | 24 | ``` 25 | $ cat file2 26 | pickles\r\n 27 | ``` 28 | 29 | ``` 30 | $ cat file3 31 | pickles 32 | ``` 33 | 34 | This is to simplify the common case of just having a single line in the 35 | passwordfile, without having to worry about newlines and whitespace 36 | at the end, and being able to easily copy paste the password to a `redis-cli` 37 | terminal. 38 | 39 | * __redis.require_password_for_localhost__: By default, the requirement for 40 | password authentication is lifted for localhost clients. Set this option to 41 | true to require authentication at all times. 42 | 43 | ## Usage 44 | 45 | An unauthenticated client will receive an error message for all issued commands: 46 | 47 | ``` 48 | some-host:7777> set mykey myvalue 49 | (error) NOAUTH Authentication required. 50 | ``` 51 | 52 | Two ways exist for a client to prove they know the password - by simply sending 53 | the password over the wire, like official redis does, or a signing challenge. 54 | 55 | ### AUTH 56 | 57 | Simply send the password over the wire towards the server, just like in official redis: 58 | 59 | ``` 60 | some-host:7777> auth some-password 61 | OK 62 | ``` 63 | 64 | ### Signing challenge 65 | 66 | This method of authentication is only viable from scripts, not interactively. 67 | It avoids sending the password over plaintext. 68 | 69 | * The client asks the server to generate a signing challenge, providing 64 random 70 | bytes: 71 | 72 | ``` 73 | eoshome-i01:7777> HMAC-AUTH-GENERATE-CHALLENGE <... 64 random bytes ...> 74 | "<... long string to sign...>" 75 | ``` 76 | 77 | * The client then signs the server-provided string using HMAC EVP sha256 and 78 | the password it knows about: 79 | 80 | ``` 81 | eoshome-i01:7777> HMAC-AUTH-VALIDATE-CHALLENGE <... hmac signature ...> 82 | OK 83 | ``` 84 | 85 | * The server validates the signature, and if the signatures match, lets the 86 | client through. 87 | -------------------------------------------------------------------------------- /docs/docs/bulkload.md: -------------------------------------------------------------------------------- 1 | # Bulkload mode 2 | 3 | We support a special mode during which writes are sped up significantly, 4 | at the cost of disallowing reads. Preventing reads enables several optimizations, 5 | such as not having to maintain in-memory structures which enable fast key lookups. 6 | 7 | Bulkload mode is available _only_ for newly created instances. If you try to 8 | open in bulkload an instance which contains data already (either standalone 9 | _or_ raft instance), the server will refuse to start. 10 | 11 | ## Starting a node in bulkload mode 12 | 13 | 1. Use quarkdb-create to make the database directory, specifying only the path. 14 | 15 | ``` 16 | quarkdb-create --path /var/lib/quarkdb/bulkload 17 | ``` 18 | 19 | 2. Start the QuarkDB process, specify `bulkload` as the mode in the configuration: 20 | 21 | ``` 22 | xrd.port 4444 23 | xrd.protocol redis:4444 libXrdQuarkDB.so 24 | redis.mode bulkload 25 | redis.database /var/lib/quarkdb/bulkload 26 | ``` 27 | 28 | 3. Here are some example commands ran towards a bulkload node: 29 | 30 | ``` 31 | 127.0.0.1:4444> quarkdb-info 32 | 1) MODE BULKLOAD 33 | 2) BASE-DIRECTORY /var/lib/quarkdb/bulkload 34 | 3) QUARKDB-VERSION 0.3.7 35 | 4) ROCKSDB-VERSION 5.18.3 36 | 5) MONITORS 0 37 | 6) BOOT-TIME 0 (0 seconds) 38 | 7) UPTIME 18 (18 seconds) 39 | 127.0.0.1:4444> set test 123 40 | OK 41 | 127.0.0.1:4444> get test 42 | (nil) 43 | ``` 44 | 45 | Note how attempting to read just-written values results in an empty string: All 46 | reads during bulkload will receive empty values. 47 | 48 | 4. Now you are free to load QuarkDB with any data you wish. 49 | 50 | ## Finalizing bulkload 51 | 52 | Once your data is written, how to turn this into a fully functioning raft cluster, 53 | with reads enabled and replication? 54 | 55 | 1. Run ``quarkdb-bulkload-finalize`` - this needs to be the last command ran 56 | on the node, more writes are disallowed from this point on. Let the command 57 | run, which may take a while. 58 | 59 | 2. Once done, shut down the QuarkDB process. 60 | 61 | 3. To initialize a new raft cluster out of bulkloaded data: 62 | 63 | 1. Run ``quarkdb-create --path /var/lib/quarkdb/raft --clusterID my-cluster-id 64 | --nodes node1:7777,node2:7777,node3:7777 --steal-state-machine /var/lib/quarkdb/bulkload/current/state-machine``. 65 | 66 | 2. ``/var/lib/quarkdb/raft`` now contains the full data. _Copy_ this directory 67 | in full into _all_ nodes destined to be part of this new cluster: ``scp -r /var/lib/quarkdb/raft node1:/some/path`` 68 | 69 | 3. Create the xrootd configuration files for each node, pointing to the location 70 | where the above directory was copied into. 71 | 72 | 4. To initialize a new standalone node out of bulkloaded data: 73 | 74 | 1. Run ``quarkdb-create --path /var/lib/quarkdb/standalone --steal-state-machine /var/lib/quarkdb/bulkload/current/state-machine`` 75 | 76 | 2. Create the xrootd configuration file as usual, pointing to ``/var/lib/quarkdb/standalone``. 77 | 78 | -------------------------------------------------------------------------------- /docs/docs/checklist.md: -------------------------------------------------------------------------------- 1 | # Checklist for production 2 | 3 | You've decided to run a cluster in production — great! Before hitting the red button, here's a list of recommendations 4 | for your setup. 5 | 6 | 1. Decide on whether you need SSDs — you probably do. Sustaining a high rate 7 | (kHz) of IOPS is not possible with spinning hard disks, and transaction throughput 8 | will be low. 9 | 10 | Note: You may get great performance initially with a hard drive thanks to page caching, 11 | *until the total data stored exceeds the amount of RAM available*, after which 12 | throughput will crash. 13 | 14 | * _Recommended:_ Use SSDs, especially if you plan on storing more data than there is RAM available 15 | on the machine, and need high transaction throughput. 16 | 17 | 1. Ensure the cluster is secure — redis is a popular protocol, and there are bots scanning the 18 | entire internet looking to attack unsecured redis instances. _This is not theoretical_ and we 19 | have seen it happen. 20 | 21 | * **Essential:** Configure your instance with [password authentication](authentication.md) 22 | * _Recommended:_ Ensure the relevant ports are blocked from the open internet with a firewall, only 23 | available within your internal network. 24 | * Optional: Use a script that periodically verifies the cluster is inaccessible without 25 | a password, and its ports shut from the open internet. 26 | 27 | 1. Ensure backups are taken at regular intervals — even though QuarkDB is replicated, _you still need backups_. 28 | 29 | * **Essential:** Set-up a script to take periodic [backups](backup.md). 30 | 31 | * **Essential:** Ensure your backup script will not silently fail. In case of failure, an alarm should be generated. 32 | 33 | * _Recommended:_ Do basic sanity checking of the generated backup using `quarkdb-validate-checkpoint` tool before putting 34 | into long-term storage. 35 | 36 | 37 | -------------------------------------------------------------------------------- /docs/docs/disk-space.md: -------------------------------------------------------------------------------- 1 | # Disk space 2 | 3 | ## How much space do I need? 4 | 5 | * The **raft journal** will grow in size until it hits the [trimming](journal-trimming.md) threshold. 6 | For pipelined small writes (1-2 kb), expect around 20-40 GB in the default trimming configuration, 7 | but this could vary a lot. 8 | 9 | If the journal is consuming too much space, consider lowering the trimming threshold. 10 | 11 | * The **state machine** will grow in proportion to how much data is stored. 12 | 13 | ## What about when storing the EOS namespace? 14 | 15 | The general rule of thumb is 0.1 - 0.2 GB per million metadata entries. The actual figure will vary 16 | depending on how long, or how compressible the filenames are. Examples from some of our instances: 17 | 18 | | Number of files | Number of directories | Raft journal | State machine | Size per million metadata entries for state machine | 19 | |-----------------|-----------------------|--------------|---------------|-----------------------------------------------------| 20 | | 236M | 51M | 24 GB | 39 GB | 0.13 GB | 21 | | 145M | 9M | 28 GB | 17 GB | 0.11 GB | 22 | | 657M | 65M | 28 GB | 104 GB | 0.14 GB | 23 | | 310M | 27M | 39 GB | 32 GB | 0.09 GB | 24 | | 152M | 16M | 37 GB | 15 GB | 0.09 GB | 25 | | 186M | 13M | 38 GB | 18 GB | 0.09 GB | 26 | | 3292M | 138M | 33 GB | 428 GB | 0.12 GB | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /docs/docs/fsync.md: -------------------------------------------------------------------------------- 1 | # Fsync policy 2 | 3 | In an ideal world, every write into QuarkDB would first be flushed to stable storage 4 | (fsync'ed) before being acknowledged, thus ensuring maximum durability in 5 | case of sudden power blackouts, or kernel crashes. 6 | 7 | Given the very high cost of fsync (often in the tens of milliseconds) 8 | QuarkDB does not by default fsync on every journal write, as that reduces throughput 9 | by around a factor of 10 or more, and introduces excessive wear on the underlying 10 | disk / SSD. 11 | 12 | Instead, starting from version 0.4.1 the journal is always fsync'ed once per second 13 | in a background thread. This limits any potential data loss during a power blackout 14 | to the last second of writes. 15 | 16 | In addition to the above, the journal can be configured with the following fsync 17 | policies: 18 | 19 | * async: Journal is synced at the discretion of the OS. 20 | * sync-important-updates (**default**): Important writes relating to the raft state 21 | are explicitly synced. This protects raft invariants after a blackout, ensuring 22 | for example that no node votes twice for the same term due to forgetting its 23 | vote after the blackout. 24 | * always: Journal is synced for **each and every** write - expect massive perfromance reduction. 25 | 26 | The default is *sync-important-updates*, as it represents a good tradeoff: During 27 | infrequent but critical raft events (voting, term changes, membership changes) 28 | the journal is synced to ensure raft state remains sane even after simultaneous, 29 | all-node power blackouts. 30 | 31 | Current fsync policy can be viewed through ``raft-info``, and changed through ``raft-set-fsync-policy``: 32 | 33 | ``` 34 | some-host:7777> raft-set-fsync-policy sync-important-updates 35 | OK 36 | ``` 37 | 38 | Things to note: 39 | 40 | * fsync policy is specific to each node **separately**, remember to change 41 | the policy on every node of your cluster. 42 | * A single node going down due to power blackout should not be a problem, as the 43 | rest will re-populate any lost entries through replication. Data loss becomes 44 | a possibility if multiple nodes are powered off *simultaneously*. 45 | * Only power blackouts and kernel crashes pose such a problem. If just QuarkDB crashes 46 | (even by ``kill -9``), no data loss will occur. 47 | 48 | -------------------------------------------------------------------------------- /docs/docs/index.md: -------------------------------------------------------------------------------- 1 | # QuarkDB, a highly available datastore 2 | 3 | ## Introduction 4 | 5 | QuarkDB is a highly available datastore speaking the redis wire protocol (RESP2), being 6 | developed by IT-ST at CERN. 7 | 8 | Highlights: 9 | 10 | * Highly available through replication and the [raft](https://raft.github.io) distributed consensus algorithm. 11 | * Built on top of [rocksdb](https://github.com/facebook/rocksdb), a transactional key-value store. 12 | * Support for hashes, sets, strings, leases, `MULTI`, pubsub, and more. 13 | 14 | We run it in production at CERN, serving as the namespace backend for [EOS](https://eos.web.cern.ch), 15 | storing metadata for billions of files. 16 | 17 | ## Getting started 18 | 19 | Visit [this chapter](installation.md) for instructions on how to get a 20 | QuarkDB cluster up and running. Check out the [production checklist](checklist.md) before 21 | running in production. 22 | 23 | There's also a short [screencast demo](https://asciinema.org/a/NdX791Ah4JVkGQnUQkBVm3dDJ), 24 | which shows how to set up a test cluster on localhost. 25 | -------------------------------------------------------------------------------- /docs/docs/installation.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | ## Packages 4 | 5 | There are several ways to obtain QuarkDB, the easiest being to install from an RPM. 6 | If running CentOS 7, store the following in `/etc/yum.repos.d/quarkdb.repo`: 7 | 8 | ``` 9 | [quarkdb-stable] 10 | name=QuarkDB repository [stable] 11 | baseurl=http://storage-ci.web.cern.ch/storage-ci/quarkdb/tag/el7/x86_64/ 12 | enabled=1 13 | gpgcheck=False 14 | ``` 15 | 16 | Then, run `yum install quarkdb quarkdb-debuginfo`, and you're done. 17 | 18 | ## Building from source 19 | 20 | Requirements / Dependencies: 21 | 22 | * Check out `utils/el7-packages.sh` for a list of build dependencies. 23 | * Build will fail with older versions of gcc/gcc-c++ 24 | * On CC7, run `yum install centos-release-sc && yum install devtoolset-8 && source /opt/rh/devtoolset-8/enable` 25 | 26 | The following will compile QuarkDB and run the tests. 27 | 28 | ``` 29 | git clone https://gitlab.cern.ch/eos/quarkdb.git && cd quarkdb 30 | git submodule update --recursive --init 31 | 32 | mkdir build && cd build 33 | cmake .. 34 | make 35 | ./test/quarkdb-tests 36 | ``` 37 | 38 | RocksDB is embedded as a submodule, but you can also compile it yourself 39 | and specify `-DROCKSDB_ROOT_DIR` to the cmake invocation, in order to speed 40 | things up if you do a full recompilation of QuarkDB often. 41 | -------------------------------------------------------------------------------- /docs/docs/journal-trimming.md: -------------------------------------------------------------------------------- 1 | # Journal trimming 2 | 3 | As you know, all writes into QuarkDB during raft mode are first recorded 4 | into the raft journal. This is a necessary step during consensus and replication, 5 | since all writes must first be stored into a quorum of nodes before being committed. 6 | 7 | However, we cannot store all writes since ever, that would cause the raft journal 8 | to grow out of control in size. It's necessary to occasionally trim it and only 9 | keep the last N entries. 10 | 11 | Two configuration options control trimming: 12 | 13 | * The number of entries to keep in the raft journal. Default value is 50 million 14 | journal entries. Values below 1 million are probably not reasonable for a production 15 | deployment, and values below 100k are disallowed. 16 | 17 | * The batch size to use during trimming: This many entries will be deleted at once 18 | when it's time to apply trimming. Default value is 200k. Too high batch sizes 19 | might cause write stalls -- values higher than 1 million are not recommended. 20 | 21 | You can change the above values with the following command towards the leader. This 22 | sets total number of entries to keep at 10M, and batch size at 200k. 23 | 24 | ``` 25 | redis-cli -p 7777 config-set raft.trimming 10000000:200000 26 | ``` 27 | 28 | You can view all configuration options with the following: 29 | 30 | ``` 31 | redis-cli -p 7777 config-getall 32 | ``` 33 | 34 | Recommendation: Keep the default values, unless the raft-journal directory is 35 | starting to consume too much space. 36 | 37 | You can see current trimming status by running `raft-info`: 38 | 39 | ``` 40 | 127.0.0.1:7777> raft-info 41 | 1) TERM 12259 42 | 2) LOG-START 35939700000 43 | 3) LOG-SIZE 35949744300 44 | ... 45 | ``` 46 | 47 | The above means that a total of `35949744300` writes have been recorded in the 48 | journal so far, but the first `35939700000` have been trimmed already. Only 49 | the last `35949744300 - 35939700000 = 10044300` entries are still available. 50 | -------------------------------------------------------------------------------- /docs/docs/raft.md: -------------------------------------------------------------------------------- 1 | # Raft basics 2 | 3 | A far more comprehensive description can be found in the [raft paper](https://raft.github.io/raft.pdf). 4 | Our implementation follows it closely. 5 | 6 | A node can be in three states: 7 | 8 | 1. Leader, or master. This is where all write and read requests from clients 9 | go - there can only be one leader at any point in time. 10 | 11 | A leader maintains its position by sending regular heartbeats to all others 12 | in the cluster. 13 | 14 | 1. Follower, or slave: such a node will not accept any read or write requests, 15 | but redirect them to the leader. 16 | 17 | 1. Candidate: if a node is not receiving heartbeats from the current leader, it 18 | will initiate an election, asking for votes from its peers in the cluster. 19 | 20 | ## Failover 21 | 22 | During normal operation, a leader will be long-lived, potentially lasting for 23 | weeks or months at a time. 24 | 25 | What happens when it fails? Assuming there's still a quorum in the cluster, the 26 | following will happen: 27 | 28 | 1. The leader fails, and stops sending heartbeats. 29 | 1. The heartbeat timeout in one of the followers expires, it becomes a candidate 30 | and starts an election, sending vote requests to its peers. 31 | 1. Most of the time, the election will succeed, with its peers voting positively 32 | for it. 33 | 1. The candidate receives the positive vote replies, and ascends as the new leader. 34 | 35 | A node will vote negatively if it has a more up-to-date journal than 36 | the candidate - in that case, the cluster might need more than one election 37 | round before selecting its new leader, but failover will usually be very quick, 38 | within a few of seconds. 39 | 40 | If there's no quorum, meaning that less than a majority of nodes are available, 41 | the election rounds will continue ad-infinitum, and the cluster will remain 42 | unavailable for reading or writing. 43 | 44 | ## Semi-synchronous replication 45 | 46 | Writes are replicated semi-synchronously, meaning that a client receives an 47 | acknowledgement to a write only after it has been replicated to a quorum of 48 | nodes, thus guaranteeing that it won't be lost, even if the leader crashes 49 | immediately after. 50 | -------------------------------------------------------------------------------- /docs/docs/ref/auth.md: -------------------------------------------------------------------------------- 1 | # AUTH password 2 | 3 | Authenticates the given client connection: The client proves knowledge of the 4 | password by supplying it directly to the server. 5 | 6 | ``` 7 | 127.0.0.1:4445> get key 8 | (error) NOAUTH Authentication required. 9 | 127.0.0.1:4445> auth wrong_password 10 | (error) ERR invalid password 11 | 127.0.0.1:4445> auth correct_password 12 | OK 13 | 127.0.0.1:4445> get key 14 | "contents" 15 | ``` 16 | 17 | The password should be supplied each time a reconnection occurs. In QClient, 18 | reconnections from transient network failures are handled transparently -- the password 19 | should be supplied as part of the handshake, not through a regular command. -------------------------------------------------------------------------------- /docs/docs/ref/hash/hexists.md: -------------------------------------------------------------------------------- 1 | # HEXISTS key field 2 | 3 | Given the key of a hash, checks whether the specified field exists. 4 | 5 | If the key holds a different type other than hash already, an error is returned. 6 | 7 | ``` 8 | 127.0.0.1:4446> hset myhash f1 v1 9 | (integer) 1 10 | 127.0.0.1:4446> hexists myhash f1 11 | (integer) 1 12 | 127.0.0.1:4446> hexists myhash f2 13 | (integer) 0 14 | ``` -------------------------------------------------------------------------------- /docs/docs/ref/hash/hget.md: -------------------------------------------------------------------------------- 1 | # HGET key field 2 | 3 | Given the key of a hash, retrieves the contents found in the given field. If the 4 | key, or corresponding field does not exist, the empty string is returned. 5 | 6 | If the key holds a different type other than hash already, an error is returned. 7 | 8 | *Cost:* Two lookups. 9 | 10 | ``` 11 | 127.0.0.1:4445> hset myhash f1 v1 12 | (integer) 1 13 | 127.0.0.1:4445> hset myhash f2 v2 14 | (integer) 1 15 | 127.0.0.1:4445> hget myhash f1 16 | "v1" 17 | 127.0.0.1:4445> hget myhash f2 18 | "v2" 19 | ``` 20 | -------------------------------------------------------------------------------- /docs/docs/ref/hash/hgetall.md: -------------------------------------------------------------------------------- 1 | # HGETALL key 2 | 3 | Given the key of a hash, returns all contained pairs of fields and values. 4 | 5 | *Cost:* One lookup + scan of _N_ items. 6 | 7 | ``` 8 | 127.0.0.1:4445> hset myhash f1 v1 9 | (integer) 1 10 | 127.0.0.1:4445> hset myhash f2 v1 11 | (integer) 1 12 | 127.0.0.1:4445> hgetall myhash 13 | 1) "f1" 14 | 2) "v1" 15 | 3) "f2" 16 | 4) "v1" 17 | ``` 18 | -------------------------------------------------------------------------------- /docs/docs/ref/hash/hkeys.md: -------------------------------------------------------------------------------- 1 | # HKEYS key 2 | 3 | Given the key of a hash, returns the names of all stored fields. 4 | 5 | *Cost:* One lookup + scan of _N_ items. 6 | 7 | ``` 8 | 127.0.0.1:4446> hset myhash f1 v1 9 | (integer) 1 10 | 127.0.0.1:4446> hset myhash f2 v1 11 | (integer) 1 12 | 127.0.0.1:4446> hkeys myhash 13 | 1) "f1" 14 | 2) "f2" 15 | ``` 16 | -------------------------------------------------------------------------------- /docs/docs/ref/hash/hmset.md: -------------------------------------------------------------------------------- 1 | # HMSET key [field value] [field value] ... 2 | 3 | Given the key of a hash and N field-value pairs, sets the contents of the corresponding 4 | fields to the given values. 5 | 6 | *Cost:* One lookup + N * (One lookup + one writes) + one write. 7 | 8 | ``` 9 | 127.0.0.1:4446> hmset myhash f1 v1 f2 v2 10 | OK 11 | 127.0.0.1:4446> hget myhash f1 12 | "v1" 13 | 127.0.0.1:4446> hget myhash f2 14 | "v2" 15 | ``` 16 | -------------------------------------------------------------------------------- /docs/docs/ref/hash/hset.md: -------------------------------------------------------------------------------- 1 | # HSET key field value 2 | 3 | Given the key of a hash, sets the value of the corresponding field to the given 4 | contents. 5 | 6 | Return value: The number of newly created fields. 7 | 8 | If the key holds a different type other than hash already, an error is returned. 9 | 10 | *Cost:* Two lookups + two writes. 11 | 12 | ``` 13 | 127.0.0.1:4445> hset myhash f1 v1 14 | (integer) 1 15 | 127.0.0.1:4445> hset myhash f1 v2 16 | (integer) 0 17 | 127.0.0.1:4445> hget myhash f1 18 | "v2" 19 | ``` 20 | -------------------------------------------------------------------------------- /docs/docs/ref/hmac-signing-challenges.md: -------------------------------------------------------------------------------- 1 | # HMAC signing challenges 2 | 3 | HMAC signing challenges are a better alternative to [AUTH](auth.md) for a client to prove 4 | knowledge of the password, without having to actually supply the password over the wire. 5 | 6 | Due to its complexity, this method of authentication is only viable through scripts 7 | and code, not interactively through the CLI. 8 | 9 | Client and server agree together on a string-to-sign, and the client proves knowledge 10 | of the password by supplying the correct HMAC EVP sha256 signature of the generated 11 | string. 12 | 13 | The procedure has been implemented as a QClient handshake, use `HmacAuthHandshake` 14 | for convenience. 15 | 16 | ## Example 17 | 18 | The client asks the server to generate a signing challenge, providing 64 random 19 | bytes: 20 | 21 | ``` 22 | localhost:7777> HMAC-AUTH-GENERATE-CHALLENGE <... 64 random bytes ...> 23 | "<... long string to sign...>" 24 | ``` 25 | 26 | The client then signs the server-provided string using HMAC EVP sha256 and 27 | the password it knows about: 28 | 29 | ``` 30 | localhost:7777> HMAC-AUTH-VALIDATE-CHALLENGE <... hmac signature ...> 31 | OK 32 | ``` 33 | 34 | The server validates the signature, and if the signatures match, lets the 35 | client through. 36 | -------------------------------------------------------------------------------- /docs/docs/ref/string/get.md: -------------------------------------------------------------------------------- 1 | # GET key 2 | 3 | Retrieves the contents of a key containing a string. If the key does not exist, 4 | the empty string is returned. 5 | 6 | If the key holds a different type other than string already, an error is returned. 7 | 8 | *Cost:* Two lookups. 9 | 10 | ``` 11 | 127.0.0.1:4445> set key chickens 12 | OK 13 | 127.0.0.1:4445> get key 14 | "chickens" 15 | 127.0.0.1:4445> get othertype 16 | (error) ERR Invalid argument: WRONGTYPE Operation against a key holding the wrong kind of value 17 | ``` 18 | -------------------------------------------------------------------------------- /docs/docs/ref/string/set.md: -------------------------------------------------------------------------------- 1 | # SET key value 2 | 3 | Stores the given value onto the specified key. If the key does not exist, it is 4 | created. 5 | 6 | If the key holds a different type other than string already, an error is returned. 7 | 8 | *Cost:* One lookup + two writes. 9 | 10 | ``` 11 | 127.0.0.1:4445> set key chickens 12 | OK 13 | 127.0.0.1:4445> get key 14 | "chickens" 15 | 127.0.0.1:4445> set othertype b 16 | (error) ERR Invalid argument: WRONGTYPE Operation against a key holding the wrong kind of value 17 | ``` 18 | -------------------------------------------------------------------------------- /docs/docs/release-notes.md: -------------------------------------------------------------------------------- 1 | # Release notes 2 | 3 | This is a stub page to be replaced by the CI scripts. 4 | -------------------------------------------------------------------------------- /docs/docs/resilvering.md: -------------------------------------------------------------------------------- 1 | # Resilvering 2 | 3 | Consider the following situation: 4 | 5 | * We have a three node QuarkDB cluster. One of the machines goes down for 10 mintues 6 | as part of scheduled maintainance. At the time of shutdown, the node's journal 7 | contained entries 100-500. 8 | * When it comes back up, the leader's journal contains entries 100-1000. 9 | * Bringing the node up to date with the leader is trivial: Just send entries 10 | 501-1000, and we are done. 11 | 12 | However, what happens if the intervention lasts far longer, such as a few weeks? 13 | 14 | * When the leader comes up, it contains entries 600-3000. 15 | * There's no way to sync the node that was offline, since the leader has 16 | [trimmed](journal-trimming.md) from its local journal entries 500-600. 17 | 18 | The same situation occurs if a node dies from a broken hard drive, and all its data 19 | is lost. If the leader has [trimmed](journal-trimming.md) any entries whatsoever from the beginning of 20 | its journal, bringing the follower back on sync is not possible by pushing 21 | the missing entries, as we don't have them anymore. 22 | 23 | In such situation, the leader will snapshot its local database (journal + state machine), 24 | and stream it over to the follower replacing its entire current contents. We call this 25 | process resilvering. Essentially we rebuild the entire contents of a node, which 26 | is quite time-consuming, only in cases where we don't have any other options. 27 | 28 | In case you'd like to disable automatic resilvering 29 | (and perform the above snapshot + copy manually when needed), run the following: 30 | 31 | ``` 32 | redis-cli -p 7777 config-set raft.resilvering.enabled FALSE 33 | ``` 34 | -------------------------------------------------------------------------------- /docs/docs/troubleshooting.md: -------------------------------------------------------------------------------- 1 | # Troubleshooting 2 | 3 | * QuarkDB does not start: `Cannot open '/var/lib/quarkdb/node-01/current/state-machine':IO error: while open a file for lock: /var/lib/quarkdb/node-01/current/state-machine/LOCK: Permission denied` 4 | 5 | Most likely, the database owner permissions are not correct. If running 6 | with the default systemd init scripts, you need run ``chown -R xrootd:xrootd /var/lib/quarkdb/node-01/``. 7 | 8 | * I get this error in the log: `MISCONFIGURATION: received handshake with wrong cluster id: "..." (mine is "...")` 9 | 10 | All members in a cluster have to have the same cluster ID, as provided in `quarkdb-create`. 11 | You probably assigned a different one to each member. 12 | 13 | Each cluster has a unique identifier assigned to it, which each member node has to know. 14 | During the initial handshake between two nodes, the cluster ID is exchanged - if 15 | it does not match, the connection is shut down, and they refuse to communicate. 16 | 17 | This is to prevent damage from a misconfiguration where two nodes from different 18 | instances accidentally cross paths. 19 | 20 | * I get this error in the log: `WARNING: I am not receiving heartbeats - not running for leader since in membership epoch 0 I am not a full node. Will keep on waiting.` 21 | 22 | The node identifier, as provided in `redis.myself`, is not part of the QuarkDB cluster, as 23 | initialized in ``quarkdb-create``. Either change `redis.myself` to match one of 24 | the nodes provided in ``quarkdb-create``, or re-run ``quarkdb-create`` with the correct 25 | nodes. 26 | 27 | Run `redis-cli -p 7777 raft-info` to check the current cluster membership. Each 28 | node expects to find `redis.myself` within `NODES`, to decide whether it's capable 29 | of starting an election. 30 | 31 | * The nodes are holding elections indefinitely, even though I've started all of them! 32 | 33 | It's likely a firewall issue. Try running 34 | `redis-cli -h qdb-test-2.cern.ch -p 7777 raft-info` from a different node, for example - 35 | if you can't connect, it's a firewall issue. 36 | -------------------------------------------------------------------------------- /docs/docs/upgrading.md: -------------------------------------------------------------------------------- 1 | # Version upgrades 2 | 3 | ## Can I upgrade without downtime? 4 | 5 | _Yes_, a routine version upgrade should require only a single leader election. 6 | The recommended steps are the following: 7 | 8 | 1. Use ``raft-info`` to find out the current cluster leader. 9 | 10 | 2. For each of the _followers_, do the following _one by one_: 11 | 12 | * Upgrade system packages. 13 | 14 | * Restart the QuarkDB service. 15 | 16 | * Wait until the leader declares the node as back online, and as having an up-to-date 17 | journal. Run ``raft-info`` on the leader node, check ``REPLICA`` section for this 18 | information. 19 | 20 | 3. Finally, upgrade and restart the leader. The followers will detect the 21 | absence of heartbeats, and elect a new leader among themselves within a 22 | few seconds. 23 | 24 | Upgrading the followers _one by one_ and not all at once is **important**: If you 25 | simultaneously upgrade both followers on a 3-node cluster, the cluster could become 26 | unavailable for a couple of minutes due to loss of quorum until the nodes come back 27 | online. 28 | 29 | ## What not to do 30 | 31 | All following methods are worse than the above, since they cause longer downtime 32 | than a single leader election. 33 | 34 | * Upgrade the leader first. Inevitably, leadership will jump to one of the followers, 35 | which will have to be restarted too at some point for the upgrade, resulting 36 | in 2 or more elections for the upgrade in total. 37 | 38 | * Upgrade all QuarkDB daemons at the same time: The cluster could potentially 39 | go down for minutes, depending on how quickly the processes are able to come back 40 | online. 41 | 42 | * An upgrade when quorum is shaky: For example, if only 2 out of 3 nodes are 43 | available (maybe the third died from a broken hard drive), an upgrade of any 44 | remaining node will cause loss of quorum for the duration of time it takes for 45 | QuarkDB to restart. 46 | -------------------------------------------------------------------------------- /docs/docs/write-path.md: -------------------------------------------------------------------------------- 1 | # Write path 2 | 3 | This is a rough summary of what happens for every successful write to 4 | QuarkDB - all the events that occur between the time a client issues a command, 5 | and the reception of an acknowledgement. 6 | 7 | The following is a simplification, glossing over certain details, such as what 8 | happens if the leader node crashes in the middle of some step, 9 | or certain optimizations such as write batching. 10 | 11 | 1. A client issues a write command towards a random QuarkDB node in the cluster, 12 | for example ```SET mykey myvalue```. 13 | 14 | 1. Assuming the client is unlucky, and the random node it contacted is not the 15 | current leader, a redirect is returned asking the client to try again towards 16 | the leader. 17 | 18 | 1. The client issues ```SET mykey myvalue``` again, this time towards the leader. 19 | 20 | 1. The leader receives the request, parses it, and appends it to its local raft journal. 21 | Its ```LOG-SIZE``` increments by one. 22 | 23 | 1. The replicator tracker of the leader notices an entry was just appended, and 24 | issues ```APPEND-ENTRIES``` RPC towards all followers. The RPC includes 25 | the contents of the write operation: ```SET mykey myvalue```. 26 | 27 | 1. The followers receive ```APPEND-ENTRIES``` RPC, and append the new write 28 | to their local journals - their local ```LOG-SIZE``` increment by one, as well. 29 | The followers then acknowledge to the leader that they have received the 30 | new entry. 31 | 32 | 1. As soon as the leader receives enough acknowledgements that allows it to determine 33 | that a quorum of nodes (including itself) contain the new entry, it declares 34 | the new write as *commited*, and increments its local ```COMMIT-INDEX```. 35 | 36 | 1. After an entry is considered committed, it is then applied to the leader's state 37 | machine. ```LAST-APPLIED``` is incremented atomically together with the application 38 | of the entry, and the leader finally issues an acknowledgement to the client 39 | that the write was successful. 40 | 41 | There are a few more details worth mentioning: 42 | 43 | * The local ```COMMIT-INDEX``` of followers is synchronized with that of the 44 | leader regularly - each ```APPEND-ENTIES``` RPC includes the 45 | leader's current ```COMMIT-INDEX```. 46 | 47 | * Followers run a background thread which continuously applies incoming, committed 48 | entries to their local state machines. This way, each follower is ready to quickly 49 | take over in case the leader fails. 50 | 51 | * A client will cache who the leader currently is for subsequent requests, thus 52 | saving the second step and additional useless network roundtrips. 53 | 54 | * The replicator will batch multiple entries into each ```APPEND-ENTRIES``` whenever 55 | possible, thus amortizing replication latency over many writes. Clients need 56 | to issue pipelined writes to benefit from this optimization. 57 | -------------------------------------------------------------------------------- /docs/mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: QuarkDB Documentation 2 | theme: 3 | name: null 4 | custom_dir: '../deps/mkdocs-material/material' 5 | language: en 6 | 7 | # 404 page 8 | static_templates: 9 | - 404.html 10 | 11 | # Don't include MkDocs' JavaScript 12 | include_search_page: false 13 | search_index_only: true 14 | 15 | # Default values, taken from mkdocs_theme.yml 16 | language: en 17 | palette: 18 | primary: indigo 19 | accent: indigo 20 | font: 21 | text: Roboto 22 | code: Roboto Mono 23 | favicon: assets/images/favicon.png 24 | logo: 25 | icon: "\uE80C" 26 | 27 | palette: 28 | font: 29 | text: Roboto 30 | code: Roboto Mono 31 | logo: 32 | icon: "\uE80C" 33 | feature: 34 | tabs: true 35 | 36 | nav: 37 | - Home: 38 | - Introduction: index.md 39 | - Getting started: 40 | - Installation: installation.md 41 | - Configuration: configuration.md 42 | - Troubleshooting: troubleshooting.md 43 | - Operator's manual: 44 | - Checklist for production: checklist.md 45 | - Disk space: disk-space.md 46 | - Version upgrades: upgrading.md 47 | - Backup & restore: backup.md 48 | - Failure scenarios: failure-scenarios.md 49 | - Configuration: 50 | - Password authentication: authentication.md 51 | - Journal trimming: journal-trimming.md 52 | - Resilvering: resilvering.md 53 | - Fsync policy: fsync.md 54 | - Bulkload mode: bulkload.md 55 | - Membership updates: membership.md 56 | - Release notes: release-notes.md 57 | - Command reference: 58 | - Authentication: 59 | - AUTH: ref/auth.md 60 | - HMAC signing challenges: ref/hmac-signing-challenges.md 61 | - String types: 62 | - GET: ref/string/get.md 63 | - SET: ref/string/set.md 64 | - Hash types: 65 | - HGET: ref/hash/hget.md 66 | - HSET: ref/hash/hset.md 67 | - HMSET: ref/hash/hmset.md 68 | - HEXISTS: ref/hash/hexists.md 69 | - HKEYS: ref/hash/hkeys.md 70 | - HGETALL: ref/hash/hgetall.md 71 | - Advanced topics: 72 | - Raft basics: raft.md 73 | - Write path: write-path.md 74 | - Raft extensions: raft-extensions.md 75 | -------------------------------------------------------------------------------- /packaging/gitlab-build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | git submodule update --init --recursive 5 | ./packaging/make-srpm.sh 6 | cd build 7 | 8 | if which dnf; then 9 | dnf builddep -y SRPMS/* 10 | else 11 | yum-builddep -y SRPMS/* 12 | fi 13 | 14 | rpmbuild --rebuild --with server --define "_build_name_fmt %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm" SRPMS/* 15 | -------------------------------------------------------------------------------- /packaging/make-dist.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | 5 | #------------------------------------------------------------------------------- 6 | # Generate a release tarball - run this from the root of the git repository. 7 | #------------------------------------------------------------------------------- 8 | 9 | git submodule update --recursive --init 10 | mkdir -p build 11 | ./genversion.py --template src/Version.hh.in --out src/Version.hh 12 | ./genversion.py --template packaging/quarkdb.spec.in --out packaging/quarkdb.spec 13 | 14 | #------------------------------------------------------------------------------- 15 | # Detect if the rocksdb cache is available. 16 | #------------------------------------------------------------------------------- 17 | ROCKSDB_CACHE=$(ci/rocksdb-cmake.sh) 18 | sed "s!@ROCKSDB_CACHED_BUILD@!${ROCKSDB_CACHE}!g" packaging/quarkdb.spec -i 19 | 20 | #------------------------------------------------------------------------------- 21 | # Extract version number, we need this for the archive name 22 | #------------------------------------------------------------------------------- 23 | VERSION_FULL=$(./genversion.py --template-string "@VERSION_FULL@") 24 | printf "Version: ${VERSION_FULL}\n" 25 | FILENAME="quarkdb-${VERSION_FULL}" 26 | 27 | #------------------------------------------------------------------------------- 28 | # Make the archive 29 | #------------------------------------------------------------------------------- 30 | TARGET_PATH=$(basename $PWD) 31 | 32 | pushd $PWD/.. 33 | tar --exclude '*/.git' --exclude "${TARGET_PATH}/build" --exclude "${TARGET_PATH}/_book" -pcvzf ${TARGET_PATH}/build/${FILENAME}.tar.gz ${TARGET_PATH} --transform "s!^${TARGET_PATH}!${FILENAME}!" --show-transformed-names 34 | popd 35 | -------------------------------------------------------------------------------- /packaging/make-srpm.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #------------------------------------------------------------------------------- 4 | # Generate a source RPM - run this from the root fo the git repository. 5 | #------------------------------------------------------------------------------- 6 | 7 | VERSION_FULL=$(./genversion.py --template-string "@VERSION_FULL@") 8 | printf "Version: ${VERSION_FULL}\n" 9 | 10 | ./packaging/make-dist.sh 11 | TARBALL="quarkdb-${VERSION_FULL}.tar.gz" 12 | BUILD_DIR=$PWD/build 13 | 14 | pushd build 15 | rpmbuild --define "_source_filedigest_algorithm md5" --define "_binary_filedigest_algorithm md5" -ts ${TARBALL} --define "_topdir ${BUILD_DIR}" --with server 16 | -------------------------------------------------------------------------------- /packaging/replace-directory.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | STAGING_AREA="$1" 5 | TARGET="$2" 6 | OLD_CONTENTS="${TARGET}-old" 7 | 8 | test ! -d "$TARGET" || mv "$TARGET" "$OLD_CONTENTS" 9 | 10 | sleep 30 11 | mv "$STAGING_AREA" "$TARGET" 12 | test ! -d "$OLD_CONTENTS" || rm -rf "$OLD_CONTENTS" 13 | 14 | -------------------------------------------------------------------------------- /src/BufferedWriter.cc: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: BufferedWriter.cc 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #include "BufferedWriter.hh" 25 | #include "Link.hh" 26 | using namespace quarkdb; 27 | 28 | BufferedWriter::BufferedWriter(Link *link_) 29 | : link(link_) { 30 | } 31 | 32 | BufferedWriter::~BufferedWriter() { 33 | 34 | } 35 | 36 | void BufferedWriter::setActive(bool newval) { 37 | std::scoped_lock lock(mtx); 38 | flush(); 39 | active = newval; 40 | } 41 | 42 | void BufferedWriter::flush() { 43 | std::scoped_lock lock(mtx); 44 | 45 | if(!link) return; 46 | if(bufferedBytes == 0) return; 47 | 48 | link->Send(buffer, bufferedBytes); 49 | bufferedBytes = 0; 50 | } 51 | 52 | LinkStatus BufferedWriter::send(std::string &&raw) { 53 | std::scoped_lock lock(mtx); 54 | 55 | if(!link) return 1; 56 | if(!active) return link->Send(raw); 57 | 58 | if(raw.size() + bufferedBytes > OUTPUT_BUFFER_SIZE) { 59 | this->flush(); 60 | if(raw.size() > OUTPUT_BUFFER_SIZE) { 61 | return link->Send(raw); // response too large for output buffer 62 | } 63 | } 64 | 65 | memcpy(buffer + bufferedBytes, raw.c_str(), raw.size()); 66 | bufferedBytes += raw.size(); 67 | return 1; 68 | } 69 | -------------------------------------------------------------------------------- /src/BufferedWriter.hh: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------- 2 | // File: BufferedWriter.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef __QUARKDB_BUFFERED_WRITER_H__ 25 | #define __QUARKDB_BUFFERED_WRITER_H__ 26 | 27 | #include 28 | 29 | namespace quarkdb { 30 | using LinkStatus = int; 31 | class Link; 32 | 33 | #define OUTPUT_BUFFER_SIZE (16*1024) 34 | 35 | class BufferedWriter { 36 | public: 37 | BufferedWriter(Link *link); 38 | ~BufferedWriter(); 39 | 40 | void setActive(bool newval); 41 | void flush(); 42 | LinkStatus send(std::string &&raw); 43 | private: 44 | Link *link; 45 | 46 | bool active = true; 47 | char buffer[OUTPUT_BUFFER_SIZE]; 48 | int bufferedBytes = 0; 49 | 50 | std::recursive_mutex mtx; 51 | }; 52 | 53 | } 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /src/EventFD.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: EventFD.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef __QUARKDB_EVENTFD_H__ 25 | #define __QUARKDB_EVENTFD_H__ 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | namespace quarkdb { 32 | 33 | class EventFD { 34 | public: 35 | EventFD() { 36 | fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); 37 | } 38 | 39 | ~EventFD() { 40 | close(); 41 | } 42 | 43 | void close() { 44 | if(fd >= 0) { 45 | ::close(fd); 46 | fd = -1; 47 | } 48 | } 49 | 50 | void wait() { 51 | struct pollfd polls[1]; 52 | polls[0].fd = fd; 53 | polls[0].events = POLLIN; 54 | polls[0].revents = 0; 55 | 56 | poll(polls, 1, -1); 57 | } 58 | 59 | void notify(int64_t val = 1) { 60 | int rc = write(fd, &val, sizeof(val)); 61 | if(rc != sizeof(val)) { 62 | qdb_throw("could not notify eventfd, write rc: " << rc << ", errno: " << errno); 63 | } 64 | } 65 | 66 | int64_t reset() { 67 | int64_t tmp; 68 | int rc = read(fd, &tmp, sizeof(tmp)); 69 | if(rc != sizeof(tmp) && !(rc == -1 && errno == EAGAIN)) { 70 | qdb_critical("could not reset eventfd, read rc: " << rc); 71 | } 72 | return tmp; 73 | } 74 | 75 | int getFD() { 76 | return fd; 77 | } 78 | private: 79 | int fd = -1; 80 | }; 81 | 82 | } 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /src/StandaloneGroup.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: StandaloneGroup.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef QUARKDB_STANDALONE_GROUP_H 25 | #define QUARKDB_STANDALONE_GROUP_H 26 | 27 | #include 28 | #include "Dispatcher.hh" 29 | #include "pubsub/Publisher.hh" 30 | #include "health/HealthIndicator.hh" 31 | 32 | namespace quarkdb { 33 | 34 | class ShardDirectory; 35 | class RedisDispatcher; 36 | class StateMachine; 37 | class Dispatcher; 38 | 39 | class StandaloneDispatcher : public Dispatcher { 40 | public: 41 | StandaloneDispatcher(StateMachine &sm, Publisher &pub); 42 | virtual LinkStatus dispatch(Connection *conn, RedisRequest &req) override final; 43 | virtual LinkStatus dispatch(Connection *conn, Transaction &req) override final; 44 | virtual void notifyDisconnect(Connection *conn) override final; 45 | 46 | private: 47 | StateMachine* stateMachine; 48 | RedisDispatcher dispatcher; 49 | Publisher* publisher; 50 | }; 51 | 52 | class StandaloneGroup { 53 | public: 54 | StandaloneGroup(ShardDirectory& shardDirectory, bool bulkload); 55 | ~StandaloneGroup(); 56 | 57 | StateMachine* getStateMachine(); 58 | Dispatcher* getDispatcher(); 59 | 60 | //---------------------------------------------------------------------------- 61 | // Return health information 62 | //---------------------------------------------------------------------------- 63 | NodeHealth getHealth(); 64 | 65 | private: 66 | ShardDirectory &shardDirectory; 67 | bool bulkload; 68 | 69 | std::unique_ptr dispatcher; 70 | std::unique_ptr publisher; 71 | StateMachine* stateMachine; 72 | }; 73 | 74 | } 75 | 76 | #endif -------------------------------------------------------------------------------- /src/Timekeeper.cc: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: Timekeeper.cc 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2018 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #include "Timekeeper.hh" 25 | #include "utils/Macros.hh" 26 | using namespace quarkdb; 27 | 28 | Timekeeper::Timekeeper(ClockValue startup) : staticClock(startup) { 29 | anchorPoint = std::chrono::steady_clock::now(); 30 | } 31 | 32 | void Timekeeper::reset(ClockValue startup) { 33 | std::unique_lock lock(mtx); 34 | staticClock = startup; 35 | anchorPoint = std::chrono::steady_clock::now(); 36 | } 37 | 38 | void Timekeeper::synchronize(ClockValue newval) { 39 | std::unique_lock lock(mtx); 40 | qdb_assert(staticClock <= newval); 41 | 42 | // We have a timejump. Re-anchor, update static clock 43 | anchorPoint = std::chrono::steady_clock::now(); 44 | staticClock = newval; 45 | } 46 | 47 | ClockValue Timekeeper::getDynamicTime() const { 48 | std::shared_lock lock(mtx); 49 | return staticClock + getTimeSinceAnchor().count(); 50 | } 51 | 52 | std::chrono::milliseconds Timekeeper::getTimeSinceAnchor() const { 53 | return std::chrono::duration_cast( 54 | std::chrono::steady_clock::now() - anchorPoint 55 | ); 56 | } 57 | -------------------------------------------------------------------------------- /src/Version.hh.in: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: Version.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef __QUARKDB_VERSION_H__ 25 | #define __QUARKDB_VERSION_H__ 26 | 27 | namespace quarkdb { 28 | 29 | #define GIT_COMMIT @GIT_SHA1@ 30 | #define GIT_COMMIT_DATE @GIT_COMMIT_DATE@ 31 | #define GIT_BRANCH @GIT_BRANCH@ 32 | 33 | #define VERSION_MAJOR @VERSION_MAJOR@ 34 | #define VERSION_MINOR @VERSION_MINOR@ 35 | #define VERSION_PATCH @VERSION_PATCH@ 36 | #define VERSION_MINIPATCH @VERSION_MINIPATCH@ 37 | #define VERSION_FULL @VERSION_FULL@ 38 | 39 | #define VERSION_FULL_STRING "@VERSION_FULL@" 40 | 41 | } 42 | 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /src/XrdPlugin.cc: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: XrdPlugin.cc 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #include 25 | 26 | #include "Xrd/XrdProtocol.hh" 27 | #include "XrdSys/XrdSysError.hh" 28 | #include "XrdVersion.hh" 29 | 30 | #include "XrdQuarkDB.hh" 31 | 32 | extern "C" { 33 | XrdProtocol *XrdgetProtocol(const char *pname, char *parms, 34 | XrdProtocol_Config *pi) { 35 | pi->eDest->Say("Copr. 2016 CERN"); 36 | pi->eDest->Say("++++++ quarkdb server initialization started"); 37 | 38 | // check if the given configuration file is valid 39 | if(!quarkdb::XrdQuarkDB::Configure(parms, pi)) { 40 | pi->eDest->Say("------ quarkdb protocol plugin initialization failed."); 41 | return 0; 42 | } 43 | 44 | XrdProtocol *protocol = (XrdProtocol*) new quarkdb::XrdQuarkDB(false); 45 | pi->eDest->Say("------ quarkdb protocol plugin initialization completed."); 46 | return protocol; 47 | } 48 | } 49 | 50 | 51 | XrdVERSIONINFO(XrdgetProtocol, xrdquarkdb); 52 | 53 | //------------------------------------------------------------------------------ 54 | // This function is called early on to determine the port we need to use. The 55 | // default is ostensibly 6379 but can be overriden; which we allow. 56 | //------------------------------------------------------------------------------ 57 | 58 | XrdVERSIONINFO(GetProtocolPort, xrdquarkdb); 59 | 60 | extern "C" { 61 | int GetProtocolPort(const char *pname, char *parms, XrdProtocol_Config *pi) { 62 | if (pi->Port < 0) return 6379; 63 | return pi->Port; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/auth/AuthenticationDispatcher.hh: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------- 2 | // File: AuthenticationDispatcher.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2018 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef QUARKDB_AUTHENTICATION_DISPATCHER_HH 25 | #define QUARKDB_AUTHENTICATION_DISPATCHER_HH 26 | 27 | #include "Dispatcher.hh" 28 | 29 | namespace quarkdb { 30 | 31 | class QuarkDBNode; 32 | 33 | class AuthenticationDispatcher { 34 | public: 35 | 36 | AuthenticationDispatcher(std::string_view secret); 37 | LinkStatus dispatch(Connection *conn, RedisRequest &req); 38 | RedisEncodedResponse dispatch(const RedisRequest &req, bool &authorized, std::unique_ptr &authenticator); 39 | 40 | private: 41 | std::string secret; 42 | }; 43 | 44 | } 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /src/raft/RaftBlockedWrites.cc: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: RaftBlockedWrites.cc 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #include "raft/RaftBlockedWrites.hh" 25 | #include "Connection.hh" 26 | using namespace quarkdb; 27 | 28 | std::shared_ptr RaftBlockedWrites::popIndex(LogIndex index) { 29 | std::scoped_lock lock(mtx); 30 | auto it = tracker.find(index); 31 | 32 | if(it == tracker.end()) return {nullptr}; 33 | 34 | std::shared_ptr ret = it->second; 35 | tracker.erase(it); 36 | 37 | return ret; 38 | } 39 | 40 | void RaftBlockedWrites::insert(LogIndex index, const std::shared_ptr &item) { 41 | std::scoped_lock lock(mtx); 42 | tracker[index] = item; 43 | } 44 | 45 | void RaftBlockedWrites::flush(const RedisEncodedResponse &resp) { 46 | std::scoped_lock lock(mtx); 47 | for(auto it = tracker.begin(); it != tracker.end(); it++) { 48 | it->second->flushPending(resp); 49 | } 50 | tracker.clear(); 51 | } 52 | 53 | size_t RaftBlockedWrites::size() { 54 | std::scoped_lock lock(mtx); 55 | return tracker.size(); 56 | } 57 | -------------------------------------------------------------------------------- /src/raft/RaftBlockedWrites.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: RaftBlockedWrites.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef __QUARKDB_RAFT_BLOCKED_WRITES_H__ 25 | #define __QUARKDB_RAFT_BLOCKED_WRITES_H__ 26 | 27 | #include 28 | #include 29 | #include 30 | #include "raft/RaftCommon.hh" 31 | 32 | namespace quarkdb { 33 | 34 | class PendingQueue; 35 | class RedisEncodedResponse; 36 | class RaftBlockedWrites { 37 | public: 38 | RaftBlockedWrites() {} 39 | ~RaftBlockedWrites() {} 40 | 41 | void flush(const RedisEncodedResponse &resp); 42 | void insert(LogIndex index, const std::shared_ptr &item); 43 | std::shared_ptr popIndex(LogIndex index); 44 | size_t size(); 45 | private: 46 | std::mutex mtx; 47 | std::map> tracker; 48 | }; 49 | 50 | } 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/raft/RaftConfig.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: RaftConfig.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef __QUARKDB_RAFT_CONFIG_H__ 25 | #define __QUARKDB_RAFT_CONFIG_H__ 26 | 27 | #include 28 | #include "Link.hh" 29 | #include "RedisRequest.hh" 30 | 31 | namespace quarkdb { 32 | 33 | class StateMachine; class RaftDispatcher; class Connection; 34 | 35 | struct TrimmingConfig { 36 | // Minimum number of journal entries to keep at all times. 37 | int64_t keepAtLeast; 38 | // Trimming step - don't bother to trim if we'd be getting rid of fewer than 39 | // step entries. 40 | int64_t step; 41 | 42 | bool parse(const std::string &str); 43 | std::string toString() const; 44 | }; 45 | 46 | struct EncodedConfigChange { 47 | std::string error; 48 | RedisRequest request; 49 | }; 50 | 51 | // A configuration update must be propagated throughout the cluster.. this object 52 | // will simply validate if the parameters given look OK, and give you back the 53 | // request to run to make it happen. 54 | 55 | class RaftConfig { 56 | public: 57 | RaftConfig(StateMachine &stateMachine); 58 | 59 | TrimmingConfig getTrimmingConfig(); 60 | EncodedConfigChange setTrimmingConfig(const TrimmingConfig &trimConfig, bool overrideSafety = false); 61 | 62 | bool getResilveringEnabled(); 63 | EncodedConfigChange setResilveringEnabled(bool value); 64 | 65 | private: 66 | StateMachine &stateMachine; 67 | }; 68 | 69 | } 70 | 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /src/raft/RaftContactDetails.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: RaftContactDetails.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef QUARKDB_RAFT_CONTACT_DETAILS_H 25 | #define QUARKDB_RAFT_CONTACT_DETAILS_H 26 | 27 | #include "RaftTimeouts.hh" 28 | 29 | namespace quarkdb { 30 | 31 | using RaftClusterID = std::string; 32 | 33 | //------------------------------------------------------------------------------ 34 | //! An immutable class containing all auxiliary information required to 35 | //! establish a node-to-node connection. 36 | //------------------------------------------------------------------------------ 37 | class RaftContactDetails { 38 | public: 39 | RaftContactDetails(const RaftClusterID &cid, const RaftTimeouts &t, const std::string &pw) 40 | : clusterID(cid), timeouts(t), password(pw) { } 41 | 42 | const RaftClusterID& getClusterID() const { 43 | return clusterID; 44 | } 45 | 46 | const RaftTimeouts& getRaftTimeouts() const { 47 | return timeouts; 48 | } 49 | 50 | const std::string& getPassword() const { 51 | return password; 52 | } 53 | 54 | private: 55 | const RaftClusterID clusterID; 56 | const RaftTimeouts timeouts; 57 | const std::string password; 58 | }; 59 | 60 | } 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /src/recovery/RecoveryDispatcher.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: RecoveryDispatcher.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef QUARKDB_RECOVERY_DISPATCHER_HH 25 | #define QUARKDB_RECOVERY_DISPATCHER_HH 26 | 27 | #include "Dispatcher.hh" 28 | #include "recovery/RecoveryEditor.hh" 29 | 30 | namespace quarkdb { 31 | 32 | class Transaction; 33 | 34 | class RecoveryDispatcher : public Dispatcher { 35 | public: 36 | RecoveryDispatcher(RecoveryEditor &editor); 37 | virtual LinkStatus dispatch(Connection *conn, Transaction &tx) override final; 38 | virtual LinkStatus dispatch(Connection *conn, RedisRequest &req) override final; 39 | virtual void notifyDisconnect(Connection *conn) override final {} 40 | RedisEncodedResponse dispatch(RedisRequest &request); 41 | 42 | private: 43 | RecoveryEditor &editor; 44 | }; 45 | 46 | } 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/recovery/RecoveryEditor.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: RecoveryEditor.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef QUARKDB_RECOVERY_EDITOR_HH 25 | #define QUARKDB_RECOVERY_EDITOR_HH 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | namespace quarkdb { 32 | 33 | //------------------------------------------------------------------------------ 34 | // A class to allow raw access to rocksdb. 35 | //------------------------------------------------------------------------------ 36 | 37 | class RecoveryEditor { 38 | public: 39 | RecoveryEditor(std::string_view path); 40 | ~RecoveryEditor(); 41 | 42 | std::vector retrieveMagicValues(); 43 | rocksdb::Status get(std::string_view key, std::string &value); 44 | rocksdb::Status set(std::string_view key, std::string_view value); 45 | rocksdb::Status del(std::string_view key); 46 | rocksdb::Status scan(std::string_view key, size_t count, std::string &nextCursor, std::vector &elements); 47 | rocksdb::Status getAllVersions(std::string_view key, std::vector &output); 48 | 49 | private: 50 | std::string path; 51 | std::unique_ptr db; 52 | }; 53 | 54 | } 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/recovery/RecoveryRunner.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: RecoveryRunner.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef QUARKDB_RECOVERY_RUNNER_HH 25 | #define QUARKDB_RECOVERY_RUNNER_HH 26 | 27 | #include "recovery/RecoveryRunner.hh" 28 | #include "recovery/RecoveryDispatcher.hh" 29 | #include "netio/AsioPoller.hh" 30 | 31 | #include 32 | #include 33 | 34 | namespace quarkdb { 35 | 36 | class RecoveryRunner { 37 | public: 38 | RecoveryRunner(const std::string &path, int port); 39 | static RedisEncodedResponse issueOneOffCommand(const std::string &path, RedisRequest &req); 40 | static void DumpTool(int argc, char** argv); 41 | static void LdbTool(int argc, char** argv); 42 | 43 | private: 44 | RecoveryEditor editor; 45 | RecoveryDispatcher dispatcher; 46 | AsioPoller poller; 47 | }; 48 | 49 | } 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/redis/ArrayResponseBuilder.cc: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: ArrayResponseBuilder.cc 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #include "utils/Macros.hh" 25 | #include "redis/ArrayResponseBuilder.hh" 26 | using namespace quarkdb; 27 | 28 | ArrayResponseBuilder::ArrayResponseBuilder(size_t size, bool phant) 29 | : itemsRemaining(size), phantom(phant) { 30 | qdb_assert(itemsRemaining >= 1); 31 | 32 | if(!phantom) { 33 | ss << "*" << size << "\r\n"; 34 | } 35 | } 36 | 37 | void ArrayResponseBuilder::push_back(const RedisEncodedResponse &item) { 38 | qdb_assert(itemsRemaining != 0); 39 | itemsRemaining--; 40 | 41 | ss << item.val; 42 | } 43 | 44 | RedisEncodedResponse ArrayResponseBuilder::buildResponse() const { 45 | qdb_assert(itemsRemaining == 0); 46 | return RedisEncodedResponse(ss.str()); 47 | } 48 | -------------------------------------------------------------------------------- /src/redis/ArrayResponseBuilder.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: ArrayResponseBuilder.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef QUARKDB_ARRAY_RESPONSE_BUILDER_H 25 | #define QUARKDB_ARRAY_RESPONSE_BUILDER_H 26 | 27 | #include "redis/RedisEncodedResponse.hh" 28 | #include 29 | 30 | namespace quarkdb { 31 | 32 | class ArrayResponseBuilder { 33 | public: 34 | ArrayResponseBuilder(size_t size, bool phantom = false); 35 | void push_back(const RedisEncodedResponse &item); 36 | RedisEncodedResponse buildResponse() const; 37 | 38 | private: 39 | size_t itemsRemaining; 40 | bool phantom; 41 | std::stringstream ss; 42 | }; 43 | 44 | } 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /src/redis/Authenticator.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: Authenticator.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef QUARKDB_AUTHENTICATOR_H 25 | #define QUARKDB_AUTHENTICATOR_H 26 | 27 | #include 28 | #include 29 | 30 | namespace quarkdb { 31 | 32 | 33 | class Authenticator { 34 | public: 35 | enum class ValidationStatus { 36 | kOk, 37 | kDeadlinePassed, 38 | kInvalidSignature 39 | }; 40 | 41 | Authenticator(std::string_view secret); 42 | std::string generateChallenge(std::string_view opponentRandomBytes, std::chrono::system_clock::time_point timestamp, std::string_view myRandomBytes); 43 | std::string generateChallenge(std::string_view opponentRandomBytes); 44 | ValidationStatus validateSignature(std::string_view signature); 45 | void resetDeadline(); 46 | ~Authenticator() {} 47 | 48 | static std::string generateSignature(std::string_view stringToSign, std::string_view key); 49 | ValidationStatus validateSignatureNoDeadline(std::string_view stringToSign); 50 | 51 | private: 52 | std::string_view secretKey; 53 | 54 | std::string challengeString; 55 | std::chrono::steady_clock::time_point challengeDeadline; 56 | }; 57 | 58 | } 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /src/redis/CommandMonitor.cc: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: CommandMonitor.cc 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #include "redis/CommandMonitor.hh" 25 | #include "Formatter.hh" 26 | #include "Link.hh" 27 | using namespace quarkdb; 28 | 29 | CommandMonitor::CommandMonitor() { 30 | 31 | } 32 | 33 | void CommandMonitor::broadcast(std::string_view linkDescription, std::string_view printableString) { 34 | if(!active) return; 35 | 36 | std::scoped_lock lock(mtx); 37 | auto it = monitors.begin(); 38 | 39 | while(it != monitors.end()) { 40 | bool stillAlive = (*it)->appendIfAttached(Formatter::status(SSTR(linkDescription << ": " << printableString))); 41 | 42 | if(!stillAlive) { 43 | it = monitors.erase(it); 44 | } 45 | else { 46 | it++; 47 | } 48 | } 49 | 50 | if(monitors.size() == 0) active = false; 51 | } 52 | 53 | void CommandMonitor::broadcast(std::string_view linkDescription, const RedisRequest& req) { 54 | if(!active) return; 55 | return broadcast(linkDescription, req.toPrintableString()); 56 | } 57 | 58 | void CommandMonitor::broadcast(std::string_view linkDescription, const Transaction& transaction) { 59 | if(!active) return; 60 | if(transaction.size() == 1u) return broadcast(linkDescription, transaction[0].toPrintableString()); 61 | return broadcast(linkDescription, transaction.toPrintableString()); 62 | } 63 | 64 | void CommandMonitor::addRegistration(Connection *c) { 65 | std::scoped_lock lock(mtx); 66 | 67 | monitors.push_back(c->getQueue()); 68 | c->setMonitor(); 69 | active = true; 70 | } 71 | 72 | size_t CommandMonitor::size() { 73 | std::scoped_lock lock(mtx); 74 | return monitors.size(); 75 | } 76 | -------------------------------------------------------------------------------- /src/redis/CommandMonitor.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: CommandMonitor.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef QUARKDB_COMMAND_MONITOR_HH 25 | #define QUARKDB_COMMAND_MONITOR_HH 26 | 27 | #include "Connection.hh" 28 | #include 29 | 30 | namespace quarkdb { 31 | 32 | class Transaction; 33 | 34 | class CommandMonitor { 35 | public: 36 | CommandMonitor(); 37 | 38 | void broadcast(std::string_view linkDescription, const RedisRequest& received); 39 | void broadcast(std::string_view linkDescription, const Transaction& transaction); 40 | 41 | void addRegistration(Connection *c); 42 | size_t size(); 43 | 44 | private: 45 | void broadcast(std::string_view linkDescription, std::string_view printableString); 46 | 47 | std::atomic active {false}; 48 | std::mutex mtx; 49 | 50 | std::list> monitors; 51 | }; 52 | 53 | } 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /src/redis/InternalFilter.cc: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: InternalFilter.cc 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2018 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #include "redis/InternalFilter.hh" 25 | #include "RedisRequest.hh" 26 | using namespace quarkdb; 27 | 28 | void InternalFilter::process(RedisRequest &req) { 29 | switch(req.getCommand()) { 30 | case RedisCommand::TIMESTAMPED_LEASE_RELEASE: 31 | case RedisCommand::TIMESTAMPED_LEASE_ACQUIRE: 32 | case RedisCommand::TIMESTAMPED_LEASE_GET: { 33 | // Bad client, bad. No cookie for you. 34 | req.invalidate(); 35 | } 36 | default: { 37 | // All is good, do nothing. 38 | return; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/redis/InternalFilter.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: InternalFilter.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2018 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef QUARKDB_REDIS_INTERNAL_FILTER_HH 25 | #define QUARKDB_REDIS_INTERNAL_FILTER_HH 26 | 27 | namespace quarkdb { 28 | 29 | class RedisRequest; 30 | 31 | class InternalFilter { 32 | public: 33 | 34 | //---------------------------------------------------------------------------- 35 | // Invalidate commands which an end-user has no business emitting, such as 36 | // TIMESTAMPED_LEASE_GET, TIMESTAMPED_LEASE_ACQUIRE. These can only be 37 | // generated internally. 38 | //---------------------------------------------------------------------------- 39 | static void process(RedisRequest &req); 40 | }; 41 | 42 | } 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /src/redis/LeaseFilter.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: LeaseFilter.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef QUARKDB_REDIS_LEASE_FILTER_HH 25 | #define QUARKDB_REDIS_LEASE_FILTER_HH 26 | 27 | namespace quarkdb { 28 | 29 | class RedisRequest; 30 | class RedisEncodedResponse; 31 | class Transaction; 32 | 33 | using ClockValue = uint64_t; 34 | 35 | class LeaseFilter { 36 | public: 37 | 38 | //---------------------------------------------------------------------------- 39 | // Transform LEASE_GET and LEASE_ACQUIRE into TIMESTAMPED_LEASE_GET and 40 | // TIMESTAMPED_LEASE_ACQUIRE, respectively. 41 | //---------------------------------------------------------------------------- 42 | static void transform(RedisRequest &req, ClockValue timestamp); 43 | static void transform(Transaction &tx, ClockValue timestamp); 44 | }; 45 | 46 | } 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/redis/MultiHandler.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: MultiHandler.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef QUARKDB_REDIS_MULTIHANDLER_H 25 | #define QUARKDB_REDIS_MULTIHANDLER_H 26 | 27 | #include "redis/Transaction.hh" 28 | #include "redis/RedisEncodedResponse.hh" 29 | 30 | namespace quarkdb { 31 | 32 | class Dispatcher; class RedisRequest; class Connection; 33 | using LinkStatus = int; 34 | 35 | class MultiHandler { 36 | public: 37 | MultiHandler(); 38 | 39 | bool active() const; 40 | LinkStatus process(Dispatcher *dispatcher, Connection *conn, RedisRequest &req); 41 | void activatePhantom(); 42 | size_t size() const; 43 | bool isPhantom() const { return activated && transaction.isPhantom(); } 44 | LinkStatus finalizePhantomTransaction(Dispatcher *dispatcher, Connection *conn); 45 | 46 | private: 47 | Transaction transaction; 48 | bool activated = false; 49 | }; 50 | 51 | } 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/redis/RedisEncodedResponse.hh: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // File: RedisEncodedResponse.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef QUARKDB_REDIS_REDISENCODEDRESPONSE_H 25 | #define QUARKDB_REDIS_REDISENCODEDRESPONSE_H 26 | 27 | #include 28 | 29 | namespace quarkdb { 30 | 31 | // Phantom type: std::string with a special meaning. Unless explicitly asked 32 | // with obj.val, this will generate compiler errors when you try to use like 33 | // plain string. 34 | class RedisEncodedResponse { 35 | public: 36 | explicit RedisEncodedResponse(std::string &&src) : val(std::move(src)) {} 37 | RedisEncodedResponse() {} 38 | bool empty() const { return val.empty(); } 39 | std::string val; 40 | 41 | bool operator==(const RedisEncodedResponse &other) const { 42 | return val == other.val; 43 | } 44 | }; 45 | 46 | } 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/storage/ConsistencyScanner.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: ChecksumScanner.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef QUARKDB_CONSISTENCY_SCANNER_HH 25 | #define QUARKDB_CONSISTENCY_SCANNER_HH 26 | 27 | #include "utils/AssistedThread.hh" 28 | 29 | namespace quarkdb { 30 | 31 | class StateMachine; 32 | 33 | class ConsistencyScanner { 34 | public: 35 | ConsistencyScanner(StateMachine &stateMachine); 36 | void main(ThreadAssistant &assistant); 37 | void nextPass(ThreadAssistant &assistant); 38 | void singlePass(); 39 | 40 | static std::chrono::seconds obtainScanPeriod(StateMachine &stateMachine); 41 | static const std::chrono::seconds kDefaultPeriod; 42 | static const std::string kConfigurationKey; 43 | private: 44 | std::mutex mtx; 45 | StateMachine &stateMachine; 46 | AssistedThread thread; 47 | }; 48 | 49 | } 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/storage/ExpirationEventCache.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: ExpirationEventCache.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2020 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef QUARKDB_EXPIRATION_EVENT_CACHE_H 25 | #define QUARKDB_EXPIRATION_EVENT_CACHE_H 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | namespace quarkdb { 33 | 34 | using ClockValue = uint64_t; 35 | 36 | class ExpirationEventCache { 37 | public: 38 | ExpirationEventCache(); 39 | 40 | void insert(ClockValue cl, const std::string &leaseName); 41 | bool empty() const; 42 | void remove(ClockValue cl, const std::string &leaseName); 43 | size_t size() const; 44 | void clear(); 45 | 46 | ClockValue getFrontDeadline(); 47 | std::string getFrontLease(); 48 | void pop_front(); 49 | 50 | private: 51 | mutable std::mutex mMutex; 52 | std::multimap mContents; 53 | std::set mStoredLeases; 54 | }; 55 | 56 | } 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /src/storage/ExpirationEventIterator.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: ExpirationEventIterator.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2018 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef QUARKDB_EXPIRATION_EVENT_ITERATOR_H 25 | #define QUARKDB_EXPIRATION_EVENT_ITERATOR_H 26 | 27 | #include "StateMachine.hh" 28 | #include 29 | #include 30 | 31 | namespace quarkdb { 32 | 33 | class StagingArea; 34 | using ClockValue = uint64_t; 35 | 36 | class ExpirationEventIterator { 37 | public: 38 | ExpirationEventIterator(StagingArea &stagingArea); 39 | virtual ~ExpirationEventIterator(); 40 | 41 | bool valid(); 42 | void next(); 43 | 44 | ClockValue getDeadline(); 45 | std::string_view getRedisKey(); 46 | 47 | private: 48 | void assertDeadlineSanity(); 49 | 50 | StagingArea &stagingArea; 51 | ClockValue lastDeadline = 0; 52 | StateMachine::IteratorPtr iter; 53 | 54 | }; 55 | 56 | } 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /src/storage/InternalKeyParsing.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: InternalKeyParsing.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2019 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef QUARKDB_INTERNAL_KEY_PARSING_HH 25 | #define QUARKDB_INTERNAL_KEY_PARSING_HH 26 | 27 | #include 28 | 29 | namespace quarkdb { 30 | 31 | bool isTombstone(std::string_view internalKey); 32 | std::string getInternalKeyType(std::string_view internalKey); 33 | 34 | } 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/storage/KeyConstants.cc: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: KeyConstants.cc 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #include "KeyConstants.hh" 25 | 26 | #define ADD_TO_ALLKEYS(name) allKeys.push_back(name) 27 | 28 | namespace quarkdb { 29 | 30 | namespace KeyConstants { 31 | 32 | std::vector allKeys; 33 | 34 | class InitializeAllKeys { 35 | public: 36 | InitializeAllKeys() { 37 | // I wish there was a way to do this automatically.. 38 | ADD_TO_ALLKEYS(kJournal_CurrentTerm); 39 | ADD_TO_ALLKEYS(kJournal_LogSize); 40 | ADD_TO_ALLKEYS(kJournal_LogStart); 41 | ADD_TO_ALLKEYS(kJournal_ClusterID); 42 | ADD_TO_ALLKEYS(kJournal_VotedFor); 43 | ADD_TO_ALLKEYS(kJournal_CommitIndex); 44 | ADD_TO_ALLKEYS(kJournal_Members); 45 | ADD_TO_ALLKEYS(kJournal_MembershipEpoch); 46 | ADD_TO_ALLKEYS(kJournal_PreviousMembers); 47 | ADD_TO_ALLKEYS(kJournal_PreviousMembershipEpoch); 48 | ADD_TO_ALLKEYS(kJournal_FsyncPolicy); 49 | 50 | ADD_TO_ALLKEYS(kStateMachine_Format); 51 | ADD_TO_ALLKEYS(kStateMachine_LastApplied); 52 | ADD_TO_ALLKEYS(kStateMachine_InBulkload); 53 | ADD_TO_ALLKEYS(kStateMachine_Clock); 54 | } 55 | }; 56 | 57 | InitializeAllKeys initializer; 58 | 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/storage/KeyConstants.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: KeyConstants.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef QUARKDB_KEY_CONSTANTS_HH 25 | #define QUARKDB_KEY_CONSTANTS_HH 26 | 27 | #include 28 | #include 29 | 30 | namespace quarkdb { 31 | 32 | namespace KeyConstants { 33 | constexpr char kJournal_CurrentTerm[] = "RAFT_CURRENT_TERM"; 34 | constexpr char kJournal_LogSize[] = "RAFT_LOG_SIZE"; 35 | constexpr char kJournal_LogStart[] = "RAFT_LOG_START"; 36 | constexpr char kJournal_ClusterID[] = "RAFT_CLUSTER_ID"; 37 | constexpr char kJournal_VotedFor[] = "RAFT_VOTED_FOR"; 38 | constexpr char kJournal_CommitIndex[] = "RAFT_COMMIT_INDEX"; 39 | constexpr char kJournal_Members[] = "RAFT_MEMBERS"; 40 | constexpr char kJournal_MembershipEpoch[] = "RAFT_MEMBERSHIP_EPOCH"; 41 | constexpr char kJournal_PreviousMembers[] = "RAFT_PREVIOUS_MEMBERS"; 42 | constexpr char kJournal_PreviousMembershipEpoch[] = "RAFT_PREVIOUS_MEMBERSHIP_EPOCH"; 43 | constexpr char kJournal_FsyncPolicy[] = "RAFT_FSYNC_POLICY"; 44 | 45 | constexpr char kStateMachine_Format[] = "__format"; 46 | constexpr char kStateMachine_LastApplied[] = "__last-applied"; 47 | constexpr char kStateMachine_InBulkload[] = "__in-bulkload"; 48 | constexpr char kStateMachine_Clock[] = "__clock"; 49 | 50 | extern std::vector allKeys; 51 | }; 52 | 53 | 54 | } 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/storage/KeyDescriptorBuilder.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: DescriptorBuilder.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef QUARKDB_DESCRIPTOR_BUILDER_HH 25 | #define QUARKDB_DESCRIPTOR_BUILDER_HH 26 | 27 | #include 28 | 29 | namespace quarkdb { 30 | 31 | class StateMachine; 32 | 33 | // Scan the entire db contents after a bulkload to build the key descriptors. 34 | class KeyDescriptorBuilder { 35 | public: 36 | KeyDescriptorBuilder(StateMachine &stateMachine); 37 | private: 38 | 39 | 40 | }; 41 | 42 | } 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /src/storage/LeaseInfo.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: LeaseInfo.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2018 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef QUARKDB_LEASE_INFO_H 25 | #define QUARKDB_LEASE_INFO_H 26 | 27 | #include 28 | 29 | namespace quarkdb { 30 | 31 | using ClockValue = uint64_t; 32 | 33 | class LeaseInfo { 34 | public: 35 | LeaseInfo() {} 36 | 37 | LeaseInfo(std::string_view val, ClockValue ren, ClockValue dl) : 38 | value(val), lastRenewal(ren), deadline(dl) {} 39 | 40 | ClockValue getLastRenewal() const { 41 | return lastRenewal; 42 | } 43 | 44 | ClockValue getDeadline() const { 45 | return deadline; 46 | } 47 | 48 | std::string_view getValue() const { 49 | return value; 50 | } 51 | 52 | private: 53 | std::string value; 54 | ClockValue lastRenewal; 55 | ClockValue deadline; 56 | }; 57 | 58 | } 59 | #endif 60 | -------------------------------------------------------------------------------- /src/storage/PatternMatching.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: PatternMatching.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef QUARKDB_PATTERN_MATCHING_HH 25 | #define QUARKDB_PATTERN_MATCHING_HH 26 | 27 | #include 28 | 29 | namespace quarkdb { 30 | 31 | // Given a redis pattern, extract the maximum prefix which doesn't contain 32 | // special glob-style characters. The rationale behind this is that we can 33 | // efficiently rule out all keys inside RocksDB which don't start with this 34 | // prefix. 35 | 36 | inline std::string extractPatternPrefix(std::string_view pattern) { 37 | for(size_t i = 0; i < pattern.size(); i++) { 38 | char c = pattern[i]; 39 | 40 | if(c == '?' || c == '*' || c == '[' || c == ']' || c == '\\') { 41 | return std::string(pattern.begin(), pattern.begin()+i); 42 | } 43 | } 44 | 45 | // The entire thing doesn't contain special characters. 46 | // Kinda weird, as it can only match a single key, but possible 47 | return std::string(pattern); 48 | } 49 | 50 | } 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/storage/Randomization.cc: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: Randomization.cc 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #include "Randomization.hh" 25 | #include "../../deps/xxhash/xxhash.hh" 26 | 27 | namespace quarkdb { 28 | 29 | HashOutput64 getPseudoRandomTag(std::string_view key) { 30 | // Changing the seed will corrupt all existing fields which depend on 31 | // random tags. Don't do it. :) 32 | constexpr uint64_t kSeed = 0x1d7a6b7d; 33 | return XXH64(key.data(), key.size(), kSeed); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/storage/Randomization.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: Randomization.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef QUARKDB_STORAGE_RANDOMIZATION_HH 25 | #define QUARKDB_STORAGE_RANDOMIZATION_HH 26 | 27 | #include 28 | #include 29 | 30 | namespace quarkdb { 31 | 32 | using HashOutput64 = uint64_t; 33 | 34 | // The output of this function must be completely deterministic, meaning 35 | // the result 100% depends on the key. However, the result should be 36 | // random-looking bytes, and never-changing, regardless of the platform, 37 | // or endianness. We use xxhash for this. 38 | HashOutput64 getPseudoRandomTag(std::string_view key); 39 | 40 | } 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/storage/WriteStallWarner.cc: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: WriteStallWarner.cc 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2020 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #include "WriteStallWarner.hh" 25 | #include "utils/Macros.hh" 26 | #include 27 | 28 | namespace quarkdb { 29 | 30 | std::string stallConditionToString(const rocksdb::WriteStallCondition& cond) { 31 | if(cond == rocksdb::WriteStallCondition::kNormal) { 32 | return "normal"; 33 | } 34 | 35 | if(cond == rocksdb::WriteStallCondition::kDelayed) { 36 | return "delayed"; 37 | } 38 | 39 | if(cond == rocksdb::WriteStallCondition::kStopped) { 40 | return "stopped"; 41 | } 42 | 43 | return "???"; 44 | } 45 | 46 | //------------------------------------------------------------------------------ 47 | // Constructor 48 | //------------------------------------------------------------------------------ 49 | WriteStallWarner::WriteStallWarner(const std::string &name) 50 | : mName(name) {} 51 | 52 | //------------------------------------------------------------------------------ 53 | // Change in stall condition 54 | //------------------------------------------------------------------------------ 55 | void WriteStallWarner::OnStallConditionsChanged(const rocksdb::WriteStallInfo& info) { 56 | std::ostringstream ss; 57 | 58 | ss << "Change in write-stall condition (" << mName << "): " << stallConditionToString(info.condition.prev) << 59 | " => " << stallConditionToString(info.condition.cur); 60 | 61 | if(info.condition.cur != rocksdb::WriteStallCondition::kNormal) { 62 | qdb_warn(ss.str()); 63 | } 64 | else { 65 | qdb_info(ss.str()); 66 | } 67 | } 68 | 69 | } 70 | 71 | -------------------------------------------------------------------------------- /src/storage/WriteStallWarner.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: WriteStallWarner.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2020 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef QUARKDB_WRITE_STALL_WARNER_HH 25 | #define QUARKDB_WRITE_STALL_WARNER_HH 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | namespace quarkdb { 33 | 34 | //------------------------------------------------------------------------------ 35 | // Describes updates during a single revision for a specific versioned hash. 36 | //------------------------------------------------------------------------------ 37 | class WriteStallWarner : public rocksdb::EventListener { 38 | public: 39 | 40 | //---------------------------------------------------------------------------- 41 | // Constructor 42 | //---------------------------------------------------------------------------- 43 | WriteStallWarner(const std::string &name); 44 | 45 | //---------------------------------------------------------------------------- 46 | // Change in stall condition 47 | //---------------------------------------------------------------------------- 48 | virtual void OnStallConditionsChanged(const rocksdb::WriteStallInfo& /*info*/) override; 49 | 50 | private: 51 | std::string mName; 52 | }; 53 | 54 | } 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/utils/FileUtils.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: FileUtils.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef __QUARKDB_FILE_UTILS_H__ 25 | #define __QUARKDB_FILE_UTILS_H__ 26 | 27 | #include 28 | #include "../Status.hh" 29 | 30 | namespace quarkdb { 31 | 32 | std::string pathJoin(std::string_view part1, std::string_view part2); 33 | bool mkpath(const std::string &path, mode_t mode, std::string &err); 34 | void mkpath_or_die(const std::string &path, mode_t mode); 35 | bool directoryExists(const std::string &path, std::string &err); 36 | bool fileExists(const std::string &path, std::string &err); 37 | bool readFile(FILE *f, std::string &contents); 38 | bool readFile(const std::string &path, std::string &contents); 39 | bool write_file(std::string_view path, std::string_view contents, std::string &err); 40 | void write_file_or_die(std::string_view path, std::string_view contents); 41 | void rename_directory_or_die(const std::string &source, const std::string &destination); 42 | bool areFilePermissionsSecure(mode_t mode); 43 | bool readPasswordFile(const std::string &path, std::string &contents); 44 | bool countFilesInDirectoryRecursively(const std::string &path, std::string &err, size_t &nfiles); 45 | Status ensureSameFilesystem(std::string_view path1, std::string_view path2); 46 | 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /src/utils/FsyncThread.cc: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: FsyncThread.cc 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #include "utils/FsyncThread.hh" 25 | #include "utils/Macros.hh" 26 | #include 27 | 28 | namespace quarkdb { 29 | 30 | //------------------------------------------------------------------------------ 31 | // Construct FsyncThread object to fsync the given rocksdb every T 32 | //------------------------------------------------------------------------------ 33 | FsyncThread::FsyncThread(rocksdb::DB *db, std::chrono::milliseconds p) 34 | : mDB(db), mPeriod(p) { 35 | 36 | mThread.reset(&FsyncThread::main, this); 37 | } 38 | 39 | //------------------------------------------------------------------------------ 40 | // Destructor 41 | //------------------------------------------------------------------------------ 42 | FsyncThread::~FsyncThread() {} 43 | 44 | //------------------------------------------------------------------------------ 45 | // Main 46 | //------------------------------------------------------------------------------ 47 | void FsyncThread::main(ThreadAssistant &assistant) { 48 | while(true) { 49 | assistant.wait_for(mPeriod); 50 | if(assistant.terminationRequested()) return; 51 | 52 | rocksdb::Status st = mDB->SyncWAL(); 53 | if(!st.ok()) { 54 | qdb_throw("Syncing rocksdb WAL failed: " << st.ToString()); 55 | } 56 | } 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/utils/FsyncThread.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: FsyncThread.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2020 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #include "utils/AssistedThread.hh" 25 | #include 26 | 27 | namespace rocksdb { 28 | class DB; 29 | } 30 | 31 | namespace quarkdb { 32 | 33 | class FsyncThread { 34 | public: 35 | //---------------------------------------------------------------------------- 36 | // Construct FsyncThread object to fsync the given rocksdb every T 37 | //---------------------------------------------------------------------------- 38 | FsyncThread(rocksdb::DB *db, std::chrono::milliseconds p); 39 | 40 | //---------------------------------------------------------------------------- 41 | // Destructor 42 | //---------------------------------------------------------------------------- 43 | ~FsyncThread(); 44 | 45 | private: 46 | //---------------------------------------------------------------------------- 47 | // Main 48 | //---------------------------------------------------------------------------- 49 | void main(ThreadAssistant &assistant); 50 | 51 | rocksdb::DB *mDB; 52 | std::chrono::milliseconds mPeriod; 53 | 54 | AssistedThread mThread; 55 | }; 56 | 57 | } -------------------------------------------------------------------------------- /src/utils/ParseUtils.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: ParsingUtils.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef QUARKDB_PARSING_UTILS_HH 25 | #define QUARKDB_PARSING_UTILS_HH 26 | 27 | #include "Utils.hh" 28 | 29 | #include 30 | 31 | namespace quarkdb { namespace ParseUtils { 32 | 33 | inline std::vector split(std::string data, const std::string &token) { 34 | std::vector output; 35 | size_t pos = std::string::npos; 36 | do { 37 | pos = data.find(token); 38 | output.push_back(data.substr(0, pos)); 39 | if(std::string::npos != pos) { 40 | data = data.substr(pos + token.size()); 41 | } 42 | } while (std::string::npos != pos); 43 | return output; 44 | } 45 | 46 | inline bool parseInt64(std::string_view str, int64_t &ret) { 47 | char *endptr = NULL; 48 | ret = strtoll(str.data(), &endptr, 10); 49 | if(endptr != str.data() + str.size() || ret == LLONG_MIN || ret == LONG_LONG_MAX) { 50 | return false; 51 | } 52 | return true; 53 | } 54 | 55 | inline bool parseIntegerList(const std::string &buffer, const std::string &separator, std::vector &results) { 56 | results.clear(); 57 | 58 | std::vector items = ParseUtils::split(buffer, separator); 59 | 60 | for(size_t i = 0; i < items.size(); i++) { 61 | int64_t value; 62 | if(!ParseUtils::parseInt64(items[i], value)) { 63 | return false; 64 | } 65 | 66 | results.emplace_back(value); 67 | } 68 | 69 | return true; 70 | } 71 | 72 | } } 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /src/utils/Random.cc: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: Random.cc 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #include "Random.hh" 25 | #include "Macros.hh" 26 | #include 27 | 28 | namespace quarkdb { 29 | 30 | std::string generateSecureRandomBytes(size_t nbytes) { 31 | char buffer[nbytes + 1]; 32 | 33 | // We might want to keep a pool of open "/dev/urandom" on standby, to avoid 34 | // opening and closing /dev/urandom too often, but meh, this'll do for now. 35 | 36 | FILE *in = fopen("/dev/urandom", "rb"); 37 | 38 | if(!in) qdb_throw("unable to open /dev/urandom"); 39 | 40 | size_t bytes_read = fread(buffer, 1, nbytes, in); 41 | qdb_assert(bytes_read == nbytes); 42 | qdb_assert(fclose(in) == 0); 43 | 44 | return std::string(buffer, nbytes); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/utils/Random.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: Random.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef QUARKDB_RANDOM_H 25 | #define QUARKDB_RANDOM_H 26 | 27 | #include 28 | 29 | namespace quarkdb { 30 | 31 | std::string generateSecureRandomBytes(size_t nbytes); 32 | 33 | } 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /src/utils/RequestCounter.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: RequestCounter.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef QUARKDB_REQUEST_COUNTER_HH 25 | #define QUARKDB_REQUEST_COUNTER_HH 26 | 27 | #include "utils/AssistedThread.hh" 28 | #include "utils/Statistics.hh" 29 | #include 30 | 31 | namespace quarkdb { 32 | 33 | class Transaction; 34 | class RedisRequest; 35 | class Statistics; 36 | 37 | //------------------------------------------------------------------------------ 38 | // Count what types of requests we've been servicing, and reports statistics 39 | // every few seconds. 40 | //------------------------------------------------------------------------------ 41 | 42 | class RequestCounter { 43 | public: 44 | RequestCounter(std::chrono::seconds interval); 45 | 46 | void account(const Transaction &transaction); 47 | void mainThread(ThreadAssistant &assistant); 48 | 49 | void setReportingStatus(bool val); 50 | void account(const RedisRequest &req); 51 | 52 | Statistics getOverallStats(); 53 | 54 | void fillHistorical(std::vector &headers, 55 | std::vector> &data); 56 | 57 | private: 58 | void account(const RedisRequest &req, Statistics *stats); 59 | 60 | std::string toRate(int64_t val); 61 | StatAggregator aggregator; 62 | 63 | bool paused = true; 64 | std::atomic activated {true}; 65 | 66 | std::chrono::seconds interval; 67 | HistoricalStatistics historical; 68 | AssistedThread thread; 69 | }; 70 | 71 | } 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /src/utils/Resilvering.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: Resilvering.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef __QUARKDB_RESILVERING_H__ 25 | #define __QUARKDB_RESILVERING_H__ 26 | 27 | #include 28 | #include 29 | 30 | using ResilveringEventID = std::string; 31 | 32 | class ResilveringEvent { 33 | public: 34 | ResilveringEvent(); 35 | ResilveringEvent(const ResilveringEventID &id, time_t finalized); 36 | 37 | ResilveringEventID getID() const; 38 | time_t getStartTime() const; 39 | 40 | std::string serialize() const; 41 | static bool deserialize(const std::string &str, ResilveringEvent &); 42 | 43 | bool operator==(const ResilveringEvent& rhs) const; 44 | private: 45 | ResilveringEventID id; 46 | time_t startTime; 47 | }; 48 | 49 | class ResilveringHistory { 50 | public: 51 | ResilveringHistory(); 52 | 53 | void append(const ResilveringEvent &event); 54 | size_t size() const; 55 | const ResilveringEvent& at(size_t i) const; 56 | 57 | std::string serialize() const; 58 | static bool deserialize(const std::string &str, ResilveringHistory &hist); 59 | void clear(); 60 | 61 | bool operator==(const ResilveringHistory& rhs) const; 62 | private: 63 | mutable std::mutex mtx; 64 | std::vector events; 65 | }; 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /src/utils/ScopedAdder.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: ScopedAdder.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef __QUARKDB_SCOPED_ADDER_H__ 25 | #define __QUARKDB_SCOPED_ADDER_H__ 26 | 27 | namespace quarkdb { 28 | 29 | template 30 | class ScopedAdder { 31 | public: 32 | ScopedAdder(std::atomic &target_, T value_ = 1) : target(target_), value(value_) { 33 | target += value; 34 | } 35 | 36 | ~ScopedAdder() { 37 | target -= value; 38 | } 39 | 40 | private: 41 | std::atomic ⌖ 42 | T value; 43 | }; 44 | 45 | } 46 | 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/utils/Stacktrace.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: Stacktrace.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef __QUARKDB_UTILS_STACKTRACE_H__ 25 | #define __QUARKDB_UTILS_STACKTRACE_H__ 26 | 27 | #define BACKWARD_HAS_DW 1 28 | 29 | #include 30 | 31 | namespace quarkdb { 32 | 33 | inline std::string getStacktrace() { 34 | std::ostringstream ss; 35 | 36 | backward::StackTrace st; st.load_here(32); 37 | backward::Printer p; 38 | p.object = true; 39 | p.color_mode = backward::ColorMode::always; 40 | p.address = true; 41 | p.print(st, ss); 42 | 43 | return ss.str(); 44 | } 45 | 46 | } 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/utils/StaticBuffer.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: StaticBuffer.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef QUARKDB_UTILS_STATIC_BUFFER_HH 25 | #define QUARKDB_UTILS_STATIC_BUFFER_HH 26 | 27 | #include "Utils.hh" 28 | #include 29 | 30 | namespace quarkdb { 31 | 32 | template 33 | class StaticBuffer { 34 | public: 35 | StaticBuffer() {} 36 | 37 | char* data() { 38 | return contents; 39 | } 40 | 41 | size_t size() { 42 | return runtime_size; 43 | } 44 | 45 | std::string_view toView() { 46 | return std::string_view(data(), size()); 47 | } 48 | 49 | void shrink(size_t newsize) { 50 | qdb_assert(newsize <= static_size); 51 | runtime_size = newsize; 52 | } 53 | 54 | char& operator[](size_t i) { 55 | return contents[i]; 56 | } 57 | 58 | private: 59 | char contents[static_size]; 60 | size_t runtime_size = static_size; 61 | }; 62 | 63 | 64 | } 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /src/utils/Synchronized.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: Synchronized.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2019 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef QUARKDB_SYNCHRONIZED_HH 25 | #define QUARKDB_SYNCHRONIZED_HH 26 | 27 | #include 28 | 29 | namespace quarkdb { 30 | 31 | template 32 | class Synchronized { 33 | public: 34 | Synchronized(const T& t) {} 35 | 36 | Synchronized() {} 37 | 38 | template 39 | void set(Args&& ... args) { 40 | std::unique_lock lock(mtx); 41 | contents = T(std::forward(args)...); 42 | } 43 | 44 | T get() const { 45 | std::shared_lock lock(mtx); 46 | return contents; 47 | } 48 | 49 | private: 50 | T contents; 51 | mutable std::shared_mutex mtx; 52 | }; 53 | 54 | } 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/utils/TimeFormatting.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: TimeFormatting.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef QUARKDB_TIME_FORMATTING_HH 25 | #define QUARKDB_TIME_FORMATTING_HH 26 | 27 | #include 28 | #include 29 | 30 | namespace quarkdb { 31 | 32 | using Days = std::chrono::duration>; 33 | using Months = std::chrono::duration>; 34 | using Years = std::chrono::duration>; 35 | 36 | std::string formatTime(const std::chrono::seconds &totalSeconds); 37 | 38 | } 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/utils/Uuid.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: Uuid.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef __QUARKDB_UUID_H__ 25 | #define __QUARKDB_UUID_H__ 26 | 27 | #include 28 | 29 | namespace quarkdb { 30 | 31 | inline std::string generateUuid() { 32 | char buffer[64]; 33 | 34 | uuid_t uuid; 35 | uuid_generate_random(uuid); 36 | uuid_unparse(uuid, buffer); 37 | 38 | return std::string(buffer); 39 | } 40 | 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /src/utils/VectorUtils.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: VectorUtils.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef __QUARKDB_VECTOR_UTILS_H__ 25 | #define __QUARKDB_VECTOR_UTILS_H__ 26 | 27 | namespace quarkdb { namespace VectorUtils { 28 | 29 | template 30 | bool checkEquality(const T& one, const T& two) { 31 | if(one.size() != two.size()) return false; 32 | 33 | for(size_t i = 0; i < one.size(); i++) { 34 | // Using != would be more natural here, but most classes 35 | // only define operator== 36 | if(one[i] == two[i]) continue; 37 | return false; 38 | } 39 | 40 | return true; 41 | } 42 | 43 | template 44 | void appendToVector(std::vector &target, const std::vector &source) { 45 | for(size_t i = 0; i < source.size(); i++) { 46 | target.emplace_back(source[i]); 47 | } 48 | } 49 | 50 | } } 51 | 52 | 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /test/bench-malloc/interceptor.cc: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: interceptor.cc 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | //------------------------------------------------------------------------------ 31 | // This is used to intercept malloc and friends to keep track of how many 32 | // allocations have occurred so far. 33 | //------------------------------------------------------------------------------ 34 | 35 | std::atomic allocationCount {0}; 36 | std::atomic freeCount {0}; 37 | 38 | typedef void* (*malloc_type)(size_t); 39 | typedef void (*free_type)(void*); 40 | 41 | int64_t getAllocationCount() { 42 | return allocationCount; 43 | } 44 | 45 | int64_t getFreeCount() { 46 | return freeCount; 47 | } 48 | 49 | extern void* malloc(size_t size) { 50 | allocationCount++; 51 | malloc_type real_malloc = (malloc_type)dlsym(RTLD_NEXT, "malloc"); 52 | return real_malloc(size); 53 | } 54 | 55 | extern void free(void* ptr) { 56 | freeCount++; 57 | free_type real_free = (free_type)dlsym(RTLD_NEXT, "free"); 58 | return real_free(ptr); 59 | } 60 | -------------------------------------------------------------------------------- /test/bench-malloc/interceptor.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: interceptor.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef __QUARKDB_BENCH_MALLOC_INTERCEPTOR_H__ 25 | #define __QUARKDB_BENCH_MALLOC_INTERCEPTOR_H__ 26 | 27 | #include 28 | 29 | int64_t getAllocationCount(); 30 | int64_t getFreeCount(); 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /test/bench-malloc/main.cc: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: main.cc 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #include 25 | #include "../config/test-config.hh" 26 | #include "Link.hh" 27 | using namespace quarkdb; 28 | 29 | int main(int argc, char **argv) { 30 | printf("Running main() from bench-mallocs/main.cc\n"); 31 | testconfig.raftTimeouts.setStatic(defaultTimeouts); 32 | Link::setConnectionLogging(false); 33 | testing::InitGoogleTest(&argc, argv); 34 | return RUN_ALL_TESTS(); 35 | } 36 | -------------------------------------------------------------------------------- /test/bench-malloc/measure.cc: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: measure.cc 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #include "interceptor.hh" 25 | #include 26 | #include "../test-utils.hh" 27 | #include 28 | #include "../test-reply-macros.hh" 29 | 30 | using namespace quarkdb; 31 | using namespace qclient; 32 | class AllocationCount : public TestCluster3NodesFixture {}; 33 | 34 | TEST_F(AllocationCount, 300k_entries) { 35 | spinup(0); spinup(1); spinup(2); 36 | RETRY_ASSERT_TRUE(checkStateConsensus(0, 1, 2)); 37 | int leaderID = getLeaderID(); 38 | 39 | int64_t startAllocations = getAllocationCount(); 40 | int64_t startFrees = getFreeCount(); 41 | 42 | std::vector> futures; 43 | 44 | constexpr int64_t NENTRIES = 300000; 45 | for(size_t i = 0; i < NENTRIES; i++) { 46 | futures.emplace_back(tunnel(leaderID)->exec("set", SSTR("key-" << i), SSTR("value-------------------------------------------------------------------" << i))); 47 | } 48 | 49 | for(size_t i = 0; i < futures.size(); i++) { 50 | ASSERT_REPLY(futures[i], "OK"); 51 | } 52 | 53 | int64_t endAllocations = getAllocationCount(); 54 | int64_t endFrees = getFreeCount(); 55 | 56 | int64_t diffAllocations = endAllocations - startAllocations; 57 | int64_t diffFrees = endFrees - startFrees; 58 | 59 | qdb_info("-------------------- Allocations per entry: " << (double) diffAllocations / (double) NENTRIES); 60 | qdb_info("-------------------- Frees per entry: " << (double) diffFrees / (double) NENTRIES); 61 | } 62 | -------------------------------------------------------------------------------- /test/bench/bench-utils.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: bench-utils.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef __QUARKDB_BENCH_UTILS_H__ 25 | #define __QUARKDB_BENCH_UTILS_H__ 26 | 27 | #include 28 | 29 | namespace quarkdb { 30 | 31 | class Stopwatch { 32 | public: 33 | Stopwatch(size_t events) 34 | : nevents(events) { 35 | start(); 36 | } 37 | 38 | void start() { 39 | startTime = std::chrono::high_resolution_clock::now(); 40 | } 41 | 42 | void stop() { 43 | endTime = std::chrono::high_resolution_clock::now(); 44 | } 45 | 46 | float spotRate(size_t eventsThusFar) { 47 | std::chrono::high_resolution_clock::time_point now = std::chrono::high_resolution_clock::now(); 48 | auto duration = std::chrono::duration_cast(now - startTime).count(); 49 | return (float) eventsThusFar / ((float) duration / (float) 1000); 50 | } 51 | 52 | // returns rate in Hz 53 | float rate() { 54 | auto duration = std::chrono::duration_cast(endTime - startTime).count(); 55 | return (float) nevents / ((float) duration / (float) 1000); 56 | } 57 | 58 | private: 59 | size_t nevents; 60 | std::chrono::high_resolution_clock::time_point startTime; 61 | std::chrono::high_resolution_clock::time_point endTime; 62 | }; 63 | 64 | } 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /test/bench/main.cc: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: main.cc 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #include 25 | #include "../config/test-config.hh" 26 | #include "Link.hh" 27 | using namespace quarkdb; 28 | 29 | int main(int argc, char **argv) { 30 | printf("Running main() from bench/main.cc\n"); 31 | testconfig.raftTimeouts.setStatic(defaultTimeouts); 32 | testconfig.databaseReuse.setStatic(false); 33 | testing::InitGoogleTest(&argc, argv); 34 | Link::setConnectionLogging(false); 35 | return RUN_ALL_TESTS(); 36 | } 37 | -------------------------------------------------------------------------------- /test/clock-wrapper.cc: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: clock-wrapper.cc 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #include "utils/ClockWrapper.hh" 25 | #include 26 | 27 | using namespace quarkdb; 28 | 29 | TEST(ClockWrapper, Steady) { 30 | SteadyClock steadyClock(true); 31 | ASSERT_TRUE(steadyClock.fake()); 32 | ASSERT_EQ(steadyClock.now(), SteadyClock::time_point()); 33 | ASSERT_TRUE(SteadyClock::is_steady); 34 | 35 | SteadyClock::time_point startOfTime; 36 | steadyClock.advance(std::chrono::seconds(5)); 37 | ASSERT_EQ(steadyClock.now(), startOfTime+std::chrono::seconds(5)); 38 | 39 | steadyClock.advance(std::chrono::seconds(10)); 40 | ASSERT_EQ(steadyClock.now(), startOfTime+std::chrono::seconds(15)); 41 | } 42 | 43 | TEST(ClockWrapper, System) { 44 | SystemClock systemClock(true); 45 | ASSERT_TRUE(systemClock.fake()); 46 | 47 | ASSERT_EQ(systemClock.now(), SystemClock::time_point()); 48 | ASSERT_FALSE(SystemClock::is_steady); 49 | 50 | SystemClock::time_point startOfTime; 51 | systemClock.advance(std::chrono::seconds(5)); 52 | ASSERT_EQ(systemClock.now(), startOfTime+std::chrono::seconds(5)); 53 | 54 | systemClock.advance(std::chrono::seconds(10)); 55 | ASSERT_EQ(systemClock.now(), startOfTime+std::chrono::seconds(15)); 56 | 57 | systemClock.set(startOfTime+std::chrono::seconds(1)); // go backwards 58 | ASSERT_EQ(systemClock.now(), startOfTime+std::chrono::seconds(1)); 59 | } 60 | -------------------------------------------------------------------------------- /test/main.cc: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: init.cc 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #include 25 | #include "config/test-config.hh" 26 | #include "Utils.hh" 27 | #include "Link.hh" 28 | using namespace quarkdb; 29 | 30 | int main(int argc, char **argv) { 31 | printf("Running main() from main.cc\n"); 32 | testing::InitGoogleTest(&argc, argv); 33 | setStacktraceOnError(false); 34 | Link::setConnectionLogging(false); 35 | return RUN_ALL_TESTS(); 36 | } 37 | -------------------------------------------------------------------------------- /test/stress/main.cc: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: init.cc 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #include 25 | #include "../config/test-config.hh" 26 | #include "Utils.hh" 27 | #include "Link.hh" 28 | using namespace quarkdb; 29 | 30 | int main(int argc, char **argv) { 31 | printf("Running main() from stress/main.cc\n"); 32 | testconfig.raftTimeouts.setStatic(defaultTimeouts); 33 | testconfig.databaseReuse.setStatic(false); 34 | testing::InitGoogleTest(&argc, argv); 35 | setStacktraceOnError(false); 36 | Link::setConnectionLogging(false); 37 | return RUN_ALL_TESTS(); 38 | } 39 | -------------------------------------------------------------------------------- /test/sudo/main.cc: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: main.cc 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2020 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #include 25 | #include "../config/test-config.hh" 26 | #include "Utils.hh" 27 | #include "Link.hh" 28 | using namespace quarkdb; 29 | 30 | int main(int argc, char **argv) { 31 | printf("Running main() from stress/main.cc\n"); 32 | testconfig.raftTimeouts.setStatic(defaultTimeouts); 33 | testconfig.databaseReuse.setStatic(false); 34 | testing::InitGoogleTest(&argc, argv); 35 | setStacktraceOnError(false); 36 | Link::setConnectionLogging(false); 37 | return RUN_ALL_TESTS(); 38 | } 39 | -------------------------------------------------------------------------------- /test/sudo/poweroff.cc: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: poweroff.cc 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2019 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #include "../test-utils.hh" 25 | #include "../test-reply-macros.hh" 26 | #include 27 | #include 28 | 29 | using namespace quarkdb; 30 | class Poweroff : public TestCluster3NodesFixture {}; 31 | 32 | TEST_F(Poweroff, WithDataLoss) { 33 | IptablesHelper iptables; 34 | 35 | ASSERT_TRUE(iptables.singleAcceptPackets(nodes()[0].port)); 36 | ASSERT_TRUE(iptables.singleAcceptPackets(nodes()[1].port)); 37 | ASSERT_TRUE(iptables.singleAcceptPackets(nodes()[2].port)); 38 | 39 | spinup(0); spinup(1); spinup(2); 40 | RETRY_ASSERT_TRUE(checkStateConsensus(0, 1, 2)); 41 | 42 | int leaderID = getLeaderID(); 43 | 44 | std::vector> vec; 45 | for(size_t i = 0; i < 10000; i++) { 46 | vec.emplace_back(tunnel(leaderID)->exec("set", SSTR("key-" << i), SSTR("value-" << i))); 47 | } 48 | 49 | for(size_t i = 0; i < 10000; i++) { 50 | ASSERT_REPLY_DESCRIBE(vec[i].get(), "OK"); 51 | } 52 | 53 | int follower = (leaderID + 1) % 3; 54 | int followerPort = nodes()[follower].port; 55 | 56 | ASSERT_TRUE(iptables.singleDropPackets(followerPort)); 57 | spindown(follower); 58 | 59 | ASSERT_TRUE(journal(follower)->simulateDataLoss(3)); 60 | ASSERT_EQ(journal(follower)->getLogSize(), journal(leaderID)->getLogSize() - 3); 61 | 62 | ASSERT_TRUE(iptables.singleAcceptPackets(followerPort)); 63 | spinup(follower); 64 | 65 | // ensure the leader restores the missing entries 66 | RETRY_ASSERT_EQ(journal(follower)->getLogSize(), journal(leaderID)->getLogSize()); 67 | } 68 | 69 | -------------------------------------------------------------------------------- /tools/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | find_package (Threads) 3 | 4 | add_executable(quarkdb-create quarkdb-create.cc) 5 | target_link_libraries(quarkdb-create XrdQuarkDB) 6 | 7 | add_executable(quarkdb-ldb quarkdb-ldb.cc) 8 | target_link_libraries(quarkdb-ldb XrdQuarkDB ${CMAKE_THREAD_LIBS_INIT}) 9 | 10 | add_executable(quarkdb-recovery quarkdb-recovery.cc) 11 | target_link_libraries(quarkdb-recovery XrdQuarkDB ${CMAKE_THREAD_LIBS_INIT} ) 12 | 13 | add_executable(quarkdb-server quarkdb-server.cc) 14 | target_link_libraries(quarkdb-server jemalloc XrdQuarkDB ${CMAKE_THREAD_LIBS_INIT} ) 15 | 16 | add_executable(quarkdb-sst-inspect quarkdb-sst-inspect.cc) 17 | target_link_libraries(quarkdb-sst-inspect XrdQuarkDB ${CMAKE_THREAD_LIBS_INIT} ) 18 | 19 | add_executable(quarkdb-validate-checkpoint quarkdb-validate-checkpoint.cc) 20 | target_link_libraries(quarkdb-validate-checkpoint XrdQuarkDB ${CMAKE_THREAD_LIBS_INIT} ) 21 | 22 | include_directories( 23 | ${XROOTD_INCLUDE_DIRS} 24 | ${CMAKE_SOURCE_DIR}/src # need access to the private headers 25 | ${CMAKE_SOURCE_DIR}/deps # for optionparser.h 26 | ${ROCKSDB_INCLUDE_DIRS} 27 | ${CMAKE_SOURCE_DIR}/deps/qclient/include 28 | ${CMAKE_SOURCE_DIR}/deps/asio/asio/include 29 | ${CMAKE_SOURCE_DIR}/deps/CLI11/include 30 | ) 31 | 32 | install( 33 | TARGETS quarkdb-create quarkdb-ldb quarkdb-recovery quarkdb-server quarkdb-sst-inspect quarkdb-validate-checkpoint 34 | RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR} 35 | ) 36 | -------------------------------------------------------------------------------- /tools/TestUtils.hh: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: TestUtils.hh 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2016 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #ifndef __QUARKDB_TEST_UTILS_HH 25 | #define __QUARKDB_TEST_UTILS_HH 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | class Cache { 32 | public: 33 | int64_t get(const std::string &key) { 34 | std::scoped_lock lock(mtx); 35 | return earliestAcceptable[key]; 36 | } 37 | 38 | void put(const std::string &key, int64_t update) { 39 | std::scoped_lock lock(mtx); 40 | 41 | int64_t current = earliestAcceptable[key]; 42 | if(current <= update) { 43 | earliestAcceptable[key] = update; 44 | } 45 | } 46 | 47 | private: 48 | std::mutex mtx; 49 | std::map earliestAcceptable; 50 | }; 51 | 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /tools/quarkdb-ldb.cc: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: quarkdb-ldb.cc 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2020 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #include "recovery/RecoveryRunner.hh" 25 | 26 | int main(int argc, char** argv) { 27 | quarkdb::RecoveryRunner::LdbTool(argc, argv); 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /tools/quarkdb-sst-inspect.cc: -------------------------------------------------------------------------------- 1 | // ---------------------------------------------------------------------- 2 | // File: quarkdb-sst-inspect.cc 3 | // Author: Georgios Bitzes - CERN 4 | // ---------------------------------------------------------------------- 5 | 6 | /************************************************************************ 7 | * quarkdb - a redis-like highly available key-value store * 8 | * Copyright (C) 2019 CERN/Switzerland * 9 | * * 10 | * This program is free software: you can redistribute it and/or modify * 11 | * it under the terms of the GNU General Public License as published by * 12 | * the Free Software Foundation, either version 3 of the License, or * 13 | * (at your option) any later version. * 14 | * * 15 | * This program is distributed in the hope that it will be useful, * 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 18 | * GNU General Public License for more details. * 19 | * * 20 | * You should have received a copy of the GNU General Public License * 21 | * along with this program. If not, see .* 22 | ************************************************************************/ 23 | 24 | #include "recovery/RecoveryRunner.hh" 25 | 26 | int main(int argc, char** argv) { 27 | quarkdb::RecoveryRunner::DumpTool(argc, argv); 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /utils/el7-packages.sh: -------------------------------------------------------------------------------- 1 | yum install -y cmake3 2 | yum install -y xrootd xrootd-devel xrootd-server-devel xrootd-private-devel 3 | yum install -y bzip2-devel 4 | -------------------------------------------------------------------------------- /utils/tsan-suppressions.txt: -------------------------------------------------------------------------------- 1 | # It appears tsan generates false positives with rocksdb's 2 | # lockless memtable.. Ignore hits in rocksdb, and certain 3 | # functions where we write into it. (as it appears certain 4 | # things get inlined, and tsan can't determine it's rocksdb 5 | # code) 6 | 7 | race:rocksdb 8 | race:RaftJournal::set_int_or_die 9 | race:RaftJournal::setCurrentTerm 10 | race:RaftJournal::appendNoLock 11 | race:StateMachine::configGet 12 | race:RaftReplicaTracker::buildPayload 13 | race:RaftWriteTracker::applySingleCommit 14 | race:RaftJournal::fetch 15 | -------------------------------------------------------------------------------- /utils/ubuntu-asan.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -ex 3 | 4 | apt update 5 | apt install -y git g++ cmake zlib1g-dev openssl libssl-dev python libbz2-dev lcov uuid-dev 6 | 7 | git submodule update --init --recursive 8 | 9 | # Build xrootd, use cache if available 10 | if [[ "$XRD_BUILD" == "" ]]; then 11 | XRD_BUILD=$PWD/xrootd 12 | fi 13 | 14 | if [ ! "$(ls -A $XRD_BUILD)" ]; then 15 | mkdir -p $XRD_BUILD 16 | pushd $XRD_BUILD 17 | rm -rf xrootd 18 | git clone https://github.com/xrootd/xrootd 19 | pushd xrootd 20 | git checkout v4.8.4 21 | mkdir build && pushd build 22 | 23 | XRD_INSTALL=$PWD/install 24 | cmake .. -DCMAKE_INSTALL_PREFIX=$XRD_INSTALL && make 25 | make install 26 | popd; popd; popd 27 | fi 28 | XRD_INSTALL="$XRD_BUILD/xrootd/build/install" 29 | 30 | # Build QuarkDB 31 | rm -rf build 32 | mkdir build && pushd build 33 | CXXFLAGS='-fsanitize=address' cmake -DTESTCOVERAGE=ON -DXROOTD_ROOT_DIR=$XRD_INSTALL -DLIBRARY_PATH_PREFIX=lib .. 34 | make 35 | ./test/quarkdb-tests 36 | ./test/quarkdb-stress-tests 37 | make coverage-report 38 | --------------------------------------------------------------------------------