FileDocCategorySizeDatePackage
DelegatedTimeoutManager.javaAPI DocGlassfish v2 API23814Fri May 04 22:36:38 BST 2007com.sun.jts.CosTransactions

DelegatedTimeoutManager

public class DelegatedTimeoutManager extends Object
This class records state for timing out transactions, and runs a thread which performs occasional checks to time out transactions. For each log location, which requires delegated recovery, an instance of this will be created. Done as part of delegated recovery support. th
version
0.01
see

Fields Summary
static final int
CANCEL_TIMEOUT
Constants 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
initialised
this attribute indicates whether initialisation has been started.
private Hashtable
pendingTimeouts
private Hashtable
indoubtTimeouts
private DelegatedTimeoutThread
timeoutThread
private boolean
timeoutActive
private boolean
quiescing
private boolean
isSetTimeout
private String
logPath
static Logger
_logger
Constructors Summary
DelegatedTimeoutManager()
synchronized static void initialise() { // 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; } }

                    
                                                      
    
     
    
DelegatedTimeoutManager(String logPath)

        this.logPath = logPath;
    
Methods Summary
java.util.EnumerationcheckTimeouts()
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.

param
return
The information for transactions which have timed out.
see

        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()) {
                    
                    DelegatedTimeoutInfo timeoutInfo = (DelegatedTimeoutInfo)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()) {
                    
                    DelegatedTimeoutInfo timeoutInfo = (DelegatedTimeoutInfo)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;
    
com.sun.jts.jtsxa.XID[]getInDoubtXids()

return
a set of in-doubt transaction ids.

        
        synchronized (indoubtTimeouts) {
            Vector inDoubtList = new Vector();
            
            Enumeration timeouts = indoubtTimeouts.elements();
            
            while (timeouts.hasMoreElements()) {
                
                DelegatedTimeoutInfo timeoutInfo = (DelegatedTimeoutInfo) 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 =
                DelegatedRecoveryManager.getLocalCoordinator(timeoutInfo.localTID, logPath);
                
                if (coord != null) {
                    XID xid = new XID();
                    xid.copy(coord.getGlobalTID());
                    inDoubtList.addElement(xid);
                }
            }
            
            return (XID[]) inDoubtList.toArray(new XID[] {});
        }
    
synchronized voidinitSetTimeout()

        if (isSetTimeout)
            return;
        isSetTimeout = true;
        timeoutThread = new DelegatedTimeoutThread(this);
        timeoutThread.start();
    
booleansetTimeout(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.

param
localTID The local identifier for the transaction.
param
timeoutType The type of timeout to establish.
param
seconds The length of the timeout.
return
Indicates success of the operation.
see

        
        boolean result = true;
        
        // Modify the timeout to the required type and value.
        
        DelegatedTimeoutInfo 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 DelegatedTimeoutManager.ACTIVE_TIMEOUT :
                if (!isSetTimeout) {
                    initSetTimeout();
                }
                timeoutInfo = new DelegatedTimeoutInfo();
                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 DelegatedTimeoutInfo();
                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;
        }
        return result;
    
voidshutdown(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.

param
immediate Indicates whether to stop immediately.
return
see

        
        // 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;
        }
    
longtimeLeft(java.lang.Long localTID)
Returns the amount of time left before the given transaction times out.

param
localTID The local identifier for the transaction.
return
The time left. If there is no timeout for the transaction, this value will be negative. If the timeout period has been exceeded, this value will be zero.
see

        
        DelegatedTimeoutInfo timeoutInfo = (DelegatedTimeoutInfo) pendingTimeouts.get(localTID);
        if (timeoutInfo == null)
            timeoutInfo = (DelegatedTimeoutInfo) indoubtTimeouts.get(localTID);
        long result = -1;
        if (timeoutInfo != null) {
            result = timeoutInfo.expireTime - new Date().getTime();
            if (result < 0) {
                result = 0;
            }
        }
        
        return result;
    
voidtimeoutCoordinator(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.

param
localTID The local identifier for the transaction.
param
timeoutType The type of timeout.
return
see

        
        // 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 = DelegatedRecoveryManager.getLocalCoordinator(localTID, logPath);
        if (coord == null) {
            if(_logger.isLoggable(Level.FINER)) {
                _logger.logp(Level.FINER,"DelegatedTimeoutManager","timeoutCoordinator()",
                "DelegatedRecoveryManager.getLocalCoordinator() returned null,"+
                "which means txn is done. Setting timeout type to CANCEL_TIMEOUT");
            }
            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 DelegatedTimeoutManager.ACTIVE_TIMEOUT :
                        if(_logger.isLoggable(Level.FINER)) {
                            _logger.logp(Level.FINER,"DelegatedTimeoutManager","timeoutCoordinator()",
                            "DelegatedTimeoutManager.timeoutCoordinator():case ACTIVE_TIMEOUT"+
                            "DelegatedRecoveryManager.getLocalCoordinator() returned non-null,"+
                            "which means txn is still around. Rolling back 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 DelegatedTimeoutManager.IN_DOUBT_TIMEOUT :
                        if(_logger.isLoggable(Level.FINER)) {
                            _logger.logp(Level.FINER,"DelegatedTimeoutManager","timeoutCoordinator()",
                            "DelegatedTimeoutManager.timeoutCoordinator():case IN_DOUBT_TIMEOUT"+
                            "DelegatedRecoveryManager.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;
                }
            }
        }