Skip to content

Commit 2e70f22

Browse files
committed
made prefetchreader also hold an internal cache
1 parent 4ca706b commit 2e70f22

File tree

2 files changed

+40
-12
lines changed

2 files changed

+40
-12
lines changed

Cargo.toml

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ description = "Low-level asynchronous TIFF reader."
99
readme = "README.md"
1010

1111
[dependencies]
12+
async-mutex = { version = "1.4.0", optional = true }
1213
byteorder = "1"
1314
bytes = "1.7.0"
1415
flate2 = "1.0.20"
@@ -35,9 +36,10 @@ tokio = { version = "1.9", features = [
3536
] }
3637

3738
[features]
38-
default = ["object_store", "reqwest"]
39+
default = ["object_store", "reqwest", "async_mutex"]
3940
tokio = ["dep:tokio"]
4041
reqwest = ["dep:reqwest"]
4142
object_store = ["dep:object_store"]
43+
async_mutex = ["dep:async-mutex"]
4244

4345
[package.metadata.cargo-all-features]

src/reader.rs

+37-11
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ use futures::TryFutureExt;
1313

1414
use 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 {
231236
pub struct PrefetchReader {
232237
reader: Arc<dyn AsyncFileReader>,
233238
buffer: Bytes,
239+
tile_info_cache: Mutex<(Range<u64>, Bytes)>,
234240
}
235241

236242
impl 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

244255
impl 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

Comments
 (0)