Skip to main content

FsRelay

Struct FsRelay 

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

The filesystem loopback relay: two (or more) DeviceLogs syncing through a shared directory — the realistic single-user two-Mac case (a shared volume, an external disk, a user-managed synced folder).

Layout under dir:

  • relay.lock — exclusive advisory lock held around every call (the OplogJournal/car-registry protocol, but blocking: concurrent callers queue rather than fail);
  • relay-state.json — roster + chains + latest-checkpoint pointer (temp + atomic rename per mutation);
  • checkpoints/<checkpoint_hash>.checkpoint.json — content-addressed checkpoint files via Checkpoint::save/load. Checkpoint files are immutable (the name IS the whole-record content address), so each is Checkpoint::load-verified once — on first sight by this handle — and then served from an in-memory cache; it is never re-hashed or re-fsync’d on subsequent (including read-only) calls. A tampering attacker in the shared folder is caught by the next process to open the relay (a fresh handle with a cold cache re-verifies), which is the actual two-Mac threat model; a handle never serves content it did not verify.

Semantics are identical to InMemoryRelay by construction — both drive the same [RelayState] core; this type only adds durability and cross-process mutual exclusion.

Implementations§

Source§

impl FsRelay

Source

pub fn open(dir: &Path, config: RelayConfig, wall: WallClock) -> Result<Self>

Trait Implementations§

Source§

impl Debug for FsRelay

Source§

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

Formats the value using the given formatter. Read more
Source§

impl Relay for FsRelay

Source§

fn register(&mut self, device_id: &str) -> Result<RosterEntry, RelayError>

Enroll (or touch) a device on the roster. Idempotent; push/pull/ack auto-register on first contact.
Source§

fn push( &mut self, device_id: &str, ops: &[OpRecord], ) -> Result<PushOutcome, RelayError>

Admit device_id’s own journal-durable ops (in seq order) onto its relay-held chain. Contract (B1, binding): the caller transmits only ops that are already journal-durable on the device.
Source§

fn pull( &mut self, device_id: &str, since: &Frontier, ) -> Result<PullResult, RelayError>

Every retained op above since (per-device seq cursor) + the latest checkpoint pointer.
Source§

fn ack( &mut self, device_id: &str, frontier: Hlc, ) -> Result<AckOutcome, RelayError>

Record a device’s fold frontier. Contract (B4, binding): the device acks only what it has DURABLY folded (journaled), never merely received.
Source§

fn checkpoint_put( &mut self, device_id: &str, checkpoint: &Checkpoint, ) -> Result<bool, RelayError>

Store a device-computed checkpoint. Verified, deduped on checkpoint_hash (whole-record content address — contract from B4). Returns false when the identical checkpoint was already stored.
Source§

fn checkpoint_get(&mut self) -> Result<Option<Checkpoint>, RelayError>

The latest stored checkpoint (dominance-monotone pointer), if any.
Source§

fn roster(&mut self) -> Result<Vec<RosterEntry>, RelayError>

The device registry.
Source§

fn stable_frontier(&mut self) -> Result<Option<Hlc>, RelayError>

min(acked) over active roster devices; None while any active device has never acked (nothing is droppable then).
Source§

fn gc(&mut self) -> Result<GcReport, RelayError>

Drop every op that is BOTH at/below the stable frontier AND covered by a stored checkpoint. Never drops anything else.

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<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> 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, <T as TryFrom<U>>::Error>

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