Interface ArtifactWalk


public interface ArtifactWalk
A totally ordered, resumable, range-segmented stream of store keys under root prefixes - the one shared enumeration primitive every whole-store sweep (garbage collection, retention eviction, derived-metadata rebuild) rides instead of hand-rolling its own list() loop. Key-level is deliberately the primitive: half the consumers sweep key spaces that are not artifacts (published/, pinned/, marker spaces); artifact-level views layer on top of it.

Order. Sibling names are visited sorted, which yields one total order over all keys - path order, plain lexicographic except that the '/' separator sorts below every other character, so a subtree (app/...) sits wholly before a longer sibling name it prefixes (app.txt). Cursors, ranges, resume and post-order roll-ups all ride that order. Only sibling pages are ever buffered (bounded by ArtifactStore.page(String, String, int, Consumer) paging, not by tree size).

The pass model. walk(ArtifactStore, String, List, ArtifactWalk.KeyVisitor) joins the current pass for consumer - starting a fresh one when none exists or the last completed - claims free segments one at a time, and streams each claimed range's keys to the visitor, committing the segment's cursor (a high-water mark in key order) every checkpoint stride. The commit doubles as the claim's lease renewal; a claim is only ever taken over a pending or expired segment, never a live holder's (refuse, don't steal), and a taken-over segment resumes from its last committed cursor. The call returns when this worker can claim nothing more: either the pass just completed (WalkPass.Status.COMPLETE) or other holders still own the remaining segments (WalkPass.Status.ACTIVE - re-invoke later, or let another node finish). Fan a pass across a worker pool by calling walk from several threads; across VMs by calling it on several nodes.

Delivery contract (documented honestly): every key present for the whole pass is visited exactly once per pass in the absence of a crash; after a crash-resume, at least once for the uncommitted stride tail - so every consumer must be idempotent per item (upsert / re-judge semantics). A key published while the pass runs is visited by this pass if it sorts after its segment's cursor at that moment, and is guaranteed by the next pass otherwise; a key removed during the pass may or may not be visited, so consumers treat a visit as "existed at some point during the pass" and re-judge on read. Steady-state freshness comes from publication events, not walk latency - the walk is the back-fill, refresh and self-heal backstop, never the hot path.

  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Interface
    Description
    static interface 
    One enumerated key.
  • Method Summary

    Modifier and Type
    Method
    Description
    pass(build.jenesis.repository.store.ArtifactStore store, String consumer)
    The current pass for consumer, empty when none was ever started - the observability read a console or fingerprint surfaces without joining the walk.
    segments(build.jenesis.repository.store.ArtifactStore store, String consumer)
    The current pass's segments with their live claim state (holder, expiry, cursor) - "node X's segment cursor stuck 40 minutes" is read straight off this.
    walk(build.jenesis.repository.store.ArtifactStore store, String consumer, List<String> roots, ArtifactWalk.KeyVisitor visitor)
    Join consumer's current pass over roots (starting a new one when none exists or the previous completed), claim segments until none is claimable, and stream every claimed key to visitor.
  • Method Details

    • walk

      WalkPass walk(build.jenesis.repository.store.ArtifactStore store, String consumer, List<String> roots, ArtifactWalk.KeyVisitor visitor) throws IOException
      Join consumer's current pass over roots (starting a new one when none exists or the previous completed), claim segments until none is claimable, and stream every claimed key to visitor. Pass and segment state live under walks/<consumer>/ in store - the only persistence, so a walk resumes across process death on any node sharing the store. Returns the pass as this worker last saw it.
      Throws:
      IOException
    • pass

      Optional<WalkPass> pass(build.jenesis.repository.store.ArtifactStore store, String consumer) throws IOException
      The current pass for consumer, empty when none was ever started - the observability read a console or fingerprint surfaces without joining the walk.
      Throws:
      IOException
    • segments

      List<WalkSegment> segments(build.jenesis.repository.store.ArtifactStore store, String consumer) throws IOException
      The current pass's segments with their live claim state (holder, expiry, cursor) - "node X's segment cursor stuck 40 minutes" is read straight off this. Empty when no pass exists.
      Throws:
      IOException