Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Significant performance enhancement for ASIDownloadCache's -clearCachedResponsesForStoragePolicy: #347

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 5 additions & 5 deletions Classes/ASIAuthenticationDialog.m
Expand Up @@ -217,9 +217,9 @@ - (UITextField *)domainField
+ (void)dismiss
{
if ([sharedDialog respondsToSelector:@selector(presentingViewController)])
[[sharedDialog presentingViewController] dismissModalViewControllerAnimated:YES];
[[sharedDialog presentingViewController] dismissViewControllerAnimated:YES completion:^{}];
else
[[sharedDialog parentViewController] dismissModalViewControllerAnimated:YES];
[[sharedDialog parentViewController] dismissViewControllerAnimated:YES completion:^{}];
}

- (void)viewDidDisappear:(BOOL)animated
Expand All @@ -237,9 +237,9 @@ - (void)dismiss
[[self class] dismiss];
} else {
if ([self respondsToSelector:@selector(presentingViewController)])
[[self presentingViewController] dismissModalViewControllerAnimated:YES];
[[self presentingViewController] dismissViewControllerAnimated:YES completion:^{}];
else
[[self parentViewController] dismissModalViewControllerAnimated:YES];
[[self parentViewController] dismissViewControllerAnimated:YES completion:^{}];
}
}

Expand Down Expand Up @@ -315,7 +315,7 @@ - (void)show
}
#endif

[[self presentingController] presentModalViewController:self animated:YES];
[[self presentingController] presentViewController:self animated:YES completion:^{}];
}

#pragma mark button callbacks
Expand Down
4 changes: 2 additions & 2 deletions Classes/ASIDataCompressor.m
Expand Up @@ -161,7 +161,7 @@ + (BOOL)compressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinati
readLength = [inputStream read:inputData maxLength:DATA_CHUNK_SIZE];

