@@ -13,6 +13,11 @@ use futures::TryFutureExt;
13
13
14
14
use crate :: error:: { AsyncTiffError , AsyncTiffResult } ;
15
15
16
+ #[ cfg( all( not( feature = "tokio" ) , feature = "async_mutex" ) ) ]
17
+ use async_mutex:: Mutex ;
18
+ #[ cfg( feature = "tokio" ) ]
19
+ use tokio:: sync:: Mutex ;
20
+
16
21
/// The asynchronous interface used to read COG files
17
22
///
18
23
/// This was derived from the Parquet
@@ -231,29 +236,50 @@ impl AsyncFileReader for ReqwestReader {
231
236
pub struct PrefetchReader {
232
237
reader : Arc < dyn AsyncFileReader > ,
233
238
buffer : Bytes ,
239
+ tile_info_cache : Mutex < ( Range < u64 > , Bytes ) > ,
234
240
}
235
241
236
242
impl PrefetchReader {
237
243
/// Construct a new PrefetchReader, catching the first `prefetch` bytes of the file.
238
244
pub async fn new ( reader : Arc < dyn AsyncFileReader > , prefetch : u64 ) -> AsyncTiffResult < Self > {
239
245
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
+ } )
241
252
}
242
253
}
243
254
244
255
impl AsyncFileReader for PrefetchReader {
245
256
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 ( )
255
261
} 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 ( )
257
283
}
258
284
}
259
285
0 commit comments