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 6f269dd689
commit ba52c69a5a
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,23 +425,49 @@ 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
for(size_t i = 0, j = [expandedURLs count]; i < j; ++i) {
NSBlockOperation *op = [[NSBlockOperation alloc] init];
[op addExecutionBlock:^{
id<SentrySpan> pathTask = nil; id<SentrySpan> pathTask = nil;
id<SentrySpan> innerTask = nil;
@try { @try {
if(containerTask) {
pathTask = [containerTask startChildWithOperation:@"Process path as container" description:[NSString stringWithFormat:@"Checking if file is container: %@", url]]; pathTask = [containerTask startChildWithOperation:@"Process path as container" description:[NSString stringWithFormat:@"Checking if file is container: %@", url]];
if([[self acceptableContainerTypes] containsObject:[[url pathExtension] lowercaseString]]) { }
id<SentrySpan> innerTask = [pathTask startChildWithOperation:@"Container, processing"];
[lock lock];
NSURL *url = [expandedURLs objectAtIndex:0];
[expandedURLs removeObjectAtIndex:0];
[lock unlock];
if([acceptableContainerTypes containsObject:[[url pathExtension] lowercaseString]]) {
if(pathTask) {
innerTask = [pathTask startChildWithOperation:@"Container, processing"];
}
NSArray *urls = [AudioContainer urlsForContainerURL:url]; NSArray *urls = [AudioContainer urlsForContainerURL:url];
if(urls != nil && [urls count] != 0) { if(urls != nil && [urls count] != 0) {
[lock lock];
[containedURLs addObjectsFromArray:urls]; [containedURLs addObjectsFromArray:urls];
[lock unlock];
// Make sure the container isn't added twice. // Make sure the container isn't added twice.
[lock lock];
[uniqueURLs addObject:url]; [uniqueURLs addObject:url];
[lock unlock];
// Find the dependencies // Find the dependencies
NSArray *depURLs = [AudioContainer dependencyUrlsForContainerURL:url]; NSArray *depURLs = [AudioContainer dependencyUrlsForContainerURL:url];
@ -451,7 +480,9 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc
} }
} }
if(depURLs) { if(depURLs) {
[lock lock];
[dependencyURLs addObjectsFromArray:depURLs]; [dependencyURLs addObjectsFromArray:depURLs];
[lock unlock];
for(NSURL *u in depURLs) { for(NSURL *u in depURLs) {
if([u isFileURL]) { if([u isFileURL]) {
@ -465,29 +496,54 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc
} }
} else { } else {
/* Fall back on adding the raw file if all container parsers have failed. */ /* Fall back on adding the raw file if all container parsers have failed. */
[lock lock];
[fileURLs addObject:url]; [fileURLs addObject:url];
[lock unlock];
} }
if(innerTask) {
[innerTask finish]; [innerTask finish];
} else if([[[url pathExtension] lowercaseString] isEqualToString:@"xml"]) { innerTask = nil;
xmlData = [XmlContainer entriesForContainerURL:url];
} else {
[fileURLs addObject:url];
} }
} else if([[[url pathExtension] lowercaseString] isEqualToString:@"xml"]) {
[lock lock];
xmlData = [XmlContainer entriesForContainerURL:url];
[lock unlock];
} else {
[lock lock];
[fileURLs addObject:url];
[lock unlock];
}
if(pathTask) {
[pathTask finish]; [pathTask finish];
pathTask = nil;
}
} }
@catch(id anException) { @catch(id anException) {
DLog(@"Exception caught while processing for containers: %@", anException); DLog(@"Exception caught while processing for containers: %@", anException);
[SentrySDK captureException:anException]; [SentrySDK captureException:anException];
if(innerTask) {
[innerTask finishWithStatus:kSentrySpanStatusInternalError];
}
if(pathTask) { if(pathTask) {
[pathTask finishWithStatus:kSentrySpanStatusInternalError]; [pathTask finishWithStatus:kSentrySpanStatusInternalError];
} }
} }
progress += progressstep; [lock lock];
[self setProgressJobStatus:progress]; weakProgress += weakProgressstep;
[self setProgressJobStatus:weakProgress];
[lock unlock];
}];
[containerQueue addOperation:op];
} }
[containerQueue waitUntilAllOperationsAreFinished];
progress = weakProgress;
[containerTask finish]; [containerTask finish];
}
progress = 0.0; progress = 0.0;
[self completeProgressJob]; [self completeProgressJob];