Re: [WORKED AROUND] Re: Bug in client side EOF locking?
Re: [WORKED AROUND] Re: Bug in client side EOF locking?
- Subject: Re: [WORKED AROUND] Re: Bug in client side EOF locking?
- From: Stamenkovic Florijan <email@hidden>
- Date: Fri, 27 Feb 2009 14:53:52 -0400
On Feb 27, 2009, at 14:14, Chuck Hill wrote:
On Feb 27, 2009, at 6:10 AM, Stamenkovic Florijan wrote:
On Feb 26, 2009, at 22:22, Chuck Hill wrote:
<snip>
I am old. My memory is weak. Less snips help.
How? Where?
willRead(), willReadRelationship(Object)
<snip>
Have stack traces?
See below. Sorry about not providing them before, that was silly.
How come this particular exception happens in a multi-threaded
scenario and not in a single threaded scenario?
Hint: more than one thread. :-) Concurrency
woooow, ya think? :-P
Dunno, just a guess. ;-)
(Also note that the lock object is not public, it's lock() and
unlock() methods are exposed through the public API of
EODistributedObjectStore). Assuming that ReenetrantLock is not
buggy, the only way I can imagine to get this exception is doing
the equivalent of:
if(accessingThreadCount > 1) // super-evil
eoDistributedObjectStoreInstance.unlock();
If anyone else knows another way, please let me know. I can't
think of one, and am amazed to see it happening.
In the meanwhile, I admit defeat, and go back to single threaded
EOF operations.
An exception resulting in an unlock upon which the other thread
locks it and then a finally block unlocking it again in the first
thread?
Interesting idea, however... Let's say that this exception you
mention gets thrown in a single threaded scenario. It would still
result in more calls to unlock() then to lock(). The
IllegalMonitorStateException would be thrown at either of the last
two unlock() calls. So, we can assume it does not happen in a
single threaded scenario, since the monitor exception is not thrown.
You would get a different error (attempt to unlock an unlocked
lock?) if ReentrantLock even throws on that condition.
It does, and it actually throws at exactly the same point. The same
line throws an exception for:
1. an unlock() without a lock()
2. one unlock() too many
3. unlock() from a thread when another thread owns the lock
Which means that it only happens in a multi threaded scenario. So,
it still falls under the category of the idiotic idiom:
if(accessingThreadCount > 1)
throw SomeException();
Or not?
I still rather doubt that. :-)
Me too... It is really weird. I just can't find any other explanation
for what I see. I've been thinking about this on and off for weeks,
and the more I do, the more stupefied I am.
Output logged from my EC's lockObjectStore() and
unlockObjectStore() methods. There is only one EC.
...
will lock: JBND worker thread
did lock: JBND worker thread
will unlock: JBND worker thread
did unlock: JBND worker thread
will lock: AWT-EventQueue-0
did lock: AWT-EventQueue-0
will lock: JBND worker thread
did lock: JBND worker thread
will unlock: AWT-EventQueue-0
did unlock: AWT-EventQueue-0
will unlock: JBND worker thread
I am not sure what that means.
Well, if the above output can be trusted, it means that an unlock()
occurs somewhere in the bowels of EOF, that is not preceded with a
lock(). Because the EC locks the object store for one thread,
immediately followed by a lock for the second thread.
Also be careful of messages output by a log mechanism in a MT
environment. NSLog in particular will show things out of exact order.
Hm, hadn't considered that... I did it with System.out.println(...)
though, and PrintStream does synchronize... Hopefully that's a tad
more reliable. Still, I see your point. Possibly the above output is
crap.
Stack traces... Got them by putting an exception breakpoint for
IllegalMonitorStateException. The breakpoint set to suspend the VM.
Traces are from the only two threads that do EOF work:
Thread [JBND worker thread] (Suspended (exception
IllegalMonitorStateException))
ReentrantLock$NonfairSync(ReentrantLock$Sync).tryRelease(int)
line: 125
ReentrantLock$NonfairSync(AbstractQueuedSynchronizer).release(int)
line: 1137
ReentrantLock.unlock() line: 431
EODistributedObjectStore.unlock() line: 107
JCEC(EOEditingContext).unlockObjectStore() line: 4668
JCEC.unlockObjectStore() line: 283
User(EOFDataObject).willRead() line: 744
_EOMutableKnownKeyDictionary$Initializer
$_GenericRecordBinding.valueInObject(Object) line: 570
User(EOCustomObject).storedValueForKey(String) line: 1634
User(_User).password() line: 77
...
Thread [AWT-EventQueue-0] (Suspended)
JCEC.lockObjectStore() line: 274
Account(EOFDataObject).willRead() line: 742
_EOMutableKnownKeyDictionary$Initializer
$_GenericRecordBinding.valueInObject(Object) line: 570
Account(EOCustomObject).storedValueForKey(String) line: 1634
Account(_Account).number() line: 94
GeneratedMethodAccessor50.invoke(Object, Object[]) line: not
available
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
Method.invoke(Object, Object...) line: 585
NSKeyValueCoding$ValueAccessor$1.methodValue(Object, Method) line:
636
NSKeyValueCoding$_MethodBinding.valueInObject(Object) line: 1134
Account(EOCustomObject).valueForKey(String) line: 1498
Account(EOFDataObject).valueForKey(String) line: 714
Account(EOFDataObject).get(String) line: 212
...
That is a lot of locks. Is there any chance that the order of
locking and unlocking is different somewhere? Not sure how that
would cause this error...
No idea. However, it is not my code itself, since my added locking is
super simple. And again the question: if the order is screwed up, why
is that not observable in a single-treaded scenario? As mentioned
above, ReentrantLock will fail loudly if anything is out of order.
Well, I guess in the end it comes down to: it's out of my hands.
F
_______________________________________________
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