From 312018c6ef5a3231c260e4ecdcd4c83588b56479 Mon Sep 17 00:00:00 2001 From: "Brian S. O'Neill" Date: Wed, 10 Aug 2011 17:39:53 +0000 Subject: Fix thread-local memory leaks. --- .../amazon/carbonado/repo/map/MapRepository.java | 5 ++++ .../amazon/carbonado/txn/TransactionManager.java | 31 ++++++++++++++++++++++ .../com/amazon/carbonado/txn/TransactionScope.java | 14 ++++++++-- 3 files changed, 48 insertions(+), 2 deletions(-) (limited to 'src/main/java/com/amazon') diff --git a/src/main/java/com/amazon/carbonado/repo/map/MapRepository.java b/src/main/java/com/amazon/carbonado/repo/map/MapRepository.java index 7fbe16a..ac847f1 100644 --- a/src/main/java/com/amazon/carbonado/repo/map/MapRepository.java +++ b/src/main/java/com/amazon/carbonado/repo/map/MapRepository.java @@ -89,6 +89,11 @@ class MapRepository extends AbstractRepository return ((MapStorage) storageFor(storableType)).getIndexInfo(); } + @Override + protected void finalize() { + close(); + } + @Override protected Log getLog() { return null; diff --git a/src/main/java/com/amazon/carbonado/txn/TransactionManager.java b/src/main/java/com/amazon/carbonado/txn/TransactionManager.java index 19aec4d..6ae3b2e 100644 --- a/src/main/java/com/amazon/carbonado/txn/TransactionManager.java +++ b/src/main/java/com/amazon/carbonado/txn/TransactionManager.java @@ -157,6 +157,9 @@ public abstract class TransactionManager { for (TransactionScope scope : mAllScopes.keySet()) { scope.close(); } + + mAllScopes.clear(); + mLocalScope.remove(); } public synchronized boolean isClosed() { @@ -270,4 +273,32 @@ public abstract class TransactionManager { * Aborts and closes the given internal transaction. */ protected abstract void abortTxn(Txn txn) throws PersistException; + + static class Closed extends TransactionManager { + static final Closed THE = new Closed(); + + @Override + protected IsolationLevel selectIsolationLevel(Transaction parent, IsolationLevel level) { + return IsolationLevel.SERIALIZABLE; + } + + @Override + protected boolean supportsForUpdate() { + return true; + } + + @Override + protected Object createTxn(Object parent, IsolationLevel level) throws Exception { + throw new IllegalStateException("Transaction manager is closed"); + } + + @Override + protected boolean commitTxn(Object txn) throws PersistException { + return false; + } + + @Override + protected void abortTxn(Object txn) throws PersistException { + } + } } diff --git a/src/main/java/com/amazon/carbonado/txn/TransactionScope.java b/src/main/java/com/amazon/carbonado/txn/TransactionScope.java index 2110ff6..7ff5997 100644 --- a/src/main/java/com/amazon/carbonado/txn/TransactionScope.java +++ b/src/main/java/com/amazon/carbonado/txn/TransactionScope.java @@ -43,9 +43,16 @@ import com.amazon.carbonado.spi.ExceptionTransformer; * @see TransactionManager */ public class TransactionScope { - final TransactionManager mTxnMgr; final Lock mLock; + // Note: Cannot be final because it needs to be replaced by close + // method. Access doesn't need to be synchronized, because only one thread + // ever accesses scope instances. The close method might be called by a + // separate thread, in which case the closed transaction manager reference + // might not be immediately visible by the thread which needs it. This is + // not harmful. + TransactionManager mTxnMgr; + TransactionImpl mActive; // Tracks all registered cursors by storage type. @@ -55,8 +62,8 @@ public class TransactionScope { private boolean mDetached; TransactionScope(TransactionManager txnMgr, boolean closed) { - mTxnMgr = txnMgr; mLock = new ReentrantLock(true); + mTxnMgr = txnMgr; if (closed) { mLock.lock(); try { @@ -332,6 +339,9 @@ public class TransactionScope { } } finally { mClosed = true; + // Swap TransactionManager out with a dummy one, to allow the + // original one to get freed. + mTxnMgr = (TransactionManager) TransactionManager.Closed.THE; mLock.unlock(); } } -- cgit v1.2.3