FileDocCategorySizeDatePackage
RecoveryCoordinatorImpl.javaAPI DocGlassfish v2 API21156Wed Jun 13 23:03:46 BST 2007com.sun.jts.CosTransactions

RecoveryCoordinatorImpl

public class RecoveryCoordinatorImpl extends RecoveryCoordinatorPOA
The RecoveryCoordinatorImpl interface is our implementation of the standard RecoveryCoordinator interface. It allows recoverable objects to drive the recovery process in certain situations. Each instance of this class is implicitly associated with a single resource registration, and may only be used by that resource in that particular transaction for which it is registered. An instance of this class should be accessed from only one thread within a process.
version
0.02
author
Simon Holdsworth, IBM Corporation
see

Fields Summary
private static boolean
recoverable
private static POA
poa
private RecoveryCoordinator
thisRef
private int
internalSeq
static Logger
_logger
GlobalTID
globalTID
Constructors Summary
RecoveryCoordinatorImpl()


	 
RecoveryCoordinatorImpl(GlobalTID globalTID, int sequence)
Sets up the RecoveryCoordinator with the global identifier.

This is so that it can always find the Coordinator to inform it of the requirement for recovery of the given Resource.

An internal sequence number is used to differentiate RecoveryCoordinator objects used for the same Coordinator object within a process. This is so that they each get a unique object identifier.

param
globalTID The global transaction identifier.
param
sequence An internal sequence number to differentiate objects.
return
see


        this.globalTID = globalTID;
        internalSeq = sequence;

        // MODIFICATION (Ram Jeyaraman) comment out the code
        // below, as it does nothing.
        /*
        byte[] tidBytes = globalTID.toBytes();
        byte[] id = new byte[tidBytes.length + 4];
        System.arraycopy(tidBytes, 0, id, 4, tidBytes.length);
        id[0] = (byte) internalSeq;
        id[1] = (byte)(internalSeq >> 8);
        id[2] = (byte)(internalSeq >> 16);
        id[3] = (byte)(internalSeq >> 24);
        */
    
RecoveryCoordinatorImpl(byte[] key)
Creates the RecoveryCoordinatorImpl with the given key.

This is done when the RecoveryCoordinator object is recreated after the server has been restarted.

The first four bytes of the key are an internal sequence number used to differentiate RecoveryCoordinator objects created in the same process for the same transaction.

The rest of the key is the global transaction identifier.

param
key The key for the object.
return
see


        // Get the global transaction identifier from the key.

        byte[] tidBytes = new byte[key.length - 4];

        // BUGFIX (Ram Jeyaraman) changed the order of array copy.
        // previously, an source and destination array was wrong.
        //System.arraycopy(tidBytes, 0, key, 4, tidBytes.length);
        System.arraycopy(key, 4, tidBytes, 0, tidBytes.length);
        
        globalTID = new GlobalTID(tidBytes);

        // Ensure that recovery has completed so that
        // we can get the Coordinator.

        RecoveryManager.waitForRecovery();

        // Leave other members at the default values.
    
Methods Summary
final synchronized voiddestroy()
Destroys the RecoveryCoordinatorImpl object.

param
return
see


        try {
            if (poa != null && thisRef != null) {
                poa.deactivate_object(poa.reference_to_id(thisRef));
                thisRef = null;
            } else {
                // BUGFIX(Ram J) It is possible that the
                // RecoveryCoordinator object was activated via the activation
                // daemon. In that case, there is no guarantee
                // that poa and thisRef are set to a meaningful value.
                // So, try to deactivate the RecoveryCoordinator object anyway.

                POA rcPoa = null;
                if (poa == null) {
                    rcPoa = Configuration.getPOA("RecoveryCoordinator"/*#Frozen*/);
                } else {
                    rcPoa = poa;
                }

                if (thisRef == null) {
                    rcPoa.deactivate_object(rcPoa.servant_to_id(this));
                } else {
                    rcPoa.deactivate_object(rcPoa.reference_to_id(thisRef));
                    thisRef = null;
                }
            }
        } catch( Exception exc ) {
				_logger.log(Level.WARNING,"jts.object_destroy_error","RecoveryCoordinator");
        }

        //finalize();
        globalTID = null;
        internalSeq = 0;
    
final synchronized RecoveryCoordinatorobject()
Returns the CORBA Object which represents this object.

