Skip to main content

ControlDb

Struct ControlDb 

Source
pub struct ControlDb { /* private fields */ }
Expand description

The one redb::Database under the control plane — and the door the runtime data-set growth takes it off the stripe through.

RedbControlStore and [RedbSecretStore] both hold an Arc of this rather than of the database, so that ONE call can close the file under every handle in the process and one call can reopen it, with nothing upstream — AuthTable, RepoCatalog, the SSH Control, the gRPC gate — holding a stale descriptor that would pin the mount. That is the whole mechanism behind DATA-SET-GROWTH-FLOW.md G4/T2: control.redb lives on the stripe, every SSH authentication reads it at call time, and the stripe has to be unmounted for the members to be grown. So:

  • ControlDb::suspend takes the write side (waiting for in-flight transactions), copies the tables into a RamCopy, and drops the database — the file is closed and umount /data can succeed;
  • while suspended every read is served from the copy, byte for byte, so principal_by_fingerprint, the grant check and the bootstrap state keep answering; every write is Error::OffStripe;
  • ControlDb::resume reopens the file, compares every document pointer on disk with the copy (they must agree — no write got through) and drops the copy.

An in-memory database (tests, --dry-run) has no file to close: it is kept, and suspend still switches every reader onto the copy and every writer onto the refusal, so the semantics are testable without a disk.

Implementations§

Source§

impl ControlDb

Source

pub fn export(&self) -> Result<ControlExport>

ControlExport of the live database (or of the RAM copy while suspended), in one read transaction.

Source§

impl ControlDb

Source

pub fn export_each<E>( &self, row: &mut dyn FnMut(ExportRow<'_>) -> Result<(), E>, ) -> Result<Result<(), E>>

ControlDb::export, row by row — every blob, then every document pointer, then every secret row, each handed to row as it is read, in one read transaction. What a twin snapshot streams: the database never lies in memory whole. row’s error stops the scan and comes back as Ok(Err(e)); the database’s own faults are the outer error.

Source

pub fn view(&self) -> Result<ControlView>

A consistent view of the whole database, taken NOW and read LATER (R5.1-A, 2026-10-07): a redb read transaction (MVCC — it holds the state of this instant while writers go on), or the RAM copy while the store is off the stripe. What a snapshot takes under the log’s freeze, so it can stream the rows AFTER the freeze is gone.

Said plainly: while a view lives, redb keeps the pages it reads and the file stays open — a growth that takes the store off the stripe meanwhile cannot unmount until the view goes.

Source§

impl ControlDb

Source

pub fn is_suspended(&self) -> bool

Is the store off the stripe right now?

Source

pub fn ram_copy(&self) -> Option<RamCopy>

The RAM copy, while suspended.

Source

pub fn begin_group(&self) -> Result<()>

Open a group on this thread (perf twin-apply-fsync, 2026-10-06): every write this thread makes through the stores over this database goes into ONE transaction until ControlDb::commit_group or ControlDb::abort_group. Writes from other threads wait for it (redb takes one writer at a time); reads see the state before it. A twin’s follower holds one for the control-plane entries of each group it takes.

Source

pub fn commit_group(&self, key: &str, seq: u64, mark: bool) -> Result<bool>

End the group with ONE durable commit, the marker key = seq inside it — when it wrote anything, or mark asks for the marker anyway. A group that wrote nothing and is not asked to mark is dropped (no I/O). A group a write failed in is aborted whole and the failure answered: none of it is kept. Answers whether it committed.

Source

pub fn durable_commits(&self) -> u64

How many durable commits (one fsync each) this database made since it was opened — what the I/O tests hold to a bound.

Source

pub fn abort_group(&self)

Drop the group on this thread, keeping none of it.

Source

pub fn set_mark(&self, key: &str, seq: u64) -> Result<()>

Move the marker key to seq, durably — inside this thread’s group when one is open (made durable with it), else in a commit of its own (one fsync, and every earlier non-durable commit with it).

Source

pub fn mark(&self, key: &str) -> Result<Option<u64>>

The marker key, None when it was never set (a box from before markers, or a fresh one).

Source

pub fn principal_activity(&self) -> Result<Vec<(String, Vec<u8>)>>

Every principal’s last-seen row (crate::activity): principal id → its encoded stamps. Empty for a database that never kept one, and while the store is off the stripe (the RAM copy carries no such table).

Source

pub fn put_principal_activity( &self, rows: &[(String, Vec<u8>)], mark: Option<&str>, ) -> Result<()>

Write last-seen rows in ONE transaction (one durable commit for the whole batch), and the marker mark = 1 in the same transaction when one is named. Refused while the store is off the stripe; the caller keeps the rows and tries again.

Source

pub fn suspend(&self, why: &str) -> Result<RamCopy>

Take the store off the stripe. Copies every table into RAM, then closes the file (an in-memory database is kept). Refuses when already suspended, and when the copy would weigh more than RAM_COPY_CEILING_BYTES — nothing is changed in that case.

Source

pub fn resume(&self) -> Result<ResumeReport>

Put the store back on the stripe. Reopens the file (the mount must be back; a missing file is an error, never a fresh database), compares every document pointer on disk with the copy, and drops the copy. Refuses when not suspended.

Trait Implementations§

Source§

impl Debug for ControlDb

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Allocation for T
where T: RefUnwindSafe + Send + Sync,

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<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

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> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

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