Re: Core Data threading fun
Re: Core Data threading fun
- Subject: Re: Core Data threading fun
- From: Luke Evans <email@hidden>
- Date: Mon, 21 Sep 2009 21:44:50 -0700
Thanks Ben.
Light testing suggests that I now have things working with -
mergeChanges (modulo exactly which merge policy I should be using).
Your notes provide some extra insight into some of the comments in the
docs though (e.g. when you should lock the PSC).
-- Luke
On 2009-09-21, at 5:10 PM, Ben Trumbull wrote:
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