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/05/23 16:08:29 UTC

(opendal) 01/01: feat: Executor

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

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

commit 308ee9b50b8e76291b82e907d5cce165b633dc03
Author: Xuanwo <gi...@xuanwo.io>
AuthorDate: Fri May 24 00:07:53 2024 +0800

    feat: Executor
    
    Signed-off-by: Xuanwo <gi...@xuanwo.io>
---
 core/src/docs/rfcs/0000_executor.md | 114 ++++++++++++++++++++++++++++++++++++
 1 file changed, 114 insertions(+)

diff --git a/core/src/docs/rfcs/0000_executor.md b/core/src/docs/rfcs/0000_executor.md
new file mode 100644
index 0000000000..333380bc9d
--- /dev/null
+++ b/core/src/docs/rfcs/0000_executor.md
@@ -0,0 +1,114 @@
+- Proposal Name: `executor`
+- Start Date: 2024-05-23
+- RFC PR: [apache/opendal#0000](https://github.com/apache/opendal/pull/0000)
+- Tracking Issue: [apache/opendal#0000](https://github.com/apache/opendal/issues/0000)
+
+# Summary
+
+Add executor in opendal to allow running tasks concurrently in background.
+
+# Motivation
+
+OpenDAL offers top-tier support for concurrent execution, allowing tasks to run simultaneously in the background. Users can easily enable concurrent file read/write operations with just one line of code:
+
+```diff
+ let w = op
+     .writer_with(path)
+     .chunk(8 * 1024 * 1024) // 8 MiB per chunk
++    .concurrent(16) // 16 concurrent tasks
+     .await?;
+```
+
+However, the execution of those tasks relies on users continuously calling `write`. They cannot run tasks concurrently in the background. (I explained the technical details in the `Rationale and alternatives` section.)
+
+This can result in the following issues:
+
+- Task latency may increase as tasks are not executed until the task queue is full.
+- Memory usage may be high because all chunks must be held in memory until the task is completed.
+
+I propose introducing an executor in OpenDAL to enable concurrent background task execution. The executor will autonomously manage the tasks without requiring user intervention for progress.
+
+# Guide-level explanation
+
+OpenDAL will add a new `Executor` struct to manage concurrent tasks.
+
+```rust
+pub struct Executor {
+    ...
+}
+
+impl Executor {
+    /// Create a new tokio based executor.
+    pub fn new() -> Self { ... }
+    
+    /// Create a new executor with given execute impl.
+    pub fn with(exec: Arc<dyn Execute>) -> Self { ... }
+
+    /// Run given future in background immediately.
+    pub fn execute<F>(&self, f: F) -> RemoteHandle<F::Output>
+    where
+        F: Future + Send + 'static,
+    {
+        ...
+    }
+}
+```
+
+The `Executor` uses the `tokio` runtime by default but users can also provide their own runtime by:
+
+```rust
+pub trait Execute {
+    fn execute<F>(&self, f: BoxedFuture<()>) -> Result<()>;
+}
+```
+
+Users can set executor in `OpWrite` / `OpRead` to enable concurrent background task execution:
+
+```rust
++ let exec = Executor::new();
+  let w = op
+      .writer_with(path)
+      .chunk(8 * 1024 * 1024) // 8 MiB per chunk
+      .concurrent(16) // 16 concurrent tasks
++     .executor(exec) // Use specfied executor
+      .await?;
+```
+
+Specifying an executor every time is cumbersome. Users can also set a global executor for given operator:
+
+```rust
++ let exec = Executor::new();
++ let op = op.with_default_executor(exec);
+
+  let w = op
+      .writer_with(path)
+      .chunk(8 * 1024 * 1024) // 8 MiB per chunk
+      .concurrent(16) // 16 concurrent tasks
+      .await?;
+```
+
+# Reference-level explanation
+
+# Drawbacks
+
+# Rationale and alternatives
+
+## Why `ConcurrentFutures` doesn't work?
+
+# Prior art
+
+# Unresolved questions
+
+# Future possibilities
+
+## Blocking Executor
+
+This proposal mainly focuses on async tasks. However, we can also consider adding blocking support to `Executor`. Users can use concurrent tasks in blocking context too:
+
+```rust
+ let w = op
+     .writer_with(path)
+     .chunk(8 * 1024 * 1024) // 8 MiB per chunk
++    .concurrent(16) // 16 concurrent tasks
+     .do()?;
+```