@@ -244,7 +244,7 @@ impl AsyncFileReader for Bytes {
244244 async { Ok ( self . slice ( usize_range) ) } . boxed ( )
245245 } else {
246246 let range_len = range. end - range. start ;
247- let range_read = range_len - ( range. end - self . len ( ) as u64 ) ;
247+ let range_read = range_len - ( range. end - self . len ( ) as u64 ) ;
248248 async move { Err ( AsyncTiffError :: EndOfFile ( range_len, range_read) ) } . boxed ( )
249249 }
250250 }
@@ -254,7 +254,9 @@ impl AsyncFileReader for Bytes {
254254/// holds a cache for out-of-prefetch metadata.
255255///
256256/// When a request is out-of-bounds, an estimate of the remaining
257- /// `tile_offsets`/`tile_byte_counts` array is made as `2*(len+2*len.isqrt())`
257+ /// `tile_offsets`+`tile_byte_counts` array is made as
258+ /// `(2*len+4*len.isqrt()).max(prefetch)`, where `len` is the length of the
259+ /// requested range and `prefetch` is the size of the prefetch buffer.
258260///
259261/// # Examples
260262///
@@ -280,7 +282,7 @@ impl AsyncFileReader for Bytes {
280282/// *reader.get_metadata_bytes(start..start + len).await?,
281283/// [42; 16 * 1024]
282284/// );
283- ///
285+ ///
284286/// // this is now also (exactly) cached
285287/// assert_eq!(
286288/// *reader
@@ -291,7 +293,7 @@ impl AsyncFileReader for Bytes {
291293///
292294/// // this will not check the cache
293295/// reader.get_image_bytes(start..start + len).await?;
294- ///
296+ ///
295297/// # Ok::<(),AsyncTiffError>(())
296298/// # });
297299/// ```
@@ -338,7 +340,20 @@ impl AsyncFileReader for PrefetchReader {
338340 }
339341 // determine new cache size
340342 let range_len = range. end - range. start ;
341- let estimate = 2 * ( range_len + 2 * range_len. isqrt ( ) ) . max ( 8 * 1024 ) ;
343+ // estimate (for bigtiff):
344+ // each overview is 1/4 the previous =geometric series=> 4/3*range_len
345+ // assume request was TileOffsets =Long8+Long=> 3/2*4/3*range_len = 2*range_len
346+ //
347+ // add edge of one overview down:
348+ // n_tiles0 = range_len/8
349+ // n_tiles1 = 1/4*n_tiles0
350+ // edge_tiles1 ≈ √n_tiles1 = √range_len/√2⁶ = √range_len/(4√2)
351+ // each edge is 1/2 the previous =geometric series=> 2*edge_tiles1 = √range_len/(2√2)
352+ // edge_bytes = 8*√range_len/(2√2) = 4/√2*√range_len
353+ // Long8+Long => 3/2*4/√2*√range_len = 6/√2*√range_len ≈ 4*√range_len
354+ //
355+ // 2*range_len+4*√range_len
356+ let estimate = ( 2 * range_len + 4 * range_len. isqrt ( ) ) . max ( self . buffer . len ( ) as _ ) ;
342357 let new_c_range = range. start ..range. start + estimate;
343358
344359 // put in new cache
0 commit comments