001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.object.tx;
005:
006: import com.tc.object.lockmanager.api.LockID;
007: import com.tc.util.Assert;
008: import com.tc.util.Stack;
009:
010: import java.util.Iterator;
011:
012: /**
013: * We have two concepts. Transactions which carry changes/creates etc... And the locks That are associated with those
014: * transactions. Transactions need to be created and then continued until the next transaction exit (in other words not
015: * just until the next begin) if we are to maintain proper semantics/ordering. The Locks on the otherhand work more like
016: * a stack. When a block is entered the locks get pushed onto the stack and associated with the current transaction and
017: * when they are exited they are removed from the current transaction. This class maintains both the current transaction
018: * and the stack of contexts that are associated with the thread.
019: */
020: public class ThreadTransactionContext {
021: private ClientTransaction currentTransaction;
022: private Stack transactionStack = new Stack();
023:
024: public void setCurrentTransaction(ClientTransaction tx) {
025: Assert.eval(tx != null);
026: this .currentTransaction = tx;
027: }
028:
029: public ClientTransaction getCurrentTransaction() {
030: return currentTransaction;
031: }
032:
033: public ClientTransaction popCurrentTransaction() {
034: transactionStack.pop();
035: ClientTransaction ctx = currentTransaction;
036: currentTransaction = null;
037: return ctx;
038: }
039:
040: public TransactionContext peekContext(LockID id) {
041: if (transactionStack.isEmpty())
042: return null;
043: int len = transactionStack.size();
044: TransactionContext tc = null;
045: int i = len - 1;
046: for (; i >= 0; i--) {
047: tc = (TransactionContext) transactionStack.get(i);
048: if (tc.getLockID().equals(id)) {
049: return tc;
050: }
051: }
052: return null;
053: }
054:
055: public ClientTransaction popCurrentTransaction(LockID id) {
056: int len = transactionStack.size();
057: boolean found = false;
058: TransactionContext tc = null;
059: int i = len - 1;
060: for (; i >= 0; i--) {
061: tc = (TransactionContext) transactionStack.get(i);
062: if (tc.getLockID().equals(id)) {
063: found = true;
064: break;
065: }
066: }
067: if (found) {
068: for (int j = i + 1; j < len; j++) {
069: tc = (TransactionContext) transactionStack.get(j);
070: tc.removeLock(id);
071: }
072: transactionStack.remove(i);
073: }
074:
075: ClientTransaction ctx = currentTransaction;
076: currentTransaction = null;
077: return ctx;
078: }
079:
080: public void pushContext(LockID id, TxnType txType) {
081: transactionStack.push(new TransactionContextImpl(id, txType,
082: getAllLockIDs(id)));
083: }
084:
085: private LockID[] getAllLockIDs(LockID id) {
086: LockID[] lids = new LockID[transactionStack.size() + 1];
087: lids[0] = id;
088: for (int i = 1; i < lids.length; i++) {
089: TransactionContext tc = (TransactionContext) transactionStack
090: .get(i - 1);
091: lids[i] = tc.getLockID();
092: }
093: return lids;
094: }
095:
096: public void removeLock(LockID id) {
097: for (Iterator i = transactionStack.iterator(); i.hasNext();) {
098: TransactionContext tc = (TransactionContext) i.next();
099: if (id.equals(tc.getLockID())) {
100: i.remove();
101: } else {
102: tc.removeLock(id);
103: }
104: }
105: }
106:
107: public TransactionContext peekContext() {
108: if (transactionStack.isEmpty())
109: return null;
110: return (TransactionContext) transactionStack.peek();
111: }
112: }
|