Re: Snapshot problems - Solved, sort of
Re: Snapshot problems - Solved, sort of
- Subject: Re: Snapshot problems - Solved, sort of
- From: Chuck Hill <email@hidden>
- Date: Mon, 23 Apr 2007 10:24:23 -0700
On Apr 22, 2007, at 10:16 AM, Steven Mark McCraw wrote:
Are other people using nested editing contexts?
Yes, in reasonably heavily used production applications. BUT the
big difference that I see is that you seem to create on per
session. I usually create one per function/page.
This seemed like the way to go to me, too, at first. But then I
read (see link below) that you couldn't reliably lock an editing
context in a page's awake/sleep
EEK! NO! I said I create them per page not IN the page! All EC
handling is centralized. I use the MultiECLockManager, Wonder uses a
different centralized mechanism.
like in session, because those might not always get called with a
one to one correlation (that is, you might somehow have two awake()
invocations or two sleep() invocations in a row). Since attributes
on EOs in that ec will be getting set when the form values are
pulled, I didn't know how to lock correctly if I couldn't lock/
unlock in awake/sleep, so I moved all that business to session, as
the post suggested.
from http://en.wikibooks.org/wiki/Programming:WebObjects/EOF/
Using_EOF/Context_and_Database_Locking:
"In general you are better to lock EC's in the session (if you've
got one) rather than the component"
and
"One thing to watch out for is that EC locking on the page's awake
() and sleep() doesn't really work, because awake may be called
more often than sleep."
So how do you get around the locking issues at the page level? Do
you just use the project wonder classes, which appear to lock
everything for you?
I finally found a workaround that works, taken from a post in
like 2002. In Application's constructor, I call
EODatabase.disableSnapshotRefCounting();
HACK! :-)
Agreed :) But why does it work?
Because EOF retains the snapshot of the object that it thinks is
deleted.
If the application runs great without snapshot reference
counting, it tells me that the problem lies in the way EODatabase
is managing its snapshot dictionary. Specifically in this
instance, it seems to be decrementing the count of things pointing
to each entry prematurely, leading it to prematurely delete the
dictionary entry.
It seemed to me more like it has associated two EOs with the same
snapshot.
So what are the possible causes of EOF making this mistake (or
what is it that I'm doing that prompts EOF to make this mistake, if
you prefer ;))?
Oh, I do prefer. :-) Is there any chance that one (or more) or your
attribute or relationship names is a name that EOF uses (e.g. the
name of a method in the public or private API)?
I guess that's what this whole thread has been about. Here's the
list of things I know about:
Don't set EO properties in the EO constructor -- use
awakeFromInsertion(...) or awakeFromFetch(...) instead : I've
examined each and every EO constructor in all my frameworks at
least 4 times now. Most either don't exist, or just call super(),
and the rest (one or two) only call super() and set a couple of non-
modeled local attributes.
Don't do anything to an EO before inserting it into an editing
context. Always insert EOs into ECs immediately. See rule #1: I
made a comprehensive list of all my EO classes (about 90) and then
searched all applications and frameworks for "new X()" where X is
the name of each EO. There are no results for any of my EOs
anymore, because they all use EOUtilities.createAndInsertInstance.
There are actually one or two places that I use introspection to
create new EOs ,but in each of those places, they get inserted
immediately after creation. Actually, this is something I've never
heard discussed. Does EOF play nice with introspection? Maybe
that is my problem. I will rewrite that code next...
What does the code look like?
Don't modify any EO properties in validateFor...(...) methods.
Doing this in validateValueForKey(...) is ok as Chuck Hill noted in
the list.: There is only one validateFor method in all of the
frameworks and applications:
public void validateForSave() throws
NSValidation.ValidationException {
super.validateForSave();
if ( supplier() == null ) {
throw new NSValidation.ValidationException( "All inventory
items must have a supplier" );
}
}
If over-riding awakeFromInsertion(...), remember to call ther
superclass implementation. Same with awakeFromFetch(...): This was
the easiest one to verify. Searched all EOs, and for sure they all
call super.awake...
Don't change the behavior of methods that EOF uses. For example, do
not override to-many relationships to return a sorted list of the
related objects. Make another method to do this.: Verified that
this cannot happen by commenting out all overridden methods in
every EO I have, recompiling, rerunning the problematic code, and
getting the same behavior
Don't use mutable classes (e.g. NSMutableArray,
NSMutableDictionary, any other class that can change internal state
after creation) as attributes. If you want this effect, use
immutable classes and provide cover methods to replace the
immutable instance with an updated instance. You and EOF will be
much, much, much happier: Definitely not doing this
Locking problems: I turned on DebugGroupMultithreading in NSLog,
and nothing happened. If I explicity comment out the code which
locks my ECs, I get warnings all over the place, so it looks like
my code is working in that regard.
Does anyone know of any other thing that causes EOF's snapshot
counting to go screwy?
When I get down to names that conflict with EOF, I am scraping the
bottom of the barrel. Next is to try and extract a minimal
reproduction case.
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
_______________________________________________
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