pub struct WriteGate { /* private fields */ }Expand description
Live policy for public-mutation surfaces.
read_only was originally a bool snapshot taken at runtime
construction. PLAN.md Phase 4.3 promotes it to an AtomicBool so
POST /admin/readonly can flip the policy without a restart. The
ReplicationRole stays immutable — flipping a replica into a
primary mid-process would need a full handshake (Phase 3 work in
the data-safety plan), and shouldn’t be a single-flag decision.
Implementations§
Source§impl WriteGate
impl WriteGate
pub fn from_options(options: &RedDBOptions) -> Self
Sourcepub fn check(&self, kind: WriteKind) -> RedDBResult<()>
pub fn check(&self, kind: WriteKind) -> RedDBResult<()>
Returns Ok(()) if the public surface is allowed to perform kind.
Returns RedDBError::ReadOnly otherwise.
Reasoning order is intentional:
- Replica role — a replica booted with
read_only = falsemust still reject; this is a structural property. - Lease lost — the strongest serverless correctness signal. A writer that lost its lease must stop immediately; running while another holder has been promoted causes split-brain.
- Operator read-only flag — explicit /admin/readonly toggle or boot-time pin; lower priority than lease loss because the operator can revoke it without external coordination.
Sourcepub fn check_consent(&self, kind: WriteKind) -> RedDBResult<WriteConsent>
pub fn check_consent(&self, kind: WriteKind) -> RedDBResult<WriteConsent>
Same as check but on success returns a sealed
WriteConsent token. Mutating port methods that take
&OperationContext demand ctx.write_consent.is_some();
the only way to mint such a token is to call this method,
so forgetting to consult the gate becomes a structural
property — not a discipline question.
pub fn is_read_only(&self) -> bool
Sourcepub fn is_manual_read_only(&self) -> bool
pub fn is_manual_read_only(&self) -> bool
Whether the operator explicitly pinned this instance read-only
(via boot config or POST /admin/readonly). Distinct from
[is_read_only] which also returns true for structural
reasons (replica role, lease lost, archive-lag pause).
Sourcepub fn is_auto_paused(&self) -> bool
pub fn is_auto_paused(&self) -> bool
Whether the engine-managed archive-lag pause (#519) is
currently active. Mutually independent of [is_manual_read_only]
so callers like /backup/status can report both.
pub fn role(&self) -> &ReplicationRole
Sourcepub fn flow_control(&self) -> &FlowController
pub fn flow_control(&self) -> &FlowController
Issue #826 — borrow the write-admission flow controller. Callers
drive observe() from the primary’s replica registry and read
throttle state for /metrics.
Sourcepub fn is_flow_throttled(&self) -> bool
pub fn is_flow_throttled(&self) -> bool
Whether write admission is currently throttled by in-quorum
replica lag (issue #826). Distinct from [is_read_only] — a
throttle is transient back-pressure, not a read-only posture.
Sourcepub fn set_read_only(&self, enabled: bool) -> bool
pub fn set_read_only(&self, enabled: bool) -> bool
PLAN.md Phase 4.3 — dynamic read-only toggle. Flipping a
replica back to writable here is a no-op for check() because
the role check fires first; the operator must change the
replication role through a separate, audited path.
Returns the previous read_only value so callers can detect idempotent calls (toggle to the same value = no work to do).
Sourcepub fn lease_state(&self) -> LeaseGateState
pub fn lease_state(&self) -> LeaseGateState
Current writer-lease gate state. NotRequired for standalone,
replica, and lease-disabled serverless instances.
Sourcepub fn configure_archive_lag_pause(&self, threshold_secs: u64, baseline_ms: u64)
pub fn configure_archive_lag_pause(&self, threshold_secs: u64, baseline_ms: u64)
Issue #519 — install the archive-lag pause threshold and the
baseline “last archive observed at” stamp. Threshold 0
disables auto-pause; subsequent record_archive_success /
evaluate_archive_lag calls then become no-ops.
Idempotent: callers should invoke once during startup after
parsing REDDB_BACKUP_PAUSE_ON_LAG_SECS. Stamping last_archive_at_ms
to “now” at construction grants a threshold_secs grace
window before the first auto-pause can fire — without it, a
freshly-booted instance with a never-archived WAL would flip
to read-only on the first poll.
Sourcepub fn record_archive_success(&self, now_ms: u64)
pub fn record_archive_success(&self, now_ms: u64)
Stamp last_archive_at_ms after a successful remote archive.
Called by the WAL-archive task wrapper in service_cli after
runtime.trigger_backup() returns Ok.
Sourcepub fn archive_pause_threshold_secs(&self) -> u64
pub fn archive_pause_threshold_secs(&self) -> u64
Current archive-lag threshold in seconds. 0 means the
feature is disabled.
Sourcepub fn last_archive_at_ms(&self) -> u64
pub fn last_archive_at_ms(&self) -> u64
Last archive observation timestamp (unix ms).
Sourcepub fn evaluate_archive_lag(&self, now_ms: u64) -> bool
pub fn evaluate_archive_lag(&self, now_ms: u64) -> bool
Re-evaluate the archive-lag state. Returns the resulting
auto_paused value.
Semantics (issue #519):
- Threshold
0→ feature disabled, returns current state without writing. - Manual read-only is sticky — when [
is_manual_read_only] is true, this method never modifiesauto_paused. The operator must clear the manual pin first; only then does the auto-path take over again on the next tick. - Lag > threshold and manual=false → set
auto_paused = true. - Lag <= threshold and
auto_paused = true→ clear it (auto-resume). Ifauto_pausedwas already false, no-op.
Trait Implementations§
Auto Trait Implementations§
impl !Freeze for WriteGate
impl RefUnwindSafe for WriteGate
impl Send for WriteGate
impl Sync for WriteGate
impl Unpin for WriteGate
impl UnsafeUnpin for WriteGate
impl UnwindSafe for WriteGate
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