pub struct Ingest<R> {
pub(crate) tx: Arc<[Sender<Job<R>>]>,
pub(crate) turn: Arc<AtomicU64>,
pub(crate) rejects: &'static Rejects,
pub(crate) wal: Option<Arc<Wal>>,
pub(crate) signal: Signal,
}Expand description
The write handle for one signal. R is that signal’s OTLP export request.
Fields§
§tx: Arc<[Sender<Job<R>>]>§turn: Arc<AtomicU64>Where the next export that cannot go to shard 0 starts looking. Shared across clones, because the point of it is to spread waiters over shards rather than over handles.
rejects: &'static Rejects§wal: Option<Arc<Wal>>§signal: SignalImplementations§
Source§impl<R> Ingest<R>
impl<R> Ingest<R>
Sourcefn reserve(&self) -> Option<Permit<'_, Job<R>>>
fn reserve(&self) -> Option<Permit<'_, Job<R>>>
A slot in the first shard that has one, or None if every shard is full
or gone.
First fit from shard 0 rather than round-robin, and that is the whole
sharding policy. Round-robin spreads a trickle of exports over every
shard, and since each shard owns its own open block, a node doing two
exports a second would publish shards nearly-empty blocks every
max_block_age instead of one — the small-file explosion section 4
rejects hash sharding for, arrived at from the other direction. First
fit keeps a node that is not saturating one flusher behaving exactly as
it did with one, and starts using the second shard at the moment the
first one’s queue stops draining, which is the moment the consumer’s
service time became the curve.
Ordering across shards is not preserved and does not need to be: two
exports are two OTLP requests, the spec orders neither against the
other, and block timestamps come from the data. Ordering within a
shard still is, which is what the carry rule in flusher needs.
Source§impl<R: Message> Ingest<R>
impl<R: Message> Ingest<R>
Sourcepub async fn submit(&self, req: R) -> Result<(), Rejected>
pub async fn submit(&self, req: R) -> Result<(), Rejected>
Enqueue and wait for durability.
What “durable” means here is the one thing Config::wal decides.
Without a log this returns once the block containing the request has
been fsynced and renamed into place, which is correct and costs a whole
max_block_age at the tail. With one it returns once the request is a
frame in the log’s page cache, which is section 11’s 2.6 s p99 turned into
microseconds and is why the log exists.
Source§impl<R: Message + Default> Ingest<R>
impl<R: Message + Default> Ingest<R>
Sourcepub fn replay(&self, body: &[u8], seq: u64) -> Result<(), Rejected>
pub fn replay(&self, body: &[u8], seq: u64) -> Result<(), Rejected>
Push one frame recovered from the log back into this signal’s flusher, under the sequence it already has.
Not submit: the frame is in the log already, so
re-appending it would number it above every watermark and the block
storing it would claim the copy instead of the original — which replays
again on the next boot, and the one after that. Nothing waits for the
ack either; the client that sent this got its answer before the crash,
or gave up long ago.
Blocking, and deliberately: this is called from a spawn_blocking hop
at boot, and the bounded channel is the only thing keeping a multi-
gigabyte log from being decoded into memory faster than it can be
sealed.
The two failures are worth telling apart: Rejected::Failed is one
frame that will never decode, which is a line in the log and the next
frame; Rejected::Closed is the flusher being gone, which means the
rest of the replay would go nowhere.
Trait Implementations§
Auto Trait Implementations§
impl<R> Freeze for Ingest<R>
impl<R> RefUnwindSafe for Ingest<R>
impl<R> Send for Ingest<R>where
R: Send,
impl<R> Sync for Ingest<R>where
R: Send,
impl<R> Unpin for Ingest<R>
impl<R> UnsafeUnpin for Ingest<R>
impl<R> UnwindSafe for Ingest<R>
Blanket Implementations§
impl<T> Allocation for T
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request§impl<L> LayerExt<L> for L
impl<L> LayerExt<L> for L
§fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>where
L: Layer<S>,
fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>where
L: Layer<S>,
Layered].