Permalink
Browse files

Rework the BinaryDelta tool to use NSOperationQueue in order to be sl…

…ightly more portable.

There's slightly less concurrency as a result as all archiving operations are now performed
serially on the main thread.  Since these make up a small percentage of the overall runtime,
the increased portability makes this a reasonable tradeoff.
  • Loading branch information...
1 parent 3ff2d82 commit 61692343004063f9d907fbcc950ae01bbae450cc Mark Rowe committed Aug 21, 2009
Showing with 97 additions and 65 deletions.
  1. +5 −4 Configurations/ConfigBinaryDelta.xcconfig
  2. +92 −61 SUBinaryDeltaTool.m
@@ -2,7 +2,8 @@
PRODUCT_NAME = BinaryDelta
GCC_PREFIX_HEADER =
-SDKROOT = macosx10.6
-MACOSX_DEPLOYMENT_TARGET[arch=i386] = 10.6
-MACOSX_DEPLOYMENT_TARGET[arch=x86_64] = 10.6
-MACOSX_DEPLOYMENT_TARGET[arch=ppc] = 10.6
+SDKROOT = macosx10.5
+MACOSX_DEPLOYMENT_TARGET[arch=i386] = 10.5
+MACOSX_DEPLOYMENT_TARGET[arch=ppc64] = 10.5
+MACOSX_DEPLOYMENT_TARGET[arch=ppc] = 10.5
+MACOSX_DEPLOYMENT_TARGET[arch=x86_64] = 10.5
View
@@ -12,7 +12,6 @@
#include "SUBinaryDeltaApply.h"
#include <CommonCrypto/CommonDigest.h>
#include <Foundation/Foundation.h>
-#include <dispatch/dispatch.h>
#include <fcntl.h>
#include <fts.h>
#include <libgen.h>
@@ -25,6 +24,52 @@
extern int bsdiff(int argc, const char **argv);
+@interface CreateBinaryDeltaOperation : NSOperation
+{
+ NSString *_relativePath;
+ NSString *_fromPath;
+ NSString *_toPath;
+ NSString *_resultPath;
+}
+- (id)initWithRelativePath:(NSString *)relativePath oldTree:(NSString *)oldTree newTree:(NSString *)newTree;
+
+- (NSString *)relativePath;
+- (NSString *)resultPath;
+@end
+
+@implementation CreateBinaryDeltaOperation
+
+- (id)initWithRelativePath:(NSString *)relativePath oldTree:(NSString *)oldTree newTree:(NSString *)newTree
+{
+ if ((self = [super init])) {
+ _relativePath = [relativePath copy];
+ _fromPath = [[oldTree stringByAppendingPathComponent:relativePath] retain];
+ _toPath = [[newTree stringByAppendingPathComponent:relativePath] retain];
+ }
+ return self;
+}
+
+- (NSString *)relativePath
+{
+ return [[_relativePath retain] autorelease];
+}
+
+- (NSString *)resultPath
+{
+ return [[_resultPath retain] autorelease];
+}
+
+- (void)main
+{
+ NSString *temporaryFile = temporaryFilename(@"BinaryDelta");
+ const char *argv[] = {"/usr/bin/bsdiff", [_fromPath fileSystemRepresentation], [_toPath fileSystemRepresentation], [temporaryFile fileSystemRepresentation]};
+ int result = bsdiff(4, argv);
+ if (!result)
+ _resultPath = [temporaryFile retain];
+}
+
+@end
+
static NSDictionary *infoForFile(FTSENT *ent)
{
NSData *hash = hashOfFile(ent);
@@ -34,33 +79,6 @@
return [NSDictionary dictionaryWithObjectsAndKeys:hash, @"hash", [NSNumber numberWithUnsignedShort:ent->fts_info], @"type", size, @"size", nil];
}
-static void addBinaryDelta(dispatch_group_t deltaGroup, dispatch_queue_t xarQueue, xar_t x, NSString *relativePath, NSString *oldBasePath, NSString *newBasePath)
-{
- NSString *oldPath = [oldBasePath stringByAppendingPathComponent:relativePath];
- NSString *newPath = [newBasePath stringByAppendingPathComponent:relativePath];
- NSString *temporaryFile = temporaryFilename(@"create-binary-delta");
-
- dispatch_queue_t bsdiffQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- dispatch_retain(xarQueue);
- dispatch_retain(deltaGroup);
-
- dispatch_group_async(deltaGroup, bsdiffQueue, ^{
- const char *argv[] = {"/usr/bin/bsdiff", [oldPath fileSystemRepresentation], [newPath fileSystemRepresentation], [temporaryFile fileSystemRepresentation]};
- int result = bsdiff(4, argv);
-
- if (!result) {
- dispatch_group_async(deltaGroup, xarQueue, ^{
- xar_file_t newFile = xar_add_frompath(x, 0, [relativePath fileSystemRepresentation], [temporaryFile fileSystemRepresentation]);
- assert(newFile);
- xar_prop_set(newFile, "binary-delta", "true");
- unlink([temporaryFile fileSystemRepresentation]);
- });
- }
- dispatch_release(xarQueue);
- dispatch_release(deltaGroup);
- });
-}
-
static NSString *absolutePath(NSString *path)
{
NSURL *url = [[[NSURL alloc] initFileURLWithPath:path] autorelease];
@@ -116,16 +134,22 @@ int main(int argc, char **argv)
NSString *newPath = [NSString stringWithUTF8String:argv[3]];
NSString *patchFile = [NSString stringWithUTF8String:argv[4]];
- if ([command isEqualToString:@"apply"])
- return applyBinaryDelta(oldPath, newPath, patchFile);
- if (![command isEqualToString:@"create"])
+ if ([command isEqualToString:@"apply"]) {
+ int result = applyBinaryDelta(oldPath, newPath, patchFile);
+ [pool drain];
+ return result;
+ }
+ if (![command isEqualToString:@"create"]) {
+ [pool drain];
goto usage;
-
- NSMutableDictionary *originalTreeState = [NSMutableDictionary new];
+ }
+
+ NSMutableDictionary *originalTreeState = [NSMutableDictionary dictionary];
const char *sourcePaths[] = {[oldPath fileSystemRepresentation], 0};
FTS *fts = fts_open((char* const*)sourcePaths, FTS_PHYSICAL | FTS_NOCHDIR, compareFiles);
if (!fts) {
+ [pool drain];
perror("fts_open");
return 1;
}
@@ -147,7 +171,7 @@ int main(int argc, char **argv)
NSString *beforeHash = hashOfTree(oldPath);
- NSMutableDictionary *newTreeState = [NSMutableDictionary new];
+ NSMutableDictionary *newTreeState = [NSMutableDictionary dictionary];
for (NSString *key in originalTreeState)
{
[newTreeState setObject:[NSNull null] forKey:key];
@@ -157,6 +181,7 @@ int main(int argc, char **argv)
sourcePaths[0] = [newPath fileSystemRepresentation];
fts = fts_open((char* const*)sourcePaths, FTS_PHYSICAL | FTS_NOCHDIR, compareFiles);
if (!fts) {
+ [pool drain];
perror("fts_open");
return 1;
}
@@ -184,49 +209,55 @@ int main(int argc, char **argv)
fprintf(stderr, "\nGenerating delta... ");
- dispatch_group_t deltaGroup = dispatch_group_create();
- dispatch_queue_t xarQueue = dispatch_queue_create("xar", 0);
-
NSString *temporaryFile = temporaryPatchFile(patchFile);
- __block xar_t x;
- dispatch_sync(xarQueue, ^{
- x = xar_open([temporaryFile fileSystemRepresentation], WRITE);
- xar_opt_set(x, XAR_OPT_COMPRESSION, "bzip2");
- xar_subdoc_t attributes = xar_subdoc_new(x, "binary-delta-attributes");
- xar_subdoc_prop_set(attributes, "before-sha1", [beforeHash UTF8String]);
- xar_subdoc_prop_set(attributes, "after-sha1", [afterHash UTF8String]);
- });
+ xar_t x = xar_open([temporaryFile fileSystemRepresentation], WRITE);
+ xar_opt_set(x, XAR_OPT_COMPRESSION, "bzip2");
+ xar_subdoc_t attributes = xar_subdoc_new(x, "binary-delta-attributes");
+ xar_subdoc_prop_set(attributes, "before-sha1", [beforeHash UTF8String]);
+ xar_subdoc_prop_set(attributes, "after-sha1", [afterHash UTF8String]);
+
+ NSOperationQueue *deltaQueue = [[NSOperationQueue alloc] init];
+ NSMutableArray *deltaOperations = [NSMutableArray array];
NSArray *keys = [[newTreeState allKeys] sortedArrayUsingSelector:@selector(compare:)];
for (NSString* key in keys) {
id value = [newTreeState valueForKey:key];
if ([value isEqual:[NSNull null]]) {
- dispatch_group_async(deltaGroup, xarQueue, ^{
- xar_file_t newFile = xar_add_frombuffer(x, 0, [key fileSystemRepresentation], "", 1);
- assert(newFile);
- xar_prop_set(newFile, "delete", "true");
- });
+ xar_file_t newFile = xar_add_frombuffer(x, 0, [key fileSystemRepresentation], "", 1);
+ assert(newFile);
+ xar_prop_set(newFile, "delete", "true");
continue;
}
NSDictionary *originalInfo = [originalTreeState objectForKey:key];
NSDictionary *newInfo = [newTreeState objectForKey:key];
if (shouldSkipDeltaCompression(key, originalInfo, newInfo)) {
NSString *path = [newPath stringByAppendingPathComponent:key];
- __block BOOL deleteFirst = shouldDeleteThenExtract(key, originalInfo, newInfo);
- dispatch_group_async(deltaGroup, xarQueue, ^{
- xar_file_t newFile = xar_add_frompath(x, 0, [key fileSystemRepresentation], [path fileSystemRepresentation]);
- assert(newFile);
- if (deleteFirst)
- xar_prop_set(newFile, "delete-then-extract", "true");
- });
- } else
- addBinaryDelta(deltaGroup, xarQueue, x, key, oldPath, newPath);
+ xar_file_t newFile = xar_add_frompath(x, 0, [key fileSystemRepresentation], [path fileSystemRepresentation]);
+ assert(newFile);
+ if (shouldDeleteThenExtract(key, originalInfo, newInfo))
+ xar_prop_set(newFile, "delete-then-extract", "true");
+ } else {
+ CreateBinaryDeltaOperation *operation = [[CreateBinaryDeltaOperation alloc] initWithRelativePath:key oldTree:oldPath newTree:newPath];
+ [deltaQueue addOperation:operation];
+ [deltaOperations addObject:operation];
+ [operation release];
+ }
+ }
+
+ [deltaQueue waitUntilAllOperationsAreFinished];
+ [deltaQueue release];
+
+ for (CreateBinaryDeltaOperation *operation in deltaOperations) {
+ NSString *resultPath = [operation resultPath];
+ xar_file_t newFile = xar_add_frompath(x, 0, [[operation relativePath] fileSystemRepresentation], [resultPath fileSystemRepresentation]);
+ assert(newFile);
+ xar_prop_set(newFile, "binary-delta", "true");
+ unlink([resultPath fileSystemRepresentation]);
}
- dispatch_group_wait(deltaGroup, UINT64_MAX);
- dispatch_sync(xarQueue, ^{ xar_close(x); });
+ xar_close(x);
unlink([patchFile fileSystemRepresentation]);
link([temporaryFile fileSystemRepresentation], [patchFile fileSystemRepresentation]);

0 comments on commit 6169234

Please sign in to comment.