Skip to main content

BlobStore

Struct BlobStore 

Source
pub struct BlobStore { /* private fields */ }
Expand description

A content-addressed blob store backed by a directory on disk and a blobs table in SQLite for refcounting.

When constructed via BlobStore::with_redactor, UTF-8 content is passed through the redaction engine before hashing and compression — the record-time enforcement point of docs/redaction-design.md. Because the content is redacted before hashing, the returned hash is the hash of what is actually stored and content-addressing stays internally consistent.

Implementations§

Source§

impl BlobStore

Source

pub fn new(blobs_dir: PathBuf) -> Self

Create a new BlobStore rooted at blobs_dir. The directory itself is created lazily on first write with 0700 permissions.

Source

pub fn with_redactor(blobs_dir: PathBuf, redactor: Arc<Detectors>) -> Self

Create a BlobStore whose Self::put redacts UTF-8 content before storing it (record-time redaction, [redaction] at_record).

Source

pub fn hash(content: &[u8]) -> String

Compute the BLAKE3 hex hash of content without storing it (FR-1.4: binary files record hashes even when content storage is skipped). Centralized here so the recorder does not depend on blake3 directly.

Source

pub fn put(&self, content: &[u8]) -> Result<PutOutcome>

Store content, compressed with zstd, keyed by its BLAKE3 hash. Returns the hash of what was stored. If the blob already exists on disk, content is not rewritten (content-addressing makes it identical). The blobs table refcount is bumped by the store’s writer when an event references this hash.

With a redactor attached (Self::with_redactor), UTF-8 content is redacted first; the returned hash/size then describe the redacted content, so callers must reference the outcome’s hash, never a hash they computed over the original bytes.

Source

pub fn get(&self, hash: &str) -> Result<Vec<u8>>

Read a blob by hash, decompress it, and return the bytes.

Source

pub fn remove_if_unreferenced(&self, hash: &str, refcount: i64) -> Result<bool>

Delete a blob from disk if its refcount has dropped to zero. Returns true if a file was removed. The caller must have already decremented the refcount in the DB; this is the GC step.

Source

pub fn shred(&self, hash: &str) -> Result<bool>

Securely delete a blob file: best-effort overwrite with zeros + fsync, then unlink (docs/redaction-design.md I2). Returns true if a file was removed. The overwrite raises the bar against recovery of the plaintext from the filesystem; it is not a forensic guarantee on journaling/copy-on-write filesystems or wear-leveled SSDs (documented in docs/redaction.md). The caller must have already removed the blob’s row / confirmed the refcount is zero.

Source

pub fn root(&self) -> &Path

The root directory of the store.

Source

pub fn iter_hashes(&self) -> Result<Vec<String>>

Enumerate the BLAKE3 hex hashes of every blob file currently on disk, by walking blobs/<2-char shard>/<64-hex>.zst. Used by crate::store::Store::prune_orphan_blobs and crate::store::Store::store_stats for orphan detection and footprint accounting (Area 3). Returns hashes in arbitrary directory order; defensively skips entries whose names are not a well-formed <hash>.zst, so a stray file in the blobs dir never panics.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.