#[cfg(not(target_family = "wasm"))]
use std::collections::VecDeque;
#[cfg(not(target_family = "wasm"))]
use std::pin::Pin;
#[cfg(not(target_family = "wasm"))]
use std::task::{Context, Poll};
#[cfg(not(target_family = "wasm"))]
use futures::Stream;
#[cfg(not(target_family = "wasm"))]
use crate::exec::ValueBatch;
use crate::exec::ValueBatchStream;
use crate::exec::access_mode::AccessMode;
use crate::exec::cardinality::CardinalityHint;
#[cfg(not(target_family = "wasm"))]
use crate::expr::FlowResult;
#[cfg(not(target_family = "wasm"))]
const SMALL_BOUNDED_THRESHOLD: usize = 1000;
#[cfg(not(target_family = "wasm"))]
pub(crate) fn buffer_stream(
stream: ValueBatchStream,
mode: AccessMode,
cardinality: CardinalityHint,
buffer_size: usize,
) -> ValueBatchStream {
if buffer_size == 0 {
return stream;
}
match cardinality {
CardinalityHint::AtMostOne => return stream,
CardinalityHint::Bounded(n) if n <= SMALL_BOUNDED_THRESHOLD => {
return prefetch_buffered(stream, buffer_size);
}
_ => {}
}
match mode {
AccessMode::ReadOnly => spawn_buffered(stream, buffer_size),
AccessMode::ReadWrite => prefetch_buffered(stream, buffer_size),
}
}
#[cfg(target_family = "wasm")]
pub(crate) fn buffer_stream(
stream: ValueBatchStream,
_mode: AccessMode,
_cardinality: CardinalityHint,
_buffer_size: usize,
) -> ValueBatchStream {
stream
}
#[cfg(not(target_family = "wasm"))]
fn spawn_buffered(stream: ValueBatchStream, buffer_size: usize) -> ValueBatchStream {
let (tx, rx) = async_channel::bounded(buffer_size);
let handle = tokio::spawn(async move {
futures::pin_mut!(stream);
while let Some(item) = futures::StreamExt::next(&mut stream).await {
if tx.send(item).await.is_err() {
break; }
}
});
Box::pin(SpawnedBufferedStream {
rx: Box::pin(rx),
handle,
})
}
#[cfg(not(target_family = "wasm"))]
struct SpawnedBufferedStream {
rx: ValueBatchStream,
handle: tokio::task::JoinHandle<()>,
}
#[cfg(not(target_family = "wasm"))]
impl Drop for SpawnedBufferedStream {
fn drop(&mut self) {
self.handle.abort();
}
}
#[cfg(not(target_family = "wasm"))]
impl Stream for SpawnedBufferedStream {
type Item = FlowResult<ValueBatch>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
self.get_mut().rx.as_mut().poll_next(cx)
}
}
#[cfg(not(target_family = "wasm"))]
fn prefetch_buffered(stream: ValueBatchStream, buffer_size: usize) -> ValueBatchStream {
Box::pin(PrefetchStream {
inner: stream,
buffer: VecDeque::with_capacity(buffer_size),
buffer_size,
exhausted: false,
})
}
#[cfg(not(target_family = "wasm"))]
struct PrefetchStream {
inner: ValueBatchStream,
buffer: VecDeque<FlowResult<ValueBatch>>,
buffer_size: usize,
exhausted: bool,
}
#[cfg(not(target_family = "wasm"))]
impl PrefetchStream {
#[inline]
fn fill_buffer(&mut self, cx: &mut Context<'_>) {
while self.buffer.len() < self.buffer_size && !self.exhausted {
match self.inner.as_mut().poll_next(cx) {
Poll::Ready(Some(item)) => self.buffer.push_back(item),
Poll::Ready(None) => {
self.exhausted = true;
}
Poll::Pending => break,
}
}
}
}
#[cfg(not(target_family = "wasm"))]
impl Stream for PrefetchStream {
type Item = FlowResult<ValueBatch>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let this = self.get_mut();
this.fill_buffer(cx);
if let Some(item) = this.buffer.pop_front() {
this.fill_buffer(cx);
Poll::Ready(Some(item))
} else if this.exhausted {
Poll::Ready(None)
} else {
Poll::Pending
}
}
}