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

com.gemstone.gemfire.internal.jta.TransactionManagerImpl Maven / Gradle / Ivy

There is a newer version: 2.0-BETA
Show newest version
/*
 * Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License. You
 * may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * permissions and limitations under the License. See accompanying
 * LICENSE file.
 */
package com.gemstone.gemfire.internal.jta;

/**
 * 

* TransactionManager: A JTA compatible Transaction Manager. *

* * @author Mitul Bid * @author Asif * @since 4.1.1 */ import com.gemstone.gemfire.i18n.LogWriterI18n; import com.gemstone.gemfire.internal.i18n.LocalizedStrings; import java.io.Serializable; //import java.sql.SQLException; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.SortedSet; import java.util.TreeSet; import javax.transaction.*; import com.gemstone.gemfire.CancelException; import com.gemstone.gemfire.internal.LogWriterImpl; import com.gemstone.gemfire.internal.cache.TXManagerImpl; public class TransactionManagerImpl implements TransactionManager, Serializable { private static final long serialVersionUID = 5033392316185449821L; /** * A mapping of Thread - Transaction Objects. * * [sumedh] Now it is in the TXManagerImpl ThreadLocal to allow for only one * ThreadLocal lookup to get current TXStateInterface and detect JTA (see * LocalRegion.discoverJTA). Furthermore, ThreadLocal lookup will normally be * more efficient than a ConcurrentMap lookup. */ //private final Map transactionMap = new ConcurrentHashMap(); /** * A mapping of Transaction - Global Transaction */ private final Map globalTransactionMap = Collections.synchronizedMap(new HashMap()); /** * Ordered set of active global transactions - Used for timeOut */ protected SortedSet gtxSet = Collections.synchronizedSortedSet(new TreeSet( new GlobalTransactionComparator())); /** * Transaction TimeOut Class */ transient private TransactionTimeOutThread cleaner; /** * Singleton transactionManager */ private static TransactionManagerImpl transactionManager = null; /** * Transaction TimeOut thread */ transient private Thread cleanUpThread = null; /** * Default Transaction Time Out */ static final int DEFAULT_TRANSACTION_TIMEOUT = Integer.getInteger("jta.defaultTimeout", 600).intValue(); /** * Asif: The integers identifying the cause of Rollback */ private static final int MARKED_ROLLBACK = 1; private static final int EXCEPTION_IN_NOTIFY_BEFORE_COMPLETION = 2; private static final int COMMIT_FAILED_SO_ROLLEDBAK = 3; private static final int COMMIT_FAILED_ROLLBAK_ALSO_FAILED = 4; private static final int ROLLBAK_FAILED = 5; //TODO:Asif .Not yet used this exception code // private static final int EXCEPTION_IN_NOTIFY_AFTER_COMPLETION = 6; /* * to enable VERBOSE = true pass System parameter jta.VERBOSE = true * while running the test. */ private static boolean VERBOSE = Boolean.getBoolean("jta.VERBOSE"); /* * checks if the TransactionManager is active */ private boolean isActive = true; /** * Constructs a new TransactionManagerImpl */ private TransactionManagerImpl() { cleaner = this.new TransactionTimeOutThread(); ThreadGroup group = LogWriterImpl.createThreadGroup(LocalizedStrings.TransactionManagerImpl_CLEAN_UP_THREADS.toLocalizedString(), (LogWriterI18n) null); cleanUpThread = new Thread(group, cleaner, "GlobalTXTimeoutMonitor"); cleanUpThread.setDaemon(true); cleanUpThread.start(); } /** * Returns the singleton TransactionManagerImpl Object */ public static TransactionManagerImpl getTransactionManager() { if (transactionManager == null) { createTransactionManager(); } return transactionManager; } /** * Creates an instance of TransactionManagerImpl if none exists */ private static synchronized void createTransactionManager() { if (transactionManager == null) transactionManager = new TransactionManagerImpl(); } /** * Create a new transaction and associate it with the current thread if none * exists with the current thread else throw an exception since nested * transactions are not supported * * Create a global transaction and associate the transaction created with the * global transaction * * @throws NotSupportedException - Thrown if the thread is already associated * with a transaction and the Transaction Manager implementation * does not support nested transactions. * @throws SystemException - Thrown if the transaction manager encounters an * unexpected error condition. * * @see javax.transaction.TransactionManager#begin() */ public void begin() throws NotSupportedException, SystemException { if (!isActive) { throw new SystemException(LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGER_INVALID.toLocalizedString()); } LogWriterI18n log = TransactionUtils.getLogWriterI18n(); if (log.fineEnabled()) { log.fine("TransactionManager.begin() invoked"); } final TXManagerImpl.TXContext context = TXManagerImpl.currentTXContext(); if (context != null && context.getJTA() != null) { String exception = LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGERIMPL_BEGIN_NESTED_TRANSACTION_IS_NOT_SUPPORTED.toLocalizedString(); if (VERBOSE) log.fine(exception); throw new NotSupportedException(exception); } try { TransactionImpl transaction = new TransactionImpl(); GlobalTransaction globalTransaction = new GlobalTransaction(); globalTransactionMap.put(transaction, globalTransaction); globalTransaction.addTransaction(transaction); globalTransaction.setStatus(Status.STATUS_ACTIVE); TXManagerImpl.beginJTA(transaction, context); } catch (Exception e) { String exception = LocalizedStrings.TransactionManagerImpl_BEGIN__SYSTEMEXCEPTION_DUE_TO_0.toLocalizedString(new Object[] {e}); if (log.severeEnabled()) log.severe(LocalizedStrings.TransactionManagerImpl_BEGIN__SYSTEMEXCEPTION_DUE_TO_0, new Object[] {e}); final SystemException ex = new SystemException(exception); ex.initCause(e); throw ex; } } /** * Complete the transaction associated with the current thread by calling the * GlobalTransaction.commit(). When this method completes, the thread is no * longer associated with a transaction. * * @throws RollbackException - Thrown to indicate that the transaction has * been rolled back rather than committed. * @throws HeuristicMixedException - Thrown to indicate that a heuristic * decision was made and that some relevant updates have been * committed while others have been rolled back. * @throws HeuristicRollbackException - Thrown to indicate that a heuristic * decision was made and that all relevant updates have been * rolled back. * @throws java.lang.SecurityException - Thrown to indicate that the thread * is not allowed to commit the transaction. * @throws java.lang.IllegalStateException - Thrown if the current thread is * not associated with a transaction. * @throws SystemException - Thrown if the transaction manager encounters an * unexpected error condition. * * @see javax.transaction.TransactionManager#commit() */ public void commit() throws HeuristicRollbackException, RollbackException, HeuristicMixedException, SystemException { if (!isActive) { throw new SystemException(LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGER_INVALID.toLocalizedString()); } int cozOfException = -1; Transaction transactionImpl = getTransaction(); if (transactionImpl == null) { String exception = LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGERIMPL_COMMIT_TRANSACTION_IS_NULL_CANNOT_COMMIT_A_NULL_TRANSACTION.toLocalizedString(); LogWriterI18n writer = TransactionUtils.getLogWriterI18n(); if (VERBOSE) writer.fine(exception); throw new IllegalStateException(exception); } GlobalTransaction gtx = getGlobalTransaction(transactionImpl); if (gtx == null) { String exception = LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGERIMPL_COMMIT_GLOBAL_TRANSACTION_IS_NULL_CANNOT_COMMIT_A_NULL_GLOBAL_TRANSACTION.toLocalizedString(); LogWriterI18n writer = TransactionUtils.getLogWriterI18n(); if (VERBOSE) writer.fine(exception); throw new SystemException(exception); } boolean isCommit = false; //ensure only one thread can commit. Use a synchronized block //Asif int status = -1; if (((status = gtx.getStatus()) == Status.STATUS_ACTIVE) || status == Status.STATUS_MARKED_ROLLBACK) { synchronized (gtx) { if ((status = gtx.getStatus()) == Status.STATUS_ACTIVE) { gtx.setStatus(Status.STATUS_COMMITTING); isCommit = true; } else if (status == Status.STATUS_MARKED_ROLLBACK) { gtx.setStatus(Status.STATUS_ROLLING_BACK); cozOfException = MARKED_ROLLBACK; } else { String exception = LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGERIMPL_COMMIT_TRANSACTION_NOT_ACTIVE_CANNOT_BE_COMMITTED_TRANSACTION_STATUS_0.toLocalizedString(Integer.valueOf(status)); LogWriterI18n writer = TransactionUtils.getLogWriterI18n(); if (VERBOSE) writer.fine(exception); throw new IllegalStateException(exception); } } } else { String exception = LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGERIMPL_COMMIT_TRANSACTION_IS_NOT_ACTIVE_AND_CANNOT_BE_COMMITTED.toLocalizedString(); LogWriterI18n writer = TransactionUtils.getLogWriterI18n(); if (VERBOSE) writer.fine(exception); throw new IllegalStateException(exception); } //Only one thread can call commit (the first thread to do reach the block // above). //Before commiting the notifications to be done before the done are called // the global transaction is called and then the after completion // notifications // are taken care of. The transactions associated to the global // transactions are //removed from the map and also the tread to transaction. // // Asif : Store the thrown Exception in case of commit . //Reuse it for thrwing later. //Asif TODO:Verify if it is a good practise boolean isClean = false; Exception e = null; try { ((TransactionImpl) transactionImpl).notifyBeforeCompletion(); isClean = true; } catch (Exception ge) { //Asif : Just mark the Tranxn to setRollbackOnly to ensure Rollback setRollbackOnly(); cozOfException = EXCEPTION_IN_NOTIFY_BEFORE_COMPLETION; e = ge; } //TODO:Asif In case the status of transaction is marked as // ROLLING_BACK , then we don't have to take a synch block // As once the status is marked for ROLLING_BACK , setRollnbackonly //will be harmless if (isCommit) { synchronized (gtx) { if ((status = gtx.getStatus()) == Status.STATUS_COMMITTING) { //Asif: Catch any exception encountered during commit // and appropriately mark the exception code try { gtx.commit(); } catch (RollbackException rbe) { e = rbe; cozOfException = COMMIT_FAILED_SO_ROLLEDBAK; } catch (SystemException se) { e = se; cozOfException = COMMIT_FAILED_ROLLBAK_ALSO_FAILED; } } else if (status == Status.STATUS_ROLLING_BACK) { try { gtx.rollback(); if (isClean) cozOfException = MARKED_ROLLBACK; } catch (SystemException se) { e = se; cozOfException = ROLLBAK_FAILED; } } } } else { try { gtx.rollback(); } catch (SystemException se) { e = se; cozOfException = ROLLBAK_FAILED; } } try { ((TransactionImpl) transactionImpl).notifyAfterCompletion(status = gtx .getStatus()); } catch (Exception ge) { LogWriterI18n writer = TransactionUtils.getLogWriterI18n(); if (writer.infoEnabled()) writer.info(LocalizedStrings.TransactionManagerImpl_EXCEPTION_IN_NOTIFY_AFTER_COMPLETION_DUE_TO__0, ge.getMessage(), ge); } TXManagerImpl.endCurrentJTA(); this.gtxSet.remove(gtx); if (status != Status.STATUS_COMMITTED) { switch (cozOfException) { case EXCEPTION_IN_NOTIFY_BEFORE_COMPLETION: { String exception = LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGERIMPL_COMMIT_TRANSACTION_ROLLED_BACK_BECAUSE_OF_EXCEPTION_IN_NOTIFYBEFORECOMPLETION_FUNCTION_CALL_ACTUAL_EXCEPTION_0.toLocalizedString(); LogWriterI18n writer = TransactionUtils.getLogWriterI18n(); if (VERBOSE) writer.fine(exception, e); RollbackException re = new RollbackException(exception); re.initCause(e); throw re; } case MARKED_ROLLBACK: { String exception = LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGERIMPL_COMMIT_TRANSACTION_ROLLED_BACK_BECAUSE_A_USER_MARKED_IT_FOR_ROLLBACK.toLocalizedString(); LogWriterI18n writer = TransactionUtils.getLogWriterI18n(); if (VERBOSE) writer.fine(exception, e); throw new RollbackException(exception); } case COMMIT_FAILED_SO_ROLLEDBAK: { LogWriterI18n writer = TransactionUtils.getLogWriterI18n(); if (VERBOSE) writer.fine(e); throw (RollbackException) e; } case COMMIT_FAILED_ROLLBAK_ALSO_FAILED: case ROLLBAK_FAILED: { LogWriterI18n writer = TransactionUtils.getLogWriterI18n(); if (VERBOSE) writer.fine(e); throw (SystemException) e; } } } gtx.setStatus(Status.STATUS_NO_TRANSACTION); } /** * Rolls back the transaction associated with the current thread by calling * the GlobalTransaction.rollback(). When this method completes, the thread * is no longer associated with a transaction. * * @throws java.lang.SecurityException - Thrown to indicate that the thread * is not allowed to commit the transaction. * @throws java.lang.IllegalStateException - Thrown if the current thread is * not associated with a transaction. * @throws SystemException - Thrown if the transaction manager encounters an * unexpected error condition. * * @see javax.transaction.TransactionManager#commit() */ public void rollback() throws IllegalStateException, SecurityException, SystemException { if (!isActive) { throw new SystemException(LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGER_INVALID.toLocalizedString()); } // boolean isRollingBack = false; LogWriterI18n writer = TransactionUtils.getLogWriterI18n(); Transaction transactionImpl = getTransaction(); if (transactionImpl == null) { String exception = LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGERIMPL_ROLLBACK_NO_TRANSACTION_EXISTS.toLocalizedString(); if (VERBOSE) writer.fine(exception); throw new IllegalStateException(exception); } GlobalTransaction gtx = getGlobalTransaction(transactionImpl); if (gtx == null) { String exception = LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGERIMPL_ROLLBACK_NO_GLOBAL_TRANSACTION_EXISTS.toLocalizedString(); if (VERBOSE) writer.fine(exception); throw new SystemException(exception); } int status = gtx.getStatus(); if (!(status == Status.STATUS_ACTIVE || status == Status.STATUS_MARKED_ROLLBACK)) { String exception = LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGERIMPL_ROLLBACK_TRANSACTION_STATUS_DOES_NOT_ALLOW_ROLLBACK_TRANSACTIONAL_STATUS_0.toLocalizedString(Integer.valueOf(status)); if (VERBOSE) writer.fine(exception); throw new IllegalStateException(exception); } //ensure only one thread proceeds from here status = -1; synchronized (gtx) { if ((status = gtx.getStatus()) == Status.STATUS_ACTIVE || status == Status.STATUS_MARKED_ROLLBACK) gtx.setStatus(Status.STATUS_ROLLING_BACK); else if (gtx.getStatus() == Status.STATUS_ROLLING_BACK) { String exception = LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGERIMPL_ROLLBACK_TRANSACTION_ALREADY_IN_A_ROLLING_BACK_STATE_TRANSACTIONAL_STATUS_0.toLocalizedString(Integer.valueOf(status)); if (VERBOSE) writer.fine(exception); throw new IllegalStateException(exception); } else { String exception = LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGERIMPL_ROLLBACK_TRANSACTION_STATUS_DOES_NOT_ALLOW_ROLLBACK.toLocalizedString(); if (VERBOSE) writer.fine(exception); throw new IllegalStateException(exception); } } //Only one thread can call rollback (the first thread to do reach the // block above). //Before rollback the notifications to be done before the done are called // the global transaction is called and then the after completion // notifications // are taken care of. The transactions associated to the global // transactions are //removed from the map and also the tread to transaction. // //TODO remove all threads-transactions (from the map) //for transactions participating in the global transaction // SystemException se = null; try { gtx.rollback(); } catch (SystemException se1) { se = se1; } try { ((TransactionImpl) transactionImpl) .notifyAfterCompletion(gtx.getStatus()); } catch (Exception e1) { if (writer.infoEnabled()) writer.info(LocalizedStrings.TransactionManagerImpl_EXCEPTION_IN_NOTIFY_AFTER_COMPLETION_DUE_TO__0, e1.getMessage(), e1); } TXManagerImpl.endCurrentJTA(); this.gtxSet.remove(gtx); if (se != null) { if (VERBOSE) writer.fine(se); throw se; } gtx.setStatus(Status.STATUS_NO_TRANSACTION); } /** * Set the Global Transaction status (Associated with the current thread) to * be RollBackOnly * * Becauce we are using one phase commit, we are not considering Prepared and * preparing states. * * @see javax.transaction.TransactionManager#setRollbackOnly() */ public void setRollbackOnly() throws IllegalStateException, SystemException { if (!isActive) { throw new SystemException(LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGER_INVALID.toLocalizedString()); } GlobalTransaction gtx = getGlobalTransaction(); if (gtx == null) { String exception = LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGERIMPL_SETROLLBACKONLY_NO_GLOBAL_TRANSACTION_EXISTS.toLocalizedString(); LogWriterI18n writer = TransactionUtils.getLogWriterI18n(); if (VERBOSE) writer.fine(exception); throw new SystemException(exception); } synchronized (gtx) { int status = gtx.getStatus(); if (status == Status.STATUS_ACTIVE) gtx.setRollbackOnly(); else if (status == Status.STATUS_COMMITTING) gtx.setStatus(Status.STATUS_ROLLING_BACK); else if (status == Status.STATUS_ROLLING_BACK) ; //Dont do anything else { String exception = LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGERIMPL_SETROLLBACKONLY_TRANSACTION_CANNOT_BE_MARKED_FOR_ROLLBACK_TRANSCATION_STATUS_0.toLocalizedString(Integer.valueOf(status)); LogWriterI18n writer = TransactionUtils.getLogWriterI18n(); if (VERBOSE) writer.fine(exception); throw new IllegalStateException(exception); } } //Asif : Log after exiting synch block LogWriterI18n writer = TransactionUtils.getLogWriterI18n(); if (VERBOSE) writer.fine("Transaction Set to Rollback only"); } /** * Get the status of the global transaction associated with this thread * * @see javax.transaction.TransactionManager#getStatus() */ public int getStatus() throws SystemException { if (!isActive) { throw new SystemException(LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGER_INVALID.toLocalizedString()); } GlobalTransaction gtx = getGlobalTransaction(); if (gtx == null) { return Status.STATUS_NO_TRANSACTION; } return gtx.getStatus(); } /** * not supported * * @see javax.transaction.TransactionManager#setTransactionTimeout(int) */ public void setTransactionTimeout(int seconds) throws SystemException { if (!isActive) { throw new SystemException(LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGER_INVALID.toLocalizedString()); } GlobalTransaction gtx = getGlobalTransaction(); if (gtx == null) { String exception = LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGERIMPL_SETTRANSACTIONTIMEOUT_NO_GLOBAL_TRANSACTION_EXISTS.toLocalizedString(); LogWriterI18n writer = TransactionUtils.getLogWriterI18n(); if (VERBOSE) writer.fine(exception); throw new SystemException(exception); } long newExpiry = gtx.setTransactionTimeoutForXARes(seconds); if(newExpiry > 0 ){ //long expirationTime = System.currentTimeMillis() + (seconds * 1000); gtxSet.remove(gtx); // Asif :Lets blindly remove the current gtx from the TreeMap & // Add only if status is neither Rolledback, Unknown , committed or no // transaction or GTX not // expired, which gurantees that the client thread will be returning & // cleaning up .so we //don't add it int status = gtx.getStatus(); if (status != Status.STATUS_NO_TRANSACTION && status != Status.STATUS_COMMITTED && status != Status.STATUS_ROLLEDBACK && !gtx.isExpired()) { //Asif : Take a lock on GTX while setting the new Transaction timeout // value, // so that cleaner thread sees the new value immediately else due to // volatility issue // we may have inconsistent values of time out boolean toAdd = false; synchronized (gtx) { if (!gtx.isExpired()) { gtx.setTimeoutValue(newExpiry); toAdd = true; } } //Asif : It is possible that in the window between we set the new //timeout value in current GTX & add it to the gtxSet , the currentGtx //is expired by the cleaner thread as there is no safeguard for it. //We allow it to happen that is add the expired GTx to the TreeSet. //Since a notify will be issued , the cleaner thread wil take care // of it. if (toAdd) { synchronized (gtxSet) { gtxSet.add(gtx); if (gtxSet.first() == gtx) { gtxSet.notify(); } } } } else { String exception = LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGERIMPL_SETTRANSACTIONTIMEOUT_TRANSACTION_HAS_EITHER_EXPIRED_OR_ROLLEDBACK_OR_COMITTED.toLocalizedString(); LogWriterI18n writer = TransactionUtils.getLogWriterI18n(); if (VERBOSE) writer.fine(exception); throw new SystemException(exception); } } } /** * @see javax.transaction.TransactionManager#suspend() */ public Transaction suspend() throws SystemException { if (!isActive) { throw new SystemException(LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGER_INVALID.toLocalizedString()); } Transaction txn = getTransaction(); if (txn != null) { GlobalTransaction gtx = getGlobalTransaction(txn); gtx.suspend(); TXManagerImpl.setCurrentJTA(null); LogWriterI18n writer = TransactionUtils.getLogWriterI18n(); if (writer.infoEnabled()) writer.info(LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGERIMPLSUSPENDTRANSACTION_SUSPENDED); } return txn; } /** * @see javax.transaction.TransactionManager#resume(javax.transaction.Transaction) */ public void resume(Transaction txn) throws InvalidTransactionException, IllegalStateException, SystemException { if (!isActive) { throw new SystemException(LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGER_INVALID.toLocalizedString()); } if (txn == null) { String exception = LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGERIMPL_RESUME_CANNOT_RESUME_A_NULL_TRANSACTION.toLocalizedString(); LogWriterI18n writer = TransactionUtils.getLogWriterI18n(); if (VERBOSE) writer.fine(exception); throw new InvalidTransactionException(exception); } GlobalTransaction gtx = getGlobalTransaction(txn); if (gtx == null) { String exception = LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGERIMPL_RESUME_CANNOT_RESUME_A_NULL_TRANSACTION.toLocalizedString(); LogWriterI18n writer = TransactionUtils.getLogWriterI18n(); if (VERBOSE) writer.fine(exception); throw new InvalidTransactionException(exception); } gtx.resume(); try { TXManagerImpl.setCurrentJTA(txn); LogWriterI18n writer = TransactionUtils.getLogWriterI18n(); if (writer.infoEnabled()) writer.info(LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGERIMPLRESUMETRANSACTION_RESUMED); } catch (Exception e) { String exception = LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGERIMPL_RESUME_ERROR_IN_LISTING_THREAD_TO_TRANSACTION_MAP_DUE_TO_0.toLocalizedString(e); LogWriterI18n writer = TransactionUtils.getLogWriterI18n(); if (VERBOSE) writer.fine(exception); final SystemException ex = new SystemException(exception); ex.initCause(e); throw ex; } } /** * Get the transaction associated with the calling thread * * @see javax.transaction.TransactionManager#getTransaction() */ public Transaction getTransaction() throws SystemException { if (!isActive) { throw new SystemException( LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGER_INVALID .toLocalizedString()); } return TXManagerImpl.getCurrentJTA(); } /** * Get the transaction associated with the calling thread with given context. * * @see javax.transaction.TransactionManager#getTransaction() */ public Transaction getTransaction(final TXManagerImpl.TXContext context) throws SystemException { if (this.isActive) { return context.getJTA(); } return null; } /** * Get the Global Transaction associated with the calling thread */ GlobalTransaction getGlobalTransaction() throws SystemException { Transaction txn = TXManagerImpl.getCurrentJTA(); if (txn == null) { return null; } GlobalTransaction gtx = (GlobalTransaction) globalTransactionMap.get(txn); return gtx; } /** * Get the Global Transaction associated with the calling thread */ GlobalTransaction getGlobalTransaction(Transaction txn) throws SystemException { if (txn == null) { String exception = LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGERIMPL_GETGLOBALTRANSACTION_NO_TRANSACTION_EXISTS.toLocalizedString(); LogWriterI18n writer = TransactionUtils.getLogWriterI18n(); if (VERBOSE) writer.fine(exception); throw new SystemException(exception); } GlobalTransaction gtx = (GlobalTransaction) globalTransactionMap.get(txn); return gtx; } //Asif : This method is used only for testing purposes Map getGlobalTransactionMap() { return globalTransactionMap; } //Asif : Remove the mapping of tranxn to Global Tranxn. //Previously thsi task was being done in GlobalTranxn void cleanGlobalTransactionMap(List tranxns) { synchronized (tranxns) { Iterator iterator = tranxns.iterator(); while (iterator.hasNext()) { globalTransactionMap.remove(iterator.next()); } } } void removeTranxnMappings(List txns) { final Map allContexts = TXManagerImpl .getJTAContexts(); Transaction tx; synchronized (allContexts) { final Iterator contextIter = allContexts .keySet().iterator(); while (contextIter.hasNext()) { final TXManagerImpl.TXContext context = contextIter.next(); if ((tx = context.getJTA()) != null && txns.contains(tx)) { context.clearJTAOnly(); contextIter.remove(); } } } for (Object o : txns) { globalTransactionMap.remove(o); } txns.clear(); } class TransactionTimeOutThread implements Runnable { protected volatile boolean toContinueRunning = true; public void run() { GlobalTransaction currentGtx = null; long lag = 0; LogWriterI18n logger = TransactionUtils.getLogWriterI18n(); while (toContinueRunning) { //Asif :Ensure that we do not get out of try { // wait //without a GTX object synchronized (gtxSet) { while (gtxSet.isEmpty() && toContinueRunning) { gtxSet.wait(); } if (!toContinueRunning) continue; currentGtx = (GlobalTransaction) gtxSet.first(); } //Asif : Check whether current GTX has timed out or not boolean continueInner = true; do { synchronized (currentGtx) { lag = System.currentTimeMillis() - currentGtx.getExpirationTime(); if (lag >= 0) { //Asif: Expire the GTX .Do not worry if some GTX comes // before it in Map , ie // even if tehre is a GTX earlier than this one to expire , // it is OK // to first take care of this one //TODO: Do the clean up from all Maps currentGtx.expireGTX(); gtxSet.remove(currentGtx); } } synchronized (gtxSet) { if (gtxSet.isEmpty()) { continueInner = false; } else { currentGtx = (GlobalTransaction) gtxSet.first(); boolean isGTXExp = false; //Asif: There will not be any need for synchronizing // on currentGTX as we are already taking lokc on gtxSet. // Since the GTXSEt is locked that implies no GTX can be // either removed or added ( if already removed) //if the thread is in this block . thus we are safe // //synchronized (currentGtx) { lag = System.currentTimeMillis() - currentGtx.getExpirationTime(); if (lag < 0) { //Asif : Make the thread wait for stipluated // time isGTXExp = false; } else { isGTXExp = true; //Asif It is possibel that GTX is already expired but // just got added in TreeSet bcoz of the small window // in setTimeOut function of TranxnManager. if (!currentGtx.isExpired()) { currentGtx.expireGTX(); } gtxSet.remove(currentGtx); //Asif Clean the objects if (gtxSet.isEmpty()) { continueInner = false; } else { currentGtx = (GlobalTransaction) gtxSet.first(); } } //} //Asif : It is OK if we release the lock on Current GTX // for sleep //bcoz as we have still the the lock on gtxSet, even if // the //transaction set time out gets modified by other client // thread, // it will notbe added to the set as the lock is still // with us. //So in case of new tiemout value, if it is such that // the GTX is /// at the beginning , notified will be issued & the // cleaner thread // wil awake. // the set as the lock is if (!isGTXExp && toContinueRunning) { gtxSet.wait(-(lag)); if (gtxSet.isEmpty()) { continueInner = false; } else { currentGtx = (GlobalTransaction) gtxSet.first(); } } if (!toContinueRunning) { continueInner = false; } } } // synchronized } while (continueInner); } catch (InterruptedException e) { // No need to reset the bit; we'll exit. if (toContinueRunning) { logger.fine("TransactionTimeOutThread: unexpected exception", e); } return; } catch (CancelException e) { // this thread is shutdown by doing an interrupt so this is expected //logger.fine("TransactionTimeOutThread: encountered exception", e); return; } catch (Exception e) { if (logger.severeEnabled() && toContinueRunning) { logger.severe( LocalizedStrings.TransactionManagerImpl_TRANSACTIONTIMEOUTTHREAD__RUN_EXCEPTION_OCCURRED_WHILE_INSPECTING_GTX_FOR_EXPIRY, e); } } } } } static class GlobalTransactionComparator implements Comparator { /** * Sort the array in ascending order of expiration times */ public int compare(Object obj1, Object obj2) { GlobalTransaction gtx1 = (GlobalTransaction) obj1; GlobalTransaction gtx2 = (GlobalTransaction) obj2; return gtx1.compare(gtx2); } /** * Overwrite default equals implementation */ @Override public boolean equals(Object o1) { return this == o1; } } /** * Shutdown the transactionManager and threads associated with this. */ public static void refresh() { getTransactionManager(); transactionManager.isActive = false; transactionManager.cleaner.toContinueRunning = false; try { transactionManager.cleanUpThread.interrupt(); } catch (Exception e) { LogWriterI18n writer = TransactionUtils.getLogWriterI18n(); if (writer.infoEnabled()) writer .info(LocalizedStrings.TransactionManagerImpl_TRANSACTIONMANAGERIMPLCLEANUPEXCEPTION_WHILE_CLEANING_THREAD_BEFORE_RE_STATRUP); } /* try { transactionManager.cleanUpThread.join(); } catch (Exception e) { e.printStackTrace(); }*/ transactionManager = null; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy