Skip to content

ADR 006: Lock-Free Orderbook Cache

Status

Accepted

Context

The arbitrage detection engine must read orderbook state for multiple markets with minimal latency while market monitors continuously update this state from WebSocket feeds. The read path is critical for opportunity detection and cannot tolerate lock contention.

Key constraints: - WebSocket updates must not block arbitrage detection - Multiple readers (strategy engines) with single writer (market monitor) per market - Sub-microsecond read latency required - State must be consistent (no torn reads)

Critical Note: "Lock-free" here refers to memory access safety for the cache, NOT cross-market execution state. Execution atomicity is handled separately by ADR-007 (Saga Pattern).

Decision

Implement lock-free atomic orderbook storage using arc_swap::ArcSwap for single-writer, multi-reader access patterns.

Implementation Pattern

use std::sync::Arc;
use arc_swap::ArcSwap;
use dashmap::DashMap;

pub struct OrderbookCache {
    // Lock-free read with atomic swap for updates
    books: DashMap<MarketId, ArcSwap<Orderbook>>,
}

impl OrderbookCache {
    pub fn update(&self, market: MarketId, book: Orderbook) {
        self.books.entry(market)
            .or_insert_with(|| ArcSwap::new(Arc::new(Orderbook::empty())))
            .store(Arc::new(book));
    }

    pub fn get(&self, market: &MarketId) -> Option<Arc<Orderbook>> {
        self.books.get(market).map(|e| e.load_full())
    }
}

Performance Characteristics

  • Reads: Lock-free, single atomic load operation
  • Writes: Atomic swap, no blocking of readers
  • Memory: Additional allocation per update (acceptable trade-off)

Alternatives Considered

Approach Pros Cons Verdict
ArcSwap Lock-free reads, simple API Extra allocation per write Chosen
RwLock Standard library, no deps Read contention possible Rejected
Crossbeam Epoch True lock-free Complex, overkill Rejected
Copy-on-write Vec Simple Memory overhead for large books Rejected

Consequences

Positive

  • Sub-microsecond read latency achievable
  • WebSocket updates never block arbitrage detection
  • No deadlock risk from concurrent access
  • Simple, auditable implementation

Negative

  • Memory allocation on every update
  • Not suitable for very high-frequency updates (>100K/s per market)
  • Old orderbook state briefly held in memory during GC

Neutral

  • Readers may see slightly stale data during swap (acceptable for trading)

References

Linked Requirements

  • NFR-ARCH-003: Orderbook cache must be lock-free for reads