com.sun.jts.CosTransactions.RegisteredResources Maven / Gradle / Ivy
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2011 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
//----------------------------------------------------------------------------
//
// Module: RegisteredResources.java
//
// Description: Transaction participant management.
//
// Product: com.sun.jts.CosTransactions
//
// Author: Simon Holdsworth
//
// Date: March, 1997
//
// Copyright (c): 1995-1997 IBM Corp.
//
// The source code for this program is not published or otherwise divested
// of its trade secrets, irrespective of what has been deposited with the
// U.S. Copyright Office.
//
// This software contains confidential and proprietary information of
// IBM Corp.
//----------------------------------------------------------------------------
package com.sun.jts.CosTransactions;
import java.util.*;
import org.omg.CORBA.*;
import org.omg.CosTransactions.*;
import com.sun.jts.codegen.otsidl.*;
import com.sun.jts.trace.*;
import com.sun.jts.jtsxa.OTSResourceImpl;
import java.util.logging.Logger;
import java.util.logging.Level;
import com.sun.logging.LogDomains;
import com.sun.jts.utils.LogFormatter;
import javax.transaction.xa.*;
/**
* The RegisteredResources class provides operations that manage a list
* of Resource objects involved in a transaction, and their states relative
* to the transaction. Resource references are stored in lists as there is no
* way to perform Resource reference comparisons. As an instance of this
* class may be accessed from multiple threads within a process,
* serialisation for thread-safety is necessary in the implementation.
* The information recorded in an instance of this class needs to be
* reconstructible in the case of a system failure.
*
* @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 OBLECT_NOT_EXIST as an allowable exception in
// distribute rollback.
//----------------------------------------------------------------------------
class RegisteredResources {
private ArrayList resourceObjects = null;
private ArrayList resourceStates = null;
private CoordinatorLog logRecord = null;
private java.lang.Object logSection = null;
private java.lang.Object heuristicLogSection = null;
private Resource laoResource = null;
private CoordinatorImpl coord = null;
private static boolean lastXAResCommit = Boolean.getBoolean("com.sun.jts.lastagentcommit");
// START IASRI 4662745
//private int commitRetries = -1;
// private static int commitRetries = -1;
// END IASRI 4662745
//introduced for performance - remembers ths number of registered resources
private int nRes=0;
// private static String commitRetryVar =
// Configuration.getPropertyValue(Configuration.COMMIT_RETRY);
// private final static long COMMIT_RETRY_WAIT = 60000; // moved to Configuration.java
private final static String LOG_SECTION_NAME = "RR"/*#Frozen*/;
private final static String HEURISTIC_LOG_SECTION_NAME = "RRH"/*#Frozen*/;
/*
Logger to log transaction messages
*/
static Logger _logger = LogDomains.getLogger(RegisteredResources.class, LogDomains.TRANSACTION_LOGGER);
/**
* Defines the CoordinatorLog which is to be used for recovery.
*
* The CoordinatorLog for the transaction is updated with empty sections
* for RegisteredResources and RegisteredResourcesHeuristic created.
*
* Initialises the list of RegisteredResources to be empty.
*
* The CoordinatorLog is used as the basis for recovering the
* RegisteredResources and RegisteredResourcesHeuristic information at
* restart.
*
* @param log The CoordinatorLog object for the transaction.
*
* @return
*
* @see
*/
RegisteredResources(CoordinatorLog log, CoordinatorImpl coord) {
resourceObjects = new ArrayList();
resourceStates = new ArrayList();
// Create two sections in the CoordinatorLog object for Resources.
logRecord = log;
//if (log != null) {
// Create section for Resources registered as part of transaction
// logSection = log.createSection(LOG_SECTION_NAME);
// Create section for Resources with heuristic actions taken
// heuristicLogSection = log.createSection(HEURISTIC_LOG_SECTION_NAME);
//}
this.coord = coord;
}
/**
* Default RegisteredResources constructor.
*
* @param
*
* @return
*
* @see
*/
RegisteredResources(CoordinatorImpl coord) { this.coord = coord;}
/**
* Directs the RegisteredResources to recover its state after a failure.
*
* This is based on the given CoordinatorLog object. The participant list
* and heuristic information is reconstructed.
*
* @param log The CoordinatorLog holding the RegisteredResources state.
*
* @return
*
* @see
*/
void reconstruct(CoordinatorLog log) {
// Set up the instance variables.
resourceObjects = new ArrayList();
resourceStates = new ArrayList();
boolean infiniteRetry = true;
// First, get the retry count.
/**
if (commitRetries == -1 && commitRetryVar != null) {
try {
commitRetries = Integer.parseInt(commitRetryVar);
} catch (Throwable e) {}
infiniteRetry = false;
}
**/
int commitRetries = Configuration.getRetries();
if (commitRetries >= 0)
infiniteRetry = false;
// Reconstruct our state from CoordinatorLog object.
// Get the Registered Resources and the Registered Resources that had
// Heuristic results. Return the list of Registered Resources that did
// not have any Heuristic results.
heuristicLogSection = log.createSection(HEURISTIC_LOG_SECTION_NAME);
java.lang.Object[] resources = log.getObjects(heuristicLogSection);
for(int i = 0; i < resources.length; i++) {
boolean exceptionThrown=true;
int commitRetriesLeft = commitRetries;
while(exceptionThrown){
try {
Resource res =
ResourceHelper.narrow((org.omg.CORBA.Object)resources[i]);
if (res != null) {
resourceObjects.add(res);
nRes++;
resourceStates.add(ResourceStatus.Heuristic);
}
exceptionThrown=false;
} catch (Throwable exc) {
if(exc instanceof TRANSIENT || exc instanceof COMM_FAILURE) {
// If the exception is either TRANSIENT or
// COMM_FAILURE, keep retrying
//$ CHECK WITH DSOM FOLKS FOR OTHER EXCEPTIONS
_logger.log(Level.WARNING,"jts.exception_on_resource_operation",
new java.lang.Object[]{exc.toString(),
"reconstruct"});
if (commitRetriesLeft > 0 || infiniteRetry) {
// For TRANSIENT or COMM_FAILURE, wait
// for a while, then retry the commit.
if (!infiniteRetry) {
commitRetriesLeft--;
}
try {
Thread.sleep(Configuration.COMMIT_RETRY_WAIT);
} catch( Throwable e ) {}
} else {
// If the retry limit has been exceeded,
// end the process with a fatal error.
_logger.log(Level.SEVERE,"jts.retry_limit_exceeded",
new java.lang.Object[] {commitRetries, "commit"});
String msg = LogFormatter.getLocalizedMessage(_logger,
"jts.retry_limit_exceeded",
new java.lang.Object[] {commitRetries, "commit"});
throw new org.omg.CORBA.INTERNAL(msg);
//exceptionThrown=false;
//Commented out code as this statement is not
//reachable
}
}
else{
exceptionThrown=false;
}
}
}
}
// Resources that did not have Heuristic outcomes are added to the list
// Get section id for Resources registered as part of transaction
logSection = log.createSection(LOG_SECTION_NAME);
resources = log.getObjects(logSection);
for (int i = 0; i < resources.length; i++) {
boolean exceptionThrown=true;
int commitRetriesLeft = commitRetries;
while(exceptionThrown){
try {
Resource res =
ResourceHelper.narrow((org.omg.CORBA.Object)resources[i]);
if (res != null) {
resourceObjects.add(res);
nRes++;
resourceStates.add(ResourceStatus.Registered);
}
exceptionThrown=false;
} catch (Throwable exc) {
if(exc instanceof TRANSIENT || exc instanceof COMM_FAILURE) {
// If the exception is either TRANSIENT or
// COMM_FAILURE, keep retrying
//$ CHECK WITH DSOM FOLKS FOR OTHER EXCEPTIONS
_logger.log(Level.WARNING,"jts.exception_on_resource_operation",
new java.lang.Object[] {exc.toString(),"reconstruct"});
if (commitRetriesLeft > 0 || infiniteRetry) {
// For TRANSIENT or COMM_FAILURE, wait
// for a while, then retry the commit.
if (!infiniteRetry) {
commitRetriesLeft--;
}
try {
Thread.sleep(Configuration.COMMIT_RETRY_WAIT);
} catch( Throwable e ) {}
} else {
// If the retry limit has been exceeded,
// end the process with a fatal error.
_logger.log(Level.SEVERE,"jts.retry_limit_exceeded",
new java.lang.Object[] {commitRetries, "commit"});
String msg = LogFormatter.getLocalizedMessage(_logger,
"jts.retry_limit_exceeded",
new java.lang.Object[] {commitRetries, "commit"});
throw new org.omg.CORBA.INTERNAL(msg);
// exceptionThrown=false;
//Commented out as this will not be executed
}
}
else{
exceptionThrown=false;
}
}
}
}
logRecord = log;
}
/**
* Adds a reference to a Resource object to the list in the
* registered state.
*
* @param obj The reference of the Resource object to be stored.
*
* @return The number of registered Resource objects.
*
* @see
*/
int addRes(Resource obj) {
//int result;
// Add the reference to the list (which was created when this object
// was created), with the "registered" status.
resourceObjects.add(obj);
nRes++;
resourceStates.add(ResourceStatus.Registered);
//result =nRes;
// Dont add the reference to the log record at this point
// as it may vote read-only.
return nRes;
}
/**
* Empties the list of registered Resources.
*
* @param
*
* @return
*
* @see
*/
/*
void empty() {
// Empty the list of all Resource references.
resourceObjects.clear();
nRes=0;
resourceStates.clear();
}
*/
/**
* Checks whether there are any Resource objects registered.
*
* If there are, the operation returns true, otherwise false.
*
* @param
*
* @return Indicates whether any Resources registered.
*
* @see
*/
boolean involved() {
boolean result = (nRes != 0 );
return result;
}
/**
* Returns the number of Resources currently in the list.
*
* @param
*
* @return The number of registered Resources.
*
* @see
*/
int numRegistered() {
return nRes;
}
/**
* Distributes prepare messages to all Resources in the registered state.
*
* Resource objects that vote to commit the transaction are added to the
* RegisteredResources section in the CoordinatorLog.
*
* All Resources that return VoteReadOnly have their state set to
* completed. The consolidated result is returned.
*
* @param
*
* @return The vote for the transaction.
*
* @exception HeuristicMixed Indicates that a participant voted
* to roll the transaction back, but one or more others have
* already heuristically committed.
* @exception HeuristicHazard Indicates that a participant voted to
* roll the transaction back, but one or more others may have
* already heuristically committed.
*
* @see
*/
Vote distributePrepare() throws HeuristicMixed, HeuristicHazard {
Vote result = Vote.VoteReadOnly;
int laoIndex = -1;
boolean rmErr = false;
// Browse through the participants, preparing them, and obtain
// a consolidated result. The following is intended to be done
// asynchronously as a group of perations, however if done
// sequentially, it should stop after the first rollback vote.
// If there are no Resource references, return the a read-only vote.
for (int i = 0;
i < nRes && result != Vote.VoteRollback;
i++) {
boolean isProxy = false;
Resource currResource = (Resource) resourceObjects.get(i);
if ((i == nRes - 1) && lastXAResCommit && (laoResource == null) &&
result == Vote.VoteCommit) {
try {
if(_logger.isLoggable(Level.FINER))
{
_logger.logp(Level.FINER,"RegisteredResources",
"distributePrepare()",
"Before invoking commit on LA resource = " +
currResource);
}
currResource.commit_one_phase();
resourceStates.set(i, ResourceStatus.Completed);
if(_logger.isLoggable(Level.FINER))
{
_logger.logp(Level.FINER,"RegisteredResources",
"distributePrepare()",
"After invoking commit on LA resource = "+
currResource);
}
} catch (Throwable exc) {
result = Vote.VoteRollback;
resourceStates.set(i,ResourceStatus.Completed);
}
return result;
}
// We determine here whether the object is subordinate or proxy
// because the object may not exist when the prepare returns.
//String crid = CoordinatorResourceHelper.id();
//boolean isSubordinate = currResource._is_a( crid );
// COMMENT(Ram J) the instanceof operation should be replaced
// by a is_local() call, once the local object contract is
// implemented.
if(!(currResource instanceof OTSResourceImpl)) {
ProxyChecker checkProxy = Configuration.getProxyChecker();
isProxy = checkProxy.isProxy(currResource);
}
Vote currResult = Vote.VoteRollback;
try {
if(_logger.isLoggable(Level.FINER))
{
_logger.logp(Level.FINER,"RegisteredResources","prepare()",
"Before invoking prepare() on resource:" +
currResource);
}
currResult = currResource.prepare();
//Mark this resource as LA if vote is null
if(currResult == null) {
if(_logger.isLoggable(Level.FINER))
{
_logger.logp(Level.FINER,"RegisteredResources","prepare()",
"Marking the current resource as LAO:" +
currResource);
}
laoResource = currResource;
laoIndex = i;
continue;
}
if(_logger.isLoggable(Level.FINER))
{
_logger.logp(Level.FINER,"RegisteredResources","prepare()",
"After invoking prepare() on resource:" +
currResource + ";This resource voted : "+
currResult);
}
} catch (Throwable exc) {
// If a heuristic exception is thrown, this is because the
// Resource represents a subordinate which is voting to
// rollback; one of its Resources voted to roll back after
// others had voted to commit, and one of the commit voters
// then raised a heuristic exception when told to roll back.
// In this situation, we need to go back through all Resources
// and try to roll them back, not including the one
// which raised the exception.
boolean hazard = exc instanceof HeuristicHazard;
boolean internal = exc instanceof INTERNAL;
if (exc instanceof HeuristicMixed || hazard || internal) {
if (!internal) {
// Mark the Resource which threw the exception as
// heuristic so that we do not
// try to roll it back, but we do send it a forget.
resourceStates.set(i,ResourceStatus.Heuristic);
}
try {
distributeRollback(true);
} catch (Throwable ex2) {
// If the rollback threw an exception, change
// HeuristicHazard to HeuristicMixed if necessary.
if (ex2 instanceof HeuristicMixed && hazard) {
hazard = false;
}
}
// Now throw the appropriate exception.
if (hazard) {
throw (HeuristicHazard) exc;
} else if (internal) {
throw (INTERNAL) exc;
} else if (exc instanceof HeuristicMixed) {
throw (HeuristicMixed) exc;
} else {
throw new HeuristicMixed();
}
} else if (exc instanceof RuntimeException) {
rmErr = true;
}
// If any other exception is raised, assume the vote
// is rollback.
//$Check for specific exceptions ?
_logger.log(Level.WARNING,"jts.exception_on_resource_operation",
new java.lang.Object[] {exc.toString(),"prepare"});
}
// Record the outcome from the participant
// Take an action depending on the participant's vote.
if (currResult == Vote.VoteCommit) {
if (logRecord != null) {
if (!(currResource instanceof OTSResourceImpl)) {
if (logSection == null)
logSection = logRecord.createSection(LOG_SECTION_NAME);
logRecord.addObject(logSection, currResource);
}
}
if (result == Vote.VoteReadOnly) {
result = Vote.VoteCommit;
}
} else {
// If a participant votes readonly, don't change the overall
// vote. If a participant votes to rollback the transaction,
// change the consolidated result to rollback.
// Dont bother writing the reference to the log.
// The state of the Resource object is set
// to completed as we must not call it after it has voted
// to rollback the transaction. Set the state of a participant
// that votes read-only to completed as it
// replies. The consolidated vote does not change.
if (!rmErr)
resourceStates.set(i,ResourceStatus.Completed);
if (isProxy) {
currResource._release();
}
if (currResult == Vote.VoteRollback) {
result = currResult;
}
}
}
if (result == Vote.VoteCommit && laoResource != null) {
try {
if(_logger.isLoggable(Level.FINER))
{
_logger.logp(Level.FINER,"RegisteredResources",
"distributePrepare()",
"Before invoking commit on LA resource = " +
laoResource);
}
// laoResource.commit();
resourceStates.set(laoIndex, ResourceStatus.Completed);
if(_logger.isLoggable(Level.FINER))
{
_logger.logp(Level.FINER,"RegisteredResources",
"distributePrepare()",
"After invoking commit on LA resource = "+
laoResource);
}
} catch (Throwable exc) {
result = Vote.VoteRollback;
resourceStates.set(laoIndex,ResourceStatus.Completed);
}
}
return result;
}
Resource getLAOResource() {
return laoResource;
}
/**
* Distributes commit messages to all Resources in the registered state
*
* (i.e. not including those that voted VoteReadOnly). All Resources that
* return successfully have their state set to completed; those that
* raise heuristic exceptions are added to the
* RegisteredResourcesHeuristic section of the CoordinatorLog and have
* their state set to heuristic.
*
* All Resources in the heuristic state are then told to forget,
* their state is set to completed, and the CoordinatorLog object
* is forced to the physical log.
*
* @param
*
* @return
*
* @exception HeuristicMixed Indicates that heuristic decisions have been
* taken which have resulted in part of the transaction
* being rolled back.
* @exception HeuristicHazard Indicates that heuristic decisions may have
* been taken which have resulted in part of the transaction
* being rolled back.
*
* @see
*/
void distributeCommit() throws HeuristicMixed, HeuristicHazard, NotPrepared {
boolean infiniteRetry = true;
boolean heuristicException = false;
boolean heuristicMixed = false;
int heuristicRollback = 0;
int heuristicCommit = 0;
int success = 0;
// First, get the retry count.
/**
if (commitRetries == -1 && commitRetryVar != null) {
try {
commitRetries = Integer.parseInt(commitRetryVar);
} catch (Throwable e) {}
infiniteRetry = false;
}
**/
int commitRetries = Configuration.getRetries();
if (commitRetries >= 0)
infiniteRetry = false;
// Browse through the participants, committing them. The following is
// intended to be done asynchronously as a group of operations.
boolean transactionCompleted = true;
String msg = null;
for (int i = 0; i < nRes; i++) {
boolean isProxy = false;
Resource currResource = (Resource) resourceObjects.get(i);
// If the current Resource in the browse is not in the registered
// state, skip over it.
if ((ResourceStatus) resourceStates.get(i) ==
ResourceStatus.Registered) {
boolean heuristicRaised = false;
// We determine here whether the object is a proxy because the
// object may not exist when the commit returns.
// COMMENT(Ram J) the instanceof operation should be replaced
// by a is_local() call, once the local object contract is
// implemented.
if(!(currResource instanceof com.sun.jts.jtsxa.OTSResourceImpl)) {
ProxyChecker checkProxy = Configuration.getProxyChecker();
isProxy = checkProxy.isProxy(currResource);
}
// Change the current Resource's state to completing.
resourceStates.set(i,ResourceStatus.Completing);
// Tell the resource to commit.
// Catch any exceptions here; keep going until
// no exception is left.
int commitRetriesLeft = commitRetries;
boolean exceptionThrown = true;
while (exceptionThrown) {
try {
if(_logger.isLoggable(Level.FINER))
{
_logger.logp(Level.FINER,"RegisteredResources",
"distributeCommit()",
"Before invoking commit on resource = " +
currResource);
}
currResource.commit();
if(_logger.isLoggable(Level.FINER))
{
_logger.logp(Level.FINER,"RegisteredResources",
"distributeCommit()",
"After invoking commit on resource = "+
currResource);
}
exceptionThrown = false;
} catch (Throwable exc) {
if (exc instanceof HeuristicCommit ||
// Work around the fact that org.omg.CosTransactions.ResourceOperations#commit
// does not declare HeuristicCommit exception
(exc instanceof HeuristicHazard && exc.getCause() instanceof XAException &&
((XAException)exc.getCause()).errorCode == XAException.XA_HEURCOM)) {
// If the exception is Heuristic Commit, remember
// that a heuristic exception has been raised.
heuristicException = true;
heuristicRaised = true;
heuristicMixed = true;
exceptionThrown = false;
heuristicCommit++;
} else if (exc instanceof HeuristicRollback ||
exc instanceof HeuristicHazard ||
exc instanceof HeuristicMixed) {
// If the exception is Heuristic Rollback,
// Mixed or Hazard, remember that a heuristic
// exception has been raised, and also that
// damage has occurred.
heuristicException = true;
if (exc instanceof HeuristicRollback) {
heuristicRollback++;
}
heuristicMixed = !(exc instanceof HeuristicHazard);
heuristicRaised = true;
exceptionThrown = false;
} else if (exc instanceof INV_OBJREF ||
exc instanceof OBJECT_NOT_EXIST) {
// If the exception is INV_OBJREF, then the target
// Resource object must have already committed.
exceptionThrown = false;
} else if (exc instanceof NotPrepared) {
// If the exception is NotPrepared, then the target
// Resource has not recorded the fact that it has
// been called for prepare, or some internal glitch
// has happened inside the RegisteredResources /
// TopCoordinator. In this case the only sensible
// action is to end the process with a fatal error
// message.
_logger.log(Level.SEVERE,
"jts.exception_on_resource_operation",
new java.lang.Object[] {exc.toString(),"commit"});
throw (NotPrepared)exc;
/**
msg = LogFormatter.getLocalizedMessage(_logger,
"jts.exception_on_resource_operation",
new java.lang.Object[] {exc.toString(),
"commit"});
throw new org.omg.CORBA.INTERNAL(msg);
**/
} else if (!(exc instanceof TRANSIENT) &&
!(exc instanceof COMM_FAILURE)) {
// If the exception is neither TRANSIENT or
// COMM_FAILURE, it is unexpected, so display a
// message and give up with this Resource.
//$ CHECK WITH DSOM FOLKS FOR OTHER EXCEPTIONS
_logger.log(Level.SEVERE,
"jts.exception_on_resource_operation",
new java.lang.Object[] {exc.toString(),"commit"});
exceptionThrown = false;
transactionCompleted = false;
msg = LogFormatter.getLocalizedMessage(_logger,
"jts.exception_on_resource_operation",
new java.lang.Object[] {exc.toString(),
"commit"});
} else if (commitRetriesLeft > 0 || infiniteRetry) {
// For TRANSIENT or COMM_FAILURE, wait
// for a while, then retry the commit.
if (!infiniteRetry) {
commitRetriesLeft--;
}
try {
Thread.sleep(Configuration.COMMIT_RETRY_WAIT);
} catch( Throwable e ) {}
} else {
// If the retry limit has been exceeded,
// end the process with a fatal error.
_logger.log(Level.SEVERE,"jts.retry_limit_exceeded",
new java.lang.Object[] {commitRetries, "commit"});
exceptionThrown = false;
transactionCompleted = false;
msg = LogFormatter.getLocalizedMessage(_logger,
"jts.retry_limit_exceeded",
new java.lang.Object[] {commitRetries, "commit"});
}
}
}
if (heuristicRaised) {
// Either mark the participant as having raised a heuristic
// exception, or as completed.
resourceStates.set(i,ResourceStatus.Heuristic);
if (logRecord != null) {
if (!(currResource instanceof OTSResourceImpl)) {
if (heuristicLogSection == null)
heuristicLogSection =
logRecord.createSection(HEURISTIC_LOG_SECTION_NAME);
logRecord.addObject(heuristicLogSection, currResource);
}
}
} else {
// If completed, and the object is a proxy,
// release the proxy now.
resourceStates.set(i,ResourceStatus.Completed);
success++;
if (isProxy) {
currResource._release();
}
}
}
}
// The browse is complete.
// If a heuristic exception was raised, perform forget processing. This
// will then throw the appropriate heuristic exception to the caller.
// Note that HeuristicHazard exception with be converted to the HeuristicRolledbackException
// by the caller
if (heuristicException) {
boolean heuristicHazard = true;
if ((heuristicCommit + success) == nRes) {
heuristicMixed = false;
heuristicHazard = false;
} else if (heuristicRollback == nRes) {
heuristicMixed = false;
}
distributeForget(commitRetries, infiniteRetry, heuristicHazard, heuristicMixed);
}
if (!transactionCompleted) {
if (coord != null)
RecoveryManager.addToIncompleTx(coord, true);
if (msg != null)
throw new org.omg.CORBA.INTERNAL(msg);
else
throw new org.omg.CORBA.INTERNAL();
}
// Otherwise just return normally.
}
/**
* Distributes rollback messages to all Resources in the registered state.
*
* (i.e. not including those that voted VoteReadOnly). All Resources that
* return successfully have their state set to completed; those that raise
* heuristic exceptions are added to the RegisteredResourcesHeuristic
* section of the CoordinatorLog and have their state set to heuristic.
*
* All Resources in the heuristic state are then told to forget,
* their state is set to completed, and the CoordinatorLog object
* is forced to the physical log.
*
* @param heuristicException Indicates that a heuristic exception has
* already been thrown for this transaction, and that forget
* processing should proceed.
*
* @return
*
* @exception HeuristicMixed Indicates that heuristic decisions have been
* taken which have resulted in part of the transaction
* being rolled back.
* @exception HeuristicHazard Indicates that heuristic decisions
* may have been taken which have resulted in part of the transaction
* being rolled back.
*
* @see
*/
void distributeRollback(boolean heuristicException)
throws HeuristicMixed, HeuristicHazard {
boolean infiniteRetry = true;
boolean heuristicMixed = false;
int heuristicRollback = 0;
int success = 0;
int processed = 0;
// First, get the retry count.
/**
if (commitRetries == -1 && commitRetryVar != null) {
try {
commitRetries = Integer.parseInt(commitRetryVar);
} catch (Throwable e) {}
infiniteRetry = false;
}
**/
int commitRetries = Configuration.getRetries();
if (commitRetries >= 0)
infiniteRetry = false;
// Browse through the participants, committing them. The following is
// intended to be done asynchronously as a group of operations.
boolean transactionCompleted = true;
String msg = null;
for (int i = 0; i < nRes; i++) {
boolean isProxy = false;
Resource currResource = (Resource)resourceObjects.get(i);
// If the current Resource in the browse is not in the registered
// state, skip over it.
if (resourceStates.get(i).equals(
ResourceStatus.Registered)) {
processed++;
boolean heuristicRaised = false;
// We determine here whether the object is a proxy because
// the object may not exist when the commit returns.
// COMMENT(Ram J) the instanceof operation should be replaced
// by a is_local() call, once the local object contract is
// implemented.
if (!(currResource instanceof com.sun.jts.jtsxa.OTSResourceImpl)) {
ProxyChecker checkProxy = Configuration.getProxyChecker();
isProxy = checkProxy.isProxy(currResource);
}
// Change the current Resource's state to completing.
resourceStates.set(i,ResourceStatus.Completing);
// Tell the resource to commit.
// Catch any exceptions here; keep going
// until no exception is left.
int rollbackRetriesLeft = commitRetries;
boolean exceptionThrown = true;
while (exceptionThrown) {
try {
if(_logger.isLoggable(Level.FINER))
{
_logger.logp(Level.FINER,"RegisteredResources",
"distributeRollback()",
"Before invoking rollback on resource = "+
currResource);
}
currResource.rollback();
if(_logger.isLoggable(Level.FINER))
{
_logger.logp(Level.FINER,"RegisteredResources",
"distributeRollback()",
"After invoking rollback on resource = "+
currResource);
}
exceptionThrown = false;
} catch (Throwable exc) {
if (exc instanceof TRANSACTION_ROLLEDBACK) {
// If the exception is TRANSACTION_ROLLED back,
// then continue.
exceptionThrown = false;
} else if (exc instanceof HeuristicRollback) {
// If the exception is Heuristic Rollback,
// remember that a heuristic exception
// has been raised.
heuristicException = true;
heuristicRaised = true;
exceptionThrown = false;
heuristicRollback++;
} else if (exc instanceof HeuristicCommit ||
exc instanceof HeuristicHazard ||
exc instanceof HeuristicMixed) {
// If the exception is Heuristic Rollback, Mixed
// or Hazard, remember that a heuristic exception
// has been raised, and also that damage has
// occurred.
heuristicException = true;
heuristicMixed = !(exc instanceof HeuristicHazard);
heuristicRaised = true;
exceptionThrown = false;
// Work around the fact that org.omg.CosTransactions.ResourceOperations#rollback
// does not declare HeuristicRollback exception
if (exc instanceof HeuristicHazard && exc.getCause() instanceof XAException &&
((XAException)exc.getCause()).errorCode == XAException.XA_HEURRB) {
heuristicRollback++;
}
} else if (exc instanceof INV_OBJREF ||
exc instanceof OBJECT_NOT_EXIST){
//GDH added NOT_EXIST
// If the exception is INV_OBJREF, then the target
// Resource object must have already rolled back.
exceptionThrown = false;
} else if (!(exc instanceof TRANSIENT) &&
!(exc instanceof COMM_FAILURE)) {
// If the exception is neither TRANSIENT or
// COMM_FAILURE, it is unexpected, so display
// a message and give up with this Resource.
_logger.log(Level.SEVERE,
"jts.exception_on_resource_operation",
new java.lang.Object[]
{ exc.toString(), "rollback"});
msg = LogFormatter.getLocalizedMessage(_logger,
"jts.exception_on_resource_operation",
new java.lang.Object[] { exc.toString(),
"rollback"});
exceptionThrown = false;
transactionCompleted = false;
} else if (rollbackRetriesLeft > 0 || infiniteRetry) {
// For TRANSIENT or COMM_FAILURE, wait for a while,
// then retry the rollback.
if (!infiniteRetry) {
rollbackRetriesLeft--;
}
try {
Thread.sleep(Configuration.COMMIT_RETRY_WAIT);
} catch( Throwable e ) {}
} else {
// If the retry limit has been exceeded, end the
// process with a fatal error.
_logger.log(Level.SEVERE,"jts.retry_limit_exceeded",
new java.lang.Object[] {commitRetries, "rollback"});
msg = LogFormatter.getLocalizedMessage(_logger,
"jts.retry_limit_exceeded",
new java.lang.Object[] {commitRetries, "rollback"});
exceptionThrown = false;
transactionCompleted = false;
}
}
}
if (heuristicRaised) {
// Either mark the participant as having raised a
// heuristic exception, or as completed.
resourceStates.set(i,ResourceStatus.Heuristic);
if (logRecord != null) {
if (!(currResource instanceof OTSResourceImpl)) {
if (heuristicLogSection == null)
heuristicLogSection =
logRecord.createSection(HEURISTIC_LOG_SECTION_NAME);
logRecord.addObject(heuristicLogSection,currResource);
}
}
} else {
success++;
// If completed, and the object is a proxy,
// release the proxy now.
resourceStates.set(i,ResourceStatus.Completed);
if (isProxy) {
currResource._release();
}
}
}
}
// The browse is complete.
// If a heuristic exception was raised, perform forget processing.
// This will then throw the appropriate heuristic exception
// to the caller.
if (heuristicException)
distributeForget(commitRetries, infiniteRetry,
(((heuristicRollback + success) == processed)? false : true), heuristicMixed);
if (!transactionCompleted) {
if (coord != null)
RecoveryManager.addToIncompleTx(coord, false);
if (msg != null)
throw new org.omg.CORBA.INTERNAL(msg);
else
throw new org.omg.CORBA.INTERNAL();
}
// Otherwise just return normally.
}
/**
* Distributes forget messages to all Resources in the heuristic state.
*
* (i.e. only those which have thrown heuristic exceptions on prepare,
* commit or rollback).
*
* All Resources then have their state set to completed.
*
* @param retries The number of times to retry the forget operation.
* @param infinite indicates infinite retry.
*
* @return
*
* @exception HeuristicMixed Indicates that heuristic decisions have been
* taken which have resulted in part of the transaction
* being rolled back.
* @exception HeuristicHazard Indicates that heuristic decisions may have
* been taken which have resulted in part of the transaction being
* rolled back.
*
* @see
*/
private void distributeForget(int retries, boolean infinite,
boolean heuristicHazard, boolean heuristicMixed) throws HeuristicMixed, HeuristicHazard {
// Force the log record to ensure that all
// heuristic Resources are logged.
if (logRecord != null) {
logRecord.write(true);
}
// Browse through the remaining participants, informing them that they
// may forget the heuristic information at this point
for (int i = 0; i < nRes; i++) {
boolean isProxy = false;
// If the current Resource in the browse is not in the heuristic
// state, skip over it.
if ((ResourceStatus)resourceStates.get(i) ==
ResourceStatus.Heuristic) {
Resource currResource = (Resource)resourceObjects.get(i);
// We determine here whether the object is a proxy because
// the object may not exist when the forget returns.
// COMMENT(Ram J) the instanceof operation should be replaced
// by a is_local() call, once the local object contract is
// implemented.
if(!(currResource instanceof com.sun.jts.jtsxa.OTSResourceImpl)) {
ProxyChecker checkProxy = Configuration.getProxyChecker();
isProxy = checkProxy.isProxy(currResource);
}
// Tell the resource to forget.
int retriesLeft = retries;
boolean exceptionThrown = true;
while (exceptionThrown) {
try {
currResource.forget();
exceptionThrown = false;
} catch (Throwable exc) {
if (exc instanceof INV_OBJREF ||
exc instanceof OBJECT_NOT_EXIST) {
// If the exception is INV_OBJREF, then the target
// Resource object must have already forgotten.
exceptionThrown = false;
} else if (!(exc instanceof COMM_FAILURE) &&
!(exc instanceof TRANSIENT)) {
// If the exception is neither TRANSIENT or
// COMM_FAILURE, it is unexpected, so display
// a message and give up with this Resource.
//$ CHECK WITH DSOM FOLKS FOR OTHER EXCEPTIONS
exceptionThrown = false;
} else if (retriesLeft > 0 || infinite) {
// For TRANSIENT or COMM_FAILURE, wait for a while,
// then retry the forget.
if (!infinite) {
retriesLeft--;
}
try {
Thread.sleep(Configuration.COMMIT_RETRY_WAIT);
} catch( Throwable e ) {}
} else {
// If the retry limit has been exceeded,
// end the process with a fatal error.
_logger.log(Level.SEVERE,"jts.retry_limit_exceeded",
new java.lang.Object[] { retries, "forget"});
String msg = LogFormatter.getLocalizedMessage(_logger,
"jts.retry_limit_exceeded",
new java.lang.Object[] {retries, "forget"});
throw new org.omg.CORBA.INTERNAL(msg);
}
}
}
// Set the state of the Resource to completed
// after a successful forget. If the
// Resource is a proxy, release the reference.
resourceStates.set(i,ResourceStatus.Completed);
if (isProxy) {
currResource._release();
}
}
}
// If the original commit or rollback threw a HeuristicHazard
// or HeuristicMixed exception was raised, throw it now.
if (heuristicMixed) {
HeuristicMixed exc = new HeuristicMixed();
throw exc;
} else if (heuristicHazard) {
HeuristicHazard exc = new HeuristicHazard();
throw exc;
}
}
/**
* Distributes commitSubtransaction messages to all registered
* SubtransactionAwareResources.
*
* @param parent The parent's Coordinator reference.
*
* @return
*
* @exception TRANSACTION_ROLLEDBACK The subtransaction could not be
* committed. Some participants may have committed and some may have
* rolled back.
*
* @see
*/
void distributeSubcommit(Coordinator parent)
throws TRANSACTION_ROLLEDBACK {
boolean exceptionRaised = false;
// Browse through the participants, committing them. The following is
// intended to be done asynchronously as a group of operations.
for (int i = 0; i < nRes; i++) {
boolean isProxy = false;
SubtransactionAwareResource currResource =
(SubtransactionAwareResource)resourceObjects.get(i);
// COMMENT(Ram J) the instanceof operation should be replaced
// by a is_local() call, once the local object contract is
// implemented.
if(!(currResource instanceof com.sun.jts.jtsxa.OTSResourceImpl)) {
ProxyChecker checkProxy = Configuration.getProxyChecker();
isProxy = checkProxy.isProxy(currResource);
}
// Tell the object to commit.
try {
currResource.commit_subtransaction(parent);
} catch (Throwable exc) {
// Check for exceptions.
// If the TRANSACTION_ROLLEDBACK exception was raised,
// remember it.
if (exc instanceof TRANSACTION_ROLLEDBACK) {
exceptionRaised = true;
}
}
// Change the state of the object.
resourceStates.set(i,ResourceStatus.Completed);
// If the Resource is a proxy, release it.
if (isProxy) {
currResource._release();
}
}
// If an exception was raised, return it to the caller.
if (exceptionRaised) {
throw new TRANSACTION_ROLLEDBACK(0,CompletionStatus.COMPLETED_YES);
}
}
/**
* Distributes rollbackSubtransaction messages to all registered
* SubtransactionAwareResources.
*
* @param
*
* @return
*
* @see
*/
void distributeSubrollback() {
// Browse through the participants, rolling them back. The following is
// intended to be done asynchronously as a group of operations.
for (int i = 0; i < nRes; i++) {
boolean isProxy = false;
SubtransactionAwareResource currResource =
(SubtransactionAwareResource) resourceObjects.get(i);
// COMMENT(Ram J) the instanceof operation should be replaced
// by a is_local() call, once the local object contract is
// implemented.
if(!(currResource instanceof com.sun.jts.jtsxa.OTSResourceImpl)) {
ProxyChecker checkProxy = Configuration.getProxyChecker();
isProxy = checkProxy.isProxy(currResource);
}
// Tell the object to roll back.
try {
currResource.rollback_subtransaction();
} catch (Throwable exc) {}
resourceStates.set(i,ResourceStatus.Completed);
// If the Resource is a proxy, release it.
if (isProxy) {
currResource._release();
}
}
}
/**
* Fills in the given Vector objects with the currently registered Resource
* objects and their corresponding states.
*
* @param resources The object to hold the objects.
* @param states The object to hold the states.
*
* @return
*
* @see
*/
/* COMMENT(Ram J) - we do not support Admin package anymore.
void getResources(ResourceSequenceHolder resources,
ResourceStatusSequenceHolder states) {
resources.value = new Resource[resourceObjects.size()];
states.value = new ResourceStatus[resourceObjects.size()];
resourceObjects.copyInto(resources.value);
resourceStates.copyInto(states.value);
}
*/
/**
* Distributes the one phase commit.
*
* @param none
*
* @return void
*
* @see
*/
void commitOnePhase() throws HeuristicMixed, HeuristicHazard {
boolean infiniteRetry = true;
boolean heuristicRaisedSetStatus = false;
boolean heuristicExceptionFlowForget = false;
boolean isProxy = false;
boolean heuristicMixed = false;
boolean heuristicHazard = false;
boolean rollback_occurred = false;
boolean outstanding_resources = true;
int retry_limit;
int no_of_attempts;
// First, get the retry count.
/**
if (commitRetries == -1 && commitRetryVar != null) {
try {
commitRetries = Integer.parseInt(commitRetryVar);
} catch (Throwable exc) {
_logger.log(Level.SEVERE,"jts.exception_on_resource_operation",
new java.lang.Object[]
{ exc.toString(), "CommitOnePhase commitRetryVar" });
String msg = LogFormatter.getLocalizedMessage(_logger,
"jts.exception_on_resource_operation",
new java.lang.Object[]
{ exc.toString(), "CommitOnePhase commitRetryVar" });
throw new org.omg.CORBA.INTERNAL(msg);
}
infiniteRetry = false;
}
**/
int commitRetries = Configuration.getRetries();
if (commitRetries >= 0)
infiniteRetry = false;
// Check we only have one resource!
// If not return
if (nRes > 1) {
_logger.log(Level.SEVERE,"jts.exception_on_resource_operation",
new java.lang.Object[] { "commitOnePhase", ">1 Resource"});
String msg = LogFormatter.getLocalizedMessage(_logger,
"jts.exception_on_resource_operation",
new java.lang.Object[]
{ "commitOnePhase", ">1 Resource"});
throw new org.omg.CORBA.INTERNAL(msg);
}
// Now we know we have one resource we can use similar
// logic to the 'commit' method
Resource currResource = (Resource) resourceObjects.get(0);
// If the single resource is not in the registered state,
// we can return too!
// (Ram Jeyaraman) Should this condition check be != and then return ?
// Previously the IF block had '==' operator and empty block
if ((ResourceStatus) resourceStates.get(0) !=
ResourceStatus.Registered) {
return;
}
// We determine here whether the object is a proxy because
// the object may not exist when the commit returns.
// COMMENT(Ram J) the instanceof operation should be replaced
// by a is_local() call, once the local object contract is
// implemented.
if(!(currResource instanceof com.sun.jts.jtsxa.OTSResourceImpl)) {
ProxyChecker checkProxy = Configuration.getProxyChecker();
isProxy = checkProxy.isProxy(currResource);
}
// Change the current Resource's state to completing.
resourceStates.set(0,ResourceStatus.Completing);
// Tell the resource to commit.
// Catch any exceptions here; keep going until no exception is left.
int commitRetriesLeft = commitRetries;
boolean exceptionThrownTryAgain = true;
while (exceptionThrownTryAgain) {
try {
if(_logger.isLoggable(Level.FINEST))
{
_logger.logp(Level.FINEST,"RegisteredResources","commitOnePhase()",
"Before invoking commit_one_phase() on resource:" +
currResource );
}
currResource.commit_one_phase();
if(_logger.isLoggable(Level.FINEST))
{
_logger.logp(Level.FINEST,"RegisteredResources","commitOnePhase()",
"After invoking commit_one_phase() on resource:" +
currResource );
}
resourceStates.set(0,ResourceStatus.Completed);
exceptionThrownTryAgain = false;
} catch (Throwable exc) {
if (exc instanceof TRANSACTION_ROLLEDBACK) {
//
// The resource rolled back - remember this.
//
rollback_occurred = true;
resourceStates.set(0,ResourceStatus.Completed);
exceptionThrownTryAgain = false;
} else if (exc instanceof HeuristicHazard) {
// If the exception is Heuristic Rollback,
// Mixed or Hazard, remember that a heuristic exception
// has been raised, and also that damage has occurred.
//IASRI START 4722883
/**
heuristicExceptionFlowForget = true;
heuristicRaisedSetStatus = true;
exceptionThrownTryAgain = false;
heuristicMixed = false;
**/
XAException e = (XAException) ((Throwable)exc).getCause();
if ((e!= null) && (e.errorCode >= XAException.XA_RBBASE && e.errorCode <= XAException.XA_RBEND)) {
rollback_occurred = true;
resourceStates.set(0,ResourceStatus.Completed);
exceptionThrownTryAgain = false;
} else {
heuristicExceptionFlowForget = true;
heuristicRaisedSetStatus = true;
exceptionThrownTryAgain = false;
if ((e!= null) && (e.errorCode == XAException.XA_HEURCOM))
heuristicHazard = false;
else
heuristicHazard = true;
if ((e!= null) && (e.errorCode == XAException.XA_HEURMIX))
heuristicMixed = true;
else
heuristicMixed = false;
}
//IASRI END 4722883
} else if (exc instanceof INV_OBJREF ||
exc instanceof OBJECT_NOT_EXIST) {
// If the exception is INV_OBJREF, then the target Resource
// object must have already committed. (Probably contacted
// the resource on a previous attempt but its OK response
// was lost due to a failure.)
resourceStates.set(0,ResourceStatus.Completed);
exceptionThrownTryAgain = false;
} else if (exc instanceof NotPrepared) {
// If the exception is NotPrepared, then the target
// Resource is probably trying to indicate that it does not
// support one phase commit. Considered switching to
// 2PC commit for a retry here but as commit one phase is
// part of our specification then something is fishy
// if it is not supported: Throw an error.
_logger.log(Level.SEVERE,"jts.exception_on_resource_operation",
new java.lang.Object[] { exc.toString(),
"commit one phase"});
String msg = LogFormatter.getLocalizedMessage(_logger,
"jts.exception_on_resource_operation",
new java.lang.Object[] { exc.toString(),
"commit one phase"});
throw new org.omg.CORBA.INTERNAL(msg);
} else if (!(exc instanceof TRANSIENT) &&
!(exc instanceof COMM_FAILURE)) {
// If the exception has not been mentione yet and is
// neither of the two below, it is unexpected,
// so display a message and give up with this Resource.
_logger.log(Level.SEVERE,"jts.exception_on_resource_operation",
new java.lang.Object[] { exc.toString(),
"commit one phase"});
String msg = LogFormatter.getLocalizedMessage(_logger,
"jts.exception_on_resource_operation",
new java.lang.Object[] { exc.toString(),
"commit one phase"});
throw new org.omg.CORBA.INTERNAL(msg);
} else if (commitRetriesLeft > 0 || infiniteRetry) {
// For TRANSIENT or COMM_FAILURE, wait for a while,
// then retry the commit.
if (!infiniteRetry) {
commitRetriesLeft--;
}
try {
Thread.sleep(Configuration.COMMIT_RETRY_WAIT);
} catch (Throwable e) {}
} else {
// If the retry limit has been exceeded, end the
// process with a fatal error.
// GDH Did consider carefully here whether the exception
// should be perculated back to the client. With 2PC
// because we can take action on the other resources we
// carry on and subsequently pass an exception to the
// client. But here there is little point in doing
// this as all recoverable work has either
// been done or not by this point - we have a
// serious problem so stop now. If the JTS was built
// into an application server (rather than being a
// toolkit for standalone apps) then we would replace
// all the FATAL_ERROR actions such as the one below
// with the actino required by the application server.
_logger.log(Level.SEVERE,"jts.retry_limit_exceeded",
new java.lang.Object[] { commitRetries, "commitOnePhase"});
String msg = LogFormatter.getLocalizedMessage(_logger,
"jts.retry_limit_exceeded",
new java.lang.Object[] {commitRetries,"commitOnePhase"});
throw new org.omg.CORBA.INTERNAL(msg);
}
} // end of catch block for exceptions
} // end while exception being raised (GDH)
// Either mark the participant as having raised a heuristic exception,
// or as completed.
if (heuristicRaisedSetStatus) {
resourceStates.set(0,ResourceStatus.Heuristic);
if (logRecord != null) {
// (The distributeForget method forces the log)
if (!(currResource instanceof OTSResourceImpl)) {
if (heuristicLogSection == null)
heuristicLogSection =
logRecord.createSection(HEURISTIC_LOG_SECTION_NAME);
logRecord.addObject(heuristicLogSection,currResource);
}
}
} else {
// Otherwise we are completed, if the object is a proxy,
// release the proxy now.
resourceStates.set(0,ResourceStatus.Completed);
if (isProxy) {
currResource._release();
}
}
// If a heuristic exception was raised, perform forget processing.
// This will then throw the appropriate heuristic exception
// to the caller.
if (heuristicExceptionFlowForget) {
distributeForget(commitRetries, infiniteRetry, heuristicHazard, heuristicMixed);
// throw is done in method above
}
if (rollback_occurred) {
throw new TRANSACTION_ROLLEDBACK(0,
CompletionStatus.COMPLETED_YES);
}
// Otherwise just return normally.
}
// START IASRI 4662745
/**
public static void setCommitRetryVar(String commitRetryString)
{
if (commitRetries == -1 && commitRetryVar != null) {
try {
commitRetries = Integer.parseInt(commitRetryVar);
} catch (Exception e) {}
}
}
**/
// END IASRI 4662745
}