You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@opendal.apache.org by me...@apache.org on 2025/04/04 13:44:57 UTC

(opendal) 01/01: chore(core/types): implement pollo_write_vectored for FuturesAsyncWriter

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

meteorgan pushed a commit to branch pollo_write_vectored
in repository https://gitbox.apache.org/repos/asf/opendal.git

commit b765114037f91a812658177983eea5a45dcf107a
Author: meteorgan <me...@gmail.com>
AuthorDate: Fri Apr 4 21:43:03 2025 +0800

    chore(core/types): implement pollo_write_vectored for FuturesAsyncWriter
---
 core/src/types/write/futures_async_writer.rs | 95 +++++++++++++++++++++++++++-
 1 file changed, 93 insertions(+), 2 deletions(-)

diff --git a/core/src/types/write/futures_async_writer.rs b/core/src/types/write/futures_async_writer.rs
index 507a1761e..e3ead2114 100644
--- a/core/src/types/write/futures_async_writer.rs
+++ b/core/src/types/write/futures_async_writer.rs
@@ -72,6 +72,45 @@ impl AsyncWrite for FuturesAsyncWriter {
         }
     }
 
+    fn poll_write_vectored(
+        self: Pin<&mut Self>,
+        cx: &mut Context<'_>,
+        bufs: &[io::IoSlice<'_>],
+    ) -> Poll<io::Result<usize>> {
+        let this = self.get_mut();
+
+        if bufs.is_empty() {
+            return Poll::Ready(Ok(0));
+        }
+
+        loop {
+            let mut total_size = 0;
+            let mut all_empty = true;
+            for buf in bufs {
+                if buf.is_empty() {
+                    continue;
+                }
+                all_empty = false;
+                let n = this.buf.put(buf);
+                total_size += n;
+                if n < buf.len() {
+                    break;
+                }
+            }
+            if total_size > 0 || all_empty {
+                return Poll::Ready(Ok(total_size));
+            }
+
+            ready!(this.sink.poll_ready_unpin(cx)).map_err(format_std_io_error)?;
+
+            let bs = this.buf.get().expect("frozen buffer must be valid");
+            this.sink
+                .start_send_unpin(Buffer::from(bs))
+                .map_err(format_std_io_error)?;
+            this.buf.clean();
+        }
+    }
+
     fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
         let this = self.get_mut();
 
@@ -111,10 +150,10 @@ impl AsyncWrite for FuturesAsyncWriter {
 
 #[cfg(test)]
 mod tests {
-    use std::sync::Arc;
-
     use super::*;
     use crate::raw::MaybeSend;
+    use futures::AsyncWriteExt;
+    use std::sync::Arc;
 
     #[tokio::test]
     async fn test_trait() {
@@ -133,4 +172,56 @@ mod tests {
 
         let _: Box<dyn Unpin + MaybeSend + Sync + 'static> = Box::new(v);
     }
+
+    #[tokio::test]
+    async fn test_poll_write_vectored() {
+        let op = Operator::via_iter(Scheme::Memory, []).unwrap();
+
+        let acc = op.clone().into_inner();
+        let path = "test";
+        let ctx = Arc::new(WriteContext::new(
+            acc,
+            path.to_string(),
+            OpWrite::new(),
+            OpWriter::new().with_chunk(1),
+        ));
+        let write_gen = WriteGenerator::create(ctx).await.unwrap();
+
+        let mut v = FuturesAsyncWriter::new(write_gen);
+        let _ = v
+            .write_vectored(&[io::IoSlice::new(b"Hello"), io::IoSlice::new(b"World")])
+            .await
+            .unwrap();
+        v.flush().await.unwrap();
+        v.close().await.unwrap();
+
+        let data = op.read(path).await.unwrap();
+        assert_eq!(data.to_vec(), b"HelloWorld");
+    }
+
+    #[tokio::test]
+    async fn test_poll_write_vectored_with_concurrent() {
+        let op = Operator::via_iter(Scheme::Memory, []).unwrap();
+
+        let acc = op.clone().into_inner();
+        let path = "test";
+        let ctx = Arc::new(WriteContext::new(
+            acc,
+            path.to_string(),
+            OpWrite::new().with_concurrent(3),
+            OpWriter::new().with_chunk(2),
+        ));
+        let write_gen = WriteGenerator::create(ctx).await.unwrap();
+
+        let mut v = FuturesAsyncWriter::new(write_gen);
+        let _ = v
+            .write_vectored(&[io::IoSlice::new(b"Hello"), io::IoSlice::new(b"World")])
+            .await
+            .unwrap();
+        v.flush().await.unwrap();
+        v.close().await.unwrap();
+
+        let data = op.read(path).await.unwrap();
+        assert_eq!(data.to_vec(), b"HelloWorld");
+    }
 }