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.tctest;
005:
006: import EDU.oswego.cs.dl.util.concurrent.SynchronizedInt;
007:
008: import com.tc.logging.TCLogger;
009: import com.tc.logging.TCLogging;
010: import com.tc.object.config.ConfigLockLevel;
011: import com.tc.object.config.ConfigVisitor;
012: import com.tc.object.config.DSOClientConfigHelper;
013: import com.tc.object.config.TransparencyClassSpec;
014: import com.tc.object.config.spec.SynchronizedIntSpec;
015: import com.tc.simulator.app.ApplicationConfig;
016: import com.tc.simulator.listener.ListenerProvider;
017: import com.tc.util.concurrent.ThreadUtil;
018: import com.tctest.runner.AbstractTransparentApp;
019:
020: import java.util.HashSet;
021: import java.util.LinkedList;
022: import java.util.List;
023:
024: public class ConcurrentLockSystemTestApp extends AbstractTransparentApp {
025:
026: private static final TCLogger logger = TCLogging
027: .getTestingLogger(ConcurrentLockSystemTestApp.class);
028: private final TestObject testObject = new TestObject();
029: private final SynchronizedInt participants = new SynchronizedInt(0);
030:
031: public ConcurrentLockSystemTestApp(String appId,
032: ApplicationConfig cfg, ListenerProvider listenerProvider) {
033: super (appId, cfg, listenerProvider);
034: }
035:
036: public static void visitL1DSOConfig(ConfigVisitor visitor,
037: DSOClientConfigHelper config) {
038: String testClassname = ConcurrentLockSystemTestApp.class
039: .getName();
040: TransparencyClassSpec spec = config
041: .getOrCreateSpec(testClassname);
042: spec.addRoot("testObject", testClassname + ".testObject");
043: spec.addRoot("participants", testClassname + ".participants");
044:
045: String testObjectClassname = TestObject.class.getName();
046: config.addIncludePattern(testObjectClassname);
047:
048: // create locks
049: config.addWriteAutolock("* " + testClassname + ".run()");
050: config.addWriteAutolock("* " + testObjectClassname
051: + ".populate(..)");
052: config.addReadAutolock("* " + testObjectClassname
053: + ".isPopulated()");
054: config.addAutolock("* " + testObjectClassname + ".increment()",
055: ConfigLockLevel.CONCURRENT);
056:
057: // config for SynchronizedInt
058: new SynchronizedIntSpec().visit(visitor, config);
059: }
060:
061: public void run() {
062: int participantCount = participants.increment();
063: boolean isWriter = participantCount == 1;
064: int iterations = 500;
065: int children = 50;
066: if (isWriter) {
067: testObject.populate(children);
068: for (int i = 0; i < iterations; i++) {
069: if (i % (iterations / 5) == 0)
070: info("incrementing TestObject in " + (i + 1)
071: + " of " + iterations + " iterations.");
072: testObject.increment();
073: }
074: }
075:
076: List counts;
077: while ((counts = testObject.getAllCounts()).size() != children + 1) {
078: System.err
079: .println("Cycling until the counts list is large enough: "
080: + counts);
081: ThreadUtil.reallySleep(1 * 500);
082: }
083:
084: List collapsedCounts;
085: List expectedCounts = new LinkedList();
086: expectedCounts.add(new Integer(iterations));
087: while (true) {
088: collapsedCounts = new LinkedList(new HashSet(testObject
089: .getAllCounts()));
090: if (expectedCounts.equals(collapsedCounts)) {
091: System.err.println("SUCCESS.");
092: return;
093: }
094: ThreadUtil.reallySleep(1 * 500);
095: }
096: }
097:
098: private void info(Object msg) {
099: logger.info(this + ": " + msg);
100: }
101:
102: private static final class TestObject {
103:
104: private TestObject child;
105: private int size;
106: private int count;
107:
108: public synchronized String toString() {
109: return "TestObject[child="
110: + (child == null ? "null" : "TestObject")
111: + ", size=" + size + ", count=" + count + "]";
112: }
113:
114: public synchronized void populate(int populateCount) {
115: if (isPopulated()) {
116: info("TestObject already populated; not populating.");
117: return;
118: }
119: info("Populating TestObject with " + populateCount
120: + " children...");
121: TestObject to = this ;
122: for (int i = 0; i < populateCount; i++) {
123: synchronized (to) {
124: to.child = new TestObject();
125: }
126: to = to.child;
127: }
128: this .size = populateCount;
129: info("Done populating TestObject.");
130: }
131:
132: public synchronized List getAllCounts() {
133: TestObject to = this ;
134: List rv = new LinkedList();
135: while (to != null) {
136: rv.add(new Integer(count));
137: to = to.child;
138: }
139: return rv;
140: }
141:
142: public synchronized boolean isPopulated() {
143: return this .child != null;
144: }
145:
146: public void increment() {
147: TestObject to = this ;
148: synchronized (this ) {
149: do {
150: to.basicIncrement();
151: to = to.child;
152: } while (to != null);
153: }
154: }
155:
156: private void basicIncrement() {
157: count++;
158: }
159:
160: private void info(Object msg) {
161: logger.info(this + ": " + msg);
162: }
163:
164: }
165:
166: }
|