Skip to main content

MeshBlobAdapter

Struct MeshBlobAdapter 

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

mesh://-scheme adapter that stores chunks as content-addressed RedexFiles. See the module-level docs for the dispatch shape.

Implementations§

Source§

impl MeshBlobAdapter

Source

pub fn new(id: impl Into<String>, redex: Arc<Redex>) -> MeshBlobAdapter

Construct a mesh-native adapter rooted at redex. Chunks are stored as in-memory RedexFiles by default — call Self::with_persistent to write to disk (requires the underlying Redex to be configured with a persistent dir), and / or Self::with_replication to opt every per-chunk file into the cross-node replication runtime.

Source

pub fn with_auto_repair_on_fetch(self, enabled: bool) -> MeshBlobAdapter

Enable fetch-path opportunistic auto-repair for RS-encoded blobs. When set, every successful reconstruction inside fetch_range re-stores the missing data chunks under their original content-addressed hashes — so the stripe goes back to healthy, the v0.3 Phase C6 GC stripe-pin lifts naturally, and subsequent fetches don’t re-pay the reconstruction cost.

Default is false — the v0.3 plan’s stated semantic is that fetch never writes. Enable for hot-blob workloads where degraded stripes would otherwise re-reconstruct on every read. The operator-driven Self::repair_blob remains the durable, sweep-the-whole-blob recovery path regardless of this flag.

Source

pub fn with_persistent(self, persistent: bool) -> MeshBlobAdapter

Opt every per-chunk file into disk persistence. Default is in-memory; switch on for production deployments that want blob chunks to survive process restart.

Source

pub fn with_tree_node_cache(self, cap_bytes: usize) -> MeshBlobAdapter

Attach a manifest-tree LRU cache for BlobRef::Tree walks. cap_bytes sets the byte budget — every walk_tree_range fetch consults the cache first and stores the fetched node bytes on miss. A second range read on the same blob whose path overlaps the prior walk’s path skips the fetch_chunk for the cached nodes.

Default 64 MiB cap ≈ 13 K nodes at the typical ~5 KiB postcard-encoded per-node size. Operators with tighter or looser memory budgets pass an explicit cap_bytes. Pass 0 to disable caching entirely (every lookup misses, every insert is a no-op — useful for ablation testing).

Cache hits stay correct under the content-addressed model (BLAKE3 hashes are immutable by construction); no invalidation surface is exposed.

Source

pub fn with_chunk_file_max_memory_bytes(self, bytes: usize) -> MeshBlobAdapter

Override the per-chunk-file max_memory_bytes reservation.

RedexFileConfig defaults to 64 MiB per channel; for blobs stored as many small chunks (e.g. 8 KiB chunks of a multi- MiB blob) that reservation is multiplied by the chunk count, easily blowing the process commit limit even though each channel only ever holds a few KiB of live bytes. Operators with chunk-heavy blobs pass a smaller value here (e.g. 1 << 20 = 1 MiB) to bound the reservation.

The upstream min(value, 64 MiB) clamp still applies — a larger value than the default has no effect.

Source

pub fn tree_node_cache_stats(&self) -> Option<(u64, u64, usize, usize)>

Snapshot of the tree-node cache’s (hits, misses, bytes, len) for operator metrics. Returns None when no cache is wired.

Source

pub fn with_replication(self, cfg: ReplicationConfig) -> MeshBlobAdapter

Per-chunk replication config applied to every newly-opened chunk file. Requires Redex::enable_replication(mesh) to have been called on the underlying handle; the per-chunk open surfaces a typed RedexError if not.

Source

pub fn with_retention_floor(self, floor: Duration) -> MeshBlobAdapter

Override the default retention floor (24 h) applied by the GC sweep. Shorter floors reclaim disk faster at the cost of premature GC under racy refcount sources; longer floors are safer but consume more disk between sweeps. Tune to match the operator’s chain-fold cadence.

Source

pub fn with_disk_capacity(self, bytes: u64) -> MeshBlobAdapter

Operator-configured disk capacity in bytes. Drives the dataforts_blob_disk_capacity_bytes gauge + the health- gate threshold. 0 (the default) disables the health gate entirely.