param
return
The CORBA object.
see


        if (thisRef == null) {
            if (poa == null) {
                poa = Configuration.getPOA("RecoveryCoordinator"/*#Frozen*/);
                recoverable = Configuration.isRecoverable();
            }

            try {

                if (recoverable && globalTID != null) {
                    // Create the object id from the global transaction
                    // identifier and the internal sequence number.

                    byte[] tidBytes = globalTID.toBytes();
                    byte[] id = new byte[tidBytes.length + 4];
                    System.arraycopy(tidBytes, 0, id, 4, tidBytes.length);
                    id[0] = (byte) internalSeq;
                    id[1] = (byte)(internalSeq >> 8);
                    id[2] = (byte)(internalSeq >> 16);
                    id[3] = (byte)(internalSeq >> 24);

                    // Activate the object and create the reference.

                    poa.activate_object_with_id(id, this);

                    org.omg.CORBA.Object obj =
                        poa.create_reference_with_id(
                            id, RecoveryCoordinatorHelper.id());
                    thisRef = RecoveryCoordinatorHelper.narrow(obj);
                    //thisRef = (RecoveryCoordinator) this;
                } else {
                    poa.activate_object(this);
                    org.omg.CORBA.Object obj = poa.servant_to_reference(this);
                    thisRef = RecoveryCoordinatorHelper.narrow(obj);
                    //thisRef = (RecoveryCoordinator)this;
                }
            } catch(Exception exc) {
				_logger.log(Level.SEVERE,"jts.create_recoverycoordinator_error");
				 String msg = LogFormatter.getLocalizedMessage(_logger,
				 						"jts.create_recoverycoordinator_error");
				  throw  new org.omg.CORBA.INTERNAL(msg);
            }
        }

        return thisRef;
    
public Statusreplay_completion(Resource res)
Informs the Transaction Service that the given Resource object has been prepared but has not received a commit or rollback operation.

If the transaction outcome is unknown, the Resource object passed on this operation will be called at some later time for commit or rollback.

param
res The Resource to be recovered.
return
The state of the transaction.
exception
NotPrepared The transaction for which the RecoveryCoordinator was created has not prepared.
see

	
		if(_logger.isLoggable(Level.FINE))
        {
			 _logger.logp(Level.FINE,"RecoveryCoordinatorImpl",
			 		"replay_completion()","replay_completion on Resource:"+
					res);
        }


        Status result = Status.StatusRolledBack;

        CoordinatorImpl coord = RecoveryManager.getCoordinator(globalTID);
        if (coord != null) {
            try {
                result = coord.get_status();
            } catch (SystemException exc) {}
        }

        switch (result.value()) {

        /*
         * If the transaction is still active, raise the NotPrepared
         * exception. The Coordinator must be marked rollback-only at
         * this point because we cannot allow the transaction to
         * complete if a participant has failed.
         */

        case Status._StatusActive :
        case Status._StatusMarkedRollback :
            try {
                coord.rollback_only();
            } catch (Throwable exc) {}

            throw new NotPrepared();

        /*
         * If the transaction is prepared, the caller must wait for the
         * Coordinator to tell it what to do, so return an unknown status, and
         * do nothing.  Note that if this Coordinator is sitting waiting for
         * its superior, this could take a int time.
         */

        case Status._StatusPrepared :
            result = Status.StatusUnknown;
            break;

        /*
         * If the transaction has been committed, the caller will receive
         * a commit.
         *
         * GDH If the transaction is commiting then we pass this on
         * to the caller. This state (added in OTS 1.1 means that
         * TopCoordinator.recover must now accept the COMMITTING state.
         */

        case Status._StatusCommitting :
            // MODIFICATION (Ram Jeyaraman) commented out the code below,
            // since a StatusCommitting will be upgraded to Committed in
            // the subordinate.
            /*
            // (Ram Jeyaraman) let the subordinate wait, and allow the root
            // finish driving the commit.
            result = Status.StatusUnknown;
            */
            break;

        case Status._StatusCommitted :
            break;

        case Status._StatusRolledBack :

            // If the transaction has been rolled back, and there is
            // no Coordinator for the transaction, we must invoke rollback
            // directly, as it will not be done otherwise.  However for
            // proxies, this rollback cannot be done from this thread as
            // it would cause deadlock in the server requesting resync.

            if (coord == null) {

                if (!Configuration.getProxyChecker().isProxy(res)) {
                    rollbackOrphan(res);
                } else {

                    // We must pass a duplicate of the proxy to the
                    // rollback thread because this proxy will be destroyed
                    // when the replay_completion request returns
                    // to the remote server.

                    try {
                        OrphanRollbackThread rollbackThread =
                            new OrphanRollbackThread(
                                this, (Resource) res._duplicate());
                        rollbackThread.start();
                    } catch (SystemException exc) {}
                }
            }

            break;

        /*
         * In any other situation, assume that the transaction has been rolled
         * back. As there is a Coordinator, it will direct the Resource to roll
         * back.
         */

        default :
            result = Status.StatusRolledBack;
        }

        return result;
    
