Skip to main content

SubscriptionBuffer

Struct SubscriptionBuffer 

Source
pub struct SubscriptionBuffer { /* private fields */ }
Expand description

Egress buffer of one subscription. It applies the subscription’s [Backpressure] policy.

The buffer never blocks and never waits. It is a plain in-memory queue (or single slot), not thread-safe by itself. BackpressureManager owns many of them, and the emitter wraps the manager in a lock.

§Examples

use brokapi_core::{
    Backpressure, Event, InstrumentId, InstrumentKey, NativeId, SubscriptionId,
};
use brokapi_runtime::{PushResult, SubscriptionBuffer};

let sber = InstrumentId::new(
    InstrumentKey::new("SBER", "TQBR"),
    NativeId::TickerClass { ticker: "SBER".into(), class_code: "TQBR".into() },
);
let mut buf = SubscriptionBuffer::new(SubscriptionId::new(1), sber, Backpressure::DropNewest { cap: 1 });

assert_eq!(buf.try_push(Event::Balances(vec![])), PushResult::Delivered);
// The buffer holds one event. The next one is thrown away and counted.
assert_eq!(buf.try_push(Event::Balances(vec![])), PushResult::DroppedNewest);
assert_eq!(buf.dropped(), 1);
assert_eq!(buf.drain().len(), 1);

Implementations§

Source§

impl SubscriptionBuffer

Source

pub fn new( sub: SubscriptionId, instrument: InstrumentId, policy: Backpressure, ) -> Self

Creates an empty buffer for a subscription with the given policy.

A cap of 0 in Lossless or DropNewest makes a buffer that accepts nothing: the first event already overflows (or is dropped).

Source

pub fn sub_id(&self) -> SubscriptionId

The subscription this buffer serves.

Source

pub fn instrument(&self) -> &InstrumentId

The instrument of the subscription, as given to new.

Source

pub fn is_overflowed(&self) -> bool

Whether a Lossless buffer has overflowed and not been reset yet.

Source

pub fn conflated(&self) -> u64

How many events a Conflate buffer replaced before they were taken.

Source

pub fn dropped(&self) -> u64

How many events a DropNewest buffer threw away.

Source

pub fn len(&self) -> usize

How many events wait in the buffer. For Conflate this is 0 or 1.

Source

pub fn is_empty(&self) -> bool

Whether the buffer holds no event.

Source

pub fn try_push(&mut self, event: Event) -> PushResult

Offers an event to the buffer without blocking.

  • Conflate: the event becomes the latest value of its kind (an order book, a quote, a portfolio and so on: one slot per kind). A value of the same kind that was still waiting is replaced and counted in conflated. Result: PushResult::Conflated.
  • Lossless { cap }: stored while fewer than cap events wait. The first event that finds the buffer full is not stored, the buffer is flagged overflowed and the result is PushResult::Overflow. After that every event gets Overflow and is not stored.
  • DropNewest { cap }: stored while fewer than cap events wait. Otherwise the new event is thrown away and counted in dropped.

Why Lossless stops for good: it is used for events that must not have a hole (orders, fills). Once one is lost, later events would hide the gap, so the consumer must be told and re-read the state.

§Examples
use brokapi_core::{Backpressure, Event, InstrumentId, InstrumentKey, NativeId, SubscriptionId};
use brokapi_runtime::{PushResult, SubscriptionBuffer};

let sber = InstrumentId::new(
    InstrumentKey::new("SBER", "TQBR"),
    NativeId::TickerClass { ticker: "SBER".into(), class_code: "TQBR".into() },
);
let mut buf = SubscriptionBuffer::new(SubscriptionId::new(1), sber, Backpressure::Lossless { cap: 1 });

assert_eq!(buf.try_push(Event::Balances(vec![])), PushResult::Delivered);
assert_eq!(buf.try_push(Event::Balances(vec![])), PushResult::Overflow);
assert!(buf.is_overflowed());
// Even after the consumer takes the stored event, the buffer stays overflowed.
assert_eq!(buf.drain().len(), 1);
assert_eq!(buf.try_push(Event::Balances(vec![])), PushResult::Overflow);
Source

pub fn overflow_event(&self, lost_from: UnixNanos) -> Event

Builds the [Event::Overflow] notice for this subscription.

lost_from is the wall-clock time from which events may be missing. The buffer does not send the notice itself, the owner does.

§Examples
use brokapi_core::{Backpressure, Event, InstrumentId, InstrumentKey, NativeId, SubscriptionId, UnixNanos};
use brokapi_runtime::SubscriptionBuffer;

let sber = InstrumentId::new(
    InstrumentKey::new("SBER", "TQBR"),
    NativeId::TickerClass { ticker: "SBER".into(), class_code: "TQBR".into() },
);
let buf = SubscriptionBuffer::new(SubscriptionId::new(7), sber, Backpressure::Lossless { cap: 1 });
let notice = buf.overflow_event(UnixNanos::from_nanos(5));
assert!(matches!(notice, Event::Overflow { sub, .. } if sub == SubscriptionId::new(7)));
Source

pub fn drain(&mut self) -> Vec<Event>

Takes everything out of the buffer: the latest conflated value first, then the queue in arrival order.

Draining does not clear the overflowed flag. Use BackpressureManager::clear_degraded for that.

Trait Implementations§

Source§

impl Debug for SubscriptionBuffer

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

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.

§

impl<T> Instrument for T

§

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

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

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<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

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.
§

impl<T> WithSubscriber for T

§

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
§

fn with_current_subscriber(self) -> WithDispatch<Self>

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