Source

pub fn with_auth_guard(self, guard: Arc<AuthGuard>) -> MeshBlobAdapter

Wire an AuthGuard handle so the *_authorized variants of Self::pin / Self::unpin / Self::delete_chunk can gate peer-initiated ops against the publishing chain’s (origin_hash, ChannelName) ACL. The unauth variants stay reachable for system-internal callers (GC sweep, chain-fold-driven refcount maintenance).

Source

pub fn with_blob_heat( self, registry: Arc<Mutex<RawMutex, BlobHeatRegistry>>, half_life: Duration, ) -> MeshBlobAdapter

Wire a shared blob-heat registry. Each successful fetch then bumps the chunk hash’s heat counter so a gravity tick can observe the read rate (PR-5j-b). The registry handle is cheap to clone (Arc<Mutex> inside); operators typically share the same handle with the gravity migration controller’s tick loop.

half_life controls the per-counter decay; pass DEFAULT_BLOB_HEAT_HALF_LIFE for the standard 60 s half-life or a custom value when tuning aggressive vs lazy migration cadence.

Source

pub fn with_overflow(self, config: OverflowConfig) -> MeshBlobAdapter

Install the supplied OverflowConfig as the initial overflow state. The enabled field of config is honored — passing OverflowConfig { enabled: true, .. Default::default() } is the typical “turn on with defaults” gesture. Subsequent Self::set_overflow_enabled / Self::set_overflow_config calls override the state set here.

Default (no call to this builder) is OverflowConfig::default() with enabled = false — the v0.2 pull-only posture.

Source

pub fn overflow_enabled(&self) -> bool

True iff the adapter is currently advertising dataforts.blob.overflow and accepting inbound OverflowPush requests. Cheap (one read-lock acquire); fine to call on the hot path.

Returns the runtime state, so operators dashboarding “is overflow on” against a recently-toggled node see the live value rather than a build-time snapshot.

Source

pub fn overflow_config(&self) -> OverflowConfig

Snapshot of the current overflow configuration. Returns a copy of the OverflowConfig (it’s Copy); the lock is released before the return. Inspection-only; mutate via Self::set_overflow_enabled or Self::set_overflow_config.

Source

pub fn set_overflow_enabled(&self, enabled: bool)

Flip the overflow master switch at runtime. No-op if enabled matches the current state. When the boolean transitions, the adapter’s next capability rebroadcast adds (or removes) the dataforts.blob.overflow tag — peers see the change on the following announcement cycle.

The adapter doesn’t hold a MeshNode handle (the two are intentionally decoupled), so the rebroadcast itself happens through one of:

  • MeshNode::announce_blob_overflow_state(adapter) — the convenience path: snapshots local caps, syncs the dataforts.blob.overflow tag to the adapter’s current state, and announces in one call. Recommended.
  • Manual announce_capabilities(updated_set) where updated_set carries the matching presence tag.

Until the rebroadcast lands, the sender-side overflow tick short-circuits (the local caps snapshot doesn’t yet reflect the new state — see drive_blob_overflow_tick) and peers reject any inbound nudge as SenderNotOverflowing.

Cheap: one write-lock acquire, one bool store. Safe to call concurrently with reads via Self::overflow_enabled — the RwLock ensures the observed value is consistent with one toggle event.

Source

pub fn set_overflow_config(&self, config: OverflowConfig)

Replace the entire overflow configuration in one call. Useful when the operator wants to update thresholds (high-water, low-water, push budget, scope) without touching the master switch — pass the same enabled value the adapter currently has, plus the new thresholds. Or use this to atomically enable + tune in one call.

Source

pub fn overflow_active(&self) -> bool

True iff the most recent overflow tick observed local disk at or above the high-water threshold (i.e. the controller is actively shedding). Mirrors the hysteresis state machine — stays true through the hysteresis band on the way down and only flips back to false once disk drops to or below the low-water threshold.

Read-only observer; the tick driver is the single writer. Cheap (one atomic load) — safe to call on a dashboard hot path.

