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