From f059e0e639e5b6a25fed83e923b28d9bf9613e66 Mon Sep 17 00:00:00 2001 From: Miltiadis Vasilakis Date: Fri, 18 Nov 2011 11:41:51 +0200 Subject: [PATCH] Memory leaks plugged. Sync daemon uses background thread for ASIPithosRequest callbacks. For server updates from local objects, a check is made if the local object still exists, and the appropriate action is taken. --- pithos-apple-common | 2 +- pithos-macos/PithosBrowserController.m | 39 ++- pithos-macos/PithosLocalObjectState.h | 3 + pithos-macos/PithosLocalObjectState.m | 2 +- pithos-macos/PithosNode.m | 2 +- pithos-macos/PithosSharingAccountsNode.m | 2 +- pithos-macos/PithosSubdirNode.m | 4 +- pithos-macos/PithosSyncDaemon.h | 2 +- pithos-macos/PithosSyncDaemon.m | 539 ++++++++++++++++++++---------- pithos-macos/PithosUtilities.m | 4 +- 10 files changed, 391 insertions(+), 208 deletions(-) diff --git a/pithos-apple-common b/pithos-apple-common index 0a4b9bd..25cafff 160000 --- a/pithos-apple-common +++ b/pithos-apple-common @@ -1 +1 @@ -Subproject commit 0a4b9bd3aa71857ebe3439befde0dc5c3b3c96b0 +Subproject commit 25cafffeaeaa994a761f9bacd5efc80308f3f60c diff --git a/pithos-macos/PithosBrowserController.m b/pithos-macos/PithosBrowserController.m index c949d79..f3c13eb 100644 --- a/pithos-macos/PithosBrowserController.m +++ b/pithos-macos/PithosBrowserController.m @@ -282,7 +282,7 @@ ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest createOrUpdateContainerRequestWithContainerName:@"pithos"]; [[PithosUtilities prepareRequest:containerRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; while (![containerRequest isFinished]) { - sleep(1); + usleep(1); } if ([containerRequest error]) { [PithosUtilities httpRequestErrorAlertWithRequest:containerRequest]; @@ -295,7 +295,7 @@ ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest createOrUpdateContainerRequestWithContainerName:@"trash"]; [[PithosUtilities prepareRequest:containerRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; while (![containerRequest isFinished]) { - sleep(1); + usleep(1); } if ([containerRequest error]) { [PithosUtilities httpRequestErrorAlertWithRequest:containerRequest]; @@ -759,7 +759,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest containerMetadataRequestWithContainerName:containerName]; [[PithosUtilities prepareRequest:containerRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; while (![containerRequest isFinished]) { - sleep(1); + usleep(1); } if ([containerRequest error]) { [PithosUtilities httpRequestErrorAlertWithRequest:containerRequest]; @@ -1090,7 +1090,6 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { NSString *filePath = [objectRequest.userInfo objectForKey:@"filePath"]; PithosActivity *activity = [objectRequest.userInfo objectForKey:@"activity"]; NSUInteger totalBytes = activity.totalBytes; - NSUInteger currentBytes = activity.currentBytes; // XXX change contentLength to objectContentLength if it is fixed in the server if (([objectRequest contentLength] == 0) && ![PithosUtilities isContentTypeDirectory:[objectRequest contentType]]) { @@ -1107,7 +1106,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { } } - currentBytes = [objectRequest objectContentLength]; + NSUInteger currentBytes = [objectRequest objectContentLength]; if (currentBytes == 0) currentBytes = totalBytes; [activityFacility endActivity:activity @@ -1118,7 +1117,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { } else { NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; if (retries > 0) { - ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest]; + ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[[PithosUtilities copyRequest:objectRequest] autorelease]; [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; [[PithosUtilities prepareRequest:newObjectRequest] startAsynchronous]; } else { @@ -1134,7 +1133,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { NSLog(@"Download failed: %@", objectRequest.url); NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; if (retries > 0) { - ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest]; + ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[[PithosUtilities copyRequest:objectRequest] autorelease]; [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; [[PithosUtilities prepareRequest:newObjectRequest] startAsynchronous]; } else { @@ -1165,7 +1164,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { } else { NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; if (retries > 0) { - ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest]; + ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[[PithosUtilities copyRequest:objectRequest] autorelease]; [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; [[PithosUtilities prepareRequest:newObjectRequest] startAsynchronous]; } else { @@ -1181,7 +1180,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { NSLog(@"Upload directory object failed: %@", objectRequest.url); NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; if (retries > 0) { - ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest]; + ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[[PithosUtilities copyRequest:objectRequest] autorelease]; [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; [[PithosUtilities prepareRequest:newObjectRequest] startAsynchronous]; } else { @@ -1262,7 +1261,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { } else { NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; if (retries > 0) { - ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest]; + ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[[PithosUtilities copyRequest:objectRequest] autorelease]; [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; [[PithosUtilities prepareRequest:newObjectRequest] startAsynchronous]; } else { @@ -1277,7 +1276,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { NSLog(@"Upload using hashmap failed: %@", objectRequest.url); NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; if (retries > 0) { - ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest]; + ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[[PithosUtilities copyRequest:objectRequest] autorelease]; [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; [[PithosUtilities prepareRequest:newObjectRequest] startAsynchronous]; } else { @@ -1339,7 +1338,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { } else { NSUInteger retries = [[containerRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; if (retries > 0) { - ASIPithosContainerRequest *newContainerRequest = (ASIPithosContainerRequest *)[PithosUtilities copyRequest:containerRequest]; + ASIPithosContainerRequest *newContainerRequest = (ASIPithosContainerRequest *)[[PithosUtilities copyRequest:containerRequest] autorelease]; [(NSMutableDictionary *)(newContainerRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; [[PithosUtilities prepareRequest:newContainerRequest] startAsynchronous]; } else { @@ -1354,7 +1353,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { NSLog(@"Upload of missing block failed: %@", containerRequest.url); NSUInteger retries = [[containerRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; if (retries > 0) { - ASIPithosContainerRequest *newContainerRequest = (ASIPithosContainerRequest *)[PithosUtilities copyRequest:containerRequest]; + ASIPithosContainerRequest *newContainerRequest = (ASIPithosContainerRequest *)[[PithosUtilities copyRequest:containerRequest] autorelease]; [(NSMutableDictionary *)(newContainerRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; [[PithosUtilities prepareRequest:newContainerRequest] startAsynchronous]; } else { @@ -1387,7 +1386,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { } else { NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; if (retries > 0) { - ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest]; + ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[[PithosUtilities copyRequest:objectRequest] autorelease]; [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; [[PithosUtilities prepareRequest:newObjectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; } else { @@ -1406,7 +1405,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { NSLog(@"Move object failed: %@", objectRequest.url); NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; if (retries > 0) { - ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest]; + ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[[PithosUtilities copyRequest:objectRequest] autorelease]; [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; [[PithosUtilities prepareRequest:newObjectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; } else { @@ -1442,7 +1441,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { } else { NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; if (retries > 0) { - ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest]; + ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[[PithosUtilities copyRequest:objectRequest] autorelease]; [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; [[PithosUtilities prepareRequest:newObjectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; } else { @@ -1461,7 +1460,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { NSLog(@"Copy object failed: %@", objectRequest.url); NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; if (retries > 0) { - ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest]; + ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[[PithosUtilities copyRequest:objectRequest] autorelease]; [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; [[PithosUtilities prepareRequest:newObjectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; } else { @@ -1494,7 +1493,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { } else { NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; if (retries > 0) { - ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest]; + ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[[PithosUtilities copyRequest:objectRequest] autorelease]; [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; [[PithosUtilities prepareRequest:newObjectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; } else { @@ -1510,7 +1509,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { NSLog(@"Delete object failed: %@", objectRequest.url); NSUInteger retries = [[objectRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; if (retries > 0) { - ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[PithosUtilities copyRequest:objectRequest]; + ASIPithosObjectRequest *newObjectRequest = (ASIPithosObjectRequest *)[[PithosUtilities copyRequest:objectRequest] autorelease]; [(NSMutableDictionary *)(newObjectRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; [[PithosUtilities prepareRequest:newObjectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; } else { @@ -1665,7 +1664,7 @@ forDraggedRowsWithIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column { NSMenuItem *menuItem; NSString *menuItemTitle; BOOL nodeContextMenu = NO; - PithosNode *menuNode; + PithosNode *menuNode = nil; NSMutableArray *menuNodes; if (menu == browserMenu) { NSInteger column = [browser clickedColumn]; diff --git a/pithos-macos/PithosLocalObjectState.h b/pithos-macos/PithosLocalObjectState.h index 71943a6..d3cf306 100644 --- a/pithos-macos/PithosLocalObjectState.h +++ b/pithos-macos/PithosLocalObjectState.h @@ -42,6 +42,9 @@ NSString *hashMapHash; NSString *filePath; BOOL isDirectory; + + BOOL exists; + NSString *hash; } - (id)initWithFile:(NSString *)aFilePath blockHash:(NSString *)blockHash blockSize:(NSUInteger)blockSize; diff --git a/pithos-macos/PithosLocalObjectState.m b/pithos-macos/PithosLocalObjectState.m index 61d73f2..3280ca9 100644 --- a/pithos-macos/PithosLocalObjectState.m +++ b/pithos-macos/PithosLocalObjectState.m @@ -52,7 +52,7 @@ if ([[NSFileManager defaultManager] fileExistsAtPath:filePath isDirectory:&isDirectory] && !isDirectory) { self.md5 = (NSString *)FileMD5HashCreateWithPath((CFStringRef)aFilePath, FileHashDefaultChunkSizeForReadingData); - self.hashMapHash = [HashMapHash calculateHashMapHash:[HashMapHash calculateObjectHashMap:filePath + self.hashMapHash = [HashMapHash calculateHashMapHash:[HashMapHash calculateObjectHashMap:aFilePath withBlockHash:blockHash andBlockSize:blockSize]]; } diff --git a/pithos-macos/PithosNode.m b/pithos-macos/PithosNode.m index ccb60cd..80d0abd 100644 --- a/pithos-macos/PithosNode.m +++ b/pithos-macos/PithosNode.m @@ -47,7 +47,7 @@ #pragma mark Object Lifecycle - (id)init { - if ((self == [super init])) { + if ((self = [super init])) { freshness = PithosNodeStateRefreshNeeded; forcedRefresh = NO; shared = NO; diff --git a/pithos-macos/PithosSharingAccountsNode.m b/pithos-macos/PithosSharingAccountsNode.m index 029d331..4dcebd5 100644 --- a/pithos-macos/PithosSharingAccountsNode.m +++ b/pithos-macos/PithosSharingAccountsNode.m @@ -49,7 +49,7 @@ #pragma mark Object Lifecycle - (id)init { - if ((self == [super init])) { + if ((self = [super init])) { self.sharingAccount = @""; } return self; diff --git a/pithos-macos/PithosSubdirNode.m b/pithos-macos/PithosSubdirNode.m index 8188c46..3b9a41b 100644 --- a/pithos-macos/PithosSubdirNode.m +++ b/pithos-macos/PithosSubdirNode.m @@ -188,7 +188,7 @@ static NSImage *sharedIcon = nil; objectName:prefix]; [[PithosUtilities prepareRequest:request] startAsynchronous]; while (![request isFinished]) { - sleep(1); + usleep(1); } if ([request error]) { alert = [[[NSAlert alloc] init] autorelease]; @@ -209,7 +209,7 @@ static NSImage *sharedIcon = nil; objectName:prefix]; [[PithosUtilities prepareRequest:request] startAsynchronous]; while (![request isFinished]) { - sleep(1); + usleep(1); } if ([request error]) { alert = [[[NSAlert alloc] init] autorelease]; diff --git a/pithos-macos/PithosSyncDaemon.h b/pithos-macos/PithosSyncDaemon.h index 450288f..1fc3843 100644 --- a/pithos-macos/PithosSyncDaemon.h +++ b/pithos-macos/PithosSyncDaemon.h @@ -62,7 +62,7 @@ NSDate *lastCompletedSync; BOOL syncIncomplete; - ASINetworkQueue *queue; + ASINetworkQueue *networkQueue; NSTimer *timer; PithosActivityFacility *activityFacility; diff --git a/pithos-macos/PithosSyncDaemon.m b/pithos-macos/PithosSyncDaemon.m index fec9018..f80e522 100644 --- a/pithos-macos/PithosSyncDaemon.m +++ b/pithos-macos/PithosSyncDaemon.m @@ -122,10 +122,10 @@ self.storedLocalObjectStates = [NSMutableDictionary dictionary]; } - queue = [[ASINetworkQueue alloc] init]; - queue.showAccurateProgress = YES; - queue.shouldCancelAllRequestsOnFailure = NO; - [queue go]; + networkQueue = [[ASINetworkQueue alloc] init]; + networkQueue.showAccurateProgress = YES; + networkQueue.shouldCancelAllRequestsOnFailure = NO; + [networkQueue go]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillTerminate:) @@ -141,8 +141,8 @@ - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; - [queue cancelAllOperations]; - [queue release]; + [networkQueue cancelAllOperations]; + [networkQueue release]; [timer invalidate]; [timer release]; [tempTrashDirPath release]; @@ -162,6 +162,123 @@ } #pragma mark - +#pragma mark Background + +- (void)fileActionFailedAlert:(NSDictionary *)args { + [PithosUtilities fileActionFailedAlertWithTitle:[args objectForKey:@"title"] + message:[args objectForKey:@"message"] + error:[args objectForKey:@"error"]]; +} + +- (void)fileActionFailedAlertWithTitle:(NSString *)title + message:(NSString *)message + error:(NSError *)error { + NSMutableDictionary *args = [NSMutableDictionary dictionaryWithObjectsAndKeys: + title, @"title", + message, @"message", + nil]; + if (error) + [args setObject:error forKey:@"error"]; + [self performSelectorOnMainThread:@selector(fileActionFailedAlert:) + withObject:args + waitUntilDone:YES]; +} + +- (void)startAndEndActivity:(NSDictionary *)args { + [activityFacility startAndEndActivityWithType:[[args objectForKey:@"type"] intValue] message:[args objectForKey:@"message"]]; +} + +- (void)startAndEndActivityWithType:(PithosActivityType)type message:(NSString *)message { + NSDictionary *args = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithInt:type], @"type", + message, @"message", + nil]; + [self performSelectorOnMainThread:@selector(startAndEndActivity:) + withObject:args + waitUntilDone:YES]; +} + +- (void)updateActivity:(NSDictionary *)args { + NSNumber *totalBytesNumber = [args objectForKey:@"totalBytes"]; + NSNumber *currentBytesNumber = [args objectForKey:@"currentBytes"]; + if (totalBytesNumber && currentBytesNumber) + [activityFacility updateActivity:[args objectForKey:@"activity"] + withMessage:[args objectForKey:@"message"] + totalBytes:[totalBytesNumber unsignedIntegerValue] + currentBytes:[currentBytesNumber unsignedIntegerValue]]; + else + [activityFacility updateActivity:[args objectForKey:@"activity"] + withMessage:[args objectForKey:@"message"]]; +} + +- (void)updateActivity:(PithosActivity *)activity + withMessage:(NSString *)message + totalBytes:(NSUInteger)totalBytes + currentBytes:(NSUInteger)currentBytes { + NSMutableDictionary *args = [NSMutableDictionary dictionaryWithObjectsAndKeys: + activity, @"activity", + [NSNumber numberWithUnsignedInteger:totalBytes], @"totalBytes", + [NSNumber numberWithUnsignedInteger:currentBytes], @"currentBytes", + nil]; + if (message) + [args setObject:message forKey:@"message"]; + [self performSelectorOnMainThread:@selector(updateActivity:) + withObject:args + waitUntilDone:YES]; +} + +- (void)updateActivity:(PithosActivity *)activity withMessage:(NSString *)message { + NSMutableDictionary *args = [NSMutableDictionary dictionaryWithObjectsAndKeys: + activity, @"activity", + nil]; + if (message) + [args setObject:message forKey:@"message"]; + [self performSelectorOnMainThread:@selector(updateActivity:) + withObject:args + waitUntilDone:YES]; +} + +- (void)endActivity:(NSDictionary *)args { + NSNumber *totalBytesNumber = [args objectForKey:@"totalBytes"]; + NSNumber *currentBytesNumber = [args objectForKey:@"currentBytes"]; + if (totalBytesNumber && currentBytesNumber) + [activityFacility endActivity:[args objectForKey:@"activity"] + withMessage:[args objectForKey:@"message"] + totalBytes:[totalBytesNumber unsignedIntegerValue] + currentBytes:[currentBytesNumber unsignedIntegerValue]]; + else + [activityFacility endActivity:[args objectForKey:@"activity"] + withMessage:[args objectForKey:@"message"]]; +} + +- (void)endActivity:(PithosActivity *)activity + withMessage:(NSString *)message + totalBytes:(NSUInteger)totalBytes + currentBytes:(NSUInteger)currentBytes { + NSMutableDictionary *args = [NSMutableDictionary dictionaryWithObjectsAndKeys: + activity, @"activity", + [NSNumber numberWithUnsignedInteger:totalBytes], @"totalBytes", + [NSNumber numberWithUnsignedInteger:currentBytes], @"currentBytes", + nil]; + if (message) + [args setObject:message forKey:@"message"]; + [self performSelectorOnMainThread:@selector(endActivity:) + withObject:args + waitUntilDone:YES]; +} + +- (void)endActivity:(PithosActivity *)activity withMessage:(NSString *)message { + NSMutableDictionary *args = [NSMutableDictionary dictionaryWithObjectsAndKeys: + activity, @"activity", + nil]; + if (message) + [args setObject:message forKey:@"message"]; + [self performSelectorOnMainThread:@selector(endActivity:) + withObject:args + waitUntilDone:YES]; +} + +#pragma mark - #pragma mark Observers - (void)applicationWillTerminate:(NSNotification *)notification { @@ -174,7 +291,7 @@ - (NSString *)pithosStateFilePath { if (!pithosStateFilePath) pithosStateFilePath = [[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"PithosLocalObjectStates.archive"] retain]; - return [pithosStateFilePath copy]; + return [[pithosStateFilePath copy] autorelease]; } - (NSString *)tempDownloadsDirPath { @@ -209,7 +326,7 @@ [userDefaults setObject:tempDownloadsDirPath forKey:@"PithosSyncTempDownloadsDirPath"]; [tempDownloadsDirPath retain]; } - return [tempDownloadsDirPath copy]; + return [[tempDownloadsDirPath copy] autorelease]; } - (NSString *)tempTrashDirPath { @@ -244,7 +361,7 @@ [userDefaults setObject:tempTrashDirPath forKey:@"PithosSyncTempTrashDirPath"]; [tempTrashDirPath retain]; } - return [tempTrashDirPath copy]; + return [[tempTrashDirPath copy] autorelease]; } #pragma mark - @@ -270,8 +387,8 @@ if (!syncOperationCount) { if (!syncIncomplete) { self.lastCompletedSync = [NSDate date]; - [activityFacility startAndEndActivityWithType:PithosActivityOther - message:[NSString stringWithFormat:@"Sync: Completed %@", lastCompletedSync]]; + [self startAndEndActivityWithType:PithosActivityOther + message:[NSString stringWithFormat:@"Sync: Completed %@", lastCompletedSync]]; } [self emptyTempTrash]; } @@ -327,8 +444,8 @@ until:nil ifModifiedSince:lastModified]; containerRequest.delegate = self; - containerRequest.didFinishSelector = @selector(listRequestFinished:); - containerRequest.didFailSelector = @selector(listRequestFailed:); + containerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:); + containerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:); PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityOther message:@"Sync: Getting server listing"]; containerRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: @@ -338,8 +455,10 @@ @"Sync: Getting server listing (finished)", @"finishedActivityMessage", [NSNumber numberWithInteger:NSOperationQueuePriorityVeryHigh], @"priority", [NSNumber numberWithUnsignedInteger:10], @"retries", + NSStringFromSelector(@selector(listRequestFinished:)), @"didFinishSelector", + NSStringFromSelector(@selector(listRequestFailed:)), @"didFailSelector", nil]; - [queue addOperation:[PithosUtilities prepareRequest:containerRequest priority:NSOperationQueuePriorityVeryHigh]]; + [networkQueue addOperation:[PithosUtilities prepareRequest:containerRequest priority:NSOperationQueuePriorityVeryHigh]]; } - (void)emptyTempTrash { @@ -350,9 +469,9 @@ // NSArray *subPaths = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:trashDirPath error:&error]; NSArray *subPaths = [fileManager contentsOfDirectoryAtPath:trashDirPath error:&error]; if (error) { - [PithosUtilities fileActionFailedAlertWithTitle:@"Directory Contents Error" - message:[NSString stringWithFormat:@"Cannot get contents of directory at '%@'", containerDirectoryPath] - error:error]; + [self fileActionFailedAlertWithTitle:@"Directory Contents Error" + message:[NSString stringWithFormat:@"Cannot get contents of directory at '%@'", containerDirectoryPath] + error:error]; return; } if ([subPaths count]) { @@ -363,9 +482,9 @@ // syncOperationCount = 1; // [[NSWorkspace sharedWorkspace] recycleURLs:subURLs completionHandler:^(NSDictionary *newURLs, NSError *error) { // if (error) { -// [PithosUtilities fileActionFailedAlertWithTitle:@"Move to Trash Error" -// message:@"Cannot move files to Trash" -// error:error]; +// [self fileActionFailedAlertWithTitle:@"Move to Trash Error" +// message:@"Cannot move files to Trash" +// error:error]; // } // syncOperationCount = 0; // }]; @@ -373,9 +492,9 @@ NSString *subFilePath = [trashDirPath stringByAppendingPathComponent:subPath]; error = nil; if (![fileManager removeItemAtPath:subFilePath error:&error] || error) - [PithosUtilities fileActionFailedAlertWithTitle:@"Remove File Error" - message:[NSString stringWithFormat:@"Cannot remove file at '%@'", subFilePath] - error:error]; + [self fileActionFailedAlertWithTitle:@"Remove File Error" + message:[NSString stringWithFormat:@"Cannot remove file at '%@'", subFilePath] + error:error]; } } } @@ -395,22 +514,22 @@ if (fileExists && isDirectory) { NSArray *subPaths = [fileManager subpathsOfDirectoryAtPath:filePath error:&error]; if (error) { - [PithosUtilities fileActionFailedAlertWithTitle:@"Directory Contents Error" - message:[NSString stringWithFormat:@"Cannot get contents of directory at '%@'", containerDirectoryPath] - error:error]; + [self fileActionFailedAlertWithTitle:@"Directory Contents Error" + message:[NSString stringWithFormat:@"Cannot get contents of directory at '%@'", containerDirectoryPath] + error:error]; return NO; } if (![fileManager createDirectoryAtPath:newDirPath withIntermediateDirectories:YES attributes:nil error:&error] || error) { - [PithosUtilities fileActionFailedAlertWithTitle:@"Create Directory Error" - message:[NSString stringWithFormat:@"Cannot create directory at '%@'", newDirPath] - error:error]; + [self fileActionFailedAlertWithTitle:@"Create Directory Error" + message:[NSString stringWithFormat:@"Cannot create directory at '%@'", newDirPath] + error:error]; return NO; } if (![fileManager moveItemAtPath:filePath toPath:newFilePath error:&error] || error) { - [PithosUtilities fileActionFailedAlertWithTitle:@"Move File Error" - message:[NSString stringWithFormat:@"Cannot move file at '%@' to '%@'", - filePath, newFilePath] - error:error]; + [self fileActionFailedAlertWithTitle:@"Move File Error" + message:[NSString stringWithFormat:@"Cannot move file at '%@' to '%@'", + filePath, newFilePath] + error:error]; return NO; } PithosLocalObjectState *currentState = [currentLocalObjectStates objectForKey:filePath]; @@ -442,16 +561,16 @@ } } else if (fileExists && !isDirectory) { if (![fileManager createDirectoryAtPath:newDirPath withIntermediateDirectories:YES attributes:nil error:&error] || error) { - [PithosUtilities fileActionFailedAlertWithTitle:@"Create Directory Error" - message:[NSString stringWithFormat:@"Cannot create directory at '%@'", newDirPath] - error:error]; + [self fileActionFailedAlertWithTitle:@"Create Directory Error" + message:[NSString stringWithFormat:@"Cannot create directory at '%@'", newDirPath] + error:error]; return NO; } if (![fileManager moveItemAtPath:filePath toPath:newFilePath error:&error] || error) { - [PithosUtilities fileActionFailedAlertWithTitle:@"Move File Error" - message:[NSString stringWithFormat:@"Cannot move file at '%@' to '%@'", - filePath, newFilePath] - error:error]; + [self fileActionFailedAlertWithTitle:@"Move File Error" + message:[NSString stringWithFormat:@"Cannot move file at '%@' to '%@'", + filePath, newFilePath] + error:error]; return NO; } PithosLocalObjectState *currentState = [currentLocalObjectStates objectForKey:filePath]; @@ -483,19 +602,19 @@ [fileManager fileExistsAtPath:localFilePath isDirectory:&isDirectory] && !isDirectory) { if ([localFilePath hasPrefix:containerDirectoryPath]) { if (![fileManager copyItemAtPath:localFilePath toPath:filePath error:&error] || error) { - [PithosUtilities fileActionFailedAlertWithTitle:@"Copy File Error" - message:[NSString stringWithFormat:@"Cannot copy file at '%@' to '%@'", - localFilePath, filePath] - error:error]; + [self fileActionFailedAlertWithTitle:@"Copy File Error" + message:[NSString stringWithFormat:@"Cannot copy file at '%@' to '%@'", + localFilePath, filePath] + error:error]; } else { return YES; } } else if (self.tempTrashDirPath && [localFilePath hasPrefix:self.tempTrashDirPath]) { if (![fileManager moveItemAtPath:localFilePath toPath:filePath error:&error] || error) { - [PithosUtilities fileActionFailedAlertWithTitle:@"Move File Error" - message:[NSString stringWithFormat:@"Cannot move file at '%@' to '%@'", - localFilePath, filePath] - error:error]; + [self fileActionFailedAlertWithTitle:@"Move File Error" + message:[NSString stringWithFormat:@"Cannot move file at '%@' to '%@'", + localFilePath, filePath] + error:error]; } else { localState.filePath = filePath; [currentLocalObjectStates setObject:localState forKey:filePath]; @@ -519,8 +638,8 @@ // Delete local object NSLog(@"Sync::delete local object: %@", filePath); if (!fileExists || [self moveToTempTrashFile:filePath]) { - [activityFacility startAndEndActivityWithType:PithosActivityOther - message:[NSString stringWithFormat:@"Sync: Deleting '%@' locally (finished)", object.name]]; + [self startAndEndActivityWithType:PithosActivityOther + message:[NSString stringWithFormat:@"Sync: Deleting '%@' locally (finished)", object.name]]; [storedLocalObjectStates removeObjectForKey:object.name]; [self saveLocalState]; } @@ -532,9 +651,9 @@ NSLog(@"Sync::local directory object doesn't exist: %@", filePath); error = nil; if (![fileManager createDirectoryAtPath:filePath withIntermediateDirectories:YES attributes:nil error:&error] || error) { - [PithosUtilities fileActionFailedAlertWithTitle:@"Create Directory Error" - message:[NSString stringWithFormat:@"Cannot create directory at '%@'", filePath] - error:error]; + [self fileActionFailedAlertWithTitle:@"Create Directory Error" + message:[NSString stringWithFormat:@"Cannot create directory at '%@'", filePath] + error:error]; } else { directoryCreated = YES; storedState.isDirectory = YES; @@ -545,8 +664,8 @@ directoryCreated = YES; } if (directoryCreated) - [activityFacility startAndEndActivityWithType:PithosActivityOther - message:[NSString stringWithFormat:@"Sync: Creating directory '%@' locally (finished)", object.name]]; + [self startAndEndActivityWithType:PithosActivityOther + message:[NSString stringWithFormat:@"Sync: Creating directory '%@' locally (finished)", object.name]]; } else if (object.bytes == 0) { // Create local object with zero length NSLog(@"Sync::create local zero length object: %@", filePath); @@ -555,9 +674,9 @@ NSLog(@"Sync::local zero length object doesn't exist: %@", filePath); error = nil; if (![fileManager createFileAtPath:filePath contents:nil attributes:nil]) { - [PithosUtilities fileActionFailedAlertWithTitle:@"Create File Error" - message:[NSString stringWithFormat:@"Cannot create file at '%@'", filePath] - error:error]; + [self fileActionFailedAlertWithTitle:@"Create File Error" + message:[NSString stringWithFormat:@"Cannot create file at '%@'", filePath] + error:error]; } else { fileCreated = YES; storedState.hash = object.hash; @@ -569,14 +688,14 @@ fileCreated = YES; } if (fileCreated) - [activityFacility startAndEndActivityWithType:PithosActivityOther - message:[NSString stringWithFormat:@"Sync: Downloading '%@' (100%%)", object.name]]; + [self startAndEndActivityWithType:PithosActivityOther + message:[NSString stringWithFormat:@"Sync: Downloading '%@' (100%%)", object.name]]; } else if (storedState.filePath == nil) { // Create new local object // Check first if a local copy exists if ([self findLocalCopyForObjectWithHash:object.hash forFile:filePath]) { - [activityFacility startAndEndActivityWithType:PithosActivityOther - message:[NSString stringWithFormat:@"Sync: Downloading '%@' (100%%)", object.name]]; + [self startAndEndActivityWithType:PithosActivityOther + message:[NSString stringWithFormat:@"Sync: Downloading '%@' (100%%)", object.name]]; } else { [self increaseSyncOperationCount]; __block ASIPithosObjectRequest *objectRequest = [PithosUtilities objectBlockDataRequestWithContainerName:containerName @@ -584,12 +703,13 @@ blockIndex:0 blockSize:blockSize]; objectRequest.delegate = self; - objectRequest.didFinishSelector = @selector(downloadObjectBlockFinished:); - objectRequest.didFailSelector = @selector(requestFailed:); + objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:); + objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:); PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityDownload message:[NSString stringWithFormat:@"Sync: Downloading '%@' (0%%)", object.name] totalBytes:object.bytes currentBytes:0]; + [self updateActivity:activity withMessage:activity.message]; objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: object, @"pithosObject", [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, (NSUInteger)ceil((object.bytes +0.0)/(blockSize + 0.0)))], @"missingBlocks", @@ -601,6 +721,8 @@ [NSString stringWithFormat:@"Sync: Downloading '%@' (100%%)", object.name], @"finishedActivityMessage", [NSNumber numberWithInteger:NSOperationQueuePriorityNormal], @"priority", [NSNumber numberWithUnsignedInteger:10], @"retries", + NSStringFromSelector(@selector(downloadObjectBlockFinished:)), @"didFinishSelector", + NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", nil]; [objectRequest setBytesReceivedBlock:^(unsigned long long size, unsigned long long total){ [activityFacility updateActivity:activity @@ -610,33 +732,33 @@ totalBytes:activity.totalBytes currentBytes:(activity.currentBytes + size)]; }]; - [queue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityNormal]]; + [networkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityNormal]]; } } else { // Resume local object download // Check first if a local copy exists if ([self findLocalCopyForObjectWithHash:object.hash forFile:filePath]) { - [activityFacility startAndEndActivityWithType:PithosActivityOther - message:[NSString stringWithFormat:@"Sync: Downloading '%@' (100%%)", object.name]]; + [self startAndEndActivityWithType:PithosActivityOther + message:[NSString stringWithFormat:@"Sync: Downloading '%@' (100%%)", object.name]]; // Delete incomplete temp download error = nil; if (![fileManager removeItemAtPath:storedState.filePath error:&error] || error) { - [PithosUtilities fileActionFailedAlertWithTitle:@"Remove File Error" - message:[NSString stringWithFormat:@"Cannot remove file at '%@'", storedState.filePath] - error:error]; + [self fileActionFailedAlertWithTitle:@"Remove File Error" + message:[NSString stringWithFormat:@"Cannot remove file at '%@'", storedState.filePath] + error:error]; } } else { [self increaseSyncOperationCount]; ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest objectHashmapRequestWithContainerName:containerName objectName:object.name]; objectRequest.delegate = self; - objectRequest.didFinishSelector = @selector(downloadObjectHashMapFinished:); - // The fail method for block download does exactly what we want - objectRequest.didFailSelector = @selector(requestFailed:); + objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:); + objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:); PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityDownload message:[NSString stringWithFormat:@"Sync: Downloading '%@' (0%%)", object.name] totalBytes:object.bytes currentBytes:0]; + [self updateActivity:activity withMessage:activity.message]; objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: object, @"pithosObject", filePath, @"filePath", @@ -646,8 +768,10 @@ [NSString stringWithFormat:@"Sync: Downloading '%@' (100%%)", object.name], @"finishedActivityMessage", [NSNumber numberWithInteger:NSOperationQueuePriorityNormal], @"priority", [NSNumber numberWithUnsignedInteger:10], @"retries", + NSStringFromSelector(@selector(downloadObjectHashMapFinished:)), @"didFinishSelector", + NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", nil]; - [queue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityNormal]]; + [networkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityNormal]]; } } } @@ -656,8 +780,17 @@ object:(ASIPithosObject *)object localFilePath:(NSString *)filePath { [self increaseSyncOperationCount]; + NSFileManager *fileManager = [NSFileManager defaultManager]; + BOOL isDirectory; + BOOL fileExists = [fileManager fileExistsAtPath:filePath isDirectory:&isDirectory]; if (currentState.isDirectory) { // Create remote directory object + if (!fileExists || !isDirectory) { + // Local directory object deleted or changed to a file in the meantime, mark the sync cycle as incomplete and skip + syncIncomplete = YES; + [self decreaseSyncOperationCount]; + return; + } ASIPithosObjectRequest *objectRequest = [ASIPithosObjectRequest writeObjectDataRequestWithContainerName:containerName objectName:object.name eTag:nil @@ -670,10 +803,11 @@ metadata:nil data:[NSData data]]; objectRequest.delegate = self; - objectRequest.didFinishSelector = @selector(uploadDirectoryObjectFinished:); - objectRequest.didFailSelector = @selector(requestFailed:); + objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:); + objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:); PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityCreateDirectory message:[NSString stringWithFormat:@"Sync: Creating directory '%@'", object.name]]; + [self updateActivity:activity withMessage:activity.message]; objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: object, @"pithosObject", activity, @"activity", @@ -682,10 +816,16 @@ [NSString stringWithFormat:@"Sync: Creating directory '%@' (finished)", object.name], @"finishedActivityMessage", [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", [NSNumber numberWithUnsignedInteger:10], @"retries", + NSStringFromSelector(@selector(uploadDirectoryObjectFinished:)), @"didFinishSelector", + NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", nil]; - [queue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]]; + [networkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]]; } else if (!currentState.exists) { // Delete remote object + if (fileExists) { + // Local object created in the meantime, just mark the sync cycle as incomplete, but do delete the server object + syncIncomplete = YES; + } NSString *safeObjectName = [PithosUtilities safeObjectNameForContainerName:@"trash" objectName:object.name]; if (safeObjectName) { @@ -696,10 +836,11 @@ checkIfExists:NO]; if (objectRequest) { objectRequest.delegate = self; - objectRequest.didFinishSelector = @selector(moveObjectToTrashFinished:); - objectRequest.didFailSelector = @selector(requestFailed:); + objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:); + objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:); PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityDelete message:[NSString stringWithFormat:@"Sync: Moving to trash '%@'", object.name]]; + [self updateActivity:activity withMessage:activity.message]; objectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: object, @"pithosObject", activity, @"activity", @@ -708,8 +849,10 @@ [NSString stringWithFormat:@"Sync: Moving to trash '%@' (finished)", object.name], @"finishedActivityMessage", [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", [NSNumber numberWithUnsignedInteger:10], @"retries", + NSStringFromSelector(@selector(moveObjectToTrashFinished:)), @"didFinishSelector", + NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", nil]; - [queue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]]; + [networkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]]; } else { syncIncomplete = YES; [self decreaseSyncOperationCount]; @@ -720,6 +863,12 @@ } } else { // Upload file to remote object + if (!fileExists || isDirectory) { + // Local file object deleted or changed to a directory in the meantime, mark the sync cycle as incomplete and skip + syncIncomplete = YES; + [self decreaseSyncOperationCount]; + return; + } NSError *error = nil; object.contentType = [PithosUtilities contentTypeOfFile:filePath error:&error]; if (object.contentType == nil) @@ -738,12 +887,13 @@ sharingAccount:nil]; if (objectRequest) { objectRequest.delegate = self; - objectRequest.didFinishSelector = @selector(uploadObjectUsingHashMapFinished:); - objectRequest.didFailSelector = @selector(requestFailed:); + objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:); + objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:); PithosActivity *activity = [activityFacility startActivityWithType:PithosActivityUpload message:[NSString stringWithFormat:@"Sync: Uploading '%@' (0%%)", object.name] totalBytes:[[objectRequest.userInfo valueForKey:@"bytes"] unsignedIntegerValue] currentBytes:0]; + [self updateActivity:activity withMessage:activity.message]; [(NSMutableDictionary *)objectRequest.userInfo addEntriesFromDictionary: [NSDictionary dictionaryWithObjectsAndKeys: object, @"pithosObject", @@ -756,8 +906,10 @@ [NSString stringWithFormat:@"Sync: Uploading '%@' (100%%)", object.name], @"finishedActivityMessage", [NSNumber numberWithInteger:NSOperationQueuePriorityNormal], @"priority", [NSNumber numberWithUnsignedInteger:10], @"retries", + NSStringFromSelector(@selector(uploadObjectUsingHashMapFinished:)), @"didFinishSelector", + NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", nil]]; - [queue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityNormal]]; + [networkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityNormal]]; } else { syncIncomplete = YES; [self decreaseSyncOperationCount]; @@ -769,7 +921,16 @@ #pragma mark - #pragma mark ASIHTTPRequestDelegate +- (void)performRequestFinishedDelegateInBackground:(ASIPithosRequest *)request { + [self performSelectorInBackground:NSSelectorFromString([request.userInfo objectForKey:@"didFinishSelector"]) withObject:request]; +} + +- (void)performRequestFailedDelegateInBackground:(ASIPithosRequest *)request { + [self performSelectorInBackground:NSSelectorFromString([request.userInfo objectForKey:@"didFailSelector"]) withObject:request]; +} + - (void)listRequestFinished:(ASIPithosContainerRequest *)containerRequest { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSLog(@"Sync::list request finished: %@", containerRequest.url); if ((containerRequest.responseStatusCode == 200) || (containerRequest.responseStatusCode == 304)) { if (containerRequest.responseStatusCode == 200) { @@ -802,26 +963,26 @@ until:nil ifModifiedSince:lastModified]; newContainerRequest.delegate = self; - newContainerRequest.didFinishSelector = @selector(listRequestFinished:); - newContainerRequest.didFailSelector = @selector(listRequestFailed:); + newContainerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:); + newContainerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:); newContainerRequest.userInfo = newContainerRequest.userInfo; [(NSMutableDictionary *)newContainerRequest.userInfo setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"]; - [queue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:[[newContainerRequest.userInfo objectForKey:@"priority"] integerValue]]]; + [networkQueue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:[[newContainerRequest.userInfo objectForKey:@"priority"] integerValue]]]; return; } } - [activityFacility endActivity:[containerRequest.userInfo objectForKey:@"activity"] - withMessage:[containerRequest.userInfo objectForKey:@"finishedActivityMessage"]]; + [self endActivity:[containerRequest.userInfo objectForKey:@"activity"] + withMessage:[containerRequest.userInfo objectForKey:@"finishedActivityMessage"]]; NSFileManager *fileManager = [NSFileManager defaultManager]; NSError *error = nil; NSArray *subPaths = [fileManager subpathsOfDirectoryAtPath:containerDirectoryPath error:&error]; if (error) { - [PithosUtilities fileActionFailedAlertWithTitle:@"Directory Contents Error" - message:[NSString stringWithFormat:@"Cannot get contents of directory at '%@'", containerDirectoryPath] - error:error]; - [activityFacility startAndEndActivityWithType:PithosActivityOther message:@"Sync: Failed to read contents of sync directory"]; + [self fileActionFailedAlertWithTitle:@"Directory Contents Error" + message:[NSString stringWithFormat:@"Cannot get contents of directory at '%@'", containerDirectoryPath] + error:error]; + [self startAndEndActivityWithType:PithosActivityOther message:@"Sync: Failed to read contents of sync directory"]; @synchronized(self) { - // Since the local listing failed, the operation finished and the sync cycle is completeted unsuccesfully + // Since the local listing failed, the operation finished and the sync cycle is completeted unsuccessfully syncOperationCount = 0; if (newSyncRequested) [self sync]; @@ -963,12 +1124,12 @@ } else { NSUInteger retries = [[containerRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; if (retries > 0) { - ASIPithosContainerRequest *newContainerRequest = (ASIPithosContainerRequest *)[PithosUtilities copyRequest:containerRequest]; + ASIPithosContainerRequest *newContainerRequest = (ASIPithosContainerRequest *)[[PithosUtilities copyRequest:containerRequest] autorelease]; [(NSMutableDictionary *)(newContainerRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; - [queue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:[[newContainerRequest.userInfo objectForKey:@"priority"] integerValue]]]; + [networkQueue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:[[newContainerRequest.userInfo objectForKey:@"priority"] integerValue]]]; } else { - [activityFacility endActivity:[containerRequest.userInfo objectForKey:@"activity"] - withMessage:[containerRequest.userInfo objectForKey:@"failedActivityMessage"]]; + [self endActivity:[containerRequest.userInfo objectForKey:@"activity"] + withMessage:[containerRequest.userInfo objectForKey:@"failedActivityMessage"]]; @synchronized(self) { // Since the server listing failed in all retries, the operation finished and the sync cycle is completeted unsuccesfully syncOperationCount = 0; @@ -977,12 +1138,14 @@ } } } + [pool drain]; } - (void)listRequestFailed:(ASIPithosContainerRequest *)containerRequest { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; if ([containerRequest isCancelled]) { - [activityFacility endActivity:[containerRequest.userInfo objectForKey:@"activity"] - withMessage:[containerRequest.userInfo objectForKey:@"stoppedActivityMessage"]]; + [self endActivity:[containerRequest.userInfo objectForKey:@"activity"] + withMessage:[containerRequest.userInfo objectForKey:@"stoppedActivityMessage"]]; [objects release]; objects = nil; @synchronized(self) { @@ -993,12 +1156,12 @@ // If the server listing fails, the sync should start over, so just retrying is enough NSUInteger retries = [[containerRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue]; if (retries > 0) { - ASIPithosContainerRequest *newContainerRequest = (ASIPithosContainerRequest *)[PithosUtilities copyRequest:containerRequest]; + ASIPithosContainerRequest *newContainerRequest = (ASIPithosContainerRequest *)[[PithosUtilities copyRequest:containerRequest] autorelease]; [(NSMutableDictionary *)(newContainerRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; - [queue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:[[newContainerRequest.userInfo objectForKey:@"priority"] integerValue]]]; + [networkQueue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:[[newContainerRequest.userInfo objectForKey:@"priority"] integerValue]]]; } else { - [activityFacility endActivity:[containerRequest.userInfo objectForKey:@"activity"] - withMessage:[containerRequest.userInfo objectForKey:@"failedActivityMessage"]]; + [self endActivity:[containerRequest.userInfo objectForKey:@"activity"] + withMessage:[containerRequest.userInfo objectForKey:@"failedActivityMessage"]]; [objects release]; objects = nil; @synchronized(self) { @@ -1008,9 +1171,11 @@ [self sync]; } } + [pool drain]; } - (void)downloadObjectBlockFinished:(ASIPithosObjectRequest *)objectRequest { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSLog(@"Sync::download object block finished: %@", objectRequest.url); if (objectRequest.responseStatusCode == 206) { ASIPithosObject *object = [objectRequest.userInfo objectForKey:@"pithosObject"]; @@ -1020,8 +1185,8 @@ NSString *downloadsDirPath = self.tempDownloadsDirPath; if (!downloadsDirPath) { - [activityFacility endActivity:activity - withMessage:[objectRequest.userInfo objectForKey:@"failedActivityMessage"]]; + [self endActivity:activity + withMessage:[objectRequest.userInfo objectForKey:@"failedActivityMessage"]]; @synchronized(self) { syncIncomplete = YES; [self decreaseSyncOperationCount]; @@ -1041,11 +1206,11 @@ NSString *tempFilePath = [fileManager stringWithFileSystemRepresentation:tempFileNameCString length:strlen(tempFileNameCString)]; free(tempFileNameCString); if (fileDescriptor == -1) { - [PithosUtilities fileActionFailedAlertWithTitle:@"Create Temporary File Error" - message:[NSString stringWithFormat:@"Cannot create temporary file at '%@'", storedState.filePath] - error:nil]; - [activityFacility endActivity:activity - withMessage:[objectRequest.userInfo objectForKey:@"failedActivityMessage"]]; + [self fileActionFailedAlertWithTitle:@"Create Temporary File Error" + message:[NSString stringWithFormat:@"Cannot create temporary file at '%@'", storedState.filePath] + error:nil]; + [self endActivity:activity + withMessage:[objectRequest.userInfo objectForKey:@"failedActivityMessage"]]; @synchronized(self) { syncIncomplete = YES; [self decreaseSyncOperationCount]; @@ -1072,8 +1237,8 @@ NSString *filePath = [objectRequest.userInfo objectForKey:@"filePath"]; NSString *dirPath = [filePath stringByDeletingLastPathComponent]; if ([fileManager fileExistsAtPath:filePath] && ![self moveToTempTrashFile:filePath]) { - [activityFacility endActivity:activity - withMessage:[objectRequest.userInfo objectForKey:@"failedActivityMessage"]]; + [self endActivity:activity + withMessage:[objectRequest.userInfo objectForKey:@"failedActivityMessage"]]; @synchronized(self) { syncIncomplete = YES; [self decreaseSyncOperationCount]; @@ -1088,11 +1253,11 @@ error = nil; [fileManager createDirectoryAtPath:dirPath withIntermediateDirectories:YES attributes:nil error:nil]; if (error != nil) { - [PithosUtilities fileActionFailedAlertWithTitle:@"Create Directory Error" - message:[NSString stringWithFormat:@"Cannot create directory at '%@'", dirPath] - error:error]; - [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] - withMessage:[objectRequest.userInfo objectForKey:@"failedActivityMessage"]]; + [self fileActionFailedAlertWithTitle:@"Create Directory Error" + message:[NSString stringWithFormat:@"Cannot create directory at '%@'", dirPath] + error:error]; + [self endActivity:[objectRequest.userInfo objectForKey:@"activity"] + withMessage:[objectRequest.userInfo objectForKey:@"failedActivityMessage"]]; @synchronized(self) { syncIncomplete = YES; [self decreaseSyncOperationCount]; @@ -1106,11 +1271,11 @@ error = nil; [fileManager moveItemAtPath:storedState.filePath toPath:filePath error:&error]; if (error != nil) { - [PithosUtilities fileActionFailedAlertWithTitle:@"Move File Error" - message:[NSString stringWithFormat:@"Cannot move file at '%@' to '%@'", storedState.filePath, filePath] - error:error]; - [activityFacility endActivity:activity - withMessage:[objectRequest.userInfo objectForKey:@"failedActivityMessage"]]; + [self fileActionFailedAlertWithTitle:@"Move File Error" + message:[NSString stringWithFormat:@"Cannot move file at '%@' to '%@'", storedState.filePath, filePath] + error:error]; + [self endActivity:activity + withMessage:[objectRequest.userInfo objectForKey:@"failedActivityMessage"]]; @synchronized(self) { syncIncomplete = YES; [self decreaseSyncOperationCount]; @@ -1119,10 +1284,10 @@ } return; } - [activityFacility endActivity:activity - withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"] - totalBytes:activity.totalBytes - currentBytes:activity.totalBytes]; + [self endActivity:activity + withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"] + totalBytes:activity.totalBytes + currentBytes:activity.totalBytes]; storedState.hash = object.hash; storedState.filePath = nil; @@ -1136,8 +1301,8 @@ return; } else { if (newSyncRequested) { - [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] - withMessage:[objectRequest.userInfo objectForKey:@"stoppedActivityMessage"]]; + [self endActivity:[objectRequest.userInfo objectForKey:@"activity"] + withMessage:[objectRequest.userInfo objectForKey:@"stoppedActivityMessage"]]; @synchronized(self) { syncIncomplete = YES; [self decreaseSyncOperationCount]; @@ -1151,8 +1316,8 @@ blockIndex:missingBlockIndex blockSize:blockSize]; newObjectRequest.delegate = self; - newObjectRequest.didFinishSelector = @selector(downloadObjectBlockFinished:); - newObjectRequest.didFailSelector = @selector(downloadObjectBlockOrHashMapFailed:); + newObjectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:); + newObjectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:); newObjectRequest.userInfo = objectRequest.userInfo; [(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:missingBlockIndex] forKey:@"missingBlockIndex"]; [(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"]; @@ -1164,13 +1329,13 @@ totalBytes:activity.totalBytes currentBytes:(activity.currentBytes + size)]; }]; - [queue addOperation:[PithosUtilities prepareRequest:newObjectRequest priority:[[newObjectRequest.userInfo objectForKey:@"priority"] integerValue]]]; + [networkQueue addOperation:[PithosUtilities prepareRequest:newObjectRequest priority:[[newObjectRequest.userInfo objectForKey:@"priority"] integerValue]]]; } } } else if (objectRequest.responseStatusCode == 412) { // The object has changed on the server - [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] - withMessage:[objectRequest.userInfo objectForKey:@"stoppedActivityMessage"]]; + [self endActivity:[objectRequest.userInfo objectForKey:@"activity"] + withMessage:[objectRequest.userInfo objectForKey:@"stoppedActivityMessage"]]; @synchronized(self) { syncIncomplete = YES; [self decreaseSyncOperationCount]; @@ -1180,14 +1345,16 @@ } else { [self requestFailed:objectRequest]; } + [pool drain]; } - (void)downloadObjectHashMapFinished:(ASIPithosObjectRequest *)objectRequest { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSLog(@"Sync::download object hashmap finished: %@", objectRequest.url); if (objectRequest.responseStatusCode == 200) { if (newSyncRequested) { - [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] - withMessage:[objectRequest.userInfo objectForKey:@"stoppedActivityMessage"]]; + [self endActivity:[objectRequest.userInfo objectForKey:@"activity"] + withMessage:[objectRequest.userInfo objectForKey:@"stoppedActivityMessage"]]; @synchronized(self) { syncIncomplete = YES; [self decreaseSyncOperationCount]; @@ -1206,24 +1373,25 @@ blockHash:blockHash withHashes:[objectRequest hashes]]; NSUInteger missingBlockIndex = [missingBlocks firstIndex]; - [activityFacility endActivity:activity - withMessage:[NSString stringWithFormat:@"Sync: Downloading '%@' (%.0f%%)", - object.name, - (100*(activity.totalBytes - [missingBlocks count]*blockSize + 0.0)/(activity.totalBytes + 0.0))] - totalBytes:activity.totalBytes - currentBytes:(activity.totalBytes - [missingBlocks count]*blockSize)]; + [self endActivity:activity + withMessage:[NSString stringWithFormat:@"Sync: Downloading '%@' (%.0f%%)", + object.name, + (100*(activity.totalBytes - [missingBlocks count]*blockSize + 0.0)/(activity.totalBytes + 0.0))] + totalBytes:activity.totalBytes + currentBytes:(activity.totalBytes - [missingBlocks count]*blockSize)]; __block ASIPithosObjectRequest *newObjectRequest = [PithosUtilities objectBlockDataRequestWithContainerName:containerName object:object blockIndex:missingBlockIndex blockSize:blockSize]; newObjectRequest.delegate = self; - newObjectRequest.didFinishSelector = @selector(downloadObjectBlockFinished:); - newObjectRequest.didFailSelector = @selector(downloadObjectBlockOrHashMapFailed:); + newObjectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:); + newObjectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:); newObjectRequest.userInfo = objectRequest.userInfo; [(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:missingBlocks forKey:@"missingBlocks"]; [(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:missingBlockIndex] forKey:@"missingBlockIndex"]; [(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"]; + [(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:NSStringFromSelector(@selector(downloadObjectBlockFinished:)) forKey:@"didFinishSelector"]; [newObjectRequest setBytesReceivedBlock:^(unsigned long long size, unsigned long long total){ [activityFacility updateActivity:activity withMessage:[NSString stringWithFormat:@"Sync: Downloading '%@' (%.0f%%)", @@ -1232,21 +1400,23 @@ totalBytes:activity.totalBytes currentBytes:(activity.currentBytes + size)]; }]; - [queue addOperation:[PithosUtilities prepareRequest:newObjectRequest priority:[[newObjectRequest.userInfo objectForKey:@"priority"] integerValue]]]; + [networkQueue addOperation:[PithosUtilities prepareRequest:newObjectRequest priority:[[newObjectRequest.userInfo objectForKey:@"priority"] integerValue]]]; } } else { [self requestFailed:objectRequest]; } + [pool drain]; } - (void)uploadDirectoryObjectFinished:(ASIPithosObjectRequest *)objectRequest { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSLog(@"Sync::upload directory object finished: %@", objectRequest.url); if (objectRequest.responseStatusCode == 201) { PithosLocalObjectState *storedState = [storedLocalObjectStates objectForKey:[[objectRequest.userInfo objectForKey:@"pithosObject"] name]]; storedState.isDirectory = YES; [self saveLocalState]; - [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] - withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"]]; + [self endActivity:[objectRequest.userInfo objectForKey:@"activity"] + withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"]]; @synchronized(self) { [self decreaseSyncOperationCount]; if (newSyncRequested && !syncOperationCount) @@ -1255,15 +1425,17 @@ } else { [self requestFailed:objectRequest]; } + [pool drain]; } - (void)moveObjectToTrashFinished:(ASIPithosObjectRequest *)objectRequest { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSLog(@"Sync::move object to trash finished: %@", objectRequest.url); if (objectRequest.responseStatusCode == 201) { [storedLocalObjectStates removeObjectForKey:[[objectRequest.userInfo objectForKey:@"pithosObject"] name]]; [self saveLocalState]; - [activityFacility endActivity:[objectRequest.userInfo objectForKey:@"activity"] - withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"]]; + [self endActivity:[objectRequest.userInfo objectForKey:@"activity"] + withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"]]; @synchronized(self) { [self decreaseSyncOperationCount]; if (newSyncRequested && !syncOperationCount) @@ -1272,9 +1444,11 @@ } else { [self requestFailed:objectRequest]; } + [pool drain]; } - (void)uploadObjectUsingHashMapFinished:(ASIPithosObjectRequest *)objectRequest { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSLog(@"Sync::upload using hashmap finished: %@", objectRequest.url); ASIPithosObject *object = [objectRequest.userInfo objectForKey:@"pithosObject"]; PithosLocalObjectState *storedState = [storedLocalObjectStates objectForKey:object.name]; @@ -1285,10 +1459,10 @@ NSLog(@"Sync::object created: %@", objectRequest.url); storedState.hash = [objectRequest eTag]; [self saveLocalState]; - [activityFacility endActivity:activity - withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"] - totalBytes:totalBytes - currentBytes:totalBytes]; + [self endActivity:activity + withMessage:[objectRequest.userInfo objectForKey:@"finishedActivityMessage"] + totalBytes:totalBytes + currentBytes:totalBytes]; @synchronized(self) { [self decreaseSyncOperationCount]; if (newSyncRequested && !syncOperationCount) @@ -1296,8 +1470,8 @@ } } else if (objectRequest.responseStatusCode == 409) { if (newSyncRequested) { - [activityFacility endActivity:activity - withMessage:[objectRequest.userInfo objectForKey:@"stoppedActivityMessage"]]; + [self endActivity:activity + withMessage:[objectRequest.userInfo objectForKey:@"stoppedActivityMessage"]]; @synchronized(self) { syncIncomplete = YES; [self decreaseSyncOperationCount]; @@ -1309,8 +1483,8 @@ NSUInteger iteration = [[objectRequest.userInfo objectForKey:@"iteration"] unsignedIntegerValue]; if (iteration == 0) { NSLog(@"Sync::upload iteration limit reached: %@", objectRequest.url); - [activityFacility endActivity:activity - withMessage:[objectRequest.userInfo objectForKey:@"stoppedActivityMessage"]]; + [self endActivity:activity + withMessage:[objectRequest.userInfo objectForKey:@"stoppedActivityMessage"]]; syncIncomplete = YES; [self decreaseSyncOperationCount]; return; @@ -1320,10 +1494,10 @@ withMissingHashesResponse:[objectRequest responseString]]; if (totalBytes >= [missingBlocks count]*blockSize) currentBytes = totalBytes - [missingBlocks count]*blockSize; - [activityFacility updateActivity:activity - withMessage:[NSString stringWithFormat:@"Sync: Uploading '%@' (%.0f%%)", object.name, (100*(currentBytes + 0.0)/(totalBytes + 0.0))] - totalBytes:totalBytes - currentBytes:currentBytes]; + [self updateActivity:activity + withMessage:[NSString stringWithFormat:@"Sync: Uploading '%@' (%.0f%%)", object.name, (100*(currentBytes + 0.0)/(totalBytes + 0.0))] + totalBytes:totalBytes + currentBytes:currentBytes]; NSUInteger missingBlockIndex = [missingBlocks firstIndex]; __block ASIPithosContainerRequest *newContainerRequest = [PithosUtilities updateContainerDataRequestWithContainerName:containerName blockSize:blockSize @@ -1331,27 +1505,30 @@ missingBlockIndex:missingBlockIndex sharingAccount:nil]; newContainerRequest.delegate = self; - newContainerRequest.didFinishSelector = @selector(uploadMissingBlockFinished:); - newContainerRequest.didFailSelector = @selector(requestFailed:); + newContainerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:); + newContainerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:); newContainerRequest.userInfo = objectRequest.userInfo; [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:(--iteration)] forKey:@"iteration"]; [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"]; [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:missingBlocks forKey:@"missingBlocks"]; [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:missingBlockIndex] forKey:@"missingBlockIndex"]; + [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:NSStringFromSelector(@selector(uploadMissingBlockFinished:)) forKey:@"didFinishSelector"]; [newContainerRequest setBytesSentBlock:^(unsigned long long size, unsigned long long total){ [activityFacility updateActivity:activity withMessage:[NSString stringWithFormat:@"Sync: Uploading '%@' (%.0f%%)", object.name, (100*(activity.currentBytes + size + 0.0)/(activity.totalBytes + 0.0))] totalBytes:activity.totalBytes currentBytes:(activity.currentBytes + size)]; }]; - [queue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:[[newContainerRequest.userInfo objectForKey:@"priority"] integerValue]]]; + [networkQueue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:[[newContainerRequest.userInfo objectForKey:@"priority"] integerValue]]]; } } else { [self requestFailed:objectRequest]; } + [pool drain]; } - (void)uploadMissingBlockFinished:(ASIPithosContainerRequest *)containerRequest { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSLog(@"Sync::upload of missing block finished: %@", containerRequest.url); if (containerRequest.responseStatusCode == 202) { ASIPithosObject *object = [containerRequest.userInfo objectForKey:@"pithosObject"]; @@ -1371,17 +1548,18 @@ hashes:&hashes sharingAccount:nil]; newObjectRequest.delegate = self; - newObjectRequest.didFinishSelector = @selector(uploadObjectUsingHashMapFinished:); - newObjectRequest.didFailSelector = @selector(requestFailed:); + newObjectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:); + newObjectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:); newObjectRequest.userInfo = containerRequest.userInfo; [(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"]; [(NSMutableDictionary *)(newObjectRequest.userInfo) removeObjectForKey:@"missingBlocks"]; [(NSMutableDictionary *)(newObjectRequest.userInfo) removeObjectForKey:@"missingBlockIndex"]; - [queue addOperation:[PithosUtilities prepareRequest:newObjectRequest priority:[[newObjectRequest.userInfo objectForKey:@"priority"] integerValue]]]; + [(NSMutableDictionary *)(newObjectRequest.userInfo) setObject:NSStringFromSelector(@selector(uploadObjectUsingHashMapFinished:)) forKey:@"didFinishSelector"]; + [networkQueue addOperation:[PithosUtilities prepareRequest:newObjectRequest priority:[[newObjectRequest.userInfo objectForKey:@"priority"] integerValue]]]; } else { if (newSyncRequested) { - [activityFacility endActivity:activity - withMessage:[containerRequest.userInfo objectForKey:@"stoppedActivityMessage"]]; + [self endActivity:activity + withMessage:[containerRequest.userInfo objectForKey:@"stoppedActivityMessage"]]; @synchronized(self) { syncIncomplete = YES; [self decreaseSyncOperationCount]; @@ -1396,8 +1574,8 @@ missingBlockIndex:missingBlockIndex sharingAccount:nil]; newContainerRequest.delegate = self; - newContainerRequest.didFinishSelector = @selector(uploadMissingBlockFinished:); - newContainerRequest.didFailSelector = @selector(requestFailed:); + newContainerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:); + newContainerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:); newContainerRequest.userInfo = containerRequest.userInfo; [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:10] forKey:@"retries"]; [(NSMutableDictionary *)(newContainerRequest.userInfo) setObject:[NSNumber numberWithUnsignedInteger:missingBlockIndex] forKey:@"missingBlockIndex"]; @@ -1407,25 +1585,27 @@ totalBytes:activity.totalBytes currentBytes:(activity.currentBytes + size)]; }]; - [queue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:[[newContainerRequest.userInfo objectForKey:@"priority"] integerValue]]]; + [networkQueue addOperation:[PithosUtilities prepareRequest:newContainerRequest priority:[[newContainerRequest.userInfo objectForKey:@"priority"] integerValue]]]; } } } else { [self requestFailed:containerRequest]; } + [pool drain]; } - (void)requestFailed:(ASIPithosRequest *)request { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; if ([request isCancelled]) { - [activityFacility endActivity:[request.userInfo objectForKey:@"activity"] - withMessage:[request.userInfo objectForKey:@"stoppedActivityMessage"]]; + [self endActivity:[request.userInfo objectForKey:@"activity"] + withMessage:[request.userInfo objectForKey:@"stoppedActivityMessage"]]; syncIncomplete = YES; [self decreaseSyncOperationCount]; return; } if (newSyncRequested) { - [activityFacility endActivity:[request.userInfo objectForKey:@"activity"] - withMessage:[request.userInfo objectForKey:@"stoppedActivityMessage"]]; + [self endActivity:[request.userInfo objectForKey:@"activity"] + withMessage:[request.userInfo objectForKey:@"stoppedActivityMessage"]]; @synchronized(self) { syncIncomplete = YES; [self decreaseSyncOperationCount]; @@ -1436,15 +1616,16 @@ } NSUInteger retries = [[request.userInfo objectForKey:@"retries"] unsignedIntegerValue]; if (retries > 0) { - ASIPithosRequest *newRequest = (ASIPithosRequest *)[PithosUtilities copyRequest:request]; + ASIPithosRequest *newRequest = (ASIPithosRequest *)[[PithosUtilities copyRequest:request] autorelease]; [(NSMutableDictionary *)(newRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"]; - [queue addOperation:[PithosUtilities prepareRequest:newRequest priority:[[newRequest.userInfo objectForKey:@"priority"] integerValue]]]; + [networkQueue addOperation:[PithosUtilities prepareRequest:newRequest priority:[[newRequest.userInfo objectForKey:@"priority"] integerValue]]]; } else { - [activityFacility endActivity:[request.userInfo objectForKey:@"activity"] - withMessage:[request.userInfo objectForKey:@"failedActivityMessage"]]; + [self endActivity:[request.userInfo objectForKey:@"activity"] + withMessage:[request.userInfo objectForKey:@"failedActivityMessage"]]; syncIncomplete = YES; [self decreaseSyncOperationCount]; } + [pool drain]; } diff --git a/pithos-macos/PithosUtilities.m b/pithos-macos/PithosUtilities.m index 173c1d1..ac77ffe 100644 --- a/pithos-macos/PithosUtilities.m +++ b/pithos-macos/PithosUtilities.m @@ -859,7 +859,7 @@ [objectRequest setRequestUserFromDefaultTo:sharingAccount]; [[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; while (![objectRequest isFinished]) { - sleep(1); + usleep(1); } *error = [objectRequest error]; if (*error) { @@ -928,7 +928,7 @@ [containerRequest setRequestUserFromDefaultTo:sharingAccount]; [[PithosUtilities prepareRequest:containerRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous]; while (![containerRequest isFinished]) { - sleep(1); + usleep(1); } if ([containerRequest error]) { [self httpRequestErrorAlertWithRequest:containerRequest]; -- 1.7.10.4