Re: Exception in saveChanges(): rowDiffsForAttributes - snapshot does not contain value
Re: Exception in saveChanges(): rowDiffsForAttributes - snapshot does not contain value
- Subject: Re: Exception in saveChanges(): rowDiffsForAttributes - snapshot does not contain value
- From: Chuck Hill <email@hidden>
- Date: Wed, 21 Feb 2007 19:25:32 -0800
Hi Mike,
On Feb 21, 2007, at 5:54 PM, Mike Schrag wrote:
Every time I've ever seen this it's either 1) touching an unlocked
EC, 2) touching an unlocked EODatabaseContext (directly -- i.e. not
through a locked EC), or 3) you just straight up invalidated that
EO while something was in the middle of an update.
If someone asked me this question, that is exactly what I would tell
them. If there is something wrong in my code (and that is usually
what it is), I am not seeing it yet.
Interestingly, invaliding the EO seems to fix it. The unlock()
followed by a lock() fixed it in my tests when I ran them through the
slower test runner. It helped, but did not totally eliminate the
problem once I started running them from the command line. When I
saw that, my next odious hack was to catch the IllegalStateException,
call
editingContext().invalidateObjectsWithGlobalIDs(new NSArray
(eo.globalID()));
and re-try the save. The tests have not failed yet so, at the very
least, this recovers from the problem. That said, I am less than
thrilled with this as a solution. I had to go wash my hands after do
that. Twice.
You can listen for the objectschangedinstore notification and stack
dump when you see an invalidate of a DownloadLog globalid.
Logging out notifications is probably what will provide the vital clues.
In your background thread, you mention locking and unlocking -- I
would verify that every time you touch that thing that it's locked
(though I suspect that's preaching to the choir with you).
Yes, but even I make mistakes. I will once again double check the
code.
I'm not exactly sure why you're seeing snapshots invaliated,
because refreshing refetched objects, IIRC, does a merge against
the existing snapshot. I don't think it invalidates.
I don't know that I am seeing snapshots invalidated. When this
happens, I can log out editingContext().committedSnapshotForObject
(eo) and see that the values are not null. But the snapshot that the
EODatabaseOperation gets is empty. At this point I am only guessing
at how that might be happening.
As I'm writing this, I recall there is a patch down in Wonder's
ERXEC that claims to fix a race condition in saveChanges resulting
from it not properly executing notifications that occured DURING
the saveChanges. I dug through EOF and it appears (in newer EOF
versions at least) that this doesn't actually happen anymore (it
looks like they enqueue notifications that occur during save and
execute them when it's done), but you never know. Something to
maybe look for.
I've been bit by that before. I am pretty sure this is not that
bug. I have logging that should fire if that happens.
Thanks for the ideas. I think it might be time to see if I can make
a minimal reproduction case.
Chuck
ms
On Feb 21, 2007, at 7:57 PM, Chuck Hill wrote:
Darn. That only "fixed" it in one batch of tests. I have another
that it still does this in.
Sigh. Ideas? Anyone?
Chuck
On Feb 21, 2007, at 3:04 PM, Chuck Hill wrote:
Hi,
Some of you will recognize this extremely fun exception:
java.lang.IllegalStateException: rowDiffsForAttributes: snapshot
in com.webobjects.eoaccess.EODatabaseOperation {
_dbSnapshot = {};
...
this = "<com.foo.bar.DownloadLog a849b0 _EOIntegralKeyGlobalID
[DownloadLog (java.lang.Long)0]>"; }";
_globalID = _EOIntegralKeyGlobalID[DownloadLog (java.lang.Long)0];
_databaseOperator = "EODatabaseUpdateOperator"; }
does not contain value for attribute named downloadDate with
snapshot key: downloadDate
The stack trace is:
at
com.webobjects.eoaccess.EODatabaseOperation.rowDiffsForAttributes
(EODatabaseOperation.java:338)
at
com.webobjects.eoaccess.EODatabaseContext.createAdaptorOperationsFor
DatabaseOperationAttributes(EODatabaseContext.java:5373)
at
com.webobjects.eoaccess.EODatabaseContext.createAdaptorOperationsFor
DatabaseOperation(EODatabaseContext.java:5548)
at com.webobjects.eoaccess.EODatabaseContext.performChanges
(EODatabaseContext.java:6365)
at
com.webobjects.eocontrol.EOObjectStoreCoordinator.saveChangesInEditi
ngContext(EOObjectStoreCoordinator.java:415)
at com.webobjects.eocontrol.EOEditingContext.saveChanges
(EOEditingContext.java:3226)
at net.global_village.eofextensions.ForgetfulEC.saveChanges
(ForgetfulEC.java:54)
at net.global_village.eofvalidation.EOEditingContext.saveChanges
(EOEditingContext.java:126)
at
net.global_village.eofvalidation.NotifyingEditingContext.saveChanges
(NotifyingEditingContext.java:159)
The exception is correct, the snapshot _dbSnapshot = {}; does not
contain any values, let alone the one it is looking for. I am
not completely sure of how this happens. It is not consistent so
I believe it to be caused by concurrent threads sending EOF
notifications interacting with the locked / unlocked state of
editing contexts.
The situation that I have that causes this exception is this: I
have a page that starts an import process. It spins off a thread
that handles the actual import. This thread has its own EC. The
first thing it does is to create a new DownloadLog to record the
start / status of the import process. While it is processing, it
periodically unlocks and re-locks the EC and does a refreshing
fetch on the download log so that it can see changes made in
other editing contexts.
Once this thread is started, and concurrent with its processing,
the app goes to a page that monitors all the download logs. This
was built using the AjaxGrid and refreshes every 30 seconds. At
each refresh it does a refreshing fetch. Of course, its EC is
unlocked between requests. It has a link to abort the import by
writing to the download log, though that is not being used when
this exception occurs.
Periodically the download processing thread will throw the above
exception while saving an update to the download log. My guess
is that the refreshing fetch is invalidating the snapshot that
the EC was referring to and it gets a null / empty dictionary for
it as it is still locked.
I fixed this (or at least I can't reproduce it anymore) by doing
ec.unlock(); ec.lock(); immediately before ec.saveChanges();. My
guess is that this allows the snapshot to get updated. I suspect
there is still a race condition in there where the a refreshing
fetch is done on the download load while saveChanges() is in
progress.
Does anyone know anything more about this or can you shed light
on what is happening and how you worked around it?
Cheers,
Chuck
--
Practical WebObjects - for developers who want to increase their
overall knowledge of WebObjects or who are trying to solve
specific problems.
http://www.global-village.net/products/practical_webobjects
--
Practical WebObjects - for developers who want to increase their
overall knowledge of WebObjects or who are trying to solve
specific problems.
http://www.global-village.net/products/practical_webobjects
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Webobjects-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
40mdimension.com
This email sent to email@hidden
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Webobjects-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
40global-village.net
This email sent to email@hidden
--
Practical WebObjects - for developers who want to increase their
overall knowledge of WebObjects or who are trying to solve specific
problems.
http://www.global-village.net/products/practical_webobjects
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Webobjects-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden