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 2024/06/05 15:16:12 UTC

(opendal) 01/01: chore(core): Add unit and bench tests for concurrent tasks

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

xuanwo pushed a commit to branch fix-block-write
in repository https://gitbox.apache.org/repos/asf/opendal.git

commit 2287284855da11de9d2acff4c010164fbb711922
Author: Xuanwo <gi...@xuanwo.io>
AuthorDate: Wed Jun 5 23:15:40 2024 +0800

    chore(core): Add unit and bench tests for concurrent tasks
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
---
 core/benches/types/concurrent_tasks.rs | 16 +++++++++----
 core/src/raw/futures_util.rs           | 44 ++++++++++++++++++++++++++++++++++
 core/src/raw/oio/write/block_write.rs  |  2 +-
 core/tests/behavior/async_write.rs     |  4 ++--
 4 files changed, 59 insertions(+), 7 deletions(-)

diff --git a/core/benches/types/concurrent_tasks.rs b/core/benches/types/concurrent_tasks.rs
index ca1dfeec55..c4acc07015 100644
--- a/core/benches/types/concurrent_tasks.rs
+++ b/core/benches/types/concurrent_tasks.rs
@@ -15,12 +15,12 @@
 // specific language governing permissions and limitations
 // under the License.
 
-use criterion::black_box;
 use criterion::BatchSize;
 use criterion::Criterion;
 use once_cell::sync::Lazy;
 use opendal::raw::ConcurrentTasks;
 use opendal::Executor;
+use std::time::Duration;
 
 pub static TOKIO: Lazy<tokio::runtime::Runtime> =
     Lazy::new(|| tokio::runtime::Runtime::new().expect("build tokio runtime"));
@@ -34,15 +34,23 @@ pub fn bench_concurrent_tasks(c: &mut Criterion) {
                 || {
                     ConcurrentTasks::new(Executor::new(), *concurrent, |()| {
                         Box::pin(async {
-                            black_box(());
+                            tokio::time::sleep(Duration::from_millis(1)).await;
                             ((), Ok(()))
                         })
                     })
                 },
                 |mut tasks| async move {
-                    let _ = tasks.execute(()).await;
+                    for _ in 0..100 {
+                        let _ = tasks.execute(()).await;
+                    }
+
+                    loop {
+                        if tasks.next().await.is_none() {
+                            break;
+                        }
+                    }
                 },
-                BatchSize::NumIterations(1000),
+                BatchSize::PerIteration,
             )
         });
     }
diff --git a/core/src/raw/futures_util.rs b/core/src/raw/futures_util.rs
index 9ffac3c2f0..6fe4472d6e 100644
--- a/core/src/raw/futures_util.rs
+++ b/core/src/raw/futures_util.rs
@@ -451,6 +451,7 @@ mod tests {
     use futures::future::BoxFuture;
     use futures::Stream;
     use rand::Rng;
+    use tokio::time::sleep;
 
     use super::*;
 
@@ -506,4 +507,47 @@ mod tests {
             assert_eq!(expected, result, "concurrent futures failed: {}", name);
         }
     }
+
+    #[tokio::test]
+    async fn test_concurrent_tasks() {
+        let executor = Executor::new();
+
+        let mut tasks = ConcurrentTasks::new(executor, 16, |(i, dur)| {
+            Box::pin(async move {
+                sleep(dur).await;
+
+                // 5% rate to fail.
+                if rand::thread_rng().gen_range(0..100) > 90 {
+                    return (
+                        (i, dur),
+                        Err(Error::new(ErrorKind::Unexpected, "I'm lucky").set_temporary()),
+                    );
+                }
+                ((i, dur), Ok(i))
+            })
+        });
+
+        let mut ans = vec![];
+
+        for i in 0..10240 {
+            // Sleep up to 10ms
+            let dur = Duration::from_millis(rand::thread_rng().gen_range(0..10));
+            loop {
+                let res = tasks.execute((i, dur)).await;
+                if res.is_ok() {
+                    break;
+                }
+            }
+        }
+
+        loop {
+            match tasks.next().await.transpose() {
+                Ok(Some(i)) => ans.push(i),
+                Ok(None) => break,
+                Err(_) => continue,
+            }
+        }
+
+        assert_eq!(ans, (0..10240).collect::<Vec<_>>())
+    }
 }
diff --git a/core/src/raw/oio/write/block_write.rs b/core/src/raw/oio/write/block_write.rs
index 9d36053946..99c76562ca 100644
--- a/core/src/raw/oio/write/block_write.rs
+++ b/core/src/raw/oio/write/block_write.rs
@@ -213,7 +213,7 @@ where
             let Some(result) = self.tasks.next().await.transpose()? else {
                 break;
             };
-            self.block_ids.push(result)
+            self.block_ids.push(result);
         }
 
         let block_ids = self.block_ids.clone();
diff --git a/core/tests/behavior/async_write.rs b/core/tests/behavior/async_write.rs
index d646ebafd6..c95fdd5f82 100644
--- a/core/tests/behavior/async_write.rs
+++ b/core/tests/behavior/async_write.rs
@@ -347,7 +347,7 @@ pub async fn test_writer_sink(op: Operator) -> Result<()> {
 
     let mut w = op
         .writer_with(&path)
-        .chunk(5 * 1024 * 1024)
+        .chunk(4 * 1024 * 1024)
         .await?
         .into_bytes_sink();
     w.send_all(&mut stream).await?;
@@ -380,7 +380,7 @@ pub async fn test_writer_sink_with_concurrent(op: Operator) -> Result<()> {
     }
 
     let path = TEST_FIXTURE.new_file_path();
-    let size = 5 * 1024 * 1024; // write file with 5 MiB
+    let size = 8 * 1024 * 1024; // write file with 8 MiB
     let content_a = gen_fixed_bytes(size);
     let content_b = gen_fixed_bytes(size);
     let mut stream = stream::iter(vec![