This is an automated email from the ASF dual-hosted git repository.

tustvold pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git


The following commit(s) were added to refs/heads/master by this push:
     new bb8e42f639 Add GetOptions::head (#4931)
bb8e42f639 is described below

commit bb8e42f6392284f4a7a39d3eec74144a603b481c
Author: Raphael Taylor-Davies <[email protected]>
AuthorDate: Sun Oct 15 11:04:14 2023 +0100

    Add GetOptions::head (#4931)
---
 object_store/src/aws/client.rs   |  9 ++-------
 object_store/src/aws/mod.rs      |  4 ----
 object_store/src/azure/client.rs |  9 ++-------
 object_store/src/azure/mod.rs    |  4 ----
 object_store/src/client/get.rs   | 24 +++---------------------
 object_store/src/gcp/mod.rs      | 13 ++-----------
 object_store/src/http/client.rs  | 15 +++++----------
 object_store/src/http/mod.rs     |  4 ----
 object_store/src/lib.rs          | 12 +++++++++++-
 object_store/src/local.rs        | 37 ++++---------------------------------
 10 files changed, 29 insertions(+), 102 deletions(-)

diff --git a/object_store/src/aws/client.rs b/object_store/src/aws/client.rs
index e3ac60eca0..ac07f9ab9a 100644
--- a/object_store/src/aws/client.rs
+++ b/object_store/src/aws/client.rs
@@ -554,15 +554,10 @@ impl GetClient for S3Client {
     const STORE: &'static str = STORE;
 
     /// Make an S3 GET request 
<https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html>
-    async fn get_request(
-        &self,
-        path: &Path,
-        options: GetOptions,
-        head: bool,
-    ) -> Result<Response> {
+    async fn get_request(&self, path: &Path, options: GetOptions) -> 
Result<Response> {
         let credential = self.get_credential().await?;
         let url = self.config.path_url(path);
-        let method = match head {
+        let method = match options.head {
             true => Method::HEAD,
             false => Method::GET,
         };
diff --git a/object_store/src/aws/mod.rs b/object_store/src/aws/mod.rs
index 0028be99fa..285ee2f59d 100644
--- a/object_store/src/aws/mod.rs
+++ b/object_store/src/aws/mod.rs
@@ -307,10 +307,6 @@ impl ObjectStore for AmazonS3 {
         self.client.get_opts(location, options).await
     }
 
-    async fn head(&self, location: &Path) -> Result<ObjectMeta> {
-        self.client.head(location).await
-    }
-
     async fn delete(&self, location: &Path) -> Result<()> {
         self.client.delete_request(location, &()).await
     }
diff --git a/object_store/src/azure/client.rs b/object_store/src/azure/client.rs
index cd1a3a10fc..f65388b61a 100644
--- a/object_store/src/azure/client.rs
+++ b/object_store/src/azure/client.rs
@@ -264,15 +264,10 @@ impl GetClient for AzureClient {
     /// Make an Azure GET request
     /// <https://docs.microsoft.com/en-us/rest/api/storageservices/get-blob>
     /// 
<https://docs.microsoft.com/en-us/rest/api/storageservices/get-blob-properties>
-    async fn get_request(
-        &self,
-        path: &Path,
-        options: GetOptions,
-        head: bool,
-    ) -> Result<Response> {
+    async fn get_request(&self, path: &Path, options: GetOptions) -> 
Result<Response> {
         let credential = self.get_credential().await?;
         let url = self.config.path_url(path);
-        let method = match head {
+        let method = match options.head {
             true => Method::HEAD,
             false => Method::GET,
         };
diff --git a/object_store/src/azure/mod.rs b/object_store/src/azure/mod.rs
index b210d486d9..9017634c42 100644
--- a/object_store/src/azure/mod.rs
+++ b/object_store/src/azure/mod.rs
@@ -202,10 +202,6 @@ impl ObjectStore for MicrosoftAzure {
         self.client.get_opts(location, options).await
     }
 
-    async fn head(&self, location: &Path) -> Result<ObjectMeta> {
-        self.client.head(location).await
-    }
-
     async fn delete(&self, location: &Path) -> Result<()> {
         self.client.delete_request(location, &()).await
     }
diff --git a/object_store/src/client/get.rs b/object_store/src/client/get.rs
index 333f6fe584..7f68b6d122 100644
--- a/object_store/src/client/get.rs
+++ b/object_store/src/client/get.rs
@@ -17,7 +17,7 @@
 
 use crate::client::header::{header_meta, HeaderConfig};
 use crate::path::Path;
-use crate::{Error, GetOptions, GetResult, ObjectMeta};
+use crate::{Error, GetOptions, GetResult};
 use crate::{GetResultPayload, Result};
 use async_trait::async_trait;
 use futures::{StreamExt, TryStreamExt};
@@ -34,27 +34,20 @@ pub trait GetClient: Send + Sync + 'static {
         last_modified_required: true,
     };
 
-    async fn get_request(
-        &self,
-        path: &Path,
-        options: GetOptions,
-        head: bool,
-    ) -> Result<Response>;
+    async fn get_request(&self, path: &Path, options: GetOptions) -> 
Result<Response>;
 }
 
 /// Extension trait for [`GetClient`] that adds common retrieval functionality
 #[async_trait]
 pub trait GetClientExt {
     async fn get_opts(&self, location: &Path, options: GetOptions) -> 
Result<GetResult>;
-
-    async fn head(&self, location: &Path) -> Result<ObjectMeta>;
 }
 
 #[async_trait]
 impl<T: GetClient> GetClientExt for T {
     async fn get_opts(&self, location: &Path, options: GetOptions) -> 
Result<GetResult> {
         let range = options.range.clone();
-        let response = self.get_request(location, options, false).await?;
+        let response = self.get_request(location, options).await?;
         let meta =
             header_meta(location, response.headers(), 
T::HEADER_CONFIG).map_err(|e| {
                 Error::Generic {
@@ -77,15 +70,4 @@ impl<T: GetClient> GetClientExt for T {
             meta,
         })
     }
-
-    async fn head(&self, location: &Path) -> Result<ObjectMeta> {
-        let options = GetOptions::default();
-        let response = self.get_request(location, options, true).await?;
-        header_meta(location, response.headers(), 
T::HEADER_CONFIG).map_err(|e| {
-            Error::Generic {
-                store: T::STORE,
-                source: Box::new(e),
-            }
-        })
-    }
 }
diff --git a/object_store/src/gcp/mod.rs b/object_store/src/gcp/mod.rs
index a0a60f27a6..f80704b917 100644
--- a/object_store/src/gcp/mod.rs
+++ b/object_store/src/gcp/mod.rs
@@ -389,16 +389,11 @@ impl GetClient for GoogleCloudStorageClient {
     const STORE: &'static str = STORE;
 
     /// Perform a get request 
<https://cloud.google.com/storage/docs/xml-api/get-object-download>
-    async fn get_request(
-        &self,
-        path: &Path,
-        options: GetOptions,
-        head: bool,
-    ) -> Result<Response> {
+    async fn get_request(&self, path: &Path, options: GetOptions) -> 
Result<Response> {
         let credential = self.get_credential().await?;
         let url = self.object_url(path);
 
-        let method = match head {
+        let method = match options.head {
             true => Method::HEAD,
             false => Method::GET,
         };
@@ -604,10 +599,6 @@ impl ObjectStore for GoogleCloudStorage {
         self.client.get_opts(location, options).await
     }
 
-    async fn head(&self, location: &Path) -> Result<ObjectMeta> {
-        self.client.head(location).await
-    }
-
     async fn delete(&self, location: &Path) -> Result<()> {
         self.client.delete_request(location).await
     }
diff --git a/object_store/src/http/client.rs b/object_store/src/http/client.rs
index 0bd2e5639c..b2a6ac0aa3 100644
--- a/object_store/src/http/client.rs
+++ b/object_store/src/http/client.rs
@@ -288,14 +288,9 @@ impl GetClient for Client {
         last_modified_required: false,
     };
 
-    async fn get_request(
-        &self,
-        location: &Path,
-        options: GetOptions,
-        head: bool,
-    ) -> Result<Response> {
-        let url = self.path_url(location);
-        let method = match head {
+    async fn get_request(&self, path: &Path, options: GetOptions) -> 
Result<Response> {
+        let url = self.path_url(path);
+        let method = match options.head {
             true => Method::HEAD,
             false => Method::GET,
         };
@@ -311,7 +306,7 @@ impl GetClient for Client {
                 Some(StatusCode::NOT_FOUND | StatusCode::METHOD_NOT_ALLOWED) 
=> {
                     crate::Error::NotFound {
                         source: Box::new(source),
-                        path: location.to_string(),
+                        path: path.to_string(),
                     }
                 }
                 _ => Error::Request { source }.into(),
@@ -322,7 +317,7 @@ impl GetClient for Client {
         if has_range && res.status() != StatusCode::PARTIAL_CONTENT {
             return Err(crate::Error::NotSupported {
                 source: Box::new(Error::RangeNotSupported {
-                    href: location.to_string(),
+                    href: path.to_string(),
                 }),
             });
         }
diff --git a/object_store/src/http/mod.rs b/object_store/src/http/mod.rs
index e9ed5902d8..6ffb623589 100644
--- a/object_store/src/http/mod.rs
+++ b/object_store/src/http/mod.rs
@@ -118,10 +118,6 @@ impl ObjectStore for HttpStore {
         self.client.get_opts(location, options).await
     }
 
-    async fn head(&self, location: &Path) -> Result<ObjectMeta> {
-        self.client.head(location).await
-    }
-
     async fn delete(&self, location: &Path) -> Result<()> {
         self.client.delete(location).await
     }
diff --git a/object_store/src/lib.rs b/object_store/src/lib.rs
index 68e785b3a3..ff0a46533d 100644
--- a/object_store/src/lib.rs
+++ b/object_store/src/lib.rs
@@ -410,7 +410,13 @@ pub trait ObjectStore: std::fmt::Display + Send + Sync + 
Debug + 'static {
     }
 
     /// Return the metadata for the specified location
-    async fn head(&self, location: &Path) -> Result<ObjectMeta>;
+    async fn head(&self, location: &Path) -> Result<ObjectMeta> {
+        let options = GetOptions {
+            head: true,
+            ..Default::default()
+        };
+        Ok(self.get_opts(location, options).await?.meta)
+    }
 
     /// Delete the object at the specified location.
     async fn delete(&self, location: &Path) -> Result<()>;
@@ -716,6 +722,10 @@ pub struct GetOptions {
     ///
     /// <https://datatracker.ietf.org/doc/html/rfc9110#name-range>
     pub range: Option<Range<usize>>,
+    /// Request transfer of no content
+    ///
+    /// <https://datatracker.ietf.org/doc/html/rfc9110#name-head>
+    pub head: bool,
 }
 
 impl GetOptions {
diff --git a/object_store/src/local.rs b/object_store/src/local.rs
index 69da170b08..3ed63a4108 100644
--- a/object_store/src/local.rs
+++ b/object_store/src/local.rs
@@ -419,35 +419,6 @@ impl ObjectStore for LocalFileSystem {
         .await
     }
 
-    async fn head(&self, location: &Path) -> Result<ObjectMeta> {
-        let path = self.config.path_to_filesystem(location)?;
-        let location = location.clone();
-
-        maybe_spawn_blocking(move || {
-            let metadata = match metadata(&path) {
-                Err(e) => Err(match e.kind() {
-                    ErrorKind::NotFound => Error::NotFound {
-                        path: path.clone(),
-                        source: e,
-                    },
-                    _ => Error::Metadata {
-                        source: e.into(),
-                        path: location.to_string(),
-                    },
-                }),
-                Ok(m) => match !m.is_dir() {
-                    true => Ok(m),
-                    false => Err(Error::NotFound {
-                        path,
-                        source: io::Error::new(ErrorKind::NotFound, "is 
directory"),
-                    }),
-                },
-            }?;
-            convert_metadata(metadata, location)
-        })
-        .await
-    }
-
     async fn delete(&self, location: &Path) -> Result<()> {
         let path = self.config.path_to_filesystem(location)?;
         maybe_spawn_blocking(move || match std::fs::remove_file(&path) {
@@ -1604,15 +1575,15 @@ mod unix_test {
         let path = root.path().join(filename);
         unistd::mkfifo(&path, stat::Mode::S_IRWXU).unwrap();
 
-        let location = Path::from(filename);
-        integration.head(&location).await.unwrap();
-
         // Need to open read and write side in parallel
         let spawned = tokio::task::spawn_blocking(|| {
-            OpenOptions::new().write(true).open(path).unwrap();
+            OpenOptions::new().write(true).open(path).unwrap()
         });
 
+        let location = Path::from(filename);
+        integration.head(&location).await.unwrap();
         integration.get(&location).await.unwrap();
+
         spawned.await.unwrap();
     }
 }

Reply via email to