holt 0.3.1

An adaptive-radix-tree metadata storage engine for path-shaped keys, with per-blob concurrency and crash-safe persistence.
Documentation
name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

env:
  CARGO_TERM_COLOR: always
  CARGO_INCREMENTAL: "0"

jobs:
  # --------------------------------------------------------------
  # Build + test the library + examples + integration tests on
  # the two Tier-1 Unix targets holt supports today.
  # --------------------------------------------------------------
  test:
    name: test (${{ matrix.os }})
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, macos-latest]
    steps:
      - uses: actions/checkout@v6

      # `rocksdb` is a dev-dependency (criterion bench harness pulls
      # it in for the apples-to-apples comparison). Its C++ build
      # needs libclang + LLVM headers.
      - name: Install LLVM (Ubuntu)
        if: runner.os == 'Linux'
        run: sudo apt-get update && sudo apt-get install -y clang libclang-dev

      - name: Install LLVM (macOS)
        if: runner.os == 'macOS'
        run: |
          brew install llvm
          echo "LIBCLANG_PATH=$(brew --prefix llvm)/lib" >> "$GITHUB_ENV"

      - uses: dtolnay/rust-toolchain@stable
        with:
          components: rustfmt, clippy

      - name: Cache cargo registry + build
        uses: Swatinem/rust-cache@v2

      - name: cargo build
        run: cargo build --workspace --all-targets --all-features --locked

      - name: cargo test (lib + integration)
        run: cargo test --workspace --all-features --lib --tests --examples --locked

      - name: cargo test (doctests)
        run: cargo test --workspace --all-features --doc --locked

      - name: cargo run --example basic_kv
        run: cargo run --example basic_kv --locked

      - name: cargo run --example filesystem_meta
        run: cargo run --example filesystem_meta --locked

      - name: cargo run --example session_store
        run: cargo run --example session_store --locked

      - name: cargo run --example s3_metadata
        run: cargo run --example s3_metadata --locked

  # --------------------------------------------------------------
  # Lint pass — formatting + clippy with deny(warnings) on top of
  # the crate's pedantic lints.
  # --------------------------------------------------------------
  lint:
    name: lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6

      - name: Install LLVM
        run: sudo apt-get update && sudo apt-get install -y clang libclang-dev

      - uses: dtolnay/rust-toolchain@stable
        with:
          components: rustfmt, clippy

      - uses: Swatinem/rust-cache@v2

      - name: cargo fmt --check
        run: cargo fmt --all --check

      # Clippy on tests + examples too, not just the library. The
      # crate opts into `clippy::pedantic` and has a vetted set of
      # `#![allow]`s in `src/lib.rs` for the unhelpful ones; any
      # new warning fails the build.
      - name: cargo clippy
        run: cargo clippy --workspace --all-targets --all-features --locked -- -D warnings

  # --------------------------------------------------------------
  # Fuzz smoke — short libFuzzer run over the storage-engine model
  # target. This is not a replacement for long fuzz campaigns; it is
  # a CI guard that keeps the fuzz target building and exercises the
  # atomic / WAL / range oracle for a bounded number of generated
  # inputs.
  # --------------------------------------------------------------
  fuzz:
    name: fuzz
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6

      - uses: dtolnay/rust-toolchain@stable

      - uses: dtolnay/rust-toolchain@nightly

      - uses: Swatinem/rust-cache@v2

      - name: install cargo-fuzz
        run: cargo +stable install cargo-fuzz --locked

      - name: cargo fuzz run atomic_model
        run: cargo +nightly fuzz run atomic_model -- -runs=512

  # --------------------------------------------------------------
  # Coverage — source-based LLVM coverage over lib + integration
  # tests + examples on Ubuntu. The line threshold is deliberately
  # close to the current measured baseline so coverage can only move
  # backward intentionally.
  # --------------------------------------------------------------
  coverage:
    name: coverage
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6

      - name: Install LLVM
        run: sudo apt-get update && sudo apt-get install -y clang libclang-dev

      - uses: dtolnay/rust-toolchain@stable
        with:
          components: llvm-tools-preview

      - uses: Swatinem/rust-cache@v2

      - name: install cargo-llvm-cov
        run: cargo install cargo-llvm-cov --locked

      - name: cargo llvm-cov
        run: |
          cargo llvm-cov clean --workspace
          cargo llvm-cov \
            --workspace --all-features --lib --tests --examples --locked \
            --fail-under-lines 88
          cargo llvm-cov report --fail-under-lines 88 > coverage.txt
          cargo llvm-cov report --lcov --output-path lcov.info
          cargo llvm-cov report --html --output-dir coverage
          {
            echo "## coverage"
            echo ""
            echo '```'
            cat coverage.txt
            echo '```'
          } >> "$GITHUB_STEP_SUMMARY"

      - name: Upload coverage artifacts
        uses: actions/upload-artifact@v4
        with:
          name: coverage
          path: |
            coverage.txt
            lcov.info
            coverage/html

  # --------------------------------------------------------------
  # Criterion microbenches — run on both Tier-1 Unix targets so
  # we can read the perf delta between the default
  # `pread`/`pwrite` backend (macOS + Linux without feature) and
  # the `--features io-uring` Linux build. Numbers go to the job
  # summary as a Markdown table; no failure thresholds — variance
  # on hosted runners is too high for hard SLOs, but eyeballing
  # the deltas tells us if a commit massively regressed
  # something. Measurement window is short (`--warm-up-time 1
  # --measurement-time 2`) so a full CI run stays under ~5 min.
  # --------------------------------------------------------------
  bench:
    name: bench (${{ matrix.os }})
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, macos-latest]
    steps:
      - uses: actions/checkout@v6

      - name: Install LLVM (Ubuntu)
        if: runner.os == 'Linux'
        run: sudo apt-get update && sudo apt-get install -y clang libclang-dev

      - name: Install LLVM (macOS)
        if: runner.os == 'macOS'
        run: |
          brew install llvm
          echo "LIBCLANG_PATH=$(brew --prefix llvm)/lib" >> "$GITHUB_ENV"

      - uses: dtolnay/rust-toolchain@stable
      - uses: Swatinem/rust-cache@v2

      # Filter to holt-only persist scenarios so the run stays
      # focused (the full matrix also benches rocksdb / sqlite for
      # the apples-to-apples comparison — those numbers belong in
      # a separate "compare" job, not the regression gate).
      - name: cargo bench (default backend)
        run: |
          set -o pipefail
          cargo bench --bench main --locked -- \
            --warm-up-time 1 --measurement-time 2 \
            "persist_put/holt|persist_get/holt|persist_mixed/holt" \
            2>&1 | tee bench-default.txt

      - name: cargo bench (io-uring backend, Linux only)
        if: runner.os == 'Linux'
        run: |
          set -o pipefail
          cargo bench --bench main --features io-uring --locked -- \
            --warm-up-time 1 --measurement-time 2 \
            "persist_put/holt|persist_get/holt|persist_mixed/holt" \
            2>&1 | tee bench-uring.txt

      - name: Post results to job summary
        if: always()
        run: |
          {
            echo "## holt bench results — ${{ matrix.os }}"
            echo ""
            echo "### Default backend (\`pread\`/\`pwrite\`)"
            echo '```'
            grep -E "time:|thrpt:" bench-default.txt || echo "(no measurements captured)"
            echo '```'
            if [ -f bench-uring.txt ]; then
              echo ""
              echo "### \`--features io-uring\` backend"
              echo '```'
              grep -E "time:|thrpt:" bench-uring.txt || echo "(no measurements captured)"
              echo '```'
            fi
          } >> "$GITHUB_STEP_SUMMARY"

      - name: Upload raw bench logs
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: bench-${{ matrix.os }}
          path: bench-*.txt
          if-no-files-found: warn

  # --------------------------------------------------------------
  # `cargo doc` — fails on broken intra-doc links / missing docs
  # so the rendered docs.rs page stays clean.
  # --------------------------------------------------------------
  docs:
    name: docs
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6

      - name: Install LLVM
        run: sudo apt-get update && sudo apt-get install -y clang libclang-dev

      - uses: dtolnay/rust-toolchain@stable
      - uses: Swatinem/rust-cache@v2

      - name: cargo doc (no deps)
        env:
          RUSTDOCFLAGS: "-D warnings"
        run: cargo doc --workspace --no-deps --locked

  # --------------------------------------------------------------
  # MSRV — pin to the rust-version field in Cargo.toml. Keeps us
  # honest about the floor we promise downstream users. We build
  # the library only (no tests/benches/examples) because
  # dev-dependencies routinely require newer Rust than the
  # library surface itself does.
  # --------------------------------------------------------------
  msrv:
    name: msrv (rust 1.82)
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@1.82
      - uses: Swatinem/rust-cache@v2

      - name: cargo build (library only)
        run: cargo build --lib --locked

  # --------------------------------------------------------------
  # Supply-chain hygiene: `cargo deny check` fails the build on
  # disallowed licenses, banned crates, RustSec advisories, and
  # duplicate / unmaintained dependencies. Policy lives in
  # `deny.toml` at the repo root.
  # --------------------------------------------------------------
  deny:
    name: deny
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: EmbarkStudios/cargo-deny-action@v2
        with:
          command: check
          arguments: --all-features --locked