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.objectserver.lockmanager.impl;
005:
006: import com.tc.logging.TCLogger;
007: import com.tc.logging.TCLogging;
008: import com.tc.net.protocol.tcm.MessageChannel;
009: import com.tc.object.net.DSOChannelManager;
010: import com.tc.object.net.NoSuchChannelException;
011: import com.tc.objectserver.lockmanager.api.LockAwardContext;
012: import com.tc.objectserver.lockmanager.api.LockEventListener;
013: import com.tc.util.Assert;
014:
015: import java.util.HashMap;
016: import java.util.HashSet;
017: import java.util.Map;
018: import java.util.Set;
019: import java.util.Timer;
020: import java.util.TimerTask;
021:
022: /**
023: * Implementation of a lock timer.
024: */
025: public class LockTimer implements LockEventListener {
026:
027: private static final TCLogger logger = TCLogging
028: .getLogger(LockTimer.class);
029:
030: private final Timer timer = new Timer(true);
031: private final DSOChannelManager channelManager;
032: private final Map tasks = new HashMap();
033: private final Set uncontended = new HashSet();
034:
035: LockTimer(DSOChannelManager channelManager) {
036: this .channelManager = channelManager;
037: }
038:
039: synchronized void startTimerForLock(LockAwardContext awardContext) {
040: logStartTimerForLock(awardContext);
041: LockTimeoutTask task = new LockTimeoutTask(awardContext);
042: putTimerTask(task);
043: timer.schedule(task, task.getTimeout());
044: }
045:
046: synchronized LockAwardContext cancel(LockAwardContext awardContext) {
047: logCancel(awardContext);
048: LockTimeoutTask task = removeTimerTask(awardContext);
049: if (task != null) {
050: task.cancel();
051: return task.awardContext;
052: } else {
053: return null;
054: }
055: }
056:
057: /*********************************************************************************************************************
058: * LockEventListener interface
059: */
060:
061: /**
062: * If the waiter count is 1, then this is the first waiter. We should schedule a timeout for this lock award context.
063: * Otherwise, we shouldn't do anything.
064: */
065: public synchronized void notifyAddPending(int waiterCount,
066: LockAwardContext ctxt) {
067: Assert.eval(waiterCount > 0);
068: if (waiterCount == 1) {
069: logNotifyAddWaitingStartTimer(waiterCount, ctxt);
070: startTimerForLock(ctxt);
071: } else {
072: logNotifyAddWaitingUncontended(waiterCount, ctxt);
073: uncontended.add(ctxt);
074: }
075: }
076:
077: private void logNotifyAddWaitingStartTimer(int waiterCount,
078: LockAwardContext ctxt) {
079: if (logger.isDebugEnabled()) {
080: logger.debug("notifyAddWaiting(waiterCount=" + waiterCount
081: + ", ctxt=" + ctxt + "): starting lock timer...");
082: }
083: }
084:
085: private void logNotifyAddWaitingUncontended(int waiterCount,
086: LockAwardContext ctxt) {
087: if (logger.isDebugEnabled()) {
088: logger.debug("notifyAddWaiting(watierCount=" + waiterCount
089: + ", ctxt=" + ctxt + "): adding to uncontended...");
090: }
091: }
092:
093: /**
094: * If the waiter count is greater than zero, we should schedule a timeout for this lock award context. Otherwise, we
095: * shouldn't do anything.
096: */
097: public synchronized void notifyAward(int waiterCount,
098: LockAwardContext ctxt) {
099: Assert.eval(waiterCount >= 0);
100: if (waiterCount > 0) {
101: logNotifyAwardStartTimer(waiterCount, ctxt);
102: startTimerForLock(ctxt);
103: } else {
104: logNotifyAwardUncontended(waiterCount, ctxt);
105: uncontended.add(ctxt);
106: }
107: }
108:
109: private void logNotifyAwardStartTimer(int waiterCount,
110: LockAwardContext ctxt) {
111: if (logger.isDebugEnabled()) {
112: logger.debug("notifyAward(waiterCount=" + waiterCount
113: + ", ctxt=" + ctxt + "): starting lock timer...");
114: }
115: }
116:
117: private void logNotifyAwardUncontended(int waiterCount,
118: LockAwardContext ctxt) {
119: if (logger.isDebugEnabled()) {
120: logger.debug("notifyAward(waiterCount=" + waiterCount
121: + ", ctxt=" + ctxt + "): adding to uncontended...");
122: }
123: }
124:
125: /**
126: * We should cancel any existing timers for the given lock award context.
127: */
128: public synchronized void notifyRevoke(LockAwardContext ctxt) {
129: LockAwardContext cancelled = cancel(ctxt);
130: logNotifyRevoke(ctxt, cancelled);
131: if (cancelled == null) {
132: // check to make sure that it was uncontended
133: Assert
134: .eval(
135: "Attempt to revoke a lock that was not awarded and not uncontended.",
136: uncontended.remove(ctxt));
137: }
138: }
139:
140: private void logNotifyRevoke(LockAwardContext ctxt,
141: LockAwardContext cancelled) {
142: if (logger.isDebugEnabled()) {
143: logger.debug("notifyRevoke(ctxt=" + ctxt + "): cancelled="
144: + cancelled);
145: }
146: }
147:
148: /*********************************************************************************************************************
149: * Private stuff.
150: */
151:
152: private void putTimerTask(LockTimeoutTask task) {
153: synchronized (this .tasks) {
154: this .tasks.put(task.awardContext, task);
155: }
156: }
157:
158: private LockTimeoutTask removeTimerTask(
159: LockAwardContext awardContext) {
160: synchronized (this .tasks) {
161: return (LockTimeoutTask) this .tasks.remove(awardContext);
162: }
163: }
164:
165: private void logStartTimerForLock(LockAwardContext awardContext) {
166: if (logger.isDebugEnabled()) {
167: logger.debug("startTimerForLock(" + awardContext + ")");
168: }
169: }
170:
171: private void logCancel(LockAwardContext awardContext) {
172: if (logger.isDebugEnabled()) {
173: logger.debug("cancel(" + awardContext + ")");
174: }
175: }
176:
177: private class LockTimeoutTask extends TimerTask {
178: private final LockAwardContext awardContext;
179:
180: private LockTimeoutTask(LockAwardContext ctxt) {
181: Assert.assertNotNull(ctxt);
182: Assert.assertNotNull(ctxt.getNodeID());
183: this .awardContext = ctxt;
184: }
185:
186: long getTimeout() {
187: return awardContext.getTimeout();
188: }
189:
190: public void run() {
191: logger.warn("Lock timeout: " + this .awardContext);
192: try {
193: MessageChannel channel = channelManager
194: .getActiveChannel(this .awardContext.getNodeID());
195: logger
196: .warn("Closing channel because of lock timeout. Award context: "
197: + this .awardContext
198: + "; channel: "
199: + channel);
200: channel.close();
201: } catch (NoSuchChannelException e) {
202: logger
203: .warn("Attempting to close channel because of lock timeout. Couldn't find channel by channel id: "
204: + this.awardContext.getNodeID());
205: }
206: }
207: }
208:
209: }
|