func (u *uploader) init() error {
	if u.cfg.Concurrency == 0 {
		u.cfg.Concurrency = DefaultUploadConcurrency
	}
	if u.cfg.PartSize == 0 {
		u.cfg.PartSize = DefaultUploadPartSize
	}
	if u.cfg.MaxUploadParts == 0 {
		u.cfg.MaxUploadParts = MaxUploadParts
	}
	if err := u.initSize(); err != nil {
		return err
	}
	poolCap := u.cfg.Concurrency + 1
	if u.cfg.partPool == nil || u.cfg.partPool.SliceSize() != u.cfg.PartSize {
		u.cfg.partPool = newByteSlicePool(u.cfg.PartSize)
		u.cfg.partPool.ModifyCapacity(poolCap)
	} else {
		u.cfg.partPool = &returnCapacityPoolCloser{byteSlicePool: u.cfg.partPool}
		u.cfg.partPool.ModifyCapacity(poolCap)
	}
	return nil
}
init will initialize all default options.
package s3manager
import (
	"bytes"
	"fmt"
	"io"
	"sort"
	"sync"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/aws/awsutil"
	"github.com/aws/aws-sdk-go/aws/client"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/request"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/s3/s3iface"
)
const MaxUploadParts = 10000
const MinUploadPartSize int64 = 1024 * 1024 * 5
const DefaultUploadPartSize = MinUploadPartSize
const DefaultUploadConcurrency = 5
type MultiUploadFailure interface {
	awserr.Error
	UploadID() string
}
type awsError awserr.Error
type multiUploadError struct {
	awsError
	uploadID string
}
func (m multiUploadError) Error() string {
	extra := fmt.Sprintf("upload id: %s", m.uploadID)
	return awserr.SprintError(m.Code(), m.Message(), extra, m.OrigErr())
}
func (m multiUploadError) String() string {
	return m.Error()
}
func (m multiUploadError) UploadID() string {
	return m.uploadID
}
type UploadOutput struct {
	Location string
	VersionID *string
	UploadID string
}
func WithUploaderRequestOptions(opts ...request.Option) func(*Uploader) {
	return func(u *Uploader) {
		u.RequestOptions = append(u.RequestOptions, opts...)
	}
}
type Uploader struct {
	PartSize int64
	Concurrency int
	LeavePartsOnError bool
	MaxUploadParts int
	S3 s3iface.S3API
	RequestOptions []request.Option
	BufferProvider ReadSeekerWriteToProvider
	partPool byteSlicePool
}
func NewUploader(c client.ConfigProvider, options ...func(*Uploader)) *Uploader {
	return newUploader(s3.New(c), options...)
}
func newUploader(client s3iface.S3API, options ...func(*Uploader)) *Uploader {
	u := &Uploader{
		S3:                client,
		PartSize:          DefaultUploadPartSize,
		Concurrency:       DefaultUploadConcurrency,
		LeavePartsOnError: false,
		MaxUploadParts:    MaxUploadParts,
		BufferProvider:    defaultUploadBufferProvider(),
	}
	for _, option := range options {
		option(u)
	}
	u.partPool = newByteSlicePool(u.PartSize)
	return u
}
func NewUploaderWithClient(svc s3iface.S3API, options ...func(*Uploader)) *Uploader {
	return newUploader(svc, options...)
}
func (u Uploader) Upload(input *UploadInput, options ...func(*Uploader)) (*UploadOutput, error) {
	return u.UploadWithContext(aws.BackgroundContext(), input, options...)
}
func (u Uploader) UploadWithContext(ctx aws.Context, input *UploadInput, opts ...func(*Uploader)) (*UploadOutput, error) {
	i := uploader{in: input, cfg: u, ctx: ctx}
	for _, opt := range opts {
		opt(&i.cfg)
	}
	i.cfg.RequestOptions = append(i.cfg.RequestOptions, request.WithAppendUserAgent("S3Manager"))
	return i.upload()
}
func (u Uploader) UploadWithIterator(ctx aws.Context, iter BatchUploadIterator, opts ...func(*Uploader)) error {
	var errs []Error
	for iter.Next() {
		object := iter.UploadObject()
		if _, err := u.UploadWithContext(ctx, object.Object, opts...); err != nil {
			s3Err := Error{
				OrigErr: err,
				Bucket:  object.Object.Bucket,
				Key:     object.Object.Key,
			}
			errs = append(errs, s3Err)
		}
		if object.After == nil {
			continue
		}
		if err := object.After(); err != nil {
			s3Err := Error{
				OrigErr: err,
				Bucket:  object.Object.Bucket,
				Key:     object.Object.Key,
			}
			errs = append(errs, s3Err)
		}
	}
	if len(errs) > 0 {
		return NewBatchError("BatchedUploadIncomplete", "some objects have failed to upload.", errs)
	}
	return nil
}
type uploader struct {
	ctx aws.Context
	cfg Uploader
	in *UploadInput
	readerPos int64  
	totalSize int64  
}
func (u *uploader) upload() (*UploadOutput, error) {
	if err := u.init(); err != nil {
		return nil, awserr.New("ReadRequestBody", "unable to initialize upload", err)
	}
	defer u.cfg.partPool.Close()
	if u.cfg.PartSize < MinUploadPartSize {
		msg := fmt.Sprintf("part size must be at least %d bytes", MinUploadPartSize)
		return nil, awserr.New("ConfigError", msg, nil)
	}
	reader, _, cleanup, err := u.nextReader()
	if err == io.EOF {  
		return u.singlePart(reader, cleanup)
	} else if err != nil {
		cleanup()
		return nil, awserr.New("ReadRequestBody", "read upload data failed", err)
	}
	mu := multiuploader{uploader: u}
	return mu.upload(reader, cleanup)
}