1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-23 14:42:11 +02:00

Bug 325943 - [concurrent] Robustify Sequence against RejectedExecutionException

This commit is contained in:
Pawel Piech 2010-09-27 23:27:18 +00:00
parent b2dd37899a
commit c72c78d35c
2 changed files with 103 additions and 24 deletions

View file

@ -421,9 +421,18 @@ abstract public class Sequence extends DsfRunnable implements Future<Object> {
@Override
protected void handleErrorOrWarning() {
abortExecution(getStatus());
abortExecution(getStatus(), true);
};
@Override
protected void handleRejectedExecutionException() {
abortExecution(
new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, 0,
"Executor shut down while executing Sequence " + this + ", step #" + fCurrentStepIdx, //$NON-NLS-1$ //$NON-NLS-2$
null),
false);
}
@Override
public String toString() {
return "Sequence \"" + fTaskName + "\", result for executing step #" + fStepIdx + " = " + getStatus(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
@ -450,10 +459,11 @@ abstract public class Sequence extends DsfRunnable implements Future<Object> {
* when the execute submits other runnables, and the other runnables
* encounter the exception.
*/
abortExecution(new Status(
IStatus.ERROR, DsfPlugin.PLUGIN_ID, 0,
"Unhandled exception when executing Sequence " + this + ", step #" + fCurrentStepIdx, //$NON-NLS-1$ //$NON-NLS-2$
t));
abortExecution(
new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, 0,
"Unhandled exception when executing Sequence " + this + ", step #" + fCurrentStepIdx, //$NON-NLS-1$ //$NON-NLS-2$
t),
true);
/*
* Since we caught the exception, it will not be logged by
@ -548,8 +558,13 @@ abstract public class Sequence extends DsfRunnable implements Future<Object> {
/**
* Tells the sequence that its execution is to be aborted and it
* should start rolling back the sequence as if it was cancelled by user.
*
* @param status Status to use for reporting the error.
* @param rollBack Whether to start rolling back the sequence after abort.
* If this parameter is <code>false</code> then the sequence will also
* finish.
*/
private void abortExecution(final IStatus error) {
private void abortExecution(final IStatus error, boolean rollBack) {
if (fRollbackTaskName != null) {
fProgressMonitor.subTask(fRollbackTaskName);
}
@ -558,9 +573,13 @@ abstract public class Sequence extends DsfRunnable implements Future<Object> {
fRequestMonitor.setStatus(error);
}
fSync.doAbort(new CoreException(error));
// Roll back starting with previous step, since current step failed.
rollBackStep(fCurrentStepIdx - 1);
if (rollBack) {
// Roll back starting with previous step, since current step failed.
rollBackStep(fCurrentStepIdx - 1);
} else {
finish();
}
}
/**

View file

@ -43,9 +43,13 @@ public class DsfSequenceTests {
@After
public void shutdownExecutor() throws ExecutionException, InterruptedException {
fExecutor.submit(new DsfRunnable() { public void run() {
fExecutor.shutdown();
}}).get();
if (!fExecutor.isShutdown()) {
// Some tests shut down the executor deliberatly)
fExecutor.submit(new DsfRunnable() { public void run() {
fExecutor.shutdown();
}}).get();
}
if (fExecutor.exceptionsCaught()) {
Throwable[] exceptions = fExecutor.getExceptions();
throw new ExecutionException(exceptions[0]);
@ -81,8 +85,8 @@ public class DsfSequenceTests {
Sequence sequence = new Sequence(fExecutor) {
@Override public Step[] getSteps() { return steps; }
};
Assert.assertTrue(!sequence.isDone());
Assert.assertTrue(!sequence.isCancelled());
Assert.assertFalse(sequence.isDone());
Assert.assertFalse(sequence.isCancelled());
fExecutor.execute(sequence);
sequence.get();
@ -92,7 +96,7 @@ public class DsfSequenceTests {
// Check post conditions
Assert.assertTrue(sequence.isDone());
Assert.assertTrue(!sequence.isCancelled());
Assert.assertFalse(sequence.isCancelled());
}
@ -129,8 +133,8 @@ public class DsfSequenceTests {
SimpleReflectionSequence sequence = new SimpleReflectionSequence();
//Sequence sequence = new SimpleReflectionSequence();
Assert.assertTrue(!sequence.isDone());
Assert.assertTrue(!sequence.isCancelled());
Assert.assertFalse(sequence.isDone());
Assert.assertFalse(sequence.isCancelled());
fExecutor.execute(sequence);
sequence.get();
@ -140,7 +144,7 @@ public class DsfSequenceTests {
// Check post conditions
Assert.assertTrue(sequence.isDone());
Assert.assertTrue(!sequence.isCancelled());
Assert.assertFalse(sequence.isCancelled());
}
@ -183,7 +187,7 @@ public class DsfSequenceTests {
};
fExecutor.execute(sequence);
// Block and wait for sequence to bomplete.
// Block and wait for sequence to complete.
try {
sequence.get();
} finally {
@ -194,7 +198,63 @@ public class DsfSequenceTests {
// Check state from Future interface
Assert.assertTrue(sequence.isDone());
Assert.assertTrue(!sequence.isCancelled());
Assert.assertFalse(sequence.isCancelled());
}
Assert.assertTrue("Exception should have been thrown", false); //$NON-NLS-1$
}
@Test (expected = ExecutionException.class)
public void rejectedTest() throws InterruptedException, ExecutionException {
// Create a counter for tracking number of steps performed and steps
// rolled back.
class IntegerHolder { int fInteger; }
final IntegerHolder stepCounter = new IntegerHolder();
final IntegerHolder rollBackCounter = new IntegerHolder();
// Create the steps of the sequence
final Sequence.Step[] steps = new Sequence.Step[] {
new Sequence.Step() {
@Override public void execute(RequestMonitor requestMonitor) {
stepCounter.fInteger++;
requestMonitor.done();
}
@Override public void rollBack(RequestMonitor requestMonitor) {
rollBackCounter.fInteger++;
requestMonitor.done();
}
},
new Sequence.Step() {
@Override public void execute(RequestMonitor requestMonitor) {
stepCounter.fInteger++;
// Shutdown exectutor to force a RejectedExecutionException
fExecutor.shutdown();
requestMonitor.done();
}
@Override public void rollBack(RequestMonitor requestMonitor) {
rollBackCounter.fInteger++;
requestMonitor.done();
}
}
};
// Create and start.
Sequence sequence = new Sequence(fExecutor) {
@Override public Step[] getSteps() { return steps; }
};
fExecutor.execute(sequence);
// Block and wait for sequence to complete.
try {
sequence.get();
} finally {
// Both steps should be performed
Assert.assertTrue(stepCounter.fInteger == 2);
// No steps should be rolled back.
Assert.assertTrue(rollBackCounter.fInteger == 0);
// Check state from Future interface
Assert.assertTrue(sequence.isDone());
Assert.assertFalse(sequence.isCancelled());
}
Assert.assertTrue("Exception should have been thrown", false); //$NON-NLS-1$
}
@ -257,7 +317,7 @@ public class DsfSequenceTests {
// Check state from Future interface
Assert.assertTrue(sequence.isDone());
Assert.assertTrue(!sequence.isCancelled());
Assert.assertFalse(sequence.isCancelled());
}
Assert.assertTrue("Exception should have been thrown", false); //$NON-NLS-1$
}
@ -320,7 +380,7 @@ public class DsfSequenceTests {
// Check state from Future interface
Assert.assertTrue(sequence.isDone());
Assert.assertTrue(!sequence.isCancelled());
Assert.assertFalse(sequence.isCancelled());
}
Assert.assertTrue("Exception should have been thrown", false); //$NON-NLS-1$
}
@ -352,7 +412,7 @@ public class DsfSequenceTests {
} finally {
// Check state from Future interface
Assert.assertTrue(sequence.isDone());
Assert.assertTrue(!sequence.isCancelled());
Assert.assertFalse(sequence.isCancelled());
}
Assert.assertTrue("Exception should have been thrown", false); //$NON-NLS-1$
}
@ -375,7 +435,7 @@ public class DsfSequenceTests {
// Cancel before invoking the sequence.
sequence.cancel(false);
Assert.assertTrue(!sequence.isDone());
Assert.assertFalse(sequence.isDone());
Assert.assertTrue(sequence.isCancelled());
// Start the sequence