Skip to main content

PrimaryReplication

Struct PrimaryReplication 

Source
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

Source

pub fn slot_path_for(data_path: &Path) -> PathBuf

Source

pub fn primary_replica_root_for(data_path: &Path) -> PathBuf

Source

pub fn slot_catalog_path_for(data_path: &Path) -> PathBuf

Source

pub fn new(data_path: Option<&Path>) -> Self

Source

pub fn new_with_config( data_path: Option<&Path>, config: &ReplicationConfig, ) -> Self

Source

pub fn append_logical_record(&self, lsn: u64, encoded: Vec<u8>)

Source

pub fn wait_for_logical_lsn_after( &self, since_lsn: u64, timeout: Duration, ) -> bool

Source

pub fn register_replica(&self, id: String) -> u64

Source

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.

Source

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.

Source

pub fn ensure_replica_registered( &self, id: &str, requested_since_lsn: u64, ) -> 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. A fresh slot starts at the replica’s requested cursor rather than the primary’s current LSN, so an empty replica does not skip WAL that was written before its first pull. Reconnects preserve existing progress and do not bump the topology epoch.

Source

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.

Source

pub fn topology_epoch(&self) -> u64

Current topology epoch. Strictly monotonic, bumps on every registry-shape change consumed by TopologyAdvertiser.

Source

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.

Source

pub fn ack_replica(&self, id: &str, lsn: u64)

Source

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.

Source

pub fn ack_replica_lsn_with_observability( &self, id: &str, applied_lsn: u64, durable_lsn: u64, apply_error_count: u64, divergence_count: u64, )

Source

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.

Source

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.

Source

pub fn replication_progress(&self) -> Option<ReplicationProgress>

Source

pub fn slot_snapshots(&self) -> Vec<ReplicationSlot>

Source

pub fn retention_floor_lsn(&self) -> Option<u64>

Source

pub fn prune_retained_wal_through(&self, archived_lsn: u64) -> Result<u64>

Source

pub fn replica_count(&self) -> usize

Source

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.

Source

pub fn touch_slot(&self, id: &str, now_ms: u128)

Source

pub fn enforce_retention_limits( &self, now_ms: u128, ) -> Vec<(String, ReplicationSlotInvalidationCause)>

Source

pub fn slot_rebootstrap_reason( &self, id: &str, requested_since_lsn: u64, oldest_available_lsn: Option<u64>, ) -> Option<ReplicationSlotInvalidationCause>

Source

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.

Source

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).

Source

pub fn full_resync_count(&self) -> u64

Number of pulls that forced a full re-bootstrap since process start (issue #839). Surfaced as reddb_replication_full_resync_total and in /replication/status — the primary operator alert signal.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<'a, T, E> AsTaggedExplicit<'a, E> for T
where T: 'a,

Source§

fn explicit(self, class: Class, tag: u32) -> TaggedParser<'a, Explicit, Self, E>

Source§

impl<'a, T, E> AsTaggedImplicit<'a, E> for T
where T: 'a,

Source§

fn implicit( self, class: Class, constructed: bool, tag: u32, ) -> TaggedParser<'a, Implicit, Self, E>

Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
Source§

impl<L> LayerExt<L> for L

Source§

fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>
where L: Layer<S>,

Applies the layer to a service and wraps it in Layered.
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<G1, G2> Within<G2> for G1
where G2: Contains<G1>,

Source§

fn is_within(&self, b: &G2) -> bool