libblobd_lite/op/
delete_object.rs

1use super::OpError;
2use super::OpResult;
3use crate::ctx::Ctx;
4use std::sync::Arc;
5use tinybuf::TinyBuf;
6
7pub struct OpDeleteObjectInput {
8  pub key: TinyBuf,
9  // Only useful if versioning is enabled.
10  pub id: Option<u64>,
11}
12
13pub struct OpDeleteObjectOutput {}
14
15// We hold write lock on bucket RwLock for entire request (including writes and data sync) for simplicity and avoidance of subtle race conditions. Performance should still be great as one bucket equals one object given desired bucket count and load. If we release lock before we (or journal) finishes writes, we need to prevent/handle any possible intermediate read and write of the state of inode elements on the device, linked list pointers, garbage collectors, premature use of data or reuse of freed space, etc.
16pub(crate) async fn op_delete_object(
17  ctx: Arc<Ctx>,
18  req: OpDeleteObjectInput,
19) -> OpResult<OpDeleteObjectOutput> {
20  let (txn, deleted) = {
21    let mut state = ctx.state.lock().await;
22    let mut txn = ctx.journal.begin_transaction();
23
24    let mut bkt = ctx.buckets.get_bucket_mut_for_key(&req.key).await;
25    // We must always commit the transaction (otherwise our journal will wait forever), so we cannot return directly here if the object does not exist.
26    let deleted = bkt
27      .move_object_to_deleted_list_if_exists(&mut txn, &mut state, req.id)
28      .await;
29
30    (txn, deleted)
31  };
32
33  // We must always commit the transaction (otherwise our journal will wait forever), so we cannot return before this if the object does not exist.
34  ctx.journal.commit_transaction(txn).await;
35
36  let Some(e) = deleted else {
37    return Err(OpError::ObjectNotFound);
38  };
39  ctx.stream_in_memory.add_event_to_in_memory_list(e);
40
41  Ok(OpDeleteObjectOutput {})
42}