public Statusreplay_completion(Resource res, java.lang.String logPath)

	
        if(_logger.isLoggable(Level.FINE))
        {
	     _logger.logp(Level.FINE,"RecoveryCoordinatorImpl",
			"replay_completion()","replay_completion on Resource:"+ res);
        }

        Status result = Status.StatusRolledBack;

        CoordinatorImpl coord = DelegatedRecoveryManager.getCoordinator(globalTID, logPath);
        if (coord != null) {
            try {
                result = coord.get_status();
            } catch (SystemException exc) {}
        }

        switch (result.value()) {

        /*
         * If the transaction is still active, raise the NotPrepared
         * exception. The Coordinator must be marked rollback-only at
         * this point because we cannot allow the transaction to
         * complete if a participant has failed.
         */

        case Status._StatusActive :
        case Status._StatusMarkedRollback :
            try {
                coord.rollback_only();
            } catch (Throwable exc) {}

            throw new NotPrepared();

        /*
         * If the transaction is prepared, the caller must wait for the
         * Coordinator to tell it what to do, so return an unknown status, and
         * do nothing.  Note that if this Coordinator is sitting waiting for
         * its superior, this could take a int time.
         */

        case Status._StatusPrepared :
            result = Status.StatusUnknown;
            break;

        /*
         * If the transaction has been committed, the caller will receive
         * a commit.
         *
         * GDH If the transaction is commiting then we pass this on
         * to the caller. This state (added in OTS 1.1 means that
         * TopCoordinator.recover must now accept the COMMITTING state.
         */

        case Status._StatusCommitting :
            // MODIFICATION (Ram Jeyaraman) commented out the code below,
            // since a StatusCommitting will be upgraded to Committed in
            // the subordinate.
            /*
            // (Ram Jeyaraman) let the subordinate wait, and allow the root
            // finish driving the commit.
            result = Status.StatusUnknown;
            */
            break;

        case Status._StatusCommitted :
            break;

        case Status._StatusRolledBack :

            // If the transaction has been rolled back, and there is
            // no Coordinator for the transaction, we must invoke rollback
            // directly, as it will not be done otherwise.  However for
            // proxies, this rollback cannot be done from this thread as
            // it would cause deadlock in the server requesting resync.

            if (coord == null) {

                if (!Configuration.getProxyChecker().isProxy(res)) {
                    rollbackOrphan(res);
                } else {

                    // We must pass a duplicate of the proxy to the
                    // rollback thread because this proxy will be destroyed
                    // when the replay_completion request returns
                    // to the remote server.

                    try {
                        OrphanRollbackThread rollbackThread =
                            new OrphanRollbackThread(
                                this, (Resource) res._duplicate());
                        rollbackThread.start();
                    } catch (SystemException exc) {}
                }
            }

            break;

        /*
         * In any other situation, assume that the transaction has been rolled
         * back. As there is a Coordinator, it will direct the Resource to roll
         * back.
         */

        default :
            result = Status.StatusRolledBack;
        }

        return result;
    
voidrollbackOrphan(Resource res)
This method invoked rollback on the Resource that is passed as a parameter.

This procedure may be called as the main procedure of a new thread, which must be done for remote Resource objects during resync to avoid the possibility of deadlock during resync.

It is called directly when the Resource is not a proxy.

param
res The Resource to be rolled back.
return
see


        try {
            res.rollback();
        } catch(Throwable exc) {

            // If the rollback raised a heuristic exception, it can
            // only be reported in a message as it will never reach
            // the Coordinator.

            if (exc instanceof HeuristicCommit ||
                    exc instanceof HeuristicMixed ||
                    exc instanceof HeuristicHazard) {
				_logger.log(Level.WARNING,"jts.heuristic_exception",exc.toString());
            } else {}
        }

        // We must release the proxy now.

        res._release();