Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/gunnar

gunnar

OpenSSF Best Practices

Fast setup: the guide · PDF — four lists of commands, one picture per setup.

Features: what is new, with status, source path and commit.

Git server in Rust, with two engine variants: znippy-based (Apache Arrow IPC in a znippy archive) or gix-based (traditional filesystem).

Building

Anyone can clone the repository read-only, with no registered SSH key:

git clone ssh://anonymous@git.gunnar.rs:2222/nordisk/gunnar.git
cd gunnar
cargo build --release -p gunnar-cli

A lone clone builds the server by itself, with nothing beside it:

git clone ssh://git.gunnar.rs:2222/nordisk/gunnar && cd gunnar && cargo build --release
./target/release/gunnar        # serves on loopback; http://127.0.0.1:8080/healthz answers ok

cargo build --release at the root builds the default member, gunnar (the server: engine-znippy, SSH and smart HTTP with TLS via --http-tls-*; no mimalloc, no company SSO, no monetize: --features mimalloc,sso adds those). The committed Cargo.lock is the crates.io lock, so cargo build --locked and cargo install --locked --path crates/gunnar-cli --features client work from a lone clone too (cargo xtask lone-clone proves it on every push). The root takes no sibling patch in any checkout. In an estate checkout, with ../edda, ../znippy, ../Skidbladnir, ../tunnr, ../draupnir and ../monetize beside it, the detached estate workspaces (gunnar-front, gunnar-monetize-guest, the benches, installtest) build against those siblings through the [patch.crates-io] in their own manifests, with --manifest-path.

This page documents gunnar 1.6.0 — the version gunnar --version prints.

License: AGPL-3.0-only, © 2026 Vetra Automation AB and Ignalina ApS (Rickard Ernst Björn Lundin). Commercial terms: COMMERCIAL-LICENSING.md.

Install the server with cargo

cargo install gunnar
gunnar

A bare gunnar serves on loopback with no configuration: SSH on 127.0.0.1:2222, smart HTTP on 127.0.0.1:8080, and health at http://127.0.0.1:8080/healthz. The default build compiles no monetize crate; the other variants are opt-in cargo features, listed in crates/gunnar/README.md.

Gunnar by hand

This guide installs Gunnar's three products from their crates: gunnar (the server), gunnar-ui (the web console) and gunnar-cli (the command-line tool). It signs in to the console with a passkey, creates a repository, pushes to it over SSH, makes an encrypted (quantum-safe) repository and adds a twin. Every command is copy-pasteable on one Linux host. You need cargo, git, OpenSSH, curl and a browser. Everything listens on loopback. The integration test cargo xtask products runs exactly these blocks, in this order.

0. The places and the names. Everything lives under $G. The main server, its twin and the console each get their own ports. Your SSH key is ~/.ssh/id_ed25519 (made here if you have none); git and gunnar-cli sign in with it.

export G="${G:-$HOME/gunnar-guide}"
export SSH="${SSH:-127.0.0.1:2222}" HTTP="${HTTP:-127.0.0.1:8080}" CTRL="${CTRL:-127.0.0.1:50051}"
export TWIN_SSH="${TWIN_SSH:-127.0.0.1:2223}" TWIN_HTTP="${TWIN_HTTP:-127.0.0.1:8081}" TWIN_CTRL="${TWIN_CTRL:-127.0.0.1:50052}"
export UI="${UI:-3210}"
mkdir -p "$G" ~/.ssh
[ -f ~/.ssh/id_ed25519 ] || ssh-keygen -q -t ed25519 -N "" -f ~/.ssh/id_ed25519
export GIT_SSH_COMMAND="ssh -i $HOME/.ssh/id_ed25519 -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new -o UserKnownHostsFile=$G/known_hosts"
export GIT_AUTHOR_NAME=alice GIT_AUTHOR_EMAIL=alice@mock.invalid GIT_COMMITTER_NAME=alice GIT_COMMITTER_EMAIL=alice@mock.invalid

1. The server

Install the server and the command-line tool, and start the server with its own data root. It serves git over SSH and smart HTTP, and its control plane on loopback:

cargo install gunnar gunnar-cli
gunnar --data-root "$G/main" serve --ssh-bind "$SSH" --http-bind "$HTTP" --grpc-bind "$CTRL" > "$G/main.log" 2>&1 &
until curl -fsS "http://$HTTP/healthz" > /dev/null 2>&1; do sleep 0.2; done

