@@ -13,6 +13,11 @@ use futures::TryFutureExt;
1313
1414use crate :: error:: { AsyncTiffError , AsyncTiffResult } ;
1515
16+ #[ cfg( all( not( feature = "tokio" ) , feature = "async_mutex" ) ) ]
17+ use async_mutex:: Mutex ;
18+ #[ cfg( feature = "tokio" ) ]
19+ use tokio:: sync:: Mutex ;
20+
1621/// The asynchronous interface used to read COG files
1722///
1823/// This was derived from the Parquet
@@ -231,29 +236,50 @@ impl AsyncFileReader for ReqwestReader {
231236pub struct PrefetchReader {
232237 reader : Arc < dyn AsyncFileReader > ,
233238 buffer : Bytes ,
239+ tile_info_cache : Mutex < ( Range < u64 > , Bytes ) > ,
234240}
235241
236242impl PrefetchReader {
237243 /// Construct a new PrefetchReader, catching the first `prefetch` bytes of the file.
238244 pub async fn new ( reader : Arc < dyn AsyncFileReader > , prefetch : u64 ) -> AsyncTiffResult < Self > {
239245 let buffer = reader. get_metadata_bytes ( 0 ..prefetch) . await ?;
240- Ok ( Self { reader, buffer } )
246+ let tile_info_cache = Mutex :: new ( ( 0 ..0 , Bytes :: new ( ) ) ) ;
247+ Ok ( Self {
248+ reader,
249+ buffer,
250+ tile_info_cache,
251+ } )
241252 }
242253}
243254
244255impl AsyncFileReader for PrefetchReader {
245256 fn get_metadata_bytes ( & self , range : Range < u64 > ) -> BoxFuture < ' _ , AsyncTiffResult < Bytes > > {
246- if range. start < self . buffer . len ( ) as _ {
247- if range. end < self . buffer . len ( ) as _ {
248- let usize_range = range. start as usize ..range. end as usize ;
249- let result = self . buffer . slice ( usize_range) ;
250- async { Ok ( result) } . boxed ( )
251- } else {
252- // TODO: reuse partial internal buffer
253- self . reader . get_metadata_bytes ( range)
254- }
257+ if range. end < self . buffer . len ( ) as _ {
258+ let usize_range = range. start as usize ..range. end as usize ;
259+ let result = self . buffer . slice ( usize_range) ;
260+ async { Ok ( result) } . boxed ( )
255261 } else {
256- self . reader . get_metadata_bytes ( range)
262+ async move {
263+ {
264+ let lock = self . tile_info_cache . lock ( ) . await ;
265+ // let (c_range, cache) = (lock.0, lock.1);
266+ if range. start >= lock. 0 . start && range. end <= lock. 0 . end {
267+ let usize_range = ( range. start - lock. 0 . start ) as usize
268+ ..( range. end - lock. 0 . start ) as usize ;
269+ return Ok ( lock. 1 . slice ( usize_range) ) ;
270+ }
271+ }
272+ let range_len = range. end - range. start ;
273+ let estimate = 2 * ( range_len + range_len. isqrt ( ) ) ;
274+ let new_c_range = range. start ..range. start + estimate;
275+ let res = self . reader . get_metadata_bytes ( new_c_range. clone ( ) ) . await ?;
276+ {
277+ let mut lock = self . tile_info_cache . lock ( ) . await ;
278+ * lock = ( new_c_range, res. clone ( ) ) ;
279+ }
280+ Ok ( res. slice ( 0 ..range_len as _ ) )
281+ }
282+ . boxed ( )
257283 }
258284 }
259285
0 commit comments