[jboss-svn-commits] JBL Code SVN: r28756 - in labs/jbosstm/trunk: ArjunaCore/arjuna/tests/byteman-scripts and 3 other directories.
jboss-svn-commits at lists.jboss.org
jboss-svn-commits at lists.jboss.org
Mon Aug 3 11:21:05 EDT 2009
Author: adinn
Date: 2009-08-03 11:21:05 -0400 (Mon, 03 Aug 2009)
New Revision: 28756
Modified:
labs/jbosstm/trunk/ArjunaCore/arjuna/build.xml
labs/jbosstm/trunk/ArjunaCore/arjuna/tests/byteman-scripts/reaper.txt
labs/jbosstm/trunk/ArjunaCore/arjuna/tests/byteman-scripts/recovery.txt
labs/jbosstm/trunk/ArjunaCore/arjuna/tests/classes/com/hp/mwtests/ts/arjuna/reaper/ReaperTestCase.java
labs/jbosstm/trunk/ArjunaCore/arjuna/tests/classes/com/hp/mwtests/ts/arjuna/reaper/ReaperTestCase2.java
labs/jbosstm/trunk/ArjunaCore/arjuna/tests/classes/com/hp/mwtests/ts/arjuna/recovery/RecoveryManagerStartStopTest.java
labs/jbosstm/trunk/ext/Readme
labs/jbosstm/trunk/ext/byteman.jar
Log:
added back reaper test cases 1 and 2 using byteman rules to single step the reaper and reaper worker threads. moved helper code used by recovery manager start stop test to the default helper n.b. needs byteman 1.0.3 snapshot lib included in ext -- fixes for JBTM-576
Modified: labs/jbosstm/trunk/ArjunaCore/arjuna/build.xml
===================================================================
--- labs/jbosstm/trunk/ArjunaCore/arjuna/build.xml 2009-08-03 14:57:18 UTC (rev 28755)
+++ labs/jbosstm/trunk/ArjunaCore/arjuna/build.xml 2009-08-03 15:21:05 UTC (rev 28756)
@@ -65,13 +65,14 @@
<!-- LogStressTest2 takes too long - needs moving to /qa -->
<exclude name="**/LogStressTest2.java"/>
<!-- ReaperTestCase2 and 3 have timing issues - adinn to fix - JBTM-567 -->
- <exclude name="**/ReaperTestCase2.java"/>
<exclude name="**/ReaperTestCase3.java"/>
<!-- tests which have been modified to run using byteman scripts -->
<exclude name="**/reaper/ReaperMonitorTest.java"/>
+ <exclude name="**/ReaperTestCase2.java"/>
<exclude name="**/reaper/ReaperTestCase.java"/>
<exclude name="**/objectstore/LogStoreRecoveryTest.java"/>
<exclude name="**/objectstore/LogStoreTest2.java"/>
+ <exclude name="**/recovery/RecoveryManagerStartStopTest.java"/>
</fileset>
</tests>
</run.tests.macro>
@@ -81,6 +82,7 @@
<fileset dir="tests/classes">
<include name="**/reaper/ReaperMonitorTest.java"/>
<include name="**/reaper/ReaperTestCase.java"/>
+ <include name="**/reaper/ReaperTestCase2.java"/>
</fileset>
</tests>
<!--
@@ -103,7 +105,7 @@
</run.tests.macro>
<run.tests.macro script="recovery.txt">
<tests>
- <fileset dir="tests/classes" includes="**/RecoveryManagerStartStopTest.java"/>
+ <fileset dir="tests/classes" includes="**/recovery/RecoveryManagerStartStopTest.java"/>
</tests>
</run.tests.macro>
</target>
Modified: labs/jbosstm/trunk/ArjunaCore/arjuna/tests/byteman-scripts/reaper.txt
===================================================================
--- labs/jbosstm/trunk/ArjunaCore/arjuna/tests/byteman-scripts/reaper.txt 2009-08-03 14:57:18 UTC (rev 28755)
+++ labs/jbosstm/trunk/ArjunaCore/arjuna/tests/byteman-scripts/reaper.txt 2009-08-03 15:21:05 UTC (rev 28756)
@@ -134,7 +134,7 @@
rendezvous("reaperworker1")
ENDRULE
-# rendezvous before marking an element as CANCELLED
+# rendezvous before marking an element as CANCEL
RULE pause transaction reaper worker 2
CLASS com.arjuna.ats.arjuna.coordinator.TransactionReaper
@@ -177,6 +177,29 @@
ENDRULE
#########################################################################
+# rules to track and flag actions by the reaper and reaper worker
+
+RULE ReaperTestCase2 flag interrupt
+CLASS com.arjuna.ats.arjuna.coordinator.TransactionReaper
+METHOD check
+AFTER CALL interrupt
+BIND NOTHING
+IF TRUE
+DO debug("reaper called interrupt on " + $e),
+ flag("interrupted")
+ENDRULE
+
+RULE ReaperTestCase2 flag zombie
+CLASS com.arjuna.ats.arjuna.coordinator.TransactionReaper
+METHOD check
+AFTER WRITE _zombieCount
+BIND NOTHING
+IF TRUE
+DO debug("reaper incremented zombie count " + $e),
+ flag("zombied")
+ENDRULE
+
+#########################################################################
#
# rules appropriate to specific tests
@@ -224,6 +247,15 @@
DO createRendezvous($1, 2, $2)
ENDRULE
+RULE ReaperTestCase disable trigger rendezvous
+CLASS com.hp.mwtests.ts.arjuna.reaper.ReaperTestCase
+METHOD disableRendezvous(Object)
+AT ENTRY
+BIND NOTHING
+IF TRUE
+DO deleteRendezvous($1, 2)
+ENDRULE
+
# if the supplied string matches a known rendezvous then trigger it
RULE ReaperTestCase rendezvous
@@ -277,3 +309,73 @@
# IF TRUE
# DO debug("adding reapable " + $e)
# ENDRULE
+
+#########################################################################
+# ReaperTestCase2 wants to ensure that the reaper is single stepped
+# through processing of inserted reaper elements
+#
+
+RULE ReaperTestCase2 enable trigger rendezvous
+CLASS com.hp.mwtests.ts.arjuna.reaper.ReaperTestCase2
+METHOD enableRendezvous(Object, boolean)
+AT ENTRY
+BIND NOTHING
+IF TRUE
+DO createRendezvous($1, 2, $2)
+ENDRULE
+
+RULE ReaperTestCase2 disable trigger rendezvous
+CLASS com.hp.mwtests.ts.arjuna.reaper.ReaperTestCase2
+METHOD disableRendezvous(Object)
+AT ENTRY
+BIND NOTHING
+IF TRUE
+DO deleteRendezvous($1, 2)
+ENDRULE
+
+# if the supplied string matches a known rendezvous then trigger it
+
+RULE ReaperTestCase2 rendezvous
+CLASS com.hp.mwtests.ts.arjuna.reaper.ReaperTestCase2
+METHOD triggerRendezvous(Object)
+AT ENTRY
+BIND thread = Thread.currentThread()
+IF isRendezvous($1, 2)
+DO debug("" + $1 + " " + thread),
+ rendezvous($1),
+ return
+ENDRULE
+
+RULE ReaperTestCase2 rendezvous 2
+CLASS com.hp.mwtests.ts.arjuna.reaper.ReaperTestCase2
+METHOD triggerRendezvous(Object)
+AT ENTRY
+BIND NOTHING
+IF NOT isRendezvous($1, 2)
+DO throw RuntimeException("invalid rendezvous for trigger " + $1)
+ENDRULE
+
+# trigger a delay
+
+RULE ReaperTestCase2 wait
+CLASS com.hp.mwtests.ts.arjuna.reaper.ReaperTestCase2
+METHOD triggerWait(int)
+AT ENTRY
+BIND NOTHING
+IF TRUE
+DO debug("wait " + $1),
+ delay($1),
+ return
+ENDRULE
+
+RULE ReapertestCase2 check and clear
+CLASS com.hp.mwtests.ts.arjuna.reaper.ReaperTestCase2
+METHOD checkAndClearFlag(Object)
+AT ENTRY
+BIND value = flagged($1)
+IF TRUE
+DO debug("setAndClear(" + $1 + ") => " + value),
+ clear($1),
+ return value
+ENDRULE
+
Modified: labs/jbosstm/trunk/ArjunaCore/arjuna/tests/byteman-scripts/recovery.txt
===================================================================
--- labs/jbosstm/trunk/ArjunaCore/arjuna/tests/byteman-scripts/recovery.txt 2009-08-03 14:57:18 UTC (rev 28755)
+++ labs/jbosstm/trunk/ArjunaCore/arjuna/tests/byteman-scripts/recovery.txt 2009-08-03 15:21:05 UTC (rev 28756)
@@ -48,7 +48,6 @@
RULE RecoveryManagerStartStopTest create rendezvous
CLASS com.hp.mwtests.ts.arjuna.recovery.RecoveryManagerStartStopTest
METHOD testStartStop()
-HELPER com.hp.mwtests.ts.arjuna.recovery.RecoveryManagerStartStopTest$JoinHelper
AT ENTRY
BIND NOTHING
IF TRUE
@@ -102,26 +101,15 @@
# threads during normal operation. it avoids doing this because it is waiting in an
# accept and so can only be woken via an interrupt -- a pointless waste of CPU. however for
# testing we want to be sure that the connection thread has actually exited. so we
-# use a rule and rule helper class to join the connection threads from the listener
-# thread. the connection threads register themselves when they run the listener
+# use a joiner to join the connection threads from the listener thread.
+# the connection threads register themselves when they run the listener
# callback by calling the helper method joinEnlist(key). the listener thread joins
# N enlisted threads by calling the helper method joinWait(key, N). The Object
# supplied as key must match.
-#
-# the helper methods may be good candidates for inclusion in the default
-# helper API. for now they are implemented on an inner class of the test
-# class
-#
-# joinEnlist(o) adds the current thread to a set identified by o and returns,
-# allowing the enlisting thread to exit.
-#
-# joinWait(o, n) waits on the set identified by o until it has N members at
-# which point it clears the set and calls join on each of the threads in the set.
RULE listener join wait
CLASS com.arjuna.ats.internal.arjuna.recovery.Listener
METHOD run()
-HELPER com.hp.mwtests.ts.arjuna.recovery.RecoveryManagerStartStopTest$JoinHelper
AT RETURN
BIND NOTHING
IF isJoin("Listener Connection", 2)
@@ -133,7 +121,6 @@
RULE connection join enlist
CLASS com.arjuna.ats.internal.arjuna.recovery.Listener
METHOD removeConnection
-HELPER com.hp.mwtests.ts.arjuna.recovery.RecoveryManagerStartStopTest$JoinHelper
AT RETURN
BIND NOTHING
IF joinEnlist("Listener Connection")
Modified: labs/jbosstm/trunk/ArjunaCore/arjuna/tests/classes/com/hp/mwtests/ts/arjuna/reaper/ReaperTestCase.java
===================================================================
--- labs/jbosstm/trunk/ArjunaCore/arjuna/tests/classes/com/hp/mwtests/ts/arjuna/reaper/ReaperTestCase.java 2009-08-03 14:57:18 UTC (rev 28755)
+++ labs/jbosstm/trunk/ArjunaCore/arjuna/tests/classes/com/hp/mwtests/ts/arjuna/reaper/ReaperTestCase.java 2009-08-03 15:21:05 UTC (rev 28756)
@@ -95,7 +95,7 @@
reaper.insert(reapable, 1); // seconds
reaper.insert(reapable2, 2);
- // enable a repeatable rendezvous before checking the worker queue
+ // enable a repeatable rendezvous before checking the reapable queue
enableRendezvous("reaper1", true);
// enable a repeatable rendezvous before scheduling a reapable in the worker queue for cancellation
enableRendezvous("reaper2", true);
Modified: labs/jbosstm/trunk/ArjunaCore/arjuna/tests/classes/com/hp/mwtests/ts/arjuna/reaper/ReaperTestCase2.java
===================================================================
--- labs/jbosstm/trunk/ArjunaCore/arjuna/tests/classes/com/hp/mwtests/ts/arjuna/reaper/ReaperTestCase2.java 2009-08-03 14:57:18 UTC (rev 28755)
+++ labs/jbosstm/trunk/ArjunaCore/arjuna/tests/classes/com/hp/mwtests/ts/arjuna/reaper/ReaperTestCase2.java 2009-08-03 15:21:05 UTC (rev 28756)
@@ -41,163 +41,372 @@
@Test
public void testReaper() throws Exception
{
- TransactionReaper.create(500);
+ TransactionReaper.create(100);
TransactionReaper reaper = TransactionReaper.transactionReaper();
- // give the reaper worker time to start too
-
- Thread.sleep(1000);
-
// create slow reapables some of which will not respond immediately
// to cancel requests and ensure that they get cancelled
// and that the reaper does not get wedged
- SlowReapable reapable1 = new SlowReapable(new Uid(), 2000, 0, true, true, false);
- SlowReapable reapable2 = new SlowReapable(new Uid(), 0, 0, true, true, false);
- SlowReapable reapable3 = new SlowReapable(new Uid(), 100, 2000, false, true, false);
- SlowReapable reapable4 = new SlowReapable(new Uid(), 1000, 1000, false, false, false);
+ // the rendezvous for the reapables are keyed by the reapable's uid
- // insert reapables so they timeout at 1 second intervals then
- // check progress of cancellations and rollbacks
+ Uid uid1 = new Uid();
+ Uid uid2 = new Uid();
+ Uid uid3 = new Uid();
+ Uid uid4 = new Uid();
+ // reapable1 will return CANCELLED from cancel and will rendezvous inside the cancel call
+ // so we can delay it. prevent_commit should not get called so we don't care about the arguments
+ TestReapable reapable1 = new TestReapable(uid1, true, true, false, false);
+ // reapable2 will return CANCELLED from cancel and will not rendezvous inside the cancel call
+ // prevent_commit should not get called so we don't care about the arguments
+ TestReapable reapable2 = new TestReapable(uid2, true, false, false, false);
+ // reapable3 will return RUNNING from cancel and will rendezvous inside the cancel call
+ // the call will get delayed causing the worker to exit as a zombie
+ // prevent_commit will be called from the reaper thread and will fail but will not rendezvous
+ TestReapable reapable3 = new TestReapable(uid3, false, true, false, false);
+ // reapable4 will return RUNNING from cancel and will not rendezvous inside the cancel call
+ // prevent_commit should get called and should return true without a rendezvous
+ TestReapable reapable4 = new TestReapable(uid4, false, false, true, false);
+
+ // enable a repeatable rendezvous before checking the reapable queue
+ enableRendezvous("reaper1", true);
+ // enable a repeatable rendezvous before processing a timed out reapable
+ // enableRendezvous("reaper2", true);
+ // enable a repeatable rendezvous before scheduling a reapable in the worker queue for cancellation
+ // enableRendezvous("reaper3", true);
+ // enable a repeatable rendezvous before rescheduling a reapable in the worker queue for cancellation
+ // enableRendezvous("reaper4", true);
+ // enable a repeatable rendezvous before interrupting a cancelled reapable
+ // enableRendezvous("reaper5", true);
+ // enable a repeatable rendezvous before marking a worker thread as a zombie
+ // enableRendezvous("reaper6", true);
+ // enable a repeatable rendezvous before marking a reapable as rollback only from the reaper thread
+ // enableRendezvous("reaper7", true);
+ // enable a repeatable rendezvous before checking the worker queue
+ enableRendezvous("reaperworker1", true);
+ // enable a repeatable rendezvous before marking a reapable as cancel
+ // enableRendezvous("reaperworker2", true);
+ // enable a repeatable rendezvous before calling cancel
+ // enableRendezvous("reaperworker3", true);
+ // enable a repeatable rendezvous before marking a reapable as rollback only from the worker thread
+ // enableRendezvous("reaperworker4", true);
+
+ // enable a repeatable rendezvous for each of the test reapables which we have marked to
+ // perform a rendezvous
+
+ enableRendezvous(uid1, true);
+ enableRendezvous(uid3, true);
+
+ // STAGE I
+ // insert two reapables so they timeout at 1 second intervals then stall the first one and
+ // check progress of cancellations and rollbacks for both
+
assertTrue(reaper.insert(reapable1, 1));
- assertTrue(reaper.insert(reapable2, 2));
+ assertTrue(reaper.insert(reapable2, 1));
- assertTrue(reaper.insert(reapable3, 3));
+ //assertTrue(reaper.insert(reapable3, 1));
- assertTrue(reaper.insert(reapable4, 4));
+ //assertTrue(reaper.insert(reapable4, 1));
+ // latch the reaper before it tries to process the queue
+
+ triggerRendezvous("reaper1");
+
// make sure they were all registered
+ // the transactions queue should be
+ // UID1 RUNNING
+ // UID2 RUNNING
- assertEquals(4, reaper.numberOfTransactions());
- assertEquals(4, reaper.numberOfTimeouts());
+ assertEquals(2, reaper.numberOfTransactions());
+ assertEquals(2, reaper.numberOfTimeouts());
- // n.b. the reaper will not operate in dynamic mode by default
- // so we have to allow an extra checkPeriod millisecs for it
- // to detect timeouts (it may go back to sleep a few
- // milliseconds before a transaction times out). also by
- // default the reaper waits 500 msecs for a cancel to take
- // effect before interrupting and 500 msecs for an interrupt
- // to take effect before making a wedged worker a zombie. so
- // these need to be factored into this thread's delays when
- // tetsing the state of the reapables.
+ // wait long enough to ensure both reapables have timed out
- // wait at most 2 seconds for the first reapable to be cancelled
+ triggerWait(1000);
- int count = 0;
+ // now let the reaper dequeue the first reapable, process it and queue it for the worker thread
+ // to deal with
- while (!reapable1.getCancelTried() && count < 20) {
- count++;
- Thread.sleep(100);
- }
+ triggerRendezvous("reaper1");
- assertTrue(count < 20);
+ // latch the reaper before it tests the queue again
- // ensure that the second one gets cancelled even if the
- // first one is wedged
+ triggerRendezvous("reaper1");
- count = 0;
+ // latch the reaperworker before it tries to dequeue from the worker queue
- while (reapable2.getRunning() && count < 15) {
- count++;
- Thread.sleep(100);
- }
+ triggerRendezvous("reaperworker1");
- assertTrue(count < 15);
+ // the transactions queue should be
+ // UID2 RUNNING
+ // UID1 CANCEL
- // ensure also that the second one gave up at the cancel and
- // not the mark for rollback
+ assertEquals(2, reaper.numberOfTransactions());
+ assertEquals(2, reaper.numberOfTimeouts());
- assertTrue(reapable2.getCancelTried());
+ // now let the worker dequeue a reapable and proceed to call cancel
- // This assert causes timing issues on some build machines
- // - skip for now pending a more robust fix e.g. code injection
- //assertTrue(!reapable2.getRollbackTried());
+ triggerRendezvous("reaperworker1");
- // ensure that the first one responded to the interrupt and
- // marks itself for rollback only
+ // latch the first reapable inside cancel
- count = 0;
+ triggerRendezvous(uid1);
- while (reapable1.getRunning() && count < 10) {
- count++;
- Thread.sleep(100);
- }
+ // now let the reaper check the queue for the second reapable, dequeue it and add it to the
+ // worker queue
- assertTrue(count < 10);
- // the first one should not be running because it marks itself ActionStatus.ABORTED
- // - the reaper should not attempt to roll it back in this case
+ triggerRendezvous("reaper1");
+
+ // latch the reaper before it tests the queue again
+
+ triggerRendezvous("reaper1");
+
+ // the transactions queue should be
+ // UID1 CANCEL
+ // UID2 SCHEDULE_CANCEL
+
+ assertEquals(2, reaper.numberOfTransactions());
+ assertEquals(2, reaper.numberOfTimeouts());
+
+ // ensure we wait long enough for the cancel to time out
+
+ triggerWait(500);
+
+ // now let the reaper check the queue and interrupt the cancel for UID1
+
+ triggerRendezvous("reaper1");
+
+ // latch the reaper before it tests the queue again
+
+ triggerRendezvous("reaper1");
+
+ // unlatch the first reapable inside cancel
+
+ triggerRendezvous(uid1);
+
+ // latch the worker as it is about to process the queue again
+
+ triggerRendezvous("reaperworker1");
+
+ // the transactions queue should be
+ // UID2 SCHEDULE_CANCEL
+
+ assertEquals(1, reaper.numberOfTransactions());
+ assertEquals(1, reaper.numberOfTimeouts());
+
+ // let the worker clear and cancel the 2nd reapable
+
+ triggerRendezvous("reaperworker1");
+
+ // latch the worker before it reads the worker queue
+
+ triggerRendezvous("reaperworker1");
+
+ // the transactions queue should be empty
+
+ assertEquals(0, reaper.numberOfTransactions());
+ assertEquals(0, reaper.numberOfTimeouts());
+
+ // ensure that cancel was tried on reapable2 and that set rollback only was not tried on either
+ // we know cancel was tried on reapable1 because we got through the rendezvous
+
+ assertTrue(reapable2.getCancelTried());
assertTrue(!reapable1.getRollbackTried());
+ assertTrue(!reapable2.getRollbackTried());
+ assertTrue(checkAndClearFlag("interrupted"));
- // check that the third one refuses the cancel and gets marked
- // for rollback instead
+ // STAGE II
+ // now use the next pair of reapables to check that a wedged reaperworker gets tuirned into a zombie and
+ // a new worker gets created to cancel the remaining reapables.
+ // insert reapables so they timeout at 1 second intervals then
+ // check progress of cancellations and rollbacks
- count = 0;
+ assertTrue(reaper.insert(reapable3, 1));
- while (!reapable3.getCancelTried() && count < 25) {
- count++;
- Thread.sleep(100);
- }
+ assertTrue(reaper.insert(reapable4, 1));
- assertTrue(count < 25);
+ // make sure they were all registered
+ // the transactions queue should be
+ // UID3 RUNNING
+ // UID4 RUNNING
- // ensure that it gets marked for rollback
+ assertEquals(2, reaper.numberOfTransactions());
+ assertEquals(2, reaper.numberOfTimeouts());
- count = 0;
+ // wait long enough to ensure both reapables have timed out
- while (reapable3.getRunning() && count < 10) {
- count++;
- Thread.sleep(100);
- }
+ triggerWait(1000);
- assertTrue(count < 10);
+ // now let the reaper dequeue the first reapable, process it and queue it for the worker thread
+ // to deal with
- assertTrue(reapable3.getRollbackTried());
+ triggerRendezvous("reaper1");
- // ensure the fourth one gets cancelled and marked for rolback
- // even though it does not play ball
+ // latch the reaper before it tests the queue again
- count = 0;
+ triggerRendezvous("reaper1");
- while (reapable4.getRunning() && count < 25) {
- count++;
- Thread.sleep(100);
- }
+ // the transactions queue should be
+ // UID4 RUNNING
+ // UID3 CANCEL
- assertTrue(count < 25);
+ assertEquals(2, reaper.numberOfTransactions());
+ assertEquals(2, reaper.numberOfTimeouts());
- assertTrue(reapable4.getCancelTried());
- assertTrue(reapable4.getRollbackTried());
+ // now let the worker dequeue a reapable and proceed to call cancel
- // we should have a zombie worker so check that the thread
- // which tried the cancel is still runnning then sleep a bit
- // to give it time to complete and check it has exited
+ triggerRendezvous("reaperworker1");
- Thread worker = reapable4.getCancelThread();
+ // latch the third reapable inside cancel
- assertTrue(worker.isAlive());
+ triggerRendezvous(uid3);
- count = 0;
+ // now let the reaper check the queue for the fourth reapable, dequeue it and add it to the
+ // worker queue
- while (worker.isAlive() && count < 30) {
- count++;
- Thread.sleep(100);
- }
+ triggerRendezvous("reaper1");
- assertTrue(count < 30);
+ // latch the reaper before it tests the queue again
+
+ triggerRendezvous("reaper1");
+
+ // the transactions queue should be
+ // UID3 CANCEL
+ // UID4 SCHEDULE_CANCEL
+
+ assertEquals(2, reaper.numberOfTransactions());
+ assertEquals(2, reaper.numberOfTimeouts());
+
+ // ensure we wait long enough for the cancel to time out
+
+ triggerWait(500);
+
+ // now let the reaper check the queue and interrupt the cancel for UID3
+
+ triggerRendezvous("reaper1");
+
+ // latch the reaper before it tests the queue again
+
+ triggerRendezvous("reaper1");
+
+ assertTrue(checkAndClearFlag("interrupted"));
+
+ // ensure we wait long enough for the cancel to time out
+
+ triggerWait(500);
+
+ // the transactions queue should be
+ // UID4 SCHEDULE_CANCEL
+ // UID3 CANCEL_INTERRUPTED
+
+ assertEquals(2, reaper.numberOfTransactions());
+ assertEquals(2, reaper.numberOfTimeouts());
+
+ // let the reaper check the queue and reschedule the fourth reapable
+
+ triggerRendezvous("reaper1");
+
+ // latch the reaper before it tests the queue again
+
+ triggerRendezvous("reaper1");
+
+ // the transactions queue should be
+ // UID3 CANCEL_INTERRUPTED
+ // UID4 SCHEDULE_CANCEL
+
+ assertEquals(2, reaper.numberOfTransactions());
+ assertEquals(2, reaper.numberOfTimeouts());
+
+ // let the reaper check the queue and mark the reaper worker as a zombie
+
+ triggerRendezvous("reaper1");
+
+ // latch the reaper before it tests the queue again
+
+ triggerRendezvous("reaper1");
+
+ // the reaper should have marked the thread as a zombie
+
+ assertTrue(checkAndClearFlag("zombied"));
+
+ // the transactions queue should be
+ // UID4 SCHEDULE_CANCEL
+
+ assertEquals(1, reaper.numberOfTransactions());
+ assertEquals(1, reaper.numberOfTimeouts());
+
+ // unlatch the third reapable inside cancel
+
+ triggerRendezvous(uid3);
+
+ // latch the new worker as it is about to process the queue again
+
+ triggerRendezvous("reaperworker1");
+
+ // let the worker clear and cancel the 2nd reapable
+
+ triggerRendezvous("reaperworker1");
+
+ // latch the worker before it reads the worker queue
+
+ triggerRendezvous("reaperworker1");
+
+ // the transactions queue should be empty
+
+ assertEquals(0, reaper.numberOfTransactions());
+ assertEquals(0, reaper.numberOfTimeouts());
+
+ // ensure that cancel was tried on reapable4 and that set rollback only was tried on reapable3
+ // and reapable4 we know cancel was tried on reapable3 because we got through the rendezvous
+
+ assertTrue(reapable4.getCancelTried());
+ assertTrue(reapable3.getRollbackTried());
+ assertTrue(reapable4.getRollbackTried());
}
- public class SlowReapable implements Reapable
+ private void enableRendezvous(Object o, boolean repeatable)
{
- public SlowReapable(Uid uid, int callDelay, int interruptDelay, boolean doCancel, boolean doRollback, boolean doComplete)
+ // do nothing this is just used for synchronization
+ }
+
+ private void triggerRendezvous(Object o)
+ {
+ // do nothing this is just used for synchronization
+ }
+
+ private void triggerWait(int msecs)
+ {
+ // do nothing this is just used for synchronization
+ }
+
+ private boolean checkAndClearFlag(Object o)
+ {
+ // return false by default -- rule system will intercept and return the relevant flag
+ // setting
+
+ return false;
+ }
+
+ public class TestReapable implements Reapable
+ {
+ /**
+ * create a mock reapable
+ * @param uid
+ * @param doCancel true if the reapable should return ABORTED from the cancel call and false if it should
+ * return RUNNING
+ * @param rendezvousInCancel true iff the reapable should rendezvous with the test code when cancel is called
+ * @param doRollback the value that the reapable should return true from the prevent_commit call
+ * @param rendezvousInInterrupt true iff the reapable should rendezvous with the test code when it is
+ */
+ public TestReapable(Uid uid, boolean doCancel, boolean rendezvousInCancel, boolean doRollback, boolean rendezvousInInterrupt)
{
this.uid = uid;
- this.callDelay = callDelay;
- this.interruptDelay = interruptDelay;
+ this.rendezvousInCancel = rendezvousInCancel;
+ this.rendezvousInInterrupt = rendezvousInInterrupt;
this.doCancel = doCancel;
this.doRollback = doRollback;
- this.doComplete = doComplete;
cancelTried = false;
rollbackTried = false;
running = true;
@@ -211,6 +420,12 @@
public boolean preventCommit()
{
setRollbackTried();
+
+ if (rendezvousInInterrupt) {
+ triggerRendezvous(uid);
+ triggerRendezvous(uid);
+ }
+
clearRunning();
return doRollback;
}
@@ -226,19 +441,10 @@
setCancelThread(Thread.currentThread());
- if (callDelay > 0) {
- try {
- Thread.sleep(callDelay);
- } catch (InterruptedException e) {
- interrupted = true;
- }
+ if (rendezvousInCancel) {
+ triggerRendezvous(uid);
+ triggerRendezvous(uid);
}
- if (interrupted && interruptDelay > 0) {
- try {
- Thread.sleep(interruptDelay);
- } catch (InterruptedException e) {
- }
- }
if (doCancel) {
clearRunning();
@@ -254,11 +460,10 @@
}
private Uid uid;
- private int callDelay; // in milliseconds
- private int interruptDelay; // in milliseconds
private boolean doCancel;
private boolean doRollback;
- private boolean doComplete;
+ private boolean rendezvousInCancel;
+ private boolean rendezvousInInterrupt;
private boolean cancelTried;
private boolean rollbackTried;
private boolean running;
Modified: labs/jbosstm/trunk/ArjunaCore/arjuna/tests/classes/com/hp/mwtests/ts/arjuna/recovery/RecoveryManagerStartStopTest.java
===================================================================
--- labs/jbosstm/trunk/ArjunaCore/arjuna/tests/classes/com/hp/mwtests/ts/arjuna/recovery/RecoveryManagerStartStopTest.java 2009-08-03 14:57:18 UTC (rev 28755)
+++ labs/jbosstm/trunk/ArjunaCore/arjuna/tests/classes/com/hp/mwtests/ts/arjuna/recovery/RecoveryManagerStartStopTest.java 2009-08-03 15:21:05 UTC (rev 28756)
@@ -250,221 +250,4 @@
}
}
}
-
- /**
- * helper class for use in byteman rules to ensure that the listener class
- * actually joins the connections it closes -- it does not need to as far as the
- * TS code is concerned but we cannot check that the test has run correctly without
- * adding this extra join
- */
-
- public static class JoinHelper extends Helper
- {
- public JoinHelper(Rule rule)
- {
- super(rule);
- }
-
- public boolean createJoin(Object key, int max)
- {
- if (max <= 0) {
- return false;
- }
-
- synchronized(joinerMap) {
- if (joinerMap.get(key) != null) {
- return false;
- }
- joinerMap.put(key, new Joiner(max));
- }
-
- return true;
- }
-
- public boolean isJoin(Object key, int max)
- {
- synchronized(joinerMap) {
- Joiner joiner = joinerMap.get(key);
-
- if (joiner == null || joiner.getMax() != max) {
- return false;
- }
- }
-
- return true;
- }
-
- public boolean joinEnlist(Object key)
- {
- Joiner joiner;
- synchronized (joinerMap)
- {
- joiner = joinerMap.get(key);
- }
-
- if (joiner == null) {
- return false;
- }
-
- Thread current = Thread.currentThread();
-
- switch (joiner.addChild(current)) {
- case DUPLICATE:
- case EXCESS:
- {
- // failed to add child
- return false;
- }
- case ADDED:
- case FILLED:
- {
- // added child but parent was not waiting so leave joiner in the map for parent to find
- return true;
- }
- case DONE:
- default:
- {
- // added child and parent was waiting so remove joiner from map now
- synchronized (joinerMap) {
- joinerMap.remove(joiner);
- }
- return true;
- }
- }
- }
-
- public boolean joinWait(Object key, int count)
- {
- Joiner joiner;
- synchronized (joinerMap)
- {
- joiner = joinerMap.get(key);
- }
-
- if (joiner == null || joiner.getMax() != count) {
- return false;
- }
-
- Thread current = Thread.currentThread();
-
- if (joiner.joinChildren(current)) {
- // successfully joined all child threads so remove joiner form map
- synchronized (joinerMap) {
- joinerMap.remove(joiner);
- }
- return true;
- } else {
- // hmm, another thread must have done the join so leave it do the remove
- return true;
- }
- }
-
- }
-
- private static HashMap<Object, Joiner> joinerMap = new HashMap<Object, Joiner>();
-
- /**
- * status values returned from child add method
- */
- private enum Status {
- /**
- * a DUPLICATE status is returned when a child fails to add itself to the join list because it is already present
- */
- DUPLICATE,
- /**
- * an EXCESS status is returned when a child fails to add itself to a join list because it already contains the
- * expected number of children
- */
- EXCESS,
- /**
- * an ADDED status is returned when a child successfully adds itself to the join list but without reaching
- * the expected number of children
- */
- ADDED,
- /**
- * a FILLED status is returned when a child successfully adds itself to the join list reaching the expected
- * number of children but there is no parent thread waiting for the children
- */
- FILLED,
- /**
- * a DONE status is returned when a child successfully adds itself to the join list reaching the expected
- * number of children and there is a parent thread waiting for the children
- */
- DONE
- }
-
- private static class Joiner
- {
-
- private List<Thread> children;
- private int max;
- private Thread parent;
-
- public Joiner(int max)
- {
- this.max = max;
- this.children = new LinkedList<Thread>();
- this.parent = null;
- }
-
- public int getMax()
- {
- return max;
- }
-
- public synchronized Status addChild(Thread thread)
- {
- if (children.contains(thread)) {
- return Status.DUPLICATE;
- }
-
- int size = children.size();
-
- if (size == max) {
- return Status.EXCESS;
- }
-
- children.add(thread);
- size++;
-
- if (size == max) {
- if (parent == null) {
- return Status.FILLED;
- } else {
- notifyAll();
- return Status.DONE;
- }
- }
- return Status.ADDED;
- }
-
- public boolean joinChildren(Thread thread)
- {
- synchronized (this) {
- if (parent != null) {
- return false;
- }
- parent = thread;
- while (children.size() < max) {
- try {
- wait();
- } catch (InterruptedException e) {
- // do nothing
- }
- }
- }
- // since we are the parent and the waiting is over we don't need to stay synchronized
- for (int i = 0; i < max;) {
- Thread child = children.get(i);
- try {
- child.join();
- } catch (InterruptedException e) {
- // try again
- break;
- }
- i++;
- }
- return true;
- }
- }
}
Modified: labs/jbosstm/trunk/ext/Readme
===================================================================
--- labs/jbosstm/trunk/ext/Readme 2009-08-03 14:57:18 UTC (rev 28755)
+++ labs/jbosstm/trunk/ext/Readme 2009-08-03 15:21:05 UTC (rev 28756)
@@ -34,4 +34,4 @@
xalan.jar
xercesImpl.jar Xerces 2.3.0
xmlParserAPIs.jar Xerces 2.3.0
-byteman.jar 1.0.3.SNAPSHOT (28 July 2009)
+byteman.jar 1.0.3.SNAPSHOT (3rd August 2009)
Modified: labs/jbosstm/trunk/ext/byteman.jar
===================================================================
(Binary files differ)
More information about the jboss-svn-commits
mailing list