The first call claims it: alice becomes its administrator, with your key. It works once.

cli() { gunnar-cli control "$@" -i ~/.ssh/id_ed25519; }
gunnar-cli control status --at "$CTRL"
cli bootstrap alice --key @"$HOME/.ssh/id_ed25519.pub" --at "$CTRL"

2. The console, and a passkey

Install the console, give it a key of its own, and enrol that key with the server (a machine with an admin grant: the console signs every call it makes for you). Then start it for http://localhost:3210; a passkey's relying party is a domain, and localhost is one.

cargo install gunnar-ui
ssh-keygen -q -t ed25519 -N "" -f "$G/ui-id"
export GUNNAR_UI_CONTROL="$CTRL" GUNNAR_UI_IDENTITY="$G/ui-id" GUNNAR_UI_DATA="$G/ui" GUNNAR_UI_STATE="$G/ui/state.redb"
mkdir -p "$G/ui" && gunnar-ui enroll --admin-key ~/.ssh/id_ed25519 --name gunnar-ui
GUNNAR_UI_BIND="127.0.0.1:$UI" GUNNAR_UI_WEBAUTHN_RP_ID=localhost GUNNAR_UI_WEBAUTHN_ORIGIN="http://localhost:$UI" gunnar-ui > "$G/ui.log" 2>&1 &
until curl -fsS "http://127.0.0.1:$UI/health" > /dev/null 2>&1; do sleep 0.2; done

Sign in with a passkey: the server mints a first-login link for alice (its secret is shown once), and you open it. The page registers your passkey (touch your security key, or use the one your browser keeps) and signs you in as alice, the administrator.

SECRET=$(cli invite create alice --first-only --at "$CTRL" | awk '$1 == "secret" {print $2}')
xdg-open "http://localhost:$UI/login?invite=$SECRET&user=alice"

3. A repository, and a push over SSH

cli repo create alice/hello --at "$CTRL"
git clone "ssh://git@$SSH/alice/hello.git" "$G/hello"
cd "$G/hello"
echo "hello, Gunnar" > README.md
git add README.md && git commit -q -m "the first commit" && git push -q origin HEAD:refs/heads/main
cd "$G"

The console shows it at http://localhost:3210/alice/hello.

4. An encrypted repository, quantum-safe

The files are sealed on your machine before they leave it, and the server holds ciphertext only. gunnar-cli crypt init makes the repository's key ring, wrapped to your encryption key: quantum-safe (ML-KEM-768 + X25519) unless you ask for --level classic. You have no encryption key yet, so it makes one, keeps it at the server wrapped to your SSH key, and commits the three files that make the repository encrypted.

cli repo create alice/vault --at "$CTRL"
git clone "ssh://git@$SSH/alice/vault.git" "$G/vault"
cd "$G/vault"
gunnar-cli crypt init --member alice
echo "the launch code is 0000-1111" > plan.txt
git add plan.txt && git commit -q -m "the plan" && git push -q origin HEAD:refs/heads/main
gunnar-cli crypt status | grep "quantum-safe"
cd "$G"

A plain clone, without your key, sees ciphertext only (no line of plan.txt says it):

git clone -q "ssh://git@$SSH/alice/vault.git" "$G/vault-plain"
if grep -q "launch code" "$G/vault-plain/plan.txt"; then echo "the server holds plaintext"; false; fi

5. A twin

A twin is a second Gunnar that holds a copy of every repository and can take over. Start it, claim it with the same key, make it a standby (read-only to people; it takes only its primary's replication pushes), and add it to the main. The main mints its own push key and prints the public line, which the twin authorises as a machine with an admin grant on the namespace (the twin creates each repository; the main asks the twin's control plane, --control, to make each one in its own object format). Then backfill it: adding a standby copies nothing that is already there.