// Make sure nothing went wrong
if ([inputStream streamStatus] == NSStreamEventErrorOccurred) {
if ([inputStream streamStatus] == NSStreamStatusError) {
if (err) {
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Compression of %@ failed because we were unable to read from the source data file",sourcePath],NSLocalizedDescriptionKey,[inputStream streamError],NSUnderlyingErrorKey,nil]];
}
Expand All @@ -187,7 +187,7 @@ + (BOOL)compressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinati
[outputStream write:(const uint8_t *)[outputData bytes] maxLength:[outputData length]];

// Make sure nothing went wrong
if ([inputStream streamStatus] == NSStreamEventErrorOccurred) {
if ([inputStream streamStatus] == NSStreamStatusError) {
if (err) {
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Compression of %@ failed because we were unable to write to the destination data file at %@",sourcePath,destinationPath],NSLocalizedDescriptionKey,[outputStream streamError],NSUnderlyingErrorKey,nil]];
}
Expand Down
4 changes: 2 additions & 2 deletions Classes/ASIDataDecompressor.m
Expand Up @@ -158,7 +158,7 @@ + (BOOL)uncompressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destina
readLength = [inputStream read:inputData maxLength:DATA_CHUNK_SIZE];

// Make sure nothing went wrong
if ([inputStream streamStatus] == NSStreamEventErrorOccurred) {
if ([inputStream streamStatus] == NSStreamStatusError) {
if (err) {
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Decompression of %@ failed because we were unable to read from the source data file",sourcePath],NSLocalizedDescriptionKey,[inputStream streamError],NSUnderlyingErrorKey,nil]];
}
Expand All @@ -184,7 +184,7 @@ + (BOOL)uncompressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destina
[outputStream write:(Bytef*)[outputData bytes] maxLength:[outputData length]];

// Make sure nothing went wrong
if ([inputStream streamStatus] == NSStreamEventErrorOccurred) {
if ([inputStream streamStatus] == NSStreamStatusError) {
if (err) {
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Decompression of %@ failed because we were unable to write to the destination data file at %@",sourcePath,destinationPath],NSLocalizedDescriptionKey,[outputStream streamError],NSUnderlyingErrorKey,nil]];
}
Expand Down
91 changes: 63 additions & 28 deletions Classes/ASIDownloadCache.m
Expand Up @@ -19,6 +19,7 @@
@interface ASIDownloadCache ()
+ (NSString *)keyForURL:(NSURL *)url;
- (NSString *)pathToFile:(NSString *)file;
- (NSString *)generateUniqueIdentifier;
@end

@implementation ASIDownloadCache
Expand Down Expand Up @@ -393,35 +394,69 @@ - (void)setDefaultCachePolicy:(ASICachePolicy)cachePolicy

- (void)clearCachedResponsesForStoragePolicy:(ASICacheStoragePolicy)storagePolicy
{
[[self accessLock] lock];
if (![self storagePath]) {
[[self accessLock] unlock];
return;
}
NSString *path = [[self storagePath] stringByAppendingPathComponent:(storagePolicy == ASICacheForSessionDurationCacheStoragePolicy ? sessionCacheFolder : permanentCacheFolder)];

NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
[[self accessLock] lock];
if (![self storagePath]) {
[[self accessLock] unlock];
return;
}
NSString *path = [[self storagePath] stringByAppendingPathComponent:(storagePolicy == ASICacheForSessionDurationCacheStoragePolicy ? sessionCacheFolder : permanentCacheFolder)];

NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];

BOOL isDirectory = NO;
BOOL exists = [fileManager fileExistsAtPath:path isDirectory:&isDirectory];
if (!exists || !isDirectory) {
[[self accessLock] unlock];
return;
}

// It is significantly faster to perform a move than a delete on the iOS filesystem, especially on older devices.
// We move the existing cache directory so it lives in the temp directory and has a unique name.
// We clear the contents of the moved directory in a background thread.
NSString *renamedPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[self generateUniqueIdentifier]];

NSError *error = nil;
BOOL renamed = [fileManager moveItemAtPath:path toPath:renamedPath error:&error];
if (!renamed) {
[[self accessLock] unlock];
[NSException raise:@"FailedToRenameCacheDirectory" format:@"Renaming cache directory failed at path '%@'",path];
}

BOOL recreated = [fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:&error];
if (!recreated) {
[[self accessLock] unlock];
[NSException raise:@"FailedToRecreateCacheDirectory" format:@"Recreating cache directory failed at path '%@'",path];
}

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
NSError *backgroundError = nil;
NSArray *cacheFiles = [fileManager contentsOfDirectoryAtPath:renamedPath error:&backgroundError];
if (backgroundError) {
[NSException raise:@"FailedToTraverseCacheDirectory" format:@"Listing cache directory failed at path '%@'",renamedPath];
}
for (NSString *file in cacheFiles) {
[fileManager removeItemAtPath:[renamedPath stringByAppendingPathComponent:file] error:&backgroundError];
if (backgroundError) {
[NSException raise:@"FailedToRemoveCacheFile" format:@"Failed to remove cached data at path '%@'",renamedPath];
}
}

// Remove the now-empty temporary directory
[fileManager removeItemAtPath:renamedPath error:&backgroundError];
if (backgroundError) {
[NSException raise:@"FailedToRemoveCacheDirectory" format:@"Failed to remove cached directory at path '%@'",renamedPath];
}
});

[[self accessLock] unlock];
}

BOOL isDirectory = NO;
BOOL exists = [fileManager fileExistsAtPath:path isDirectory:&isDirectory];
if (!exists || !isDirectory) {
[[self accessLock] unlock];
return;
}
NSError *error = nil;
NSArray *cacheFiles = [fileManager contentsOfDirectoryAtPath:path error:&error];
if (error) {
[[self accessLock] unlock];
[NSException raise:@"FailedToTraverseCacheDirectory" format:@"Listing cache directory failed at path '%@'",path];
}
for (NSString *file in cacheFiles) {
[fileManager removeItemAtPath:[path stringByAppendingPathComponent:file] error:&error];
if (error) {
[[self accessLock] unlock];
[NSException raise:@"FailedToRemoveCacheFile" format:@"Failed to remove cached data at path '%@'",path];
}
}
[[self accessLock] unlock];
- (NSString *)generateUniqueIdentifier
{
CFUUIDRef uniqueIdentifier = CFUUIDCreate(NULL);
CFStringRef uniqueIdentifierString = CFUUIDCreateString(NULL, uniqueIdentifier);
CFRelease(uniqueIdentifier);
return [(NSString *)uniqueIdentifierString autorelease];
}

+ (BOOL)serverAllowsResponseCachingForRequest:(ASIHTTPRequest *)request
Expand Down
24 changes: 13 additions & 11 deletions Classes/ASIHTTPRequest.m
Expand Up @@ -1211,17 +1211,19 @@ - (void)startRequest
if (![self validatesSecureCertificate]) {
// see: http://iphonedevelopment.blogspot.com/2010/05/nsstream-tcp-and-ssl.html

NSDictionary *sslProperties = [[NSDictionary alloc] initWithObjectsAndKeys:
[NSNumber numberWithBool:YES], kCFStreamSSLAllowsExpiredCertificates,
[NSNumber numberWithBool:YES], kCFStreamSSLAllowsAnyRoot,
[NSNumber numberWithBool:NO], kCFStreamSSLValidatesCertificateChain,
kCFNull,kCFStreamSSLPeerName,
nil];
// This is deprecated and we don't need it for now

// NSDictionary *sslProperties = [[NSDictionary alloc] initWithObjectsAndKeys:
// [NSNumber numberWithBool:YES], kCFStreamSSLAllowsExpiredCertificates,
// [NSNumber numberWithBool:YES], kCFStreamSSLAllowsAnyRoot,
// [NSNumber numberWithBool:NO], kCFStreamSSLValidatesCertificateChain,
// kCFNull,kCFStreamSSLPeerName,
// nil];

CFReadStreamSetProperty((CFReadStreamRef)[self readStream],
kCFStreamPropertySSLSettings,
(CFTypeRef)sslProperties);
[sslProperties release];
// CFReadStreamSetProperty((CFReadStreamRef)[self readStream],
// kCFStreamPropertySSLSettings,
// (CFTypeRef)sslProperties);
// [sslProperties release];
}

// Tell CFNetwork to use a client certificate
Expand Down Expand Up @@ -4866,7 +4868,7 @@ + (NSDate *)expiryDateForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterva

// RFC 2612 says max-age must override any Expires header
if (maxAge) {
return [[NSDate date] addTimeInterval:maxAge];
return [[NSDate date] dateByAddingTimeInterval:maxAge];
} else {
NSString *expires = [responseHeaders objectForKey:@"Expires"];
if (expires) {
Expand Down