Skip to content

Commit 86decdb

Browse files
feat(storage): Customize minimum multipart upload size (#3039)
* Customize minimum upload part size (for client apps) Co-authored-by: arunj-kp <[email protected]>
1 parent c6bec63 commit 86decdb

File tree

2 files changed

+77
-9
lines changed

2 files changed

+77
-9
lines changed

aws-android-sdk-s3/src/main/java/com/amazonaws/mobileconnectors/s3/transferutility/TransferUtility.java

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import java.util.ArrayList;
4444
import java.util.List;
4545

46+
import static com.amazonaws.services.s3.internal.Constants.GB;
4647
import static com.amazonaws.services.s3.internal.Constants.MAXIMUM_UPLOAD_PARTS;
4748
import static com.amazonaws.services.s3.internal.Constants.MB;
4849

@@ -141,7 +142,9 @@ public class TransferUtility {
141142
* Default minimum part size for upload parts. Anything below this will use a
142143
* single upload
143144
*/
144-
static final int MINIMUM_UPLOAD_PART_SIZE = 5 * MB;
145+
static final int DEFAULT_MINIMUM_UPLOAD_PART_SIZE_IN_BYTES = 5 * MB;
146+
static final int MINIMUM_SUPPORTED_UPLOAD_PART_SIZE_IN_BYTES = 5 * MB;
147+
static final long MAXIMUM_SUPPORTED_UPLOAD_PART_SIZE_IN_BYTES = 5 * GB;
145148

146149
private static String userAgentFromConfig = "";
147150

@@ -770,15 +773,16 @@ private List<Integer> getTransferIdsWithTypeAndStates(TransferType type, Transfe
770773
*/
771774
private int createMultipartUploadRecords(String bucket, String key, File file, ObjectMetadata metadata,
772775
CannedAccessControlList cannedAcl) {
773-
long remainingLenth = file.length();
774-
double partSize = (double) remainingLenth / (double) MAXIMUM_UPLOAD_PARTS;
776+
long remainingLength = file.length();
777+
double partSize = (double) remainingLength / (double) MAXIMUM_UPLOAD_PARTS;
775778
partSize = Math.ceil(partSize);
776-
final long optimalPartSize = (long) Math.max(partSize, MINIMUM_UPLOAD_PART_SIZE);
779+
final long optimalPartSize = (long) Math.max(partSize,
780+
transferUtilityOptions.getMinimumUploadPartSizeInBytes());
777781
long fileOffset = 0;
778782
int partNumber = 1;
779783

780784
// the number of parts
781-
final int partCount = (int) Math.ceil((double) remainingLenth / (double) optimalPartSize);
785+
final int partCount = (int) Math.ceil((double) remainingLength / (double) optimalPartSize);
782786

783787
/*
784788
* the size of valuesArray is partCount + 1, one for a multipart upload summary,
@@ -788,11 +792,11 @@ private int createMultipartUploadRecords(String bucket, String key, File file, O
788792
valuesArray[0] = dbUtil.generateContentValuesForMultiPartUpload(bucket, key, file, fileOffset, 0, "",
789793
file.length(), 0, metadata, cannedAcl, transferUtilityOptions);
790794
for (int i = 1; i < partCount + 1; i++) {
791-
final long bytesForPart = Math.min(optimalPartSize, remainingLenth);
795+
final long bytesForPart = Math.min(optimalPartSize, remainingLength);
792796
valuesArray[i] = dbUtil.generateContentValuesForMultiPartUpload(bucket, key, file, fileOffset, partNumber,
793-
"", bytesForPart, remainingLenth - optimalPartSize <= 0 ? 1 : 0, metadata, cannedAcl, transferUtilityOptions);
797+
"", bytesForPart, remainingLength - optimalPartSize <= 0 ? 1 : 0, metadata, cannedAcl, transferUtilityOptions);
794798
fileOffset += optimalPartSize;
795-
remainingLenth -= optimalPartSize;
799+
remainingLength -= optimalPartSize;
796800
partNumber++;
797801
}
798802
return dbUtil.bulkInsertTransferRecords(valuesArray);
@@ -986,7 +990,10 @@ private synchronized void submitTransferJob(String action, int id) {
986990
}
987991

988992
private boolean shouldUploadInMultipart(File file) {
989-
return (file != null && file.length() > MINIMUM_UPLOAD_PART_SIZE);
993+
return (
994+
file != null &&
995+
file.length() > transferUtilityOptions.getMinimumUploadPartSizeInBytes()
996+
);
990997
}
991998

992999
static <X extends AmazonWebServiceRequest> X appendTransferServiceUserAgentString(final X request) {

aws-android-sdk-s3/src/main/java/com/amazonaws/mobileconnectors/s3/transferutility/TransferUtilityOptions.java

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@
1515

1616
package com.amazonaws.mobileconnectors.s3.transferutility;
1717

18+
import static com.amazonaws.mobileconnectors.s3.transferutility.TransferUtility.DEFAULT_MINIMUM_UPLOAD_PART_SIZE_IN_BYTES;
19+
import static com.amazonaws.mobileconnectors.s3.transferutility.TransferUtility.MAXIMUM_SUPPORTED_UPLOAD_PART_SIZE_IN_BYTES;
20+
import static com.amazonaws.mobileconnectors.s3.transferutility.TransferUtility.MINIMUM_SUPPORTED_UPLOAD_PART_SIZE_IN_BYTES;
21+
22+
import com.amazonaws.logging.Log;
23+
import com.amazonaws.logging.LogFactory;
24+
import com.amazonaws.services.s3.internal.Constants;
25+
1826
import java.io.Serializable;
1927

2028
/**
@@ -39,6 +47,8 @@
3947
*/
4048
public class TransferUtilityOptions implements Serializable {
4149

50+
private static final Log LOGGER = LogFactory.getLog(TransferUtilityOptions.class);
51+
4252
/**
4353
* Default serial versionID.
4454
*/
@@ -64,6 +74,12 @@ public class TransferUtilityOptions implements Serializable {
6474
*/
6575
private int transferThreadPoolSize;
6676

77+
/**
78+
* Minimum part size for upload parts. Anything below this will use a
79+
* single upload
80+
*/
81+
private long minimumUploadPartSizeInBytes;
82+
6783
/**
6884
* Type of connection to use for transfers.
6985
*/
@@ -78,6 +94,7 @@ public TransferUtilityOptions() {
7894
this.transferServiceCheckTimeInterval = getDefaultCheckTimeInterval();
7995
this.transferThreadPoolSize = getDefaultThreadPoolSize();
8096
this.transferNetworkConnectionType = getDefaultTransferNetworkConnectionType();
97+
this.minimumUploadPartSizeInBytes = DEFAULT_MINIMUM_UPLOAD_PART_SIZE_IN_BYTES;
8198
}
8299

83100
/**
@@ -93,6 +110,7 @@ public TransferUtilityOptions(int transferThreadPoolSize,
93110
this.transferServiceCheckTimeInterval = getDefaultCheckTimeInterval();
94111
this.transferThreadPoolSize = transferThreadPoolSize;
95112
this.transferNetworkConnectionType = transferNetworkConnectionType;
113+
this.minimumUploadPartSizeInBytes = DEFAULT_MINIMUM_UPLOAD_PART_SIZE_IN_BYTES;
96114
}
97115

98116
/**
@@ -162,6 +180,49 @@ static int getDefaultThreadPoolSize() {
162180
return 2 * (Runtime.getRuntime().availableProcessors() + 1);
163181
}
164182

183+
/**
184+
* Retrieve minimum part size for upload parts in Bytes.
185+
* @return the minimum upload part size in Bytes
186+
*/
187+
protected long getMinimumUploadPartSizeInBytes() {
188+
return minimumUploadPartSizeInBytes;
189+
}
190+
191+
/**
192+
* Retrieve minimum part size for upload parts in MB.
193+
* @return the minimum upload part size in MB
194+
*/
195+
public int getMinimumUploadPartSizeInMB() {
196+
return (int) (minimumUploadPartSizeInBytes / Constants.MB);
197+
}
198+
199+
/**
200+
* Set the minimum part size in MB for upload parts.
201+
* There maximum value allowed is 5GB. Anything higher will set minimum part size at a 5GB.
202+
* There minimum value allowed is 5MB. Anything lower will set minimum part size at 5MB.
203+
* @param minimumUploadPartSizeInMB the minimum part size to set in MB.
204+
*/
205+
public void setMinimumUploadPartSizeInMB(final int minimumUploadPartSizeInMB) {
206+
long minimumUploadPartSizeInBytes = minimumUploadPartSizeInMB * ((long) Constants.MB);
207+
if (minimumUploadPartSizeInBytes > MAXIMUM_SUPPORTED_UPLOAD_PART_SIZE_IN_BYTES) {
208+
LOGGER.warn(
209+
"The provided minimumUploadPartSize is greater than the maximum upload part " +
210+
"size limit. Setting upload part size to the maximum allowed value of"
211+
+ (MINIMUM_SUPPORTED_UPLOAD_PART_SIZE_IN_BYTES / Constants.MB) + "MB."
212+
);
213+
this.minimumUploadPartSizeInBytes = MAXIMUM_SUPPORTED_UPLOAD_PART_SIZE_IN_BYTES;
214+
} else if (minimumUploadPartSizeInBytes < MINIMUM_SUPPORTED_UPLOAD_PART_SIZE_IN_BYTES) {
215+
LOGGER.warn(
216+
"The provided minimumUploadPartSize is less than the minimum upload part " +
217+
"size limit. Setting upload part size to the minimum allowed value of"
218+
+ (MINIMUM_SUPPORTED_UPLOAD_PART_SIZE_IN_BYTES / Constants.MB) + "MB."
219+
);
220+
this.minimumUploadPartSizeInBytes = MINIMUM_SUPPORTED_UPLOAD_PART_SIZE_IN_BYTES;
221+
} else {
222+
this.minimumUploadPartSizeInBytes = minimumUploadPartSizeInBytes;
223+
}
224+
}
225+
165226
/**
166227
* Return the default check time interval.
167228
*

0 commit comments

Comments
 (0)