Core Data Store: Handle concurrency properly

All concurrency from other threads should pass through the viewContext's
performBlock or performBlockAndWait functions, and no other way. So now,
all access to Core Data is either happening on the main thread, or by
using these code blocks, all of which will wait for their access to
proceed.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
main
Christopher Snowhill 2022-10-30 16:48:59 -07:00
parent e3ae28369f
commit 4bed0af868
10 changed files with 361 additions and 445 deletions

View File

@ -223,12 +223,7 @@ static AppController *kAppController = nil;
request.predicate = predicate;
NSError *error = nil;
[playlistController.persistentContainerLock lock];
NSArray *results = [playlistController.persistentContainer.viewContext executeFetchRequest:request error:&error];
if(results) {
results = [results copy];
}
[playlistController.persistentContainerLock unlock];
if(results && [results count] == 1) {
PlaylistEntry *pe = results[0];
@ -434,9 +429,7 @@ static AppController *kAppController = nil;
for(PlaylistEntry *pe in playlistController.arrangedObjects) {
if(pe.deLeted) {
[playlistController.persistentContainerLock lock];
[moc deleteObject:pe];
[playlistController.persistentContainerLock unlock];
continue;
}
if([artLeftovers objectForKey:pe.artHash]) {
@ -444,11 +437,9 @@ static AppController *kAppController = nil;
}
}
[playlistController.persistentContainerLock lock];
for(NSString *key in artLeftovers) {
[moc deleteObject:[artLeftovers objectForKey:key]];
}
[playlistController.persistentContainerLock unlock];
[playlistController commitPersistentStore];

View File

@ -68,7 +68,6 @@ typedef NS_ENUM(NSInteger, URLOrigin) {
@property(retain) NSString *_Nullable totalTime;
@property(retain) NSString *_Nullable currentStatus;
@property(strong, nonatomic, readonly) NSLock *_Nonnull persistentContainerLock;
@property(strong, nonatomic, readonly) NSPersistentContainer *_Nonnull persistentContainer;
@property(strong, nonatomic, readonly) NSMutableDictionary<NSString *, AlbumArtwork *> *_Nonnull persistentArtStorage;
@ -143,7 +142,6 @@ typedef NS_ENUM(NSInteger, URLOrigin) {
- (void)readShuffleListFromDataStore;
+ (NSPersistentContainer *_Nonnull)sharedPersistentContainer;
+ (NSLock *_Nonnull)sharedPersistentContainerLock;
// reload metadata of selection
- (IBAction)reloadTags:(id _Nullable)sender;

View File

@ -30,8 +30,6 @@
extern BOOL kAppControllerShuttingDown;
NSLock *kPersistentContainerLock = nil;
NSPersistentContainer *kPersistentContainer = nil;
@implementation PlaylistController
@ -128,10 +126,6 @@ static void *playlistControllerContext = &playlistControllerContext;
kPersistentContainer = self.persistentContainer;
_persistentContainerLock = [[NSLock alloc] init];
kPersistentContainerLock = self.persistentContainerLock;
self.persistentContainer.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
_persistentArtStorage = [[NSMutableDictionary alloc] init];
@ -144,10 +138,6 @@ static void *playlistControllerContext = &playlistControllerContext;
return kPersistentContainer;
}
+ (NSLock *)sharedPersistentContainerLock {
return kPersistentContainerLock;
}
- (void)awakeFromNib {
[super awakeFromNib];
@ -251,28 +241,28 @@ static void *playlistControllerContext = &playlistControllerContext;
}
- (void)commitPersistentStore {
[self.persistentContainer.viewContext performBlockAndWait:^{
NSError *error = nil;
[self.persistentContainerLock lock];
[self.persistentContainer.viewContext save:&error];
[self.persistentContainerLock unlock];
if(error) {
ALog(@"Error committing playlist storage: %@", [error localizedDescription]);
}
}];
}
- (void)updatePlayCountForTrack:(PlaylistEntry *)pe {
if(pe.countAdded) return;
pe.countAdded = YES;
PlayCount *pc = pe.playCountItem;
__block PlayCount *pc = pe.playCountItem;
if(pc) {
[self.persistentContainerLock lock];
[self.persistentContainer.viewContext performBlockAndWait:^{
pc.count += 1;
pc.lastPlayed = [NSDate date];
[self.persistentContainerLock unlock];
}];
} else {
[self.persistentContainerLock lock];
[self.persistentContainer.viewContext performBlockAndWait:^{
pc = [NSEntityDescription insertNewObjectForEntityForName:@"PlayCount" inManagedObjectContext:self.persistentContainer.viewContext];
pc.count = 1;
pc.firstSeen = pc.lastPlayed = [NSDate date];
@ -280,17 +270,17 @@ static void *playlistControllerContext = &playlistControllerContext;
pc.artist = pe.artist;
pc.title = pe.title;
pc.filename = pe.filenameFragment;
[self.persistentContainerLock unlock];
}];
}
[self commitPersistentStore];
}
- (void)firstSawTrack:(PlaylistEntry *)pe {
PlayCount *pc = pe.playCountItem;
__block PlayCount *pc = pe.playCountItem;
if(!pc) {
[self.persistentContainerLock lock];
[self.persistentContainer.viewContext performBlockAndWait:^{
pc = [NSEntityDescription insertNewObjectForEntityForName:@"PlayCount" inManagedObjectContext:self.persistentContainer.viewContext];
pc.count = 0;
pc.firstSeen = [NSDate date];
@ -298,16 +288,16 @@ static void *playlistControllerContext = &playlistControllerContext;
pc.artist = pe.artist;
pc.title = pe.title;
pc.filename = pe.filenameFragment;
[self.persistentContainerLock unlock];
}];
}
}
- (void)ratingUpdatedWithEntry:(PlaylistEntry *)pe rating:(CGFloat)rating {
if(pe && !pe.deLeted) {
PlayCount *pc = pe.playCountItem;
__block PlayCount *pc = pe.playCountItem;
if(!pc) {
[self.persistentContainerLock lock];
[self.persistentContainer.viewContext performBlockAndWait:^{
pc = [NSEntityDescription insertNewObjectForEntityForName:@"PlayCount" inManagedObjectContext:self.persistentContainer.viewContext];
pc.count = 0;
pc.firstSeen = [NSDate date];
@ -315,12 +305,12 @@ static void *playlistControllerContext = &playlistControllerContext;
pc.artist = pe.artist;
pc.title = pe.title;
pc.filename = pe.filenameFragment;
[self.persistentContainerLock unlock];
}];
}
[self.persistentContainerLock lock];
[self.persistentContainer.viewContext performBlockAndWait:^{
pc.rating = rating;
[self.persistentContainerLock unlock];
}];
[self commitPersistentStore];
}
@ -330,7 +320,9 @@ static void *playlistControllerContext = &playlistControllerContext;
PlayCount *pc = pe.playCountItem;
if(pc) {
[self.persistentContainer.viewContext performBlockAndWait:^{
pc.count = 0;
}];
}
}
@ -338,7 +330,9 @@ static void *playlistControllerContext = &playlistControllerContext;
PlayCount *pc = pe.playCountItem;
if(pc) {
[self.persistentContainer.viewContext performBlockAndWait:^{
pc.rating = 0;
}];
}
}
@ -1380,19 +1374,16 @@ static void *playlistControllerContext = &playlistControllerContext;
request.predicate = predicate;
request.sortDescriptors = @[sortDescriptor];
[self.persistentContainer.viewContext performBlockAndWait:^{
NSError *error = nil;
[self.persistentContainerLock lock];
NSArray *results = [self.persistentContainer.viewContext executeFetchRequest:request error:&error];
if(results) {
results = [results copy];
}
[self.persistentContainerLock unlock];
if(results && [results count] > 0) {
[queueList removeAllObjects];
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [results count])];
[queueList insertObjects:results atIndexes:indexSet];
}
}];
}
- (void)readShuffleListFromDataStore {
@ -1404,19 +1395,16 @@ static void *playlistControllerContext = &playlistControllerContext;
request.predicate = predicate;
request.sortDescriptors = @[sortDescriptor];
[self.persistentContainer.viewContext performBlockAndWait:^{
NSError *error = nil;
[self.persistentContainerLock lock];
NSArray *results = [self.persistentContainer.viewContext executeFetchRequest:request error:&error];
if(results) {
results = [results copy];
}
[self.persistentContainerLock unlock];
if(results && [results count] > 0) {
[shuffleList removeAllObjects];
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [results count])];
[shuffleList insertObjects:results atIndexes:indexSet];
}
}];
}
- (void)addShuffledListToFront {
@ -1946,16 +1934,18 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc
}
- (BOOL)pathSuggesterEmpty {
BOOL rval;
__block BOOL rval;
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"SandboxToken"];
[self.persistentContainer.viewContext performBlockAndWait:^{
NSError *error = nil;
[self.persistentContainerLock lock];
NSArray *results = [self.persistentContainer.viewContext executeFetchRequest:request error:&error];
if(!results || [results count] < 1) rval = YES;
else rval = NO;
[self.persistentContainerLock unlock];
if(!results || [results count] < 1)
rval = YES;
else
rval = NO;
}];
return rval;
}

