pub trait PgCacheConn: Send + Sync {
// Required methods
fn select<'life0, 'life1, 'async_trait>(
&'life0 self,
table: PgTable,
key: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<Vec<u8>>, StoreError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait;
fn upsert<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
table: PgTable,
key: &'life1 str,
value: &'life2 [u8],
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait;
fn delete<'life0, 'life1, 'async_trait>(
&'life0 self,
table: PgTable,
key: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait;
fn keys<'life0, 'async_trait>(
&'life0 self,
table: PgTable,
) -> Pin<Box<dyn Future<Output = Result<Vec<String>, StoreError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
Self: 'async_trait;
fn keys_with_prefix<'life0, 'life1, 'async_trait>(
&'life0 self,
table: PgTable,
prefix: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Vec<String>, StoreError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait;
fn clear<'life0, 'async_trait>(
&'life0 self,
table: PgTable,
) -> Pin<Box<dyn Future<Output = Result<u64, StoreError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
Self: 'async_trait;
fn upsert_nar_chunk<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
key: &'life1 str,
seq: i32,
value: &'life2 [u8],
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait;
fn select_nar_chunk<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
seq: i32,
) -> Pin<Box<dyn Future<Output = Result<Option<Vec<u8>>, StoreError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait;
fn delete_nar_chunks<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait;
fn clear_nar_chunks<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<u64, StoreError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
Self: 'async_trait;
fn select_nar_window<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
offset: i64,
len: i32,
) -> Pin<Box<dyn Future<Output = Result<Option<(Vec<u8>, i64)>, StoreError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait;
// Provided method
fn ensure_schema<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
Self: 'async_trait { ... }
}Expand description
The minimal typed Postgres row-verb surface PgStorageBackend depends on.
This is the injectable Environment seam: a real implementation
([SqlxPgCacheConn], postgres feature) talks to a live Postgres pool; tests
substitute an in-memory mock. Keeping the surface this small means the whole L2
mapping is proven against a mock, and the only unmocked code is the thin
SQL translation.
Required Methods§
Sourcefn select<'life0, 'life1, 'async_trait>(
&'life0 self,
table: PgTable,
key: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<Vec<u8>>, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn select<'life0, 'life1, 'async_trait>(
&'life0 self,
table: PgTable,
key: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<Vec<u8>>, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
SELECT value FROM <table> WHERE key = $1 — raw bytes, or Ok(None) on a
missing row.
Sourcefn upsert<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
table: PgTable,
key: &'life1 str,
value: &'life2 [u8],
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
fn upsert<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
table: PgTable,
key: &'life1 str,
value: &'life2 [u8],
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
Upsert (INSERT … ON CONFLICT (key) DO UPDATE) — idempotent by key; a
re-put of a content-addressed key overwrites with identical bytes.
Sourcefn delete<'life0, 'life1, 'async_trait>(
&'life0 self,
table: PgTable,
key: &'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,
table: PgTable,
key: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
DELETE FROM <table> WHERE key = $1 — idempotent; deleting an absent key
is Ok(()).
Sourcefn keys<'life0, 'async_trait>(
&'life0 self,
table: PgTable,
) -> Pin<Box<dyn Future<Output = Result<Vec<String>, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
fn keys<'life0, 'async_trait>(
&'life0 self,
table: PgTable,
) -> Pin<Box<dyn Future<Output = Result<Vec<String>, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
SELECT key FROM <table> — the authoritative full key set (this is a
durable tier, not a partial hot cache).
Sourcefn keys_with_prefix<'life0, 'life1, 'async_trait>(
&'life0 self,
table: PgTable,
prefix: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Vec<String>, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn keys_with_prefix<'life0, 'life1, 'async_trait>(
&'life0 self,
table: PgTable,
prefix: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Vec<String>, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
SELECT key FROM <table> WHERE starts_with(key, $1) — the key set under
one prefix.
REQUIRED, not defaulted, and not “fetch keys and filter
in Rust”: the reverse-index lookup runs once per delete, and filtering
client-side would make it O(every edge in the cache) per call while the
primary-key btree can answer it as a range scan.
Sourcefn clear<'life0, 'async_trait>(
&'life0 self,
table: PgTable,
) -> Pin<Box<dyn Future<Output = Result<u64, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
fn clear<'life0, 'async_trait>(
&'life0 self,
table: PgTable,
) -> Pin<Box<dyn Future<Output = Result<u64, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
DELETE FROM <table> — clear the whole table, returning the row count
removed. The typed whole-store wipe primitive (the inverse of a warm
push); reaches NAR rows a per-key delete cannot.
Sourcefn upsert_nar_chunk<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
key: &'life1 str,
seq: i32,
value: &'life2 [u8],
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
fn upsert_nar_chunk<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
key: &'life1 str,
seq: i32,
value: &'life2 [u8],
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
Upsert one bounded chunk of a NAR. seq is 0..n, or
[CHUNK_MARKER_SEQ] for the completeness marker.
Sourcefn select_nar_chunk<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
seq: i32,
) -> Pin<Box<dyn Future<Output = Result<Option<Vec<u8>>, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn select_nar_chunk<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
seq: i32,
) -> Pin<Box<dyn Future<Output = Result<Option<Vec<u8>>, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Read one chunk back. Ok(None) when that (key, seq) row is absent.
Sourcefn delete_nar_chunks<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn delete_nar_chunks<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Delete every chunk (and the marker) of key. Idempotent.
Sourcefn clear_nar_chunks<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<u64, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
fn clear_nar_chunks<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<u64, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
DELETE FROM sui_cache_nar_chunk — clear the chunk table, returning the
row count removed.
Sourcefn select_nar_window<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
offset: i64,
len: i32,
) -> Pin<Box<dyn Future<Output = Result<Option<(Vec<u8>, i64)>, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn select_nar_window<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
offset: i64,
len: i32,
) -> Pin<Box<dyn Future<Output = Result<Option<(Vec<u8>, i64)>, StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Read a bounded window of a legacy whole-value NAR row, returning
(window_bytes, total_byte_length); Ok(None) when the row is absent.
offset is 1-based (Postgres substr semantics). This exists so rows
written by the pre-streaming build — every NAR already in the production
database — can be served without materializing them. Without it the
read path would stay unbounded until the cache happened to turn over.
Provided Methods§
Sourcefn ensure_schema<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
fn ensure_schema<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<(), StoreError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
Idempotently (re-)create every table this connection serves.
This is the self-heal verb. PgStorageBackend calls it when a row
verb reports StoreError::SchemaMissing, then retries the verb once —
so a durable tier that comes back on an empty volume repairs itself on
the next request instead of erroring until someone restarts the process.
It must be safe to call at any time, any number of times
(CREATE TABLE IF NOT EXISTS), including concurrently.
The default is a no-op, so a backend whose schema cannot go missing (an
in-memory mock) needs no implementation. A backend that does return
SchemaMissing must override this — otherwise the retry re-runs against
the same absent schema and fails identically, which is still correct, just
unhealed.
§Errors
Returns an error if the DDL cannot be executed.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".