use of com.arjuna.ats.arjuna.coordinator.RecordList in project narayana by jbosstm.
the class Transaction method end.
// in this version close need to run as blocking code {@link Vertx().executeBlocking}
public int end(boolean compensate) {
inFlight = false;
int res = status();
boolean nested = !isTopLevel();
if (scheduledAbort != null) {
scheduledAbort.cancel(false);
scheduledAbort = null;
}
// nested compensators need to be remembered in case the enclosing LRA decides to compensate
// also save the list so that we can retrieve any response data after committing compensators
// if (nested)
savePendingList();
if ((res != ActionStatus.RUNNING) && (res != ActionStatus.ABORT_ONLY)) {
if (nested && compensate) {
/*
* Note that we do not hook into ActionType.NESTED because that would mean that after a
* nested txn is committed its participants are merged
* with the parent and they can then only be aborted if the parent aborts whereas in
* the LRA model nested LRAs can be compensated whilst the enclosing LRA is completed
*/
// repopulate the pending list TODO it won't neccessarily be present during recovery
pendingList = new RecordList();
pending.forEach(r -> pendingList.putRear(r));
updateState(CompensatorStatus.Compensating);
super.phase2Abort(true);
// res = super.Abort();
res = status();
status = toLRAStatus(status());
}
} else {
if (compensate || status() == ActionStatus.ABORT_ONLY) {
// compensators must be called in reverse order so reverse the pending list
int sz = pendingList == null ? 0 : pendingList.size();
for (int i = sz - 1; i > 0; i--) pendingList.putRear(pendingList.getFront());
// tell each participant that the lra canceled
updateState(CompensatorStatus.Compensating);
// this route to abort forces a log write on failures and heuristics
res = super.Abort();
} else {
// tell each participant that the lra completed ok
updateState(CompensatorStatus.Completing);
res = super.End(true);
}
}
updateState();
// gather up any response data
ObjectMapper mapper = new ObjectMapper();
if (pending != null && pending.size() != 0) {
if (!nested)
// TODO we will loose this data if we need recovery
pending.clear();
}
if (getSize(heuristicList) != 0 || getSize(failedList) != 0)
status = CompensatorStatus.Compensating;
else if (getSize(pendingList) != 0 || getSize(preparedList) != 0)
status = CompensatorStatus.Completing;
else
status = toLRAStatus(res);
if (!isRecovering())
if (lraService != null)
lraService.finished(this, false);
else
LRALogger.logger.warn("null LRAService in LRA#end");
responseData = status == null ? null : status.name();
return res;
}
use of com.arjuna.ats.arjuna.coordinator.RecordList in project narayana by jbosstm.
the class ActionBean method setStatus.
/**
* Request a change in status of a participant. For example if a record has a
* heuristic status then this method could be used to move it back into the
* prepared state so that the recovery system can replay phase 2 of the
* commitment protocol
* @param logrec the record whose status is to be changed
* @param newStatus the desired status
* @return true if the status was changed
*/
public boolean setStatus(LogRecordWrapper logrec, ParticipantStatus newStatus) {
ParticipantStatus lt = logrec.getListType();
AbstractRecord targRecord = logrec.getRecord();
RecordList oldList = ra.getRecords(lt);
RecordList newList = ra.getRecords(newStatus);
// move the record from currList to targList
if (oldList.remove(targRecord)) {
if (newList.insert(targRecord)) {
if (lt.equals(ParticipantStatus.HEURISTIC)) {
switch(newStatus) {
case FAILED:
ra.clearHeuristicDecision(TwoPhaseOutcome.FINISH_ERROR);
break;
case PENDING:
ra.clearHeuristicDecision(TwoPhaseOutcome.NOT_PREPARED);
break;
case PREPARED:
ra.clearHeuristicDecision(TwoPhaseOutcome.PREPARE_OK);
break;
case READONLY:
ra.clearHeuristicDecision(TwoPhaseOutcome.PREPARE_READONLY);
break;
default:
break;
}
}
ra.doUpdateState();
return true;
}
}
return false;
}
use of com.arjuna.ats.arjuna.coordinator.RecordList in project narayana by jbosstm.
the class RecordListUnitTest method test.
@Test
public void test() throws Exception {
RecordList rl = new RecordList();
DisposeRecord dr = new DisposeRecord();
rl.insert(dr);
assertEquals(rl.getFront(), dr);
rl.insert(dr);
assertEquals(rl.getRear(), dr);
RecordList copy = new RecordList(rl);
ActivationRecord ar = new ActivationRecord();
rl.insert(ar);
rl.print(new PrintWriter(new ByteArrayOutputStream()));
assertTrue(rl.toString() != null);
assertEquals(rl.getNext(dr), null);
assertTrue(rl.peekFront() != null);
assertTrue(rl.peekRear() != null);
assertEquals(rl.peekNext(dr), null);
assertTrue(rl.remove(dr));
}
use of com.arjuna.ats.arjuna.coordinator.RecordList in project narayana by jbosstm.
the class CrashRecoveryCommitReturnsXA_RETRYHeuristicRollback method testHeuristicRollback.
@Test
public void testHeuristicRollback() throws Exception {
// this test is supposed to leave a record around in the log store
// during a commit long enough
// that the periodic recovery thread runs and detects it. rather than
// rely on delays to make
// this happen (placing us at the mercy of the scheduler) we use a
// byteman script to enforce
// the thread sequence we need
RecoveryEnvironmentBean recoveryEnvironmentBean = BeanPopulator.getDefaultInstance(RecoveryEnvironmentBean.class);
// JBTM-1354 we need to make sure that a full scan has gone off
recoveryEnvironmentBean.setRecoveryBackoffPeriod(1);
recoveryEnvironmentBean.setPeriodicRecoveryPeriod(Integer.MAX_VALUE);
List<String> recoveryModuleClassNames = new ArrayList<String>();
recoveryModuleClassNames.add("com.arjuna.ats.internal.arjuna.recovery.AtomicActionRecoveryModule");
recoveryModuleClassNames.add("com.arjuna.ats.internal.jta.recovery.arjunacore.XARecoveryModule");
recoveryEnvironmentBean.setRecoveryModuleClassNames(recoveryModuleClassNames);
List<String> expiryScannerClassNames = new ArrayList<String>();
expiryScannerClassNames.add("com.arjuna.ats.internal.arjuna.recovery.ExpiredTransactionStatusManagerScanner");
recoveryEnvironmentBean.setExpiryScannerClassNames(expiryScannerClassNames);
recoveryEnvironmentBean.setRecoveryActivators(null);
// start the recovery manager
RecoveryManager.manager().initialize();
XARecoveryModule xaRecoveryModule = null;
for (RecoveryModule recoveryModule : ((Vector<RecoveryModule>) RecoveryManager.manager().getModules())) {
if (recoveryModule instanceof XARecoveryModule) {
xaRecoveryModule = (XARecoveryModule) recoveryModule;
break;
}
}
if (xaRecoveryModule == null) {
throw new Exception("No XARM");
}
// JBTM-1354 Run a scan to make sure that the recovery thread has completed a full run before starting the test
// The important thing is that replayCompletion is allowed to do a scan of the transactions
RecoveryManager.manager().scan();
XAResource firstResource = new SimpleResource();
Object toWakeUp = new Object();
final SimpleResourceXA_RETRYHeuristicRollback secondResource = new SimpleResourceXA_RETRYHeuristicRollback();
xaRecoveryModule.addXAResourceRecoveryHelper(new XAResourceRecoveryHelper() {
@Override
public boolean initialise(String p) throws Exception {
// TODO Auto-generated method stub
return true;
}
@Override
public XAResource[] getXAResources() throws Exception {
// TODO Auto-generated method stub
return new XAResource[] { secondResource };
}
});
// ok, now drive a TX to completion. the script should ensure that the
// recovery
javax.transaction.TransactionManager tm = com.arjuna.ats.jta.TransactionManager.transactionManager();
tm.begin();
javax.transaction.Transaction theTransaction = tm.getTransaction();
Uid txUid = ((TransactionImple) theTransaction).get_uid();
theTransaction.enlistResource(firstResource);
theTransaction.enlistResource(secondResource);
assertFalse(secondResource.wasCommitted());
tm.commit();
InputObjectState uids = new InputObjectState();
String type = new AtomicAction().type();
StoreManager.getRecoveryStore().allObjUids(type, uids);
boolean moreUids = true;
boolean found = false;
while (moreUids) {
Uid theUid = UidHelper.unpackFrom(uids);
if (theUid.equals(txUid)) {
found = true;
Field heuristicListField = BasicAction.class.getDeclaredField("heuristicList");
heuristicListField.setAccessible(true);
ActionStatusService ass = new ActionStatusService();
{
int theStatus = ass.getTransactionStatus(type, theUid.stringForm());
assertTrue(theStatus == ActionStatus.COMMITTED);
RecoverAtomicAction rcvAtomicAction = new RecoverAtomicAction(theUid, theStatus);
theStatus = rcvAtomicAction.status();
rcvAtomicAction.replayPhase2();
assertTrue(theStatus == ActionStatus.COMMITTED);
assertTrue(secondResource.wasCommitted());
RecordList heuristicList = (RecordList) heuristicListField.get(rcvAtomicAction);
assertTrue("Expected 1 heuristics: " + heuristicList.size(), heuristicList.size() == 1);
}
{
int theStatus = ass.getTransactionStatus(type, theUid.stringForm());
assertTrue(theStatus == ActionStatus.COMMITTED);
RecoverAtomicAction rcvAtomicAction = new RecoverAtomicAction(theUid, theStatus);
theStatus = rcvAtomicAction.status();
assertTrue(theStatus == ActionStatus.COMMITTED);
RecordList heuristicList = (RecordList) heuristicListField.get(rcvAtomicAction);
assertTrue("Expected 1 heuristics: " + heuristicList.size(), heuristicList.size() == 1);
assertTrue(secondResource.wasCommitted());
}
} else if (theUid.equals(Uid.nullUid())) {
moreUids = false;
}
}
if (!found) {
throw new Exception("Could not locate the Uid");
}
}
Aggregations