1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// SPDX-FileCopyrightText: Szilárd Hajba
// SPDX-License-Identifier: LGPL-3.0-or-later
//! Adapter that manages and stores blobs (immutable file data)
use async_trait::async_trait;
use axum::body::Bytes;
use futures_core::Stream;
use std::{fmt::Debug, pin::Pin};
use tokio::io::AsyncRead;
use crate::prelude::*;
#[derive(Clone, Default)]
pub struct CreateBlobOptions {}
#[derive(Debug, Clone)]
pub struct BlobStat {
pub size: u64,
/// Unix epoch seconds of the blob's last modification (or creation).
pub modified_at: i64,
}
#[async_trait]
pub trait BlobAdapter: Debug + Send + Sync {
/// Creates a new blob from a buffer
async fn create_blob_buf(
&self,
tn_id: TnId,
file_id: &str,
data: &[u8],
opts: &CreateBlobOptions,
) -> ClResult<()>;
/// Creates a new blob using a stream
async fn create_blob_stream(
&self,
tn_id: TnId,
file_id: &str,
stream: &mut (dyn AsyncRead + Send + Unpin),
) -> ClResult<()>;
/// Stats a blob. Returns `None` if the blob is not present.
async fn stat_blob(&self, tn_id: TnId, blob_id: &str) -> Option<BlobStat>;
/// Reads a blob
async fn read_blob_buf(&self, tn_id: TnId, blob_id: &str) -> ClResult<Box<[u8]>>;
/// Reads a byte range from a blob
async fn read_blob_range(
&self,
tn_id: TnId,
blob_id: &str,
offset: u64,
length: u64,
) -> ClResult<Box<[u8]>>;
/// Reads a blob
async fn read_blob_stream(
&self,
tn_id: TnId,
blob_id: &str,
) -> ClResult<Pin<Box<dyn Stream<Item = Result<Bytes, std::io::Error>> + Send>>>;
/// Creates a new blob by copying a file from a local path (no memory allocation)
async fn create_blob_from_path(
&self,
tn_id: TnId,
file_id: &str,
source: &std::path::Path,
opts: &CreateBlobOptions,
) -> ClResult<()>;
/// Delete every blob owned by the tenant. Treats a missing tenant directory
/// as success. Used by tenant purge orchestration.
async fn delete_tenant_blobs(&self, tn_id: TnId) -> ClResult<()>;
/// Delete a single blob. Missing blob is success (idempotent).
async fn delete_blob(&self, tn_id: TnId, blob_id: &str) -> ClResult<()>;
/// Enumerate every `blob_id` (typically a `variant_id`) currently present
/// in this tenant's blob store. Used by the GC scanner.
async fn list_blobs(
&self,
tn_id: TnId,
) -> ClResult<Pin<Box<dyn Stream<Item = ClResult<String>> + Send>>>;
/// Delete in-progress upload artifacts whose mtime is at or before
/// `cutoff_secs` (Unix epoch seconds). These are written outside the
/// content-addressed `xx/yy/` shards by `create_blob_stream`, so they
/// are invisible to `list_blobs`. Returns the number of files removed.
/// Adapters with no notion of tmp files may return `Ok(0)`.
async fn cleanup_tmp_files(&self, tn_id: TnId, cutoff_secs: i64) -> ClResult<u64>;
}
// vim: ts=4