Class UploadStagingStore
<root>/xfer/<rid>/ holds one reservation.json, and per file <fid>.part (the bytes as received, compressed if the transfer uses gzip) beside <fid>.json.Every path is derived from the reservation ID and the file index only; no client string ever becomes a path. Sidecars are written atomically (temporary file, then move). The part is appended before its sidecar is rewritten, so the sidecar's hwm is always at most the part's length; openForAppend(String,int,long) truncates a longer part back to hwm, never the other way round.
This is a separate root from the file provider's per-session publish directory on purpose: a half-written, unverified upload must never sit in a publish root.
Thread-safety: callers serialize access per reservation (the registry's per-reservation lock); the sweeps take a directory snapshot and tolerate concurrent deletion.
- Author:
- Christopher Mindus
Field Summary
FieldsConstructor Summary
ConstructorsMethod Summary
Modifier and TypeMethodDescriptionstatic voidcheckReservationID(String rid) Validates a reservation ID: exactly 32 lower-case hex characters, so that it can only ever name a direct child of the root.voidcreateReservation(ReservationRecord reservation, List<FileRecord> files) Creates the directory of a new reservation and writes its sidecar and every file sidecar.voiddeleteFile(String rid, int fid) Deletes a part and its sidecar (a failed or cancelled file).booleandeleteReservation(String rid) Deletes a reservation directory: every part and sidecar whose file is notUploadState.CONSUMED, then the directory itself if nothing is left.getRoot()Gets the canonical root (<staging>/xfer).longGets the server process start time this store was created with.Lists the reservation IDs present on disk.openForAppend(String rid, int fid, long hwm) Opens a part for appending at the acknowledged high-water mark.Gets the part file of a file.longpartLength(String rid, int fid) Gets the current length of a part.Reads a file sidecar.Reads every file sidecar of a reservation.readReservation(String rid) Reads a reservation sidecar.Gets the directory of a reservation.sidecarFile(String rid, int fid) Gets the sidecar file of a file.Sweeps the root: every reservation directory whose record is unreadable, from a previous boot, cancelled, or open but no longer in flight, is deleted (consumed files excepted).voidwriteFile(FileRecord file) Rewrites a file sidecar.voidwriteReservation(ReservationRecord reservation) Rewrites a reservation sidecar.
Field Details
XFER
The transfer subdirectory under the configured staging directory.- See Also:
RESERVATION_JSON
BUFFER_SIZE
public static final int BUFFER_SIZEThe buffer size used when streaming a body into a part.- See Also:
Constructor Details
UploadStagingStore
Constructor. The root is created if absent.- Parameters:
stagingDirectory- The configured staging directory ($upload.dir).serverBoot- The server process start time in milliseconds.- Throws:
IOException- If the root cannot be created or canonicalized.
Method Details
getRoot
getServerBoot
public long getServerBoot()Gets the server process start time this store was created with.- Returns:
- The boot time.
checkReservationID
Validates a reservation ID: exactly 32 lower-case hex characters, so that it can only ever name a direct child of the root.- Parameters:
rid- The reservation ID.- Throws:
IllegalArgumentException- If the ID is not of that form.
reservationDirectory
Gets the directory of a reservation.- Parameters:
rid- The reservation ID.- Returns:
- The directory, existing or not.
- Throws:
IllegalArgumentException- If the ID is malformed.
partFile
sidecarFile
createReservation
public void createReservation(ReservationRecord reservation, List<FileRecord> files) throws IOException Creates the directory of a new reservation and writes its sidecar and every file sidecar.- Parameters:
reservation- The reservation record.files- The file records, in file index order.- Throws:
IOException- For file errors, including an already existing directory.
writeReservation
Rewrites a reservation sidecar.- Parameters:
reservation- The record.- Throws:
IOException- For file errors.
writeFile
Rewrites a file sidecar.- Parameters:
file- The record.- Throws:
IOException- For file errors.
readReservation
Reads a reservation sidecar.- Parameters:
rid- The reservation ID.- Returns:
- The record, or null if absent or unreadable.
- Throws:
IOException- For file errors.
readFile
Reads a file sidecar.- Parameters:
rid- The reservation ID.fid- The file index.- Returns:
- The record, or null if absent or unreadable.
- Throws:
IOException- For file errors.
partLength
Gets the current length of a part.- Parameters:
rid- The reservation ID.fid- The file index.- Returns:
- The length in bytes, 0 if the part does not exist yet.
- Throws:
IOException- For file errors.
openForAppend
Opens a part for appending at the acknowledged high-water mark. A part longer thanhwm(a crash between an append and its sidecar rewrite) is truncated tohwm; a part shorter thanhwmcannot happen by the write order and is reported.- Parameters:
rid- The reservation ID.fid- The file index.hwm- The acknowledged length from the sidecar.- Returns:
- A channel positioned at
hwm; the caller closes it. - Throws:
IOException- For file errors.IllegalStateException- If the part is shorter thanhwm.
deleteFile
Deletes a part and its sidecar (a failed or cancelled file).- Parameters:
rid- The reservation ID.fid- The file index.- Throws:
IOException- For file errors.
deleteReservation
Deletes a reservation directory: every part and sidecar whose file is notUploadState.CONSUMED, then the directory itself if nothing is left. A consumed file's part is never touched; its sidecar is removed only together with the directory, i.e. never while the part is still there.- Parameters:
rid- The reservation ID.- Returns:
- true if the directory is gone, false if consumed files keep it.
- Throws:
IOException- For file errors.
readFiles
Reads every file sidecar of a reservation.- Parameters:
rid- The reservation ID.- Returns:
- The records, in file index order; unreadable sidecars are skipped.
- Throws:
IOException- For file errors.
listReservations
Lists the reservation IDs present on disk.- Returns:
- The IDs of every well-formed subdirectory; malformed names are reported and deleted only by
sweep(Predicate,long). - Throws:
IOException- For file errors.
sweep
Sweeps the root: every reservation directory whose record is unreadable, from a previous boot, cancelled, or open but no longer in flight, is deleted (consumed files excepted). A reservation is in flight when its record says so (ReservationRecord.isInFlight(long, long)) AND the caller's predicate confirms its application session is alive.At startup the predicate is irrelevant: no record can carry this boot's time yet, so every directory is a previous boot's and is swept.
- Parameters:
sessionAlive- Answers whether an application session UUID is alive now.now- The current time in milliseconds.- Returns:
- The IDs of the reservations that were swept.
- Throws:
IOException- For file errors on the root itself; per-directory errors are logged and skipped.