summaryrefslogtreecommitdiff
path: root/src/main/java/com/amazon/carbonado/spi
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/amazon/carbonado/spi')
-rw-r--r--src/main/java/com/amazon/carbonado/spi/AbstractRepository.java10
-rw-r--r--src/main/java/com/amazon/carbonado/spi/TransactionManager.java51
-rw-r--r--src/main/java/com/amazon/carbonado/spi/TransactionScope.java62
3 files changed, 99 insertions, 24 deletions
diff --git a/src/main/java/com/amazon/carbonado/spi/AbstractRepository.java b/src/main/java/com/amazon/carbonado/spi/AbstractRepository.java
index 7150f56..c9bc0b5 100644
--- a/src/main/java/com/amazon/carbonado/spi/AbstractRepository.java
+++ b/src/main/java/com/amazon/carbonado/spi/AbstractRepository.java
@@ -112,19 +112,19 @@ public abstract class AbstractRepository<Txn>
}
public Transaction enterTransaction() {
- return mTxnMgr.localTransactionScope().enter(null);
+ return mTxnMgr.localScope().enter(null);
}
public Transaction enterTransaction(IsolationLevel level) {
- return mTxnMgr.localTransactionScope().enter(level);
+ return mTxnMgr.localScope().enter(level);
}
public Transaction enterTopTransaction(IsolationLevel level) {
- return mTxnMgr.localTransactionScope().enterTop(level);
+ return mTxnMgr.localScope().enterTop(level);
}
public IsolationLevel getTransactionIsolationLevel() {
- return mTxnMgr.localTransactionScope().getIsolationLevel();
+ return mTxnMgr.localScope().getIsolationLevel();
}
/**
@@ -217,7 +217,7 @@ public abstract class AbstractRepository<Txn>
* Returns the thread-local TransactionScope, creating it if needed.
*/
protected TransactionScope<Txn> localTransactionScope() {
- return mTxnMgr.localTransactionScope();
+ return mTxnMgr.localScope();
}
/**
diff --git a/src/main/java/com/amazon/carbonado/spi/TransactionManager.java b/src/main/java/com/amazon/carbonado/spi/TransactionManager.java
index 9afddd8..4a28d24 100644
--- a/src/main/java/com/amazon/carbonado/spi/TransactionManager.java
+++ b/src/main/java/com/amazon/carbonado/spi/TransactionManager.java
@@ -35,12 +35,12 @@ import com.amazon.carbonado.Transaction;
* @author Brian S O'Neill
*/
public abstract class TransactionManager<Txn> {
- private static final int NOT_CLOSED = 0, CLOSED = 1, SUSPENDED = 2;
+ private static final int OPEN = 0, CLOSED = 1, SUSPENDED = 2;
private final ThreadLocal<TransactionScope<Txn>> mLocalScope;
private final Map<TransactionScope<Txn>, ?> mAllScopes;
- private int mClosedState;
+ private int mState;
public TransactionManager() {
mLocalScope = new ThreadLocal<TransactionScope<Txn>>();
@@ -50,17 +50,17 @@ public abstract class TransactionManager<Txn> {
/**
* Returns the thread-local TransactionScope, creating it if needed.
*/
- public TransactionScope<Txn> localTransactionScope() {
+ public TransactionScope<Txn> localScope() {
TransactionScope<Txn> scope = mLocalScope.get();
if (scope == null) {
- int closedState;
+ int state;
synchronized (this) {
- closedState = mClosedState;
- scope = new TransactionScope<Txn>(this, closedState != NOT_CLOSED);
+ state = mState;
+ scope = new TransactionScope<Txn>(this, state != OPEN);
mAllScopes.put(scope, null);
}
mLocalScope.set(scope);
- if (closedState == SUSPENDED) {
+ if (state == SUSPENDED) {
// Immediately suspend new scope.
scope.getLock().lock();
}
@@ -69,6 +69,39 @@ public abstract class TransactionManager<Txn> {
}
/**
+ * Detaches the thread-local TransactionScope from the current thread. It
+ * can be {@link TransactionScope#attach attached} later, and to any thread
+ * which does not currently have a TransactionScope.
+ *
+ * @return detached thread-local TransactionScope or null if none
+ */
+ /*
+ public TransactionScope<Txn> detachLocalScope() {
+ TransactionScope<Txn> scope = mLocalScope.get();
+ if (scope != null) {
+ if (!scope.detach()) {
+ scope = null;
+ } else {
+ mLocalScope.remove();
+ }
+ }
+ return scope;
+ }
+ */
+
+ // Called by TransactionScope.
+ /*
+ void attach(TransactionScope<Txn> scope) {
+ TransactionScope<Txn> existing = mLocalScope.get();
+ if (existing == null || existing == scope) {
+ mLocalScope.set(scope);
+ } else {
+ throw new IllegalStateException("Current thread already has a transaction scope");
+ }
+ }
+ */
+
+ /**
* Closes all transaction scopes. Should be called only when repository is
* closed.
*
@@ -76,7 +109,7 @@ public abstract class TransactionManager<Txn> {
* with transactions
*/
public synchronized void close(boolean suspend) throws RepositoryException {
- if (mClosedState == SUSPENDED) {
+ if (mState == SUSPENDED) {
// If suspended, attempting to close again will likely deadlock.
return;
}
@@ -90,7 +123,7 @@ public abstract class TransactionManager<Txn> {
}
}
- mClosedState = suspend ? SUSPENDED : CLOSED;
+ mState = suspend ? SUSPENDED : CLOSED;
for (TransactionScope<?> scope : mAllScopes.keySet()) {
scope.close();
diff --git a/src/main/java/com/amazon/carbonado/spi/TransactionScope.java b/src/main/java/com/amazon/carbonado/spi/TransactionScope.java
index 28d8260..0ac2cee 100644
--- a/src/main/java/com/amazon/carbonado/spi/TransactionScope.java
+++ b/src/main/java/com/amazon/carbonado/spi/TransactionScope.java
@@ -41,6 +41,8 @@ import com.amazon.carbonado.Transaction;
* @see TransactionManager
*/
public class TransactionScope<Txn> {
+ private static final int OPEN = 0, DETACHED = 1, CLOSED = 2;
+
final TransactionManager<Txn> mTxnMgr;
final Lock mLock;
@@ -49,12 +51,12 @@ public class TransactionScope<Txn> {
// Tracks all registered cursors by storage type.
private Map<Class<?>, CursorList<TransactionImpl<Txn>>> mCursors;
- private boolean mClosed;
+ private int mState;
TransactionScope(TransactionManager<Txn> txnMgr, boolean closed) {
mTxnMgr = txnMgr;
mLock = new ReentrantLock(true);
- mClosed = closed;
+ mState = closed ? CLOSED : OPEN;
}
/**
@@ -118,7 +120,7 @@ public class TransactionScope<Txn> {
public <S extends Storable> void register(Class<S> type, Cursor<S> cursor) {
mLock.lock();
try {
- checkState();
+ checkClosed();
if (mCursors == null) {
mCursors = new IdentityHashMap<Class<?>, CursorList<TransactionImpl<Txn>>>();
}
@@ -177,7 +179,7 @@ public class TransactionScope<Txn> {
public Txn getTxn() throws Exception {
mLock.lock();
try {
- checkState();
+ checkClosed();
return mActive == null ? null : mActive.getTxn();
} finally {
mLock.unlock();
@@ -190,7 +192,7 @@ public class TransactionScope<Txn> {
public boolean isForUpdate() {
mLock.lock();
try {
- return (mClosed || mActive == null) ? false : mActive.isForUpdate();
+ return (mState == CLOSED || mActive == null) ? false : mActive.isForUpdate();
} finally {
mLock.unlock();
}
@@ -203,11 +205,51 @@ public class TransactionScope<Txn> {
public IsolationLevel getIsolationLevel() {
mLock.lock();
try {
- return (mClosed || mActive == null) ? null : mActive.getIsolationLevel();
+ return (mState == CLOSED || mActive == null) ? null : mActive.getIsolationLevel();
+ } finally {
+ mLock.unlock();
+ }
+ }
+
+ /**
+ * Attach this scope to the current thread, if it has been {@link
+ * TransactionManager#detachLocalScope detached}.
+ *
+ * @throws IllegalStateException if scope is not detached or if current
+ * thread already has a transaction scope
+ */
+ /*
+ public void attach() {
+ mLock.lock();
+ try {
+ if (mState != DETACHED) {
+ throw new IllegalStateException("Transaction scope is not detached");
+ }
+ mState = OPEN;
+ } finally {
+ mLock.unlock();
+ }
+ mTxnMgr.attach(this);
+ }
+ */
+
+ /**
+ * @return false if closed
+ */
+ /*
+ boolean detach() {
+ mLock.lock();
+ try {
+ if (mState == CLOSED) {
+ return false;
+ }
+ mState = DETACHED;
+ return true;
} finally {
mLock.unlock();
}
}
+ */
/**
* Exits all transactions and closes all cursors. Should be called only
@@ -216,7 +258,7 @@ public class TransactionScope<Txn> {
void close() throws RepositoryException {
mLock.lock();
try {
- if (!mClosed) {
+ if (mState != CLOSED) {
while (mActive != null) {
mActive.exit();
}
@@ -227,7 +269,7 @@ public class TransactionScope<Txn> {
}
}
} finally {
- mClosed = true;
+ mState = CLOSED;
mLock.unlock();
}
}
@@ -235,8 +277,8 @@ public class TransactionScope<Txn> {
/**
* Caller must hold mLock.
*/
- private void checkState() {
- if (mClosed) {
+ private void checkClosed() {
+ if (mState == CLOSED) {
throw new IllegalStateException("Repository is closed");
}
}