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

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

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2010 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:      TimeoutManager.java
//
// Description: Transaction time-out manager.
//
// 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.
//----------------------------------------------------------------------------
//Portions Copyright [2016] [Payara Foundation]
package com.sun.jts.CosTransactions;

import java.util.*;

import org.omg.CosTransactions.*;
import com.sun.jts.jtsxa.XID;


import java.util.logging.Logger;
import java.util.logging.Level;
import com.sun.logging.LogDomains;

/**
 * This class records state for timing out transactions, and runs a thread
 * which performs occasional checks to time out transactions.
 *
 * @version 0.01
 *
 * @author Simon Holdsworth, IBM Corporation
 *
 * @see
*/

//----------------------------------------------------------------------------
// CHANGE HISTORY
//
// Version By     Change Description
//   0.01  SAJH   Initial implementation.
//----------------------------------------------------------------------------

class TimeoutManager {
    /**
     * Constants which define the types of timeout possible.
     */
    static final int CANCEL_TIMEOUT   = 0;
    static final int NO_TIMEOUT       = 0;
    static final int ACTIVE_TIMEOUT   = 1;
    static final int IN_DOUBT_TIMEOUT = 2;

    /**
     * this attribute indicates whether initialisation has been started.
     */
    private static boolean initialised = false;

    private static Hashtable     pendingTimeouts = new Hashtable();
    private static Hashtable     indoubtTimeouts = new Hashtable();
    private static TimeoutThread timeoutThread = null;
    private static boolean       timeoutActive = false;
    private static boolean       quiescing = false;
    private static boolean       isSetTimeout = false;

	/*
		Logger to log transaction messages
	*/  
    static Logger _logger = LogDomains.getLogger(TimeoutManager.class, LogDomains.TRANSACTION_LOGGER);
    /**
     * Initialises the static state of the TimeoutManager class.
     *
     * @param
     *
     * @return
     *
     * @see
     */
    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;
        }
    }


    static synchronized void initSetTimeout() {
	if (isSetTimeout)
	   return;
        isSetTimeout = true;
        
        // to prevent classloader explicitly set context classloader
        
        timeoutThread = new TimeoutThread();
        timeoutThread.setContextClassLoader(timeoutThread.getClass().getClassLoader());
        timeoutThread.start();
    }

    /**
     * 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 */ static boolean setTimeout(Long localTID, int timeoutType, int seconds) { 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 * 1000L; 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 * 1000L; 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; } /** * 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 */ static void timeoutCoordinator(Long localTID, int timeoutType) { // 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; } } } } /** * 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 */ static Enumeration checkTimeouts() { 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; } /** * @return a set of in-doubt transaction ids. */ static 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[] {}); } } /** * 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 */ static long timeLeft(Long localTID) { 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; } /** * 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 */ static void shutdown(boolean immediate) { // 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; } } /** * Reports the contents of the TimeoutManager tables. *$Only required for debug. * * @param immediate Indicates whether to stop immediately. * * @return * * @see */ /* static void report() { // Report on pendingTimeouts. if (pendingTimeouts.size() > 0) { if(_logger.isLoggable(Level.FINER)) { _logger.logp(Level.FINER,"TimeoutManager","report()", "TimeoutManager.pendingTimeouts non-empty"); } Enumeration keys = pendingTimeouts.keys(); while (keys.hasMoreElements()) { Long localTID = (Long) keys.nextElement(); TimeoutInfo timeInfo = (TimeoutInfo) pendingTimeouts.get(localTID); if(_logger.isLoggable(Level.FINER)) { _logger.logp(Level.FINER,"TimeoutManager","report()", "localTid :"+localTID+" -> " + timeInfo); } } } else { if(_logger.isLoggable(Level.FINER)) { _logger.logp(Level.FINER,"TimeoutManager","report()", "TimeoutManager.pendingTimeouts empty"); } } } */ } /** * This class records information for a timeout for a transaction. * * @version 0.1 * * @author Simon Holdsworth, IBM Corporation * * @see */ //---------------------------------------------------------------------------- // CHANGE HISTORY // // Version By Change Description // 0.1 SAJH Initial implementation. //---------------------------------------------------------------------------- class TimeoutInfo extends Object { Long localTID = null; long expireTime = 0; int timeoutType = TimeoutManager.NO_TIMEOUT; } /** * This class represents a thread on which the TimeoutManager can perform * timeout checking. * * @version 0.01 * * @author Simon Holdsworth, IBM Corporation * * @see */ //---------------------------------------------------------------------------- // CHANGE HISTORY // // Version By Change Description // 0.01 SAJH Initial implementation. //---------------------------------------------------------------------------- class TimeoutThread extends Thread { private int TIMEOUT_INTERVAL ; static Logger _logger = LogDomains.getLogger(TimeoutThread.class, LogDomains.TRANSACTION_LOGGER); /** * TimeoutThread constructor. *

* This sets the thread name, and sets the thread to be a daemon thread so * that it does not prevent the process from terminating. * * @param * * @return * * @see */ TimeoutThread() { setName("JTS Timeout Thread"/*#Frozen*/); setDaemon(true); try{ String timeout_interval = Configuration.getPropertyValue(Configuration.TIMEOUT_INTERVAL); if(timeout_interval!=null){ TIMEOUT_INTERVAL= Integer.parseInt(timeout_interval); TIMEOUT_INTERVAL*=1000; if(TIMEOUT_INTERVAL<10000) TIMEOUT_INTERVAL=10000; } else{ TIMEOUT_INTERVAL=10000; } }catch(Exception e){ TIMEOUT_INTERVAL=10000; } } /** * Performs timeout checking on a regular basis (every ten seconds or so). * * @param * * @return * * @see */ public void run() { try { while (true) { // Sleep for a while between checks. Thread.sleep(TIMEOUT_INTERVAL); // Perform timeout checks, getting a list of timed-out // transactions. Enumeration timedOut = TimeoutManager.checkTimeouts(); // Now we must go through the list, telling each // timed-out Coordinator to do something appropriate. if (timedOut != null) { while (timedOut.hasMoreElements()) { TimeoutInfo timeoutInfo = (TimeoutInfo) timedOut.nextElement(); // Look up the Coordinator and tell it to roll back // if it still exists. Note that we rely on the // Coordinator calling removeCoordinator when it // has finished, which will remove the timeout from // the list, and remove other associations as well. TimeoutManager. timeoutCoordinator(timeoutInfo.localTID, timeoutInfo.timeoutType); } } } } catch (InterruptedException exc) { _logger.log(Level.INFO,"jts.time_out_thread_stopped"); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy