2 Replies Latest reply on Jun 2, 2005 11:10 AM by Dimitris Andreadis

    MT-change to JBossManagedConnectionPool.BasePool.getConnecti

    Dimitris Andreadis Master

      Possible races condition in enlist(), when trackByTx is true, are probably caused one step back while a ConnectionListener is checkout from the ManagedConnectionPool.

      I understand that 2 threads in the same Tx could both get a different managed connection, so I'm considering re-writing BasePool.getConnection(..) to temporarily lock on the ThreadLocal when trackByTx is active.

      Code now

       public ConnectionListener getConnection(Transaction transaction, Subject subject, ConnectionRequestInfo cri)
       throws ResourceException
       {
       // Determine the pool key for this request
       boolean separateNoTx = false;
       if (noTxSeparatePools)
       separateNoTx = clf.isTransactional();
       Object key = getKey(subject, cri, separateNoTx);
       InternalManagedConnectionPool mcp = getPool(key, subject, cri);
      
       // Are we doing track by connection?
       TransactionLocal trackByTx = null;
       if (transaction != null)
       trackByTx = (TransactionLocal) trackByTxPools.get(key);
      
       // Do we have a previous connection in this transaction?
       if (trackByTx != null)
       {
       ConnectionListener cl = (ConnectionListener) trackByTx.get(transaction);
       if (cl != null)
       {
       if (traceEnabled)
       dump("Getting connection tracked by transaction " + cl);
       return cl;
       }
       }
      
       // Get a connection from the correct pool
       ConnectionListener cl = mcp.getConnection(subject, cri);
      
       // Are we tracking by connection?
       if (transaction != null && trackByTx != null)
       {
       cl.setTrackByTx(true);
       trackByTx.set(cl);
       }
      
       if (traceEnabled)
       dump("Getting connection from pool " + cl);
       return cl;
       }
      


      Changed to

       /**
       * Return a connection from the pool, optionally tracked by a transaction
       */
       public ConnectionListener getConnection(Transaction transaction, Subject subject, ConnectionRequestInfo cri)
       throws ResourceException
       {
       // The connection listener to return
       ConnectionListener cl;
      
       // Use separate pools, if noTxSeparatePools configured in the
       // BasePool and the ConnectionListenerFactory is transactional
       boolean separateNoTx = false;
       if (noTxSeparatePools)
       {
       separateNoTx = clf.isTransactional();
       }
       // The overriding subclass determines the pool key for this request
       Object key = getKey(subject, cri, separateNoTx);
      
       // Get the pool for this particular key, create it first if needed
       InternalManagedConnectionPool mcp = getPool(key, subject, cri);
      
       // Are we tracking connection by transaction?
       //
       // TxConnectionManager will pass a non-null transaction if there
       // is a transaction associated with the thread and the connection
       // manager is configured to trackConnectionByTx
      
       if (transaction != null)
       {
       TransactionLocal trackByTx = (TransactionLocal) trackByTxPools.get(key);
      
       if (trackByTx != null)
       {
       // If trackByTx we need to synchronize competing threads
       // on the TransactionLocal, so they end up using the same
       // ConnectionListener/ManagedConnection
      
       trackByTx.lock();
       try
       {
       // Do we have a previous connection in this transaction?
       cl = (ConnectionListener) trackByTx.get(transaction);
      
       // If yes use it, if no get a one from the pool
       if (cl != null)
       {
       if (traceEnabled)
       log.trace("Getting existing connection tracked by transaction");
       }
       else
       {
       // Get a new connection (listener) from the pool
       cl = mcp.getConnection(subject, cri);
       // Mark that is tracked by transaction
       cl.setTrackByTx(true);
       // Store the connection listener to the TransactionLocal
       trackByTx.set(cl);
      
       if (traceEnabled)
       log.trace("Getting a connection from the pool to track the transaction");
       }
       }
       finally
       {
       trackByTx.unlock();
       }
       }
       else
       {
       // Weird, can happen only if BasePool.getTransationManager()
       // returns null, while constructing the TransactionLocal in
       // getPool(). Treat as if trackByTx is disabled
       if (traceEnabled)
       log.trace("TrackByTx true, but no TransactionManager associated with the pool;" +
       " getting a connection from the pool");
      
       // Get a new connection (listener) from the pool
       cl = mcp.getConnection(subject, cri);
       }
       }
       else
       {
       // Not tracking connection by transaction
       if (traceEnabled)
       log.trace("Getting a connection from the pool");
      
       // Get a connection from the correct pool
       cl = mcp.getConnection(subject, cri);
       }
      
       if (traceEnabled)
       dump("Returning connection " + cl);
      
       return cl;
       }