Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

existingObjectWithID deadlock with NSPrivateQueueConcurrencyType

I'm running in to a freeze (deadlock?) with the NSPrivateQueueConcurrencyType concurrency type and not with the NSMainQueueConcurrencyType.

My context initialization:

_managedObjectContext = [[NSManagedObjectContext alloc] 
initWithConcurrencyType:NSPrivateQueueConcurrencyType];  
[_managedObjectContext setPersistentStoreCoordinator:coordinator];

The troublesome code:

NSManagedObjectID *managedObjectID = [self managedObjectIDForEntity:entity 
withParseObjectId:object.objectId];  
managedObject = [context existingObjectWithID:managedObjectID error:error];

The backtrace: backtrace

Link to Github project and open issue for some context into the issue.

like image 864
sbonami Avatar asked Oct 02 '22 21:10

sbonami


1 Answers

You have shot yourself in the face.

executeFetchRequest:error: creates a separate child context on which it does some work (while the parent's queue is blocked). This work involves synchronously dispatching work to the parent's queue (via insertOrUpdateObjects:).

This is because NSManagedObjectContext -existingObjectWithId: with nested contexts dispatches to the parent's queue to fulfill objects faulted in to the parent context. Unfortunately you've already blocked the parent's queue with your performBlockAndWait on the child context.

A great sadness ensues.


Edit: Thoughts on a possible solution

The problem here is caused by the use of nested contexts with different queues. I'm not sure I understand the motivation for using a nested context in this situation unless the provided context is NSMainQueueConcurrencyType.

Even then, forcing fetch work off the calling context's queue is hazardous, since any existing objects in the fetch will fall victim to this problem if they are faulted (as is being done here).

It is possible that the AFIncrementalStore somehow guarantees graph isolation in this situation. I found this issue filed against AFNetwork:

https://github.com/AFNetworking/AFIncrementalStore/commit/1f822279e6a7096327ae56a2f65ce8e2ff36da83

It is suspiciously similar in that a retain cycle prevented an object from being deallocated, thereby causing it to permanently exist in the parent context and deadlock trying to fault.

like image 174
ImHuntingWabbits Avatar answered Oct 13 '22 10:10

ImHuntingWabbits