1
1
package amazon
2
2
3
3
import (
4
- "bytes"
5
4
"context"
6
5
"errors"
7
6
"fmt"
7
+ "io"
8
8
"log/slog"
9
9
"os"
10
10
"sync"
@@ -100,8 +100,9 @@ func MultiPartUpload(input MultiPartUploadInput) error {
100
100
101
101
// Get the total number of parts we will upload
102
102
numParts := getTotalNumberParts (fileSize , input .PartSize )
103
+ partSize := getPartSize (fileSize , numParts , input .PartSize )
103
104
if input .Logger != nil {
104
- input .Logger .Debug ("will upload file in parts" , "file" , input .Filepath , "parts" , numParts )
105
+ input .Logger .Debug ("will upload file in parts" , "file" , input .Filepath , "parts" , numParts , "partSize" , partSize , "fileSize" , fileSize )
105
106
}
106
107
107
108
var (
@@ -114,8 +115,8 @@ func MultiPartUpload(input MultiPartUploadInput) error {
114
115
orderedParts := make ([]* s3.CompletedPart , numParts )
115
116
for i := int64 (0 ); i < numParts ; i ++ {
116
117
partNumber := i + 1
117
- offset := i * input . PartSize
118
- bytesToRead := min (input . PartSize , fileSize - offset )
118
+ offset := i * partSize
119
+ bytesToRead := min (partSize , fileSize - offset )
119
120
120
121
wg .Add (1 )
121
122
go func (partNumber int64 , bytesToRead int64 , offset int64 ) {
@@ -125,23 +126,18 @@ func MultiPartUpload(input MultiPartUploadInput) error {
125
126
}()
126
127
defer wg .Done ()
127
128
128
- partBuffer := make ([]byte , bytesToRead )
129
- _ , err := file .ReadAt (partBuffer , offset )
130
- if err != nil {
131
- ch <- err
132
- return
133
- }
129
+ partReader := io .NewSectionReader (file , offset , bytesToRead )
134
130
135
131
if input .Logger != nil {
136
- input .Logger .Debug ("uploading file part" , "file" , input .Filepath , "part" , partNumber , "size" , len ( partBuffer ) )
132
+ input .Logger .Debug ("uploading file part" , "file" , input .Filepath , "part" , partNumber , "size" , bytesToRead )
137
133
}
138
134
139
135
resp , err := input .Svc .UploadPart (& s3.UploadPartInput {
140
136
Bucket : aws .String (input .DestinationBucket ),
141
137
Key : aws .String (input .DestinationKey ),
142
138
UploadId : & uploadID ,
143
139
PartNumber : aws .Int64 (partNumber ),
144
- Body : bytes . NewReader ( partBuffer ) ,
140
+ Body : partReader ,
145
141
})
146
142
if err != nil {
147
143
ch <- fmt .Errorf ("error uploading part %d : %w" , partNumber , err )
@@ -155,7 +151,7 @@ func MultiPartUpload(input MultiPartUploadInput) error {
155
151
}
156
152
157
153
if input .Logger != nil {
158
- input .Logger .Debug ("finished uploading file part" , "file" , input .Filepath , "part" , partNumber , "size" , len ( partBuffer ) )
154
+ input .Logger .Debug ("finished uploading file part" , "file" , input .Filepath , "part" , partNumber , "size" , bytesToRead )
159
155
}
160
156
}(partNumber , bytesToRead , offset )
161
157
}
@@ -197,7 +193,18 @@ func min(a, b int64) int64 {
197
193
198
194
func getTotalNumberParts (filesize int64 , partsize int64 ) int64 {
199
195
if filesize % partsize == 0 {
200
- return filesize / partsize
196
+ return min (10000 , filesize / partsize )
197
+ }
198
+ return min (10000 , filesize / partsize + 1 )
199
+ }
200
+
201
+ func getPartSize (filesize int64 , numParts int64 , defaultPartSize int64 ) int64 {
202
+ if numParts < 10000 {
203
+ return defaultPartSize
204
+ }
205
+ if filesize % numParts == 0 {
206
+ return filesize / numParts
201
207
}
202
- return filesize / partsize + 1
208
+ // numParts-1 to account for any rounding (makes the parts slightly larger)
209
+ return filesize / (numParts - 1 )
203
210
}
0 commit comments