Skip to main content

Module fence

Module fence 

Source
Expand description

Stale-term fencing for a returning ex-primary (issue #835, PRD #819, ADR 0030).

After a failover the cluster serves a new term. A former primary that rejoins on its old, stale term must not be able to corrupt the new timeline — its term-stamped writes and its stream handshakes have to be refused until it re-syncs and adopts the new term. This module is the reusable term-comparison primitive both fencing boundaries share:

  • Apply boundary — a replica rejects a WAL/logical record whose term is behind its current term. The live replica apply path enforces this directly in super::logical::LogicalChangeApplier::apply (it already tracks the last-applied term); TermFence::admit_record is the same rule expressed over a durable term so it survives a restart.
  • Handshake boundary — when a node opens a replication stream it declares the term it is streaming under. TermFence::admit_handshake refuses a handshake whose declared term is behind the current term, so a stale ex-primary cannot even establish the stream.
  • Lease boundary — a serverless writer lease is stamped with the term it was taken under; a holder whose term is behind the current term fails closed before mutating remote artifacts.

The decision is deliberately the data-path twin of the election-side super::RefusalReason::StaleTerm:

  • incoming == currentadmit at the live term;
  • incoming > current → a newer timeline supersedes ours, so adopt the new term (persisted durably) and then admit. This is how a replica moves forward when the legitimate new primary streams to it;
  • incoming < currentfenced: a superseded primary, refused.

The current term is held behind a TermStore so adoption is durable — a replica that crashes after adopting term N comes back fencing stale term N-1 records rather than briefly accepting them. Production wires the file-backed store alongside the node’s other durable replication state; tests use the in-memory store.

Structs§

FileTermStore
MemoryTermStore
In-memory term store for tests and ephemeral nodes.
StaleTermFenced
Why the term fence refused a message: the incoming term is behind the current term, so the sender is a deposed primary on a superseded timeline.
StreamHandshake
A replication-stream handshake as seen by the admitting replica.
TermFence
The stale-term fence. Wraps a durable TermStore and applies the term rule at the apply and handshake boundaries.

Enums§

FenceBoundary
The boundary at which a term-stamped message is being admitted. Only affects diagnostics — the term rule is identical at both.
FenceVerdict
The verdict of the term fence for one incoming term-stamped message.
TermStoreError
Error reading or persisting the durable current term.

Traits§

TermStore
Durable store for a node’s current replication term. The default (when nothing was ever written) is DEFAULT_REPLICATION_TERM, matching the term records carry before any failover.

Functions§

term_is_stale
The one shared stale-term predicate: only a strictly older incoming term is stale. Equal terms are retries; newer terms are adoption candidates.

Type Aliases§

StaleTermRejection