Source

pub async fn drive_overflow_tick( &self, ctx: OverflowTickContext<'_>, size_for_hash: impl Fn([u8; 32]) -> Option<u64>, ) -> BlobOverflowTickReport

Convenience: drive one overflow tick + auto-record the resulting report into the adapter’s metrics registry. Composes super::overflow::drive_blob_overflow_tick with super::metrics::BlobMetrics::record_overflow_tick so operators don’t have to thread the report through two calls on every tick.

ctx carries everything the controller needs that the adapter doesn’t already own: the capability index, the heat registry, the sink, the local caps snapshot, and the disk-usage stats. The adapter contributes the refcount, config, and overflow_active hysteresis state from self. The closure size_for_hash stays separate (closures don’t sit in struct fields without a Box<dyn Fn> wrapper that’s heavier than the inlined-impl-Fn shape).

The controller’s config is read live from self.overflow_config() so an operator-toggled threshold lands on the next tick.

Returns the super::overflow::BlobOverflowTickReport so callers can inspect per-tick state without a second metrics scrape.

Source

pub fn record_overflow_reject(&self, reason: OverflowReject)

Bump the receive-side overflow rejection counter for reason. Called by super::overflow::OverflowPushHandler on every inbound push that admission rejects; surfaces in the adapter’s Prometheus body as dataforts_blob_overflow_rejected_total{reason}.

The sender’s own metrics bump dataforts_blob_overflow_push_errors_total on the same event (via the controller’s push_errors counter); the two surfaces are complementary so operators dashboarding either side see matching volumes.

Source

pub fn blob_heat_enabled(&self) -> bool

True iff this adapter is wired to bump a shared blob-heat registry on fetch.

Source

pub async fn tick_blob_heat( &self, policy: &DataGravityPolicy, sink: &dyn BlobHeatSink, ) -> Result<u64, BlobError>

Run one tick of the blob-heat registry: walk every tracked hash, apply decay, ask the supplied policy whether to emit, and route each Emit { rate } / Withdraw decision through sink (as announce_blob_heat_batch). Returns the count of emissions that landed (Emit + Withdraw combined). PR-5j-c emission path; operators drive from a periodic task at DataGravityPolicy::emit_interval cadence.

No-op (Ok(0)) when no registry is wired. The emission snapshot is taken under the registry lock; the lock is released before awaiting the sink, so a concurrent fetch on this adapter can keep bumping heat in parallel. The lock is !Send across .await — holding it past an await would also break the runtime’s task model (a task rescheduled to a different worker while holding a thread- affine guard) — which is the real concern. parking_lot mutexes don’t poison; the explicit scoping below is about preserving Send for the awaited future.

Source

pub fn pin_authorized( &self, hash: [u8; 32], origin_hash: u64, channel: &ChannelName, now_unix_ms: u64, ) -> Result<(), BlobError>

Pin hash against GC, gated by an AuthGuard::is_authorized_full check on (origin_hash, channel). Returns BlobError::Backend if the adapter has no guard configured (operator misconfiguration on the peer-facing path) or if the caller is not authorized for channel.

channel is the canonical name of the chain that originally published the blob — the caller of the pin op must be authorized on that chain.

Source

pub fn unpin_authorized( &self, hash: [u8; 32], origin_hash: u64, channel: &ChannelName, now_unix_ms: u64, ) -> Result<(), BlobError>

Unpin hash, gated by an AuthGuard::is_authorized_full check on (origin_hash, channel). Returns BlobError::Backend if no guard is configured or the caller is not authorized.

Source

pub async fn delete_chunk_authorized( &self, hash: &[u8; 32], origin_hash: u64, channel: &ChannelName, ) -> Result<(), BlobError>

Delete a single chunk file by content hash, gated by an AuthGuard::is_authorized_full check on (origin_hash, channel). Mirrors Self::delete_chunk on the success path; returns a typed BlobError::Backend if no guard is configured or the caller is not authorized.

System-internal callers (the GC sweep) use the unauth Self::delete_chunk variant — only peer-initiated deletes route through this gate.

Source

pub fn refcount_table(&self) -> &BlobRefcountTable

Refcount table reference. Operators bump via BlobRefcountTable::incr from chain-fold / CortEX integration sites; the adapter reads on sweep + stat paths.

Source

pub fn metrics(&self) -> &BlobMetrics

Atomic-counter registry surfaced for Prometheus scrape.

Source

pub fn prometheus_text(&self) -> String

Render a Prometheus-text snapshot for the operator scrape. Concatenates the counter / gauge bodies with the live gc_pending_total from the refcount table.

Source

pub fn pin(&self, hash: [u8; 32], now_unix_ms: u64)

Pin hash against GC. Operator escape hatch — pinned hashes survive sweep regardless of refcount + retention floor. Returns the hash for ergonomic chaining.

now_unix_ms should be the operator’s current wall-clock — used to stamp last_seen and (if the hash is new) first_seen.

Source

pub fn unpin(&self, hash: [u8; 32], now_unix_ms: u64)

Unpin hash. After this, the hash returns to the normal refcount / retention-floor sweep contract.

Source

pub async fn sweep_gc( &self, now_unix_ms: u64, disk_pressure_critical: bool, ) -> Result<u64, BlobError>

Run a GC sweep. Pure-logic in two halves: decide (which hashes are deletable under the refcount + retention + pressure + pin rules), then act (delete the chunk files, remove the refcount entries, bump dataforts_blob_gc_swept_total). The two halves are fused here for the typical operator-driven sweep; advanced callers can invoke BlobRefcountTable::deletable_hashes + Self::delete_chunk directly for dry-run / batched flows.

Returns the count of chunks actually swept (may be less than deletable_hashes if some chunk-file deletes failed — the failures are logged but the refcount entry is left in place so the next sweep retries).

Source

pub async fn delete_chunk(&self, hash: &[u8; 32]) -> Result<(), BlobError>

Delete a single chunk file by content hash. The chunk’s RedexFile is closed + removed from the Redex manager (including any on-disk segment dir for persistent deployments), and the refcount table entry is dropped on success so stat() stops surfacing a stale last_seen_unix_ms for a deleted blob and any subsequent re-store starts a fresh retention-floor clock. Idempotent on the success path — closing an already-closed file returns Ok(()) from the Redex layer. Used by the peer-initiated Self::delete_chunk_authorized as a force-delete; reachable directly for operators running batched / dry-run flows against BlobRefcountTable::deletable_hashes.

On Err the refcount entry is preserved so the next sweep can retry — chunk-file close failures shouldn’t strand the retention clock.

The GC sweep does NOT route through this method: it uses BlobRefcountTable::remove_if_deletable + a direct close_and_unlink_file so an incr racing the sweep can rescue the entry without losing data.

Source

pub async fn store_stream_tree( &self, stream: Pin<Box<dyn Stream<Item = Result<Bytes, BlobError>> + Send>>, encoding: Encoding, chunking: ChunkingStrategy, ) -> Result<BlobRef, BlobError>

Store a byte stream as a hierarchical-manifest blob (BlobRef::Tree). Returns the constructed reference; every constituent chunk + tree node is persisted before the return.

Streams are consumed chunk-by-chunk against the supplied ChunkingStrategy. v0.3 Phase A accepts only ChunkingStrategy::Fixed at exactly BLOB_CHUNK_SIZE_BYTES (4 MiB) — CDC lands in Phase B, other fixed sizes break v0.2 chunk-level dedup and are rejected. Each chunk is hashed (BLAKE3), persisted via the existing store_chunk path (idempotent on hash collision), then fed into a TreeBuilder that accumulates the manifest tree incrementally.

Memory bound: O(chunk_size + TREE_FANOUT × MAX_TREE_DEPTH × entry_size) — roughly 4 MiB + 20 KiB at the v0.3a defaults. Independent of total stream size; a 1 TiB stream uses the same peak memory as a 1 GiB stream.

Phase A ships with sequential store_chunk dispatch — each chunk is awaited before the next is requested. Phase D’s crate::adapter::net::redex::BandwidthClass surface adds dynamic in-flight parallelism (~256 MB target). For TB-scale streams on a fast link, the sequential path may not saturate the wire; that’s an acknowledged Phase A trade-off.

Source

pub async fn publish_stream_with_downgrade( &self, stream: Pin<Box<dyn Stream<Item = Result<Bytes, BlobError>> + Send>>, encoding: Encoding, chunking: ChunkingStrategy, size_hint: Option<u64>, probes: &DowngradeProbes<'_>, ) -> Result<BlobRef, BlobError>

Publish a byte stream, choosing BlobRef::Tree vs BlobRef::Manifest based on a TreeSupportProbe + the TREE_THRESHOLD_BYTES producer hint, AND applying CDC + erasure downgrades from the matching capability probes before any store work runs.

Decision flow:

  1. Apply super::cdc::cdc_downgrade to chunking — peers that don’t advertise CDC support get the Fixed fallback so their chunk-store can recompute leaf boundaries.
  2. Apply super::erasure::erasure_downgrade to encoding — peers that don’t advertise Reed-Solomon support get Replicated so they don’t see a stripe layout they can’t reconstruct.
  3. If tree_probe.check() == false, force the Manifest path (Tree-incompatible peer). Caps at 16 GiB; oversize streams return BlobError::Backend.
  4. Else if size_hint < TREE_THRESHOLD_BYTES, prefer the Manifest path for round-trip efficiency.
  5. Else use the Tree path with the (possibly downgraded) encoding + chunking.

size_hint is the producer’s best estimate of total bytes — None defaults to “above threshold,” routing the stream through Tree. The decision is one-way: a stream routed to Manifest can’t switch to Tree mid-stream because Manifest’s buffered path has already committed to in-memory accumulation.

Phase A6: the TreeSupportProbe::Dynamic arm wires future capability-tag advertisement; v0.3a callers without that substrate use AlwaysSupported for single-cluster deployments or ForceManifest for cross-version cluster rollouts. The CDC + erasure probes mirror the same shape one-for-one.

Source

pub fn chunk_channel_for_hash(hash: &[u8; 32]) -> ChannelName

Channel name for a given chunk hash. Public accessor so e2e tests + operator tools can construct chunk channels for Redex::open_file / replication_coordinator_for lookups without re-implementing the dataforts/blob/<hex32> format (and risking drift).

Source

pub async fn repair_blob( &self, blob_ref: &BlobRef, ) -> Result<RepairReport, BlobError>

Operator-driven Reed-Solomon repair sweep over the chunks reachable from blob_ref. Walks the manifest tree, inspects each ErasureLeaf stripe, and for any RS stripe that has at least one missing data chunk:

  1. Fetch every surviving chunk (data + parity) of the stripe.
  2. If >= k shards survive, run RS reconstruction.
  3. Re-store each previously-missing data chunk under its original content-addressed hash.

Stripes that are already healthy (every data chunk present) are skipped without I/O on the parity side. Stripes that have fewer than k survivors are counted as unrecoverable — repair_blob does NOT error on unrecoverable stripes; it records them in the report so the operator can take human action (restore from snapshot, accept data loss, etc.). A single unrecoverable stripe doesn’t abort repair of the rest of the blob.

Encoding::Replicated stripes (the small-stripe trailing fallback) have no parity model and are skipped with a dedicated counter.

Non-Tree blobs return a zero-counter report (no repair surface — Small and Manifest blobs have no parity).

The repair sweep is iterative (no concurrency for v0.3 Phase C7); a future commit may parallelise the per-stripe recovery across the BandwidthClass-aware send queue.

Trust model. This entry point is unauthenticated and intended for system-internal callers: the operator CLI running against a local store, an in-process scheduled repair cadence (if one ever lands), and unit tests. A peer- initiated / network-exposed repair must route through Self::repair_blob_authorized instead, because the sweep walks every chunk of the blob (full disk + CPU cost) and is trivially amplifiable into a DoS by an attacker who can reach this surface without a capability check.

Source

pub async fn repair_blob_authorized( &self, blob_ref: &BlobRef, origin_hash: u64, channel: &ChannelName, ) -> Result<RepairReport, BlobError>

Capability-gated wrapper around Self::repair_blob. Mirrors the Self::pin_authorized / Self::unpin_authorized / Self::delete_chunk_authorized pattern: the adapter must have an AuthGuard configured, and the caller must be authorized for (origin_hash, channel) per auth_allows_blob_op. Returns BlobError::Unauthorized on either failure.

This is the peer-initiated / network-exposed repair entry. repair_blob walks the entire tree, fetches every chunk, hashes each, constructs an RS encoder per stripe, and may re-store reconstructed bytes — a hostile caller running it across many blobs amplifies I/O and CPU substantially, so it must not be reachable without the capability check.

Source§

impl MeshBlobAdapter

Source

pub async fn sync_blob(&self, blob_ref: &BlobRef) -> Result<(), BlobError>

Flush every chunk file referenced by blob_ref to disk. Used by publish_with_blob (see super::publish_with_blob) under BlobDurability::DurableOnLocal to satisfy “blob survives local node restart” before the publish step. No-op for BestEffort; ReplicatedTo(n) composes this with a wait-for-replicas poll above.

Iterates BlobRef::Small as a single chunk; iterates BlobRef::Manifest over every ChunkRef. Each chunk’s underlying RedexFile::sync runs sequentially — the call order is stable but partial-progress on error means some chunks may have been flushed before the failure point. Surface as BlobError::Backend for the operator to retry / inspect.

Trait Implementations§

Source§

impl BlobAdapter for MeshBlobAdapter

Source§

fn prefetch<'life0, 'life1, 'async_trait>( &'life0 self, blob_ref: &'life1 BlobRef, ) -> Pin<Box<dyn Future<Output = Result<(), BlobError>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, MeshBlobAdapter: 'async_trait,

Open each chunk channel against the local Redex handle using the adapter’s existing chunk_file_config. When replication is configured + active on the underlying handle, the per-channel runtime spawned by open_file begins syncing from peers carrying the chunk’s causal:<hex> advertisement — that’s the cross-node fetch path. Returns Ok(()) as soon as every chunk channel has been opened; the actual chunk arrival is asynchronous and reachable via fetch / exists once the replication-runtime sync completes.

No-op when the chunk is already locally present (the open_file fast path on the existing entry skips the spawn; the chunk-file len() check on a subsequent fetch returns the bytes without going over the network).

Source§

fn adapter_id(&self) -> &str

Stable identifier for this adapter instance. The registry rejects re-registrations with the same id.
Source§

fn accepted_schemes(&self) -> &[&str]

URI schemes this adapter accepts on inbound BlobRefs. The substrate’s blob-dispatch layer routes by channel- configured blob_adapter_id; before invoking the adapter it checks the inbound URI’s scheme against this list and rejects with BlobError::UnsupportedScheme when the URI scheme isn’t accepted. Default returns an empty slice, which means “accept anything” — adapters in trusted / single-tenant deployments may leave this as-is, but adapters that have authority over a privileged backend (FS adapter, host-side keys, etc.) should override and list the schemes they actually serve so a publisher with append rights cannot dictate arbitrary URIs the adapter then resolves.
Source§

fn store<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, blob_ref: &'life1 BlobRef, bytes: &'life2 [u8], ) -> Pin<Box<dyn Future<Output = Result<(), BlobError>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, MeshBlobAdapter: 'async_trait,

Persist bytes at the URI carried in blob_ref. Most adapters will derive the URI from blob_ref.hash (content- addressing) and ignore the inbound URI; some (e.g. FileSystemAdapter) honor it directly. The hash on blob_ref is the source of truth — the substrate computes it before calling this method.
Source§

fn fetch<'life0, 'life1, 'async_trait>( &'life0 self, blob_ref: &'life1 BlobRef, ) -> Pin<Box<dyn Future<Output = Result<Bytes, BlobError>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, MeshBlobAdapter: 'async_trait,

Fetch the full content at blob_ref.uri. The substrate runs BlobRef::verify on the returned bytes; on a mismatch the call as a whole fails with BlobError::HashMismatch. Read more
Source§

fn fetch_range<'life0, 'life1, 'async_trait>( &'life0 self, blob_ref: &'life1 BlobRef, range: Range<u64>, ) -> Pin<Box<dyn Future<Output = Result<Bytes, BlobError>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, MeshBlobAdapter: 'async_trait,

Fetch a byte range. range.start <= range.end and both bounded by blob_ref.size; out-of-range queries surface as BlobError::Backend from the adapter. The substrate does NOT verify partial fetches against the full-content hash; callers using range fetch are accepting that trade-off. Read more
Source§

fn exists<'life0, 'life1, 'async_trait>( &'life0 self, blob_ref: &'life1 BlobRef, ) -> Pin<Box<dyn Future<Output = Result<bool, BlobError>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, MeshBlobAdapter: 'async_trait,

Probe for existence without fetching. Adapters that cannot answer cheaply may emulate by fetch + drop; the trait makes no efficiency promise.
Source§

fn delete<'life0, 'life1, 'async_trait>( &'life0 self, _blob_ref: &'life1 BlobRef, ) -> Pin<Box<dyn Future<Output = Result<(), BlobError>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, MeshBlobAdapter: 'async_trait,

Best-effort delete. The substrate calls this on the GC sweep path (v0.2 MeshBlobAdapter); external-storage adapters (S3 / IPFS) typically defer durability decisions to the backend’s own lifecycle policies and may treat this as a no-op. Read more
Source§

fn stat<'life0, 'life1, 'async_trait>( &'life0 self, blob_ref: &'life1 BlobRef, ) -> Pin<Box<dyn Future<Output = Result<BlobStat, BlobError>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, MeshBlobAdapter: 'async_trait,

Return an operational snapshot of the blob. Used by the net blob stat CLI + the metrics exporters; surfaces size, replica counts (where the adapter knows), encoding, etc. Read more
Source§

fn list<'life0, 'life1, 'async_trait>( &'life0 self, opts: &'life1 BlobListOptions, ) -> Pin<Box<dyn Future<Output = Result<Vec<BlobInventoryEntry>, BlobError>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, MeshBlobAdapter: 'async_trait,

Enumerate blob chunks the adapter has observed. Powers the operator-facing “Blob & Artifact Explorer” surface (DECK_PLAN.md § Deferred work § Blob & Artifact Explorer) — adapters that can cheaply enumerate (Mesh, fs) override; adapters with prohibitive enumeration cost (S3 with millions of keys, IPFS) leave the default “empty” so consumers don’t accidentally rack up backend charges. Read more
Source§

fn supports_list(&self) -> bool

Whether Self::list returns an authoritative enumeration. Read more
Source§

fn fetch_stream<'life0, 'life1, 'async_trait>( &'life0 self, blob_ref: &'life1 BlobRef, ) -> Pin<Box<dyn Future<Output = Result<Pin<Box<dyn Stream<Item = Result<Bytes, BlobError>> + Send>>, BlobError>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, Self: 'async_trait,

Stream the blob content as a sequence of byte chunks. Default impl routes through Self::fetch and emits the whole payload as a single chunk — fine for adapters that hold blobs in RAM or pull them in one shot anyway (S3 GetObject with no Range, IPFS). Adapters with real streaming backends (chunked HTTP, mmap’d local files, range-fetched S3) should override to yield progressively. Read more
Source§

fn store_stream<'life0, 'life1, 'async_trait>( &'life0 self, blob_ref: &'life1 BlobRef, stream: Pin<Box<dyn Stream<Item = Result<Bytes, BlobError>> + Send>>, size_hint: Option<u64>, ) -> Pin<Box<dyn Future<Output = Result<(), BlobError>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, Self: 'async_trait,

Store from a stream of byte chunks. Default impl drains the stream into a Vec<u8> and forwards to Self::store; adapters with real streaming write paths (S3 multipart upload, chunked filesystem write) should override. Read more
Source§

impl Clone for MeshBlobAdapter

Source§

fn clone(&self) -> MeshBlobAdapter

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more

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<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
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.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more