Skip to content

Commit dd8f5ef

Browse files
author
Brennan Stehling
committed
WIP
1 parent 9205058 commit dd8f5ef

File tree

3 files changed

+60
-100
lines changed

3 files changed

+60
-100
lines changed

AWSS3/AWSS3TransferUtility.m

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2379,7 +2379,6 @@ - (void)completeTask:(AWSS3TransferUtilityTask *)task removeCompletedTask:(BOOL)
23792379
[self.completedTaskDictionary removeObjectForKey:task.transferID];
23802380
[self unregisterTaskIdentifier:task.taskIdentifier];
23812381
}
2382-
23832382
}
23842383

23852384
- (void)cleanupForMultiPartUploadTask:(AWSS3TransferUtilityMultiPartUploadTask *)task {

AWSS3/AWSS3TransferUtilityTasks.m

Lines changed: 57 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,15 @@ - (instancetype)init {
129129
_waitingPartsDictionary = [NSMutableDictionary new];
130130
_inProgressPartsDictionary = [NSMutableDictionary new];
131131
_completedPartsSet = [NSMutableSet new];
132+
_serialQueue = dispatch_queue_create("com.amazonaws.AWSS3.MultipartUploadTask", DISPATCH_QUEUE_SERIAL);
132133
}
133134
return self;
134135
}
135136

136137
- (BOOL)isUnderConcurrencyLimit {
137-
return self.inProgressPartsDictionary.count < [self.transferUtility.transferUtilityConfiguration.multiPartConcurrencyLimit integerValue];
138+
NSUInteger dynamicLimit = NSProcessInfo.processInfo.activeProcessorCount * 2;
139+
NSUInteger configuredLimit = self.transferUtility.transferUtilityConfiguration.multiPartConcurrencyLimit.integerValue;
140+
return self.inProgressPartsDictionary.count < MAX(dynamicLimit, configuredLimit);
138141
}
139142

