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 2023/09/13 03:03:04 UTC

[incubator-opendal] 01/03: Implement buffer cal

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

xuanwo pushed a commit to branch apply-buffer
in repository https://gitbox.apache.org/repos/asf/incubator-opendal.git

commit f07dfbca783717557cfd4d555b99b938b6c09e4c
Author: Xuanwo <gi...@xuanwo.io>
AuthorDate: Wed Sep 13 10:46:54 2023 +0800

    Implement buffer cal
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
---
 core/src/layers/complete.rs  | 48 ++++++++++++++++++++++++++++----------------
 core/src/types/capability.rs | 12 +++++++++++
 2 files changed, 43 insertions(+), 17 deletions(-)

diff --git a/core/src/layers/complete.rs b/core/src/layers/complete.rs
index 1abed7bbd..84b587efa 100644
--- a/core/src/layers/complete.rs
+++ b/core/src/layers/complete.rs
@@ -17,11 +17,11 @@
 
 use std::fmt::Debug;
 use std::fmt::Formatter;
-use std::io;
 use std::sync::Arc;
 use std::task::ready;
 use std::task::Context;
 use std::task::Poll;
+use std::{cmp, io};
 
 use async_trait::async_trait;
 use bytes::Bytes;
@@ -95,17 +95,6 @@ use crate::*;
 /// If there is a hint that `ReadStreamable`, we will use existing reader
 /// directly. Otherwise, we will use transform this reader as a stream.
 ///
-/// ### Consume instead of Drop
-///
-/// Normally, if reader is seekable, we need to drop current reader and start
-/// a new read call.
-///
-/// We can consume the data if the seek position is close enough. For
-/// example, users try to seek to `Current(1)`, we can just read the data
-/// can consume it.
-///
-/// In this way, we can reduce the extra cost of dropping reader.
-///
 /// ## List Completion
 ///
 /// There are two styles of list, but not all services support both of
@@ -366,7 +355,10 @@ impl<A: Accessor> LayeredAccessor for CompleteReaderAccessor<A> {
     type Inner = A;
     type Reader = CompleteReader<A, A::Reader>;
     type BlockingReader = CompleteReader<A, A::BlockingReader>;
-    type Writer = CompleteWriter<A::Writer>;
+    type Writer = oio::TwoWaysWriter<
+        CompleteWriter<A::Writer>,
+        oio::ExactBufWriter<CompleteWriter<A::Writer>>,
+    >;
     type BlockingWriter = CompleteWriter<A::BlockingWriter>;
     type Pager = CompletePager<A, A::Pager>;
     type BlockingPager = CompletePager<A, A::BlockingPager>;
@@ -433,10 +425,32 @@ impl<A: Accessor> LayeredAccessor for CompleteReaderAccessor<A> {
             ));
         }
 
-        self.inner
-            .write(path, args)
-            .await
-            .map(|(rp, w)| (rp, CompleteWriter::new(w)))
+        // Calculate buffer size.
+        let buffer_size = args.buffer().map(|mut size| {
+            if let Some(v) = capability.write_multi_max_size {
+                size = cmp::min(v, size);
+            }
+            if let Some(v) = capability.write_multi_min_size {
+                size = cmp::max(v, size);
+            }
+            if let Some(v) = capability.write_multi_align_size {
+                // Make sure size >= size first.
+                size = cmp::max(v, size);
+                size -= size % v;
+            }
+
+            size
+        });
+
+        let (rp, w) = self.inner.write(path, args.clone()).await?;
+        let w = CompleteWriter::new(w);
+
+        let w = match buffer_size {
+            None => oio::TwoWaysWriter::One(w),
+            Some(size) => oio::TwoWaysWriter::Two(oio::ExactBufWriter::new(w, size)),
+        };
+
+        Ok((rp, w))
     }
 
     fn blocking_write(&self, path: &str, args: OpWrite) -> Result<(RpWrite, Self::BlockingWriter)> {
diff --git a/core/src/types/capability.rs b/core/src/types/capability.rs
index b568b3ee8..abe7eb9c4 100644
--- a/core/src/types/capability.rs
+++ b/core/src/types/capability.rs
@@ -84,6 +84,18 @@ pub struct Capability {
     pub write_with_content_disposition: bool,
     /// If operator supports write with cache control.
     pub write_with_cache_control: bool,
+    /// write_multi_max_size is the max size that services support in write_multi.
+    ///
+    /// For example, AWS S3 supports 5GiB as max in write_multi.
+    pub write_multi_max_size: Option<usize>,
+    /// write_multi_min_size is the min size that services support in write_multi.
+    ///
+    /// For example, AWS S3 requires at least 5MiB in write_multi expect the last one.
+    pub write_multi_min_size: Option<usize>,
+    /// write_multi_align_size is the align size that services required in write_multi.
+    ///
+    /// For example, Google GCS requires align size to 256KiB in write_multi.
+    pub write_multi_align_size: Option<usize>,
 
     /// If operator supports create dir.
     pub create_dir: bool,