pub struct LogicalChangeApplier { /* private fields */ }Expand description
Shared logical change applier so replica replay and PITR converge on the same semantics. Stateful (PLAN.md Phase 11.5): tracks the last applied LSN + payload hash so duplicates / older LSNs / gaps / divergences are detected explicitly.
Implementations§
Source§impl LogicalChangeApplier
impl LogicalChangeApplier
Sourcepub fn new(starting_lsn: u64) -> LogicalChangeApplier
pub fn new(starting_lsn: u64) -> LogicalChangeApplier
Build a fresh applier. starting_lsn is the LSN already
covered by the snapshot (or 0 for an empty replica). The
next acceptable record is any positive LSN; from there the
chain advances by 1.
Sourcepub fn with_metrics(
starting_lsn: u64,
metrics: Arc<ReplicaApplyMetrics>,
) -> LogicalChangeApplier
pub fn with_metrics( starting_lsn: u64, metrics: Arc<ReplicaApplyMetrics>, ) -> LogicalChangeApplier
Build an applier that records apply misses / errors into a shared
ReplicaApplyMetrics (issue #814). The production replica loop
passes the runtime’s metrics so a swallowed delete leaves a trail
on reddb_replica_apply_errors_total{kind="apply_miss"}.
Sourcepub fn metrics(&self) -> &Arc<ReplicaApplyMetrics> ⓘ
pub fn metrics(&self) -> &Arc<ReplicaApplyMetrics> ⓘ
The metrics handle this applier records misses/errors into.
pub fn last_applied_lsn(&self) -> u64
pub fn received_frontier_lsn(&self) -> u64
pub fn last_applied_term(&self) -> u64
pub fn wait_for_bookmark( &self, bookmark: &CausalBookmark, timeout: Duration, ) -> Result<(), BookmarkWaitError>
Sourcepub fn apply(
&self,
db: &RedDB,
record: &ChangeRecord,
mode: ApplyMode,
) -> Result<ApplyOutcome, LogicalApplyError>
pub fn apply( &self, db: &RedDB, record: &ChangeRecord, mode: ApplyMode, ) -> Result<ApplyOutcome, LogicalApplyError>
Apply one logical change record. The state machine:
- first record after
starting_lsn == 0→ apply, anchor. lsn == last + 1→ apply, advance.lsn == last&& payload hash equal → idempotent skip.lsn == last&& payload hash differs →Divergence(fail closed).lsn < last→ older replay, skip with debug log.lsn > last + 1→Gap(fail closed; caller marks unhealthy).
Sourcepub fn apply_record(
db: &RedDB,
record: &ChangeRecord,
mode: ApplyMode,
) -> Result<(), RedDBError>
pub fn apply_record( db: &RedDB, record: &ChangeRecord, mode: ApplyMode, ) -> Result<(), RedDBError>
Stateless apply — applies the record without monotonicity
checks. Kept for callers that don’t yet thread the stateful
applier through. New code should prefer
LogicalChangeApplier::new() + apply(). Apply misses (delete
against a missing target) are recorded into a throwaway metrics
handle; use [apply_record_with_metrics] to surface them.
Sourcepub fn apply_record_with_metrics(
db: &RedDB,
record: &ChangeRecord,
_mode: ApplyMode,
metrics: &ReplicaApplyMetrics,
) -> Result<(), RedDBError>
pub fn apply_record_with_metrics( db: &RedDB, record: &ChangeRecord, _mode: ApplyMode, metrics: &ReplicaApplyMetrics, ) -> Result<(), RedDBError>
Stateless apply that records apply misses (issue #814) into
metrics. A delete against a missing collection or a missing
entity is a non-fatal divergence signal: it bumps
ApplyErrorKind::Miss and emits a structured warn line, but still
returns Ok(()) so the LSN chain advances and idempotent re-pull
(#813) converges. A genuine (non-missing-target) store error on a
delete propagates as a real apply error — counted, fail-closed —
rather than being swallowed by the old let _ =.
Auto Trait Implementations§
impl !Freeze for LogicalChangeApplier
impl RefUnwindSafe for LogicalChangeApplier
impl Send for LogicalChangeApplier
impl Sync for LogicalChangeApplier
impl Unpin for LogicalChangeApplier
impl UnsafeUnpin for LogicalChangeApplier
impl UnwindSafe for LogicalChangeApplier
Blanket Implementations§
Source§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
Source§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
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
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 moreSource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request