Skip to main content

Module blob

Module blob 

Source
Expand description

The blob engine: coven’s single owner of a blob’s whole durability lifecycle.

coven syncs opaque encrypted blobs referenced by DB rows. By default it owns the cloud layout (the content-addressed {namespace}/{ab}/{cd}/{id}) and encryption; the host decides which rows carry blobs, where their plaintext lives locally, and how each is scoped for encryption. A home configured for the unobfuscated blob-path scheme instead stores each blob at the consumer’s readable BlobRef::cloud_path so the bucket is browsable.

§The coven concept tree

A blob has two declared properties — Provenance (its Local story) and CacheFill (its Remote story) — and one state, locality, flipped by the transitions. The cache is a mechanism that serves Remote blobs; it is not a kind of blob.

A blob the host declares with:

provenance — its LOCAL story: where the bytes live when Local, and the
             Remote→Local path requirement
   ├─ user-provided   the user's file at a path; coven references it.
   │                  Remote→Local writes the bytes back to a user file → NEEDS A PATH.
   └─ host-provided   bae hands coven the data; coven keeps it in its local store.
                      Remote→Local restores it to the local store → no path.

cache fill — its REMOTE story: how a device gets the bytes when the release is
             Remote. A cache-mechanism setting; applies to ANY blob, regardless of
             provenance, once it is Remote.
   ├─ CacheEager   fetched into the cache on pull, with the SQL row   (covers)
   └─ CacheLazy    fetched into the cache on first read               (audio — big, fetch what you play)

and a current state:

locality
   ├─ Local    bytes on-device — the user's path (user-provided) or coven's local store (host-provided)
   └─ Remote   bytes in the cloud; each device's local copy is a CACHE copy, filled
               per `cache fill`, kept-or-evicted per `pin`

namespace (bucket)   the blob's category — release_files · covers · artist_images

transitions
   ├─ Local → Remote   upload the bytes; now cache-distributed to every device per cache fill
   └─ Remote → Local   bring the bytes back to a local file — path required iff user-provided

cache budget   per-NAMESPACE size limit; each namespace evicts independently, so
               evicting release_files (big) never touches covers (small reserved slice)
pin            keep one specific Remote blob's cache copy from eviction (e.g. a
               release the user pinned for offline)

§The cache vs local files

The cache holds local copies of Remote blobs (filled per cache fill, evicted per budget unless pinned). It is segmented by namespace: each namespace has its own configurable cache budget and evicts independently, so evicting release_files (big) never touches covers (a small reserved slice). A CacheEager cover that falls out of its namespace budget shows a placeholder until the next read re-fetches it — covers are not pinned. A Local blob is not in the cache: a user-provided Local blob is the user’s file at its path (an external ref); a host-provided Local blob is in coven’s local store, whose paths and file operations are owned by coven_foundation::store_dir::StoreDir. The cache is the mechanism for remoteness — so CacheEager/CacheLazy/pin/budget describe a blob only while it is Remote, never while it is Local.

§The engine’s halves

This module is the engine; its halves move a blob through its lifecycle:

  • blob::cache — the device-local cache for Remote blobs: bytes on disk keyed by exact locator hash, with the folder a file lives in as the only retention truth (storage/pinned/ protected, storage/cache/ evictable). Reads — one-shot whole, which checks the plaintext against the row’s hash because it reads every byte anyway, or an opened stream whose ranges each cost their own bytes: a positioned read of a local file, or the sealed chunks covering the range fetched from the cloud object and opened — plus pin/unpin, clear, and budget eviction.
  • coven_foundation::store_dir::StoreDir — coven’s own copy of a host-provided Local blob, in storage/local/<namespace>/<id>. Never evicted; the budget sweep never walks it.
  • blob::upload — the cloud-write half: drain the durable upload queue, sealing each blob under its scope and writing it to the cloud with coalesced progress, so a local-only blob becomes uploaded. The sync cycle calls the drain each round before it pushes.
  • blob::delete — the cloud-delete half: turn a queued deletion into a signed cloud tombstone, hold the blob for a convergence grace so a lagging peer isn’t stranded, then GC the blob once the grace has passed. The sync cycle drains tombstones and runs the GC each round after it pulls.

The types below (BlobRef, BlobScope, Provenance, CacheFill, BlobTransitionObserver) are the vocabulary both halves and the host speak. Which rows carry blobs is not a runtime callback but a per-table declaration (crate::synced_schema::BlobDecl) coven resolves into a the database’s BlobDecls each cycle to derive the blob set itself.

