Recoverable Soft-Delete Registry
Problem
Design RecoverableSoftDeleteRegistry to manage named collections that can be deleted, viewed, and restored during a fixed retention window.
Requirements
- Initialization. Construction stores every supplied collection ID and name as live and uses the supplied retention interval for every later deletion.
- Deletion. Deleting a live collection returns
trueand creates a tombstone withdeletedAt = nowSecondsandexpiresAt = nowSeconds + retentionSeconds. Deleting an absent or already-deleted collection returnsfalsewithout changing state or timestamps. - Restoration. Restoring a tombstone while
nowSeconds < expiresAtreturnstrue, makes the original collection live, and preserves its ID and name. Restoring an absent ID, a live collection, or a tombstone at or after expiry returnsfalsewithout changing registry state. - Deleted view.
getDeletedCollections(nowSeconds)returns exactly the ID-name mappings for tombstones withnowSeconds < expiresAt. Map iteration order is not observable.
API
| Signature | Returns | Behavior |
|---|---|---|
RecoverableSoftDeleteRegistry(initialCollections: map<string, string>, retentionSeconds: integer) | Not applicable | Copies the supplied collections into live state and fixes the retention interval. |
deleteCollection(collectionId: string, nowSeconds: integer) | boolean | Applies the deletion transition or returns false atomically. |
restoreCollection(collectionId: string, nowSeconds: integer) | boolean | Restores one unexpired tombstone or returns false atomically. |
getDeletedCollections(nowSeconds: integer) | map<string, string> | Returns all and only currently recoverable tombstones. |
Examples
For RecoverableSoftDeleteRegistry({"c1": "Payments", "c2": "Health"}, 10):
| Step | Operation | Result |
|---|---|---|
| 1 | deleteCollection("c1", 100) | true |
| 2 | getDeletedCollections(105) | {"c1": "Payments"} |
| 3 | restoreCollection("c1", 109) | true |
| 4 | getDeletedCollections(109) | {} |
| 5 | deleteCollection("c1", 120) | true |
| 6 | restoreCollection("c1", 130) | false |
Constraints
0 <= initialCollections.size <= 10,000.- IDs and names are nonempty; IDs are unique map keys and names may repeat.
1 <= retentionSeconds <= 1,000,000,000.0 <= nowSeconds <= 1,000,000,000,000.- Time-bearing calls on one instance use nondecreasing
nowSeconds. - At most
15,000public method calls occur per testcase. - Expiry arithmetic uses signed 64-bit integers.
Notes
A collection is either live or represented by one tombstone. Calls are sequential, and concurrent use has no guarantee.