forked from johannesboyne/gofakes3
-
-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathmultipart_backend.go
More file actions
99 lines (93 loc) · 5.14 KB
/
Copy pathmultipart_backend.go
File metadata and controls
99 lines (93 loc) · 5.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package gofakes3
import (
"context"
"errors"
"io"
)
// ErrMultipartUploadNotSupported is returned by a MultipartBackend implementation
// to signal that GoFakeS3 should fall back to the default in-memory multipart
// implementation for this particular upload. It is not surfaced to the S3 client.
var ErrMultipartUploadNotSupported = errors.New("gofakes3: multipart upload not supported by backend")
// MultipartBackend is an optional interface that a Backend may implement in order
// to handle multipart uploads itself, streaming each part directly into storage
// instead of having GoFakeS3 buffer every part in memory in its default uploader.
//
// When a Backend implements this interface, GoFakeS3 routes the four multipart
// operations (Initiate, UploadPart, Complete, Abort) to it. If the backend
// cannot handle a specific upload (for example, because the underlying storage
// does not support chunked writes for that bucket/object), CreateMultipartUpload
// may return ErrMultipartUploadNotSupported and GoFakeS3 will fall back to the
// default in-memory implementation for just that upload.
//
// All other Backend methods continue to be called normally; only the multipart
// path is affected.
//
// # Concurrency and lifecycle
//
// GoFakeS3 does not serialise multipart operations for a given UploadID, and it
// only removes its own bookkeeping for an upload after the backend has
// acknowledged Complete or Abort (so that a backend error leaves the upload
// available for the client to retry). Two consequences follow that
// implementations must be prepared for:
//
// - Concurrent CompleteMultipartUpload calls for the same UploadID may both be
// dispatched to the backend. On a versioned backend this can produce more
// than one object version from a single logical completion. Make Complete
// idempotent (or restartable) if this matters to you; see
// CompleteMultipartUpload.
//
// - An upload is only released once Complete or Abort succeeds. A client that
// neither completes nor aborts (or whose Complete keeps failing) leaves the
// upload tracked indefinitely. Backends that persist part data should expose
// their own way to reap abandoned uploads rather than relying on GoFakeS3 to
// do so.
type MultipartBackend interface {
// CreateMultipartUpload begins a new multipart upload and returns the
// UploadID that subsequent UploadPart / CompleteMultipartUpload /
// AbortMultipartUpload calls will reference.
//
// UploadIDs must be non-empty and unique within the lifetime of the
// GoFakeS3 instance: GoFakeS3 tracks in-progress uploads keyed by UploadID
// and will reject an empty or colliding ID (the backend will be asked to
// abort the just-created upload). Implementations should use a globally
// unique generator (for example a UUID) rather than a per-backend counter.
//
// Returning ErrMultipartUploadNotSupported signals GoFakeS3 to handle this
// particular upload with its default in-memory implementation.
CreateMultipartUpload(ctx context.Context, bucket, object string, meta map[string]string) (UploadID, error)
// UploadPart writes a single part. body yields at most contentLength
// bytes. The returned etag is sent back to the S3 client and must be the
// same value provided to CompleteMultipartUpload in the matching
// CompletedPart entry.
//
// GoFakeS3 does NOT guarantee that body actually contains contentLength
// bytes: if the client under-delivers (a truncated or aborted request)
// body reaches EOF early. Unlike the in-memory path, GoFakeS3 does not
// reject a short part for a streaming backend, so the implementation MUST
// verify that it read exactly contentLength bytes and return an error
// (for example ErrIncompleteBody) otherwise; treating a short read as a
// complete part will silently store a truncated object.
//
// If UploadPart returns an error the part is considered failed and the
// implementation must discard any partial data it has already persisted
// for that part.
UploadPart(ctx context.Context, bucket, object string, uploadID UploadID, partNumber int, contentLength int64, body io.Reader) (etag string, err error)
// CompleteMultipartUpload finalises an upload that was started by
// CreateMultipartUpload. The input lists the parts (and their etags) to
// assemble. Implementations should validate the etags and part ordering
// against the parts they have already received.
//
// The returned etag is sent back to the S3 client.
//
// If CompleteMultipartUpload returns an error GoFakeS3 leaves the upload
// in place so the client may retry; implementations should therefore make
// completion idempotent or restartable.
CompleteMultipartUpload(ctx context.Context, bucket, object string, uploadID UploadID, input *CompleteMultipartUploadRequest) (versionID VersionID, etag string, err error)
// AbortMultipartUpload discards an in-progress multipart upload and any
// parts that have been received.
//
// If AbortMultipartUpload returns an error GoFakeS3 leaves the upload in
// place so the client may retry; implementations should therefore make
// abort idempotent.
AbortMultipartUpload(ctx context.Context, bucket, object string, uploadID UploadID) error
}