All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.infinispan.transaction.xa.recovery.RecoveryAwareTransactionTable Maven / Gradle / Ivy

There is a newer version: 9.1.7.Final
Show newest version
package org.infinispan.transaction.xa.recovery;

import org.infinispan.commons.CacheException;
import org.infinispan.factories.annotations.Inject;
import org.infinispan.remoting.transport.Address;
import org.infinispan.transaction.impl.LocalTransaction;
import org.infinispan.transaction.impl.RemoteTransaction;
import org.infinispan.transaction.xa.GlobalTransaction;
import org.infinispan.transaction.xa.LocalXaTransaction;
import org.infinispan.transaction.xa.XaTransactionTable;
import org.infinispan.util.logging.Log;
import org.infinispan.util.logging.LogFactory;

import javax.transaction.Transaction;
import javax.transaction.xa.Xid;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Transaction table that delegates prepared transaction's management to the {@link RecoveryManager}.
 *
 * @author [email protected]
 * @since 5.0
 */
public class RecoveryAwareTransactionTable extends XaTransactionTable {

   private static final Log log = LogFactory.getLog(RecoveryAwareTransactionTable.class);
   private static final boolean trace = log.isTraceEnabled();

   private RecoveryManagerImpl recoveryManager;

   @Inject
   public void initialize(RecoveryManager recoveryManager) {
      this.recoveryManager = (RecoveryManagerImpl) recoveryManager;
   }

   /**
    * Marks the transaction as prepared. If at a further point the originator fails, the transaction is removed form the
    * "normal" transactions collection and moved into the cache that holds in-doubt transactions.
    * See {@link #cleanupLeaverTransactions(java.util.List)}
    */
   @Override
   public void remoteTransactionPrepared(GlobalTransaction gtx) {
      RecoveryAwareRemoteTransaction remoteTransaction =
            (RecoveryAwareRemoteTransaction) getRemoteTransaction(gtx);
      if (remoteTransaction == null)
         throw new CacheException(String.format(
               "Remote transaction for global transaction (%s) not found", gtx));
      remoteTransaction.setPrepared(true);
   }

   /**
    * @see #localTransactionPrepared(org.infinispan.transaction.impl.LocalTransaction)
    */
   @Override
   public void localTransactionPrepared(LocalTransaction localTransaction) {
      ((RecoveryAwareLocalTransaction) localTransaction).setPrepared(true);
   }

   /**
    * First moves the prepared transactions originated on the leavers into the recovery cache and then cleans up the
    * transactions that are not yet prepared.
    * @param members The list of cluster members
    */
   @Override
   public void cleanupLeaverTransactions(List
members) { Iterator it = getRemoteTransactions().iterator(); while (it.hasNext()) { RecoveryAwareRemoteTransaction recTx = (RecoveryAwareRemoteTransaction) it.next(); recTx.computeOrphan(members); if (recTx.isInDoubt()) { recoveryManager.registerInDoubtTransaction(recTx); it.remove(); } } //this cleans up the transactions that are not yet prepared super.cleanupLeaverTransactions(members); } @Override public RemoteTransaction getRemoteTransaction(GlobalTransaction txId) { RemoteTransaction remoteTransaction = super.getRemoteTransaction(txId); if (remoteTransaction != null) return remoteTransaction; //also look in the recovery manager, as this transaction might be prepared return recoveryManager.getPreparedTransaction(((RecoverableTransactionIdentifier) txId).getXid()); } @Override public void remoteTransactionRollback(GlobalTransaction gtx) { super.remoteTransactionRollback(gtx); recoveryManager.removeRecoveryInformation(((RecoverableTransactionIdentifier) gtx).getXid()); } @Override public void remoteTransactionCommitted(GlobalTransaction gtx, boolean onePc) { RecoveryAwareRemoteTransaction remoteTransaction = (RecoveryAwareRemoteTransaction) getRemoteTransaction(gtx); if (remoteTransaction == null) throw new CacheException(String.format("Remote transaction for global transaction (%s) not found", gtx)); remoteTransaction.markCompleted(true); super.remoteTransactionCommitted(gtx, onePc); } public List getLocalPreparedXids() { List result = new LinkedList(); for (Map.Entry e : xid2LocalTx.entrySet()) { RecoveryAwareLocalTransaction value = (RecoveryAwareLocalTransaction) e.getValue(); if (value.isPrepared()) { result.add(e.getKey()); } } return result; } @Override public void failureCompletingTransaction(Transaction tx) { // TODO Change the Transaction parameter to LocalTransaction to avoid the reverse lookup and the // NullPointerException when called from RecoveryManagerImpl.forceTransactionCompletion RecoveryAwareLocalTransaction localTx = (RecoveryAwareLocalTransaction) getLocalTransaction(tx); if (localTx == null) throw new CacheException(String.format("Local transaction for transaction (%s) not found", tx)); localTx.setCompletionFailed(true); log.tracef("Marked as completion failed %s", localTx); } public Set getLocalTxThatFailedToComplete() { Set result = new HashSet(4); for (LocalTransaction lTx : xid2LocalTx.values()) { RecoveryAwareLocalTransaction lTx1 = (RecoveryAwareLocalTransaction) lTx; if (lTx1.isCompletionFailed()) { result.add(lTx1); } } return result; } /** * Iterates over the remote transactions and returns the XID of the one that has an internal id equal with the * supplied internal Id. */ public Xid getRemoteTransactionXid(Long internalId) { for (RemoteTransaction rTx : getRemoteTransactions()) { RecoverableTransactionIdentifier gtx = (RecoverableTransactionIdentifier) rTx.getGlobalTransaction(); if (gtx.getInternalId() == internalId) { if (trace) log.tracef("Found xid %s matching internal id %s", gtx.getXid(), internalId); return gtx.getXid(); } } if (trace) log.tracef("Could not find remote transactions matching internal id %s", internalId); return null; } public RemoteTransaction removeRemoteTransaction(Xid xid) { if (clustered) { Iterator it = getRemoteTransactions().iterator(); while (it.hasNext()) { RemoteTransaction next = it.next(); RecoverableTransactionIdentifier gtx = (RecoverableTransactionIdentifier) next.getGlobalTransaction(); if (xid.equals(gtx.getXid())) { it.remove(); recalculateMinTopologyIdIfNeeded(next); next.notifyOnTransactionFinished(); return next; } } } return null; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy