Skip to main content

ServerApp

Struct ServerApp 

Source
pub struct ServerApp(pub Exchange);
Expand description

Transparent newtype around Exchange that carries the Application trait impl. Exists solely so the impl can live in melin-server (the wiring crate) without violating the orphan rule — neither Application (in melin-app) nor Exchange (in melin-exchange-core) is local to melin-server, but ServerApp is.

The inner field is pub because the server frequently constructs an Exchange directly (Exchange::with_capacity) and wraps it; making the wrap explicit at every construction site is cheaper than introducing a parallel set of constructors here.

Tuple Fields§

§0: Exchange

Implementations§

Source§

impl ServerApp

Source

pub fn new() -> Self

Construct a ServerApp wrapping a freshly-initialised Exchange. Convenience for tests and bootstrap paths that want the default Exchange::new() sizing without spelling the wrap.

Methods from Deref<Target = Exchange>§

Source

pub fn cancel_replace( &mut self, symbol: Symbol, account: AccountId, order_id: OrderId, new_price: Price, new_quantity: Quantity, reports: &mut Vec<ExecutionReport>, )

Atomically amend a resting limit order’s price and/or quantity.

Validation order (all checks before any mutation):

  1. Instrument exists
  2. Order exists on the book (resting limit only — not stops, not market)
  3. Circuit breaker: halted or price band violation
  4. Risk limits: max qty, max notional
  5. Price-would-cross check: reject if new price crosses the spread
  6. Reservation adjustment: compute new required amount, check balance

If any check fails, the original order remains untouched.

Time priority rules:

  • Same price, qty decrease → keep priority
  • Same price, qty increase → lose priority
  • Price change → lose priority
Source

pub fn execute( &mut self, symbol: Symbol, order: Order, reports: &mut Vec<ExecutionReport>, )

Submit an order to the matching engine for the given instrument.

Validates the instrument exists, reserves funds, then executes. On fill, balances are updated. On reject/cancel, reserves are released.

Under feature = "skip-order-exec" the body is short-circuited to a single Rejected{NoLiquidity} push, used by the server’s transport-only benchmark build to isolate transport throughput from matching cost. Same wire shape — bench clients still see one response per SubmitOrder — but no order book / account state touched.

Source

pub fn snapshot_key_hwm(&self) -> Vec<(u64, u64)>

Snapshot per-key request sequence HWMs for serialization.

Source

pub fn instrument_specs(&self) -> impl Iterator<Item = &InstrumentSpec>

Iterate over instrument specs (for snapshot serialization).

Source

pub fn snapshot_order_sides(&self) -> Vec<((AccountId, OrderId), Side)>

Snapshot the order-side map as a Vec for serialization. Only serializes the side; reservation slots are ephemeral and reassigned on restore.

Source

pub fn snapshot_risk_limits(&self) -> Vec<(Symbol, RiskLimits)>

Snapshot the per-instrument risk limits for serialization.

Source

pub fn snapshot_circuit_breakers(&self) -> Vec<(Symbol, CircuitBreakerConfig)>

Snapshot the per-instrument circuit breaker configs for serialization.

Source

pub fn prefault_seed(&mut self, num_accounts: usize, num_instruments: usize)

Pre-allocate collections for a known bulk-seed workload.

Sizes the balance map to num_accounts × num_instruments × 2 (base + quote per instrument per account) so the seed phase doesn’t hit multi-hundred-ms rehash stalls as the map grows.

Populates the instrument pool with one OrderBook per expected instrument (indexed by symbol). add_instrument pulls from this pool instead of allocating fresh, avoiding the 5-11 ms first-touch + mlock spike during seed (matching thread runs under MCL_FUTURE so any new allocation faults thousands of pages at once).

Source

pub fn set_max_open_orders_per_account(&mut self, max: u32)

Configure the per-account open-order cap (0 = unlimited). See the field doc on max_open_orders_per_account for semantics and the primary/replica determinism constraint.

Source

pub fn max_open_orders_per_account(&self) -> u32

Read back the configured per-account open-order cap. Test/admin only.

Source

pub fn set_max_orders_per_second(&mut self, rate: u32, burst: u32)

Configure the per-account order-submission rate limit (SEC-04). Argument semantics (active values, 0 = disabled, etc.) live on the max_orders_per_second / max_orders_burst field docs above.

Bucket-clearing rule: existing per-account bucket state is cleared only when transitioning between two active configurations whose (rate, burst) values differ — the online- reconfig case where tokens credited at the old rate could over- credit under the new one. All other transitions preserve buckets:

  • Initial activation (previous config was (0, _) or (_, 0), i.e. limiter was disabled): buckets that exist on the map can only have come from a snapshot restore via restore_order_buckets, and that is exactly the state we need to preserve to close the SEC-04 divergence window. A fresh engine with no restored buckets is unaffected.
  • Deactivation (new config is (0, _) or (_, 0)): the limiter is off, so bucket contents are unobserved. Keeping them is harmless and avoids losing state if the operator later re-enables with the same values.
  • No-op reapply (values unchanged): obviously preserve.

Determinism: must match across primary and replicas — see the field docs on max_orders_per_second / max_orders_burst.

Side effect (online-reconfig path only): clearing buckets resets every account to a full burst at next first-touch. Operators should treat online reconfiguration as a rare, audit-logged change — frequent re-tuning is effectively a throttle bypass. Engine library users embedding the matching core should gate the call behind their own auth path.

Source

pub fn max_orders_per_second(&self) -> (u32, u32)

Read back the configured rate limit (rate_per_sec, burst). Test/admin only.

Source

pub fn set_current_event_ts_ns(&mut self, now_ns: u64)

Stash the current event’s now_ns so per-event methods (execute, cancel, …) can read a deterministic clock without each method taking a now_ns parameter. Called by Application::apply exactly once per event before dispatch.

Source

pub fn open_order_count(&self, account: AccountId) -> u32

Current count of open orders (resting limits + pending stops + in-flight) for account, across all instruments. Returns 0 if the account has never traded. Used by proptests and admin queries to inspect the same counter the SEC-03 cap reads.

Source

pub fn order_bucket_count(&self) -> usize

Live rate-limiter bucket count. Used by the server’s startup path to detect a primary↔replica config mismatch after snapshot restore (non-empty buckets paired with a disabled limiter indicates the operator forgot to wire the rate-limit config) and by tests to assert bucket-eviction behaviour.

Source

pub fn drain_due_scheduled_tasks( &mut self, now_ns: u64, reports: &mut Vec<ExecutionReport>, )

Drain every scheduled task whose fire_ns <= now_ns. Called at the head of every event the matching stage processes, so time-driven work runs in lockstep with the journal. Tombstones — tasks that point to orders that have already been cancelled or filled — are silently dropped via the find_gtd_expiry lookup.

Source

pub fn check_request_seq(&mut self, key_hash: u64, request_seq: u64) -> bool

Check per-key request sequence for idempotency dedup. Returns true if this is a new request (should be processed). Returns false if duplicate (caller should reject with DuplicateRequest). Exempt when key_hash == 0 (internal/seed events with no authenticated key).

Source

pub fn request_seq_hwm(&self, key_hash: u64) -> u64

Current request_seq HWM for key_hash, or 0 if no event has ever been accepted from that key. Read-only; safe to call from the matching stage at any point. Used by the QueryRequestSeq query handler so reconnecting clients can resume their outbound seq past whatever the engine has already seen.

Source

pub fn instrument_count(&self) -> usize

Number of active instruments (for diagnostics).

Source

pub fn set_risk_limits(&mut self, symbol: Symbol, limits: RiskLimits)

Set fat finger risk limits for an instrument. No-op if the instrument doesn’t exist (matches previous behavior).

Source

pub fn set_circuit_breaker( &mut self, symbol: Symbol, config: CircuitBreakerConfig, )

Set circuit breaker configuration for an instrument. No-op if the instrument doesn’t exist (matches previous behavior).

Source

pub fn set_fee_schedule( &mut self, symbol: Symbol, schedule: FeeSchedule, reports: &mut Vec<ExecutionReport>, )

Set the maker/taker fee schedule for an instrument.

When the effective max fee rate changes, all affected buy-side orders have their reservations adjusted:

  • Resting limit buys and pending stop-limit buys: reservation topped up from available balance, or cancelled if insufficient.
  • Pending stop-market buys: quote_budget recalculated so the fill leaves room for the new fee.

No-op if the instrument doesn’t exist, or if either rate is outside the documented ±10_000 bps range (±100%) — see below.

Source

pub fn prefault(&mut self)

Touch all pre-allocated HashMap pages so page faults happen at startup, not on the hot path. Call once after adding instruments, before accepting orders. Skips maps that already contain data — their pages are already faulted from the insertions that populated them.

Source

pub fn add_instrument(&mut self, spec: InstrumentSpec)

Register a new instrument with its currency pair specification. Grows the instrument Vec if needed (admin operation, not hot path).

Source

pub fn deposit(&mut self, account: AccountId, currency: CurrencyId, amount: u64)

Deposit funds into an account.

Source

pub fn provision_account(&mut self, account: AccountId, amount: u64)

Provision an account with amount deposited in every currency of every registered instrument. Replaces O(instruments) individual Deposit calls with a single operation for bulk seeding.

Source

pub fn accounts(&self) -> &AccountManager

Get the account manager (for balance queries).

Source

pub fn cancel_all( &mut self, account: AccountId, reports: &mut Vec<ExecutionReport>, )

Cancel all resting orders and pending stops for an account across all instruments (kill switch). Releases all associated reservations.

Source

pub fn end_of_day(&mut self, reports: &mut Vec<ExecutionReport>)

Cancel all resting orders and pending stops with TimeInForce::Day across all instruments. Called at end-of-session.

Source

pub fn disable_instrument( &mut self, symbol: Symbol, reports: &mut Vec<ExecutionReport>, )

Disable an instrument: reject future orders and cancel all resting orders and pending stops. Idempotent — disabling an already-disabled instrument is a no-op (no reports emitted).

Source

pub fn enable_instrument( &mut self, symbol: Symbol, reports: &mut Vec<ExecutionReport>, )

Re-enable a previously disabled instrument, allowing new orders.

Source

pub fn remove_instrument( &mut self, symbol: Symbol, reports: &mut Vec<ExecutionReport>, )

Permanently remove a disabled instrument, reclaiming memory. Only succeeds if the instrument is disabled and has no resting orders (which disable guarantees). Active instruments must be disabled first.

Source

pub fn cancel( &mut self, symbol: Symbol, account: AccountId, order_id: OrderId, reports: &mut Vec<ExecutionReport>, )

Cancel a resting order on the given instrument.

Source

pub fn best_bid(&self, symbol: Symbol) -> Option<Price>

Best (highest) bid on symbol’s book, or None if the bid side is empty or the symbol is not registered. Read-only book introspection (market-data / audit queries); not on the matching hot path.

Source

pub fn best_ask(&self, symbol: Symbol) -> Option<Price>

Best (lowest) ask on symbol’s book, or None if the ask side is empty or the symbol is not registered.

Source

pub fn depth_at(&self, symbol: Symbol, price: Price, side: Side) -> u64

Total resting quantity at one exact price level on symbol’s book, or 0 if the level does not exist or the symbol is not registered.

Source

pub fn withdraw( &mut self, account: AccountId, currency: CurrencyId, amount: u64, ) -> Result<(), RejectReason>

Withdraw funds from an account. Rejects if the account has resting orders (must CancelAll first) or insufficient available balance. Removes the balance entry if it reaches zero (memory cleanup).

