Skip to main content

OplogJournal

Struct OplogJournal 

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

Append-only JSONL journal for OpRecords. Holds an exclusive advisory lock on <path>.lock for its lifetime — one writer per journal path.

Implementations§

Source§

impl OplogJournal

Source

pub fn open(path: &Path) -> Result<Self>

Open (creating parents and the file if needed) for appending. Existing content is preserved — append mode, never truncate.

If the file’s last line is torn (a crash mid-write left it without a terminating newline), a newline is written first so the next append starts a fresh line instead of gluing itself onto the garbage — otherwise the first post-crash append would be lost with the tail.

Source

pub fn append(&mut self, op: &OpRecord) -> Result<()>

Append one op as a single JSON line and flush it to the OS page cache, so a subsequent crash can tear at most the next record.

Not a durability barrierflush clears the BufWriter buffer to the OS but does not fsync. A caller with a journal-durable-before-transmit / ack-asserts-durable contract (the sync session) MUST call OplogJournal::sync before it transmits or acks; per-op fsync would be needless latency (one batch barrier at the contract point is enough).

Failure recovers the writer. On a write/flush error the BufWriter would otherwise retain the unflushed line; a later append would then emit that rolled-back line beside the caller’s re-minted same-seq op — a permanent chain fork. So a failed append recreates the writer on a fresh append-mode handle, discarding the poisoned buffer, before returning the error (the caller rolls its in-memory chain back to the durable ops). Bytes that already reached the file are at most one torn trailing line, which OplogJournal::load tolerates.

Source

pub fn sync(&mut self) -> Result<()>

Durability barrier: flush the buffer and fsync the journal file to stable storage. The sync session crosses this before it transmits an op (journal-durable-before-transmit, B1 MUST) and before it acks a fold frontier (ack-asserts-durable, B4 MUST) — one batch call, not per-op.

Source

pub fn path(&self) -> &Path

Source

pub fn truncate_to( &mut self, ops: &[OpRecord], checkpoint_hash: &str, ) -> Result<()>

Rewrite the journal to exactly ops, stamped with a TruncationMarker naming checkpoint_hash as its first line — B4’s truncation-below-a-frontier step, executed under the advisory lock this open journal already holds (no second writer can interleave). The marker travels IN the rewritten file, so it is atomic with the truncation: there is no crash window in which the journal is truncated but unmarked (or marked but untruncated).

Durability: the retained ops are written to a sibling temp file, fsync’d, and atomically renamed over the journal, so a crash at any point leaves either the old complete journal or the new complete tail — never a partial rewrite. Crash-ordering invariant (callers MUST honor it; crate::compact::compact_and_truncate does by construction): the covering checkpoint is durable BEFORE this runs. Truncation makes the dropped ops unrecoverable from the journal; the checkpoint named by the marker is what still accounts for them.

Source

pub fn load(path: &Path) -> Result<Vec<OpRecord>>

Load a full (never-truncated) journal: every parseable op, in file order. Blank and unparseable (torn) lines are skipped; a missing file is an empty log (a fresh device bootstraps from nothing).

A journal carrying a TruncationMarker is refused with a runtime error: its ops are only the retained tail, and treating them as the whole log silently re-mints truncated seqs on DeviceLog::resume — the permanent chain fork. Use OplogJournal::load_with_marker + the named checkpoint + crate::checkpoint::resume_anchored instead.

Source

pub fn load_with_marker( path: &Path, ) -> Result<(Option<TruncationMarker>, Vec<OpRecord>)>

Load a journal that may have been truncated: the TruncationMarker (if any) plus every parseable op, in file order. Blank and unparseable (torn) lines are skipped; a missing file is (None, []). When the marker is Some, the ops are a retained tail — anchor them on the named checkpoint (crate::checkpoint::verify_anchored) and resume via crate::checkpoint::resume_anchored, never DeviceLog::resume.

Trait Implementations§

Source§

impl Debug for OplogJournal

Source§

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

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

impl Drop for OplogJournal

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

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