|
373 | 373 | //! a large existing system that has demonstrated performance issues. |
374 | 374 | //! |
375 | 375 | //! If in doubt, just use multiple requests and multiple connections. |
376 | | -use std::io; |
| 376 | +use std::{ |
| 377 | + io, |
| 378 | + ops::{Bound, RangeBounds}, |
| 379 | +}; |
377 | 380 |
|
| 381 | +use bao_tree::{io::round_up_to_chunks, ChunkNum}; |
378 | 382 | use builder::GetRequestBuilder; |
379 | 383 | use derive_more::From; |
380 | 384 | use iroh::endpoint::VarInt; |
381 | 385 | use irpc::util::AsyncReadVarintExt; |
382 | 386 | use postcard::experimental::max_size::MaxSize; |
| 387 | +use range_collections::{range_set::RangeSetEntry, RangeSet2}; |
383 | 388 | use serde::{Deserialize, Serialize}; |
384 | 389 | mod range_spec; |
385 | 390 | pub use bao_tree::ChunkRanges; |
386 | 391 | pub use range_spec::{ChunkRangesSeq, NonEmptyRequestRangeSpecIter, RangeSpec}; |
387 | 392 | use snafu::{GenerateImplicitData, Snafu}; |
388 | 393 | use tokio::io::AsyncReadExt; |
389 | 394 |
|
390 | | -pub use crate::util::ChunkRangesExt; |
391 | 395 | use crate::{api::blobs::Bitfield, provider::CountingReader, BlobFormat, Hash, HashAndFormat}; |
392 | 396 |
|
393 | 397 | /// Maximum message size is limited to 100MiB for now. |
@@ -714,6 +718,73 @@ impl TryFrom<VarInt> for Closed { |
714 | 718 | } |
715 | 719 | } |
716 | 720 |
|
| 721 | +pub trait ChunkRangesExt { |
| 722 | + fn last_chunk() -> Self; |
| 723 | + fn chunk(offset: u64) -> Self; |
| 724 | + fn bytes(ranges: impl RangeBounds<u64>) -> Self; |
| 725 | + fn chunks(ranges: impl RangeBounds<u64>) -> Self; |
| 726 | + fn offset(offset: u64) -> Self; |
| 727 | +} |
| 728 | + |
| 729 | +impl ChunkRangesExt for ChunkRanges { |
| 730 | + fn last_chunk() -> Self { |
| 731 | + ChunkRanges::from(ChunkNum(u64::MAX)..) |
| 732 | + } |
| 733 | + |
| 734 | + /// Create a chunk range that contains a single chunk. |
| 735 | + fn chunk(offset: u64) -> Self { |
| 736 | + ChunkRanges::from(ChunkNum(offset)..ChunkNum(offset + 1)) |
| 737 | + } |
| 738 | + |
| 739 | + /// Create a range of chunks that contains the given byte ranges. |
| 740 | + /// The byte ranges are rounded up to the nearest chunk size. |
| 741 | + fn bytes(ranges: impl RangeBounds<u64>) -> Self { |
| 742 | + round_up_to_chunks(&bounds_from_range(ranges, |v| v)) |
| 743 | + } |
| 744 | + |
| 745 | + /// Create a range of chunks from u64 chunk bounds. |
| 746 | + /// |
| 747 | + /// This is equivalent but more convenient than using the ChunkNum newtype. |
| 748 | + fn chunks(ranges: impl RangeBounds<u64>) -> Self { |
| 749 | + bounds_from_range(ranges, ChunkNum) |
| 750 | + } |
| 751 | + |
| 752 | + /// Create a chunk range that contains a single byte offset. |
| 753 | + fn offset(offset: u64) -> Self { |
| 754 | + Self::bytes(offset..offset + 1) |
| 755 | + } |
| 756 | +} |
| 757 | + |
| 758 | +// todo: move to range_collections |
| 759 | +pub(crate) fn bounds_from_range<R, T, F>(range: R, f: F) -> RangeSet2<T> |
| 760 | +where |
| 761 | + R: RangeBounds<u64>, |
| 762 | + T: RangeSetEntry, |
| 763 | + F: Fn(u64) -> T, |
| 764 | +{ |
| 765 | + let from = match range.start_bound() { |
| 766 | + Bound::Included(start) => Some(*start), |
| 767 | + Bound::Excluded(start) => { |
| 768 | + let Some(start) = start.checked_add(1) else { |
| 769 | + return RangeSet2::empty(); |
| 770 | + }; |
| 771 | + Some(start) |
| 772 | + } |
| 773 | + Bound::Unbounded => None, |
| 774 | + }; |
| 775 | + let to = match range.end_bound() { |
| 776 | + Bound::Included(end) => end.checked_add(1), |
| 777 | + Bound::Excluded(end) => Some(*end), |
| 778 | + Bound::Unbounded => None, |
| 779 | + }; |
| 780 | + match (from, to) { |
| 781 | + (Some(from), Some(to)) => RangeSet2::from(f(from)..f(to)), |
| 782 | + (Some(from), None) => RangeSet2::from(f(from)..), |
| 783 | + (None, Some(to)) => RangeSet2::from(..f(to)), |
| 784 | + (None, None) => RangeSet2::all(), |
| 785 | + } |
| 786 | +} |
| 787 | + |
717 | 788 | pub mod builder { |
718 | 789 | use std::collections::BTreeMap; |
719 | 790 |
|
@@ -863,7 +934,7 @@ pub mod builder { |
863 | 934 | use bao_tree::ChunkNum; |
864 | 935 |
|
865 | 936 | use super::*; |
866 | | - use crate::{protocol::GetManyRequest, util::ChunkRangesExt}; |
| 937 | + use crate::protocol::{ChunkRangesExt, GetManyRequest}; |
867 | 938 |
|
868 | 939 | #[test] |
869 | 940 | fn chunk_ranges_ext() { |
|
0 commit comments