From a257625c81ab5f535ddebeb98ebee3d8eeab0ec8 Mon Sep 17 00:00:00 2001 From: "Brian S. O'Neill" Date: Mon, 1 Oct 2012 23:42:35 +0000 Subject: Prevent deadlock during close. --- .../com/amazon/carbonado/txn/TransactionScope.java | 42 +++++++++++++--------- 1 file changed, 25 insertions(+), 17 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/com/amazon/carbonado/txn/TransactionScope.java b/src/main/java/com/amazon/carbonado/txn/TransactionScope.java index 07cb826..b39d091 100644 --- a/src/main/java/com/amazon/carbonado/txn/TransactionScope.java +++ b/src/main/java/com/amazon/carbonado/txn/TransactionScope.java @@ -319,31 +319,39 @@ public class TransactionScope { */ void close() throws RepositoryException { mLock.lock(); + if (mClosed) { + mLock.unlock(); + return; + } + + Map, CursorList>> cursors; try { - if (!mClosed) { - while (mActive != null) { - mActive.exit(); - } - if (mCursors != null) { - try { - for (CursorList> cursorList : mCursors.values()) { - cursorList.closeCursors(); - } - } finally { - // Ensure that map is freed promptly. Thread-local - // reference to this scope otherwise keeps map and its - // contents lingering around for a very long time. - mCursors = null; - } - } + cursors = mCursors; + + // Ensure that map is freed promptly. Thread-local reference to + // this scope otherwise keeps map and its contents lingering around + // for a very long time. + mCursors = null; + + while (mActive != null) { + mActive.exit(); } } finally { - mClosed = true; // Swap TransactionManager out with a dummy one, to allow the // original one to get freed. mTxnMgr = (TransactionManager) TransactionManager.Closed.THE; + mClosed = true; mLock.unlock(); } + + // Close cursors without lock held, to prevent deadlock. Cursor close + // operation might acquire its own lock, which in turn acquires a lock + // on this scope. + if (cursors != null) { + for (CursorList> cursorList : cursors.values()) { + cursorList.closeCursors(); + } + } } /** -- cgit v1.2.3