Re: [ cayenne-Bugs-646399 ] Spurious failure of RequestQueueTst

From: Holger Hoffstätte (holge..izards.de)
Date: Mon Dec 16 2002 - 16:25:26 EST

  • Next message: Craig Miskell: "Re: [ cayenne-Bugs-646399 ] Spurious failure of RequestQueueTst"

    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