I have a server app that responds to network requests, making use of a Core Data database to serve responses. Some requests update the database. I have chosen to allow requests to arrive on multiple threads, and intend for these threads to use Core Data directly.

In keeping with Core Data's doc related to threading, I have one Managed Object Context per thread, and these all share a common Persistent Store Coordinator that is managing a SQLite data file. It's my understanding that this scenario is an acceptable configuration, indeed it appears in the Core Data notes on threading as the 'preferred option' (q.v. http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/CoreData/Articles/cdMultiThreading.html ).

OK, here comes the problem (!)...
One type of request can change the name of an object. The handler for this request (using its thread's own MOC): 1. Fetches the required object by persistent ID (i.e. stringified NSManagedObjectID).
2. Changes the value of the 'name' property on the fetched object
3. Commits the change by calling 'save' on the MOC

Unfortunately, while this works some of the time, I have a situation where a subsequent other request (possibly on another thread) sees the old name of this object. This request gets 'all' the entities of this type and sends properties (such as name) back.

I'm pretty sure my MOC handling per thread is good. I be checking that, but lets assume this is the case.

I have a number of questions arising from both the Core Data docs, and my own ignorance as to what exactly Core Data will be doing in a "MOC- per-thread, shared coordinator" configuration.

1. Sharing the Coordinator
This seems to be 'encouraged' (or at least permitted as the 'preferred option'). However, there are some passages in the docs that, while not exactly contradictory, cause me to wonder what the 'best' thing to do is:

...
A persistent store coordinator provides to its managed object contexts the façade of one virtual store. For completely concurrent operations you need a different coordinator for each thread.

...

There are three patterns you can adopt to support multi-threading in a Core Data application; in order of preference they are:

Create a separate managed object context for each thread and share a single persistent store coordinator. If you need to “pass” managed objects between threads, you just pass their object IDs.

If you want to aggregate a number of operations in one context together as if a virtual single transaction, you can lock the persistent store coordinator to prevent other managed object contexts using the persistent store coordinator over the scope of several operations.

...

Should I have a PSC per thread too? If so, will they behave correctly talking to the same SQLite data file? With a shared PSC, should I lock this whenever a write is being performed (at least)?


2. Locking the MOC
There is talk that locking the MOC, even one that is private to a thread, will engender 'thread friendly' behaviour in the PSC:

...
Typically you lock the context or coordinator using tryLock or lock. If you do this, the framework will ensure that what it does behind the scenes is also thread-safe. For example, if you create one context per thread, but all pointing to the same persistent store coordinator, Core Data takes care of accessing the coordinator in a thread-safe way (NSManagedObjectContext's lock and unlockmethods handle recursivity).
...

Should I lock the MOC, or just the PSC (see 1)?
Would this really fix my experience of changes not appearing on other threads anyway?


3. Changes propagating back to other MOCs looking at the same data
I assume Core Data is smart enough to realise that an attribute value change in a Managed Object cached in one thread's MOC, should be reflected on (or at least invalidate old data in) another Managed Object instance representing the same data in another MOC. At the very least, I think I'd expect a new fetch request that has this object in the result set would cause data changed in the persistent store to show up properly on the object.

The best guess I have right now is that some kind of MOC-related caching is causing problems. Both queries have separate MOCs, and do fresh look-ups when a request comes in, yet (apparently) a successfully saved change in one MOC (the method succeeds without error) is not reflected in a different MOC. There is actually no system pressure when I'm experiencing the problem at the moment, I'm the only user although my serial requests are being handled by different threads (ergo MOCs).

Is there anything that comes to mind that I'm apparently not doing, which would be needed for states cached in different MOCs to be properly synchronised?


Well, thanks if you're taken the time to read that little lot.
If you have any insights too I'd be obliged!


Cheers

-- Luke






_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to