pub struct PgStorageBackend<C>where
C: PgCacheConn,{ /* private fields */ }Expand description
L2 durable cache tier: content-addressed key → value over Postgres, shared across pods, survives a roll.
Generic over the PgCacheConn seam so it is fully testable against a mock.
Implementations§
Source§impl<C> PgStorageBackend<C>where
C: PgCacheConn,
impl<C> PgStorageBackend<C>where
C: PgCacheConn,
Sourcepub fn new(conn: C) -> PgStorageBackend<C>
pub fn new(conn: C) -> PgStorageBackend<C>
Wrap a PgCacheConn.
Trait Implementations§
Source§impl<C> NarRefIndex for PgStorageBackend<C>where
C: PgCacheConn + 'static,
The reverse index as one zero-value row per edge in sui_cache_nar_ref.
impl<C> NarRefIndex for PgStorageBackend<C>where
C: PgCacheConn + 'static,
The reverse index as one zero-value row per edge in sui_cache_nar_ref.
The key is the canonical NarRefKey, so the referrer lookup is a
primary-key range scan under NarRefScan rather than a table sweep.
Source§fn record<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
nar_path: &'life1 str,
hash: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
PgStorageBackend<C>: 'async_trait,
fn record<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
nar_path: &'life1 str,
hash: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
PgStorageBackend<C>: 'async_trait,
Source§fn forget<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
nar_path: &'life1 str,
hash: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
PgStorageBackend<C>: 'async_trait,
fn forget<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
nar_path: &'life1 str,
hash: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
PgStorageBackend<C>: 'async_trait,
Ok(()). Read moreSource§fn referrers<'life0, 'life1, 'async_trait>(
&'life0 self,
nar_path: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Vec<String>, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
PgStorageBackend<C>: 'async_trait,
fn referrers<'life0, 'life1, 'async_trait>(
&'life0 self,
nar_path: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Vec<String>, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
PgStorageBackend<C>: 'async_trait,
nar_path, sorted and
deduplicated. Read moreSource§impl<C> StorageBackend for PgStorageBackend<C>where
C: PgCacheConn + 'static,
impl<C> StorageBackend for PgStorageBackend<C>where
C: PgCacheConn + 'static,
Source§fn delete_nar_record<'life0, 'life1, 'async_trait>(
&'life0 self,
nar_path: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
PgStorageBackend<C>: 'async_trait,
fn delete_nar_record<'life0, 'life1, 'async_trait>(
&'life0 self,
nar_path: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
PgStorageBackend<C>: 'async_trait,
Remove a NAR by key, clearing both generations.
A key may exist as a legacy whole-value row (written before the streaming path) or as chunk rows, and a NAR that was re-pushed across the change can be both. Dropping only one leaves the other still readable, so a “deleted” NAR would keep serving.
Source§fn nar_residency(&self) -> NarResidency
fn nar_residency(&self) -> NarResidency
O(chunk). A NAR crosses the wire as NAR_CHUNK_BYTES rows in both
directions; no statement ever binds or returns the whole value.
Source§fn get_nar_stream<'life0, 'life1, 'async_trait>(
&'life0 self,
path: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<Pin<Box<dyn Stream<Item = Result<Bytes, StoreError>> + Send>>>, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
PgStorageBackend<C>: 'async_trait,
fn get_nar_stream<'life0, 'life1, 'async_trait>(
&'life0 self,
path: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<Pin<Box<dyn Stream<Item = Result<Bytes, StoreError>> + Send>>>, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
PgStorageBackend<C>: 'async_trait,
Read a NAR back as bounded chunks, from either storage generation.
Chunked rows are checked first (via the marker); a key with no marker
falls back to windowing a legacy whole-value row with substr. Both
arms are O(chunk) — the fallback exists so the NARs already in the
production database are servable without materializing them, not as a
buffered escape hatch.
Source§fn put_nar_stream<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
path: &'life1 str,
src: &'life2 dyn NarSource,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
PgStorageBackend<C>: 'async_trait,
fn put_nar_stream<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
path: &'life1 str,
src: &'life2 dyn NarSource,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
PgStorageBackend<C>: 'async_trait,
Write a NAR as bounded chunk rows, publishing with a marker written last.
Order is the invariant, not a convention:
- drop any prior chunks and the legacy whole row — a stale marker or a stale legacy row would otherwise shadow the new value;
- write chunks
0..n, each a bounded bind; - write the marker.
A failure anywhere in (1)–(2) leaves no marker, so the key reads as a clean miss. There is no window in which a reader can observe a truncated NAR.
Source§fn wipe_all<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<usize, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
PgStorageBackend<C>: 'async_trait,
fn wipe_all<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<usize, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
PgStorageBackend<C>: 'async_trait,
Complete L2 wipe: truncate the narinfo, legacy NAR, NAR-chunk and
reverse-edge tables. Unlike the per-hash delete, this reclaims NAR rows
wholesale. Returns the narinfo row count.
Source§fn get_narinfo<'life0, 'life1, 'async_trait>(
&'life0 self,
hash: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<String>, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
PgStorageBackend<C>: 'async_trait,
fn get_narinfo<'life0, 'life1, 'async_trait>(
&'life0 self,
hash: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<String>, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
PgStorageBackend<C>: 'async_trait,
Source§fn put_narinfo_record<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
hash: &'life1 str,
content: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
PgStorageBackend<C>: 'async_trait,
fn put_narinfo_record<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
hash: &'life1 str,
content: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
PgStorageBackend<C>: 'async_trait,
Source§fn delete_narinfo_record<'life0, 'life1, 'async_trait>(
&'life0 self,
hash: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
PgStorageBackend<C>: 'async_trait,
fn delete_narinfo_record<'life0, 'life1, 'async_trait>(
&'life0 self,
hash: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
PgStorageBackend<C>: 'async_trait,
Ok(()). Read moreSource§fn nar_ref_index(&self) -> &dyn NarRefIndex
fn nar_ref_index(&self) -> &dyn NarRefIndex
Source§fn get_nar<'life0, 'life1, 'async_trait>(
&'life0 self,
path: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<Vec<u8>>, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
PgStorageBackend<C>: 'async_trait,
fn get_nar<'life0, 'life1, 'async_trait>(
&'life0 self,
path: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<Vec<u8>>, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
PgStorageBackend<C>: 'async_trait,
Source§fn put_nar<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
path: &'life1 str,
data: &'life2 [u8],
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
PgStorageBackend<C>: 'async_trait,
fn put_nar<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
path: &'life1 str,
data: &'life2 [u8],
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
PgStorageBackend<C>: 'async_trait,
Source§fn list_narinfos<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<String>, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
PgStorageBackend<C>: 'async_trait,
fn list_narinfos<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<String>, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
PgStorageBackend<C>: 'async_trait,
Source§fn put_narinfo<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
hash: &'life1 str,
content: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
fn put_narinfo<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
hash: &'life1 str,
content: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
Source§fn advertised_nar<'life0, 'life1, 'async_trait>(
&'life0 self,
hash: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<String>, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn advertised_nar<'life0, 'life1, 'async_trait>(
&'life0 self,
hash: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<String>, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Source§fn delete<'life0, 'life1, 'async_trait>(
&'life0 self,
hash: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn delete<'life0, 'life1, 'async_trait>(
&'life0 self,
hash: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Source§fn reindex_nar_refs<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<usize, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
fn reindex_nar_refs<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<usize, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
Auto Trait Implementations§
impl<C> Freeze for PgStorageBackend<C>
impl<C> RefUnwindSafe for PgStorageBackend<C>where
C: RefUnwindSafe,
impl<C> Send for PgStorageBackend<C>
impl<C> Sync for PgStorageBackend<C>
impl<C> Unpin for PgStorageBackend<C>
impl<C> UnsafeUnpin for PgStorageBackend<C>
impl<C> UnwindSafe for PgStorageBackend<C>where
C: RefUnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more