Hone logo
Hone
Problems

Deferred Deletion in Rust

Deferred deletion is a pattern where the actual deletion of a resource (like a file, database entry, or network connection) is delayed until a later point in time. This is useful when you want to ensure that the resource isn't deleted prematurely, perhaps because other parts of your program still need it, or because the deletion operation is expensive and should be batched. This challenge asks you to implement a system for deferred deletion in Rust using closures and potentially Arc and Mutex for thread safety.

Problem Description

You need to create a DeferredDeleter struct that allows you to register resources for deletion. The DeferredDeleter should maintain a list of closures, each representing a deletion operation. When the delete_all method is called, it should execute all registered deletion closures in order. The DeferredDeleter should be thread-safe, allowing multiple threads to register and delete resources concurrently.

Key Requirements:

  • Registration: Provide a method to register a closure that performs the deletion of a resource. This closure should take no arguments.
  • Deletion: Provide a method to trigger the deletion of all registered resources. This method should execute all registered closures sequentially.
  • Thread Safety: The DeferredDeleter must be safe to use from multiple threads concurrently. Registration and deletion should be protected against race conditions.
  • Resource Representation: The closure represents the resource to be deleted. The closure itself doesn't need to return a value.

Expected Behavior:

  • When register_deleter is called, the provided closure is added to the internal list of deletion operations.
  • When delete_all is called, each registered closure is executed in the order they were registered.
  • The DeferredDeleter should handle the case where no resources have been registered for deletion.
  • The DeferredDeleter should handle the case where a closure panics during deletion. (Consider how you want to handle panics - ignore them, re-panic, etc. Document your choice.)

Edge Cases to Consider:

  • Multiple threads registering deletion closures concurrently.
  • Multiple threads calling delete_all concurrently.
  • A closure panicking during deletion.
  • No deletion closures registered.

Examples

Example 1:

Input:
```rust
let mut deleter = DeferredDeleter::new();
deleter.register_deleter(|| println!("Deleting file A"));
deleter.register_deleter(|| println!("Deleting file B"));
deleter.delete_all();

Output:

Deleting file A
Deleting file B

Explanation: The two deletion closures are registered and then executed sequentially by delete_all.

Example 2:

Input:
```rust
let mut deleter = DeferredDeleter::new();
deleter.delete_all();

Output:

// No output - nothing to delete

Explanation: delete_all is called before any closures are registered, so no actions are performed.

Example 3: (Handling Panics)

Input:
```rust
let mut deleter = DeferredDeleter::new();
deleter.register_deleter(|| {
    println!("Deleting file C");
    panic!("Simulated deletion error!");
});
deleter.register_deleter(|| println!("Deleting file D"));
deleter.delete_all();

Output:

Deleting file C
// Program panics with "Simulated deletion error!"

Explanation: The first closure panics. The behavior here is to re-panic, halting the deletion process. (This behavior should be documented in your solution).

Constraints

  • The DeferredDeleter must be thread-safe.
  • The deletion closures should be executed sequentially.
  • The number of registered deletion closures can be up to 1000.
  • The closures themselves can perform any arbitrary operation (within reason, of course - no infinite loops!).
  • The delete_all method should complete within a reasonable time (e.g., no more than 1 second for 1000 closures).

Notes

  • Consider using Arc<Mutex<Vec<Box<dyn Fn()>>>> to store the deletion closures. Arc allows shared ownership across threads, and Mutex provides mutual exclusion to prevent race conditions. Box<dyn Fn()> allows you to store closures of different signatures.
  • Think carefully about how you want to handle panics within the deletion closures. Re-panicking is a simple approach, but you could also choose to log the error and continue with the remaining closures. Document your choice.
  • Focus on correctness and thread safety first. Performance optimizations can be considered later.
  • The Fn() trait represents a closure that takes no arguments and returns nothing.
Loading editor...
rust