You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@opendal.apache.org by xu...@apache.org on 2026/05/22 14:47:55 UTC
(opendal) branch main updated: feat(copy): apply timeout to copy operations (#7594)
This is an automated email from the ASF dual-hosted git repository.
Xuanwo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/opendal.git
The following commit(s) were added to refs/heads/main by this push:
new dc200b3c2 feat(copy): apply timeout to copy operations (#7594)
dc200b3c2 is described below
commit dc200b3c25a637f1e105cd7642c321c8fca6fd4b
Author: dentiny <de...@gmail.com>
AuthorDate: Fri May 22 07:47:48 2026 -0700
feat(copy): apply timeout to copy operations (#7594)
* feat(copy): apply timeout to copy operations
* fmt
---
core/layers/timeout/src/lib.rs | 53 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 52 insertions(+), 1 deletion(-)
diff --git a/core/layers/timeout/src/lib.rs b/core/layers/timeout/src/lib.rs
index 9a24ae718..004c6d8c2 100644
--- a/core/layers/timeout/src/lib.rs
+++ b/core/layers/timeout/src/lib.rs
@@ -213,7 +213,7 @@ impl<A: Access> LayeredAccess for TimeoutAccessor<A> {
type Writer = TimeoutWrapper<A::Writer>;
type Lister = TimeoutWrapper<A::Lister>;
type Deleter = TimeoutWrapper<A::Deleter>;
- type Copier = A::Copier;
+ type Copier = TimeoutWrapper<A::Copier>;
fn inner(&self) -> &Self::Inner {
&self.inner
@@ -248,6 +248,7 @@ impl<A: Access> LayeredAccess for TimeoutAccessor<A> {
self.inner.copy(from, to, args, opts.clone()),
)
.await
+ .map(|(rp, c)| (rp, TimeoutWrapper::new(c, self.io_timeout)))
}
async fn rename(&self, from: &str, to: &str, args: OpRename) -> Result<RpRename> {
@@ -369,6 +370,18 @@ impl<R: oio::Delete> oio::Delete for TimeoutWrapper<R> {
}
}
+impl<C: oio::Copy> oio::Copy for TimeoutWrapper<C> {
+ async fn next(&mut self) -> Result<Option<usize>> {
+ let fut = self.inner.next();
+ Self::io_timeout(self.timeout, Operation::Copy.into_static(), fut).await
+ }
+
+ async fn abort(&mut self) -> Result<()> {
+ let fut = self.inner.abort();
+ Self::io_timeout(self.timeout, Operation::Copy.into_static(), fut).await
+ }
+}
+
#[cfg(test)]
mod tests {
use std::future::pending;
@@ -415,6 +428,16 @@ mod tests {
async fn list(&self, _: &str, _: OpList) -> Result<(RpList, Self::Lister)> {
Ok((RpList::default(), Box::new(MockLister)))
}
+
+ async fn copy(
+ &self,
+ _: &str,
+ _: &str,
+ _: OpCopy,
+ _: OpCopier,
+ ) -> Result<(RpCopy, Self::Copier)> {
+ Ok((RpCopy::default(), Box::new(MockCopier)))
+ }
}
#[derive(Debug, Clone, Default)]
@@ -448,6 +471,19 @@ mod tests {
}
}
+ #[derive(Debug, Clone, Default)]
+ struct MockCopier;
+
+ impl oio::Copy for MockCopier {
+ fn next(&mut self) -> impl Future<Output = Result<Option<usize>>> {
+ pending()
+ }
+
+ fn abort(&mut self) -> impl Future<Output = Result<()>> {
+ pending()
+ }
+ }
+
#[tokio::test]
async fn test_operation_timeout() {
let srv = MockService;
@@ -513,6 +549,21 @@ mod tests {
assert!(err.to_string().contains("timeout"));
}
+ #[tokio::test]
+ async fn test_copy_io_timeout() {
+ use oio::Copy;
+
+ let acc = TimeoutLayer::default()
+ .with_io_timeout(Duration::from_millis(100))
+ .layer(MockService);
+ let (_, mut copier) = Access::copy(&acc, "f", "t", OpCopy::default(), OpCopier::default())
+ .await
+ .unwrap();
+
+ let err = copier.next().await.unwrap_err();
+ assert!(err.to_string().contains("timeout"));
+ }
+
#[tokio::test]
async fn test_list_timeout_raw() {
use oio::List;