pub trait ChangeLog:
Debug
+ Send
+ Sync {
// Required methods
fn record<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
id: &'life1 ChangeId,
change: &'life2 Change,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn remove<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 ChangeId,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn scan<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<(ChangeId, Change)>>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
}Expand description
Durable write-ahead log for multi-step storage changes.
Records in-progress changes that span both HV and LT backends so that recovery can identify and clean up orphaned LT blobs after crashes. The log is stored independently from the data backend (though it may share infrastructure) and is scoped per service instance.
Recovery is garbage collection — it reads HV state to determine which blobs are unreferenced and deletes them. It never replays CAS mutations or finishes incomplete operations.
Implementations handle instance identity, heartbeats, and key prefixing internally — callers interact only with entries.
Required Methods§
Sourcefn record<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
id: &'life1 ChangeId,
change: &'life2 Change,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn record<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
id: &'life1 ChangeId,
change: &'life2 Change,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Records a change before any side effects begin (write-ahead).
Must be durable before returning — the caller will proceed with LT writes immediately after.
Sourcefn remove<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 ChangeId,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn remove<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 ChangeId,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Removes a completed change from the log.
Called after all cleanup (LT blob deletion) is finished. Removing a nonexistent entry is not an error (idempotent).
Sourcefn scan<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<(ChangeId, Change)>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn scan<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<(ChangeId, Change)>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Returns all outstanding changes eligible for recovery.
During normal operation this returns only the calling instance’s entries. During recovery of a dead instance, the implementation may return that instance’s entries after the caller has claimed ownership (via heartbeat CAS).
The returned entries are unordered.