diff --git a/binaries/oay/src/services/http/mod.rs b/binaries/oay/src/services/http/mod.rs index c588b4f533ba..643226076e2e 100644 --- a/binaries/oay/src/services/http/mod.rs +++ b/binaries/oay/src/services/http/mod.rs @@ -78,7 +78,7 @@ impl Service { .op .object(&percent_decode(req.path().as_bytes()).decode_utf8_lossy()); - let meta = o.metadata().await?; + let meta = o.stat().await?; let (size, r) = if let Some(range) = req.headers().get(header::RANGE) { let br = BytesRange::from_str(range.to_str().map_err(|e| { @@ -103,7 +103,7 @@ impl Service { } async fn put(&self, req: HttpRequest, mut body: web::Payload) -> Result { - let o = self + let mut o = self .op .object(&percent_decode(req.path().as_bytes()).decode_utf8_lossy()); @@ -167,7 +167,7 @@ impl Service { let o = self .op .object(&percent_decode(req.path().as_bytes()).decode_utf8_lossy()); - let meta = o.metadata().await?; + let meta = o.stat().await?; Ok(HttpResponse::Ok().body(SizedStream::new( meta.content_length(), diff --git a/binaries/oli/src/commands/cp.rs b/binaries/oli/src/commands/cp.rs index 33079e18664e..8fae3e5df850 100644 --- a/binaries/oli/src/commands/cp.rs +++ b/binaries/oli/src/commands/cp.rs @@ -31,9 +31,9 @@ pub async fn main(args: Option) -> Result<()> { .get_one::("destination") .ok_or_else(|| anyhow!("missing target"))?; let (dst_op, dst_path) = parse_location(dst)?; - let dst_o = dst_op.object(dst_path); + let mut dst_o = dst_op.object(dst_path); - let size = src_o.metadata().await?.content_length(); + let size = src_o.stat().await?.content_length(); let reader = src_o.reader().await?; dst_o.write_from(size, reader).await?; Ok(()) diff --git a/bindings/object_store/src/lib.rs b/bindings/object_store/src/lib.rs index 015bf38eec4a..ca7f76d9acbd 100644 --- a/bindings/object_store/src/lib.rs +++ b/bindings/object_store/src/lib.rs @@ -56,7 +56,7 @@ impl std::fmt::Display for OpendalStore { #[async_trait] impl ObjectStore for OpendalStore { async fn put(&self, location: &Path, bytes: Bytes) -> Result<()> { - let o = self.inner.object(location.as_ref()); + let mut o = self.inner.object(location.as_ref()); Ok(o.write(bytes) .await .map_err(|err| format_object_store_error(err, location.as_ref()))?) @@ -106,7 +106,7 @@ impl ObjectStore for OpendalStore { async fn head(&self, location: &Path) -> Result { let o = self.inner.object(location.as_ref()); let meta = o - .metadata() + .stat() .await .map_err(|err| format_object_store_error(err, location.as_ref()))?; @@ -127,7 +127,7 @@ impl ObjectStore for OpendalStore { } async fn delete(&self, location: &Path) -> Result<()> { - let o = self.inner.object(location.as_ref()); + let mut o = self.inner.object(location.as_ref()); o.delete() .await .map_err(|err| format_object_store_error(err, location.as_ref()))?; diff --git a/src/error.rs b/src/error.rs index fec913181a3a..6380ee549f43 100644 --- a/src/error.rs +++ b/src/error.rs @@ -23,7 +23,7 @@ //! use opendal::ErrorKind; //! # #[tokio::main] //! # async fn test(op: Operator) -> Result<()> { -//! if let Err(e) = op.object("test_file").metadata().await { +//! if let Err(e) = op.object("test_file").stat().await { //! if e.kind() == ErrorKind::ObjectNotFound { //! println!("object not exist") //! } diff --git a/src/layers/complete.rs b/src/layers/complete.rs index 16cdfe641041..1cb4550909fa 100644 --- a/src/layers/complete.rs +++ b/src/layers/complete.rs @@ -291,6 +291,19 @@ impl LayeredAccessor for CompleteReaderAccessor { self.complete_blocking_reader(path, args) } + async fn stat(&self, path: &str, args: OpStat) -> Result { + self.inner + .stat(path, args) + .await + .map(|v| v.map_metadata(|m| m.with_complete())) + } + + fn blocking_stat(&self, path: &str, args: OpStat) -> Result { + self.inner + .blocking_stat(path, args) + .map(|v| v.map_metadata(|m| m.with_complete())) + } + async fn list(&self, path: &str, args: OpList) -> Result<(RpList, Self::Pager)> { self.complete_list(path, args).await } diff --git a/src/layers/immutable_index.rs b/src/layers/immutable_index.rs index 9818c19627a3..9325742c4456 100644 --- a/src/layers/immutable_index.rs +++ b/src/layers/immutable_index.rs @@ -289,14 +289,17 @@ mod tests { let mut map = HashMap::new(); let mut set = HashSet::new(); let mut ds = op.object("").list().await?; - while let Some(entry) = ds.try_next().await? { + while let Some(mut entry) = ds.try_next().await? { debug!("got entry: {}", entry.path()); assert!( set.insert(entry.path().to_string()), "duplicated value: {}", entry.path() ); - map.insert(entry.path().to_string(), entry.mode().await?); + map.insert( + entry.path().to_string(), + entry.metadata(ObjectMetadataKey::Mode).await?.mode(), + ); } assert_eq!(map["file"], ObjectMode::FILE); @@ -324,14 +327,17 @@ mod tests { let mut ds = op.object("/").scan().await?; let mut set = HashSet::new(); let mut map = HashMap::new(); - while let Some(entry) = ds.try_next().await? { + while let Some(mut entry) = ds.try_next().await? { debug!("got entry: {}", entry.path()); assert!( set.insert(entry.path().to_string()), "duplicated value: {}", entry.path() ); - map.insert(entry.path().to_string(), entry.mode().await?); + map.insert( + entry.path().to_string(), + entry.metadata(ObjectMetadataKey::Mode).await?.mode(), + ); } debug!("current files: {:?}", map); @@ -366,13 +372,16 @@ mod tests { let mut map = HashMap::new(); let mut set = HashSet::new(); let mut ds = op.object("/").list().await?; - while let Some(entry) = ds.try_next().await? { + while let Some(mut entry) = ds.try_next().await? { assert!( set.insert(entry.path().to_string()), "duplicated value: {}", entry.path() ); - map.insert(entry.path().to_string(), entry.mode().await?); + map.insert( + entry.path().to_string(), + entry.metadata(ObjectMetadataKey::Mode).await?.mode(), + ); } assert_eq!(map.len(), 1); @@ -382,13 +391,16 @@ mod tests { let mut map = HashMap::new(); let mut set = HashSet::new(); let mut ds = op.object("dataset/stateful/").list().await?; - while let Some(entry) = ds.try_next().await? { + while let Some(mut entry) = ds.try_next().await? { assert!( set.insert(entry.path().to_string()), "duplicated value: {}", entry.path() ); - map.insert(entry.path().to_string(), entry.mode().await?); + map.insert( + entry.path().to_string(), + entry.metadata(ObjectMetadataKey::Mode).await?.mode(), + ); } assert_eq!( @@ -430,13 +442,16 @@ mod tests { let mut map = HashMap::new(); let mut set = HashSet::new(); - while let Some(entry) = ds.try_next().await? { + while let Some(mut entry) = ds.try_next().await? { assert!( set.insert(entry.path().to_string()), "duplicated value: {}", entry.path() ); - map.insert(entry.path().to_string(), entry.mode().await?); + map.insert( + entry.path().to_string(), + entry.metadata(ObjectMetadataKey::Mode).await?.mode(), + ); } debug!("current files: {:?}", map); diff --git a/src/lib.rs b/src/lib.rs index 9cc54b111b64..7aea8a834c2f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,7 +40,7 @@ //! .finish(); //! //! // Create object handler. -//! let o = op.object("test_file"); +//! let mut o = op.object("test_file"); //! //! // Write data //! o.write("Hello, World!").await?; @@ -49,7 +49,7 @@ //! let bs = o.read().await?; //! //! // Fetch metadata -//! let meta = o.metadata().await?; +//! let meta = o.stat().await?; //! let mode = meta.mode(); //! let length = meta.content_length(); //! @@ -79,6 +79,7 @@ mod object; pub use object::Object; pub use object::ObjectLister; pub use object::ObjectMetadata; +pub use object::ObjectMetadataKey; pub use object::ObjectMode; pub use object::ObjectMultipart; pub use object::ObjectPart; @@ -116,9 +117,8 @@ mod tests { assert_eq!(88, size_of::()); assert_eq!(16, size_of::()); assert_eq!(112, size_of::()); - assert_eq!(208, size_of::()); - assert_eq!(48, size_of::()); - assert_eq!(184, size_of::()); + assert_eq!(32, size_of::()); + assert_eq!(192, size_of::()); assert_eq!(1, size_of::()); assert_eq!(64, size_of::()); assert_eq!(32, size_of::()); diff --git a/src/object/blocking_reader.rs b/src/object/blocking_reader.rs index 57b38db0ff41..bfa656a52dcf 100644 --- a/src/object/blocking_reader.rs +++ b/src/object/blocking_reader.rs @@ -14,17 +14,14 @@ use std::io; use std::io::SeekFrom; -use std::sync::Arc; use bytes::Bytes; -use parking_lot::Mutex; use crate::error::Error; use crate::error::Result; use crate::ops::OpRead; use crate::raw::*; use crate::ErrorKind; -use crate::ObjectMetadata; /// BlockingObjectReader is the public API for users. pub struct BlockingObjectReader { @@ -39,12 +36,7 @@ impl BlockingObjectReader { /// /// We don't want to expose those details to users so keep this function /// in crate only. - pub(crate) fn create( - acc: FusedAccessor, - path: &str, - _meta: Arc>, - op: OpRead, - ) -> Result { + pub(crate) fn create(acc: FusedAccessor, path: &str, op: OpRead) -> Result { let acc_meta = acc.metadata(); let r = if acc_meta.hints().contains(AccessorHint::ReadSeekable) { diff --git a/src/object/metadata.rs b/src/object/metadata.rs index 40d8ffc02579..4eb72150fcd1 100644 --- a/src/object/metadata.rs +++ b/src/object/metadata.rs @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +use flagset::flags; +use flagset::FlagSet; use time::OffsetDateTime; use crate::raw::*; @@ -24,41 +26,39 @@ use crate::*; /// mode and content_length are required metadata that all services /// should provide during `stat` operation. But in `list` operation, /// a.k.a., `Entry`'s content length could be `None`. -#[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct ObjectMetadata { /// Mark if this metadata is complete or not. complete: bool, + /// bit stores current key store. + bit: FlagSet, /// Mode of this object. mode: ObjectMode, + /// Content-Disposition of this object + content_disposition: Option, /// Content Length of this object - /// - /// # NOTE - /// - /// - For `stat` operation, content_length is required to set. - /// - For `list` operation, content_length could be None. - /// - For `read` operation, content_length could be the length of request. content_length: Option, /// Content MD5 of this object. content_md5: Option, - /// Content Type of this object. - content_type: Option, /// Content Range of this object. content_range: Option, - /// Last Modified of this object. - last_modified: Option, + /// Content Type of this object. + content_type: Option, /// ETag of this object. etag: Option, - /// Content-Disposition of this object - content_disposition: Option, + /// Last Modified of this object. + last_modified: Option, } impl ObjectMetadata { /// Create a new object metadata pub fn new(mode: ObjectMode) -> Self { Self { - complete: false, + // If mode is dir, we will set complete to true. + complete: mode == ObjectMode::DIR, + bit: ObjectMetadataKey::Mode.into(), mode, @@ -73,20 +73,19 @@ impl ObjectMetadata { } /// If this object metadata if complete - pub fn is_complete(&self) -> bool { + pub(crate) fn is_complete(&self) -> bool { self.complete } /// Make this object metadata if complete. - pub fn set_complete(&mut self) -> &mut Self { + pub(crate) fn with_complete(mut self) -> Self { self.complete = true; self } - /// Make this object metadata if complete. - pub fn with_complete(mut self) -> Self { - self.complete = true; - self + /// Get the bit from object metadata. + pub(crate) fn bit(&self) -> FlagSet { + self.bit } /// Object mode represent this object's mode. @@ -97,12 +96,14 @@ impl ObjectMetadata { /// Set mode for object. pub fn set_mode(&mut self, mode: ObjectMode) -> &mut Self { self.mode = mode; + self.bit |= ObjectMetadataKey::Mode; self } /// Set mode for object. pub fn with_mode(mut self, mode: ObjectMode) -> Self { self.mode = mode; + self.bit |= ObjectMetadataKey::Mode; self } @@ -122,12 +123,14 @@ impl ObjectMetadata { /// Set content length of this object. pub fn set_content_length(&mut self, content_length: u64) -> &mut Self { self.content_length = Some(content_length); + self.bit |= ObjectMetadataKey::ContentLength; self } /// Set content length of this object. pub fn with_content_length(mut self, content_length: u64) -> Self { self.content_length = Some(content_length); + self.bit |= ObjectMetadataKey::ContentLength; self } @@ -147,6 +150,7 @@ impl ObjectMetadata { /// And removed by [RFC 7231](https://www.rfc-editor.org/rfc/rfc7231). pub fn set_content_md5(&mut self, content_md5: &str) -> &mut Self { self.content_md5 = Some(content_md5.to_string()); + self.bit |= ObjectMetadataKey::ContentMd5; self } @@ -154,8 +158,9 @@ impl ObjectMetadata { /// /// Content MD5 is defined by [RFC 2616](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html). /// And removed by [RFC 7231](https://www.rfc-editor.org/rfc/rfc7231). - pub fn with_content_md5(mut self, content_md5: &str) -> Self { - self.content_md5 = Some(content_md5.to_string()); + pub fn with_content_md5(mut self, content_md5: String) -> Self { + self.content_md5 = Some(content_md5); + self.bit |= ObjectMetadataKey::ContentMd5; self } @@ -171,14 +176,16 @@ impl ObjectMetadata { /// Content Type is defined by [RFC 9110](https://httpwg.org/specs/rfc9110.html#field.content-type). pub fn set_content_type(&mut self, v: &str) -> &mut Self { self.content_type = Some(v.to_string()); + self.bit |= ObjectMetadataKey::ContentType; self } /// Set Content Type of this object. /// /// Content Type is defined by [RFC 9110](https://httpwg.org/specs/rfc9110.html#field.content-type). - pub fn with_content_type(mut self, v: &str) -> Self { - self.content_type = Some(v.to_string()); + pub fn with_content_type(mut self, v: String) -> Self { + self.content_type = Some(v); + self.bit |= ObjectMetadataKey::ContentType; self } @@ -194,6 +201,7 @@ impl ObjectMetadata { /// Content Range is defined by [RFC 9110](https://httpwg.org/specs/rfc9110.html#field.content-range). pub fn set_content_range(&mut self, v: BytesContentRange) -> &mut Self { self.content_range = Some(v); + self.bit |= ObjectMetadataKey::ContentRange; self } @@ -202,6 +210,7 @@ impl ObjectMetadata { /// Content Range is defined by [RFC 9110](https://httpwg.org/specs/rfc9110.html#field.content-range). pub fn with_content_range(mut self, v: BytesContentRange) -> Self { self.content_range = Some(v); + self.bit |= ObjectMetadataKey::ContentRange; self } @@ -221,6 +230,7 @@ impl ObjectMetadata { /// Refer to [MDN Last-Modified](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified) for more information. pub fn set_last_modified(&mut self, last_modified: OffsetDateTime) -> &mut Self { self.last_modified = Some(last_modified); + self.bit |= ObjectMetadataKey::LastModified; self } @@ -230,6 +240,7 @@ impl ObjectMetadata { /// Refer to [MDN Last-Modified](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified) for more information. pub fn with_last_modified(mut self, last_modified: OffsetDateTime) -> Self { self.last_modified = Some(last_modified); + self.bit |= ObjectMetadataKey::LastModified; self } @@ -261,6 +272,7 @@ impl ObjectMetadata { /// `"` is part of etag, don't trim it before setting. pub fn set_etag(&mut self, etag: &str) -> &mut Self { self.etag = Some(etag.to_string()); + self.bit |= ObjectMetadataKey::Etag; self } @@ -275,8 +287,9 @@ impl ObjectMetadata { /// - `W/"0815"` /// /// `"` is part of etag, don't trim it before setting. - pub fn with_etag(mut self, etag: &str) -> Self { - self.etag = Some(etag.to_string()); + pub fn with_etag(mut self, etag: String) -> Self { + self.etag = Some(etag); + self.bit |= ObjectMetadataKey::Etag; self } @@ -306,8 +319,9 @@ impl ObjectMetadata { /// - "inline" /// - "attachment" /// - "attachment; filename=\"filename.jpg\"" - pub fn with_content_disposition(mut self, content_disposition: &str) -> Self { - self.content_disposition = Some(content_disposition.to_string()); + pub fn with_content_disposition(mut self, content_disposition: String) -> Self { + self.content_disposition = Some(content_disposition); + self.bit |= ObjectMetadataKey::ContentDisposition; self } @@ -324,6 +338,41 @@ impl ObjectMetadata { /// - "attachment; filename=\"filename.jpg\"" pub fn set_content_disposition(&mut self, content_disposition: &str) -> &mut Self { self.content_disposition = Some(content_disposition.to_string()); + self.bit |= ObjectMetadataKey::ContentDisposition; self } } + +flags! { + /// ObjectMetadataKey describes the metadata keys that can be stored + /// or quried. + /// + /// ## For store + /// + /// Internally, we will store a flag set of ObjectMetadataKey to check + /// whether we have set some key already. + /// + /// ## For query + /// + /// At user side, we will allow user to query the object metadata. If + /// the meta has been stored, we will return directly. If no, we will + /// call `stat` internally to fecth the metadata. + pub enum ObjectMetadataKey: u64 { + /// Key for mode. + Mode, + /// Key for content disposition. + ContentDisposition, + /// Key for content length. + ContentLength, + /// Key for content md5. + ContentMd5, + /// Key for content range. + ContentRange, + /// Key for content type. + ContentType, + /// Key for etag. + Etag, + /// Key for last last modified. + LastModified, + } +} diff --git a/src/object/mod.rs b/src/object/mod.rs index 8a6ace2ca6f7..2a0b8768d594 100644 --- a/src/object/mod.rs +++ b/src/object/mod.rs @@ -17,6 +17,7 @@ pub use mode::ObjectMode; mod metadata; pub use metadata::ObjectMetadata; +pub use metadata::ObjectMetadataKey; mod multipart; pub use multipart::ObjectMultipart; diff --git a/src/object/object.rs b/src/object/object.rs index ca24b12c954d..577e3d5002e4 100644 --- a/src/object/object.rs +++ b/src/object/object.rs @@ -17,12 +17,10 @@ use std::io::Read; use std::ops::RangeBounds; use std::sync::Arc; +use flagset::FlagSet; use futures::io::Cursor; use futures::AsyncReadExt; -use parking_lot::Mutex; -use parking_lot::MutexGuard; use time::Duration; -use time::OffsetDateTime; use tokio::io::ReadBuf; use super::BlockingObjectLister; @@ -41,9 +39,9 @@ use crate::*; #[derive(Clone, Debug)] pub struct Object { acc: FusedAccessor, - path: String, + path: Arc, - meta: Arc>, + meta: Option>, } impl Object { @@ -53,14 +51,14 @@ impl Object { /// - Path endswith `/` means it's a dir path. /// - Otherwise, it's a file path. pub fn new(op: Operator, path: &str) -> Self { - Self::with(op, path, ObjectMetadata::new(ObjectMode::Unknown)) + Self::with(op, path, None) } - pub(crate) fn with(op: Operator, path: &str, meta: ObjectMetadata) -> Self { + pub(crate) fn with(op: Operator, path: &str, meta: Option) -> Self { Self { acc: op.inner(), - path: normalize_path(path), - meta: Arc::new(Mutex::new(meta)), + path: Arc::new(normalize_path(path)), + meta: meta.map(Arc::new), } } @@ -149,44 +147,6 @@ impl Object { get_basename(&self.path) } - /// Return this object entry's object mode. - pub async fn mode(&self) -> Result { - { - let guard = self.meta.lock(); - // Object mode other than unknown is OK to be returned. - if guard.mode() != ObjectMode::Unknown { - return Ok(guard.mode()); - } - // Object mode is unknown, but the object metadata is marked - // as complete. - if guard.mode() == ObjectMode::Unknown && guard.is_complete() { - return Ok(guard.mode()); - } - } - - let guard = self.metadata_ref().await?; - Ok(guard.mode()) - } - - /// Return this object entry's object mode in blocking way. - pub fn blocking_mode(&self) -> Result { - { - let guard = self.meta.lock(); - // Object mode other than unknown is OK to be returned. - if guard.mode() != ObjectMode::Unknown { - return Ok(guard.mode()); - } - // Object mode is unknown, but the object metadata is marked - // as complete. - if guard.mode() == ObjectMode::Unknown && guard.is_complete() { - return Ok(guard.mode()); - } - } - - let guard = self.blocking_metadata_ref()?; - Ok(guard.mode()) - } - /// Create an empty object, like using the following linux commands: /// /// - `touch path/to/file` @@ -207,7 +167,7 @@ impl Object { /// # use futures::TryStreamExt; /// # #[tokio::main] /// # async fn test(op: Operator) -> Result<()> { - /// let o = op.object("path/to/file"); + /// let mut o = op.object("path/to/file"); /// let _ = o.create().await?; /// # Ok(()) /// # } @@ -221,12 +181,12 @@ impl Object { /// # use futures::TryStreamExt; /// # #[tokio::main] /// # async fn test(op: Operator) -> Result<()> { - /// let o = op.object("path/to/dir/"); + /// let mut o = op.object("path/to/dir/"); /// let _ = o.create().await?; /// # Ok(()) /// # } /// ``` - pub async fn create(&self) -> Result<()> { + pub async fn create(&mut self) -> Result<()> { let _ = if self.path.ends_with('/') { self.acc .create(self.path(), OpCreate::new(ObjectMode::DIR)) @@ -259,7 +219,7 @@ impl Object { /// # use opendal::Operator; /// # use futures::TryStreamExt; /// # fn test(op: Operator) -> Result<()> { - /// let o = op.object("path/to/file"); + /// let mut o = op.object("path/to/file"); /// let _ = o.blocking_create()?; /// # Ok(()) /// # } @@ -272,12 +232,12 @@ impl Object { /// # use opendal::Operator; /// # use futures::TryStreamExt; /// # async fn test(op: Operator) -> Result<()> { - /// let o = op.object("path/to/dir/"); + /// let mut o = op.object("path/to/dir/"); /// let _ = o.blocking_create()?; /// # Ok(()) /// # } /// ``` - pub fn blocking_create(&self) -> Result<()> { + pub fn blocking_create(&mut self) -> Result<()> { if self.path.ends_with('/') { self.acc .blocking_create(self.path(), OpCreate::new(ObjectMode::DIR))?; @@ -302,7 +262,7 @@ impl Object { /// # use futures::TryStreamExt; /// # #[tokio::main] /// # async fn test(op: Operator) -> Result<()> { - /// let o = op.object("path/to/file"); + /// let mut o = op.object("path/to/file"); /// # o.write(vec![0; 4096]).await?; /// let bs = o.read().await?; /// # Ok(()) @@ -324,7 +284,7 @@ impl Object { /// # use opendal::Operator; /// # /// # fn test(op: Operator) -> Result<()> { - /// let o = op.object("path/to/file"); + /// # let mut o = op.object("path/to/file"); /// # o.blocking_write(vec![0; 4096])?; /// let bs = o.blocking_read()?; /// # Ok(()) @@ -351,7 +311,7 @@ impl Object { /// # use futures::TryStreamExt; /// # #[tokio::main] /// # async fn test(op: Operator) -> Result<()> { - /// let o = op.object("path/to/file"); + /// let mut o = op.object("path/to/file"); /// # o.write(vec![0; 4096]).await?; /// let bs = o.range_read(1024..2048).await?; /// # Ok(()) @@ -408,7 +368,7 @@ impl Object { /// # use futures::TryStreamExt; /// # use opendal::Scheme; /// # async fn test(op: Operator) -> Result<()> { - /// let o = op.object("path/to/file"); + /// # let mut o = op.object("path/to/file"); /// # o.blocking_write(vec![0; 4096])?; /// let bs = o.blocking_range_read(1024..2048)?; /// # Ok(()) @@ -543,7 +503,7 @@ impl Object { let op = OpRead::new().with_range(range.into()); - BlockingObjectReader::create(self.accessor(), self.path(), self.meta.clone(), op) + BlockingObjectReader::create(self.accessor(), self.path(), op) } /// Read the whole object into a bytes with auto detected compress algorithm. @@ -697,12 +657,12 @@ impl Object { /// /// # #[tokio::main] /// # async fn test(op: Operator) -> Result<()> { - /// let o = op.object("path/to/file"); + /// let mut o = op.object("path/to/file"); /// let _ = o.write(vec![0; 4096]).await?; /// # Ok(()) /// # } /// ``` - pub async fn write(&self, bs: impl Into>) -> Result<()> { + pub async fn write(&mut self, bs: impl Into>) -> Result<()> { let bs: Vec = bs.into(); let op = OpWrite::new(bs.len() as u64); self.write_with(op, bs).await @@ -724,14 +684,14 @@ impl Object { /// /// # #[tokio::main] /// # async fn test(op: Operator) -> Result<()> { - /// let o = op.object("path/to/file"); + /// let mut o = op.object("path/to/file"); /// let bs = b"hello, world!".to_vec(); /// let args = OpWrite::new(bs.len() as u64).with_content_type("text/plain"); /// let _ = o.write_with(args, bs).await?; /// # Ok(()) /// # } /// ``` - pub async fn write_with(&self, args: OpWrite, bs: impl Into>) -> Result<()> { + pub async fn write_with(&mut self, args: OpWrite, bs: impl Into>) -> Result<()> { if !validate_path(self.path(), ObjectMode::FILE) { return Err( Error::new(ErrorKind::ObjectIsADirectory, "write path is a directory") @@ -746,9 +706,10 @@ impl Object { let rp = self.acc.write(self.path(), args, Box::new(r)).await?; // Always write latest metadata into cache. - { - let mut guard = self.meta.lock(); - *guard = ObjectMetadata::new(ObjectMode::FILE).with_content_length(rp.written()); + if self.meta.is_some() { + self.meta = Some(Arc::new( + ObjectMetadata::new(ObjectMode::FILE).with_content_length(rp.written()), + )); } Ok(()) @@ -770,12 +731,12 @@ impl Object { /// use bytes::Bytes; /// /// # fn test(op: Operator) -> Result<()> { - /// let o = op.object("path/to/file"); + /// let mut o = op.object("path/to/file"); /// let _ = o.blocking_write(vec![0; 4096])?; /// # Ok(()) /// # } /// ``` - pub fn blocking_write(&self, bs: impl Into>) -> Result<()> { + pub fn blocking_write(&mut self, bs: impl Into>) -> Result<()> { let bs: Vec = bs.into(); let op = OpWrite::new(bs.len() as u64); self.blocking_write_with(op, bs) @@ -796,14 +757,14 @@ impl Object { /// use opendal::ops::OpWrite; /// /// # async fn test(op: Operator) -> Result<()> { - /// let o = op.object("hello.txt"); + /// let mut o = op.object("hello.txt"); /// let bs = b"hello, world!".to_vec(); /// let ow = OpWrite::new(bs.len() as u64).with_content_type("text/plain"); /// let _ = o.blocking_write_with(ow, bs)?; /// # Ok(()) /// # } /// ``` - pub fn blocking_write_with(&self, args: OpWrite, bs: impl Into>) -> Result<()> { + pub fn blocking_write_with(&mut self, args: OpWrite, bs: impl Into>) -> Result<()> { if !validate_path(self.path(), ObjectMode::FILE) { return Err( Error::new(ErrorKind::ObjectIsADirectory, "write path is a directory") @@ -818,9 +779,10 @@ impl Object { let rp = self.acc.blocking_write(self.path(), args, Box::new(r))?; // Always write latest metadata into cache. - { - let mut guard = self.meta.lock(); - *guard = ObjectMetadata::new(ObjectMode::FILE).with_content_length(rp.written()); + if self.meta.is_some() { + self.meta = Some(Arc::new( + ObjectMetadata::new(ObjectMode::FILE).with_content_length(rp.written()), + )); } Ok(()) } @@ -843,13 +805,13 @@ impl Object { /// /// # #[tokio::main] /// # async fn test(op: Operator) -> Result<()> { - /// let o = op.object("path/to/file"); + /// let mut o = op.object("path/to/file"); /// let r = Cursor::new(vec![0; 4096]); /// let _ = o.write_from(4096, r).await?; /// # Ok(()) /// # } /// ``` - pub async fn write_from(&self, size: u64, br: impl input::Read + 'static) -> Result<()> { + pub async fn write_from(&mut self, size: u64, br: impl input::Read + 'static) -> Result<()> { if !validate_path(self.path(), ObjectMode::FILE) { return Err( Error::new(ErrorKind::ObjectIsADirectory, "write path is a directory") @@ -884,14 +846,14 @@ impl Object { /// use bytes::Bytes; /// /// # async fn test(op: Operator) -> Result<()> { - /// let o = op.object("path/to/file"); + /// let mut o = op.object("path/to/file"); /// let r = Cursor::new(vec![0; 4096]); /// let _ = o.blocking_write_from(4096, r)?; /// # Ok(()) /// # } /// ``` pub fn blocking_write_from( - &self, + &mut self, size: u64, br: impl input::BlockingRead + 'static, ) -> Result<()> { @@ -928,14 +890,12 @@ impl Object { /// # Ok(()) /// # } /// ``` - pub async fn delete(&self) -> Result<()> { + pub async fn delete(&mut self) -> Result<()> { let _ = self.acc.delete(self.path(), OpDelete::new()).await?; // Always write latest metadata into cache. - { - let mut guard = self.meta.lock(); - *guard = ObjectMetadata::new(ObjectMode::Unknown); - } + self.meta = None; + Ok(()) } @@ -956,14 +916,12 @@ impl Object { /// # Ok(()) /// # } /// ``` - pub fn blocking_delete(&self) -> Result<()> { + pub fn blocking_delete(&mut self) -> Result<()> { let _ = self.acc.blocking_delete(self.path(), OpDelete::new())?; // Always write latest metadata into cache. - { - let mut guard = self.meta.lock(); - *guard = ObjectMetadata::new(ObjectMode::Unknown); - } + self.meta = None; + Ok(()) } @@ -985,9 +943,14 @@ impl Object { /// # async fn test(op: Operator) -> Result<()> { /// let o = op.object("path/to/dir/"); /// let mut ds = o.list().await?; - /// // ObjectStreamer implements `futures::Stream` - /// while let Some(de) = ds.try_next().await? { - /// match de.mode().await? { + /// while let Some(mut de) = ds.try_next().await? { + /// let meta = de + /// .metadata({ + /// use opendal::ObjectMetadataKey::*; + /// Mode + /// }) + /// .await?; + /// match meta.mode() { /// ObjectMode::FILE => { /// println!("Handling file") /// } @@ -1032,9 +995,12 @@ impl Object { /// # fn test(op: Operator) -> Result<()> { /// let o = op.object("path/to/dir/"); /// let mut ds = o.blocking_list()?; - /// while let Some(de) = ds.next() { - /// let de = de?; - /// match de.blocking_mode()? { + /// while let Some(mut de) = ds.next() { + /// let meta = de?.blocking_metadata({ + /// use opendal::ObjectMetadataKey::*; + /// Mode + /// })?; + /// match meta.mode() { /// ObjectMode::FILE => { /// println!("Handling file") /// } @@ -1076,13 +1042,19 @@ impl Object { /// # use opendal::Operator; /// # use opendal::ObjectMode; /// # use futures::TryStreamExt; + /// # /// # #[tokio::main] /// # async fn test(op: Operator) -> Result<()> { /// let o = op.object("path/to/dir/"); /// let mut ds = o.scan().await?; - /// // ObjectStreamer implements `futures::Stream` - /// while let Some(de) = ds.try_next().await? { - /// match de.mode().await? { + /// while let Some(mut de) = ds.try_next().await? { + /// let meta = de + /// .metadata({ + /// use opendal::ObjectMetadataKey::*; + /// Mode + /// }) + /// .await?; + /// match meta.mode() { /// ObjectMode::FILE => { /// println!("Handling file") /// } @@ -1127,9 +1099,12 @@ impl Object { /// # fn test(op: Operator) -> Result<()> { /// let o = op.object("path/to/dir/"); /// let mut ds = o.blocking_list()?; - /// while let Some(de) = ds.next() { - /// let de = de?; - /// match de.blocking_mode()? { + /// while let Some(mut de) = ds.next() { + /// let meta = de?.blocking_metadata({ + /// use opendal::ObjectMetadataKey::*; + /// Mode + /// })?; + /// match meta.mode() { /// ObjectMode::FILE => { /// println!("Handling file") /// } @@ -1157,79 +1132,60 @@ impl Object { Ok(BlockingObjectLister::new(self.acc.clone(), pager)) } - /// metadata_ref is used to get object metadata with mutex guard. - /// - /// Called can decide to access or clone the content of object metadata. - /// But they can't pass the guard outside or across the await boundary. + /// Get current object's metadata **without cache** directly. /// /// # Notes /// - /// We return `MutexGuard<'_, ObjectMetadata>` here to make rustc 1.60 happy. - /// After MSRV bumped to higher version, we can elide this. - async fn metadata_ref(&self) -> Result> { - // Make sure the mutex guard has been dropped. - { - let guard = self.meta.lock(); - if guard.is_complete() { - return Ok(guard); - } - } - - let rp = self.acc.stat(self.path(), OpStat::new()).await?; - let meta = rp.into_metadata(); - - let mut guard = self.meta.lock(); - *guard = meta; - - Ok(guard) - } - - fn blocking_metadata_ref(&self) -> Result> { - // Make sure the mutex guard has been dropped. - { - let guard = self.meta.lock(); - if guard.is_complete() { - return Ok(guard); - } - } - - let rp = self.acc.blocking_stat(self.path(), OpStat::new())?; - let meta = rp.into_metadata(); - - let mut guard = self.meta.lock(); - *guard = meta; - - Ok(guard) - } - - /// Get current object's metadata **without cache**. + /// Use `stat` if you: /// - /// # Notes + /// - Want detect the outside changes of object. + /// - Don't want to read from cached object metadata. + /// - No repeated stat call will be sent to the same object. /// - /// This function works exactly the same with `Object::metadata`.The - /// only difference is it will not try to load data from cached metadata. + /// You may want to use `metadata`, if you: /// - /// Use this function to detect the outside changes of object. + /// - Are working with objects returned by [`ObjectLister`]. It's highly possible that metadata you want has already been cached. + /// - Are working with the same object instance. + /// + /// # Examples + /// + /// ``` + /// # use anyhow::Result; + /// # use futures::io; + /// # use opendal::Operator; + /// use opendal::ErrorKind; + /// # + /// # #[tokio::main] + /// # async fn test(op: Operator) -> Result<()> { + /// if let Err(e) = op.object("test").stat().await { + /// if e.kind() == ErrorKind::ObjectNotFound { + /// println!("object not exist") + /// } + /// } + /// # Ok(()) + /// # } + /// ``` pub async fn stat(&self) -> Result { let rp = self.acc.stat(self.path(), OpStat::new()).await?; let meta = rp.into_metadata(); - // Always write latest metadata into cache. - { - let mut guard = self.meta.lock(); - *guard = meta.clone(); - } - Ok(meta) } - /// Get current object's metadata with cache. + /// Get current object's metadata **without cache** directly. /// /// # Notes /// - /// This function will try access the local metadata cache first. - /// If there are outside changes of the object, `metadata` could return - /// out-of-date metadata. To overcome this, please use [`Object::stat`]. + /// Use `stat` if you: + /// + /// - Want detect the outside changes of object. + /// - Don't want to read from cached object metadata. + /// - No repeated stat call will be sent to the same object. + /// + /// You may want to use `metadata`, if you: + /// + /// - Are working with objects returned by [`ObjectLister`]. It's highly possible that metadata you want has already been cached. + /// - Are working with the same object instance. /// /// # Examples /// @@ -1239,9 +1195,8 @@ impl Object { /// # use opendal::Operator; /// use opendal::ErrorKind; /// # - /// # #[tokio::main] - /// # async fn test(op: Operator) -> Result<()> { - /// if let Err(e) = op.object("test").metadata().await { + /// # fn test(op: Operator) -> Result<()> { + /// if let Err(e) = op.object("test").blocking_stat() { /// if e.kind() == ErrorKind::ObjectNotFound { /// println!("object not exist") /// } @@ -1249,131 +1204,139 @@ impl Object { /// # Ok(()) /// # } /// ``` - pub async fn metadata(&self) -> Result { - let guard = self.metadata_ref().await?; + pub fn blocking_stat(&self) -> Result { + let rp = self.acc.blocking_stat(self.path(), OpStat::new())?; + let meta = rp.into_metadata(); - Ok(guard.clone()) + Ok(meta) } - /// The size of `Entry`'s corresponding object + /// Get current object's metadata with cache. /// - /// `content_length` is a prefetched metadata field in `Entry`. - pub async fn content_length(&self) -> Result { - { - let guard = self.meta.lock(); - if let Some(v) = guard.content_length_raw() { - return Ok(v); - } - if guard.is_complete() { - return Ok(0); - } - } - - let guard = self.metadata_ref().await?; - Ok(guard.content_length()) - } - - /// The MD5 message digest of `Entry`'s corresponding object + /// `metadata` will check the given query with already cached metadata + /// first. And query from storage if not found. /// - /// `content_md5` is a prefetched metadata field in `Entry` + /// # Notes /// - /// It doesn't mean this metadata field of object doesn't exist if `content_md5` is `None`. - /// Then you have to call `output::Entry::metadata()` to get the metadata you want. - pub async fn content_md5(&self) -> Result> { - { - let guard = self.meta.lock(); - - if let Some(v) = guard.content_md5() { - return Ok(Some(v.to_string())); - } - if guard.is_complete() { - return Ok(None); - } - } - - let guard = self.metadata_ref().await?; - Ok(guard.content_md5().map(|v| v.to_string())) - } - - /// The last modified UTC datetime of `Entry`'s corresponding object + /// Use `metadata` if you: /// - /// `last_modified` is a prefetched metadata field in `Entry` + /// - Are working with objects returned by [`ObjectLister`]. It's highly possible that metadata you want has already been cached. + /// - Are working with the same object instance. /// - /// It doesn't mean this metadata field of object doesn't exist if `last_modified` is `None`. - /// Then you have to call `output::Entry::metadata()` to get the metadata you want. - pub async fn last_modified(&self) -> Result> { - { - let guard = self.meta.lock(); - - if let Some(v) = guard.last_modified() { - return Ok(Some(v)); - } - if guard.is_complete() { - return Ok(None); - } - } - - let guard = self.metadata_ref().await?; - Ok(guard.last_modified()) - } - - /// The ETag string of `Entry`'s corresponding object + /// You may want to use `stat`, if you: /// - /// `etag` is a prefetched metadata field in `Entry`. + /// - Want detect the outside changes of object. + /// - Don't want to read from cached object metadata. + /// - No repeated stat call will be sent to the same object. /// - /// It doesn't mean this metadata field of object doesn't exist if `etag` is `None`. - /// Then you have to call `output::Entry::metadata()` to get the metadata you want. - pub async fn etag(&self) -> Result> { - { - let guard = self.meta.lock(); - - if let Some(v) = guard.etag() { - return Ok(Some(v.to_string())); + /// # Behavior + /// + /// `metadata` only make sure that the quired metadata is fetched. Not + /// fetched metadata key could be `None`, it doesn't means it's really + /// empty. Please make sure input metadata key is correct. + /// + /// # Examples + /// + /// ``` + /// # use anyhow::Result; + /// # use futures::io; + /// # use opendal::Operator; + /// use opendal::ErrorKind; + /// # + /// # #[tokio::main] + /// # async fn test(op: Operator) -> Result<()> { + /// let meta = op + /// .object("test") + /// .metadata({ + /// use opendal::ObjectMetadataKey::*; + /// ContentLength | ContentType + /// }) + /// .await?; + /// let _ = meta.content_length(); + /// let _ = meta.content_type(); + /// # Ok(()) + /// # } + /// ``` + pub async fn metadata( + &mut self, + flags: impl Into>, + ) -> Result> { + if let Some(meta) = &self.meta { + if meta.is_complete() { + return Ok(meta.clone()); } - if guard.is_complete() { - return Ok(None); + if meta.bit().contains(flags) { + return Ok(meta.clone()); } } - let meta = self.metadata().await?; - Ok(meta.etag().map(|v| v.to_string())) + let meta = Arc::new(self.stat().await?); + self.meta = Some(meta.clone()); + + Ok(meta) } - /// Get current object's metadata. + /// Get current object's metadata with cache in blocking way. + /// + /// `metadata` will check the given query with already cached metadata + /// first. And query from storage if not found. + /// + /// # Notes + /// + /// Use `metadata` if you: + /// + /// - Are working with objects returned by [`ObjectLister`]. It's highly possible that metadata you want has already been cached. + /// - Are working with the same object instance. + /// + /// You may want to use `stat`, if you: + /// + /// - Want detect the outside changes of object. + /// - Don't want to read from cached object metadata. + /// - No repeated stat call will be sent to the same object. + /// + /// # Behavior + /// + /// `metadata` only make sure that the quired metadata is fetched. Not + /// fetched metadata key could be `None`, it doesn't means it's really + /// empty. Please make sure input metadata key is correct. /// /// # Examples /// - /// ```no_run + /// ``` /// # use anyhow::Result; /// # use futures::io; /// # use opendal::Operator; /// use opendal::ErrorKind; /// # + /// # #[tokio::main] /// # async fn test(op: Operator) -> Result<()> { - /// if let Err(e) = op.object("test").blocking_metadata() { - /// if e.kind() == ErrorKind::ObjectNotFound { - /// println!("object not exist") - /// } - /// } + /// let meta = op + /// .object("test") + /// .metadata({ + /// use opendal::ObjectMetadataKey::*; + /// ContentLength | ContentType + /// }) + /// .await?; + /// let _ = meta.content_length(); + /// let _ = meta.content_type(); /// # Ok(()) /// # } /// ``` - pub fn blocking_metadata(&self) -> Result { - // Make sure the mutex guard has been dropped. - { - let guard = self.meta.lock(); - if guard.is_complete() { - return Ok(guard.clone()); + pub fn blocking_metadata( + &mut self, + flags: impl Into>, + ) -> Result> { + if let Some(meta) = &self.meta { + if meta.is_complete() { + return Ok(meta.clone()); + } + if meta.bit().contains(flags) { + return Ok(meta.clone()); } } - let rp = self.acc.blocking_stat(self.path(), OpStat::new())?; - let meta = rp.into_metadata(); - - { - let mut guard = self.meta.lock(); - *guard = meta.clone(); - } + let meta = Arc::new(self.blocking_stat()?); + self.meta = Some(meta.clone()); Ok(meta) } @@ -1394,8 +1357,8 @@ impl Object { /// Ok(()) /// } /// ``` - pub async fn is_exist(&self) -> Result { - let r = self.metadata_ref().await; + pub async fn is_exist(&mut self) -> Result { + let r = self.stat().await; match r { Ok(_) => Ok(true), Err(err) => match err.kind() { @@ -1418,8 +1381,8 @@ impl Object { /// Ok(()) /// } /// ``` - pub fn blocking_is_exist(&self) -> Result { - let r = self.blocking_metadata(); + pub fn blocking_is_exist(&mut self) -> Result { + let r = self.blocking_stat(); match r { Ok(_) => Ok(true), Err(err) => match err.kind() { @@ -1428,6 +1391,7 @@ impl Object { }, } } + /// Presign an operation for stat(head). /// /// # Example diff --git a/src/object/reader.rs b/src/object/reader.rs index 7a64e1db9798..d1d3e7daa343 100644 --- a/src/object/reader.rs +++ b/src/object/reader.rs @@ -240,7 +240,7 @@ mod tests { let op = Operator::create(services::Memory::default()) .unwrap() .finish(); - let obj = op.object("test_file"); + let mut obj = op.object("test_file"); let content = gen_random_bytes(); obj.write(&*content) @@ -262,7 +262,7 @@ mod tests { let op = Operator::create(services::Memory::default()) .unwrap() .finish(); - let obj = op.object("test_file"); + let mut obj = op.object("test_file"); let content = gen_random_bytes(); obj.write(&*content) diff --git a/src/operator.rs b/src/operator.rs index d33f26bbc308..3584a004db12 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -504,14 +504,14 @@ impl BatchOperator { /// # } /// ``` pub async fn remove_all(&self, path: &str) -> Result<()> { - let parent = self.src.object(path); - let meta = parent.metadata().await?; + let mut parent = self.src.object(path); + let meta = parent.stat().await?; if meta.mode() != ObjectMode::DIR { return parent.delete().await; } - let obs = self.src.object(path).scan().await?; + let obs = parent.scan().await?; if self.meta.can_batch() { let mut obs = obs.try_chunks(self.limit); @@ -537,7 +537,7 @@ impl BatchOperator { } } } else { - obs.try_for_each(|v| async move { v.delete().await }) + obs.try_for_each(|mut v| async move { v.delete().await }) .await?; } diff --git a/src/raw/io/output/entry.rs b/src/raw/io/output/entry.rs index fe98e0ea5519..3dff4956b2ad 100644 --- a/src/raw/io/output/entry.rs +++ b/src/raw/io/output/entry.rs @@ -71,6 +71,6 @@ impl Entry { /// Consume to convert into an object. pub fn into_object(self, op: Operator) -> Object { - Object::with(op, &self.path, self.meta) + Object::with(op, &self.path, Some(self.meta)) } } diff --git a/src/raw/rps.rs b/src/raw/rps.rs index 8114873868c3..f6d61a5b4fe0 100644 --- a/src/raw/rps.rs +++ b/src/raw/rps.rs @@ -261,6 +261,12 @@ impl RpStat { RpStat { meta } } + /// Operate on inner metadata. + pub fn map_metadata(mut self, f: impl FnOnce(ObjectMetadata) -> ObjectMetadata) -> Self { + self.meta = f(self.meta); + self + } + /// Consume RpStat to get the inner metadata. pub fn into_metadata(self) -> ObjectMetadata { self.meta diff --git a/src/services/azblob/dir_stream.rs b/src/services/azblob/dir_stream.rs index 9cef731298a6..65c0c49fdc90 100644 --- a/src/services/azblob/dir_stream.rs +++ b/src/services/azblob/dir_stream.rs @@ -93,7 +93,7 @@ impl output::Page for DirStream { for prefix in prefixes { let de = output::Entry::new( &build_rel_path(&self.root, &prefix.name), - ObjectMetadata::new(ObjectMode::DIR).with_complete(), + ObjectMetadata::new(ObjectMode::DIR), ); entries.push(de) @@ -109,10 +109,10 @@ impl output::Page for DirStream { let meta = ObjectMetadata::new(ObjectMode::FILE) // Keep fit with ETag header. - .with_etag(&format!("\"{}\"", object.properties.etag.as_str())) + .with_etag(format!("\"{}\"", object.properties.etag.as_str())) .with_content_length(object.properties.content_length) - .with_content_md5(object.properties.content_md5.as_str()) - .with_content_type(&object.properties.content_type) + .with_content_md5(object.properties.content_md5) + .with_content_type(object.properties.content_type) .with_last_modified( OffsetDateTime::parse(object.properties.last_modified.as_str(), &Rfc2822) .map_err(|e| { @@ -122,8 +122,7 @@ impl output::Page for DirStream { ) .set_source(e) })?, - ) - .with_complete(); + ); let de = output::Entry::new(&build_rel_path(&self.root, &object.name), meta); diff --git a/src/services/azdfs/dir_stream.rs b/src/services/azdfs/dir_stream.rs index 11539646573f..9d2719d863d7 100644 --- a/src/services/azdfs/dir_stream.rs +++ b/src/services/azdfs/dir_stream.rs @@ -104,7 +104,7 @@ impl output::Page for DirStream { let meta = ObjectMetadata::new(mode) // Keep fit with ETag header. - .with_etag(&format!("\"{}\"", &object.etag)) + .with_etag(format!("\"{}\"", &object.etag)) .with_content_length(object.content_length.parse().map_err(|err| { Error::new(ErrorKind::Unexpected, "content length is not valid integer") .set_source(err) @@ -117,8 +117,7 @@ impl output::Page for DirStream { ) .set_source(e) })?, - ) - .with_complete(); + ); let mut path = build_rel_path(&self.root, &object.name); if mode == ObjectMode::DIR { diff --git a/src/services/fs/dir_stream.rs b/src/services/fs/dir_stream.rs index 8d54acb54e0f..9ea4b411e9cd 100644 --- a/src/services/fs/dir_stream.rs +++ b/src/services/fs/dir_stream.rs @@ -72,7 +72,7 @@ impl output::Page for DirPager { // Make sure we are returning the correct path. output::Entry::new( &format!("{rel_path}/"), - ObjectMetadata::new(ObjectMode::DIR).with_complete(), + ObjectMetadata::new(ObjectMode::DIR), ) } else { output::Entry::new(&rel_path, ObjectMetadata::new(ObjectMode::Unknown)) @@ -133,7 +133,7 @@ impl output::BlockingPage for BlockingDirPager { // Make sure we are returning the correct path. output::Entry::new( &format!("{rel_path}/"), - ObjectMetadata::new(ObjectMode::DIR).with_complete(), + ObjectMetadata::new(ObjectMode::DIR), ) } else { output::Entry::new(&rel_path, ObjectMetadata::new(ObjectMode::Unknown)) diff --git a/src/services/ftp/dir_stream.rs b/src/services/ftp/dir_stream.rs index 4f132ef78567..bab4d3eb3e3c 100644 --- a/src/services/ftp/dir_stream.rs +++ b/src/services/ftp/dir_stream.rs @@ -86,19 +86,12 @@ impl output::Page for DirStream { &path, ObjectMetadata::new(ObjectMode::FILE) .with_content_length(de.size() as u64) - .with_last_modified(OffsetDateTime::from(de.modified())) - .with_complete(), + .with_last_modified(OffsetDateTime::from(de.modified())), ) } else if de.is_directory() { - output::Entry::new( - &format!("{}/", &path), - ObjectMetadata::new(ObjectMode::DIR).with_complete(), - ) + output::Entry::new(&format!("{}/", &path), ObjectMetadata::new(ObjectMode::DIR)) } else { - output::Entry::new( - &path, - ObjectMetadata::new(ObjectMode::Unknown).with_complete(), - ) + output::Entry::new(&path, ObjectMetadata::new(ObjectMode::Unknown)) }; oes.push(d) diff --git a/src/services/gcs/dir_stream.rs b/src/services/gcs/dir_stream.rs index 18c8e6c5246e..8e09692542e5 100644 --- a/src/services/gcs/dir_stream.rs +++ b/src/services/gcs/dir_stream.rs @@ -91,7 +91,7 @@ impl output::Page for DirStream { for prefix in output.prefixes { let de = output::Entry::new( &build_rel_path(&self.root, &prefix), - ObjectMetadata::new(ObjectMode::DIR).with_complete(), + ObjectMetadata::new(ObjectMode::DIR), ); entries.push(de); @@ -120,7 +120,6 @@ impl output::Page for DirStream { Error::new(ErrorKind::Unexpected, "parse last modified as rfc3339").set_source(e) })?; meta.set_last_modified(dt); - meta.set_complete(); let de = output::Entry::new(&build_rel_path(&self.root, &object.name), meta); diff --git a/src/services/hdfs/dir_stream.rs b/src/services/hdfs/dir_stream.rs index d2c5cc16a13a..f34093522dd5 100644 --- a/src/services/hdfs/dir_stream.rs +++ b/src/services/hdfs/dir_stream.rs @@ -57,10 +57,7 @@ impl output::Page for DirStream { output::Entry::new(&path, meta) } else if de.is_dir() { // Make sure we are returning the correct path. - output::Entry::new( - &format!("{path}/"), - ObjectMetadata::new(ObjectMode::DIR).with_complete(), - ) + output::Entry::new(&format!("{path}/"), ObjectMetadata::new(ObjectMode::DIR)) } else { output::Entry::new(&path, ObjectMetadata::new(ObjectMode::Unknown)) }; @@ -91,10 +88,7 @@ impl output::BlockingPage for DirStream { output::Entry::new(&path, meta) } else if de.is_dir() { // Make sure we are returning the correct path. - output::Entry::new( - &format!("{path}/"), - ObjectMetadata::new(ObjectMode::DIR).with_complete(), - ) + output::Entry::new(&format!("{path}/"), ObjectMetadata::new(ObjectMode::DIR)) } else { output::Entry::new(&path, ObjectMetadata::new(ObjectMode::Unknown)) }; diff --git a/src/services/http/backend.rs b/src/services/http/backend.rs index 953c67983be6..41d835532bfe 100644 --- a/src/services/http/backend.rs +++ b/src/services/http/backend.rs @@ -456,7 +456,8 @@ mod tests { builder.root("/"); let op = Operator::create(builder)?.finish(); - let bs = op.object("hello").metadata().await?; + let o = op.object("hello"); + let bs = o.stat().await?; assert_eq!(bs.mode(), ObjectMode::FILE); assert_eq!(bs.content_length(), 128); diff --git a/src/services/ipfs/backend.rs b/src/services/ipfs/backend.rs index a5bda09e25a4..75fd6298b095 100644 --- a/src/services/ipfs/backend.rs +++ b/src/services/ipfs/backend.rs @@ -503,7 +503,7 @@ impl output::Page for DirStream { name += "/"; } - oes.push(output::Entry::new(&name, meta.with_complete())) + oes.push(output::Entry::new(&name, meta)) } self.consumed = true; diff --git a/src/services/ipmfs/dir_stream.rs b/src/services/ipmfs/dir_stream.rs index 909f9d0671be..d4ff56b048f6 100644 --- a/src/services/ipmfs/dir_stream.rs +++ b/src/services/ipmfs/dir_stream.rs @@ -83,9 +83,7 @@ impl output::Page for DirStream { output::Entry::new( &path, - ObjectMetadata::new(object.mode()) - .with_content_length(object.size) - .with_complete(), + ObjectMetadata::new(object.mode()).with_content_length(object.size), ) }) .collect(), diff --git a/src/services/obs/dir_stream.rs b/src/services/obs/dir_stream.rs index 7488a273865f..4ab7e185c215 100644 --- a/src/services/obs/dir_stream.rs +++ b/src/services/obs/dir_stream.rs @@ -96,7 +96,7 @@ impl output::Page for DirStream { for prefix in common_prefixes { let de = output::Entry::new( &build_rel_path(&self.root, &prefix.prefix), - ObjectMetadata::new(ObjectMode::DIR).with_complete(), + ObjectMetadata::new(ObjectMode::DIR), ); entries.push(de); diff --git a/src/services/oss/dir_stream.rs b/src/services/oss/dir_stream.rs index 4d809fa27fb8..06895cc3548a 100644 --- a/src/services/oss/dir_stream.rs +++ b/src/services/oss/dir_stream.rs @@ -98,7 +98,7 @@ impl output::Page for DirStream { for prefix in output.common_prefixes { let de = output::Entry::new( &build_rel_path(&self.root, &prefix.prefix), - ObjectMetadata::new(ObjectMode::DIR).with_complete(), + ObjectMetadata::new(ObjectMode::DIR), ); entries.push(de); } @@ -107,7 +107,7 @@ impl output::Page for DirStream { if object.key.ends_with('/') { continue; } - let mut meta = ObjectMetadata::new(ObjectMode::FILE).with_complete(); + let mut meta = ObjectMetadata::new(ObjectMode::FILE); meta.set_etag(&object.etag); meta.set_content_length(object.size); diff --git a/src/services/s3/dir_stream.rs b/src/services/s3/dir_stream.rs index c0216bbe0507..e40c3389d0ca 100644 --- a/src/services/s3/dir_stream.rs +++ b/src/services/s3/dir_stream.rs @@ -101,7 +101,7 @@ impl output::Page for DirStream { for prefix in output.common_prefixes { let de = output::Entry::new( &build_rel_path(&self.root, &prefix.prefix), - ObjectMetadata::new(ObjectMode::DIR).with_complete(), + ObjectMetadata::new(ObjectMode::DIR), ); entries.push(de); @@ -115,7 +115,7 @@ impl output::Page for DirStream { continue; } - let mut meta = ObjectMetadata::new(ObjectMode::FILE).with_complete(); + let mut meta = ObjectMetadata::new(ObjectMode::FILE); meta.set_etag(&object.etag); meta.set_content_md5(object.etag.trim_matches('"')); diff --git a/src/services/webdav/dir_stream.rs b/src/services/webdav/dir_stream.rs index 735bdb7bfae1..f3bec49c5a09 100644 --- a/src/services/webdav/dir_stream.rs +++ b/src/services/webdav/dir_stream.rs @@ -65,10 +65,7 @@ impl output::Page for DirStream { let entry = if de.propstat.prop.resourcetype.value == Some(super::list_response::ResourceType::Collection) { - output::Entry::new( - &normalized_path, - ObjectMetadata::new(ObjectMode::DIR).with_complete(), - ) + output::Entry::new(&normalized_path, ObjectMetadata::new(ObjectMode::DIR)) } else { output::Entry::new(&normalized_path, ObjectMetadata::new(ObjectMode::FILE)) }; diff --git a/tests/behavior/blocking_list.rs b/tests/behavior/blocking_list.rs index 61a7084adca5..c3a88930b406 100644 --- a/tests/behavior/blocking_list.rs +++ b/tests/behavior/blocking_list.rs @@ -88,7 +88,7 @@ pub fn test_list_dir(op: Operator) -> Result<()> { let mut found = false; for de in obs { let de = de?; - let meta = de.blocking_metadata()?; + let meta = de.blocking_stat()?; if de.path() == path { assert_eq!(meta.mode(), ObjectMode::FILE); assert_eq!(meta.content_length(), size as u64); diff --git a/tests/behavior/blocking_read.rs b/tests/behavior/blocking_read.rs index 0a0d61350cd1..ed1d7b19d4c9 100644 --- a/tests/behavior/blocking_read.rs +++ b/tests/behavior/blocking_read.rs @@ -75,11 +75,11 @@ macro_rules! behavior_blocking_read_tests { /// Stat normal file and dir should return metadata pub fn test_stat(op: Operator) -> Result<()> { - let meta = op.object("normal_file").blocking_metadata()?; + let meta = op.object("normal_file").blocking_stat()?; assert_eq!(meta.mode(), ObjectMode::FILE); assert_eq!(meta.content_length(), 262144); - let meta = op.object("normal_dir/").blocking_metadata()?; + let meta = op.object("normal_dir/").blocking_stat()?; assert_eq!(meta.mode(), ObjectMode::DIR); Ok(()) @@ -89,13 +89,13 @@ pub fn test_stat(op: Operator) -> Result<()> { pub fn test_stat_special_chars(op: Operator) -> Result<()> { let meta = op .object("special_file !@#$%^&()_+-=;',") - .blocking_metadata()?; + .blocking_stat()?; assert_eq!(meta.mode(), ObjectMode::FILE); assert_eq!(meta.content_length(), 262144); let meta = op .object("special_dir !@#$%^&()_+-=;',/") - .blocking_metadata()?; + .blocking_stat()?; assert_eq!(meta.mode(), ObjectMode::DIR); Ok(()) @@ -105,7 +105,7 @@ pub fn test_stat_special_chars(op: Operator) -> Result<()> { pub fn test_stat_not_exist(op: Operator) -> Result<()> { let path = uuid::Uuid::new_v4().to_string(); - let meta = op.object(&path).blocking_metadata(); + let meta = op.object(&path).blocking_stat(); assert!(meta.is_err()); assert_eq!(meta.unwrap_err().kind(), ErrorKind::ObjectNotFound); diff --git a/tests/behavior/blocking_write.rs b/tests/behavior/blocking_write.rs index 91e875a69abe..f28b7c8701e3 100644 --- a/tests/behavior/blocking_write.rs +++ b/tests/behavior/blocking_write.rs @@ -97,11 +97,11 @@ macro_rules! behavior_blocking_write_tests { pub fn test_create_file(op: Operator) -> Result<()> { let path = uuid::Uuid::new_v4().to_string(); - let o = op.object(&path); + let mut o = op.object(&path); o.blocking_create()?; - let meta = o.blocking_metadata()?; + let meta = o.blocking_stat()?; assert_eq!(meta.mode(), ObjectMode::FILE); assert_eq!(meta.content_length(), 0); @@ -115,13 +115,13 @@ pub fn test_create_file(op: Operator) -> Result<()> { pub fn test_create_file_existing(op: Operator) -> Result<()> { let path = uuid::Uuid::new_v4().to_string(); - let o = op.object(&path); + let mut o = op.object(&path); o.blocking_create()?; o.blocking_create()?; - let meta = o.blocking_metadata()?; + let meta = o.blocking_stat()?; assert_eq!(meta.mode(), ObjectMode::FILE); assert_eq!(meta.content_length(), 0); @@ -135,12 +135,12 @@ pub fn test_create_file_existing(op: Operator) -> Result<()> { pub fn test_create_file_with_special_chars(op: Operator) -> Result<()> { let path = format!("{} !@#$%^&()_+-=;',.txt", uuid::Uuid::new_v4()); - let o = op.object(&path); + let mut o = op.object(&path); debug!("{o:?}"); o.blocking_create()?; - let meta = o.blocking_metadata()?; + let meta = o.blocking_stat()?; assert_eq!(meta.mode(), ObjectMode::FILE); assert_eq!(meta.content_length(), 0); @@ -154,11 +154,11 @@ pub fn test_create_file_with_special_chars(op: Operator) -> Result<()> { pub fn test_create_dir(op: Operator) -> Result<()> { let path = format!("{}/", uuid::Uuid::new_v4()); - let o = op.object(&path); + let mut o = op.object(&path); o.blocking_create()?; - let meta = o.blocking_metadata()?; + let meta = o.blocking_stat()?; assert_eq!(meta.mode(), ObjectMode::DIR); op.object(&path) @@ -171,13 +171,13 @@ pub fn test_create_dir(op: Operator) -> Result<()> { pub fn test_create_dir_existing(op: Operator) -> Result<()> { let path = format!("{}/", uuid::Uuid::new_v4()); - let o = op.object(&path); + let mut o = op.object(&path); o.blocking_create()?; o.blocking_create()?; - let meta = o.blocking_metadata()?; + let meta = o.blocking_stat()?; assert_eq!(meta.mode(), ObjectMode::DIR); op.object(&path) @@ -194,10 +194,7 @@ pub fn test_write(op: Operator) -> Result<()> { op.object(&path).blocking_write(content)?; - let meta = op - .object(&path) - .blocking_metadata() - .expect("stat must succeed"); + let meta = op.object(&path).blocking_stat().expect("stat must succeed"); assert_eq!(meta.content_length(), size as u64); op.object(&path) @@ -226,10 +223,7 @@ pub fn test_write_with_special_chars(op: Operator) -> Result<()> { op.object(&path).blocking_write(content)?; - let meta = op - .object(&path) - .blocking_metadata() - .expect("stat must succeed"); + let meta = op.object(&path).blocking_stat().expect("stat must succeed"); assert_eq!(meta.content_length(), size as u64); op.object(&path) @@ -248,7 +242,7 @@ pub fn test_stat(op: Operator) -> Result<()> { .blocking_write(content) .expect("write must succeed"); - let meta = op.object(&path).blocking_metadata()?; + let meta = op.object(&path).blocking_stat()?; assert_eq!(meta.mode(), ObjectMode::FILE); assert_eq!(meta.content_length(), size as u64); @@ -266,7 +260,7 @@ pub fn test_stat_dir(op: Operator) -> Result<()> { .blocking_create() .expect("write must succeed"); - let meta = op.object(&path).blocking_metadata()?; + let meta = op.object(&path).blocking_stat()?; assert_eq!(meta.mode(), ObjectMode::DIR); op.object(&path) @@ -285,7 +279,7 @@ pub fn test_stat_with_special_chars(op: Operator) -> Result<()> { .blocking_write(content) .expect("write must succeed"); - let meta = op.object(&path).blocking_metadata()?; + let meta = op.object(&path).blocking_stat()?; assert_eq!(meta.mode(), ObjectMode::FILE); assert_eq!(meta.content_length(), size as u64); @@ -299,7 +293,7 @@ pub fn test_stat_with_special_chars(op: Operator) -> Result<()> { pub fn test_stat_not_exist(op: Operator) -> Result<()> { let path = uuid::Uuid::new_v4().to_string(); - let meta = op.object(&path).blocking_metadata(); + let meta = op.object(&path).blocking_stat(); assert!(meta.is_err()); assert_eq!(meta.unwrap_err().kind(), ErrorKind::ObjectNotFound); diff --git a/tests/behavior/list.rs b/tests/behavior/list.rs index b2c13bcb4354..c8c4147d9cf1 100644 --- a/tests/behavior/list.rs +++ b/tests/behavior/list.rs @@ -73,7 +73,6 @@ macro_rules! behavior_list_tests { test_check, test_list_dir, test_list_rich_dir, - test_list_dir_metadata_cache, test_list_empty_dir, test_list_non_exist_dir, test_list_sub_dir, @@ -107,7 +106,7 @@ pub async fn test_list_dir(op: Operator) -> Result<()> { let mut obs = op.object("/").list().await?; let mut found = false; while let Some(de) = obs.try_next().await? { - let meta = de.metadata().await?; + let meta = de.stat().await?; if de.path() == path { assert_eq!(meta.mode(), ObjectMode::FILE); assert_eq!(meta.content_length(), size as u64); @@ -135,7 +134,7 @@ pub async fn test_list_rich_dir(op: Operator) -> Result<()> { expected .iter() .map(|v| async { - let o = op.object(v); + let mut o = op.object(v); o.create().await.expect("create must succeed"); }) // Collect into a FuturesUnordered. @@ -159,31 +158,6 @@ pub async fn test_list_rich_dir(op: Operator) -> Result<()> { Ok(()) } -/// List dir should return newly created file with correct metadata. -pub async fn test_list_dir_metadata_cache(op: Operator) -> Result<()> { - let path = uuid::Uuid::new_v4().to_string(); - debug!("Generate a random file: {}", &path); - let (content, _) = gen_bytes(); - - op.object(&path) - .write(content) - .await - .expect("write must succeed"); - - let mut obs = op.object("/").list().await?; - while let Some(de) = obs.try_next().await? { - let meta_from_raw = de.stat().await?; - let meta_from_cache = de.metadata().await?; - assert_eq!(meta_from_raw, meta_from_cache) - } - - op.object(&path) - .delete() - .await - .expect("delete must succeed"); - Ok(()) -} - /// List empty dir should return nothing. pub async fn test_list_empty_dir(op: Operator) -> Result<()> { let dir = format!("{}/", uuid::Uuid::new_v4()); @@ -228,7 +202,7 @@ pub async fn test_list_sub_dir(op: Operator) -> Result<()> { let mut found = false; while let Some(de) = obs.try_next().await? { if de.path() == path { - assert_eq!(de.mode().await?, ObjectMode::DIR); + assert_eq!(de.stat().await?.mode(), ObjectMode::DIR); assert_eq!(de.name(), path); found = true @@ -276,7 +250,7 @@ pub async fn test_list_nested_dir(op: Operator) -> Result<()> { let meta = objects .get(&file_path) .expect("file should be found in list") - .metadata() + .stat() .await?; assert_eq!(meta.mode(), ObjectMode::FILE); assert_eq!(meta.content_length(), 0); @@ -285,7 +259,7 @@ pub async fn test_list_nested_dir(op: Operator) -> Result<()> { let meta = objects .get(&dir_path) .expect("file should be found in list") - .metadata() + .stat() .await?; assert_eq!(meta.mode(), ObjectMode::DIR); diff --git a/tests/behavior/list_only.rs b/tests/behavior/list_only.rs index 1a3babe00975..96d3bdb1e383 100644 --- a/tests/behavior/list_only.rs +++ b/tests/behavior/list_only.rs @@ -71,7 +71,7 @@ pub async fn test_list(op: Operator) -> Result<()> { let mut ds = op.object("/").list().await?; while let Some(de) = ds.try_next().await? { - entries.insert(de.path().to_string(), de.metadata().await?.mode()); + entries.insert(de.path().to_string(), de.stat().await?.mode()); } assert_eq!(entries["normal_file"], ObjectMode::FILE); diff --git a/tests/behavior/multipart.rs b/tests/behavior/multipart.rs index 3ded57608c8e..30eded18c480 100644 --- a/tests/behavior/multipart.rs +++ b/tests/behavior/multipart.rs @@ -85,7 +85,7 @@ pub async fn test_multipart_complete(op: Operator) -> Result<()> { // Complete let o = mp.complete(vec![p1, p2]).await?; - let meta = o.metadata().await?; + let meta = o.stat().await?; assert_eq!(10 * 1024 * 1024, meta.content_length(), "complete size"); assert_eq!( diff --git a/tests/behavior/multipart_presign.rs b/tests/behavior/multipart_presign.rs index 7f52b3057fc2..505ee4e95138 100644 --- a/tests/behavior/multipart_presign.rs +++ b/tests/behavior/multipart_presign.rs @@ -111,7 +111,7 @@ pub async fn test_presign_write_multipart(op: Operator) -> Result<()> { let o = mp.complete(vec![ObjectPart::new(1, etag)]).await?; - let meta = o.metadata().await.expect("stat must succeed"); + let meta = o.stat().await.expect("stat must succeed"); assert_eq!(meta.content_length(), size as u64); op.object(&path) diff --git a/tests/behavior/presign.rs b/tests/behavior/presign.rs index a1017b41a91b..781e86d30ed4 100644 --- a/tests/behavior/presign.rs +++ b/tests/behavior/presign.rs @@ -101,11 +101,7 @@ pub async fn test_presign_write(op: Operator) -> Result<()> { resp.text().await.expect("read response must succeed") ); - let meta = op - .object(&path) - .metadata() - .await - .expect("stat must succeed"); + let meta = op.object(&path).stat().await.expect("stat must succeed"); assert_eq!(meta.content_length(), size as u64); op.object(&path) diff --git a/tests/behavior/read_only.rs b/tests/behavior/read_only.rs index 7c5858a75867..d197c218b087 100644 --- a/tests/behavior/read_only.rs +++ b/tests/behavior/read_only.rs @@ -86,11 +86,11 @@ macro_rules! behavior_read_tests { /// Stat normal file and dir should return metadata pub async fn test_stat(op: Operator) -> Result<()> { - let meta = op.object("normal_file").metadata().await?; + let meta = op.object("normal_file").stat().await?; assert_eq!(meta.mode(), ObjectMode::FILE); assert_eq!(meta.content_length(), 262144); - let meta = op.object("normal_dir/").metadata().await?; + let meta = op.object("normal_dir/").stat().await?; assert_eq!(meta.mode(), ObjectMode::DIR); Ok(()) @@ -98,17 +98,11 @@ pub async fn test_stat(op: Operator) -> Result<()> { /// Stat special file and dir should return metadata pub async fn test_stat_special_chars(op: Operator) -> Result<()> { - let meta = op - .object("special_file !@#$%^&()_+-=;',") - .metadata() - .await?; + let meta = op.object("special_file !@#$%^&()_+-=;',").stat().await?; assert_eq!(meta.mode(), ObjectMode::FILE); assert_eq!(meta.content_length(), 262144); - let meta = op - .object("special_dir !@#$%^&()_+-=;',/") - .metadata() - .await?; + let meta = op.object("special_dir !@#$%^&()_+-=;',/").stat().await?; assert_eq!(meta.mode(), ObjectMode::DIR); Ok(()) @@ -116,7 +110,7 @@ pub async fn test_stat_special_chars(op: Operator) -> Result<()> { /// Stat not cleaned path should also succeed. pub async fn test_stat_not_cleaned_path(op: Operator) -> Result<()> { - let meta = op.object("//normal_file").metadata().await?; + let meta = op.object("//normal_file").stat().await?; assert_eq!(meta.mode(), ObjectMode::FILE); assert_eq!(meta.content_length(), 262144); @@ -127,7 +121,7 @@ pub async fn test_stat_not_cleaned_path(op: Operator) -> Result<()> { pub async fn test_stat_not_exist(op: Operator) -> Result<()> { let path = uuid::Uuid::new_v4().to_string(); - let meta = op.object(&path).metadata().await; + let meta = op.object(&path).stat().await; assert!(meta.is_err()); assert_eq!(meta.unwrap_err().kind(), ErrorKind::ObjectNotFound); @@ -136,10 +130,10 @@ pub async fn test_stat_not_exist(op: Operator) -> Result<()> { /// Root should be able to stat and returns DIR. pub async fn test_stat_root(op: Operator) -> Result<()> { - let meta = op.object("").metadata().await?; + let meta = op.object("").stat().await?; assert_eq!(meta.mode(), ObjectMode::DIR); - let meta = op.object("/").metadata().await?; + let meta = op.object("/").stat().await?; assert_eq!(meta.mode(), ObjectMode::DIR); Ok(()) diff --git a/tests/behavior/write.rs b/tests/behavior/write.rs index ce4821a968be..4df52ef324dd 100644 --- a/tests/behavior/write.rs +++ b/tests/behavior/write.rs @@ -110,11 +110,11 @@ macro_rules! behavior_write_tests { pub async fn test_create_file(op: Operator) -> Result<()> { let path = uuid::Uuid::new_v4().to_string(); - let o = op.object(&path); + let mut o = op.object(&path); o.create().await?; - let meta = o.metadata().await?; + let meta = o.stat().await?; assert_eq!(meta.mode(), ObjectMode::FILE); assert_eq!(meta.content_length(), 0); @@ -129,13 +129,13 @@ pub async fn test_create_file(op: Operator) -> Result<()> { pub async fn test_create_file_existing(op: Operator) -> Result<()> { let path = uuid::Uuid::new_v4().to_string(); - let o = op.object(&path); + let mut o = op.object(&path); o.create().await?; o.create().await?; - let meta = o.metadata().await?; + let meta = o.stat().await?; assert_eq!(meta.mode(), ObjectMode::FILE); assert_eq!(meta.content_length(), 0); @@ -150,11 +150,11 @@ pub async fn test_create_file_existing(op: Operator) -> Result<()> { pub async fn test_create_file_with_special_chars(op: Operator) -> Result<()> { let path = format!("{} !@#$%^&()_+-=;',.txt", uuid::Uuid::new_v4()); - let o = op.object(&path); + let mut o = op.object(&path); o.create().await?; - let meta = o.metadata().await?; + let meta = o.stat().await?; assert_eq!(meta.mode(), ObjectMode::FILE); assert_eq!(meta.content_length(), 0); @@ -169,11 +169,11 @@ pub async fn test_create_file_with_special_chars(op: Operator) -> Result<()> { pub async fn test_create_dir(op: Operator) -> Result<()> { let path = format!("{}/", uuid::Uuid::new_v4()); - let o = op.object(&path); + let mut o = op.object(&path); o.create().await?; - let meta = o.metadata().await?; + let meta = o.stat().await?; assert_eq!(meta.mode(), ObjectMode::DIR); op.object(&path) @@ -187,13 +187,13 @@ pub async fn test_create_dir(op: Operator) -> Result<()> { pub async fn test_create_dir_existing(op: Operator) -> Result<()> { let path = format!("{}/", uuid::Uuid::new_v4()); - let o = op.object(&path); + let mut o = op.object(&path); o.create().await?; o.create().await?; - let meta = o.metadata().await?; + let meta = o.stat().await?; assert_eq!(meta.mode(), ObjectMode::DIR); op.object(&path) @@ -210,11 +210,7 @@ pub async fn test_write(op: Operator) -> Result<()> { op.object(&path).write(content).await?; - let meta = op - .object(&path) - .metadata() - .await - .expect("stat must succeed"); + let meta = op.object(&path).stat().await.expect("stat must succeed"); assert_eq!(meta.content_length(), size as u64); op.object(&path) @@ -243,11 +239,7 @@ pub async fn test_write_with_special_chars(op: Operator) -> Result<()> { op.object(&path).write(content).await?; - let meta = op - .object(&path) - .metadata() - .await - .expect("stat must succeed"); + let meta = op.object(&path).stat().await.expect("stat must succeed"); assert_eq!(meta.content_length(), size as u64); op.object(&path) @@ -267,7 +259,7 @@ pub async fn test_stat(op: Operator) -> Result<()> { .await .expect("write must succeed"); - let meta = op.object(&path).metadata().await?; + let meta = op.object(&path).stat().await?; assert_eq!(meta.mode(), ObjectMode::FILE); assert_eq!(meta.content_length(), size as u64); @@ -284,7 +276,7 @@ pub async fn test_stat_dir(op: Operator) -> Result<()> { op.object(&path).create().await.expect("write must succeed"); - let meta = op.object(&path).metadata().await?; + let meta = op.object(&path).stat().await?; assert_eq!(meta.mode(), ObjectMode::DIR); op.object(&path) @@ -304,7 +296,7 @@ pub async fn test_stat_with_special_chars(op: Operator) -> Result<()> { .await .expect("write must succeed"); - let meta = op.object(&path).metadata().await?; + let meta = op.object(&path).stat().await?; assert_eq!(meta.mode(), ObjectMode::FILE); assert_eq!(meta.content_length(), size as u64); @@ -326,7 +318,7 @@ pub async fn test_stat_not_cleaned_path(op: Operator) -> Result<()> { .await .expect("write must succeed"); - let meta = op.object(&format!("//{}", &path)).metadata().await?; + let meta = op.object(&format!("//{}", &path)).stat().await?; assert_eq!(meta.mode(), ObjectMode::FILE); assert_eq!(meta.content_length(), size as u64); @@ -341,7 +333,7 @@ pub async fn test_stat_not_cleaned_path(op: Operator) -> Result<()> { pub async fn test_stat_not_exist(op: Operator) -> Result<()> { let path = uuid::Uuid::new_v4().to_string(); - let meta = op.object(&path).metadata().await; + let meta = op.object(&path).stat().await; assert!(meta.is_err()); assert_eq!(meta.unwrap_err().kind(), ErrorKind::ObjectNotFound); @@ -350,10 +342,10 @@ pub async fn test_stat_not_exist(op: Operator) -> Result<()> { /// Root should be able to stat and returns DIR. pub async fn test_stat_root(op: Operator) -> Result<()> { - let meta = op.object("").metadata().await?; + let meta = op.object("").stat().await?; assert_eq!(meta.mode(), ObjectMode::DIR); - let meta = op.object("/").metadata().await?; + let meta = op.object("/").stat().await?; assert_eq!(meta.mode(), ObjectMode::DIR); Ok(())