lace_tokio/
record_stream.rs1use lace_sans_io::runtime_support::io_budget::IoReservation;
4use lace_sans_io::runtime_support::record_sink::SinkIoDone;
5use lace_sans_io::runtime_support::record_stream::RecordStreamDecoder;
6use tokio::io::{AsyncRead, AsyncReadExt};
7use tokio::task::JoinHandle;
8
9use crate::io::IO;
10use crate::{Error, LaceHandle, Record, Result};
11
12pub struct RecordStream<R> {
15 reader: R,
16 decoder: Option<RecordStreamDecoder>,
18 buffer: Box<[u8]>,
19 start: usize,
20 end: usize,
21 io_task: Option<JoinHandle<SinkIoDone>>,
24 _reservation: IoReservation,
25}
26
27pub fn read_record_stream<R: AsyncRead + Unpin>(
38 lace: &LaceHandle,
39 reader: R,
40 max_bytes: u64,
41) -> Result<RecordStream<R>> {
42 lace.owner.claim()?;
43 let chunk_bytes = IO.chunk_bytes();
44 let reservation = IO.reserve(chunk_bytes)?;
45 Ok(RecordStream {
46 reader,
47 decoder: Some(RecordStreamDecoder::new(
48 lace.owner.record_staging.clone(),
49 max_bytes,
50 )),
51 buffer: vec![0; chunk_bytes].into_boxed_slice(),
52 start: 0,
53 end: 0,
54 io_task: None,
55 _reservation: reservation,
56 })
57}
58
59impl<R: AsyncRead + Unpin> RecordStream<R> {
60 pub async fn next(&mut self) -> Option<Result<Record>> {
64 self.decoder.as_ref()?;
65 let result = self.next_record().await.transpose();
66 if !matches!(result, Some(Ok(_))) {
67 self.decoder = None;
68 }
69 result
70 }
71
72 async fn next_record(&mut self) -> Result<Option<Record>> {
73 loop {
74 if let Some(record) = self.settle_io().await? {
75 return Ok(Some(record));
76 }
77 let decoder = self.decoder.as_mut().expect("a live record stream");
78 if self.start == self.end {
79 let count = self.reader.read(&mut self.buffer).await.map_err(|error| {
80 Error::transport(format!("record stream read failed: {error}"))
81 })?;
82 if count == 0 {
83 decoder.finish()?;
84 return Ok(None);
85 }
86 (self.start, self.end) = (0, count);
87 }
88 let (consumed, record) = decoder.decode(&self.buffer[self.start..self.end])?;
89 self.start += consumed;
90 if record.is_some() {
91 return Ok(record);
92 }
93 }
94 }
95
96 async fn settle_io(&mut self) -> Result<Option<Record>> {
99 loop {
100 let decoder = self.decoder.as_mut().expect("a live record stream");
101 let task = match &mut self.io_task {
102 Some(task) => task,
103 task => {
104 let Some(io) = decoder.take_io() else {
105 return Ok(None);
106 };
107 task.insert(tokio::task::spawn_blocking(move || io.run()))
108 }
109 };
110 let done = task.await;
111 self.io_task = None;
112 let done = done.map_err(|error| {
113 Error::integration(format!("record staging task failed: {error}"))
114 })?;
115 let decoder = self.decoder.as_mut().expect("a live record stream");
116 if let Some(record) = decoder.complete_io(done)? {
117 return Ok(Some(record));
118 }
119 }
120 }
121}
122
123#[cfg(test)]
124#[path = "record_stream_tests.rs"]
125mod tests;