View File

@ -16,7 +16,6 @@
#import "SHA256Digest.h"
#import "SecondsFormatter.h"
extern NSLock *kPersistentContainerLock;
extern NSPersistentContainer *kPersistentContainer;
extern NSMutableDictionary<NSString *, AlbumArtwork *> *kArtworkDictionary;
@ -364,11 +363,9 @@ extern NSMutableDictionary<NSString *, AlbumArtwork *> *kArtworkDictionary;
self.artHash = imageCacheTag;
if(![kArtworkDictionary objectForKey:imageCacheTag]) {
[kPersistentContainerLock lock];
AlbumArtwork *art = [NSEntityDescription insertNewObjectForEntityForName:@"AlbumArtwork" inManagedObjectContext:kPersistentContainer.viewContext];
art.artHash = imageCacheTag;
art.artData = albumArtInternal;
[kPersistentContainerLock unlock];
[kArtworkDictionary setObject:art forKey:imageCacheTag];
}
@ -585,11 +582,13 @@ NSURL *_Nullable urlForPath(NSString *_Nullable path) {
NSCompoundPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[albumPredicate, artistPredicate, titlePredicate]];
__block PlayCount *item = nil;
[kPersistentContainer.viewContext performBlockAndWait:^{
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"PlayCount"];
request.predicate = predicate;
NSError *error = nil;
[kPersistentContainerLock lock];
NSArray *results = [kPersistentContainer.viewContext executeFetchRequest:request error:&error];
if(!results || [results count] < 1) {
@ -601,14 +600,12 @@ NSURL *_Nullable urlForPath(NSString *_Nullable path) {
results = [kPersistentContainer.viewContext executeFetchRequest:request error:&error];
}
if(results) {
results = [results copy];
}
[kPersistentContainerLock unlock];
if(!results || [results count] < 1) return;
if(!results || [results count] < 1) return nil;
item = results[0];
}];
return results[0];
return item;
}
@dynamic playCount;

View File

@ -567,13 +567,11 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc
__block PlaylistEntry *pe;
dispatch_sync_reentrant(dispatch_get_main_queue(), ^{
[self->playlistController.persistentContainerLock lock];
pe = [NSEntityDescription insertNewObjectForEntityForName:@"PlaylistEntry" inManagedObjectContext:self->playlistController.persistentContainer.viewContext];
pe.url = url;
pe.index = index + i;
pe.rawTitle = [[url path] lastPathComponent];
pe.queuePosition = -1;
[self->playlistController.persistentContainerLock unlock];
});
[entries addObject:pe];
@ -591,12 +589,10 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc
__block PlaylistEntry *pe;
dispatch_sync_reentrant(dispatch_get_main_queue(), ^{
[self->playlistController.persistentContainerLock lock];
pe = [NSEntityDescription insertNewObjectForEntityForName:@"PlaylistEntry" inManagedObjectContext:self->playlistController.persistentContainer.viewContext];
[pe setValuesForKeysWithDictionary:entry];
pe.index = index + i;
pe.queuePosition = -1;
[self->playlistController.persistentContainerLock unlock];
});
[entries addObject:pe];
@ -791,16 +787,12 @@ NSURL *_Nullable urlForPath(NSString *_Nullable path);
NSCompoundPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[deletedPredicate, hasUrlPredicate]];
[moc performBlockAndWait:^{
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"PlaylistEntry"];
request.predicate = predicate;
NSError *error;
[playlistController.persistentContainerLock lock];
NSArray *results = [moc executeFetchRequest:request error:&error];
if(results) {
results = [results copy];
}
[playlistController.persistentContainerLock unlock];
if(results && [results count] > 0) {
for(PlaylistEntry *pe in results) {
@ -810,6 +802,7 @@ NSURL *_Nullable urlForPath(NSString *_Nullable path);
}
}
}
}];
for(size_t i = 0, j = [outArray count]; i < j; i += 2) {
__block NSString *entryKey = [outArray objectAtIndex:i];
@ -927,10 +920,8 @@ NSURL *_Nullable urlForPath(NSString *_Nullable path);
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"AlbumArtwork"];
NSError *error = nil;
[playlistController.persistentContainerLock lock];
NSArray *results = [moc executeFetchRequest:request error:&error];
if(!results) {
[playlistController.persistentContainerLock unlock];
ALog(@"Error fetching AlbumArtwork objects: %@\n%@", [error localizedDescription], [error userInfo]);
abort();
}
@ -938,7 +929,6 @@ NSURL *_Nullable urlForPath(NSString *_Nullable path);
for(AlbumArtwork *art in results) {
[kArtworkDictionary setObject:art forKey:art.artHash];
}
[playlistController.persistentContainerLock unlock];
request = [NSFetchRequest fetchRequestWithEntityName:@"PlaylistEntry"];
@ -946,30 +936,24 @@ NSURL *_Nullable urlForPath(NSString *_Nullable path);
request.sortDescriptors = @[sortDescriptor];
[playlistController.persistentContainerLock lock];
results = [moc executeFetchRequest:request error:&error];
if(!results) {
[playlistController.persistentContainerLock unlock];
ALog(@"Error fetching PlaylistEntry objects: %@\n%@", [error localizedDescription], [error userInfo]);
abort();
}
if([results count] == 0) {
[playlistController.persistentContainerLock unlock];
return NO;
}
NSMutableArray *resultsCopy = [results mutableCopy];
[playlistController.persistentContainerLock unlock];
NSMutableIndexSet *pruneSet = [[NSMutableIndexSet alloc] init];
NSUInteger index = 0;
for(PlaylistEntry *pe in resultsCopy) {
if(pe.deLeted || !pe.urlString || [pe.urlString length] < 1) {
[pruneSet addIndex:index];
[playlistController.persistentContainerLock lock];
[moc deleteObject:pe];
[playlistController.persistentContainerLock unlock];
}
++index;
}

View File

@ -55,7 +55,6 @@
[pathsList removeObjects:[pathsList arrangedObjects]];
NSLock *lock = [NSClassFromString(@"PlaylistController") sharedPersistentContainerLock];
NSPersistentContainer *pc = [NSClassFromString(@"PlaylistController") sharedPersistentContainer];
NSPredicate *hasUrlPredicate = [NSPredicate predicateWithFormat:@"urlString != nil && urlString != %@", @""];
@ -67,12 +66,7 @@
request.predicate = predicate;
NSError *error = nil;
[lock lock];
NSArray *results = [pc.viewContext executeFetchRequest:request error:&error];
if(results) {
results = [results copy];
}
[lock unlock];
if(!results || [results count] < 1) return;

View File

@ -36,18 +36,12 @@
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"path" ascending:YES];
[self setSortDescriptors:@[sortDescriptor]];
NSLock *lock = [NSClassFromString(@"PlaylistController") sharedPersistentContainerLock];
NSPersistentContainer *pc = [NSClassFromString(@"PlaylistController") sharedPersistentContainer];
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"SandboxToken"];
NSError *error = nil;
[lock lock];
NSArray *results = [pc.viewContext executeFetchRequest:request error:&error];
if(results) {
results = [results copy];
}
[lock unlock];
if(results && [results count] > 0) {
for(SandboxToken *token in results) {
@ -67,31 +61,31 @@
return;
}
NSLock *lock = [NSClassFromString(@"PlaylistController") sharedPersistentContainerLock];
NSPersistentContainer *pc = [NSClassFromString(@"PlaylistController") sharedPersistentContainer];
[lock lock];
[pc.viewContext performBlockAndWait:^{
SandboxToken *token = [NSEntityDescription insertNewObjectForEntityForName:@"SandboxToken" inManagedObjectContext:pc.viewContext];
if(token) {
NSError *err = nil;
token.path = [url path];
token.bookmark = bookmark;
[pc.viewContext save:&err];
[lock unlock];
if(err) {
ALog(@"Error saving bookmark: %@", [err localizedDescription]);
} else {
[self addObject:@{ @"path": [url path], @"valid": NSLocalizedPrefString(@"ValidYes"), @"isFolder": @(token.folder), @"token": token }];
[self addObject:@{@"path": [url path],
@"valid": NSLocalizedPrefString(@"ValidYes"),
@"isFolder": @(token.folder),
@"token": token}];
[NSClassFromString(@"SandboxBroker") cleanupFolderAccess];
[self refresh];
}
} else {
[lock unlock];
}
}];
}
- (void)removeToken:(id)token {
NSLock *lock = [NSClassFromString(@"PlaylistController") sharedPersistentContainerLock];
NSPersistentContainer *pc = [NSClassFromString(@"PlaylistController") sharedPersistentContainer];
NSArray *objects = [[self arrangedObjects] copy];
@ -101,46 +95,45 @@
for(NSDictionary *obj in objects) {
if([[obj objectForKey:@"token"] isEqualTo:token]) {
[self removeObject:obj];
[lock lock];
[pc.viewContext performBlockAndWait:^{
[pc.viewContext deleteObject:token];
[lock unlock];
}];
updated = YES;
break;
}
}
if(updated) {
[pc.viewContext performBlockAndWait:^{
NSError *error;
[lock lock];
[pc.viewContext save:&error];
[lock unlock];
if(error) {
ALog(@"Error deleting bookmark: %@", [error localizedDescription]);
}
}];
}
}
- (void)removeStaleEntries {
BOOL updated = NO;
NSLock *lock = [NSClassFromString(@"PlaylistController") sharedPersistentContainerLock];
NSPersistentContainer *pc = [NSClassFromString(@"PlaylistController") sharedPersistentContainer];
for(NSDictionary *entry in [[self arrangedObjects] copy]) {
if([[entry objectForKey:@"valid"] isEqualToString:NSLocalizedPrefString(@"ValidNo")]) {
[self removeObject:entry];
[lock lock];
[pc.viewContext performBlockAndWait:^{
[pc.viewContext deleteObject:[entry objectForKey:@"token"]];
[lock unlock];
}];
updated = YES;
}
}
if(updated) {
[pc.viewContext performBlockAndWait:^{
NSError *error;
[lock lock];
[pc.viewContext save:&error];
[lock unlock];
if(error) {
ALog(@"Error saving after removing stale bookmarks: %@", [error localizedDescription]);
}
}];
}
}

View File

@ -13,7 +13,6 @@
// with format (entryKey, transformerName)
static NSDictionary *importKeys;
extern NSLock *kPersistentContainerLock;
extern NSPersistentContainer *kPersistentContainer;
@implementation SpotlightPlaylistEntry
@ -38,8 +37,9 @@ extern NSPersistentContainer *kPersistentContainer;
}
+ (PlaylistEntry *)playlistEntryWithMetadataItem:(NSMetadataItem *)metadataItem {
[kPersistentContainerLock lock];
PlaylistEntry *entry = [NSEntityDescription insertNewObjectForEntityForName:@"PlaylistEntry" inManagedObjectContext:kPersistentContainer.viewContext];
__block PlaylistEntry *entry = nil;
[kPersistentContainer.viewContext performBlockAndWait:^{
entry = [NSEntityDescription insertNewObjectForEntityForName:@"PlaylistEntry" inManagedObjectContext:kPersistentContainer.viewContext];
entry.deLeted = YES;
@ -84,7 +84,7 @@ extern NSPersistentContainer *kPersistentContainer;
entry.url = url;
[entry setMetadata:dict];
[kPersistentContainerLock unlock];
}];
return entry;
}

View File

@ -14,7 +14,6 @@
#import "SHA256Digest.h"
extern NSLock *kPersistentContainerLock;
extern NSPersistentContainer *kPersistentContainer;
NSString *getDatabasePath(void) {
@ -1444,15 +1443,15 @@ static SQLiteStore *g_sharedStore = nil;
#endif
- (PlaylistEntry *_Nonnull)getTrack:(int64_t)trackId {
[kPersistentContainerLock lock];
PlaylistEntry *entry = [NSEntityDescription insertNewObjectForEntityForName:@"PlaylistEntry" inManagedObjectContext:kPersistentContainer.viewContext];
__block PlaylistEntry *entry = nil;
[kPersistentContainer.viewContext performBlockAndWait:^{
entry = [NSEntityDescription insertNewObjectForEntityForName:@"PlaylistEntry" inManagedObjectContext:kPersistentContainer.viewContext];
if(trackId < 0) {
entry.error = YES;
entry.errorMessage = NSLocalizedString(@"ErrorInvalidTrackId", @"");
entry.deLeted = YES;
[kPersistentContainerLock unlock];
return entry;
return;
}
sqlite3_stmt *st = stmt[stmt_select_track_data];
@ -1462,8 +1461,7 @@ static SQLiteStore *g_sharedStore = nil;
entry.error = YES;
entry.errorMessage = NSLocalizedString(@"ErrorSqliteProblem", @"");
entry.deLeted = YES;
[kPersistentContainerLock unlock];
return entry;
return;
}
int rc = sqlite3_step(st);
@ -1473,8 +1471,7 @@ static SQLiteStore *g_sharedStore = nil;
entry.error = YES;
entry.errorMessage = NSLocalizedString(@"ErrorSqliteProblem", @"");
entry.deLeted = YES;
[kPersistentContainerLock unlock];
return entry;
return;
}
if(rc == SQLITE_ROW) {
@ -1549,9 +1546,9 @@ static SQLiteStore *g_sharedStore = nil;
entry.errorMessage = NSLocalizedString(@"ErrorTrackMissing", @"");
entry.deLeted = YES;
}
[kPersistentContainerLock unlock];
sqlite3_reset(st);
}];
return entry;
}
@ -1846,7 +1843,7 @@ static SQLiteStore *g_sharedStore = nil;
}
- (PlaylistEntry *)playlistGetItem:(int64_t)index {
PlaylistEntry *entry = nil;
__block PlaylistEntry *entry = nil;
sqlite3_stmt *st = stmt[stmt_select_playlist];
@ -1866,15 +1863,15 @@ static SQLiteStore *g_sharedStore = nil;
int64_t entryId = sqlite3_column_int64(st, select_playlist_out_entry_id);
entry = [self getTrack:trackId];
if(!entry.deLeted && !entry.error) {
[kPersistentContainerLock lock];
[kPersistentContainer.viewContext performBlockAndWait:^{
entry.index = index;
entry.entryId = entryId;
[kPersistentContainerLock unlock];
}];
} else {
[kPersistentContainerLock lock];
[kPersistentContainer.viewContext performBlockAndWait:^{
[kPersistentContainer.viewContext deleteObject:entry];
[kPersistentContainerLock unlock];
entry = nil;
}];
}
}