gunnar --data-root "$G/twin" serve --ssh-bind "$TWIN_SSH" --http-bind "$TWIN_HTTP" --grpc-bind "$TWIN_CTRL" > "$G/twin.log" 2>&1 &
until curl -fsS "http://$TWIN_HTTP/healthz" > /dev/null 2>&1; do sleep 0.2; done
cli bootstrap alice --key @"$HOME/.ssh/id_ed25519.pub" --at "$TWIN_CTRL"
cli replication standby --at "$TWIN_CTRL"
cli replication add twin "ssh://git@$TWIN_SSH" --control "$TWIN_CTRL" --at "$CTRL" | tee "$G/twin-add.txt"
PRIMARY_KEY=$(sed -n 's/^ *\(ssh-ed25519 .*\)$/\1/p' "$G/twin-add.txt" | head -n 1)
cli user add primary --key "$PRIMARY_KEY" --kind machine --at "$TWIN_CTRL"
cli grant primary admin --namespace alice --at "$TWIN_CTRL"
cli replication resync twin --at "$CTRL"
for try in $(seq 120); do cli replication list --at "$CTRL" | grep -q "copied.*alice/hello" && break; sleep 1; done
cli replication list --at "$CTRL" | grep "copied.*alice/hello"
git clone -q "ssh://git@$TWIN_SSH/alice/hello.git" "$G/hello-from-the-twin"
git -C "$G/hello-from-the-twin" log --oneline | grep "the first commit"

The twin takes over with cli replication promote --at "$TWIN_CTRL" (and the old main steps down with cli replication demote and cli replication standby); see the guide, §3. Stop the three programs: kill %1 %2 %3.

The old program names, and what they are now:

was is
gunnar from gunnar-cli (the git client) gunnar-cli (cargo install gunnar-cli): every verb it had, and control
gunnar-solo cargo install gunnar-cli --features server: both halves in one program
gunnar-service cargo install gunnar-cli --features systemd: the server as a systemd service
gunnar-ui-server gunnar-ui (cargo install gunnar-ui); gunnar-ui-server is the same program under its old name

Release provenance (SLSA Build L3)

Releases are built by dwarves, the build server, in its isolated release-build mode and carry signed SLSA v1 provenance: one in-toto statement per release, every artifact by its sha256, signed on the owner's YubiKey. The bundles are in attestations/, the release key in slsa/; how to verify (cosign, dwarves or Holger) and what still keeps us below L3: docs/SLSA.md.

Complexity and measurements

n objects, r refs, e refs in a batch, k batch size, s object size, |W|/|H| want/have closure. Read off the znippy engine's code.

operation znippy
put_pack O(bytes), index deferred
put_refs O(r) + O(e·log n)
get O(log n) + O(s)
has O(log n)
size O(log n)
extents O(k·log n)
refs O(r)
update_ref O(log r)
head O(log r)
header O(log n)
reachable O(1) map lookup + bitmap OR
gc O(n) compact

Measured: the table below is rendered from the newest result file of each bench in crates/gunnar-perfbench/results/ by cargo xtask bench-readme write, and xtask/tests/bench_readme.rs is red when it is anything else. The weekly CI run (bench-gunnar in the dwarves forge, on oden) commits a new result and this block. The older hand-copied rows (a synthetic 16 384-commit repository, the gitea comparison, 2026-08 and 2026-09 on the desktop) are gone: no bencher run backs them today.

Every number here comes from a bencher run, rendered from its result file; none is typed in. Wall time per operation (p50, p99), CPU per operation (server and client), the server's peak RSS during that step (heap = RssAnon, all = VmHWM, which also counts mapped pack pages), and the load1 of the machine at that step. A cost row is what a query pays to get there: the first push, the index build after a restart, the rebuild after a push.

Source: gunnar-perfbench-index-build (crates/gunnar-perfbench/results/2026-11-01-oden-gunnar-perfbench-index-build.json), measured on oden (32 threads, 499 GiB RAM) on 2026-11-01, load1 77.8 to 102.3 during the run (74.6 before it), built from gunnar 172aa1a3 + znippy-plugin-git 0.2.3 + GP-7 (lane gitidx after-gp7 binary). Real clients: git 2.47.3, OpenSSH_10.0p2 Debian-7+deb13u4, OpenSSL 3.5.6 7 Apr 2026, git-lfs/3.6.1 (GitHub; linux amd64; go 1.24.4). One release build with both engines (--features engine-gix), the engine picked per run by GUNNAR_ENGINE.

repository step engine p50 p99 server CPU/op client CPU/op peak RSS heap / all rate run
git.git (411 105 objects, 1 006 refs, 318 MB pack) cost: index build: a restarted server's first fetch of a new commit (znippy-plugin-git builds its reach index here and persists it), HTTP (n=1) znippy 15.6 s 15.6 s 13.4 s 70.0 ms 396 MiB / 695 MiB — oden, 2026-11-01, load 102.3
git.git (411 105 objects, 1 006 refs, 318 MB pack) memory: memory of the idle server, just started (22 repositories) znippy — — — — 5 MiB / 24 MiB — oden, 2026-11-01, load 77.8
git.git (411 105 objects, 1 006 refs, 318 MB pack) memory: memory held after the run, not what one request needs: the handle cache (up to 256 open repositories, stores::DEFAULT_OPEN_REPOS, each with its redb cache) and the reach bitmaps (22 repositories) znippy — — — — 353 MiB / 657 MiB — oden, 2026-11-01, load 102.3

Source: gunnar-perfbench-window-after-gp7 (crates/gunnar-perfbench/results/2026-11-01-oden-gunnar-perfbench-window-after-gp7.json), measured on oden on 2026-11-01, load1 1.6 to 3.1 during the run (1.8 before it), built from gunnar 172aa1a3 + znippy-plugin-git 0.2.3 + GP-7 (lane gitidx after-gp7 binary). Lane gitidx quiet bench window (oden freshly rebooted, nothing else running), GUNPERF_ONLY=clone,fetch, znippy only; with GP-7 a git.git clone takes the reach index.

repository step engine p50 p99 server CPU/op client CPU/op peak RSS heap / all rate run
git.git (411 105 objects, 1 006 refs, 318 MB pack) cost: rebuild after a push: push one commit, fetch it (znippy: the index update; gix: a walk), HTTP (n=10) znippy 119 ms 152 ms 55.0 ms — — / 936 MiB — oden, 2026-11-01, load 2.6
git.git (411 105 objects, 1 006 refs, 318 MB pack) cost: rebuild after a push: push one commit, fetch it (znippy: the index update; gix: a walk), SSH (n=10) znippy 141 ms 150 ms 57.0 ms — — / 1.1 GiB — oden, 2026-11-01, load 2.8
git.git (411 105 objects, 1 006 refs, 318 MB pack) clone (bare, warm), HTTP (n=3) znippy 11.5 s 11.6 s 930 ms 35.1 s 883 MiB / 1.2 GiB 27.2 MB/s oden, 2026-11-01, load 3.1
git.git (411 105 objects, 1 006 refs, 318 MB pack) clone (bare, warm), SSH (n=3) znippy 11.5 s 22.1 s 4.9 s 35.8 s 913 MiB / 1.2 GiB 27.2 MB/s oden, 2026-11-01, load 1.9
git.git (411 105 objects, 1 006 refs, 318 MB pack) fetch with nothing new, HTTP (n=20) znippy 29.1 ms 31.3 ms 1.50 ms 28.0 ms 792 MiB / 1.1 GiB — oden, 2026-11-01, load 2.9
git.git (411 105 objects, 1 006 refs, 318 MB pack) fetch with nothing new, SSH (n=20) znippy 34.1 ms 36.5 ms 2.50 ms 31.5 ms 792 MiB / 1.1 GiB — oden, 2026-11-01, load 3.1

Source: gunnar-perfbench (crates/gunnar-perfbench/results/2026-10-31-oden-gunnar-perfbench.json), measured on oden (32 threads, 499 GiB RAM) on 2026-10-31, load1 31.3 to 137.5 during the run (64.4 before it), built from gunnar 172aa1a3. Real clients: git 2.47.3, OpenSSH_10.0p2 Debian-7+deb13u4, OpenSSL 3.5.6 7 Apr 2026, git-lfs/3.6.1 (GitHub; linux amd64; go 1.24.4). One release build with both engines (--features engine-gix), the engine picked per run by GUNNAR_ENGINE.

