public XAResourceHolderState startRecovery() throws RecoveryException { if (recoveryXAResourceHolder != null) { throw new RecoveryException("recovery already in progress on " + this); } if (xaResourceHolders.isEmpty()) { throw new RecoveryException("no XAResource registered, recovery cannot be done on " + this); } recoveryXAResourceHolder = new RecoveryXAResourceHolder(xaResourceHolders.values().iterator().next()); return new XAResourceHolderState(recoveryXAResourceHolder, this); }
public void testRemove() { Scheduler<XAResourceHolderState> resourceScheduler = new Scheduler<XAResourceHolderState>(); XAResourceHolderState xarhs0 = new XAResourceHolderState(null, new MockResourceBean(0)); XAResourceHolderState xarhs1 = new XAResourceHolderState(null, new MockResourceBean(1)); resourceScheduler.add(xarhs0, xarhs0.getTwoPcOrderingPosition()); resourceScheduler.add(xarhs1, xarhs1.getTwoPcOrderingPosition()); resourceScheduler.remove(xarhs0); resourceScheduler.add(xarhs0, xarhs0.getTwoPcOrderingPosition()); Iterator<XAResourceHolderState> it = resourceScheduler.iterator(); assertTrue(it.hasNext()); assertTrue(xarhs0 == it.next()); it.remove(); assertTrue(xarhs1 == it.next()); it.remove(); }
XAResourceHolderState alreadyEnlistedHolder = findXAResourceHolderState(xaResourceHolderState.getXAResource()); if (alreadyEnlistedHolder != null && !alreadyEnlistedHolder.isEnded()) { xaResourceHolderState.setXid(alreadyEnlistedHolder.getXid()); log.warn("ignoring enlistment of already enlisted but not ended resource " + xaResourceHolderState); return; xid = toBeJoinedHolderState.getXid(); flag = XAResource.TMJOIN; if (flag != XAResource.TMJOIN && xaResourceHolderState.getTwoPcOrderingPosition() == Scheduler.ALWAYS_LAST_POSITION && !TransactionManagerServices.getConfiguration().isAllowMultipleLrc()) { List<XAResourceHolderState> alwaysLastResources = resources.getByNaturalOrderForPosition(Scheduler.ALWAYS_LAST_POSITION); xaResourceHolderState.setXid(xid); xaResourceHolderState.start(flag); resources.add(xaResourceHolderState, xaResourceHolderState.getTwoPcOrderingPosition());
private void forgetHeuristicCommit(XAResourceHolderState resourceHolder) { try { if (log.isDebugEnabled()) { log.debug("handling heuristic commit on resource " + resourceHolder.getXAResource()); } resourceHolder.getXAResource().forget(resourceHolder.getXid()); if (log.isDebugEnabled()) { log.debug("forgotten heuristically committed resource " + resourceHolder.getXAResource()); } } catch (XAException ex) { String extraErrorDetails = TransactionManagerServices.getExceptionAnalyzer().extractExtraXAExceptionDetails(ex); log.error("cannot forget " + resourceHolder.getXid() + " assigned to " + resourceHolder.getXAResource() + ", error=" + Decoder.decodeXAExceptionErrorCode(ex) + (extraErrorDetails == null ? "" : ", extra error=" + extraErrorDetails), ex); } }
/** * Resume all enlisted resources in the current transaction context. * @throws XAException if the resource threw an exception during resume. */ public void resume() throws XAException { // all XAResource needs to be re-enlisted but this must happen // outside the Scheduler's iteration as enlist() can change the // collection's content and confuse the iterator. List<XAResourceHolderState> toBeReEnlisted = new ArrayList<XAResourceHolderState>(); for (XAResourceHolderState xaResourceHolderState : resources) { if (log.isDebugEnabled()) { log.debug("resuming " + xaResourceHolderState); } // If a prepared statement is (re-)used after suspend/resume is performed its XAResource needs to be // re-enlisted. This must be done outside this loop or that will confuse the iterator! toBeReEnlisted.add(new XAResourceHolderState(xaResourceHolderState)); } if (toBeReEnlisted.size() > 0 && log.isDebugEnabled()) log.debug("re-enlisting " + toBeReEnlisted.size() + " resource(s)"); for (XAResourceHolderState xaResourceHolderState : toBeReEnlisted) { if (log.isDebugEnabled()) { log.debug("re-enlisting resource " + xaResourceHolderState); } try { enlist(xaResourceHolderState); xaResourceHolderState.getXAResourceHolder().putXAResourceHolderState(xaResourceHolderState.getXid(), xaResourceHolderState); } catch (BitronixSystemException ex) { throw new BitronixXAException("error re-enlisting resource during resume: " + xaResourceHolderState, XAException.XAER_RMERR, ex); } } }
/** * Search for an eventually already enlisted {@link XAResourceHolderState} that could be joined with the * {@link XAResourceHolderState} passed as parameter.<br/> * If datasource configuration property <code>bitronix.useTmJoin=false</code> is set this method always returns null. * @param xaResourceHolderState a {@link XAResourceHolderState} looking to be joined. * @return another enlisted {@link XAResourceHolderState} that can be joined with the one passed in or null if none is found. * @throws XAException if call to XAResource.isSameRM() fails. */ private XAResourceHolderState getManagedResourceWithSameRM(XAResourceHolderState xaResourceHolderState) throws XAException { if (!xaResourceHolderState.getUseTmJoin()) { if (log.isDebugEnabled()) { log.debug("join disabled on resource " + xaResourceHolderState); } return null; } for (XAResourceHolderState alreadyEnlistedHolderState : resources) { if (log.isDebugEnabled()) log.debug("checking joinability of " + xaResourceHolderState + " with " + alreadyEnlistedHolderState); if (alreadyEnlistedHolderState.isEnded() && !alreadyEnlistedHolderState.isSuspended() && xaResourceHolderState.getXAResource().isSameRM(alreadyEnlistedHolderState.getXAResource())) { if (log.isDebugEnabled()) { log.debug("resources are joinable"); } return alreadyEnlistedHolderState; } if (log.isDebugEnabled()) { log.debug("resources are not joinable"); } } if (log.isDebugEnabled()) { log.debug("no joinable resource found for " + xaResourceHolderState); } return null; }
protected static Set<String> collectResourcesUniqueNames(List<XAResourceHolderState> resources) { Set<String> uniqueNames = new HashSet<String>(); for (XAResourceHolderState resourceHolderState : resources) { uniqueNames.add(resourceHolderState.getUniqueName()); } return uniqueNames; }
/** * Log exceptions that happened during a phase failure. * @param ex the phase exception. */ protected void logFailedResources(PhaseException ex) { List<Exception> exceptions = ex.getExceptions(); List<XAResourceHolderState> resources = ex.getResourceStates(); for (int i = 0; i < exceptions.size(); i++) { Exception e = exceptions.get(i); XAResourceHolderState holderState = resources.get(i); log.error("resource " + holderState.getUniqueName() + " failed on " + holderState.getXid(), e); } }
/** * Delist the specified {@link XAResourceHolderState}. A reference to the resource is kept anyway. * @param xaResourceHolderState the {@link XAResourceHolderState} to be delisted. * @param flag the delistment flag. * @return true if the resource could be delisted, false otherwise. * @throws XAException if the resource threw an exception during delistment. * @throws BitronixSystemException if an internal error occured. */ public boolean delist(XAResourceHolderState xaResourceHolderState, int flag) throws XAException, BitronixSystemException { if (findXAResourceHolderState(xaResourceHolderState.getXAResource()) != null) { if (log.isDebugEnabled()) { log.debug("delisting resource " + xaResourceHolderState); } xaResourceHolderState.end(flag); return true; } log.warn("trying to delist resource that has not been previously enlisted: " + xaResourceHolderState); return false; }
/** * Suspend all enlisted resources from the current transaction context. * @throws XAException if the resource threw an exception during suspend. */ public void suspend() throws XAException { for (XAResourceHolderState xaResourceHolderState : resources) { if (!xaResourceHolderState.isEnded()) { if (log.isDebugEnabled()) log.debug("suspending " + xaResourceHolderState); xaResourceHolderState.end(XAResource.TMSUCCESS); } } // while }
/** * Remove this transaction's {@link XAResourceHolderState} from all enlisted * {@link bitronix.tm.resource.common.XAResourceHolder}s. */ public void clearXAResourceHolderStates() { if (log.isDebugEnabled()) log.debug("clearing XAResourceHolder states on " + resources.size() + " resource(s)"); Iterator<XAResourceHolderState> it = resources.iterator(); while (it.hasNext()) { XAResourceHolderState xaResourceHolderState = it.next(); XAResourceHolder resourceHolder = xaResourceHolderState.getXAResourceHolder(); // clear out the current state resourceHolder.removeXAResourceHolderState(xaResourceHolderState.getXid()); Map statesForGtrid = resourceHolder.getXAResourceHolderStatesForGtrid(gtrid); if (statesForGtrid != null) log.warn("resource " + resourceHolder + " did not clean up " + statesForGtrid.size() + "transaction states for GTRID [" + gtrid + "]"); else if (log.isDebugEnabled()) log.debug("resource " + resourceHolder + " cleaned up all transaction states for GTRID [" + gtrid + "]"); it.remove(); } }
@Override public String toString() { return "an XAResourceHolderState with uniqueName=" + bean.getUniqueName() + " XAResource=" + getXAResource() + (started ? " (started)":"") + (ended ? " (ended)":"") + (suspended ? " (suspended)":"") + " with XID " + xid; } }
xidCount = recover(xaResourceHolderState, xids, XAResource.TMSTARTRSCAN); } catch (XAException ex) { if (xaResourceHolderState.getIgnoreRecoveryFailures()) { if (log.isDebugEnabled()) { log.debug("ignoring recovery failure on resource " + xaResourceHolderState, ex); } return Collections.emptySet();
public void testReverseRemove() { Scheduler<XAResourceHolderState> resourceScheduler = new Scheduler<XAResourceHolderState>(); XAResourceHolderState xarhs0 = new XAResourceHolderState(null, new MockResourceBean(0)); XAResourceHolderState xarhs1 = new XAResourceHolderState(null, new MockResourceBean(1)); resourceScheduler.add(xarhs0, xarhs0.getTwoPcOrderingPosition()); resourceScheduler.add(xarhs1, xarhs1.getTwoPcOrderingPosition()); resourceScheduler.remove(xarhs0); resourceScheduler.add(xarhs0, xarhs0.getTwoPcOrderingPosition()); Iterator<XAResourceHolderState> it = resourceScheduler.reverseIterator(); assertTrue(it.hasNext()); assertTrue(xarhs1 == it.next()); it.remove(); assertTrue(xarhs0 == it.next()); it.remove(); }
XAResourceHolderState alreadyEnlistedHolder = findXAResourceHolderState(xaResourceHolderState.getXAResource()); if (alreadyEnlistedHolder != null && !alreadyEnlistedHolder.isEnded()) { xaResourceHolderState.setXid(alreadyEnlistedHolder.getXid()); log.warn("ignoring enlistment of already enlisted but not ended resource " + xaResourceHolderState); return; xid = toBeJoinedHolderState.getXid(); flag = XAResource.TMJOIN; if (flag != XAResource.TMJOIN && xaResourceHolderState.getTwoPcOrderingPosition() == Scheduler.ALWAYS_LAST_POSITION && !TransactionManagerServices.getConfiguration().isAllowMultipleLrc()) { List<XAResourceHolderState> alwaysLastResources = resources.getByNaturalOrderForPosition(Scheduler.ALWAYS_LAST_POSITION); xaResourceHolderState.setXid(xid); xaResourceHolderState.start(flag); resources.add(xaResourceHolderState, xaResourceHolderState.getTwoPcOrderingPosition());
private void forgetHeuristicCommit(XAResourceHolderState resourceHolder) { try { if (log.isDebugEnabled()) log.debug("handling heuristic commit on resource " + resourceHolder.getXAResource()); resourceHolder.getXAResource().forget(resourceHolder.getXid()); if (log.isDebugEnabled()) log.debug("forgotten heuristically committed resource " + resourceHolder.getXAResource()); } catch (XAException ex) { String extraErrorDetails = TransactionManagerServices.getExceptionAnalyzer().extractExtraXAExceptionDetails(ex); log.error("cannot forget " + resourceHolder.getXid() + " assigned to " + resourceHolder.getXAResource() + ", error=" + Decoder.decodeXAExceptionErrorCode(ex) + (extraErrorDetails == null ? "" : ", extra error=" + extraErrorDetails), ex); } }
/** * Resume all enlisted resources in the current transaction context. * @throws XAException if the resource threw an exception during resume. */ public void resume() throws XAException { // all XAResource needs to be re-enlisted but this must happen // outside the Scheduler's iteration as enlist() can change the // collection's content and confuse the iterator. List<XAResourceHolderState> toBeReEnlisted = new ArrayList<XAResourceHolderState>(); for (XAResourceHolderState xaResourceHolderState : resources) { if (log.isDebugEnabled()) log.debug("resuming " + xaResourceHolderState); // If a prepared statement is (re-)used after suspend/resume is performed its XAResource needs to be // re-enlisted. This must be done outside this loop or that will confuse the iterator! toBeReEnlisted.add(new XAResourceHolderState(xaResourceHolderState)); } if (toBeReEnlisted.size() > 0 && log.isDebugEnabled()) log.debug("re-enlisting " + toBeReEnlisted.size() + " resource(s)"); for (XAResourceHolderState xaResourceHolderState : toBeReEnlisted) { if (log.isDebugEnabled()) log.debug("re-enlisting resource " + xaResourceHolderState); try { enlist(xaResourceHolderState); xaResourceHolderState.getXAResourceHolder().putXAResourceHolderState(xaResourceHolderState.getXid(), xaResourceHolderState); } catch (BitronixSystemException ex) { throw new BitronixXAException("error re-enlisting resource during resume: " + xaResourceHolderState, XAException.XAER_RMERR, ex); } } }
/** * Search for an eventually already enlisted {@link XAResourceHolderState} that could be joined with the * {@link XAResourceHolderState} passed as parameter.<br/> * If datasource configuration property <code>bitronix.useTmJoin=false</code> is set this method always returns null. * @param xaResourceHolderState a {@link XAResourceHolderState} looking to be joined. * @return another enlisted {@link XAResourceHolderState} that can be joined with the one passed in or null if none is found. * @throws XAException if call to XAResource.isSameRM() fails. */ private XAResourceHolderState getManagedResourceWithSameRM(XAResourceHolderState xaResourceHolderState) throws XAException { if (!xaResourceHolderState.getUseTmJoin()) { if (log.isDebugEnabled()) log.debug("join disabled on resource " + xaResourceHolderState); return null; } for (XAResourceHolderState alreadyEnlistedHolderState : resources) { if (log.isDebugEnabled()) log.debug("checking joinability of " + xaResourceHolderState + " with " + alreadyEnlistedHolderState); if (alreadyEnlistedHolderState.isEnded() && !alreadyEnlistedHolderState.isSuspended() && xaResourceHolderState.getXAResource().isSameRM(alreadyEnlistedHolderState.getXAResource())) { if (log.isDebugEnabled()) log.debug("resources are joinable"); return alreadyEnlistedHolderState; } if (log.isDebugEnabled()) log.debug("resources are not joinable"); } if (log.isDebugEnabled()) log.debug("no joinable resource found for " + xaResourceHolderState); return null; }
protected static Set<String> collectResourcesUniqueNames(List<XAResourceHolderState> resources) { Set<String> uniqueNames = new HashSet<String>(); for (XAResourceHolderState resourceHolderState : resources) { uniqueNames.add(resourceHolderState.getUniqueName()); } return uniqueNames; }