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}
253
254impl std::fmt::Debug for SplitEmitter<'_> {
255 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
256 f.debug_struct("SplitEmitter")
257 .field("emitted", &self.emitted)
258 .field("flow", &self.flow)
259 .finish_non_exhaustive()
260 }
261}
262
263impl SplitEmitter<'_> {
264 #[inline]
274 pub fn emit<'buf, F: RecFamily + 'static>(&mut self, handle: Sink<F>, row: F::Rec<'buf>) {
275 let branch = self
276 .branches
277 .get_mut(handle.idx)
278 .and_then(|b| b.as_any_mut().downcast_mut::<Branch<F>>())
279 .expect(
280 "split branch/handle mismatch: this Sink<F> handle does not name a \
281 branch of this split (a handle from another split, or the wrong \
282 record family)",
283 );
284 let flow = branch.push(Record {
285 payload: row,
286 meta: self.meta,
287 ack: self.ack.clone(),
288 });
289 self.emitted += 1;
290 if self.flow != Flow::Blocked {
291 self.flow = flow;
292 }
293 }
294
295 #[must_use]
297 pub fn meta(&self) -> RecordMeta {
298 self.meta
299 }
300}
301
302pub struct SplitTerminal<SrcF: RecFamily, G> {
308 route: G,
309 branches: Vec<Box<dyn ErasedBranch>>,
310 unmatched: ErrorPolicy,
311 meter: OpMeterSlot,
312 fatal: FatalSlot,
313 component: Arc<str>,
314 _family: PhantomData<fn() -> SrcF>,
315}
316
317impl<SrcF: RecFamily, G> SplitTerminal<SrcF, G> {
318 pub(crate) fn new(
319 route: G,
320 branches: Vec<Box<dyn ErasedBranch>>,
321 unmatched: ErrorPolicy,
322 meter: OpMeterSlot,
323 component: Arc<str>,
324 ) -> Self {
325 SplitTerminal {
326 route,
327 branches,
328 unmatched,
329 meter,
330 fatal: FatalSlot(None),
331 component,
332 _family: PhantomData,
333 }
334 }
335}
336
337impl<SrcF: RecFamily, G> std::fmt::Debug for SplitTerminal<SrcF, G> {
338 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
339 f.debug_struct("SplitTerminal")
340 .field("branches", &self.branches.len())
341 .field("unmatched", &self.unmatched)
342 .finish_non_exhaustive()
343 }
344}
345
346impl<'buf, SrcF, G> Collector<<SrcF as RecFamily>::Rec<'buf>> for SplitTerminal<SrcF, G>
347where
348 SrcF: RecFamily,
349 G: for<'b> FnMut(SrcF::Rec<'b>, &mut SplitEmitter<'_>),
350{
351 fn push(&mut self, rec: Record<SrcF::Rec<'buf>>) -> Flow {
352 self.meter.0.seen();
353 if self.fatal.0.is_some() {
356 return Flow::Continue;
357 }
358 let Record {
359 payload, meta, ack, ..
360 } = rec;
361 let mut em = SplitEmitter {
362 branches: &mut self.branches,
363 meta,
364 ack: &ack,
365 emitted: 0,
366 flow: Flow::Continue,
367 };
368 (self.route)(payload, &mut em);
369 let (emitted, flow) = (em.emitted, em.flow);
370 if emitted == 0 {
371 match self.unmatched {
372 ErrorPolicy::Skip => self.meter.0.unrouted(),
375 _ => {
377 self.fatal.0 = Some(FatalError {
378 component: self.component.to_string(),
379 reason: "record matched no split branch".into(),
380 });
381 }
382 }
383 } else {
384 self.meter.0.out_n(u64::from(emitted));
385 }
386 flow
387 }
388}
389
390impl<SrcF: RecFamily, G> StageLifecycle for SplitTerminal<SrcF, G> {
391 fn on_batch_end(&mut self, elapsed: Duration) {
392 self.meter.0.flush(elapsed);
393 for branch in &mut self.branches {
394 branch.on_batch_end(elapsed);
395 }
396 }
397
398 fn take_fatal(&mut self) -> Option<FatalError> {
399 if let Some(fatal) = self.fatal.0.take() {
400 return Some(fatal);
401 }
402 for branch in &mut self.branches {
403 if let Some(fatal) = branch.take_fatal() {
404 return Some(fatal);
405 }
406 }
407 None
408 }
409
410 fn relieve(&mut self) -> Flow {
411 let mut flow = Flow::Continue;
414 for branch in &mut self.branches {
415 if branch.relieve() == Flow::Blocked {
416 flow = Flow::Blocked;
417 }
418 }
419 flow
420 }
421
422 fn flush_terminal(&mut self) -> Flow {
423 let mut flow = Flow::Continue;
424 for branch in &mut self.branches {
425 if branch.flush_terminal() == Flow::Blocked {
426 flow = Flow::Blocked;
427 }
428 }
429 flow
430 }
431}