@@ -13,6 +13,13 @@ 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
+ #[ cfg( not( any( feature="tokio" , feature="async_mutex" ) ) ) ]
21
+ compile_error ! ( "at least one of 'tokio' or 'async_mutex' features should be enabled" ) ;
22
+
16
23
/// The asynchronous interface used to read COG files
17
24
///
18
25
/// This was derived from the Parquet
@@ -231,29 +238,50 @@ impl AsyncFileReader for ReqwestReader {
231
238
pub struct PrefetchReader {
232
239
reader : Arc < dyn AsyncFileReader > ,
233
240
buffer : Bytes ,
241
+ tile_info_cache : Mutex < ( Range < u64 > , Bytes ) > ,
234
242
}
235
243
236
244
impl PrefetchReader {
237
245
/// Construct a new PrefetchReader, catching the first `prefetch` bytes of the file.
238
246
pub async fn new ( reader : Arc < dyn AsyncFileReader > , prefetch : u64 ) -> AsyncTiffResult < Self > {
239
247
let buffer = reader. get_metadata_bytes ( 0 ..prefetch) . await ?;
240
- Ok ( Self { reader, buffer } )
248
+ let tile_info_cache = Mutex :: new ( ( 0 ..0 , Bytes :: new ( ) ) ) ;
249
+ Ok ( Self {
250
+ reader,
251
+ buffer,
252
+ tile_info_cache,
253
+ } )
241
254
}
242
255
}
243
256
244
257
impl AsyncFileReader for PrefetchReader {
245
258
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
- }
259
+ if range. end < self . buffer . len ( ) as _ {
260
+ let usize_range = range. start as usize ..range. end as usize ;
261
+ let result = self . buffer . slice ( usize_range) ;
262
+ async { Ok ( result) } . boxed ( )
255
263
} else {
256
- self . reader . get_metadata_bytes ( range)
264
+ async move {
265
+ {
266
+ let lock = self . tile_info_cache . lock ( ) . await ;
267
+ // let (c_range, cache) = (lock.0, lock.1);
268
+ if range. start >= lock. 0 . start && range. end <= lock. 0 . end {
269
+ let usize_range = ( range. start - lock. 0 . start ) as usize
270
+ ..( range. end - lock. 0 . start ) as usize ;
271
+ return Ok ( lock. 1 . slice ( usize_range) ) ;
272
+ }
273
+ }
274
+ let range_len = range. end - range. start ;
275
+ let estimate = 2 * ( range_len + range_len. isqrt ( ) ) ;
276
+ let new_c_range = range. start ..range. start + estimate;
277
+ let res = self . reader . get_metadata_bytes ( new_c_range. clone ( ) ) . await ?;
278
+ {
279
+ let mut lock = self . tile_info_cache . lock ( ) . await ;
280
+ * lock = ( new_c_range, res. clone ( ) ) ;
281
+ }
282
+ Ok ( res. slice ( 0 ..range_len as _ ) )
283
+ }
284
+ . boxed ( )
257
285
}
258
286
}
259
287
0 commit comments