adam-roth / coredata-threadsafe

A thread-safe extension to Core Data that provides drop-in replacements for the standard (non-thread-safe) classes.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

The follow-up to the SO question

stanislaw opened this issue · comments

I've just got your response on this question and decided to ask my further question here, because it is about the possible usage of your extension: http://stackoverflow.com/questions/12790923/get-a-number-of-resources-asynchronously-and-asynchronously-save-them-to-a-dat

I did read a FAQ on the README page here. I understand your points there, the only question I have being a newbie iOS dev, is how numerous threads could operate on one managed context even subclassed from your extension class?

For example, in my thread I declare managedObjectContext to point on this moc shared instance and after having some operations done I call managedObjectContext save:&error - do I understand right that this will save all temporary data and operations that are there, even the ones which were done by the other threads? Thinking about this I've decided to each time create a new moc (each pointing to the shared instance of persistent store), which led me to the original question - each moc in this case "should be aware of the others".

I hope, I described my points and related question clear here.

Thanks.

To make it even more clear I'll provide concrete example (it is from SO question):

In the same time I create a new Category entity with some fields in one thread and in another thread I create exactly the same Category entity aiming to be the same Category object like the first thread has.

One thread wins calling [ThreadSavePoweredManagedContext save:&error], but then before the actual record is appeared in the PersistentStore, the second does call the save too. The question is: how to prevent the duplication of records in 'categories' table?

Response to first post:

Yes, when you call 'save' on the context it will save the current state.
That will include anything that has been inserted to the context, and any
changes made to entities associated with the context.

Depending upon what your exact concerns are with respect to possibly
issuing a 'save' while another thread is in between two distinct but
related database operations, there are some approaches which might be
simpler than having a separate context for each request. I assume your
primary concern is visibility of the incomplete changes, since with the
thread-safe context you will still ultimately end up with a
complete/consistent database once all of the async calls have completed
processing and invoked 'save', whether or not some of the saves were
invoked at sub-optimal moments.

If you're mostly worried about having incomplete changes show up in your
application interface, then you can use two contexts, one for the
interface, and one for receiving all of the async updates. You can
complete your changes in the async context, and the merge it into your
interface context (or swap their positions so that the async context
becomes the interface context and the interface context becomes the new
async buffer for the next round of updates).

Another possible approach, instead of calling 'save' after each async
response, is to track how many async calls are still in flight and only
call 'save' when that number equals 0. Under this approach you'd remove
the possibility of having 'save' called while another thread was in-between
operations, and your context data should always be complete/consistent.
This should work with a single context or with the dual-context approach
described above, and it should be a lot more sane than giving every async
request its own context and trying to make each one aware of all the others.

On Tue, Oct 9, 2012 at 10:54 AM, Stanislaw Pankevich <
notifications@github.com> wrote:

I've just got your response on this question and decided to ask my further
question here, because it is about the possible usage of your extension:
http://stackoverflow.com/questions/12790923/get-a-number-of-resources-asynchronously-and-asynchronously-save-them-to-a-dat

I did read a FAQ on the README page here. I understand your points there,
the only question I have being a newbie iOS dev, is how numerous threads
could operate on one managed context even subclassed from your extension
class?

For example, in my thread I declare managedObjectContext to point on this
moc shared instance and after having some operations done I call managedObjectContext
save:&error - do I understand right that this will save all temporary
data and operations that are there, even the ones which were done by the
other threads? Thinking about this I've decided to each time create a new
moc (each pointing to the shared instance of persistent store), which led
me to the original question - each moc in this case "should be aware about
the others".

I hope, I described my points and related question clear here.

Thanks.


Reply to this email directly or view it on GitHubhttps://github.com//issues/1.

Response to the second post:

That sounds more like an application-level synchronization issue than a
data-model level one. Why do you end up with two threads trying to create
the same Category? Can you modify the API that is synchronizing this data
so that all of the Categories you'll need are returned first, in a separate
list from whatever other data references them (I assume your code is
creating a new Category whenever it finds an entity that references a
Category that does not appear to be in the context yet)?

If you can't do that, then you'll need to manually serialize the Category
creation (so instead of creating the Category as part of the async handler,
post a call to something like [CategoryUtil createCategory:], and implement
that method so that it 1) is synchronized using an @synchronized{} block,
2) checks first to see if the Category has already been created, and 3)
returns the existing Category if it finds one or otherwise the new Category
that it creates). Unfortunately having a thread-safe context can't help you if
your application is allowing two threads to be spun up that each try to
create the same thing at the same time. It's still the application's
responsibility to make sure that what it does with the context doesn't
violate that data model's basic consistency constraints.

On Tue, Oct 9, 2012 at 11:50 AM, Stanislaw Pankevich <
notifications@github.com> wrote:

To make it even more clear I'll provide concrete example (it is from SO
question):

In the same time I create a new Category entity with some fields in one
thread and in another thread I create exactly the same Category entity
aiming to be the same Category object like the first thread has.

One thread wins calling [ThreadSavePoweredManagedContext save:&error], but
then while the actual record is appeared in the PersistentStore, the second
does call the save too. The question is: how to prevent the duplication
of records in 'categories' table?


Reply to this email directly or view it on GitHubhttps://github.com//issues/1#issuecomment-9246507.

Thanks really for thorough answers.

Actually, I understand that my SO question and this follow-up could be divided into two separate topics:

  1. How to prevent duplication of records if two separate threads are trying to save the same element into the database.

I thought too about pre-fetching Categories in isolation to prevent this issue. I knew I could do it in this particular case, but I have still decided to fetch places associated categories by demand: I looked through your code and discovered @synchronized{} block usage (it is in your answer also) - using it this problem transforms into a uniqueness validation problem, which I understand how to handle. Your answers confirmed my assumptions, thanks!

My intuition tells me it is very interesting pattern (when this conflict could not be avoided by "concerns isolation") which I should know how to resolve because I will probably meet it many times in the nearest future when developing my app (promising to be rather complex).

  1. [Generalized and abstracted from this issue] How to reuse one shared managed object context beetween threads, when each thread could be working with the data not related to the data in other given thread.

For example, one thread has prepared Place entity and is doing some processing on it (filling particular fields and their calculation takes time) and the other - Category entity; the second "Category" thread wants to persist Category entity with save:&error causing Place entity from the first thread to be saved also while it didn't finished its processing job. Clear? Do I right that this will cause problems when using one shared moc?

Thanks again!

Regarding the second one, I've written a question on SO and got the answer: http://stackoverflow.com/questions/12812846/is-it-possible-to-reuse-one-shared-managed-object-context-beetween-threads-when.

I am closing this. Sorry for making the noise asking the questions, mostly irrelevant to your project.

Thanks for you answers.