diff --git a/src/buffered.rs b/src/buffered.rs index 45020829..d22ecda5 100644 --- a/src/buffered.rs +++ b/src/buffered.rs @@ -19,8 +19,8 @@ use crate::path::Path; use crate::{ - Attributes, Extensions, ObjectMeta, ObjectStore, PutMultipartOptions, PutOptions, - PutPayloadMut, TagSet, WriteMultipart, + Attributes, Extensions, ObjectMeta, ObjectStore, ObjectStoreExt, PutMultipartOptions, + PutOptions, PutPayloadMut, TagSet, WriteMultipart, }; use bytes::Bytes; use futures::future::{BoxFuture, FutureExt}; @@ -37,7 +37,7 @@ pub const DEFAULT_BUFFER_SIZE: usize = 1024 * 1024; /// An async-buffered reader compatible with the tokio IO traits /// -/// Internally this maintains a buffer of the requested size, and uses [`ObjectStore::get_range`] +/// Internally this maintains a buffer of the requested size, and uses [`ObjectStoreExt::get_range`] /// to populate its internal buffer once depleted. This buffer is cleared on seek. /// /// Whilst simple, this interface will typically be outperformed by the native [`ObjectStore`] @@ -46,7 +46,7 @@ pub const DEFAULT_BUFFER_SIZE: usize = 1024 * 1024; /// round-trips is critical to throughput. /// /// Systems looking to sequentially scan a file should instead consider using [`ObjectStoreExt::get`], -/// or [`ObjectStore::get_opts`], or [`ObjectStore::get_range`] to read a particular range. +/// or [`ObjectStore::get_opts`], or [`ObjectStoreExt::get_range`] to read a particular range. /// /// Systems looking to read multiple ranges of a file should instead consider using /// [`ObjectStore::get_ranges`], which will optimise the vectored IO. diff --git a/src/chunked.rs b/src/chunked.rs index cbd66f62..4db6071f 100644 --- a/src/chunked.rs +++ b/src/chunked.rs @@ -135,13 +135,10 @@ impl ObjectStore for ChunkedStore { }) } - async fn get_range(&self, location: &Path, range: Range) -> Result { - self.inner.get_range(location, range).await - } - async fn get_ranges(&self, location: &Path, ranges: &[Range]) -> Result> { self.inner.get_ranges(location, ranges).await } + async fn head(&self, location: &Path) -> Result { self.inner.head(location).await } diff --git a/src/lib.rs b/src/lib.rs index c4c39dcd..dca9bcd7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -823,46 +823,6 @@ pub trait ObjectStore: std::fmt::Display + Send + Sync + Debug + 'static { /// ``` async fn get_opts(&self, location: &Path, options: GetOptions) -> Result; - /// Return the bytes that are stored at the specified location - /// in the given byte range. - /// - /// See [`GetRange::Bounded`] for more details on how `range` gets interpreted. - /// - /// To retrieve a range of bytes from a versioned object, use [`ObjectStore::get_opts`] by specifying the range in the [`GetOptions`]. - /// - /// ## Examples - /// - /// This example uses a basic local filesystem object store to get a byte range from an object. - /// - /// ```ignore-wasm32 - /// # use object_store::local::LocalFileSystem; - /// # use tempfile::tempdir; - /// # use object_store::{path::Path, ObjectStore, ObjectStoreExt}; - /// async fn get_range_example() { - /// let tmp = tempdir().unwrap(); - /// let store = LocalFileSystem::new_with_prefix(tmp.path()).unwrap(); - /// let location = Path::from("example.txt"); - /// let content = b"Hello, Object Store!"; - /// - /// // Put the object into the store - /// store - /// .put(&location, content.as_ref().into()) - /// .await - /// .expect("Failed to put object"); - /// - /// // Get the object from the store - /// let bytes = store - /// .get_range(&location, 0..5) - /// .await - /// .expect("Failed to get object"); - /// println!("Retrieved range [0-5]: {}", String::from_utf8_lossy(&bytes)); - /// } - /// ``` - async fn get_range(&self, location: &Path, range: Range) -> Result { - let options = GetOptions::new().with_range(Some(range)); - self.get_opts(location, options).await?.bytes().await - } - /// Return the bytes that are stored at the specified location /// in the given byte ranges async fn get_ranges(&self, location: &Path, ranges: &[Range]) -> Result> { @@ -1138,10 +1098,6 @@ macro_rules! as_ref_impl { self.as_ref().get_opts(location, options).await } - async fn get_range(&self, location: &Path, range: Range) -> Result { - self.as_ref().get_range(location, range).await - } - async fn get_ranges( &self, location: &Path, @@ -1257,6 +1213,43 @@ pub trait ObjectStoreExt: ObjectStore { /// } /// ``` fn get(&self, location: &Path) -> impl Future>; + + /// Return the bytes that are stored at the specified location + /// in the given byte range. + /// + /// See [`GetRange::Bounded`] for more details on how `range` gets interpreted. + /// + /// To retrieve a range of bytes from a versioned object, use [`ObjectStore::get_opts`] by specifying the range in the [`GetOptions`]. + /// + /// ## Examples + /// + /// This example uses a basic local filesystem object store to get a byte range from an object. + /// + /// ```ignore-wasm32 + /// # use object_store::local::LocalFileSystem; + /// # use tempfile::tempdir; + /// # use object_store::{path::Path, ObjectStore, ObjectStoreExt}; + /// async fn get_range_example() { + /// let tmp = tempdir().unwrap(); + /// let store = LocalFileSystem::new_with_prefix(tmp.path()).unwrap(); + /// let location = Path::from("example.txt"); + /// let content = b"Hello, Object Store!"; + /// + /// // Put the object into the store + /// store + /// .put(&location, content.as_ref().into()) + /// .await + /// .expect("Failed to put object"); + /// + /// // Get the object from the store + /// let bytes = store + /// .get_range(&location, 0..5) + /// .await + /// .expect("Failed to get object"); + /// println!("Retrieved range [0-5]: {}", String::from_utf8_lossy(&bytes)); + /// } + /// ``` + fn get_range(&self, location: &Path, range: Range) -> impl Future>; } impl ObjectStoreExt for T @@ -1276,6 +1269,11 @@ where async fn get(&self, location: &Path) -> Result { self.get_opts(location, GetOptions::default()).await } + + async fn get_range(&self, location: &Path, range: Range) -> Result { + let options = GetOptions::new().with_range(Some(range)); + self.get_opts(location, options).await?.bytes().await + } } /// Result of a list call that includes objects, prefixes (directories) and a diff --git a/src/limit.rs b/src/limit.rs index a46ba569..99f7d975 100644 --- a/src/limit.rs +++ b/src/limit.rs @@ -100,11 +100,6 @@ impl ObjectStore for LimitStore { Ok(permit_get_result(r, permit)) } - async fn get_range(&self, location: &Path, range: Range) -> Result { - let _permit = self.semaphore.acquire().await.unwrap(); - self.inner.get_range(location, range).await - } - async fn get_ranges(&self, location: &Path, ranges: &[Range]) -> Result> { let _permit = self.semaphore.acquire().await.unwrap(); self.inner.get_ranges(location, ranges).await diff --git a/src/local.rs b/src/local.rs index ee261717..9eccd5f8 100644 --- a/src/local.rs +++ b/src/local.rs @@ -429,15 +429,6 @@ impl ObjectStore for LocalFileSystem { .await } - async fn get_range(&self, location: &Path, range: Range) -> Result { - let path = self.path_to_filesystem(location)?; - maybe_spawn_blocking(move || { - let (mut file, _) = open_file(&path)?; - read_range(&mut file, &path, range) - }) - .await - } - async fn get_ranges(&self, location: &Path, ranges: &[Range]) -> Result> { let path = self.path_to_filesystem(location)?; let ranges = ranges.to_vec(); diff --git a/src/prefix.rs b/src/prefix.rs index 19d2ada4..029ecb94 100644 --- a/src/prefix.rs +++ b/src/prefix.rs @@ -114,11 +114,6 @@ impl ObjectStore for PrefixStore { self.inner.put_multipart_opts(&full_path, opts).await } - async fn get_range(&self, location: &Path, range: Range) -> Result { - let full_path = self.full_path(location); - self.inner.get_range(&full_path, range).await - } - async fn get_opts(&self, location: &Path, options: GetOptions) -> Result { let full_path = self.full_path(location); self.inner.get_opts(&full_path, options).await diff --git a/src/throttle.rs b/src/throttle.rs index 8b6196ab..b31d454b 100644 --- a/src/throttle.rs +++ b/src/throttle.rs @@ -181,17 +181,6 @@ impl ObjectStore for ThrottledStore { Ok(throttle_get(result, wait_get_per_byte)) } - async fn get_range(&self, location: &Path, range: Range) -> Result { - let config = self.config(); - - let sleep_duration = - config.wait_get_per_call + config.wait_get_per_byte * (range.end - range.start) as u32; - - sleep(sleep_duration).await; - - self.inner.get_range(location, range).await - } - async fn get_ranges(&self, location: &Path, ranges: &[Range]) -> Result> { let config = self.config();