api-put-object-common.go (4419B)
1 /* 2 * MinIO Go Library for Amazon S3 Compatible Cloud Storage 3 * Copyright 2015-2017 MinIO, Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package minio 19 20 import ( 21 "context" 22 "io" 23 "math" 24 "os" 25 26 "github.com/minio/minio-go/v7/pkg/s3utils" 27 ) 28 29 const nullVersionID = "null" 30 31 // Verify if reader is *minio.Object 32 func isObject(reader io.Reader) (ok bool) { 33 _, ok = reader.(*Object) 34 return 35 } 36 37 // Verify if reader is a generic ReaderAt 38 func isReadAt(reader io.Reader) (ok bool) { 39 var v *os.File 40 v, ok = reader.(*os.File) 41 if ok { 42 // Stdin, Stdout and Stderr all have *os.File type 43 // which happen to also be io.ReaderAt compatible 44 // we need to add special conditions for them to 45 // be ignored by this function. 46 for _, f := range []string{ 47 "/dev/stdin", 48 "/dev/stdout", 49 "/dev/stderr", 50 } { 51 if f == v.Name() { 52 ok = false 53 break 54 } 55 } 56 } else { 57 _, ok = reader.(io.ReaderAt) 58 } 59 return 60 } 61 62 // OptimalPartInfo - calculate the optimal part info for a given 63 // object size. 64 // 65 // NOTE: Assumption here is that for any object to be uploaded to any S3 compatible 66 // object storage it will have the following parameters as constants. 67 // 68 // maxPartsCount - 10000 69 // minPartSize - 16MiB 70 // maxMultipartPutObjectSize - 5TiB 71 func OptimalPartInfo(objectSize int64, configuredPartSize uint64) (totalPartsCount int, partSize int64, lastPartSize int64, err error) { 72 // object size is '-1' set it to 5TiB. 73 var unknownSize bool 74 if objectSize == -1 { 75 unknownSize = true 76 objectSize = maxMultipartPutObjectSize 77 } 78 79 // object size is larger than supported maximum. 80 if objectSize > maxMultipartPutObjectSize { 81 err = errEntityTooLarge(objectSize, maxMultipartPutObjectSize, "", "") 82 return 83 } 84 85 var partSizeFlt float64 86 if configuredPartSize > 0 { 87 if int64(configuredPartSize) > objectSize { 88 err = errEntityTooLarge(int64(configuredPartSize), objectSize, "", "") 89 return 90 } 91 92 if !unknownSize { 93 if objectSize > (int64(configuredPartSize) * maxPartsCount) { 94 err = errInvalidArgument("Part size * max_parts(10000) is lesser than input objectSize.") 95 return 96 } 97 } 98 99 if configuredPartSize < absMinPartSize { 100 err = errInvalidArgument("Input part size is smaller than allowed minimum of 5MiB.") 101 return 102 } 103 104 if configuredPartSize > maxPartSize { 105 err = errInvalidArgument("Input part size is bigger than allowed maximum of 5GiB.") 106 return 107 } 108 109 partSizeFlt = float64(configuredPartSize) 110 if unknownSize { 111 // If input has unknown size and part size is configured 112 // keep it to maximum allowed as per 10000 parts. 113 objectSize = int64(configuredPartSize) * maxPartsCount 114 } 115 } else { 116 configuredPartSize = minPartSize 117 // Use floats for part size for all calculations to avoid 118 // overflows during float64 to int64 conversions. 119 partSizeFlt = float64(objectSize / maxPartsCount) 120 partSizeFlt = math.Ceil(partSizeFlt/float64(configuredPartSize)) * float64(configuredPartSize) 121 } 122 123 // Total parts count. 124 totalPartsCount = int(math.Ceil(float64(objectSize) / partSizeFlt)) 125 // Part size. 126 partSize = int64(partSizeFlt) 127 // Last part size. 128 lastPartSize = objectSize - int64(totalPartsCount-1)*partSize 129 return totalPartsCount, partSize, lastPartSize, nil 130 } 131 132 // getUploadID - fetch upload id if already present for an object name 133 // or initiate a new request to fetch a new upload id. 134 func (c *Client) newUploadID(ctx context.Context, bucketName, objectName string, opts PutObjectOptions) (uploadID string, err error) { 135 // Input validation. 136 if err := s3utils.CheckValidBucketName(bucketName); err != nil { 137 return "", err 138 } 139 if err := s3utils.CheckValidObjectName(objectName); err != nil { 140 return "", err 141 } 142 143 // Initiate multipart upload for an object. 144 initMultipartUploadResult, err := c.initiateMultipartUpload(ctx, bucketName, objectName, opts) 145 if err != nil { 146 return "", err 147 } 148 return initMultipartUploadResult.UploadID, nil 149 }