Source

pub fn clone_via_snapshot(&self) -> Exchange

Create a deep copy of this Exchange by round-tripping through the snapshot representation. Used by the shadow snapshot stage to obtain an independent replica of the exchange state at startup.

Not suitable for the hot path — allocates extensively.

Trait Implementations§

Source§

impl Application for ServerApp

Source§

const APP_VERSION: u16 = engine_snapshot::PAYLOAD_VERSION

Schema version for the snapshot payload. Tracks the underlying snapshot module’s PAYLOAD_VERSION — any change there forces a bump here too, surfaced through the transport-owned frame.

Source§

fn apply( &mut self, event: Self::Event, ctx: &ApplyCtx, out: &mut Vec<Self::Report>, ) -> Option<Self::QueryResponse>

Thin dispatcher over TradingEvent. Marked #[inline] so the matching stage’s monomorphised hot loop can see through to each concrete Exchange method: the inner methods (execute, cancel, …) own the real work and keep their own inlining attrs.

Source§

fn prefault(&mut self)

Route through Exchange::prefault, which walks the pre-allocated slabs and indices so the first hot-path access after startup doesn’t soft-fault. Avoids the default snapshot-round-trip implementation on a cold allocator.

Source§

fn clone_via_snapshot(&self) -> Result<Self>

Exchange exposes an in-memory clone_via_snapshot that skips the byte serialisation — faster than the default serialise-then-deserialise path. Keep the optimisation for the shadow-snapshot stage.

Source§

fn snapshot<W: Write>(&self, w: &mut W) -> Result<()>

Writes the engine payload bytes verbatim. The transport stores APP_VERSION in its frame and rejects mismatching files before restore is ever called, so duplicating the version in the payload would be unreachable. If multi-version migration ever lands, drop the transport-side APP_VERSION check and reintroduce an in-payload version prefix here.

Source§

type Event = TradingEvent

The application-defined event type. One variant per business operation (submit order, cancel, deposit, …).
Source§

type Report = ExecutionReport

Per-event output payloads. One input event may produce many reports (fills, acks, query rows). Copy keeps the output ring buffer allocation-free.
Source§

type QueryResponse = QueryResponse

1:1 query responses returned directly from apply, bypassing the fan-out scratch Vec. Routed through OutputPayload::QueryResponse on the output ring. Read more
Source§

fn tick(&mut self, now_ns: u64, out: &mut Vec<Self::Report>)

Advance the application’s wall-clock without applying a business event. The transport calls tick once per dispatched slot, before apply, to fire time-driven tasks (expiries, session transitions) with monotonically increasing now_ns.
Source§

fn check_request_seq(&mut self, key_hash: u64, seq: u64) -> bool

Per-key idempotency gate. Returns true if seq is strictly greater than the previously seen sequence for key_hash (and the high-water mark has been advanced), false on a duplicate. Read more
Source§

fn build_reject( event: &Self::Event, reason: TransportRejectReason, ) -> Self::Report

Synthesise a rejection report for a transport-originated reject. Called by the transport before apply has observed the event. No access to &self — the reject must be constructible from the event alone (plus the transport’s reason).
Source§

fn restore<R: Read>(r: &mut R) -> Result<Self>

Reconstruct application state from a snapshot produced by snapshot. r yields exactly the bytes that snapshot wrote — the transport has already stripped its framing.
Source§

impl Default for ServerApp

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl Deref for ServerApp

Source§

type Target = Exchange

The resulting type after dereferencing.
Source§

fn deref(&self) -> &Exchange

Dereferences the value.
Source§

impl DerefMut for ServerApp

Source§

fn deref_mut(&mut self) -> &mut Exchange

Mutably dereferences the value.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<P, T> Receiver for P
where P: Deref<Target = T> + ?Sized, T: ?Sized,

Source§

type Target = T

🔬This is a nightly-only experimental API. (arbitrary_self_types)
The target type on which the method may be called.
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more