Interface IUploadStore
Represents the storage of chunked uploads, which keeps everything the service knows about them: their records, their chunks, the claims of their handler runs and their outcomes. Chunked uploads use a store in a directory by default (see Directory), and a store that the app registers as a singleton IUploadStore service instead.
Namespace: Singulink.Net.Http.Api.Service.Uploads
Assembly: Singulink.Net.Http.Api.Service.dll
Syntax
public interface IUploadStore
Remarks
Servers that share a store share its uploads, so every operation must be safe to call at the same time from several requests and servers:
- Writing a chunk is idempotent: writing a chunk again replaces it with the same bytes. A chunk is reported as received only once all of its bytes are stored durably, and a write that fails or is interrupted leaves it missing, or as it was, also when it was received before.
- Claiming a run is atomic: of claims made at the same time, at most one succeeds, and none succeeds while the upload has a claim, whether its lease is current or has lapsed, or has an outcome.
- Claiming a run excludes chunk writes: a claim does not succeed while a chunk is being written, and a write that starts once a run is claimed does not change the upload's file. A write and a claim that start at the same time don't both fail: if the claim fails, the write is written.
- Storing an outcome is atomic and durable: only the first outcome of an upload is stored, and once stored it is kept until the upload is deleted.
- Reserving an idempotency key is atomic: of reservations of a user's key made at the same time, one succeeds, and the others get it.
The service applies all of the protocol's rules, such as the users and endpoints that uploads belong to, their states, limits and expiry, and the lengths of chunks, so a store only keeps what it is given. Metadata and outcomes are text in a format of the service's own, which a store keeps as it is.
The service takes an exception of the store, other than an ApiException and the cancellation of the operation, for a failure that may not last, such as of a share that can't be reached for a moment, and reports it with StoreUnavailable, which clients retry for a while. A store reports an error that lasts with an ApiException.
Properties
| Name | Description |
|---|---|
| MaxChunkCount | Gets the largest number of chunks that the store accepts for an upload. Default is MaxValue, for no limit of the store's own. |
| MaxChunkSize | Gets the largest chunk size that the store accepts, in bytes. The service never uses chunks larger than 64 MiB. Default is MaxValue, for no limit of the store's own. |
| MinChunkSize | Gets the smallest chunk size that the store accepts for every chunk but the last, in bytes. The service never uses chunks smaller than 5 MiB. Default is 0, for no limit of the store's own. |
Methods
| Name | Description |
|---|---|
| CleanUpAsync(CancellationToken) | Removes data that belongs to no upload, such as what is left of a creation that failed or of a deletion that could not finish, and reservations of idempotency keys for uploads that were never created. The service calls it after each of its cleanup passes, every few minutes. Default does nothing. |
| DeleteAsync(UploadRecord, CancellationToken) | Deletes an upload and everything the store keeps for it, including the reservation of its idempotency key. If the upload's run is claimed, the claim's next renewal fails, so the server that runs the handler stops it. Deleting an upload that no longer exists does nothing. |
| GetAsync(string, string, CancellationToken) | Gets an upload of a user with its current state. |
| GetContentAsync(UploadRecord, CancellationToken) | Gets the complete file of an upload whose run the caller has claimed, assembling it from the chunks first if the store needs to. It can be called again for the same upload, such as when a run is claimed again after a claim was released. |
| GetReceivedChunksAsync(UploadRecord, CancellationToken) | Gets the indexes of the chunks of an upload that have been received. |
| ListAsync(string?, bool, CancellationToken) | Lists uploads with their current state: the uploads of a user, or all of them. The service lists them to count a user's open uploads, and to find the uploads to remove and their total size. |
| ReleaseKeyAsync(string, string, string, CancellationToken) | Releases the reservation of an idempotency key of a user if it is reserved for the specified upload, such as when the upload's creation failed. |
| ReserveKeyAsync(string, string, string, CancellationToken) | Reserves an idempotency key of a user for an upload that is about to be created, unless the key is reserved already. |
| TryClaimRunAsync(UploadRecord, TimeSpan, CancellationToken) | Claims the run of an upload's handler for the server that calls it. |
| TryCreateAsync(UploadRecord, CancellationToken) | Creates an upload with the specified record, reserving room for its length if the store can. |
| TrySetOutcomeAsync(UploadRecord, string, CancellationToken) | Stores the outcome of an upload, unless it already has one or no longer exists, and removes its content, its chunks and its run claim. |
| WriteChunkAsync(UploadRecord, int, Stream, CancellationToken) | Writes a chunk of an upload, replacing the chunk if it was already written, unless the run of the upload's handler is claimed or the upload has an outcome. The chunk is reported as received once this returns Written. The upload's LastWriteUtc is the time when a write starts, and again when it ends. |