View File

@ -92,10 +92,6 @@ static SandboxBroker *kSharedSandboxBroker = nil;
return kSharedSandboxBroker;
}
+ (NSLock *)sharedPersistentContainerLock {
return [NSClassFromString(@"PlaylistController") sharedPersistentContainerLock];
}
+ (NSPersistentContainer *)sharedPersistentContainer {
return [NSClassFromString(@"PlaylistController") sharedPersistentContainer];
}
@ -151,25 +147,21 @@ static SandboxBroker *kSharedSandboxBroker = nil;
}
- (SandboxEntry *)recursivePathTest:(NSURL *)url {
SandboxEntry *ret = nil;
__block SandboxEntry *ret = nil;
NSLock *lock = [SandboxBroker sharedPersistentContainerLock];
NSPersistentContainer *pc = [SandboxBroker sharedPersistentContainer];
NSPredicate *folderPredicate = [NSPredicate predicateWithFormat:@"folder == NO"];
NSPredicate *filePredicate = [NSPredicate predicateWithFormat:@"path == %@", [url path]];
[pc.viewContext performBlockAndWait:^{
NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[folderPredicate, filePredicate]];
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"SandboxToken"];
request.predicate = predicate;
NSError *error = nil;
[lock lock];
NSArray *results = [pc.viewContext executeFetchRequest:request error:&error];
if(results) {
results = [results copy];
}
[lock unlock];
if(results && [results count] > 0) {
ret = [[SandboxEntry alloc] initWithToken:results[0]];
}
@ -184,12 +176,7 @@ static SandboxBroker *kSharedSandboxBroker = nil;
request.predicate = predicate;
error = nil;
[lock lock];
results = [pc.viewContext executeFetchRequest:request error:&error];
if(results) {
results = [results copy];
}
[lock unlock];
if(results && [results count] > 0) {
for(SandboxToken *token in results) {
@ -202,6 +189,7 @@ static SandboxBroker *kSharedSandboxBroker = nil;
}
}
}
}];
if(ret) {
BOOL isStale;
@ -212,7 +200,9 @@ static SandboxBroker *kSharedSandboxBroker = nil;
return nil;
}
[pc.viewContext performBlockAndWait:^{
ret.secureUrl = secureUrl;
}];
return ret;
}
@ -253,22 +243,17 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc
return;
}
dispatch_sync_reentrant(dispatch_get_main_queue(), ^{
NSLock *lock = [SandboxBroker sharedPersistentContainerLock];
NSPersistentContainer *pc = [SandboxBroker sharedPersistentContainer];
[lock lock];
[pc.viewContext performBlockAndWait:^{
SandboxToken *token = [NSEntityDescription insertNewObjectForEntityForName:@"SandboxToken" inManagedObjectContext:pc.viewContext];
if(token) {
token.path = [folderUrl path];
token.bookmark = bookmark;
[lock unlock];
[SandboxBroker cleanupFolderAccess];
} else {
[lock unlock];
}
});
}];
}
}
}
@ -303,11 +288,9 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc
return;
}
NSLock *lock = [SandboxBroker sharedPersistentContainerLock];
NSPersistentContainer *pc = [SandboxBroker sharedPersistentContainer];
dispatch_sync_reentrant(dispatch_get_main_queue(), ^{
[lock lock];
[pc.viewContext performBlockAndWait:^{
SandboxToken *token = [NSEntityDescription insertNewObjectForEntityForName:@"SandboxToken" inManagedObjectContext:pc.viewContext];
if(token) {
@ -315,8 +298,7 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc
token.bookmark = bookmark;
token.folder = NO;
}
[lock unlock];
});
}];
}
}
}
@ -372,19 +354,14 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc
return;
}
NSLock *lock = [SandboxBroker sharedPersistentContainerLock];
NSPersistentContainer *pc = [SandboxBroker sharedPersistentContainer];
[lock lock];
SandboxToken *token = [NSEntityDescription insertNewObjectForEntityForName:@"SandboxToken" inManagedObjectContext:pc.viewContext];
if(token) {
token.path = [folderUrl path];
token.bookmark = bookmark;
[lock unlock];
[SandboxBroker cleanupFolderAccess];
} else {
[lock unlock];
}
}
});
@ -393,21 +370,19 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc
}
+ (void)cleanupFolderAccess {
NSLock *lock = [SandboxBroker sharedPersistentContainerLock];
NSPersistentContainer *pc = [SandboxBroker sharedPersistentContainer];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"path.length" ascending:YES];
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"SandboxToken"];
request.sortDescriptors = @[sortDescriptor];
[pc.viewContext performBlockAndWait:^{
NSError *error = nil;
NSMutableArray *resultsCopy = nil;
[lock lock];
NSArray *results = [pc.viewContext executeFetchRequest:request error:&error];
NSMutableArray *resultsCopy = nil;
if(results) {
resultsCopy = [results mutableCopy];
}
[lock unlock];
BOOL isUpdated = NO;
@ -418,9 +393,7 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc
for(NSUInteger j = i + 1; j < [resultsCopy count];) {
SandboxToken *compareToken = resultsCopy[j];
if([SandboxBroker isPath:[NSURL fileURLWithPath:compareToken.path] aSubdirectoryOf:url]) {
[lock lock];
[pc.viewContext deleteObject:compareToken];
[lock unlock];
isUpdated = YES;
[resultsCopy removeObjectAtIndex:j];
} else {
@ -432,13 +405,12 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc
if(isUpdated) {
NSError *error;
[lock lock];
[pc.viewContext save:&error];
[lock unlock];
if(error) {
ALog(@"Error saving data: %@", [error localizedDescription]);
}
}
}];
}
- (const void *)beginFolderAccess:(NSURL *)fileUrl {