MT-change to JBossManagedConnectionPool.BasePool.getConnecti
dimitris Jun 2, 2005 10:16 AMPossible 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; }