Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multipart features #1358

Merged
merged 6 commits into from
Jul 30, 2019
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/storage.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ config:
insecure_skip_verify: false
trace:
enable: false
part_size: 0
```

At a minimum, you will need to provide a value for the `bucket`, `endpoint`, `access_key`, and `secret_key` keys. The rest of the keys are optional.
Expand All @@ -74,6 +75,8 @@ You can configure the timeout settings for the HTTP client by setting the `http_

Please refer to the documentation of [the Transport type](https://golang.org/pkg/net/http/#Transport) in the `net/http` package for detailed information on what each option does.

`part_size` is specified in bytes and refers to the minimum file size used for multipart uploads, as some custom S3 implementations may have different requirements. A value of `0` means to use a default 128 MiB size.

For debug and testing purposes you can set

* `insecure: true` to switch to plain insecure HTTP instead of HTTPS
Expand Down
14 changes: 14 additions & 0 deletions pkg/objstore/s3/s3.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ import (
// DirDelim is the delimiter used to model a directory structure in an object store bucket.
const DirDelim = "/"

// Minimum file size after which an HTTP multipart request should be used to upload objects to storage.
// Set to 128 MiB as in the minio client.
const minPartSize = 1024 * 1024 * 128
GiedriusS marked this conversation as resolved.
Show resolved Hide resolved

// Config stores the configuration for s3 bucket.
type Config struct {
Bucket string `yaml:"bucket"`
Expand All @@ -45,6 +49,7 @@ type Config struct {
PutUserMetadata map[string]string `yaml:"put_user_metadata"`
HTTPConfig HTTPConfig `yaml:"http_config"`
TraceConfig TraceConfig `yaml:"trace"`
PartSize uint64 `yaml:"part_size"`
}

type TraceConfig struct {
Expand All @@ -65,6 +70,7 @@ type Bucket struct {
client *minio.Client
sse encrypt.ServerSide
putUserMetadata map[string]string
partSize uint64
}

// parseConfig unmarshals a buffer into a Config with default HTTPConfig values.
Expand All @@ -81,6 +87,12 @@ func parseConfig(conf []byte) (Config, error) {
if config.PutUserMetadata == nil {
config.PutUserMetadata = make(map[string]string)
}

// Use the default minPartSize if not set.
deejay1 marked this conversation as resolved.
Show resolved Hide resolved
if config.PartSize == 0 {
config.PartSize = minPartSize
}

return config, nil
}

Expand Down Expand Up @@ -174,6 +186,7 @@ func NewBucketWithConfig(logger log.Logger, config Config, component string) (*B
client: client,
sse: sse,
putUserMetadata: config.PutUserMetadata,
partSize: config.PartSize,
}
return bkt, nil
}
Expand Down Expand Up @@ -308,6 +321,7 @@ func (b *Bucket) Upload(ctx context.Context, name string, r io.Reader) error {
r,
fileSize,
minio.PutObjectOptions{
PartSize: b.partSize,
ServerSideEncryption: b.sse,
UserMetadata: b.putUserMetadata,
},
Expand Down
33 changes: 33 additions & 0 deletions pkg/objstore/s3/s3_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,36 @@ http_config:

testutil.Equals(t, "bucket-owner-full-control", cfg2.PutUserMetadata["X-Amz-Acl"])
}

func TestParseConfig_PartSize(t *testing.T) {
input := []byte(`bucket: "bucket-name"
endpoint: "s3-endpoint"
access_key: "access_key"
insecure: false
signature_version2: false
encrypt_sse: false
secret_key: "secret_key"
http_config:
insecure_skip_verify: false
idle_conn_timeout: 50s`)

cfg, err := parseConfig(input)
testutil.Ok(t, err)
testutil.Assert(t, cfg.PartSize == 1024*1024*128, "when part size not set it should default to 128MiB")

input2 := []byte(`bucket: "bucket-name"
endpoint: "s3-endpoint"
access_key: "access_key"
insecure: false
signature_version2: false
encrypt_sse: false
secret_key: "secret_key"
part_size: 104857600
http_config:
insecure_skip_verify: false
idle_conn_timeout: 50s`)

cfg2, err := parseConfig(input2)
testutil.Ok(t, err)
testutil.Assert(t, cfg2.PartSize == 1024*1024*100, "when part size should be set to 100MiB")
}