pub struct PrimaryReplication {
pub wal_buffer: Arc<WalBuffer>,
pub logical_wal_spool: Option<Arc<LogicalWalSpool>>,
pub replicas: RwLock<Vec<ReplicaState>>,
pub commit_waiter: Arc<CommitWaiter>,
/* private fields */
}Expand description
Primary replication manager.
Fields§
§wal_buffer: Arc<WalBuffer>§logical_wal_spool: Option<Arc<LogicalWalSpool>>§replicas: RwLock<Vec<ReplicaState>>§commit_waiter: Arc<CommitWaiter>PLAN.md Phase 11.4 — ack-driven commit synchronization. Always
allocated so the policy enum can flip from Local to
AckN/Quorum without touching this struct’s shape.
Implementations§
Source§impl PrimaryReplication
impl PrimaryReplication
pub fn slot_path_for(data_path: &Path) -> PathBuf
pub fn new(data_path: Option<&Path>) -> PrimaryReplication
pub fn new_with_config( data_path: Option<&Path>, config: &ReplicationConfig, ) -> PrimaryReplication
pub fn append_logical_record(&self, lsn: u64, encoded: Vec<u8>)
pub fn wait_for_logical_lsn_after( &self, since_lsn: u64, timeout: Duration, ) -> bool
pub fn register_replica(&self, id: String) -> u64
Sourcepub fn register_replica_with_region(
&self,
id: String,
region: Option<String>,
) -> u64
pub fn register_replica_with_region( &self, id: String, region: Option<String>, ) -> u64
Register a replica with an explicit region tag (Phase 2.6 multi-region).
Preferred when the replica handshake declares a region — the quorum
coordinator uses this field to decide whether the replica counts
toward a QuorumMode::Regions commit.
Idempotent on reconnect (issue #812): if a replica with id is
already registered, the existing entry is updated in place rather
than duplicated — progress LSNs (last_acked_lsn, last_sent_lsn,
last_durable_lsn) are preserved so a reconnecting replica is not
rewound, only last_seen_at_unix_ms is refreshed (and region when
a non-None value is supplied). A re-registration is not a
registry-shape change, so it does not bump the topology epoch.
Returns the slot restart_lsn the replica should resume streaming from:
the current WAL LSN for a fresh registration, or the durable slot
restart point for a reconnect.
Sourcepub fn set_replica_rebootstrapping(
&self,
id: &str,
rebootstrapping: bool,
) -> bool
pub fn set_replica_rebootstrapping( &self, id: &str, rebootstrapping: bool, ) -> bool
Mark (or clear) a replica’s re-bootstrap state (issue #837).
While rebootstrapping is true the replica keeps serving
non-causal reads from its existing data, but the advertiser
surfaces the flag so causal (bookmark) reads route to a
caught-up peer instead — the rebuilding replica’s applied
frontier describes data it is about to discard. The primary
flips this back to false when the replica reports its atomic
snapshot swap complete.
A change to the flag is a registry-shape change for routing
purposes, so it bumps the topology epoch to force consumers to
re-read the advertisement. Returns true when a replica with
id was present and updated.
Sourcepub fn ensure_replica_registered(&self, id: &str) -> bool
pub fn ensure_replica_registered(&self, id: &str) -> bool
Ensure a replica identifying itself with id is present in the
registry (issue #812). This is the production self-registration hook
used by the pull_wal_records path: the first time a replica sends
its replica_id on a pull, the primary registers it so it is no
longer blind to that replica’s existence; subsequent pulls are
idempotent no-ops. Returns true when a new registration was
created. Delegates to register_replica_with_region, so reconnects
preserve progress and do not bump the topology epoch.
Sourcepub fn unregister_replica(&self, id: &str) -> bool
pub fn unregister_replica(&self, id: &str) -> bool
Unregister a replica by id. Returns true when the replica
was present (and removed). Bumps the topology epoch so a
pending advertisement reflects the new fleet size.
Sourcepub fn topology_epoch(&self) -> u64
pub fn topology_epoch(&self) -> u64
Current topology epoch. Strictly monotonic, bumps on every
registry-shape change consumed by TopologyAdvertiser.
Sourcepub fn bump_topology_epoch(&self)
pub fn bump_topology_epoch(&self)
Advance the topology epoch. Call sites: register, unregister,
and the health-sweep tick that flips a replica between
healthy/unhealthy. Wrapping is not a concern in practice
(u64::MAX events would take centuries at any realistic ack
rate) but fetch_add saturates implicitly via wrap-around;
the consumer treats epoch as opaque so a wrap is still
strictly “different” from the previous value.
pub fn ack_replica(&self, id: &str, lsn: u64)
Sourcepub fn ack_replica_lsn(&self, id: &str, applied_lsn: u64, durable_lsn: u64)
pub fn ack_replica_lsn(&self, id: &str, applied_lsn: u64, durable_lsn: u64)
PLAN.md Phase 11.4 — replica reports applied + durable LSN
after persisting a batch. Idempotent: only advances LSNs
monotonically. last_seen_at_unix_ms always refreshes.
Also signals commit_waiter so any thread blocked on
ack_n / quorum can wake and re-check its threshold.
pub fn ack_replica_lsn_with_observability( &self, id: &str, applied_lsn: u64, durable_lsn: u64, apply_error_count: u64, divergence_count: u64, )
Sourcepub fn note_replica_pull(&self, id: &str, last_sent_lsn: u64)
pub fn note_replica_pull(&self, id: &str, last_sent_lsn: u64)
PLAN.md Phase 11.4 — primary records the LSN it last sent to a
replica via pull_wal_records. Helpful for lag_records = last_sent_lsn - last_acked_lsn to distinguish pull-side delay
from apply-side delay.
Sourcepub fn replica_snapshots(&self) -> Vec<ReplicaState>
pub fn replica_snapshots(&self) -> Vec<ReplicaState>
Snapshot of all currently registered replicas, for /metrics + /admin/status. Returns owned clones so callers don’t hold the lock during serialization.
pub fn replication_progress(&self) -> Option<ReplicationProgress>
pub fn slot_snapshots(&self) -> Vec<ReplicationSlot>
pub fn retention_floor_lsn(&self) -> Option<u64>
pub fn prune_retained_wal_through( &self, archived_lsn: u64, ) -> Result<u64, Error>
pub fn replica_count(&self) -> usize
Sourcepub fn current_logical_lsn(&self) -> u64
pub fn current_logical_lsn(&self) -> u64
Current primary write position (logical WAL LSN, falling back to the in-memory WAL buffer). Used as the reference point for per-replica lag — including issue #826 flow control.
pub fn touch_slot(&self, id: &str, now_ms: u128)
pub fn enforce_retention_limits( &self, now_ms: u128, ) -> Vec<(String, SlotInvalidationCause)>
pub fn slot_rebootstrap_reason( &self, id: &str, requested_since_lsn: u64, oldest_available_lsn: Option<u64>, ) -> Option<SlotInvalidationCause>
Sourcepub fn plan_replica_resume(
&self,
id: &str,
requested_since_lsn: u64,
oldest_available_lsn: Option<u64>,
) -> ResumeMode
pub fn plan_replica_resume( &self, id: &str, requested_since_lsn: u64, oldest_available_lsn: Option<u64>, ) -> ResumeMode
Decide how a reconnecting replica’s pull should be served
(issue #832). If the slot is invalidated or the requested
position has fallen behind the retained WAL floor, the replica
must re-bootstrap; otherwise it resumes via a partial resync
from its slot position (never rewound behind it). Every
partial-resync decision bumps the partial_resync_count metric
so a brief disconnect that recovers without a full re-bootstrap
is observable.
Sourcepub fn partial_resync_count(&self) -> u64
pub fn partial_resync_count(&self) -> u64
Number of pulls served as a partial resync since process start. Surfaced in the replication metrics/status payload (issue #832).
Auto Trait Implementations§
impl !Freeze for PrimaryReplication
impl RefUnwindSafe for PrimaryReplication
impl Send for PrimaryReplication
impl Sync for PrimaryReplication
impl Unpin for PrimaryReplication
impl UnsafeUnpin for PrimaryReplication
impl UnwindSafe for PrimaryReplication
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