Class StagingArea
-
- All Implemented Interfaces:
public final class StagingAreaStaged, atomically-published writes (HEL-236 guarantee 2). Object storage has NO atomic rename, so atomicity is constructed from the primitives it does have:
every artifact is first written under a run-scoped STAGING prefix (
<prefix>/.staging/<runId>/…) that readers never look at;staged objects are server-side COPIED to their run-scoped final keys — still invisible, because readers only trust manifests;
the manifest is PUT with WriteCondition.IfAbsent — this single conditional create IS the commit point: before it, the dataset does not exist; after it, it is complete (the manifest names every part);
staging is deleted.
A crash anywhere before step 3 leaves only invisible garbage, never a half-published dataset. Losing the step-3 race (PreconditionFailedException) rolls back this run's copies deterministically. Abandoned staging has a DETERMINISTIC ownership/cleanup rule: a run owns
.staging/<runId>/, and cleanupAbandoned deletes any run whose newest object is older than the caller's threshold (a live writer keeps its staging young by writing).Requires StorageCapability.CONDITIONAL_CREATE; the constructor rejects a provider without it BEFORE any data movement.
-
-
Field Summary
Fields Modifier and Type Field Description public final static StringSTAGING_SEGMENTprivate final StringstagingPrefixprivate final StringfinalPrefixprivate final StringrunId
-
Constructor Summary
Constructors Constructor Description StagingArea(ObjectStore store, String finalPrefix, String runId, Clock clock)
-
Method Summary
Modifier and Type Method Description final StringgetStagingPrefix()final StringgetFinalPrefix()final StringgetRunId()final ObjectKeystageKey(String name)The staging key for a run-relative artifact name. final PutResultstage(String name, ContentSource source, PutOptions options)Write one artifact into staging (delegates to ObjectStore.put). final List<ObjectSummary>stagedObjects()Everything currently staged for THIS run. final PutResultpublish(Map<ObjectKey, ObjectKey> plan, ObjectKey manifestKey, ContentSource manifestBody, PutOptions manifestOptions)Commit: copy each staged object to its final key per plan, then create manifestKey conditionally, then drop staging. final Longdiscard()Drop every staged object of this run. final static LongcleanupAbandoned(ObjectStore store, String finalPrefix, Duration olderThan, Clock clock)Delete abandoned staging runs under finalPrefix: any .staging/<runId>/whose NEWEST object is older than olderThan.-
-
Constructor Detail
-
StagingArea
StagingArea(ObjectStore store, String finalPrefix, String runId, Clock clock)
-
-
Method Detail
-
getStagingPrefix
final String getStagingPrefix()
-
getFinalPrefix
final String getFinalPrefix()
-
stage
final PutResult stage(String name, ContentSource source, PutOptions options)
Write one artifact into staging (delegates to ObjectStore.put).
-
stagedObjects
final List<ObjectSummary> stagedObjects()
Everything currently staged for THIS run.
-
publish
final PutResult publish(Map<ObjectKey, ObjectKey> plan, ObjectKey manifestKey, ContentSource manifestBody, PutOptions manifestOptions)
Commit: copy each staged object to its final key per plan, then create manifestKey conditionally, then drop staging. On a lost commit race the already-copied final objects of THIS run are deleted and the PreconditionFailedException is rethrown — the winner's dataset is untouched. plan final keys MUST be run-unique (e.g. carry runId); that is what makes step 2 collision-free without conditional copies.
-
cleanupAbandoned
final static Long cleanupAbandoned(ObjectStore store, String finalPrefix, Duration olderThan, Clock clock)
Delete abandoned staging runs under finalPrefix: any
.staging/<runId>/whose NEWEST object is older than olderThan. Returns the number of objects deleted. Safe to run concurrently with live writers as long as their threshold exceeds the writer's maximum quiet period — the rule is deterministic, pick it deliberately.
-
-
-
-