Guys,
I've spent some more time with the infamous RequestQueue failure and can
confirm that Craig's comment below really describes the cause of the
spurious failures:
> I think I've figured out what's wrong, but not how to fix
> it. If you turn on debug in log4j, it turns out that
> "thread-4" is getting started before "thread-3", or rather,
> the particulars of timing means that thread-4 gets a go at
> executing before thread-3. For a failed test, the following
> (..)
> So, I *think* I know the fix, but not how to do it. After
> starting thread-3, the test needs to wait for that thread to
> be properly enqueued (loop waiting for
> RequestQueue.getSize() to return >0 maybe?).
Yes, this will stop the test from failing and is a good quick fix for both
testQueueFull() and testWaitTimedOut(). I added the following to all tests
after the first thread start():
while (testCase1.getQueue().getSize() == 0) {
Thread.yield(); // same as sleep(reallySmallAmount)
}
and ran everything several hundred thousand times now without a single
failure. In order to fix the test this might really be the quickest and
safest solution. Unfortunately I don't think it solves the root of the
problem. :(
IMHO everything should work without this manual caretaking - what if I
really want to start() a couple of threads in quick succession and the
queue is full? The current enqueueThread() method IMHO does two unrelated
things (accepting/rejecting initial requests & synchronizing) so that got
me thinking.
I tried to redesign the threads' start() method and the dequeue handling
in RequestQueue.enqueueThread() to better handle the initial
synchronization by splitting up enqueueThread() between both
synchronized(..) blocks: the first one went into a separate
getRequestDequeue(String threadName) method, which will return a dequeue
token with initial ENQUEUED status (new) or the usual QUEUE_FULL
otherwise. enqueueThread() gets the dequeue to wait for as parameter. In
the threads' run() method the dequeue is obtained by non-blockingly
getting it from the queue, and enqueueThread() is subsequently only called
if the returned dequeue isEnqueued(), otherwise the method returns without
doing anything else. This prevents waiting for nonexisting/lingering
threads and 'gate crashing' due to successive start()s and IMHO is more in
line with regular token handling. Unfortunately it also changes the
semantics of some of the other parts of the tests (result null/!null etc.)
or introduce yet another race and therefore might need some more thinking
through; comments very welcome. Maybe it's a dumb idea and I missed
something essential.
So, for a quick fix the manual waiting is IMHO OK and should be applied
ASAP since the occasionally failing test really does not build confidence.
all IMHO :)
Holger
This archive was generated by hypermail 2.0.0 : Mon Dec 16 2002 - 16:25:46 EST