coven also owns the two locality transitions (blob::transition): make_remote (Local → Remote: upload the bytes, then flip the gate) and make_local (Remote → Local: bring each blob back to a local file, then retract). The The upload drain advances the durable make-Remote intent after every exact object lands. The Store publication activates the resulting gate change; hosts observe both handoffs through the durable cloud-outbox query.

Modules§

locator

Structs§

BlobRef
A blob a row references: its cloud identity, encryption scope, and the two declared properties (provenance + fill). coven derives it from the row’s declared columns (crate::synced_schema::BlobDecl) via the database’s BlobDecls. Where its bytes live depends on its locality and provenance: a user-provided Local blob is the user’s file at its path; a host-provided Local blob is in coven’s local store (storage/local/<namespace>/<id>); a Remote blob’s device-local copy is a cache copy (storage/pinned/<namespace>/<locator-hash> / storage/cache/<namespace>/<locator-hash>, built from the validated namespace + exact locator hash — see blob::cache).
ContentHasher
An incremental SHA-256 over a blob’s plaintext, so the streaming download path verifies a blob’s content hash without holding the whole plaintext in memory: feed each decrypted chunk to update, call finish, and compare the returned digest with the row’s hash before committing the bytes to the cache. The hex-encoded digest matches content_hash over the same bytes.
DeferredLocalBlobDispositionError
DeferredLocalBlobDrop
RowBlobRef
One exact blob-bearing row version. A reference becomes stale when the live row stamp or any declared blob value changes.
TransferLimits
How many blob transfers coven runs at once in each of its two transfer loops: the upload drain and the pin/download loop. An open-time blob-engine tunable the host sets on the builder, carried on the Database alongside the other open-time blob config and read back by each loop, which holds &Database.

Enums§

BlobOpeningAuthority
BlobOpeningAuthorityError
BlobReplacement
A blob’s replacement story: whether the row carrying it may ever be repointed at a different blob. Orthogonal to Provenance and CacheFill; a blob declares all three.
BlobScope
Which key encrypts a blob, as a host names it on a BlobRef.
CacheFill
A blob’s Remote story: how a device gets the bytes once the blob is Remote. A cache-mechanism setting — it describes a blob only while Remote — that applies to ANY blob regardless of Provenance. Orthogonal to provenance; a blob declares both.
DeferredLocalBlobDisposition
Provenance
A blob’s Local story: where its bytes live while the blob is Local, and whether bringing it back from Remote needs a destination path. Orthogonal to CacheFill (the Remote story) — a blob declares both.
RowBlobAuthority
The authority state that determines where one row version’s blob lives. A remote-audience blob remains PendingRemote while its verified plaintext is local and no cloud object has been created; Remote carries the exact package authority needed to open its committed object.
RowBlobRefError

Constants§

BLOB_TOMBSTONE_GRACE
The default convergence window a host gets if it configures none: how long a deleted blob is kept after its tombstone is written, before a GC pass reclaims it. The host overrides it on the coven builder; the writer’s tombstone collection evaluates whatever grace it is handed against the tombstone’s deleted_at.

Traits§

BlobTransitionObserver
Notified about coven’s blob transitions, for host-specific bookkeeping and UI: per-blob upload progress while a make_remote uploads, per-blob materialize progress while a make_local copies files back, and the synchronous make-local completion the host turns into its own UI event.

Functions§

cloud_path_names_blob
Whether the readable cloud_path a consumer supplied names the blob blob_id — what coven requires of a Replaceable blob’s key on a browsable home, and what a hashed key gets for free by carrying the id itself.
content_hash
The content hash a blob-bearing row carries: the lowercase-hex SHA-256 of the blob’s plaintext bytes, computed at import and stored in the row’s blob columns alongside the declared size. The row is carried in a signed changeset (and in a signed snapshot), so this hash is signed by the row’s author — that is what makes it authoritative: on download coven hashes the decrypted plaintext and requires equality with the row’s hash, so the bytes are pinned by the author, not by the cloud key they happened to arrive under. A host computes this over a blob’s plaintext at import and writes it into the row’s declared hash column, the same way it writes the plaintext length into the size column.
locator_describes_row
locator_is_this_rows_upload
Whether locator describes exactly the row version it was minted for.