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

com.atomikos.icatch.imp.CompositeTransactionImp Maven / Gradle / Ivy

/**
 * Copyright (C) 2000-2016 Atomikos 
 *
 * LICENSE CONDITIONS
 *
 * See http://www.atomikos.com/Main/WhichLicenseApplies for details.
 */

package com.atomikos.icatch.imp;

import java.util.Map;
import java.util.Stack;

import com.atomikos.finitestates.FSMEnterEvent;
import com.atomikos.finitestates.FSMEnterListener;
import com.atomikos.icatch.CompositeCoordinator;
import com.atomikos.icatch.CompositeTransaction;
import com.atomikos.icatch.Extent;
import com.atomikos.icatch.HeurHazardException;
import com.atomikos.icatch.HeurMixedException;
import com.atomikos.icatch.HeurRollbackException;
import com.atomikos.icatch.Participant;
import com.atomikos.icatch.RecoveryCoordinator;
import com.atomikos.icatch.RollbackException;
import com.atomikos.icatch.SubTxAwareParticipant;
import com.atomikos.icatch.Synchronization;
import com.atomikos.icatch.SysException;
import com.atomikos.logging.Logger;
import com.atomikos.logging.LoggerFactory;
import com.atomikos.recovery.TxState;

/**
 * A complete composite transaction implementation for use in the local VM.
 */

class CompositeTransactionImp extends AbstractCompositeTransaction implements FSMEnterListener
{
	private static final long serialVersionUID = 975317723773209940L;

	private static final Logger LOGGER = LoggerFactory.createLogger(CompositeTransactionImp.class);

	private CoordinatorImp coordinator = null;

	private TransactionServiceImp txservice;

	private Extent extent = null;

    protected boolean noLocalAncestors;

    private TransactionStateHandler stateHandler;

    /**
     * This constructor is kept for compatibility with the test classes.
     */

    CompositeTransactionImp ( Stack lineage , String tid , boolean serial ,
            CoordinatorImp coordinator )
    {
        this ( null , lineage , tid , serial , coordinator );
    }

    /**
     * Constructor.
     *
     * @param txservice
     *            The Transaction Service this is for.
     * @param lineage
     *            The ancestor information.
     * @param tid
     *            The identifier for this one.
     * @param serial
     *            If true, no parallel calls allowed.
     * @param coordinator
     *            The coordinator to use.
     * @exception IllegalStateException
     *                If coordinator no longer activatable.
     */

    CompositeTransactionImp ( TransactionServiceImp txservice ,
            Stack lineage , String tid , boolean serial ,
            CoordinatorImp coordinator ) throws IllegalStateException
    {

        super ( tid , lineage , serial );
        this.coordinator = coordinator;
        this.txservice = txservice;
        this.extent = null;
        this.noLocalAncestors = true;
        this.stateHandler = new TxActiveStateHandler ( this );
        coordinator.addFSMEnterListener ( this, TxState.TERMINATED );

    }

    synchronized void localSetTransactionStateHandler ( TransactionStateHandler handler )
    {
        stateHandler = handler;
    }

    synchronized void localTestAndSetTransactionStateHandler ( TransactionStateHandler expected , TransactionStateHandler newHandler )
    {
    	if ( stateHandler != expected ) throw new IllegalStateException ( "State is no longer " + expected.getState() + " but " + newHandler.getState()  );
    	localSetTransactionStateHandler( newHandler );
    }

    synchronized TransactionStateHandler localGetTransactionStateHandler()
    {
    	return stateHandler;
    }

    boolean isLocalRoot ()
    {
        return noLocalAncestors;
    }

    TransactionServiceImp getTransactionService ()
    {
        return txservice;
    }

    CoordinatorImp getCoordinatorImp ()
    {
        return coordinator;
    }

    public int getLocalSubTxCount ()
    {
        return localGetTransactionStateHandler().getSubTransactionCount ();
    }

    public synchronized void setSerial () throws IllegalStateException,
            SysException
    {
        if ( !isRoot () ) throw new IllegalStateException ( "Not a root tx." );
        serial_ = true;
    }


    /**
     * @see TransactionControl.
     */

    public CompositeTransaction createSubTransaction () throws SysException,
            IllegalStateException
    {
        CompositeTransaction ret = localGetTransactionStateHandler().createSubTransaction ();
        if(LOGGER.isDebugEnabled()){
        	LOGGER.logDebug("createSubTransaction(): created new SUBTRANSACTION "
                    + ret.getTid () + " for existing transaction " + getTid ());
        }

        return ret;
    }

    /**
     * @see CompositeTransaction
     */

    public RecoveryCoordinator addParticipant ( Participant participant )
            throws SysException, java.lang.IllegalStateException
    {

        RecoveryCoordinator ret = localGetTransactionStateHandler().addParticipant ( participant );
        if(LOGGER.isDebugEnabled()){
        	LOGGER.logDebug("addParticipant ( " + participant + " ) for transaction "
                    + getTid ());
        }
        return ret;
    }

    /**
     * @see CompositeTransaction
     */

    public void registerSynchronization ( Synchronization sync ) throws // RollbackException,
            IllegalStateException, UnsupportedOperationException, SysException
    {
    	localGetTransactionStateHandler().registerSynchronization ( sync );
    	if(LOGGER.isDebugEnabled()){
    		LOGGER.logDebug("registerSynchronization ( " + sync + " ) for transaction "
                    + getTid ());
    	}
    }

    /**
     * @see CompositeTransaction
     */

    public void addSubTxAwareParticipant ( SubTxAwareParticipant subtxaware )
            throws SysException, java.lang.IllegalStateException
    {
    	localGetTransactionStateHandler().addSubTxAwareParticipant ( subtxaware );
    }

    /**
     * @see TransactionControl.
     */

    protected void doRollback () throws java.lang.IllegalStateException,
            SysException
    {
    	localGetTransactionStateHandler().rollbackWithStateCheck ();
    	if(LOGGER.isDebugEnabled()){
    		LOGGER.logDebug("rollback() done of transaction " + getTid ());
    	}

    }

    /**
     * @see CompositeTransaction.
     */

    public CompositeCoordinator getCompositeCoordinator () throws SysException
    {
        return coordinator;
    }

    /**
     * @see CompositeTransaction.
     */

    public boolean isLocal ()
    {
        return true;
    }

    /**
     * Successfully end the composite transaction. Marks it as inactive. Called
     * by Terminator implementation only! NOTE: this does NOT commit the
     * participants, but rather only marks the (sub)transaction as being
     * ELIGIBLE FOR PREPARE IN 2PC.
     *
     * @exception IllegalStateException
     *                If no longer active.
     * @exception SysException
     *                Unexpected failure.
     */

    protected void doCommit () throws SysException,
            java.lang.IllegalStateException, RollbackException
    {

    	localGetTransactionStateHandler().commit ();
    	if(LOGGER.isDebugEnabled()){
    		LOGGER.logDebug("commit() done (by application) of transaction " + getTid ());
    	}
    }

    public long getTimeout ()
    {
        return coordinator.getTimeOut ();
    }

    public synchronized Extent getExtent ()
    {
    		if ( extent == null )
            extent = new ExtentImp ();
    		return extent;
    }

    public void setRollbackOnly ()
    {
    	localGetTransactionStateHandler().setRollbackOnly ();
    	if(LOGGER.isDebugEnabled()){
    		LOGGER.logDebug("setRollbackOnly() called for transaction " + getTid ());
    	}


    }

    /**
     * @see com.atomikos.icatch.CompositeTransaction#commit()
     */
    public void commit () throws HeurRollbackException, HeurMixedException,
            HeurHazardException, SysException, SecurityException,
            RollbackException
    {
        doCommit ();
        setSiblingInfoForIncoming1pcRequestFromRemoteClient();
        
        if ( isRoot () ) {
            try {
                coordinator.terminate ( true );
            }

            catch ( RollbackException rb ) {
                throw rb;
            } catch ( HeurHazardException hh ) {
                throw hh;
            } catch ( HeurRollbackException hr ) {
                throw hr;
            } catch ( HeurMixedException hm ) {
                throw hm;
            } catch ( SysException se ) {
                throw se;
            } catch ( Exception e ) {
                throw new SysException (
                        "Unexpected error: " + e.getMessage (), e );
            }
        }
    }

    private void setSiblingInfoForIncoming1pcRequestFromRemoteClient() {
    	Map cascadelist = getExtent().getRemoteParticipants ();
        coordinator.setGlobalSiblingCount ( coordinator.getLocalSiblingCount () );
        coordinator.setCascadeList ( cascadelist );
	}


    /**
     * @see com.atomikos.icatch.CompositeTransaction#rollback()
     */
    public void rollback () throws IllegalStateException, SysException
    {
    	doRollback ();
        if ( isRoot () ) {
            try {
                coordinator.terminate ( false );
            } catch ( Exception e ) {
                throw new SysException ( "Unexpected error in rollback: " + e.getMessage (), e );
            }
        }
    }

    /**
     * @see com.atomikos.finitestates.Stateful.
     */

    public TxState getState ()
    {
        return localGetTransactionStateHandler().getState ();
    }

    /**
     * @see com.atomikos.finitestates.FSMEnterListener#preEnter(com.atomikos.finitestates.FSMEnterEvent)
     */
    public void entered ( FSMEnterEvent coordinatorTerminatedEvent )
    {
        if (getState().isOneOf(TxState.ACTIVE,TxState.MARKED_ABORT )) {
        	// our coordinator terminated and we did not -> coordinator must have seen a timeout/abort 
            try {
            	if (!( stateHandler instanceof TxTerminatedStateHandler ) ) {
            		// note: check for TxTerminatedStateHandler differentiates regular rollback from timeout/rollback !!!           		          		
            		setRollbackOnly(); // see case 27857: keep tx context for thread on timeout
            	} else  {
            		rollback();
            	}

            } catch ( Exception e ) {
                // ignore but log
            	LOGGER.logTrace("Ignoring error during event callback",e);
            }
        }

    }


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy