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.tcsimulator;
006:
007: import EDU.oswego.cs.dl.util.concurrent.BrokenBarrierException;
008: import EDU.oswego.cs.dl.util.concurrent.CountDown;
009: import EDU.oswego.cs.dl.util.concurrent.CyclicBarrier;
010:
011: import com.tc.object.config.ConfigVisitor;
012: import com.tc.object.config.DSOClientConfigHelper;
013: import com.tc.object.config.spec.CountDownSpec;
014: import com.tc.object.config.spec.CyclicBarrierSpec;
015: import com.tc.simulator.control.Control;
016: import com.tc.simulator.control.TCBrokenBarrierException;
017: import com.tc.simulator.listener.MutationCompletionListener;
018:
019: public class ControlImpl implements Control, MutationCompletionListener {
020: private static final boolean DEBUG = false;
021:
022: private final int mutatorCount;
023: private final int completeParties;
024: private final CyclicBarrier startBarrier;
025: private final CountDown validationStartCount;
026: private final CountDown countdown;
027: private final int validatorCount;
028: private final Control testWideControl;
029: private final boolean crashActiveServerAfterMutate;
030:
031: private CountDown mutationCompleteCount;
032: private long executionTimeout;
033:
034: public ControlImpl(int mutatorCount) {
035: this (mutatorCount, 0, false);
036: }
037:
038: // used to create container-wide control
039: public ControlImpl(int mutatorCount, Control testWideControl) {
040: this (mutatorCount, 0, testWideControl, false);
041: }
042:
043: // used to create test-wide control
044: public ControlImpl(int mutatorCount, int validatorCount,
045: boolean crashActiveServerAfterMutate) {
046: this (mutatorCount, validatorCount, null,
047: crashActiveServerAfterMutate);
048: }
049:
050: public ControlImpl(int mutatorCount, int validatorCount,
051: Control testWideControl,
052: boolean crashActiveServerAfterMutate) {
053: if (mutatorCount < 0 || validatorCount < 0) {
054: throw new AssertionError(
055: "MutatorCount and validatorCount must be non-negative numbers! mutatorCount=["
056: + mutatorCount + "] validatorCount=["
057: + validatorCount + "]");
058: }
059:
060: executionTimeout = -1;
061: this .testWideControl = testWideControl;
062: this .crashActiveServerAfterMutate = crashActiveServerAfterMutate;
063: this .mutatorCount = mutatorCount;
064: this .validatorCount = validatorCount;
065: completeParties = mutatorCount + validatorCount;
066:
067: debugPrintln("####### completeParties=[" + completeParties
068: + "]");
069:
070: startBarrier = new CyclicBarrier(this .mutatorCount);
071: mutationCompleteCount = new CountDown(this .mutatorCount);
072: countdown = new CountDown(completeParties);
073:
074: // "1" indicates the server
075: if (this .crashActiveServerAfterMutate) {
076: validationStartCount = new CountDown(completeParties + 1);
077: } else {
078: validationStartCount = new CountDown(completeParties);
079: }
080: }
081:
082: public static void visitL1DSOConfig(ConfigVisitor visitor,
083: DSOClientConfigHelper config) {
084: String classname = ControlImpl.class.getName();
085: config.addIncludePattern(classname);
086: config.addWriteAutolock("* " + classname + ".*(..)");
087:
088: String cyclicBarrierClassname = CyclicBarrier.class.getName();
089: config.addIncludePattern(cyclicBarrierClassname);
090: config.addWriteAutolock("* " + cyclicBarrierClassname
091: + ".*(..)");
092:
093: String countdownClassname = CountDown.class.getName();
094: config.addIncludePattern(countdownClassname);
095: config.addWriteAutolock("* " + countdownClassname + ".*(..)");
096: }
097:
098: public static void visitDSOApplicationConfig(
099: com.tc.object.config.ConfigVisitor visitor,
100: com.tc.object.config.DSOApplicationConfig config) {
101: String classname = ControlImpl.class.getName();
102: config.addIncludePattern(classname);
103: config.addWriteAutolock("* " + classname + ".*(..)");
104:
105: new CyclicBarrierSpec().visit(visitor, config);
106: new CountDownSpec().visit(visitor, config);
107:
108: }
109:
110: public String toString() {
111: return getClass().getName() + "[ mutatorCount=" + mutatorCount
112: + ", completeParties=" + completeParties
113: + ", startBarrier=" + startBarrier + ", countdown="
114: + countdown + ", mutationCompleteCount="
115: + mutationCompleteCount + ", validatorCount="
116: + validatorCount + " ]"
117: + ", crashActiveServerAfterMutate=["
118: + crashActiveServerAfterMutate + "]";
119: }
120:
121: public void waitForStart() throws InterruptedException,
122: TCBrokenBarrierException {
123: try {
124: try {
125: this .startBarrier.barrier();
126: } catch (InterruptedException e1) {
127: throw e1;
128: }
129: } catch (BrokenBarrierException e) {
130: throw new TCBrokenBarrierException(e);
131: }
132: }
133:
134: public void notifyMutationComplete() {
135: mutationCompleteCount.release();
136: }
137:
138: public void notifyValidationStart() {
139: debugPrintln("******** validation.release() called: init=["
140: + validationStartCount.initialCount() + "] before=["
141: + validationStartCount.currentCount() + "]");
142: validationStartCount.release();
143: debugPrintln("******* validation.release() called: after=["
144: + validationStartCount.currentCount() + "]");
145: }
146:
147: /*
148: * Control interface method
149: */
150: public boolean waitForMutationComplete(long timeout)
151: throws InterruptedException {
152: if (timeout < 0) {
153: while (true) {
154: synchronized (this ) {
155: wait();
156: }
157: }
158: }
159: try {
160: checkExecutionTimeout(timeout);
161: boolean rv = mutationCompleteCount.attempt(timeout);
162: return rv;
163: } catch (InterruptedException e) {
164: throw e;
165: }
166: }
167:
168: public boolean waitForValidationStart(long timeout)
169: throws InterruptedException {
170: debugPrintln("******* waitForValidationStart: validationStartCount=["
171: + validationStartCount.currentCount() + "]");
172: if (timeout < 0) {
173: while (true) {
174: synchronized (this ) {
175: wait();
176: }
177: }
178: }
179: try {
180: checkExecutionTimeout(timeout);
181: boolean rv = validationStartCount.attempt(timeout);
182: return rv;
183: } catch (InterruptedException e) {
184: throw e;
185: }
186: }
187:
188: /*
189: * MutationCompletionListener interface method -- called by applications
190: */
191: public void waitForMutationCompleteTestWide() throws Exception {
192: try {
193: if (testWideControl == null) {
194: throw new AssertionError(
195: "Application should be calling this on container-wide control, not test-wide control.");
196: }
197: checkExecutionTimeout(executionTimeout);
198: boolean rv = testWideControl
199: .waitForMutationComplete(executionTimeout);
200: if (!rv) {
201: throw new RuntimeException(
202: "Wait on MutationCompletionCount did not pass: executionTimeout=["
203: + executionTimeout + "] ");
204: }
205: } catch (InterruptedException e) {
206: throw e;
207: }
208: }
209:
210: public void waitForValidationStartTestWide() throws Exception {
211: try {
212: if (testWideControl == null) {
213: throw new AssertionError(
214: "Application should be calling this on container-wide control, not test-wide control.");
215: }
216: checkExecutionTimeout(executionTimeout);
217: boolean rv = testWideControl
218: .waitForValidationStart(executionTimeout);
219: if (!rv) {
220: throw new RuntimeException(
221: "Wait on ValidationStartCount did not pass: executionTimeout=["
222: + executionTimeout + "] ");
223: }
224: } catch (InterruptedException e) {
225: throw e;
226: }
227: }
228:
229: public void notifyComplete() {
230: debugPrintln("******* countdown called: control=["
231: + toString() + "]");
232: this .countdown.release();
233: }
234:
235: public boolean waitForAllComplete(long timeout)
236: throws InterruptedException {
237: if (timeout < 0) {
238: while (true) {
239: synchronized (this ) {
240: wait();
241: }
242: }
243: }
244: try {
245: checkExecutionTimeout(timeout);
246: boolean rv = this .countdown.attempt(timeout);
247: return rv;
248: } catch (InterruptedException e) {
249: throw e;
250: }
251: }
252:
253: public void setExecutionTimeout(long timeout) {
254: checkExecutionTimeout(timeout);
255: executionTimeout = timeout;
256: }
257:
258: private void checkExecutionTimeout(long timeout) {
259: if (timeout < 0) {
260: throw new AssertionError(
261: "Execution timeout should be a non-negative number: timeout=["
262: + timeout + "]");
263: }
264: }
265:
266: private void debugPrintln(String s) {
267: if (DEBUG) {
268: System.err.println(s);
269: }
270: }
271: }
|