@@ -27,7 +27,7 @@ use crate::{
27
27
Stats ,
28
28
} ,
29
29
protocol:: { GetRequest , RangeSpec , RangeSpecSeq } ,
30
- store:: { BaoBatchWriter , MapEntryMut , Store } ,
30
+ store:: { BaoBatchWriter , BaoBlobSize , MapEntry , MapEntryMut , Store } ,
31
31
util:: local_pool:: { self , LocalPool , LocalPoolHandle } ,
32
32
Hash ,
33
33
} ;
@@ -89,6 +89,64 @@ pub trait BitfieldSubscription: std::fmt::Debug + Send + 'static {
89
89
/// A boxed bitfield subscription
90
90
pub type BoxedBitfieldSubscription = Box < dyn BitfieldSubscription > ;
91
91
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
+
92
150
/// Events from observing a local bitfield
93
151
#[ derive( Debug , PartialEq , Eq , derive_more:: From ) ]
94
152
pub enum BitfieldEvent {
@@ -98,32 +156,32 @@ pub enum BitfieldEvent {
98
156
Update ( BitfieldUpdate ) ,
99
157
}
100
158
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
+
101
168
/// An update to a bitfield
102
169
#[ derive( Debug , PartialEq , Eq ) ]
103
170
pub struct BitfieldUpdate {
104
171
/// The ranges that were added
105
172
pub added : ChunkRanges ,
106
173
/// The ranges that were removed
107
174
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 ,
119
177
}
120
178
121
179
impl BitfieldState {
122
180
/// State for a completely unknown bitfield
123
181
pub fn unknown ( ) -> Self {
124
182
Self {
125
183
ranges : ChunkRanges :: empty ( ) ,
126
- size : u64 :: MAX ,
184
+ size : BaoBlobSizeOpt :: Unknown ,
127
185
}
128
186
}
129
187
}
@@ -345,7 +403,7 @@ impl BitfieldSubscription for TestBitfieldSubscription {
345
403
futures_lite:: stream:: once (
346
404
BitfieldState {
347
405
ranges,
348
- size : 1024 * 1024 * 1024 * 1024 * 1024 ,
406
+ size : BaoBlobSizeOpt :: Unknown ,
349
407
}
350
408
. into ( ) ,
351
409
)
@@ -375,7 +433,24 @@ impl<S> SimpleBitfieldSubscription<S> {
375
433
376
434
async fn get_valid_ranges_local < S : Store > ( hash : & Hash , store : S ) -> anyhow:: Result < BitfieldEvent > {
377
435
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
+ } ;
379
454
Ok ( BitfieldState { ranges, size } . into ( ) )
380
455
} else {
381
456
Ok ( BitfieldState :: unknown ( ) . into ( ) )
@@ -391,7 +466,11 @@ async fn get_valid_ranges_remote(
391
466
let ( size, _) = crate :: get:: request:: get_verified_size ( & conn, hash) . await ?;
392
467
let chunks = ( size + 1023 ) / 1024 ;
393
468
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 ( ) )
395
474
}
396
475
397
476
impl < S : Store > BitfieldSubscription for SimpleBitfieldSubscription < S > {
0 commit comments