betex 0.26.0

Betfair / Prediction Market Exchange
Documentation

betex

Deterministic, event-sourced matching engine for exchange odds and binary prediction markets.

WAL Locking

Mutable WAL opens take a fail-fast single-writer lock on WAL_ROOT/.writer.lock. This prevents two writer processes from accidentally opening the same WAL root at the same time. The lock is held for the lifetime of the mutable journal handler and is released automatically when the process exits. Read-only recovery via JournalReader does not take the writer lock.

This locking model is intended for local filesystems and single-attach block storage, including typical Kubernetes deployments backed by ReadWriteOnce / ReadWriteOncePod persistent disks.

It is not a complete fencing solution for shared RWX storage such as GKE Filestore, NFS, SMB, or other multi-node shared-disk environments. Those deployments need an external lease or fencing mechanism in addition to any local file lock.

WAL Sizing

JournalConfig.max_segment_events is a soft rotation hint, not a hard cap. The WAL poller commits the full poll_wait() batch and only rotates after that commit on a tx boundary. In practice, the true commit boundary is the available Disruptor backlog, bounded by ring size.

  • Default live ring size is 32768.
  • Default max_segment_events is 5000, so the nominal target is about 5000 events/segment.
  • At roughly 500k events/sec, 5000 events is about 10ms of traffic.
  • In live runs, Betex event payloads have been much smaller than the configured LMDB map: observed segments were typically a few MiB, with the largest seen around 6.6 MiB.

Sizing example for the current largest known batched-cancel payload:

  • OrderCancelledBatched with 4096 cancelled orders serializes to about 32904 bytes.
  • 5000 * 32904 ~= 157 MiB raw payload.
  • 32768 * 32904 ~= 1.004 GiB raw payload for one full-ring poll_wait() commit.

Operational implication:

  • If poll_wait() remains the effective commit boundary, size segment_map_size_bytes against the largest expected poll batch, not just against max_segment_events.
  • max_segment_events should be treated as a rotation hint for typical workloads, not as a strict upper bound on segment occupancy.