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/incubator-opendal.git


The following commit(s) were added to refs/heads/main by this push:
     new 470fc2fe39 RFC-3911: Deleter API (#3911)
470fc2fe39 is described below

commit 470fc2fe397c8e8973aa3bc190969d07f1bee110
Author: Xuanwo <[email protected]>
AuthorDate: Sat Jan 6 11:43:09 2024 +0800

    RFC-3911: Deleter API (#3911)
    
    * Save work
    
    Signed-off-by: Xuanwo <[email protected]>
    
    * Add deleter_api
    
    Signed-off-by: Xuanwo <[email protected]>
    
    * Assign number
    
    Signed-off-by: Xuanwo <[email protected]>
    
    * Polish
    
    Signed-off-by: Xuanwo <[email protected]>
    
    * Add tracking issues
    
    Signed-off-by: Xuanwo <[email protected]>
    
    * Reduce confusion
    
    Signed-off-by: Xuanwo <[email protected]>
    
    * Fix typo
    
    Signed-off-by: Xuanwo <[email protected]>
    
    ---------
    
    Signed-off-by: Xuanwo <[email protected]>
---
 core/src/docs/rfcs/3911_deleter_api.md | 172 +++++++++++++++++++++++++++++++++
 core/src/docs/rfcs/mod.rs              |   6 ++
 2 files changed, 178 insertions(+)

diff --git a/core/src/docs/rfcs/3911_deleter_api.md 
b/core/src/docs/rfcs/3911_deleter_api.md
new file mode 100644
index 0000000000..b87636b0d0
--- /dev/null
+++ b/core/src/docs/rfcs/3911_deleter_api.md
@@ -0,0 +1,172 @@
+- Proposal Name: `deleter_api`
+- Start Date: 2024-01-04
+- RFC PR: 
[apache/incubator-opendal#3911](https://github.com/apache/incubator-opendal/pull/3911)
+- Tracking Issue: 
[apache/incubator-opendal#3922](https://github.com/apache/incubator-opendal/issues/3922)
+
+# Summary
+
+Introduce the `Deleter` API to enhance batch and recursive deletion 
capabilities.
+
+# Motivation
+
+All OpenDAL's public API follow the same design:
+
+- `read`: Execute a read operation.
+- `read_with`: Execute a read operation with additional options, like range 
and if_match.
+- `reader`: Create a reader for streaming data, enabling flexible access.
+- `reader_with`: Create a reader with advanced options.
+
+However, `delete` operations vary. OpenDAL offers several methods for file 
deletion:
+
+- `delete`: Delete a single file or an empty dir.
+- `remove`: Remove a list of files.
+- `remove_via`: Remove files produced by a stream.
+- `remove_all`: Remove all files under a path.
+
+This design is not consistent with the other APIs, and it is not easy to use.
+
+So I propose `Deleter` to address them all at once.
+
+# Guide-level explanation
+
+The following new API will be added to `Operator`:
+
+```diff
+impl Operator {
+  pub async fn detele(&self, path: &str) -> Result<()>;
++  pub async fn delete_with(&self, path: &str) -> FutureDelete;
+
++  pub async fn deleter(&self) -> Result<Deleter>;
++  pub async fn deleter_with(&self) -> FutureDeleter;
+}
+```
+
+- `delete` is the existing API, which deletes a single file or an empty dir.
+- `delete_with` is an extension of the existing `delete` API, which supports 
additional options, such as `recursive`.
+- `deleter` is a new API that returns a `Deleter` instance.
+- `deleter_with` is an extension of the existing `deleter` API, which supports 
additional options, such as `recursive`.
+
+The following new options will be available for `delete_with` and 
`deleter_with`:
+
+- `recursive`: Enable recursive deletion.
+- `concurrent`: How many delete tasks can be performed concurrently?
+- `buffer`: How many files can be buffered for send in a single batch?
+
+Users can delete a file recursively in this way:
+
+```rust
+let _ = op.delete_with("path/to/file").recursive(true).await?;
+```
+
+Users can delete multiple files in this way:
+
+
+```rust
+let deleter = op.deleter().await?;
+
+// Add a single file to the deleter.
+deleter.delete(path).await?;
+
+// Add a stream of files to the deleter.
+deleter.delete_all(&mut lister).await?;
+
+// Close deleter, make sure all input files are deleted.
+deleter.close().await?;
+```
+
+`Deleter` also implements 
[`Sink`](https://docs.rs/futures/latest/futures/sink/trait.Sink.html), so all 
the methods of `Sink` are available for `Deleter`. For example, users can use 
[`forward`](https://docs.rs/futures/latest/futures/stream/trait.StreamExt.html#method.forward)
 to forward a stream of files to `Deleter`:
+
+```rust
+// Init a deleter to start batch delete tasks.
+let deleter = op.deleter().await?;
+// List all files that ends with tmp
+let lister = op.lister(path).await?
+  .filter(|x|future::ready(x.ends_with(".tmp")));
+
+// Forward all paths into deleter.
+lister.forward(deleter).await?;
+
+// Send all from a stream into deleter.
+deleter.send_all(&mut lister).await?;
+
+// Close the deleter.
+deleter.close().await?;
+```
+
+Users can control the behavior of `Deleter` by setting the options:
+
+```rust
+let deleter = op.deleter()
+  // Allow up to 8 concurrent delete tasks, default to 1.
+  .concurrent(8)
+  // Configure the buffer size to 1000, default value provided by services.
+  .buffer(1000)
+  .await?;
+
+// Add a single file to the deleter.
+deleter.delete(path).await?;
+
+// Add a stream of files to the deleter.
+deleter.delete_all(&mut lister).await?;
+
+// Close deleter, make sure all input files are deleted.
+deleter.close().await?;
+```
+
+In response to `Deleter` API, we will remove APIs like `remove`, `remove_via` 
and `remove_all`.
+
+- `remove` and `remove_via` could be replaced by `Deleter` directly.
+- `remove_all` could be replaced by `delete_with(path).recursive(true)`.
+
+# Reference-level explanation
+
+To provide those public APIs, we will add a new associated type in `Accessor`:
+
+```rust
+trait Accessor {
+    ...
+    
+    type Deleter = oio::Delete;
+    type BlockingDeleter = oio::BlockingDelete;
+}
+```
+
+And the `delete` API will be changed to return a `oio::Delete` instead:
+
+```diff
+trait Accessor {
+-  async fn delete(&self, path: &str, args: OpDelete) -> Result<RpDelete>;
++  async fn delete(&self, path: &str, args: OpDelete) -> Result<(RpDelete, 
Self::Deleter)>;
+}
+```
+
+Along with this change, we will remove the `batch` API from `Accessor`:
+
+```rust
+trait Accessor {
+-   async fn batch(&self, args: OpBatch) -> Result<RpBatch>;
+}
+```
+
+# Drawbacks
+
+- Big breaking changes.
+
+
+# Rationale and alternatives
+
+None.
+
+# Prior art
+
+None.
+
+# Unresolved questions
+
+None.
+
+# Future possibilities
+
+## Add API that accepts `IntoIterator`
+
+It's possible to add a new API that accepts `IntoIterator` so users can input 
`Vec<String>` or `Iter<String>` into `Deleter`.
diff --git a/core/src/docs/rfcs/mod.rs b/core/src/docs/rfcs/mod.rs
index 57bc6824d4..1d665ef273 100644
--- a/core/src/docs/rfcs/mod.rs
+++ b/core/src/docs/rfcs/mod.rs
@@ -217,8 +217,14 @@ pub mod rfc_3526_list_recursive {}
 #[doc = include_str!("3574_concurrent_stat_in_list.md")]
 pub mod rfc_3574_concurrent_stat_in_list {}
 
+/// Buffered Reader
 #[doc = include_str!("3734_buffered_reader.md")]
 pub mod rfc_3734_buffered_reader {}
 
+/// Concurrent Writer
 #[doc = include_str!("3898_concurrent_writer.md")]
 pub mod rfc_3898_concurrent_writer {}
+
+/// Deleter API
+#[doc = include_str!("3911_deleter_api.md")]
+pub mod rfc_3911_deleter_api {}

Reply via email to