Skip to content

Commit fe6dcac

Browse files
authored
refactor(iroh-bytes): use even newer bao-tree (#2168)
## Description refactor(iroh-bytes): use even newer bao-tree There is a new version of bao-tree that fixes some long standing api consistency issues and drops the tokio dependency. This updates iroh to use it. We of course still use tokio, but switching to something else would be easier at least as far as bao-tree is concerned. The other change is that encode_ranges_validated no longer writes the length prefix, so we have to do this ourselves. This was done to simplify the bao-tree API and make it more flexible. ## Notes & open questions <!-- Any notes, remarks or open questions you have to make about the PR. --> ## Change checklist - [x] Self-review. - [x] Documentation updates if relevant. - [x] Tests if relevant.
1 parent 5d4ac52 commit fe6dcac

File tree

13 files changed

+92
-68
lines changed

13 files changed

+92
-68
lines changed

Cargo.lock

Lines changed: 5 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

iroh-base/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ workspace = true
1616

1717
[dependencies]
1818
anyhow = { version = "1" }
19-
bao-tree = { version = "0.12", features = ["tokio_fsm", "validate"], default-features = false, optional = true }
19+
bao-tree = { version = "0.13", features = ["tokio_fsm", "validate"], default-features = false, optional = true }
2020
data-encoding = { version = "2.3.3", optional = true }
2121
hex = "0.4.3"
2222
multibase = { version = "0.9.1", optional = true }

iroh-bytes/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ workspace = true
1717

1818
[dependencies]
1919
anyhow = { version = "1" }
20-
bao-tree = { version = "0.12", features = ["tokio_fsm"], default-features = false }
20+
bao-tree = { version = "0.13", features = ["tokio_fsm"], default-features = false }
2121
bytes = { version = "1.4", features = ["serde"] }
2222
chrono = "0.4.31"
2323
data-encoding = "2.3.3"
@@ -28,7 +28,7 @@ futures-buffered = "0.2.4"
2828
genawaiter = { version = "0.99.1", features = ["futures03"] }
2929
hex = "0.4.3"
3030
iroh-base = { version = "0.13.0", features = ["redb"], path = "../iroh-base" }
31-
iroh-io = { version = "0.4.0", features = ["stats"] }
31+
iroh-io = { version = "0.6.0", features = ["stats"] }
3232
iroh-metrics = { version = "0.13.0", path = "../iroh-metrics", optional = true }
3333
iroh-net = { version = "0.13.0", path = "../iroh-net", optional = true }
3434
num_cpus = "1.15.0"

iroh-bytes/src/get.rs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,10 @@ pub mod fsm {
7070
BaoTree, ChunkRanges, TreeNode,
7171
};
7272
use derive_more::From;
73-
use iroh_io::AsyncSliceWriter;
74-
use tokio::io::{AsyncReadExt, AsyncWriteExt};
73+
use iroh_io::{AsyncSliceWriter, AsyncStreamReader, TokioStreamReader};
74+
use tokio::io::AsyncWriteExt;
75+
76+
type WrappedRecvStream = TrackingReader<TokioStreamReader<RecvStream>>;
7577

7678
self_cell::self_cell! {
7779
struct RangesIterInner {
@@ -142,7 +144,7 @@ pub mod fsm {
142144
pub async fn next(self) -> Result<AtConnected, quinn::ConnectionError> {
143145
let start = Instant::now();
144146
let (writer, reader) = self.connection.open_bi().await?;
145-
let reader = TrackingReader::new(reader);
147+
let reader = TrackingReader::new(TokioStreamReader::new(reader));
146148
let writer = TrackingWriter::new(writer);
147149
Ok(AtConnected {
148150
start,
@@ -157,7 +159,7 @@ pub mod fsm {
157159
#[derive(Debug)]
158160
pub struct AtConnected {
159161
start: Instant,
160-
reader: TrackingReader<quinn::RecvStream>,
162+
reader: WrappedRecvStream,
161163
writer: TrackingWriter<quinn::SendStream>,
162164
request: GetRequest,
163165
}
@@ -292,7 +294,7 @@ pub mod fsm {
292294
#[derive(Debug)]
293295
pub struct AtStartRoot {
294296
ranges: ChunkRanges,
295-
reader: TrackingReader<quinn::RecvStream>,
297+
reader: TrackingReader<TokioStreamReader<quinn::RecvStream>>,
296298
misc: Box<Misc>,
297299
hash: Hash,
298300
}
@@ -301,7 +303,7 @@ pub mod fsm {
301303
#[derive(Debug)]
302304
pub struct AtStartChild {
303305
ranges: ChunkRanges,
304-
reader: TrackingReader<quinn::RecvStream>,
306+
reader: TrackingReader<TokioStreamReader<quinn::RecvStream>>,
305307
misc: Box<Misc>,
306308
child_offset: u64,
307309
}
@@ -376,7 +378,7 @@ pub mod fsm {
376378
#[derive(Debug)]
377379
pub struct AtBlobHeader {
378380
ranges: ChunkRanges,
379-
reader: TrackingReader<quinn::RecvStream>,
381+
reader: TrackingReader<TokioStreamReader<quinn::RecvStream>>,
380382
misc: Box<Misc>,
381383
hash: Hash,
382384
}
@@ -412,7 +414,7 @@ pub mod fsm {
412414
impl AtBlobHeader {
413415
/// Read the size header, returning it and going into the `Content` state.
414416
pub async fn next(mut self) -> Result<(AtBlobContent, u64), AtBlobHeaderNextError> {
415-
let size = self.reader.read_u64_le().await.map_err(|cause| {
417+
let size = self.reader.read::<8>().await.map_err(|cause| {
416418
if cause.kind() == io::ErrorKind::UnexpectedEof {
417419
AtBlobHeaderNextError::NotFound
418420
} else if let Some(e) = cause
@@ -424,6 +426,7 @@ pub mod fsm {
424426
AtBlobHeaderNextError::Io(cause)
425427
}
426428
})?;
429+
let size = u64::from_le_bytes(size);
427430
let stream = ResponseDecoder::new(
428431
self.hash.into(),
429432
self.ranges,
@@ -513,7 +516,7 @@ pub mod fsm {
513516
/// State while we are reading content
514517
#[derive(Debug)]
515518
pub struct AtBlobContent {
516-
stream: ResponseDecoder<TrackingReader<RecvStream>>,
519+
stream: ResponseDecoder<WrappedRecvStream>,
517520
misc: Box<Misc>,
518521
}
519522

@@ -792,7 +795,7 @@ pub mod fsm {
792795
/// State after we have read all the content for a blob
793796
#[derive(Debug)]
794797
pub struct AtEndBlob {
795-
stream: TrackingReader<RecvStream>,
798+
stream: WrappedRecvStream,
796799
misc: Box<Misc>,
797800
}
798801

@@ -826,16 +829,12 @@ pub mod fsm {
826829
#[derive(Debug)]
827830
pub struct AtClosing {
828831
misc: Box<Misc>,
829-
reader: TrackingReader<RecvStream>,
832+
reader: WrappedRecvStream,
830833
check_extra_data: bool,
831834
}
832835

833836
impl AtClosing {
834-
fn new(
835-
misc: Box<Misc>,
836-
reader: TrackingReader<RecvStream>,
837-
check_extra_data: bool,
838-
) -> Self {
837+
fn new(misc: Box<Misc>, reader: WrappedRecvStream, check_extra_data: bool) -> Self {
839838
Self {
840839
misc,
841840
reader,
@@ -846,7 +845,8 @@ pub mod fsm {
846845
/// Finish the get response, returning statistics
847846
pub async fn next(self) -> result::Result<Stats, quinn::ReadError> {
848847
// Shut down the stream
849-
let (mut reader, bytes_read) = self.reader.into_parts();
848+
let (reader, bytes_read) = self.reader.into_parts();
849+
let mut reader = reader.into_inner();
850850
if self.check_extra_data {
851851
if let Some(chunk) = reader.read_chunk(8, false).await? {
852852
reader.stop(0u8.into()).ok();

iroh-bytes/src/get/db.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ pub async fn valid_ranges<D: MapMut>(entry: &D::EntryMut) -> anyhow::Result<Chun
145145
use tracing::trace as log;
146146
// compute the valid range from just looking at the data file
147147
let mut data_reader = entry.data_reader().await?;
148-
let data_size = data_reader.len().await?;
148+
let data_size = data_reader.size().await?;
149149
let valid_from_data = ChunkRanges::from(..ChunkNum::full_chunks(data_size));
150150
// compute the valid range from just looking at the outboard file
151151
let mut outboard = entry.outboard().await?;

iroh-bytes/src/provider.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,8 @@ pub async fn transfer_collection<D: Map, E: EventSender>(
217217
// wrap the data reader in a tracking reader so we can get some stats for reading
218218
let mut tracking_reader = TrackingSliceReader::new(&mut data);
219219
// send the root
220+
tw.write(outboard.tree().size().to_le_bytes().as_slice())
221+
.await?;
220222
encode_ranges_validated(
221223
&mut tracking_reader,
222224
&mut outboard,
@@ -490,13 +492,14 @@ pub async fn send_blob<D: Map, W: AsyncStreamWriter>(
490492
db: &D,
491493
name: Hash,
492494
ranges: &RangeSpec,
493-
writer: W,
495+
mut writer: W,
494496
) -> Result<(SentStatus, u64, SliceReaderStats)> {
495497
match db.get(&name).await? {
496498
Some(entry) => {
497499
let outboard = entry.outboard().await?;
498500
let size = outboard.tree().size();
499501
let mut file_reader = TrackingSliceReader::new(entry.data_reader().await?);
502+
writer.write(size.to_le_bytes().as_slice()).await?;
500503
let res = encode_ranges_validated(
501504
&mut file_reader,
502505
outboard,

iroh-bytes/src/store/bao_file.rs

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ impl AsyncSliceReader for DataReader {
426426
.await
427427
}
428428

429-
async fn len(&mut self) -> io::Result<u64> {
429+
async fn size(&mut self) -> io::Result<u64> {
430430
with_storage(
431431
&mut self.0,
432432
BaoFileStorage::is_mem,
@@ -458,7 +458,7 @@ impl AsyncSliceReader for OutboardReader {
458458
.await
459459
}
460460

461-
async fn len(&mut self) -> io::Result<u64> {
461+
async fn size(&mut self) -> io::Result<u64> {
462462
with_storage(
463463
&mut self.0,
464464
BaoFileStorage::is_mem,
@@ -732,9 +732,9 @@ pub mod test_support {
732732
BlockSize, ChunkRanges,
733733
};
734734
use futures::{Future, Stream, StreamExt};
735+
use iroh_io::AsyncStreamReader;
735736
use rand::RngCore;
736737
use range_collections::RangeSet2;
737-
use tokio::io::{AsyncRead, AsyncReadExt};
738738

739739
use crate::util::limited_range;
740740

@@ -751,10 +751,11 @@ pub mod test_support {
751751
mut target: W,
752752
) -> io::Result<()>
753753
where
754-
R: AsyncRead + Unpin,
754+
R: AsyncStreamReader,
755755
W: BaoBatchWriter,
756756
{
757-
let size = encoded.read_u64_le().await?;
757+
let size = encoded.read::<8>().await?;
758+
let size = u64::from_le_bytes(size);
758759
let mut reading =
759760
ResponseDecoder::new(root.into(), ranges, BaoTree::new(size, block_size), encoded);
760761
let mut stack = Vec::new();
@@ -792,7 +793,8 @@ pub mod test_support {
792793
/// Take some data and encode it
793794
pub fn simulate_remote(data: &[u8]) -> (Hash, Cursor<Bytes>) {
794795
let outboard = bao_tree::io::outboard::PostOrderMemOutboard::create(data, IROH_BLOCK_SIZE);
795-
let mut encoded = Vec::new();
796+
let size = data.len() as u64;
797+
let mut encoded = size.to_le_bytes().to_vec();
796798
bao_tree::io::sync::encode_ranges_validated(
797799
data,
798800
&outboard,
@@ -823,7 +825,8 @@ pub mod test_support {
823825
let chunk_ranges = round_up_to_chunks(&range_set);
824826
// compute the outboard
825827
let outboard = PostOrderMemOutboard::create(data, IROH_BLOCK_SIZE).flip();
826-
let mut encoded = Vec::new();
828+
let size = data.len() as u64;
829+
let mut encoded = size.to_le_bytes().to_vec();
827830
encode_ranges_validated(data, &outboard, &chunk_ranges, &mut encoded).unwrap();
828831
(outboard.root.into(), chunk_ranges, encoded)
829832
}
@@ -866,8 +869,11 @@ pub mod test_support {
866869

867870
#[cfg(test)]
868871
mod tests {
872+
use std::io::Write;
873+
869874
use bao_tree::{blake3, ChunkNum, ChunkRanges};
870875
use futures::StreamExt;
876+
use iroh_io::TokioStreamReader;
871877
use tests::test_support::{
872878
decode_response_into_batch, local, make_wire_data, random_test_data, trickle, validate,
873879
};
@@ -900,7 +906,7 @@ mod tests {
900906
let trickle = trickle(&wire_data, 1200, std::time::Duration::from_millis(10))
901907
.map(io::Result::Ok)
902908
.boxed();
903-
let trickle = tokio_util::io::StreamReader::new(trickle);
909+
let trickle = TokioStreamReader::new(tokio_util::io::StreamReader::new(trickle));
904910
let _task = tasks.spawn_local(async move {
905911
decode_response_into_batch(hash, IROH_BLOCK_SIZE, chunk_ranges, trickle, file)
906912
.await
@@ -912,18 +918,22 @@ mod tests {
912918
println!(
913919
"len {:?} {:?}",
914920
handle,
915-
handle.data_reader().len().await.unwrap()
921+
handle.data_reader().size().await.unwrap()
916922
);
917923
#[allow(clippy::single_range_in_vec_init)]
918924
let ranges = [1024 * 16..1024 * 48];
919925
validate(&handle, &test_data, &ranges).await;
920926

921927
// let ranges =
922928
// let full_chunks = bao_tree::io::full_chunk_groups();
923-
let encoded = Vec::new();
929+
let mut encoded = Vec::new();
930+
let ob = handle.outboard().unwrap();
931+
encoded
932+
.write_all(ob.tree.size().to_le_bytes().as_slice())
933+
.unwrap();
924934
bao_tree::io::fsm::encode_ranges_validated(
925935
handle.data_reader(),
926-
handle.outboard().unwrap(),
936+
ob,
927937
&ChunkRanges::from(ChunkNum(16)..ChunkNum(48)),
928938
encoded,
929939
)
@@ -957,7 +967,7 @@ mod tests {
957967
let trickle = trickle(&wire_data, 1200, std::time::Duration::from_millis(10))
958968
.map(io::Result::Ok)
959969
.boxed();
960-
let trickle = tokio_util::io::StreamReader::new(trickle);
970+
let trickle = TokioStreamReader::new(tokio_util::io::StreamReader::new(trickle));
961971
let task = local.spawn_pinned(move || async move {
962972
decode_response_into_batch(hash, IROH_BLOCK_SIZE, chunk_ranges, trickle, file).await
963973
});
@@ -969,16 +979,20 @@ mod tests {
969979
println!(
970980
"len {:?} {:?}",
971981
handle,
972-
handle.data_reader().len().await.unwrap()
982+
handle.data_reader().size().await.unwrap()
973983
);
974984
#[allow(clippy::single_range_in_vec_init)]
975985
let ranges = [0..n];
976986
validate(&handle, &test_data, &ranges).await;
977987

978-
let encoded = Vec::new();
988+
let mut encoded = Vec::new();
989+
let ob = handle.outboard().unwrap();
990+
encoded
991+
.write_all(ob.tree.size().to_le_bytes().as_slice())
992+
.unwrap();
979993
bao_tree::io::fsm::encode_ranges_validated(
980994
handle.data_reader(),
981-
handle.outboard().unwrap(),
995+
ob,
982996
&ChunkRanges::all(),
983997
encoded,
984998
)
@@ -1013,10 +1027,14 @@ mod tests {
10131027
.unwrap();
10141028
validate(&handle, &test_data, &ranges).await;
10151029

1016-
let encoded = Vec::new();
1030+
let mut encoded = Vec::new();
1031+
let ob = handle.outboard().unwrap();
1032+
encoded
1033+
.write_all(ob.tree.size().to_le_bytes().as_slice())
1034+
.unwrap();
10171035
bao_tree::io::fsm::encode_ranges_validated(
10181036
handle.data_reader(),
1019-
handle.outboard().unwrap(),
1037+
ob,
10201038
&ChunkRanges::all(),
10211039
encoded,
10221040
)

iroh-bytes/src/store/fs/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -793,7 +793,7 @@ async fn actor_store_smoke() {
793793
hash,
794794
IROH_BLOCK_SIZE,
795795
chunk_ranges.clone(),
796-
Cursor::new(wire_data),
796+
Cursor::new(wire_data.as_slice()),
797797
handle.batch_writer().await.unwrap(),
798798
)
799799
.await

0 commit comments

Comments
 (0)