repository step engine p50 p99 server CPU/op client CPU/op peak RSS heap / all rate run
git.git (411 105 objects, 1 006 refs, 318 MB pack) cost: first push of the whole repository, HTTP (n=1) znippy 38.6 s 38.6 s 37.2 s 1.9 s 2.2 GiB / 4.6 GiB 8.5 MB/s oden, 2026-10-31, load 84.2
git.git (411 105 objects, 1 006 refs, 318 MB pack) cost: first push of the whole repository, HTTP (n=1) gix 26.6 s 26.6 s 30.2 s 1.7 s 1.8 GiB / 2.5 GiB 12.3 MB/s oden, 2026-10-31, load 50.9
git.git (411 105 objects, 1 006 refs, 318 MB pack) cost: first push of the whole repository, SSH (n=1) znippy 34.1 s 34.1 s 36.8 s 1.6 s 1.8 GiB / 3.9 GiB 9.6 MB/s oden, 2026-10-31, load 69.1
git.git (411 105 objects, 1 006 refs, 318 MB pack) cost: first push of the whole repository, SSH (n=1) gix 27.4 s 27.4 s 30.7 s 1.6 s 1.7 GiB / 2.3 GiB 12.0 MB/s oden, 2026-10-31, load 59.2
git.git (411 105 objects, 1 006 refs, 318 MB pack) cost: cold start: a restarted server's first clone (znippy: its index build, when the select takes the index), HTTP (n=1) znippy 50.5 s 50.5 s 19.8 s 32.0 s 242 MiB / 541 MiB 6.2 MB/s oden, 2026-10-31, load 90.2
git.git (411 105 objects, 1 006 refs, 318 MB pack) cost: cold start: a restarted server's first clone (znippy: its index build, when the select takes the index), HTTP (n=1) gix 39.0 s 39.0 s 13.2 s 33.2 s 251 MiB / 838 MiB 8.0 MB/s oden, 2026-10-31, load 65.4
git.git (411 105 objects, 1 006 refs, 318 MB pack) cost: cold start: a restarted server's first push of one commit and its fetch (znippy: the index build), HTTP (n=1) znippy 103 s 103 s 92.2 s 200 ms 809 MiB / 1.1 GiB — oden, 2026-10-31, load 82.8
git.git (411 105 objects, 1 006 refs, 318 MB pack) cost: cold start: a restarted server's first push of one commit and its fetch (znippy: the index build), HTTP (n=1) gix 55.1 s 55.1 s 47.9 s 160 ms 85 MiB / 410 MiB — oden, 2026-10-31, load 68.0
git.git (411 105 objects, 1 006 refs, 318 MB pack) cost: rebuild after a push: push one commit, fetch it (znippy: the index update; gix: a walk), HTTP (n=10) znippy 944 ms 7.2 s 1.2 s 70.0 ms 3.6 GiB / 5.7 GiB — oden, 2026-10-31, load 126.0
git.git (411 105 objects, 1 006 refs, 318 MB pack) cost: rebuild after a push: push one commit, fetch it (znippy: the index update; gix: a walk), HTTP (n=10) gix 47.8 s 55.4 s 47.1 s 100 ms 1.9 GiB / 2.5 GiB — oden, 2026-10-31, load 31.3
git.git (411 105 objects, 1 006 refs, 318 MB pack) cost: rebuild after a push: push one commit, fetch it (znippy: the index update; gix: a walk), SSH (n=10) znippy 4.5 s 142 s 13.0 s 86.0 ms 3.6 GiB / 5.8 GiB — oden, 2026-10-31, load 137.5
git.git (411 105 objects, 1 006 refs, 318 MB pack) cost: rebuild after a push: push one commit, fetch it (znippy: the index update; gix: a walk), SSH (n=10) gix 49.6 s 58.8 s 47.7 s 87.0 ms 1.9 GiB / 2.8 GiB — oden, 2026-10-31, load 74.9
git.git (411 105 objects, 1 006 refs, 318 MB pack) memory: memory of the idle server, just started (22 repositories) znippy — — — — 6 MiB / 26 MiB — oden, 2026-10-31, load 64.4
git.git (411 105 objects, 1 006 refs, 318 MB pack) memory: memory of the idle server, just started (22 repositories) gix — — — — 4 MiB / 23 MiB — oden, 2026-10-31, load 75.5
git.git (411 105 objects, 1 006 refs, 318 MB pack) memory: memory held after the run, not what one request needs: the handle cache (up to 256 open repositories, stores::DEFAULT_OPEN_REPOS, each with its redb cache) and the reach bitmaps (22 repositories) znippy — — — — 932 MiB / 1.2 GiB — oden, 2026-10-31, load 84.6
git.git (411 105 objects, 1 006 refs, 318 MB pack) memory: memory held after the run, not what one request needs: the handle cache (up to 256 open repositories, stores::DEFAULT_OPEN_REPOS, each with its redb cache) and the reach bitmaps (22 repositories) gix — — — — 150 MiB / 481 MiB — oden, 2026-10-31, load 76.9
git.git (411 105 objects, 1 006 refs, 318 MB pack) clone (bare, warm), HTTP (n=3) znippy 49.1 s 51.2 s 19.7 s 32.7 s 2.7 GiB / 5.1 GiB 6.4 MB/s oden, 2026-10-31, load 77.4
git.git (411 105 objects, 1 006 refs, 318 MB pack) clone (bare, warm), HTTP (n=3) gix 33.3 s 36.1 s 13.5 s 34.5 s 2.0 GiB / 2.9 GiB 9.4 MB/s oden, 2026-10-31, load 48.5
git.git (411 105 objects, 1 006 refs, 318 MB pack) clone (bare, warm), SSH (n=3) znippy 53.5 s 55.1 s 20.2 s 32.6 s 2.6 GiB / 5.0 GiB 5.8 MB/s oden, 2026-10-31, load 117.5
git.git (411 105 objects, 1 006 refs, 318 MB pack) clone (bare, warm), SSH (n=3) gix 35.8 s 41.9 s 13.8 s 34.8 s 2.0 GiB / 2.9 GiB 8.7 MB/s oden, 2026-10-31, load 58.0
git.git (411 105 objects, 1 006 refs, 318 MB pack) fetch with nothing new, HTTP (n=20) znippy 101 ms 515 ms 1.50 ms 31.5 ms 2.7 GiB / 5.1 GiB — oden, 2026-10-31, load 104.2
git.git (411 105 objects, 1 006 refs, 318 MB pack) fetch with nothing new, HTTP (n=20) gix 97.7 ms 241 ms 16.0 ms 31.0 ms 1.9 GiB / 2.8 GiB — oden, 2026-10-31, load 51.9
git.git (411 105 objects, 1 006 refs, 318 MB pack) fetch with nothing new, SSH (n=20) znippy 123 ms 393 ms 3.00 ms 36.5 ms 2.8 GiB / 5.2 GiB — oden, 2026-10-31, load 83.3
git.git (411 105 objects, 1 006 refs, 318 MB pack) fetch with nothing new, SSH (n=20) gix 62.0 ms 106 ms 17.5 ms 33.5 ms 1.9 GiB / 2.8 GiB — oden, 2026-10-31, load 51.8
git.git (411 105 objects, 1 006 refs, 318 MB pack) git ls-remote (process start included), HTTP (n=50) znippy 18.2 ms 112 ms 1.80 ms 11.8 ms 815 MiB / 1.1 GiB — oden, 2026-10-31, load 83.8
git.git (411 105 objects, 1 006 refs, 318 MB pack) git ls-remote (process start included), HTTP (n=50) gix 39.4 ms 98.0 ms 16.0 ms 11.8 ms 31 MiB / 362 MiB — oden, 2026-10-31, load 70.3
git.git (411 105 objects, 1 006 refs, 318 MB pack) git ls-remote (process start included), SSH (n=50) znippy 29.4 ms 174 ms 3.20 ms 15.0 ms 814 MiB / 1.1 GiB — oden, 2026-10-31, load 83.6
git.git (411 105 objects, 1 006 refs, 318 MB pack) git ls-remote (process start included), SSH (n=50) gix 47.6 ms 137 ms 16.8 ms 15.2 ms 30 MiB / 361 MiB — oden, 2026-10-31, load 68.1
git.git (411 105 objects, 1 006 refs, 318 MB pack) info/refs, protocol v0 (rate at c=16), HTTP (n=1000) znippy 1.45 ms 13.1 ms 1.46 ms — 901 MiB / 1.2 GiB 1 027 req/s oden, 2026-10-31, load 88.9
git.git (411 105 objects, 1 006 refs, 318 MB pack) info/refs, protocol v0 (rate at c=16), HTTP (n=1000) gix 16.1 ms 52.0 ms 15.4 ms — 117 MiB / 448 MiB 84 req/s oden, 2026-10-31, load 84.8
git.git (411 105 objects, 1 006 refs, 318 MB pack) info/refs, protocol v2 (rate at c=16), HTTP (n=1000) znippy 0.10 ms 4.09 ms 0.11 ms — 903 MiB / 1.2 GiB 22 703 req/s oden, 2026-10-31, load 90.5
git.git (411 105 objects, 1 006 refs, 318 MB pack) info/refs, protocol v2 (rate at c=16), HTTP (n=1000) gix 0.11 ms 5.04 ms 0.12 ms — 118 MiB / 449 MiB 14 675 req/s oden, 2026-10-31, load 87.2
git.git (411 105 objects, 1 006 refs, 318 MB pack) ls-refs (rate at c=16), HTTP (n=1000) znippy 1.61 ms 6.67 ms 1.49 ms — 906 MiB / 1.2 GiB 1 020 req/s oden, 2026-10-31, load 88.7
git.git (411 105 objects, 1 006 refs, 318 MB pack) ls-refs (rate at c=16), HTTP (n=1000) gix 18.1 ms 88.6 ms 15.6 ms — 118 MiB / 449 MiB 71 req/s oden, 2026-10-31, load 81.2
linux (the Linux kernel's history) pending: not run yet — — — — — — / — — —
big, synthetic (34 objects, 1 ref, 269 MB pack) cost: first push of the whole repository, HTTP (n=3) znippy 8.8 s 8.9 s 1.8 s 6.8 s 1.2 GiB / 2.9 GiB 30.5 MB/s oden, 2026-10-31, load 57.2
big, synthetic (34 objects, 1 ref, 269 MB pack) cost: first push of the whole repository, HTTP (n=3) gix 8.6 s 9.2 s 4.0 s 6.8 s 1.5 GiB / 2.0 GiB 31.1 MB/s oden, 2026-10-31, load 55.7
lfs, synthetic (83 objects, 1 ref, 0.34 MB pack) LFS upload, HTTP (n=3) znippy 1.2 s 1.4 s 1.1 s 463 ms 929 MiB / 1.2 GiB 235.0 MB/s oden, 2026-10-31, load 88.7
lfs, synthetic (83 objects, 1 ref, 0.34 MB pack) LFS upload, HTTP (n=3) gix 1.5 s 1.8 s 1.1 s 267 ms 148 MiB / 478 MiB 176.4 MB/s oden, 2026-10-31, load 79.0
lfs, synthetic (83 objects, 1 ref, 0.34 MB pack) LFS download, HTTP (n=3) znippy 408 ms 487 ms 190 ms 457 ms 932 MiB / 1.2 GiB 668.4 MB/s oden, 2026-10-31, load 84.6
lfs, synthetic (83 objects, 1 ref, 0.34 MB pack) LFS download, HTTP (n=3) gix 723 ms 862 ms 187 ms 467 ms 150 MiB / 481 MiB 377.0 MB/s oden, 2026-10-31, load 76.9
small, synthetic (121 objects, 1 ref, 0.05 MB pack) cost: first push of the whole repository, HTTP (n=3) znippy 37.9 ms 42.7 ms 10.0 ms 13.3 ms 16 MiB / 43 MiB 1.2 MB/s oden, 2026-10-31, load 64.4
small, synthetic (121 objects, 1 ref, 0.05 MB pack) cost: first push of the whole repository, HTTP (n=3) gix 78.3 ms 101 ms 13.3 ms 20.0 ms 18 MiB / 42 MiB 0.6 MB/s oden, 2026-10-31, load 75.5
small, synthetic (121 objects, 1 ref, 0.05 MB pack) clone (bare, warm), HTTP (n=20) znippy 47.3 ms 75.6 ms 1.00 ms 20.0 ms 2.6 GiB / 4.9 GiB 1.0 MB/s oden, 2026-10-31, load 92.4
small, synthetic (121 objects, 1 ref, 0.05 MB pack) clone (bare, warm), HTTP (n=20) gix 42.8 ms 148 ms 2.00 ms 20.0 ms 1.8 GiB / 2.3 GiB 1.1 MB/s oden, 2026-10-31, load 61.2
small, synthetic (121 objects, 1 ref, 0.05 MB pack) info/refs, protocol v2 (rate at c=16), HTTP (n=1000) znippy 0.16 ms 11.8 ms 0.14 ms — 873 MiB / 1.2 GiB 20 997 req/s oden, 2026-10-31, load 85.8
small, synthetic (121 objects, 1 ref, 0.05 MB pack) info/refs, protocol v2 (rate at c=16), HTTP (n=1000) gix 0.19 ms 3.57 ms 0.12 ms — 85 MiB / 416 MiB 15 101 req/s oden, 2026-10-31, load 73.7
wide, synthetic (11 263 objects, 1 ref, 7.0 MB pack) clone (bare, warm), HTTP (n=5) znippy 316 ms 443 ms 20.0 ms 244 ms 2.6 GiB / 4.9 GiB 22.2 MB/s oden, 2026-10-31, load 93.5
wide, synthetic (11 263 objects, 1 ref, 7.0 MB pack) clone (bare, warm), HTTP (n=5) gix 342 ms 438 ms 86.0 ms 238 ms 1.8 GiB / 2.3 GiB 20.5 MB/s oden, 2026-10-31, load 61.3
wide, synthetic (11 263 objects, 1 ref, 7.0 MB pack) info/refs, protocol v2 (rate at c=16), HTTP (n=1000) znippy 0.099 ms 3.08 ms 0.11 ms — 882 MiB / 1.2 GiB 12 134 req/s oden, 2026-10-31, load 88.8
wide, synthetic (11 263 objects, 1 ref, 7.0 MB pack) info/refs, protocol v2 (rate at c=16), HTTP (n=1000) gix 0.090 ms 2.34 ms 0.10 ms — 102 MiB / 433 MiB 14 343 req/s oden, 2026-10-31, load 79.9

Source: znippy-plugin-git-store (crates/gunnar-perfbench/results/2026-10-31-oden-znippy-plugin-git-store.json), measured on oden on 2026-10-31, load1 69.8 to 71.7 during the run (70.2 before it), built from znippy-plugin-git 0.2.3 from crates.io. Store level, no server: plugins/native/znippy-plugin-git/examples/reach_real_repo.rs, one process; peak RSS is the process's VmHWM so far; CPU is the process's.

repository step engine p50 p99 server CPU/op client CPU/op peak RSS heap / all rate run
git.git (411 105 objects, 1 007 refs, 292 MB pack) cost: ingest: the repository's pack stored and indexed (n=1) znippy-plugin-git 0.2.3 11.5 s — 14.7 s — — / 1.2 GiB — oden, 2026-10-31, load 70.2
git.git (411 105 objects, 1 007 refs, 292 MB pack) cost: index build: first select of every tip (once per repository, then persisted) (n=1) znippy-plugin-git 0.2.3 15.6 s — 12.8 s — — / 1.4 GiB — oden, 2026-10-31, load 69.8
git.git (411 105 objects, 1 007 refs, 292 MB pack) cost: rebuild after a push: the first select after it (n=1) znippy-plugin-git 0.2.3 27.0 ms — 27.0 ms — — / 1.4 GiB — oden, 2026-10-31, load 71.4
git.git (411 105 objects, 1 007 refs, 292 MB pack) cost: restart: reopen and the first fetch-shaped select (n=1) znippy-plugin-git 0.2.3 274 ms — 256 ms — — / 1.4 GiB — oden, 2026-10-31, load 71.4
git.git (411 105 objects, 1 007 refs, 292 MB pack) cost: push of one commit, the fold included (n=1) znippy-plugin-git 0.2.3 341 ms — 247 ms — — / 1.4 GiB — oden, 2026-10-31, load 71.4
git.git (411 105 objects, 1 007 refs, 292 MB pack) select of every tip, warm (the clone question) (n=3) znippy-plugin-git 0.2.3 24.0 ms — 0.000 ms — — / 1.4 GiB — oden, 2026-10-31, load 71.7
git.git (411 105 objects, 1 007 refs, 292 MB pack) fetch-shaped select (master against master^) (n=3) znippy-plugin-git 0.2.3 mean 164 ms — 158 ms — — / 1.4 GiB — oden, 2026-10-31, load 71.7
git.git (411 105 objects, 1 007 refs, 292 MB pack) refs(), the advertisement (n=200) znippy-plugin-git 0.2.3 mean 0.80 ms — 0.80 ms — — / 1.2 GiB — oden, 2026-10-31, load 69.8
git.git (411 105 objects, 1 007 refs, 292 MB pack) cost: put every ref once (n=1) znippy-plugin-git 0.2.3 3.00 ms — 3.00 ms — — / 1.2 GiB — oden, 2026-10-31, load 69.8

Thanks

Contributing, security and changes

Sponsors

None so far — we would love to have one. Contact gunnar@gunnar.rs.

AI-generated details: .nornir/detail.md

Files

Newest commits