001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.object.lockmanager.api;
006:
007: import com.tc.exception.ImplementMe;
008: import com.tc.object.session.SessionProvider;
009: import com.tc.object.tx.TransactionID;
010: import com.tc.object.tx.WaitInvocation;
011: import com.tc.util.concurrent.NoExceptionLinkedQueue;
012:
013: import java.util.Arrays;
014: import java.util.Collection;
015: import java.util.HashMap;
016: import java.util.Iterator;
017: import java.util.LinkedList;
018: import java.util.Map;
019:
020: /**
021: * @author steve
022: */
023: public class TestRemoteLockManager implements RemoteLockManager {
024: public final LockResponder LOOPBACK_LOCK_RESPONDER = new LoopbackLockResponder();
025: public final LockResponder NULL_LOCK_RESPONDER = new LockResponder() {
026: public void respondToLockRequest(LockRequest request) {
027: return;
028: }
029: };
030: private ClientLockManager lockManager;
031: private Map locks = new HashMap();
032: private int lockRequests = 0;
033: private int unlockRequests = 0;
034: private int flushCount = 0;
035: private boolean isGreedy = false;
036: public LockResponder lockResponder = LOOPBACK_LOCK_RESPONDER;
037:
038: public final NoExceptionLinkedQueue lockRequestCalls = new NoExceptionLinkedQueue();
039: private final SessionProvider sessionProvider;
040:
041: public TestRemoteLockManager(SessionProvider sessionProvider) {
042: this .sessionProvider = sessionProvider;
043: }
044:
045: public void setClientLockManager(ClientLockManager lockManager) {
046: this .lockManager = lockManager;
047: }
048:
049: public synchronized int getLockRequestCount() {
050: return this .lockRequests;
051: }
052:
053: public synchronized int getUnlockRequestCount() {
054: return this .unlockRequests;
055: }
056:
057: // *************************
058: // This manager doesn't implement lock upgrades correctly. Lock
059: // upgrades/downgrades are always awarded. Locks held
060: // by other transactions are not taken into consideration
061: // *************************
062:
063: public synchronized void requestLock(LockID lockID,
064: ThreadID threadID, int lockType) {
065: lockRequests++;
066: lockRequestCalls.put(new Object[] { lockID, threadID,
067: new Integer(lockType) });
068:
069: LockRequest request;
070: if (isGreedy) {
071: request = new LockRequest(lockID, ThreadID.VM_ID, LockLevel
072: .makeGreedy(lockType));
073: } else {
074: request = new LockRequest(lockID, threadID, lockType);
075: }
076:
077: if (!locks.containsKey(lockID)) {
078: locks.put(lockID, new LinkedList(
079: Arrays.asList(new Object[] { new Lock(threadID,
080: lockType) })));
081: lockResponder.respondToLockRequest(request);
082: return;
083: }
084:
085: LinkedList myLocks = (LinkedList) locks.get(lockID);
086: for (Iterator iter = myLocks.iterator(); iter.hasNext();) {
087: // allow lock upgrades/downgrades
088: Lock lock = (Lock) iter.next();
089: if (lock.threadID.equals(threadID)) {
090: lock.upCount();
091: lockResponder.respondToLockRequest(request);
092: return;
093: }
094: }
095:
096: myLocks.addLast(new Lock(request.threadID(), request
097: .lockLevel()));
098: }
099:
100: public synchronized void makeLocksGreedy() {
101: isGreedy = true;
102: }
103:
104: public synchronized void makeLocksNotGreedy() {
105: isGreedy = false;
106: }
107:
108: public synchronized void releaseLock(LockID lockID,
109: ThreadID threadID) {
110: unlockRequests++;
111:
112: LinkedList myLocks = (LinkedList) locks.get(lockID);
113:
114: Lock current = (Lock) myLocks.getFirst();
115: if (current.threadID.equals(threadID)) {
116: int count = current.downCount();
117: if (count == 0) {
118: myLocks.removeFirst();
119: } else {
120: return;
121: }
122: }
123:
124: if (myLocks.isEmpty()) {
125: locks.remove(lockID);
126: return;
127: }
128:
129: Lock lock = (Lock) myLocks.remove(0);
130: lockResponder.respondToLockRequest(new LockRequest(lockID,
131: lock.threadID, lock.type));
132: }
133:
134: public void releaseLockWait(LockID lockID, ThreadID threadID,
135: WaitInvocation call) {
136: return;
137: }
138:
139: public void recallCommit(LockID lockID, Collection lockContext,
140: Collection waitContext, Collection pendingRequests,
141: Collection pendingTryLockRequests) {
142: return;
143: }
144:
145: public synchronized void flush(LockID lockID) {
146: flushCount++;
147: }
148:
149: public synchronized void resetFlushCount() {
150: flushCount = 0;
151: }
152:
153: public synchronized int getFlushCount() {
154: return flushCount;
155: }
156:
157: public boolean isTransactionsForLockFlushed(LockID lockID,
158: LockFlushCallback callback) {
159: return true;
160: }
161:
162: public void notify(LockID lockID, TransactionID transactionID,
163: boolean all) {
164: // TODO: this really should get called by a test at some point. At such
165: // time, you probably want to record the
166: // request and return
167: throw new ImplementMe();
168: }
169:
170: public interface LockResponder {
171: void respondToLockRequest(LockRequest request);
172: }
173:
174: private class LoopbackLockResponder implements LockResponder {
175: public void respondToLockRequest(LockRequest request) {
176: lockManager.awardLock(sessionProvider.getSessionID(),
177: request.lockID(), request.threadID(), request
178: .lockLevel());
179: }
180: }
181:
182: private static class Lock {
183: final ThreadID threadID;
184: final int type;
185: int count = 1;
186:
187: Lock(ThreadID threadID, int type) {
188: this .threadID = threadID;
189: this .type = type;
190: }
191:
192: int upCount() {
193: return ++count;
194: }
195:
196: int downCount() {
197: return --count;
198: }
199: }
200:
201: public void queryLock(LockID lockID, ThreadID threadID) {
202: throw new ImplementMe();
203: }
204:
205: public void interrruptWait(LockID lockID, ThreadID threadID) {
206: throw new ImplementMe();
207: }
208:
209: public void tryRequestLock(LockID lockID, ThreadID threadID,
210: WaitInvocation timeout, int lockType) {
211: //
212: }
213: }
|