The Problem

Kovan addresses the fundamental synchronization problem in wait-free programming: safely reclaiming memory when multiple threads access shared data without locks. In lock-free types, a drop() or free() can invalidate a pointer another thread still holds. Without tracking in-progress accesses, reclamation risks use-after-free bugs. Kovan provides a mechanism to determine when retired memory is safe to reclaim, offering bounded memory usage and predictable latency near read-only overhead.

What This Does

Kovan is a portfolio of 6 self-contained Rust crates, all built around the same memory-reclamation core. The root crate (kovan) defines the Atom<T> API and low-level pin()/load()/retire() protocol. Five ecosystem crates embed it: kovan-channel provides multi-producermulti-consumer channels (kovan-channel/src/lib.rs), kovan-map implements concurrent hash maps (kovan-map/src/hashmap.rs, kovan-map/src/hopscotch.rs), kovan-mvcc delivers Percolator-style MVCC (kovan-mvcc/src/percolator.rs, kovan-mvcc/src/storage.rs), kovan-queue offers queue primitives and a disruptor (kovan-queue/src/disruptor.rs, kovan-queue/src/array_queue.rs), and kovan-stm implements TL2-style software transactional memory (kovan-stm/src/lib.rs). The README documents Atom<T> as the simplest entry point and a low-level pin()/load()/retire() API for types embedding RetiredNode. Performance comparisons against epoch-based, hyaline, and hazard-pointer schemes show kovan’s pin + drop at 2.79 ns versus 13.66–18.09 ns for alternatives.

How It Is Wired

Execution starts at three real entry points: main in kovan/examples/simple.rs:6 reaches 88 functions with no external callers; run in kovan-queue/src/disruptor.rs:634 reaches 93 functions; start in kovan-queue/src/disruptor.rs:787 reaches 89 functions. The internal call graph resolves 955 edges between self-functions. Hub functions called from 50+ locations include pin (51 callers), is_null (50), store (43), begin (43), and commit (42). Functions with the widest blast radius are pin, is_null, and store — changes to any ripple across dozens of call sites. The responsibility map, ranked by function count and cross-file calls, shows kovan/src/atom.rs defines 42 functions called from 27 other files; kovan-queue/src/disruptor.rs defines 60 functions called from 4 files; kovan-mvcc/src/percolator.rs defines 32 functions called from 15 files; kovan-map/src/hopscotch.rs defines 37 functions called from 8 files; and kovan/src/guard.rs defines 25 functions called from 16 files. No circular dependencies were found across 81 analyzed code files. The wiring outside the repo: one function reads or writes a database, as mapped by the analysis.

How To Use It

Setup: Add the crate to Cargo.toml:

[dependencies]
kovan = "0.1"

For the full ecosystem, add kovan-channel, kovan-map, kovan-mvcc, kovan-queue, or kovan-stm as separate dependencies. The root Cargo.toml and each crate’s Cargo.toml are present; no global config beyond standard Rust tooling is required.

Configuration: No environment variables or secret keys are documented. The repo has a .cargo/config.toml and Cargo.lock; build is cargo build / cargo test from the root or any crate directory.

Running it: The README’s quick-start example uses Atom::new:

use kovan::Atom;
let shared = Atom::new(42_u64);
let guard = shared.load();
println!("Value: {}", *guard);
drop(guard);
let old = shared.swap(100_u64);

For low-level control, the pin()/load()/retire() API requires types with RetiredNode as the first field, as shown in the README’s examples/ section.

Real-World Use

A telemetry pipeline buffering inbound packets across threads could use kovan-channel as a lock-free multi-producer channel. Producers pin() a guard, load() the shared head pointer, splice new nodes, and retire() old nodes — the guard ensures no consumer is mid-traversal, and memory reclaimed automatically once all guards drop. The near-zero read overhead means the critical path adds only one atomic load and a comparison, suitable for high-QPS paths.

Code Health & Issues

  • Measured findings (static analysis, 37 total): 8 high — deep nesting in kovan/benches/comparison.rs, kovan/benches/throughput.rs, kovan/src/guard.rs (max indentation depth 13); duplicated 6-line blocks across 15 files (94 repeats in benches and tests). 29 medium — oversized files: kovan/benches/comparison.rs, kovan/src/guard.rs, kovan/tests/atom.rs (638 lines each); high branching density in kovan/src/retired.rs and kovan/src/ttas.rs (20 branch points over ~70 lines). 0 low.
  • Code health audit (6 findings, 0 critical):
  • [HIGH] Pin third-party GitHub Actions to a commit SHA — .github/workflows uses dtolnay/rust-toolchain@nightly, Swatinem/rust-cache@v2, dtolnay/rust-toolchain@stable; tags can move, exposing secrets.
  • [MEDIUM] Declare least-privilege permissions for GITHUB_TOKEN — 2 workflows (miri.yml, test.yml) declare no permissions; token inherits default, allowing injected steps to push or mint releases.
  • [MEDIUM] Enable Dependabot or Renovate — 7 manifests, no update bot configured; advisories may go unpatched.
  • [MEDIUM] Gate pull requests on a dependency vulnerability scan — no dependency scan in CI.
  • [MEDIUM] Set persist-credentials: false on checkout — test.yml checkout retains the token; later steps may read pushable credentials implicitly.
  • [LOW] Set timeout-minutes on workflow jobs — miri.yml has no job timeout, risking overlap on a two-hourly schedule.

The Bottom Line

Kovan delivers a focused, high-performance memory-reclamation layer that several concurrent-data-structure crates depend on. The core API is small, the overhead is measurable and low, and the ecosystem is coherent. Health findings are dominated by CI hygiene (pinned Actions, dependabot, token permissions) and code-maintainability issues (deep nesting, duplicated blocks, outsized files) that are straightforward to address. Teams building lock-free structures who need bounded memory and predictable latency will find kovan a practical foundation; those needing a fully integrated, out-of-the-box data-service platform will look elsewhere.