Skip to content

Commit ab1f6a1

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

File tree

2 files changed

+42
-12
lines changed

2 files changed

+42
-12
lines changed

Cargo.toml

Lines changed: 3 additions & 1 deletion
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

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@ 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+
#[cfg(not(any(feature="tokio", feature="async_mutex")))]
21+
compile_error!("at least one of 'tokio' or 'async_mutex' features should be enabled");
22+
1623
/// The asynchronous interface used to read COG files
1724
///
1825
/// This was derived from the Parquet
@@ -231,29 +238,50 @@ impl AsyncFileReader for ReqwestReader {
231238
pub struct PrefetchReader {
232239
reader: Arc<dyn AsyncFileReader>,
233240
buffer: Bytes,
241+
tile_info_cache: Mutex<(Range<u64>, Bytes)>,
234242
}
235243

236244
impl PrefetchReader {
237245
/// Construct a new PrefetchReader, catching the first `prefetch` bytes of the file.
238246
pub async fn new(reader: Arc<dyn AsyncFileReader>, prefetch: u64) -> AsyncTiffResult<Self> {
239247
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+
})
241254
}
242255
}
243256

244257
impl AsyncFileReader for PrefetchReader {
245258
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()
255263
} 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()
257285
}
258286
}
259287

0 commit comments

Comments
 (0)