140143
- (BOOL)hasWaitingTasks {
@@ -167,13 +170,11 @@ - (AWSS3TransferUtilityMultiPartUploadExpression *)expression {
167170
- (void)cancel {
168171
self.cancelled = YES;
169172
self.status = AWSS3TransferUtilityTransferStatusCancelled;
170-
for (NSNumber *key in [self.inProgressPartsDictionary allKeys]) {
171-
AWSS3TransferUtilityUploadSubTask *subTask = [self.inProgressPartsDictionary objectForKey:key];
173+
for (AWSS3TransferUtilityUploadSubTask *subTask in self.inProgressTasks) {
172174
[subTask.sessionTask cancel];
173175
}
174176

175-
for (NSNumber *key in [self.waitingPartsDictionary allKeys]) {
176-
AWSS3TransferUtilityUploadSubTask *subTask = [self.waitingPartsDictionary objectForKey:key];
177+
for (AWSS3TransferUtilityUploadSubTask *subTask in self.waitingTasks) {
177178
[subTask.sessionTask cancel];
178179
}
179180

@@ -190,37 +191,13 @@ - (void)resume {
190191
}
191192

192193
NSCAssert(self.transferUtility != nil, @"Transfer Utility must be provided.");
193-
194-
// for (NSNumber *key in [self.inProgressPartsDictionary allKeys]) {
195-
// AWSS3TransferUtilityUploadSubTask *subTask = [self.inProgressPartsDictionary objectForKey:key];
196-
// subTask.status = AWSS3TransferUtilityTransferStatusInProgress;
197-
// [AWSS3TransferUtilityDatabaseHelper updateTransferRequestInDB:subTask.transferID
198-
// partNumber:subTask.partNumber
199-
// taskIdentifier:subTask.taskIdentifier
200-
// eTag:subTask.eTag
201-
// status:subTask.status
202-
// retry_count:self.retryCount
203-
// databaseQueue:self.databaseQueue];
204-
// [subTask.sessionTask resume];
205-
// }
206-
//
207-
// self.status = AWSS3TransferUtilityTransferStatusInProgress;
208-
// //Update the Master Record
209-
// [AWSS3TransferUtilityDatabaseHelper updateTransferRequestInDB:self.transferID
210-
// partNumber:@0
211-
// taskIdentifier:0
212-
// eTag:@""
213-
// status:self.status
214-
// retry_count:self.retryCount
215-
// databaseQueue:self.databaseQueue];
216194

217195
// Change status from paused to waiting
218196
for (AWSS3TransferUtilityUploadSubTask * nextSubTask in self.waitingTasks) {
219197
nextSubTask.status = AWSS3TransferUtilityTransferStatusWaiting;
220198
}
221199

222-
[self moveWaitingTasksToInProgress];
223-
[self completeIfDone];
200+
[self moveWaitingTasksToInProgress:YES];
224201
}
225202

226203
- (void)suspend {
@@ -231,30 +208,6 @@ - (void)suspend {
231208

232209
NSCAssert(self.transferUtility != nil, @"Transfer Utility must be provided.");
233210

234-
// for (NSNumber *key in [self.inProgressPartsDictionary allKeys]) {
235-
// // all in progress tasks should be cancelled and a new subtask should replace it which is
236-
// // put in the waiting dictionary and set with that status with a URLSessionTask which
237-
// // has not been started.
238-
//
239-
// // then resuming should start uploading a number of parts up to the concurrency limit.
240-
//
241-
// AWSS3TransferUtilityUploadSubTask *subTask = [self.inProgressPartsDictionary objectForKey:key];
242-
// if (!subTask) {
243-
// continue;
244-
// }
245-
// [subTask.sessionTask suspend];
246-
// subTask.status = AWSS3TransferUtilityTransferStatusPaused;
247-
//
248-
// [AWSS3TransferUtilityDatabaseHelper updateTransferRequestInDB:subTask.transferID
249-
// partNumber:subTask.partNumber
250-
// taskIdentifier:subTask.taskIdentifier
251-
// eTag:subTask.eTag
252-
// status:subTask.status
253-
// retry_count:self.retryCount
254-
// databaseQueue:self.databaseQueue];
255-
// }
256-
//
257-
258211
// Cancel session task for all subtasks which are in progress and set status to paused
259212
for (AWSS3TransferUtilityUploadSubTask *inProgressSubTask in self.inProgressTasks) {
260213
// Note: This can happen due to lack of thread-safety
@@ -280,8 +233,7 @@ - (void)suspend {
280233

281234
NSError *error = [self.transferUtility createUploadSubTask:self
282235
subTask:subTask
283-
startTransfer:NO
284-
internalDictionaryToAddSubTaskTo:self.waitingPartsDictionary];
236+
startTransfer:NO];
285237

286238
if (error) {
287239
AWSDDLogError(@"Error creating AWSS3TransferUtilityUploadSubTask [%@]", error);
@@ -294,7 +246,7 @@ - (void)suspend {
294246
[AWSS3TransferUtilityDatabaseHelper insertMultiPartUploadRequestSubTaskInDB:self subTask:subTask databaseQueue:self.databaseQueue];
295247
}
296248
}
297-
249+
298250
self.status = AWSS3TransferUtilityTransferStatusPaused;
299251
//Update the Master Record
300252
[AWSS3TransferUtilityDatabaseHelper updateTransferRequestInDB:self.transferID
@@ -313,13 +265,14 @@ - (void)addUploadSubTask:(AWSS3TransferUtilityUploadSubTask *)subTask {
313265
self.waitingPartsDictionary[@(subTask.taskIdentifier)] = subTask;
314266
} else if (subTask.status == AWSS3TransferUtilityTransferStatusInProgress) {
315267
self.inProgressPartsDictionary[@(subTask.taskIdentifier)] = subTask;
316-
317268
} else if (subTask.status == AWSS3TransferUtilityTransferStatusCompleted) {
318269
[self.completedPartsSet addObject:subTask];
319270
} else {
320271
AWSDDLogDebug(@"Sub Task status not supported: %lu", subTask.status);
321272
NSCAssert(NO, @"Status not supported");
322273
}
274+
275+
[self completeIfDone];
323276
}
324277

325278
- (void)removeWaitingUploadSubTask:(NSUInteger)taskIdentifier {
@@ -344,13 +297,15 @@ - (void)moveWaitingTaskToInProgress:(AWSS3TransferUtilityUploadSubTask *)subTask
344297

345298
- (void)moveWaitingTaskToInProgress:(AWSS3TransferUtilityUploadSubTask *)subTask startTransfer:(BOOL)startTransfer {
346299
if ([self.waitingTasks containsObject:subTask]) {
347-
//Add to inProgress list
300+
// Add to inProgress list
348301
self.inProgressPartsDictionary[@(subTask.taskIdentifier)] = subTask;
349-
//Remove it from the waitingList
302+
// Remove it from the waitingList
350303
self.waitingPartsDictionary[@(subTask.taskIdentifier)] = nil;
351304
AWSDDLogDebug(@"Moving Task[%@] to progress for Multipart[%@]", @(subTask.taskIdentifier), self.uploadID);
352305

353306
if (startTransfer) {
307+
AWSDDLogDebug(@"Starting subTask %@", @(subTask.taskIdentifier));
308+
NSCAssert(subTask.sessionTask.state == NSURLSessionTaskStateSuspended, @"State should be suspended before resuming.");
354309
[subTask.sessionTask resume];
355310
}
356311
}
@@ -381,20 +336,24 @@ - (void)moveWaitingTasksToInProgress:(BOOL)startTransfer {
381336
// move parts from waiting to in progress if under the concurrency limit
382337
while (self.isUnderConcurrencyLimit && self.hasWaitingTasks) {
383338
//Get a part from the waitingList
384-
AWSS3TransferUtilityUploadSubTask *nextSubTask = [[self.waitingPartsDictionary allValues] objectAtIndex:0];
339+
AWSS3TransferUtilityUploadSubTask *nextSubTask = [self.waitingTasks objectAtIndex:0];
385340

386341
//Add to inProgress list
387342
self.inProgressPartsDictionary[@(nextSubTask.taskIdentifier)] = nextSubTask;
343+
nextSubTask.status = AWSS3TransferUtilityTransferStatusInProgress;
388344

389345
//Remove it from the waitingList
390-
[self.waitingPartsDictionary removeObjectForKey:@(nextSubTask.taskIdentifier)];
346+
self.waitingPartsDictionary[@(nextSubTask.taskIdentifier)] = nil;
391347
AWSDDLogDebug(@"Moving Task[%@] to progress for Multipart[%@]", @(nextSubTask.taskIdentifier), self.uploadID);
348+
392349
if (startTransfer) {
393350
AWSDDLogDebug(@"Starting subTask %@", @(nextSubTask.taskIdentifier));
351+
NSCAssert(nextSubTask.sessionTask.state == NSURLSessionTaskStateSuspended, @"State should be suspended before resuming.");
394352
[nextSubTask.sessionTask resume];
395353
}
396-
nextSubTask.status = AWSS3TransferUtilityTransferStatusInProgress;
397354
}
355+
356+
[self completeIfDone];
398357
}
399358

400359
- (void)completeUploadSubTask:(AWSS3TransferUtilityUploadSubTask *)subTask
@@ -421,45 +380,49 @@ - (void)completeUploadSubTask:(AWSS3TransferUtilityUploadSubTask *)subTask
421380
}
422381

423382
- (void)completeIfDone {
424-
// Complete multipart upload if in progress and waiting tasks are done
425-
if (!self.isDone) {
426-
return;
427-
}
383+
dispatch_async(self.serialQueue, ^{
384+
// Complete multipart upload if in progress and waiting tasks are done
385+
if (!self.isDone && self.status != AWSS3TransferUtilityTransferStatusCompleted) {
386+
return;
387+
}
428388

429-
//If there are no more inProgress parts, then we are done.
389+
//If there are no more inProgress parts, then we are done.
430390

431-
//Validate that all the content has been uploaded.
432-
int64_t totalBytesSent = 0;
433-
for (AWSS3TransferUtilityUploadSubTask *aSubTask in self.completedPartsSet) {
434-
totalBytesSent += aSubTask.totalBytesExpectedToSend;
435-
}
391+
//Validate that all the content has been uploaded.
392+
int64_t totalBytesSent = 0;
393+
for (AWSS3TransferUtilityUploadSubTask *aSubTask in self.completedTasks) {
394+
totalBytesSent += aSubTask.totalBytesExpectedToSend;
395+
}
436396

437-
if (totalBytesSent != self.contentLength.longLongValue ) {
438-
NSString *errorMessage = [NSString stringWithFormat:@"Expected to send [%@], but sent [%@] and there are no remaining parts. Failing transfer ",
439-
self.contentLength, @(totalBytesSent)];
440-
AWSDDLogDebug(@"%@", errorMessage);
441-
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:errorMessage
442-
forKey:@"Message"];
397+
if (totalBytesSent != self.contentLength.longLongValue ) {
398+
NSString *errorMessage = [NSString stringWithFormat:@"Expected to send [%@], but sent [%@] and there are no remaining parts. Failing transfer ",
399+
self.contentLength, @(totalBytesSent)];
400+
AWSDDLogDebug(@"%@", errorMessage);
401+
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:errorMessage
402+
forKey:@"Message"];
443403

444-
self.error = [NSError errorWithDomain:AWSS3TransferUtilityErrorDomain
445-
code:AWSS3TransferUtilityErrorClientError
446-
userInfo:userInfo];
404+
self.error = [NSError errorWithDomain:AWSS3TransferUtilityErrorDomain
405+
code:AWSS3TransferUtilityErrorClientError
406+
userInfo:userInfo];
447407

448-
//Execute call back if provided.
449-
[self.transferUtility completeTask:self];
408+
//Execute call back if provided.
409+
[self.transferUtility completeTask:self];
450410

451-
//Abort the request, so the server can clean up any partials.
452-
[self.transferUtility callAbortMultiPartForUploadTask:self];
411+
//Abort the request, so the server can clean up any partials.
412+
[self.transferUtility callAbortMultiPartForUploadTask:self];
453413

454-
//clean up.
455-
[self.transferUtility cleanupForMultiPartUploadTask:self];
456-
return;
457-
}
414+
//clean up.
415+
[self.transferUtility cleanupForMultiPartUploadTask:self];
416+
return;
417+
}
418+
419+
AWSDDLogDebug(@"There are %lu waiting upload parts.", (unsigned long)self.waitingTasks.count);
420+
AWSDDLogDebug(@"There are %lu in progress upload parts.", (unsigned long)self.inProgressTasks.count);
421+
AWSDDLogDebug(@"There are %lu completed upload parts.", (unsigned long)self.completedTasks.count);
422+
[self.transferUtility completeMultiPartForUploadTask:self];
423+
self.status = AWSS3TransferUtilityTransferStatusCompleted;
424+
});
458425

459-
AWSDDLogDebug(@"There are %lu waiting upload parts.", (unsigned long)self.waitingPartsDictionary.count);
460-
AWSDDLogDebug(@"There are %lu in progress upload parts.", (unsigned long)self.inProgressPartsDictionary.count);
461-
AWSDDLogDebug(@"There are %lu completed upload parts.", (unsigned long)self.completedPartsSet.count);
462-
[self.transferUtility completeMultiPartForUploadTask:self];
463426
}
464427

465428
- (void)setCompletionHandler:(AWSS3TransferUtilityMultiPartUploadCompletionHandlerBlock)completionHandler {
@@ -498,7 +461,6 @@ - (void)cancel {
498461
}
499462

500463
- (void)setCompletionHandler:(AWSS3TransferUtilityDownloadCompletionHandlerBlock)completionHandler {
501-
502464
self.expression.completionHandler = completionHandler;
503465
//If the task has already completed successfully
504466
//Or the task has completed with error, complete the task

AWSS3/AWSS3TransferUtility_private.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,11 @@
2323
@interface AWSS3TransferUtility ()
2424

2525
- (NSError *)createUploadSubTask:(AWSS3TransferUtilityMultiPartUploadTask *)transferUtilityMultiPartUploadTask
26-
subTask:(AWSS3TransferUtilityUploadSubTask *)subTask
27-
internalDictionaryToAddSubTaskTo:(NSMutableDictionary *)internalDictionaryToAddSubTaskTo;
26+
subTask:(AWSS3TransferUtilityUploadSubTask *)subTask;
2827

2928
- (NSError *)createUploadSubTask:(AWSS3TransferUtilityMultiPartUploadTask *)transferUtilityMultiPartUploadTask
3029
subTask:(AWSS3TransferUtilityUploadSubTask *)subTask
31-
startTransfer:(BOOL)startTransfer
32-
internalDictionaryToAddSubTaskTo:(NSMutableDictionary *)internalDictionaryToAddSubTaskTo;
30+
startTransfer:(BOOL)startTransfer;
3331

3432
- (void)completeTask:(AWSS3TransferUtilityTask *)task;
3533
- (AWSTask *)callAbortMultiPartForUploadTask:(AWSS3TransferUtilityMultiPartUploadTask *)uploadTask;
@@ -81,6 +79,7 @@ internalDictionaryToAddSubTaskTo:(NSMutableDictionary *)internalDictionaryToAddS
8179
@property (strong, nonatomic) NSMutableDictionary <NSNumber *, AWSS3TransferUtilityUploadSubTask *> *waitingPartsDictionary;
8280
@property (strong, nonatomic) NSMutableDictionary <NSNumber *, AWSS3TransferUtilityUploadSubTask *> *inProgressPartsDictionary;
8381
@property (strong, nonatomic) NSMutableSet <AWSS3TransferUtilityUploadSubTask *> *completedPartsSet;
82+
@property (strong, nonatomic) dispatch_queue_t serialQueue;
8483
@property int partNumber;
8584
@property NSNumber *contentLength;
8685

0 commit comments

Comments
 (0)