Skip to main content

AttachmentStore

Trait AttachmentStore 

Source
pub trait AttachmentStore: Send + Sync {
    // Required methods
    fn put<'life0, 'async_trait>(
        &'life0 self,
        bytes: Vec<u8>,
        meta: AttachmentCreateMeta,
    ) -> Pin<Box<dyn Future<Output = Result<AttachmentRef, AttachmentStoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait;
    fn get<'life0, 'life1, 'async_trait>(
        &'life0 self,
        id: &'life1 AttachmentId,
    ) -> Pin<Box<dyn Future<Output = Result<StoredAttachment, AttachmentStoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;
    fn delete<'life0, 'life1, 'async_trait>(
        &'life0 self,
        id: &'life1 AttachmentId,
    ) -> Pin<Box<dyn Future<Output = Result<(), AttachmentStoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;
    fn list<'life0, 'async_trait>(
        &'life0 self,
    ) -> Pin<Box<dyn Future<Output = Result<Vec<StoredBlobRef>, AttachmentStoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait;

    // Provided methods
    fn persistence(&self) -> AttachmentStorePersistence { ... }
    fn head<'life0, 'life1, 'async_trait>(
        &'life0 self,
        id: &'life1 AttachmentId,
    ) -> Pin<Box<dyn Future<Output = Result<Option<StoredBlobRef>, AttachmentStoreError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait { ... }
}
Expand description

A flat, content-addressed blob store: host-supplied dumb infrastructure.

The store maps a content hash to its bytes and nothing more. It has no notion of sessions — identical bytes written by any number of sessions resolve to one physical blob, and that dedup is intended. Reference tracking and the session boundary live one layer up in SessionAttachmentStore and the AttachmentManifest; lifecycle (which blobs may be deleted) lives above that in the host, via reclaim_unreferenced_attachments.

Conventions every backend upholds: put is idempotent (identical bytes are a no-op returning the same ref), delete is idempotent, and a missing blob maps to AttachmentStoreError::NotFound.

Required Methods§

Source

fn put<'life0, 'async_trait>( &'life0 self, bytes: Vec<u8>, meta: AttachmentCreateMeta, ) -> Pin<Box<dyn Future<Output = Result<AttachmentRef, AttachmentStoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Source

fn get<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 AttachmentId, ) -> Pin<Box<dyn Future<Output = Result<StoredAttachment, AttachmentStoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Source

fn delete<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 AttachmentId, ) -> Pin<Box<dyn Future<Output = Result<(), AttachmentStoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Remove one blob. Idempotent: deleting an absent blob is a no-op. This is the primitive mark-and-sweep GC uses to reclaim unreferenced content; per-session lifecycle is expressed by dropping manifest refs, never by calling this directly for a live session.

Source

fn list<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<Vec<StoredBlobRef>, AttachmentStoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Enumerate every blob currently held. Used only by mark-and-sweep GC. Large deployments may hold many blobs; backends should stream/batch internally where possible. Order is unspecified.

Provided Methods§

Source

fn persistence(&self) -> AttachmentStorePersistence

Source

fn head<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 AttachmentId, ) -> Pin<Box<dyn Future<Output = Result<Option<StoredBlobRef>, AttachmentStoreError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Re-fetch one blob’s current freshness signal, or None if it is absent.

The mark-and-sweep GC calls this immediately before deleting a candidate: the last_modified_epoch_ms captured by the list snapshot is stale by delete time, so a blob that a fresh put (a new intent for the same content id) touched after the snapshot must be spared. The default implementation scans list; backends override it with a cheap stat/HEAD.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§