1use super::Collector;
28use super::chain::{FatalSlot, OpMeterSlot, StageLifecycle};
29use super::handoff::{ChunkConfig, SinkHandoff};
30use crate::backpressure::InflightBudget;
31use crate::checkpoint::AckRef;
32use crate::deser::RecFamily;
33use crate::error::{ErrorPolicy, FatalError, SinkError};
34use crate::record::{Flow, Record, RecordMeta};
35use crate::sink::{RecordRouter, RowEncoder, ShardQueues};
36use bytes::BytesMut;
37use std::any::Any;
38use std::marker::PhantomData;
39use std::sync::Arc;
40use std::time::Duration;
41
42#[derive(Clone, Debug)]
48#[non_exhaustive]
49pub struct SinkCtx {
50 pub(crate) name: String,
51 pub(crate) queues: ShardQueues,
52 pub(crate) budget: Arc<InflightBudget>,
53 pub(crate) chunk: ChunkConfig,
57}
58
59impl SinkCtx {
60 #[must_use]
66 pub fn new(name: String, queues: ShardQueues, budget: Arc<InflightBudget>) -> Self {
67 SinkCtx {
68 name,
69 queues,
70 budget,
71 chunk: ChunkConfig::default(),
72 }
73 }
74
75 #[must_use]
78 pub fn with_chunk(mut self, chunk: ChunkConfig) -> Self {
79 self.chunk = chunk;
80 self
81 }
82}
83
84pub struct Sink<F: RecFamily> {
89 idx: usize,
90 _f: PhantomData<fn() -> F>,
91}
92
93impl<F: RecFamily> Sink<F> {
94 pub(crate) fn new(idx: usize) -> Self {
95 Sink {
96 idx,
97 _f: PhantomData,
98 }
99 }
100}
101
102impl<F: RecFamily> Clone for Sink<F> {
103 fn clone(&self) -> Self {
104 *self
105 }
106}
107
108impl<F: RecFamily> Copy for Sink<F> {}
109
110impl<F: RecFamily> std::fmt::Debug for Sink<F> {
111 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112 f.debug_struct("Sink").field("idx", &self.idx).finish()
113 }
114}
115
116trait EncoderClone<F: RecFamily>: RowEncoder<F> {
121 fn clone_box(&self) -> Box<dyn EncoderClone<F>>;
123}
124
125impl<F: RecFamily, T> EncoderClone<F> for T
126where
127 T: RowEncoder<F> + Clone + 'static,
128{
129 fn clone_box(&self) -> Box<dyn EncoderClone<F>> {
130 Box::new(self.clone())
131 }
132}
133
134type BoxedEncoder<F> = Box<dyn EncoderClone<F>>;
136
137impl<F: RecFamily> Clone for BoxedEncoder<F> {
138 fn clone(&self) -> Self {
139 (**self).clone_box()
144 }
145}
146
147impl<F: RecFamily> RowEncoder<F> for BoxedEncoder<F> {
148 fn encode<'buf>(
149 &mut self,
150 rec: &Record<F::Rec<'buf>>,
151 buf: &mut BytesMut,
152 ) -> Result<(), SinkError> {
153 (**self).encode(rec, buf)
154 }
155
156 fn buffered_bytes(&self) -> usize {
157 (**self).buffered_bytes()
158 }
159
160 fn finish_chunk(&mut self, buf: &mut BytesMut) -> Result<(), SinkError> {
161 (**self).finish_chunk(buf)
162 }
163}
164
165type BoxedRouter<F> = Box<dyn RecordRouter<F>>;
167
168impl<F: RecFamily> RecordRouter<F> for BoxedRouter<F> {
169 fn route_record<'buf>(&self, rec: &Record<F::Rec<'buf>>, num_shards: usize) -> usize {
170 (**self).route_record(rec, num_shards)
171 }
172}
173
174type Branch<F> = SinkHandoff<F, BoxedEncoder<F>, BoxedRouter<F>>;
177
178pub(crate) trait ErasedBranch: Send {
184 fn relieve(&mut self) -> Flow;
185 fn flush_terminal(&mut self) -> Flow;
186 fn take_fatal(&mut self) -> Option<FatalError>;
187 fn on_batch_end(&mut self, elapsed: Duration);
188 fn as_any_mut(&mut self) -> &mut dyn Any;
189}
190
191impl<F, E, R> ErasedBranch for SinkHandoff<F, E, R>
192where
193 F: RecFamily + 'static,
194 E: RowEncoder<F> + Clone + 'static,
195 R: RecordRouter<F> + 'static,
196{
197 fn relieve(&mut self) -> Flow {
198 StageLifecycle::relieve(self)
199 }
200
201 fn flush_terminal(&mut self) -> Flow {
202 StageLifecycle::flush_terminal(self)
203 }
204
205 fn take_fatal(&mut self) -> Option<FatalError> {
206 StageLifecycle::take_fatal(self)
207 }
208
209 fn on_batch_end(&mut self, elapsed: Duration) {
210 StageLifecycle::on_batch_end(self, elapsed);
211 }
212
213 fn as_any_mut(&mut self) -> &mut dyn Any {
214 self
215 }
216}
217
218pub(crate) fn new_branch<F, E, R>(
220 encoder: E,
221 router: R,
222 queues: ShardQueues,
223 budget: Arc<InflightBudget>,
224 cfg: ChunkConfig,
225 meter: OpMeterSlot,
226 component: Arc<str>,
227) -> Box<dyn ErasedBranch>
228where
229 F: RecFamily + 'static,
230 E: RowEncoder<F> + Clone + Send + 'static,
231 R: RecordRouter<F> + 'static,
232{
233 let encoder: BoxedEncoder<F> = Box::new(encoder);
234 let router: BoxedRouter<F> = Box::new(router);
235 let handoff: Branch<F> =
236 SinkHandoff::new(encoder, router, queues, budget, cfg, meter, component);
237 Box::new(handoff)
238}
239
240pub struct SplitEmitter<'a> {
247 branches: &'a mut [Box<dyn ErasedBranch>],
248 meta: RecordMeta,
249 ack: &'a AckRef,
250 emitted: u32,
251 flow: Flow,
252 latched: bool,
254}
255
256impl std::fmt::Debug for SplitEmitter<'_> {
257 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
258 f.debug_struct("SplitEmitter")
259 .field("emitted", &self.emitted)
260 .field("flow", &self.flow)
261 .finish_non_exhaustive()
262 }
263}
264
265impl SplitEmitter<'_> {
266 #[inline]
278 pub fn emit<'buf, F: RecFamily + 'static>(&mut self, handle: Sink<F>, row: F::Rec<'buf>) {
279 let branch = self
280 .branches
281 .get_mut(handle.idx)
282 .and_then(|b| b.as_any_mut().downcast_mut::<Branch<F>>())
283 .expect(
284 "split branch/handle mismatch: this Sink<F> handle does not name a \
285 branch of this split (a handle from another split, or the wrong \
286 record family)",
287 );
288 if self.latched {
292 return;
293 }
294 let flow = branch.push(Record {
295 payload: row,
296 meta: self.meta,
297 ack: self.ack.clone(),
298 });
299 self.latched = branch.fatal.0.is_some();
300 self.emitted += 1;
301 if self.flow != Flow::Blocked {
302 self.flow = flow;
303 }
304 }
305
306 #[must_use]
308 pub fn meta(&self) -> RecordMeta {
309 self.meta
310 }
311}
312
313pub struct SplitTerminal<SrcF: RecFamily, G> {
319 route: G,
320 branches: Vec<Box<dyn ErasedBranch>>,
321 unmatched: ErrorPolicy,
322 meter: OpMeterSlot,
323 fatal: FatalSlot,
324 latched: bool,
327 component: Arc<str>,
328 _family: PhantomData<fn() -> SrcF>,
329}
330
331impl<SrcF: RecFamily, G> SplitTerminal<SrcF, G> {
332 pub(crate) fn new(
333 route: G,
334 branches: Vec<Box<dyn ErasedBranch>>,
335 unmatched: ErrorPolicy,
336 meter: OpMeterSlot,
337 component: Arc<str>,
338 ) -> Self {
339 SplitTerminal {
340 route,
341 branches,
342 unmatched,
343 meter,
344 fatal: FatalSlot(None),
345 latched: false,
346 component,
347 _family: PhantomData,
348 }
349 }
350}
351
352impl<SrcF: RecFamily, G> std::fmt::Debug for SplitTerminal<SrcF, G> {
353 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
354 f.debug_struct("SplitTerminal")
355 .field("branches", &self.branches.len())
356 .field("unmatched", &self.unmatched)
357 .finish_non_exhaustive()
358 }
359}
360
361impl<'buf, SrcF, G> Collector<<SrcF as RecFamily>::Rec<'buf>> for SplitTerminal<SrcF, G>
362where
363 SrcF: RecFamily,
364 G: for<'b> FnMut(SrcF::Rec<'b>, &mut SplitEmitter<'_>),
365{
366 fn push(&mut self, rec: Record<SrcF::Rec<'buf>>) -> Flow {
367 self.meter.0.seen();
368 if self.fatal.0.is_some() || self.latched {
373 return Flow::Continue;
374 }
375 let Record {
376 payload, meta, ack, ..
377 } = rec;
378 let mut em = SplitEmitter {
379 branches: &mut self.branches,
380 meta,
381 ack: &ack,
382 emitted: 0,
383 flow: Flow::Continue,
384 latched: false,
385 };
386 (self.route)(payload, &mut em);
387 let (emitted, flow) = (em.emitted, em.flow);
388 self.latched = em.latched;
389 if emitted == 0 {
390 match self.unmatched {
391 ErrorPolicy::Skip => self.meter.0.unrouted(),
394 _ => {
396 self.meter.0.fatal_error();
397 self.fatal.0 = Some(FatalError {
398 component: self.component.to_string(),
399 reason: "record matched no split branch".into(),
400 });
401 }
402 }
403 } else {
404 self.meter.0.out_n(u64::from(emitted));
405 }
406 flow
407 }
408}
409
410impl<SrcF: RecFamily, G> StageLifecycle for SplitTerminal<SrcF, G> {
411 fn on_batch_end(&mut self, elapsed: Duration) {
412 self.meter.0.flush(elapsed);
413 for branch in &mut self.branches {
414 branch.on_batch_end(elapsed);
415 }
416 }
417
418 fn take_fatal(&mut self) -> Option<FatalError> {
419 self.latched = false;
424 let mut earliest = None;
425 for branch in &mut self.branches {
426 let fatal = branch.take_fatal();
427 if earliest.is_none() {
428 earliest = fatal;
429 }
430 }
431 earliest.or_else(|| self.fatal.0.take())
432 }
433
434 fn relieve(&mut self) -> Flow {
435 let mut flow = Flow::Continue;
438 for branch in &mut self.branches {
439 if branch.relieve() == Flow::Blocked {
440 flow = Flow::Blocked;
441 }
442 }
443 flow
444 }
445
446 fn flush_terminal(&mut self) -> Flow {
447 let mut flow = Flow::Continue;
448 for branch in &mut self.branches {
449 if branch.flush_terminal() == Flow::Blocked {
450 flow = Flow::Blocked;
451 }
452 }
453 flow
454 }
455}