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

com.sun.jts.CosTransactions.RecoveryCoordinatorImpl Maven / Gradle / Ivy

There is a newer version: 8.0.0-JDK17-M9
Show newest version
/*
 * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
 * Copyright (c) 1995-1997 IBM Corp. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

//----------------------------------------------------------------------------
//
// Module:      RecoveryCoordinatorImpl.java
//
// Description: Transaction RecoveryCoordinator object implementation.
//
// Product:     com.sun.jts.CosTransactions
//
// Author:      Simon Holdsworth
//
// Date:        March, 1997
//----------------------------------------------------------------------------

package com.sun.jts.CosTransactions;

import com.sun.jts.utils.LogFormatter;
import com.sun.logging.LogDomains;

import java.util.logging.Level;
import java.util.logging.Logger;

import org.omg.CORBA.SystemException;
import org.omg.CosTransactions.HeuristicCommit;
import org.omg.CosTransactions.HeuristicHazard;
import org.omg.CosTransactions.HeuristicMixed;
import org.omg.CosTransactions.NotPrepared;
import org.omg.CosTransactions.RecoveryCoordinator;
import org.omg.CosTransactions.RecoveryCoordinatorHelper;
import org.omg.CosTransactions.RecoveryCoordinatorPOA;
import org.omg.CosTransactions.Resource;
import org.omg.CosTransactions.Status;
import org.omg.PortableServer.POA;

/**
 * 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
 */

//----------------------------------------------------------------------------
// CHANGE HISTORY
//
// Version By     Change Description
//   0.01  SAJH   Initial implementation.
//   0.02  GDH    Gordon Hutchison April 1998
//                Added in COMMITTING to replay_completion
//-----------------------------------------------------------------------------

class RecoveryCoordinatorImpl extends RecoveryCoordinatorPOA {

    private static boolean recoverable = false;
    private static POA poa = null;
    private RecoveryCoordinator thisRef = null;
    private int internalSeq = 0;
    /*
        Logger to log transaction messages
    */
    static Logger _logger = LogDomains.getLogger(RecoveryCoordinatorImpl.class, LogDomains.TRANSACTION_LOGGER);
    GlobalTID globalTID = null;

    RecoveryCoordinatorImpl() {}

    /**
     * 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 */ RecoveryCoordinatorImpl(GlobalTID globalTID, int sequence) { 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); */ } /** * 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 */ public Status replay_completion(Resource res) throws NotPrepared { 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; } // same as replay_completion(res) : added for delegated recovery support public Status replay_completion(Resource res, String logPath) throws NotPrepared { 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; } /** * 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 */ void rollbackOrphan(Resource res) { 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(); } /** * 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 */ RecoveryCoordinatorImpl(byte[] key) { // 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. } /** * Returns the CORBA Object which represents this object. * * @param * * @return The CORBA object. * * @see */ synchronized final RecoveryCoordinator object() { 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; } /** * Destroys the RecoveryCoordinatorImpl object. * * @param * * @return * * @see */ synchronized final void destroy() { 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"); } globalTID = null; internalSeq = 0; } } /** * This class is provided to allow a Resource to be rolled back by the * RecoveryCoordinator on a new thread. This is required for * Resource objects which are proxies because deadlock would occur * if the rollback was called from the same thread as the one on * which the replay_completion was executing. * * @version 0.01 * * @author Simon Holdsworth, IBM Corporation * * @see */ class OrphanRollbackThread extends Thread { Resource resource = null; RecoveryCoordinatorImpl recovery = null; /** * OrphanRollbackThread constructor. * * @param recovery * @param resource * * @return * * @see */ OrphanRollbackThread(RecoveryCoordinatorImpl recovery, Resource resource) { this.resource = resource; this.recovery = recovery; setName("JTS Orphan Rollback Thread"/*#Frozen*/); } /** * Calls the RecoveryCoordinator to rollback the Resource. * * @param * * @return * * @see */ public void run() { recovery.rollbackOrphan(resource); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy