RecoveryCoordinatorImplpublic 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. |
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.
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.
// 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 void | destroy()Destroys the RecoveryCoordinatorImpl object.
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 RecoveryCoordinator | object()Returns the CORBA Object which represents this 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;
| public Status | replay_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.
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 Status | replay_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;
| void | rollbackOrphan(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.
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();
|
|