Skip to main content

snix_castore/blobstore/
mod.rs

1#![deny(missing_docs)]
2//! [BlobMeta] storage, used to assemble blobs from more granular Chunks.
3use auto_impl::auto_impl;
4use tonic::async_trait;
5
6mod blob_meta;
7mod blob_reader;
8mod blob_writer;
9
10#[cfg(feature = "mocks")]
11mod mock_writer;
12
13pub mod combinators;
14pub mod grpc;
15pub mod memory;
16pub mod object_store;
17
18use crate::{
19    B3Digest,
20    composition::{Registry, ServiceBuilder},
21};
22pub use blob_meta::BlobMeta;
23pub use blob_reader::{BlobReader, LimitBlobReader};
24pub use blob_writer::BlobWriter;
25
26#[cfg(feature = "mocks")]
27pub use mock_writer::MockWriter;
28
29/// Retrieves and stores [BlobMeta] about Blobs.
30/// Blobs can consist of multiple Chunks.
31/// Blobs are keyed by the BLAKE3 digest of their entire data.
32#[cfg_attr(test, mockall::automock)]
33#[async_trait]
34#[auto_impl(&, &mut, Arc, Box)]
35pub trait BlobStore: Send + Sync {
36    /// Retrieves a [BlobMeta] for a given blob digest.
37    async fn get(&self, digest: &B3Digest) -> Result<Option<BlobMeta>, Error>;
38
39    /// Checks if a [BlobMeta] for a given blob exists.
40    async fn has(&self, digest: &B3Digest) -> Result<bool, Error>;
41
42    /// Persists a [BlobMeta] for the given blob digest.
43    async fn put(&self, digest: &B3Digest, blob_meta: BlobMeta) -> Result<(), Error>;
44}
45
46/// Error returned from all BlobStores.
47///
48/// Usually boxes an inner, more backend-specific error.
49#[derive(thiserror::Error, Debug)]
50#[error(transparent)]
51pub struct Error(#[from] Box<dyn std::error::Error + Send + Sync + 'static>);
52
53/// Registers the builtin [BlobStore]s with the registry.
54pub(crate) fn register_blob_stores(reg: &mut Registry) {
55    reg.register::<Box<dyn ServiceBuilder<Output = dyn BlobStore>>, combinators::CacheConfig>(
56        "cache",
57    );
58    reg.register::<Box<dyn ServiceBuilder<Output = dyn BlobStore>>, grpc::GRPCBlobStoreConfig>(
59        "grpc",
60    );
61    reg.register::<Box<dyn ServiceBuilder<Output = dyn BlobStore>>, memory::MemoryBlobStoreConfig>(
62        "memory",
63    );
64    reg.register::<Box<dyn ServiceBuilder<Output = dyn BlobStore>>, object_store::ObjectStoreBlobStoreConfig>("objectstore");
65    reg.register::<Box<dyn ServiceBuilder<Output = dyn BlobStore>>, combinators::PriorityConfig>(
66        "priority",
67    );
68    reg.register::<Box<dyn ServiceBuilder<Output = dyn BlobStore>>, combinators::RaceConfig>(
69        "race",
70    );
71}
72
73/// A [tokio::io::AsyncWrite] that the user needs to close() afterwards to persist.
74/// On success, it returns the digest of the written blob.
75#[async_trait]
76pub trait Writer: tokio::io::AsyncWrite + Send + Unpin {
77    /// Signal there's no more data to be written, and return the digest of the
78    /// contents written.
79    ///
80    /// Closing an already-closed BlobWriter is a no-op.
81    async fn close(&mut self) -> std::io::Result<crate::B3Digest>;
82}
83
84/// BlobReader is a [tokio::io::AsyncRead] that also allows seeking.
85pub trait Reader:
86    tokio::io::AsyncRead + tokio::io::AsyncSeek + std::any::Any + Send + Unpin
87{
88}