Skip to content

RepartitionExec produces no output if the input stream errors #437

Description

@alamb

Describe the bug
Given a RepartitionExec where its input stream does not have a record batch for immediate consumption, it will terminate early.

I found this while trying to figure out why this plan was failing in IOx (nothing ever bothered to read from the stream provided to RepartionExec:

ProjectionExec: expr=[town, count]
RepartitionExec: partitioning=RoundRobinBatch(16)
IOxReadFilterNode: table_name=restaurant, chunks=1 predicate=Predicate

To Reproduce
Set up a plan like this:

┌───────────────────┐ ┌───────────────────────┐
│ │ │ │
│ InputStream │───────▶│ RepartitionStream │
│ │ │ │
└───────────────────┘ └───────────────────────┘

Where the input stream won't produce the record batch immediately. Full reproducer below.

I expect to the repartition stream to produce the same record batch as the input stream (will) provide (or produce a meaningful error). However, I get nothing!

expected:
[
"+------------------+",
"| my_awesome_field |",
"+------------------+",
"| foo |",
"| bar |",
"+------------------+",
]
actual:
[
"++",
"++",
]

Full Reproducer (run in repartition.rs)
Add any other context about the problem here.

#[tokio::test]asyncfnrepartition_with_delayed_stream(){let input = DelayedExec::new();let partitioning = input.output_partitioning();let expected_batches = vec![input.batch.clone()];let exec = RepartitionExec::try_new(Arc::new(input), partitioning).unwrap();let expected = vec!["+------------------+","| my_awesome_field |","+------------------+","| foo |","| bar |","+------------------+",];assert_batches_eq!(&expected,&expected_batches);let output_stream = exec.execute(0).await.unwrap();let batches = crate::physical_plan::common::collect(output_stream).await.unwrap();assert_batches_eq!(&expected,&batches);}#[derive(Debug)]structDelayedExec{batch:RecordBatch}implDelayedExec{fnnew() -> Self{let batch = RecordBatch::try_from_iter(vec![("my_awesome_field",Arc::new(StringArray::from(vec!["foo","bar"]))asArrayRef)]).unwrap();Self{
batch
}}}#[async_trait]implExecutionPlanforDelayedExec{fnas_any(&self) -> &dynAny{self}fnschema(&self) -> SchemaRef{self.batch.schema()}fnoutput_partitioning(&self) -> Partitioning{Partitioning::UnknownPartitioning(1)}fnchildren(&self) -> Vec<Arc<dynExecutionPlan>>{unimplemented!()}fnwith_new_children(&self,_children:Vec<Arc<dynExecutionPlan>>,) -> Result<Arc<dynExecutionPlan>>{unimplemented!()}/// Returns a stream which does not have data immediately, but/// needs to yield (to allow another task to run) to get its/// input.asyncfnexecute(&self,partition:usize) -> Result<SendableRecordBatchStream>{assert_eq!(partition,0);let batch = self.batch.clone();let schema = batch.schema();let(tx, rx) = tokio::sync::mpsc::channel(2);// task simply sends the batch
tokio::task::spawn(asyncmove{println!("Sending batch via delayed stream");ifletErr(e) = tx.send(Ok(batch.clone())).await{println!("ERROR batch via delayed stream: {}", e);}});// returned stream simply reads off the rx streamlet stream = ParquetStream{
schema,inner:ReceiverStream::new(rx),};Ok(Box::pin(stream))}}#[derive(Debug)]pubstructParquetStream{schema:SchemaRef,inner:ReceiverStream<ArrowResult<RecordBatch>>,}implStreamforParquetStream{typeItem = ArrowResult<RecordBatch>;fnpoll_next(mutself: std::pin::Pin<&mutSelf>,cx:&mutContext<'_>,) -> Poll<Option<Self::Item>>{println!("ParquetStream::poll_next");let res = self.inner.poll_next_unpin(cx);println!("ParquetStream::poll_next() done");
res
}}implRecordBatchStreamforParquetStream{fnschema(&self) -> SchemaRef{Arc::clone(&self.schema)}}implDropforParquetStream{fndrop(&mutself){println!("ParquetStream::drop()");}}

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions