Interface ArtifactWalk
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 ClassesModifier and TypeInterfaceDescriptionstatic interfaceOne enumerated key. -
Method Summary
Modifier and TypeMethodDescriptionThe current pass forconsumer, empty when none was ever started - the observability read a console or fingerprint surfaces without joining the walk.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) Joinconsumer's current pass overroots(starting a new one when none exists or the previous completed), claim segments until none is claimable, and stream every claimed key tovisitor.
-
Method Details
-
walk
WalkPass walk(build.jenesis.repository.store.ArtifactStore store, String consumer, List<String> roots, ArtifactWalk.KeyVisitor visitor) throws IOException Joinconsumer's current pass overroots(starting a new one when none exists or the previous completed), claim segments until none is claimable, and stream every claimed key tovisitor. Pass and segment state live underwalks/<consumer>/instore- 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 forconsumer, 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
-