re: Core Data threading fun
re: Core Data threading fun
- Subject: re: Core Data threading fun
- From: Ben Trumbull <email@hidden>
- Date: Mon, 21 Sep 2009 17:10:12 -0700
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).
Why stringify it ? NSManagedObjectIDs are immutable and you can just
pass them between threads.
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.
You can merge the changes into that context explicitly, or refetch the
objects.
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)?
Per-thread PSCs doesn't sound like what you want. You probably want
the simpler shared PSC configuration for now. When you share a PSC
between threads, the key point is to lock it whenever you message that
PSC directly yourself. Typically, that's adding and removing
persistent stores. It's easier to do that at init time, and leave the
configuration stack after you start spawning threads. Core Data
assumes responsibility for locking the PSC if we ever send ObjC
messages to it.
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?
No, if you find yourself locking MOCs, you're almost certainly doing
something wrong.
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.
We don't automate this step, although there is API to assist you. We
try as much as possible to never change the state of your objects out
from underneath you (e.g. push state). The reason for that is how
complex things become when that local MOC has pending edits. Do we
overwrite it out from underneath you ? Or not update it, but update
other unchanged objects (seemingly randomly). There isn't a clear
paradigm for coordinating these kinds of push changes between the
framework and your code. So instead we follow something like a
principle of least surprise mates with lesser evil.
Basically, Core Data uses the poll model. State may change, but only
because you did something to ask us to do that. Like refetch the
objects, use a staleness interval, or call -mergeChanges...
- Ben
_______________________________________________
Cocoa-dev mailing list (email@hidden)
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:
This email sent to email@hidden