TimeoutManagerpublic class TimeoutManager extends Object This class records state for timing out transactions, and runs a thread
which performs occasional checks to time out transactions. |
Fields Summary |
---|
static final int | CANCEL_TIMEOUTConstants which define the types of timeout possible. | static final int | NO_TIMEOUT | static final int | ACTIVE_TIMEOUT | static final int | IN_DOUBT_TIMEOUT | private static boolean | initialisedthis attribute indicates whether initialisation has been started. | private static Hashtable | pendingTimeouts | private static Hashtable | indoubtTimeouts | private static TimeoutThread | timeoutThread | private static boolean | timeoutActive | private static boolean | quiescing | private static boolean | isSetTimeout | static Logger | _logger |
Methods Summary |
---|
static java.util.Enumeration | checkTimeouts()Periodically checks the existing timeouts.
This is done to discover if any transactions have overrun their allotted
time. Those which have are returned as an Enumeration.
Note that this method should not do anything that will cause a
synchronized method in the RecoveryManager to be called, as this could
cause a deadlock when RecoveryManager methods on other threads call
setTimeout.
if (!isSetTimeout)
return null;
Enumeration result = null;
// When woken up, go through all current timeouts and identify those
// which have expired.
if (timeoutActive && ((pendingTimeouts.size() != 0) || (indoubtTimeouts.size() != 0))) {
Vector timedOut = null;
Enumeration timeouts = null;
synchronized (pendingTimeouts) {
timeouts = pendingTimeouts.elements();
while (timeouts.hasMoreElements()) {
TimeoutInfo timeoutInfo = (TimeoutInfo)timeouts.nextElement();
// For each timeout in the list, check whether it has expired.
// If so, look up the Coordinator and roll it back.
if (new Date().getTime() > timeoutInfo.expireTime) {
// Add the TimeoutInfo to the queue of
//those that have timed out.
if (timedOut == null) {
timedOut = new Vector();
}
timedOut.addElement(timeoutInfo);
}
}
}
synchronized (indoubtTimeouts) {
timeouts = indoubtTimeouts.elements();
while (timeouts.hasMoreElements()) {
TimeoutInfo timeoutInfo = (TimeoutInfo)timeouts.nextElement();
// For each timeout in the list, check whether it has expired.
// If so, look up the Coordinator and roll it back.
if (new Date().getTime() > timeoutInfo.expireTime) {
// Add the TimeoutInfo to the queue of
//those that have timed out.
if (timedOut == null) {
timedOut = new Vector();
}
timedOut.addElement(timeoutInfo);
}
}
}
// Enumerate the transactions which have timed out.
if (timedOut != null) {
result = timedOut.elements();
}
}
// The remainder of the timeout processing is not carried out here
// because we would get deadlocked with addCoordinator or
// removeCoordinator that also update the timeout list. Hence the
// returned enumeration, which may be processed with
// no concurrency control.
return result;
| static com.sun.jts.jtsxa.XID[] | getInDoubtXids()
synchronized (indoubtTimeouts) {
Vector inDoubtList = new Vector();
Enumeration timeouts = indoubtTimeouts.elements();
while (timeouts.hasMoreElements()) {
TimeoutInfo timeoutInfo = (TimeoutInfo) timeouts.nextElement();
// Look up the Coordinator for the transaction.
// If there is none, then the transaction has already gone.
// Otherwise do something with the transaction.
CoordinatorImpl coord =
RecoveryManager.getLocalCoordinator(timeoutInfo.localTID);
if (coord != null) {
XID xid = new XID();
xid.copy(coord.getGlobalTID());
inDoubtList.addElement(xid);
}
}
return (XID[]) inDoubtList.toArray(new XID[] {});
}
| static synchronized void | initSetTimeout()
if (isSetTimeout)
return;
isSetTimeout = true;
timeoutThread = new TimeoutThread();
timeoutThread.start();
| static synchronized void | initialise()Initialises the static state of the TimeoutManager class.
// If already initialised, return immediately.
if (initialised) {
return;
}
initialised = true;
// Start the timeout thread.
if (!timeoutActive && timeoutThread == null) {
// timeoutThread = new TimeoutThread();
// timeoutThread.start();
timeoutActive = true;
}
| static boolean | setTimeout(java.lang.Long localTID, int timeoutType, int seconds)Sets the timeout for the transaction to the specified type and time in
seconds.
If the type is none, the timeout for the transaction is
cancelled, otherwise the current timeout for the transaction is modified
to be of the new type and duration.
boolean result = true;
// Modify the timeout to the required type and value.
if (timeoutActive) {
TimeoutInfo timeoutInfo = null;
switch (timeoutType) {
// If the new type is active or in_doubt, then create a
// new TimeoutInfo if necessary, and set up the type and interval.
case TimeoutManager.ACTIVE_TIMEOUT :
if (!isSetTimeout) {
initSetTimeout();
}
timeoutInfo = new TimeoutInfo();
timeoutInfo.expireTime =
new Date().getTime() + seconds * 1000;
timeoutInfo.localTID = localTID;
timeoutInfo.timeoutType = timeoutType;
pendingTimeouts.put(localTID,timeoutInfo);
break;
case TimeoutManager.IN_DOUBT_TIMEOUT :
if (!isSetTimeout) {
initSetTimeout();
// isSetTimeout = true;
}
timeoutInfo = new TimeoutInfo();
timeoutInfo.expireTime =
new Date().getTime() + seconds * 1000;
timeoutInfo.localTID = localTID;
timeoutInfo.timeoutType = timeoutType;
indoubtTimeouts.put(localTID,timeoutInfo);
break;
// For any other type, remove the timeout if there is one.
default:
if (!isSetTimeout)
break;
result = (pendingTimeouts.remove(localTID) != null);
if (!result)
result = (indoubtTimeouts.remove(localTID) != null);
// If the transaction service is quiescing and
// there are no more pending timeouts,
// deactivate timeout and stop the timeout thread.
if (quiescing && pendingTimeouts.isEmpty() && indoubtTimeouts.isEmpty()) {
timeoutThread.stop();
timeoutActive = false;
// pendingTimeouts = null;
}
break;
}
} else {
// If timeouts are not active, just return false.
result = false;
}
return result;
| static void | shutdown(boolean immediate)Informs the TimeoutManager that the transaction service
is being shut down. For immediate shutdown, the timeout thread is
stopped and all timeout information discarded.
For quiesce, the timeout thread is stopped when there are no running
transactions left.
// For immediate, kill the timeout thread and throw
// away all information. Also, if there are no pending
// timeouts, there is nothing to quiesce so
// shutdown immediately regardless.
if (immediate ||
pendingTimeouts == null || pendingTimeouts.isEmpty()) {
if (timeoutThread != null) {
timeoutThread.stop();
}
if (pendingTimeouts != null) {
pendingTimeouts.clear();
}
pendingTimeouts = null;
timeoutThread = null;
timeoutActive = false;
} else {
quiescing = true;
}
| static long | timeLeft(java.lang.Long localTID)Returns the amount of time left before the given transaction times out.
TimeoutInfo timeoutInfo = (TimeoutInfo) pendingTimeouts.get(localTID);
if (timeoutInfo == null)
timeoutInfo = (TimeoutInfo) indoubtTimeouts.get(localTID);
long result = -1;
if (timeoutInfo != null) {
result = timeoutInfo.expireTime - new Date().getTime();
if (result < 0) {
result = 0;
}
}
return result;
| static void | timeoutCoordinator(java.lang.Long localTID, int timeoutType)Takes appropriate action for a timeout.
The type fo timeout is given, and the transaction represented by the
Coordinator and its local identifier.
This method does not reference the TimeoutManager's state directly
and so does not need to be synchronized.
// Look up the Coordinator for the transaction.
// If there is none, then the transaction has already gone.
// Otherwise do something with the transaction.
CoordinatorImpl coord = RecoveryManager.getLocalCoordinator(localTID);
if (coord == null) {
if(_logger.isLoggable(Level.FINER))
{
_logger.logp(Level.FINER,"TimeoutManager","timeoutCoordinator()",
"RecoveryManager.getLocalCoordinator() returned null,"+
"which means txn is done. Setting timeout type to CANCEL_TIMEOUT");
}
TimeoutManager.setTimeout(localTID,
TimeoutManager.CANCEL_TIMEOUT,
0);
} else {
synchronized (coord) {
boolean[] isRoot = new boolean[1];
switch (timeoutType) {
// If active, then attempt to roll the transaction back.
case TimeoutManager.ACTIVE_TIMEOUT :
if(_logger.isLoggable(Level.FINER))
{
_logger.logp(Level.FINER,"TimeoutManager","timeoutCoordinator()",
"TimeoutManager.timeoutCoordinator():case ACTIVE_TIMEOUT"+
"RecoveryManager.getLocalCoordinator() returned non-null,"+
"which means txn is still around. Marking for Rollback the"+
"transaction...: GTID is : " +
((TopCoordinator)coord).superInfo.globalTID.toString());
}
try {
// coord.rollback(true);
coord.rollback_only();
} catch (Throwable exc) {}
break;
// If in doubt, it must be a TopCoordinator.
// In that case replay_completion needs to be driven.
// This is done by telling the TopCoordinator to act as
// if in recovery. The result is then used to
// determine what to do with the Coordinator.
case TimeoutManager.IN_DOUBT_TIMEOUT :
if(_logger.isLoggable(Level.FINER))
{
_logger.logp(Level.FINER,"TimeoutManager","timeoutCoordinator()",
"TimeoutManager.timeoutCoordinator():case IN_DOUBT_TIMEOUT"+
"RecoveryManager.getLocalCoordinator() returned non-null,"+
"which means txn is still around. Invoking recover(boolean)"+
"on TopCoordinator...: GTID is: "+
((TopCoordinator)coord).superInfo.globalTID.toString());
}
Status state = ((TopCoordinator) coord).recover(isRoot);
if (state == Status.StatusUnknown) {
// If the outcome is not currently known, we do
// nothing with the transaction, as we expect to
// eventually get an outcome from the parent.
// GDH put out warning in case this state
// continues for a long time.
_logger.log(Level.WARNING, "jts.transaction_resync_from_orginator_failed");
} else if (state == Status.StatusCommitted) {
// For committed or rolled back, proceed with
// completion of the transaction, regardless of whether
// it is the root or a subordinate. This will
// result in the removal of the in-doubt timeout.
try {
((TopCoordinator)coord).commit();
if (isRoot[0]) {
((TopCoordinator) coord).
afterCompletion(state);
}
} catch (Throwable exc) {}
} else {
// By default, roll the transaction back.
try {
((TopCoordinator) coord).rollback(true);
if (isRoot[0]) {
((TopCoordinator) coord).
afterCompletion(Status.StatusRolledBack);
}
} catch (Throwable exc) {}
}
break;
default:
// Otherwise do nothing.
break;
}
}
}
|
|