pub struct OpLog { /* private fields */ }Implementations§
Source§impl OpLog
impl OpLog
pub fn open(root: &Path) -> Result<Self>
Sourcepub fn put(&self, rec: &OperationRecord) -> Result<()>
pub fn put(&self, rec: &OperationRecord) -> Result<()>
Persist a record. Idempotent on existing op_ids (the bytes must match by content addressing).
Crash safety: the tempfile’s data is fsync’d before rename,
so a successful return implies a durable file at the final
path. The containing directory is not fsync’d; on a crash
between rename and the directory’s metadata flush, the file
can be lost. For a content-addressed log this is acceptable
— a lost record can be re-derived from the same source — but
callers that also persist references to the op_id (e.g.
branch heads) should fsync those refs after put returns.
pub fn get(&self, op_id: &OpId) -> Result<Option<OperationRecord>>
Sourcepub fn repack(&self, threshold: usize) -> Result<usize>
pub fn repack(&self, threshold: usize) -> Result<usize>
Consolidate loose op records into a deterministic, content- addressed packfile (#261 slice 1). Returns the number of ops moved into the new pack.
threshold is the minimum number of loose ops required to
trigger a repack — under that, returns 0 and leaves the
log alone. The idea: small stores stay loose; only repack
when the file count starts to matter.
Determinism: the pack name is the SHA-256 of the sorted op_ids (newline-joined), so two independent runs against the same set of loose ops produce a byte-identical pack. Re-running on an empty loose directory is a no-op.
Crash safety: the .pack.tmp and .idx.tmp files are
fsync’d before rename; loose files are deleted only after
both renames succeed. A crash mid-repack leaves both loose
and partial-pack files; a subsequent get finds the loose
version, and a subsequent repack cleans up.
Sourcepub fn evict(&self, victims: &BTreeSet<OpId>) -> Result<usize>
pub fn evict(&self, victims: &BTreeSet<OpId>) -> Result<usize>
Remove every op_id in victims from the log, across both
loose files and packfiles (#261 slice 2). Used by
lex op gc after a retention plan identifies which ops to
drop. Idempotent — calling twice with the same set is a
no-op on the second pass.
Pack handling: any pack containing one or more victims is rewritten to a new content-addressed pack with only the surviving ops; the old pack and its index file are deleted. A pack whose every op is a victim is deleted outright.
Returns the count of ops actually removed (loose files deleted + packed ops dropped). Pre-existing absences don’t contribute.
Sourcepub fn delete(&self, op_id: &OpId) -> Result<()>
pub fn delete(&self, op_id: &OpId) -> Result<()>
Remove a record from the log. Used by crate::migrate to
delete the old <op_id>.json files after a format migration
has written their replacements. Idempotent on missing files.
Not part of the day-to-day op-log API — the log is
append-only by design (#129). The only legitimate caller is
the migration tool, which is supervising a destructive,
--confirm-gated batch.
Sourcepub fn walk_back(
&self,
head: &OpId,
limit: Option<usize>,
) -> Result<Vec<OperationRecord>>
pub fn walk_back( &self, head: &OpId, limit: Option<usize>, ) -> Result<Vec<OperationRecord>>
Walk parents transitively. Newest-first, BFS, dedup’d by op_id.
Stops at parentless ops or after limit records.
Sourcepub fn walk_forward(
&self,
head: &OpId,
limit: Option<usize>,
) -> Result<Vec<OperationRecord>>
pub fn walk_forward( &self, head: &OpId, limit: Option<usize>, ) -> Result<Vec<OperationRecord>>
Same set as walk_back but oldest-first. Used by branch_head for left-to-right transition replay.
Sourcepub fn lca(&self, a: &OpId, b: &OpId) -> Result<Option<OpId>>
pub fn lca(&self, a: &OpId, b: &OpId) -> Result<Option<OpId>>
Common ancestor of two op_ids in the DAG.
On tree-shaped histories and chain merges this is the
lowest common ancestor — the closest shared op. On
criss-cross merges (two ops each with two parents from
independent histories) there can be multiple
incomparable common ancestors; this picks one
deterministically (the first hit when traversing b’s
ancestors newest-first), but not via a recursive merge.
None if no shared ancestor exists.
Tier-1 merge in #129 covers linear and tree-shaped
histories; criss-cross resolution is deferred to a
future tier (Git’s recursive strategy is the reference).
Sourcepub fn list_all(&self) -> Result<Vec<OperationRecord>>
pub fn list_all(&self) -> Result<Vec<OperationRecord>>
Every record in the log. Order is whatever the directory
listing produces — undefined and not stable. Used by the
[crate::predicate] evaluator when no narrower candidate
set is available.