@@ -27,7 +27,7 @@ use crate::{
2727 Stats ,
2828 } ,
2929 protocol:: { GetRequest , RangeSpec , RangeSpecSeq } ,
30- store:: { BaoBatchWriter , MapEntryMut , Store } ,
30+ store:: { BaoBatchWriter , BaoBlobSize , MapEntry , MapEntryMut , Store } ,
3131 util:: local_pool:: { self , LocalPool , LocalPoolHandle } ,
3232 Hash ,
3333} ;
@@ -89,6 +89,64 @@ pub trait BitfieldSubscription: std::fmt::Debug + Send + 'static {
8989/// A boxed bitfield subscription
9090pub type BoxedBitfieldSubscription = Box < dyn BitfieldSubscription > ;
9191
92+ /// Knowlege about the size of a blob
93+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
94+ pub enum BaoBlobSizeOpt {
95+ /// We have a size that a peer told us about, but we don't know if it is correct
96+ /// It can be off at most by a factor of 2, so it is OK for things like showing
97+ /// a progress bar or even for an allocation size
98+ Unverified ( u64 ) ,
99+ /// We know the size, and it is verified
100+ /// either by having the last chunk locally or by receiving a size proof from a peer
101+ Verified ( u64 ) ,
102+ /// We know nothing, e.g. we have never heard of the blob
103+ Unknown ,
104+ }
105+
106+ impl BaoBlobSizeOpt {
107+ /// Get the value of the size, if known
108+ pub fn value ( self ) -> Option < u64 > {
109+ match self {
110+ BaoBlobSizeOpt :: Unverified ( x) => Some ( x) ,
111+ BaoBlobSizeOpt :: Verified ( x) => Some ( x) ,
112+ BaoBlobSizeOpt :: Unknown => None ,
113+ }
114+ }
115+
116+ /// Update the size information
117+ ///
118+ /// Unkown sizes are always updated
119+ /// Unverified sizes are updated if the new size is verified
120+ /// Verified sizes must never change
121+ pub fn update ( & mut self , size : BaoBlobSizeOpt ) -> anyhow:: Result < ( ) > {
122+ match self {
123+ BaoBlobSizeOpt :: Verified ( old) => {
124+ if let BaoBlobSizeOpt :: Verified ( new) = size {
125+ if * old != new {
126+ anyhow:: bail!( "mismatched verified sizes: {old} != {new}" ) ;
127+ }
128+ }
129+ }
130+ BaoBlobSizeOpt :: Unverified ( _) => {
131+ if let BaoBlobSizeOpt :: Verified ( new) = size {
132+ * self = BaoBlobSizeOpt :: Verified ( new) ;
133+ }
134+ }
135+ BaoBlobSizeOpt :: Unknown => * self = size,
136+ } ;
137+ Ok ( ( ) )
138+ }
139+ }
140+
141+ impl From < BaoBlobSize > for BaoBlobSizeOpt {
142+ fn from ( size : BaoBlobSize ) -> Self {
143+ match size {
144+ BaoBlobSize :: Unverified ( x) => Self :: Unverified ( x) ,
145+ BaoBlobSize :: Verified ( x) => Self :: Verified ( x) ,
146+ }
147+ }
148+ }
149+
92150/// Events from observing a local bitfield
93151#[ derive( Debug , PartialEq , Eq , derive_more:: From ) ]
94152pub enum BitfieldEvent {
@@ -98,32 +156,32 @@ pub enum BitfieldEvent {
98156 Update ( BitfieldUpdate ) ,
99157}
100158
159+ /// The state of a bitfield
160+ #[ derive( Debug , PartialEq , Eq ) ]
161+ pub struct BitfieldState {
162+ /// The ranges that are set
163+ pub ranges : ChunkRanges ,
164+ /// Whatever size information is available
165+ pub size : BaoBlobSizeOpt ,
166+ }
167+
101168/// An update to a bitfield
102169#[ derive( Debug , PartialEq , Eq ) ]
103170pub struct BitfieldUpdate {
104171 /// The ranges that were added
105172 pub added : ChunkRanges ,
106173 /// The ranges that were removed
107174 pub removed : ChunkRanges ,
108- /// The total size of the bitfield in bytes
109- pub size : u64 ,
110- }
111-
112- /// The state of a bitfield
113- #[ derive( Debug , PartialEq , Eq ) ]
114- pub struct BitfieldState {
115- /// The ranges that are set
116- pub ranges : ChunkRanges ,
117- /// The total size of the bitfield in bytes
118- pub size : u64 ,
175+ /// Possible update to the size information
176+ pub size : BaoBlobSizeOpt ,
119177}
120178
121179impl BitfieldState {
122180 /// State for a completely unknown bitfield
123181 pub fn unknown ( ) -> Self {
124182 Self {
125183 ranges : ChunkRanges :: empty ( ) ,
126- size : u64 :: MAX ,
184+ size : BaoBlobSizeOpt :: Unknown ,
127185 }
128186 }
129187}
@@ -345,7 +403,7 @@ impl BitfieldSubscription for TestBitfieldSubscription {
345403 futures_lite:: stream:: once (
346404 BitfieldState {
347405 ranges,
348- size : 1024 * 1024 * 1024 * 1024 * 1024 ,
406+ size : BaoBlobSizeOpt :: Unknown ,
349407 }
350408 . into ( ) ,
351409 )
@@ -375,7 +433,24 @@ impl<S> SimpleBitfieldSubscription<S> {
375433
376434async fn get_valid_ranges_local < S : Store > ( hash : & Hash , store : S ) -> anyhow:: Result < BitfieldEvent > {
377435 if let Some ( entry) = store. get_mut ( hash) . await ? {
378- let ( ranges, size) = crate :: get:: db:: valid_ranges_and_size :: < S > ( & entry) . await ?;
436+ let ranges = crate :: get:: db:: valid_ranges :: < S > ( & entry) . await ?;
437+ let size = entry. size ( ) ;
438+ let size = match size {
439+ size @ BaoBlobSize :: Unverified ( value) => {
440+ if let Some ( last_chunk) = ChunkNum :: chunks ( value) . 0 . checked_sub ( 1 ) . map ( ChunkNum ) {
441+ if ranges. contains ( & last_chunk) {
442+ BaoBlobSizeOpt :: Verified ( value)
443+ } else {
444+ size. into ( )
445+ }
446+ } else {
447+ // this branch is just for size == 0
448+ // todo: return BaoBlobSize::Verified(0) if the hash is the hash of the empty blob
449+ BaoBlobSizeOpt :: Unknown
450+ }
451+ }
452+ size => size. into ( ) ,
453+ } ;
379454 Ok ( BitfieldState { ranges, size } . into ( ) )
380455 } else {
381456 Ok ( BitfieldState :: unknown ( ) . into ( ) )
@@ -391,7 +466,11 @@ async fn get_valid_ranges_remote(
391466 let ( size, _) = crate :: get:: request:: get_verified_size ( & conn, hash) . await ?;
392467 let chunks = ( size + 1023 ) / 1024 ;
393468 let ranges = ChunkRanges :: from ( ChunkNum ( 0 ) ..ChunkNum ( chunks) ) ;
394- Ok ( BitfieldState { ranges, size } . into ( ) )
469+ Ok ( BitfieldState {
470+ ranges,
471+ size : BaoBlobSizeOpt :: Verified ( size) ,
472+ }
473+ . into ( ) )
395474}
396475
397476impl < S : Store > BitfieldSubscription for SimpleBitfieldSubscription < S > {
0 commit comments