Optimization: Perform container checks in queue

Perform the file container checks in an operation queue, since those are
a major bottleneck at this point, too.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
This commit is contained in:
Christopher Snowhill 2025-02-27 19:02:33 -08:00
parent 00d861efc0
commit 9fc7c99022
2 changed files with 120 additions and 63 deletions

View file

@ -27,6 +27,7 @@ typedef enum {
IBOutlet NSScrollView *playlistView; IBOutlet NSScrollView *playlistView;
IBOutlet PlaybackController *playbackController; IBOutlet PlaybackController *playbackController;
NSOperationQueue *containerQueue;
NSOperationQueue *queue; NSOperationQueue *queue;
BOOL metadataLoadInProgress; BOOL metadataLoadInProgress;

View file

@ -52,6 +52,9 @@ extern NSMutableDictionary<NSString *, AlbumArtwork *> *kArtworkDictionary;
if(self) { if(self) {
[self initDefaults]; [self initDefaults];
containerQueue = [[NSOperationQueue alloc] init];
[containerQueue setMaxConcurrentOperationCount:8];
queue = [[NSOperationQueue alloc] init]; queue = [[NSOperationQueue alloc] init];
[queue setMaxConcurrentOperationCount:8]; [queue setMaxConcurrentOperationCount:8];
@ -335,15 +338,15 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc
} }
- (NSArray *)insertURLs:(NSArray *)urls atIndex:(NSInteger)index sort:(BOOL)sort { - (NSArray *)insertURLs:(NSArray *)urls atIndex:(NSInteger)index sort:(BOOL)sort {
NSMutableSet *uniqueURLs = [NSMutableSet set]; __block NSMutableSet *uniqueURLs = [NSMutableSet set];
NSMutableArray *expandedURLs = [NSMutableArray array]; __block NSMutableArray *expandedURLs = [[NSMutableArray alloc] init];
NSMutableArray *containedURLs = [NSMutableArray array]; __block NSMutableArray *containedURLs = [[NSMutableArray alloc] init];
NSMutableArray *fileURLs = [NSMutableArray array]; __block NSMutableArray *fileURLs = [[NSMutableArray alloc] init];
NSMutableArray *validURLs = [NSMutableArray array]; NSMutableArray *validURLs = [[NSMutableArray alloc] init];
NSMutableArray *folderURLs = [NSMutableArray array]; NSMutableArray *folderURLs = [[NSMutableArray alloc] init];
NSMutableArray *dependencyURLs = [NSMutableArray array]; NSMutableArray *dependencyURLs = [[NSMutableArray alloc] init];
NSDictionary *xmlData = nil; __block NSDictionary *xmlData = nil;
BOOL addOtherFilesInFolder = [[NSUserDefaults standardUserDefaults] boolForKey:@"addOtherFilesInFolders"]; BOOL addOtherFilesInFolder = [[NSUserDefaults standardUserDefaults] boolForKey:@"addOtherFilesInFolders"];
@ -422,73 +425,126 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc
progressstep = [expandedURLs count] ? 100.0 / (double)([expandedURLs count]) : 0; progressstep = [expandedURLs count] ? 100.0 / (double)([expandedURLs count]) : 0;
id<SentrySpan> containerTask = [mainTask startChildWithOperation:@"Process paths for containers"]; if([expandedURLs count]) {
__block id<SentrySpan> containerTask = [mainTask startChildWithOperation:@"Process paths for containers"];
__block NSLock *lock = [[NSLock alloc] init];
__block NSArray *acceptableContainerTypes = [self acceptableContainerTypes];
__block double weakProgress = progress;
__block double weakProgressstep = progressstep;
for(url in expandedURLs) {
// Container vs non-container url // Container vs non-container url
id<SentrySpan> pathTask = nil; for(size_t i = 0, j = [expandedURLs count]; i < j; ++i) {
@try { NSBlockOperation *op = [[NSBlockOperation alloc] init];
pathTask = [containerTask startChildWithOperation:@"Process path as container" description:[NSString stringWithFormat:@"Checking if file is container: %@", url]];
if([[self acceptableContainerTypes] containsObject:[[url pathExtension] lowercaseString]]) { [op addExecutionBlock:^{
id<SentrySpan> innerTask = [pathTask startChildWithOperation:@"Container, processing"]; id<SentrySpan> pathTask = nil;
id<SentrySpan> innerTask = nil;
NSArray *urls = [AudioContainer urlsForContainerURL:url]; @try {
if(containerTask) {
if(urls != nil && [urls count] != 0) { pathTask = [containerTask startChildWithOperation:@"Process path as container" description:[NSString stringWithFormat:@"Checking if file is container: %@", url]];
[containedURLs addObjectsFromArray:urls];
// Make sure the container isn't added twice.
[uniqueURLs addObject:url];
// Find the dependencies
NSArray *depURLs = [AudioContainer dependencyUrlsForContainerURL:url];
BOOL localFound = NO;
for(NSURL *u in urls) {
if([u isFileURL]) {
localFound = YES;
break;
}
} }
if(depURLs) {
[dependencyURLs addObjectsFromArray:depURLs]; [lock lock];
NSURL *url = [expandedURLs objectAtIndex:0];
for(NSURL *u in depURLs) { [expandedURLs removeObjectAtIndex:0];
if([u isFileURL]) { [lock unlock];
localFound = YES;
break; if([acceptableContainerTypes containsObject:[[url pathExtension] lowercaseString]]) {
if(pathTask) {
innerTask = [pathTask startChildWithOperation:@"Container, processing"];
}
NSArray *urls = [AudioContainer urlsForContainerURL:url];
if(urls != nil && [urls count] != 0) {
[lock lock];
[containedURLs addObjectsFromArray:urls];
[lock unlock];
// Make sure the container isn't added twice.
[lock lock];
[uniqueURLs addObject:url];
[lock unlock];
// Find the dependencies
NSArray *depURLs = [AudioContainer dependencyUrlsForContainerURL:url];
BOOL localFound = NO;
for(NSURL *u in urls) {
if([u isFileURL]) {
localFound = YES;
break;
}
} }
if(depURLs) {
[lock lock];
[dependencyURLs addObjectsFromArray:depURLs];
[lock unlock];
for(NSURL *u in depURLs) {
if([u isFileURL]) {
localFound = YES;
break;
}
}
}
if(localFound) {
[[SandboxBroker sharedSandboxBroker] requestFolderForFile:url];
}
} else {
/* Fall back on adding the raw file if all container parsers have failed. */
[lock lock];
[fileURLs addObject:url];
[lock unlock];
} }
if(innerTask) {
[innerTask finish];
innerTask = nil;
}
} else if([[[url pathExtension] lowercaseString] isEqualToString:@"xml"]) {
[lock lock];
xmlData = [XmlContainer entriesForContainerURL:url];
[lock unlock];
} else {
[lock lock];
[fileURLs addObject:url];
[lock unlock];
} }
if(localFound) { if(pathTask) {
[[SandboxBroker sharedSandboxBroker] requestFolderForFile:url]; [pathTask finish];
pathTask = nil;
} }
} else {
/* Fall back on adding the raw file if all container parsers have failed. */
[fileURLs addObject:url];
} }
[innerTask finish]; @catch(id anException) {
} else if([[[url pathExtension] lowercaseString] isEqualToString:@"xml"]) { DLog(@"Exception caught while processing for containers: %@", anException);
xmlData = [XmlContainer entriesForContainerURL:url]; [SentrySDK captureException:anException];
} else { if(innerTask) {
[fileURLs addObject:url]; [innerTask finishWithStatus:kSentrySpanStatusInternalError];
} }
[pathTask finish]; if(pathTask) {
} [pathTask finishWithStatus:kSentrySpanStatusInternalError];
@catch(id anException) { }
DLog(@"Exception caught while processing for containers: %@", anException); }
[SentrySDK captureException:anException];
if(pathTask) { [lock lock];
[pathTask finishWithStatus:kSentrySpanStatusInternalError]; weakProgress += weakProgressstep;
} [self setProgressJobStatus:weakProgress];
[lock unlock];
}];
[containerQueue addOperation:op];
} }
progress += progressstep; [containerQueue waitUntilAllOperationsAreFinished];
[self setProgressJobStatus:progress];
progress = weakProgress;
[containerTask finish];
} }
[containerTask finish];
progress = 0.0; progress = 0.0;
[self completeProgressJob]; [self completeProgressJob];