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.tctest;
006:
007: import EDU.oswego.cs.dl.util.concurrent.SynchronizedRef;
008:
009: import com.tc.object.config.ConfigVisitor;
010: import com.tc.object.config.DSOClientConfigHelper;
011: import com.tc.object.config.TransparencyClassSpec;
012: import com.tc.simulator.app.ApplicationConfig;
013: import com.tc.simulator.listener.ListenerProvider;
014: import com.tctest.runner.AbstractTransparentApp;
015:
016: import java.util.Collection;
017: import java.util.HashMap;
018: import java.util.HashSet;
019: import java.util.Iterator;
020: import java.util.Map;
021: import java.util.Set;
022:
023: public class ConcentratedClassTestApp extends AbstractTransparentApp {
024: private static final boolean DEBUG = false;
025:
026: private static final int THREAD_COUNT = 5;
027: private static Map root = new HashMap();
028: final private static long runtime = 1000 * 200; // 200 seconds
029:
030: public ConcentratedClassTestApp(String appId,
031: ApplicationConfig cfg, ListenerProvider listenerProvider) {
032: super (appId, cfg, listenerProvider);
033: if (getParticipantCount() < 2) {
034: // this test needs to have transactions coming in from other nodes (such that reflection based field set()'ing
035: // occurs as DNA is applied locally
036: throw new RuntimeException(
037: "Need at least 2 participants for this test");
038: }
039: }
040:
041: public static void visitL1DSOConfig(ConfigVisitor visitor,
042: DSOClientConfigHelper config) {
043: String testClass = ConcentratedClassTestApp.class.getName();
044: TransparencyClassSpec spec = config.getOrCreateSpec(testClass);
045: String methodExpression = "* " + testClass + "*.*(..)";
046: config.addWriteAutolock(methodExpression);
047:
048: spec.addRoot("root", "lock");
049: config.addIncludePattern(ConcentratedClass.class.getName());
050: }
051:
052: private void threadEntry(String id, int count) {
053:
054: debugPrintln("threadEntry id=[" + id + "] count=[" + count
055: + "]");
056:
057: ConcentratedClass cc = new ConcentratedClass();
058:
059: synchronized (root) {
060: final Object prev = root.put(id, cc);
061: if (prev != null) {
062: throw new RuntimeException(
063: "replaced an entry in the map for id " + id);
064: }
065:
066: if (root.size() == count) {
067: debugPrintln("notifyingAll root size matches");
068: root.notifyAll();
069: } else {
070: while (root.size() != count) {
071: try {
072: debugPrintln("waiting until root size matches");
073: root.wait();
074: } catch (InterruptedException e) {
075: throw new RuntimeException(e);
076: }
077: }
078: }
079: }
080:
081: Collection values;
082: synchronized (root) {
083: values = root.values();
084: }
085:
086: Set all = new HashSet();
087:
088: long end = System.currentTimeMillis() + runtime;
089: while (end > System.currentTimeMillis()) {
090: debugPrintln("inside while loop id=[" + id + "]");
091:
092: final ConcentratedClass prevCC;
093: final ConcentratedClass newCC = new ConcentratedClass();
094: all.add(newCC);
095:
096: synchronized (root) {
097: prevCC = (ConcentratedClass) root.put(id, newCC);
098: values = root.values();
099: }
100:
101: try {
102: Thread.sleep((int) (Math.random() * 10));
103: } catch (Exception e) {
104: //
105: }
106:
107: if (values.size() != count) {
108: throw new RuntimeException("unexpected size: "
109: + values.size());
110: }
111:
112: all.add(prevCC);
113: for (Iterator iter = all.iterator(); iter.hasNext();) {
114: ConcentratedClass someCC = (ConcentratedClass) iter
115: .next();
116: someCC.increment();
117: }
118: }
119:
120: debugPrintln("while loop ends id=[" + id + "]");
121: }
122:
123: public void run() {
124: final SynchronizedRef error = new SynchronizedRef(null);
125: final String id = getApplicationId();
126:
127: debugPrintln("Starting app run id=[" + id + "] threadCount=["
128: + THREAD_COUNT + "]");
129:
130: Thread threads[] = new Thread[THREAD_COUNT];
131: for (int i = 0; i < threads.length; i++) {
132: final int cnt = i;
133: threads[i] = new Thread(new Runnable() {
134: public void run() {
135: try {
136: threadEntry(id + cnt, getParticipantCount()
137: * THREAD_COUNT);
138: } catch (Throwable t) {
139: error.set(t);
140: }
141: }
142: });
143: }
144:
145: for (int i = 0; i < threads.length; i++) {
146: threads[i].start();
147: }
148:
149: for (int i = 0; i < threads.length; i++) {
150: try {
151: threads[i].join(runtime + 1000);
152: } catch (InterruptedException e) {
153: throw new RuntimeException(e);
154: }
155: }
156:
157: Throwable t = (Throwable) error.get();
158: if (t != null) {
159: throw new RuntimeException(t);
160: }
161: }
162:
163: private static class ConcentratedClass {
164: // Leave these fields private! This test is trying to shake out concurrency problems set/get()'ing private
165: // fields via reflection in GenericTCField
166: private int counter1 = 0;
167: private int counter2 = 0;
168:
169: synchronized int increment() {
170: counter1++;
171: counter2++;
172: return counter1;
173: }
174: }
175:
176: private void debugPrintln(String s) {
177: if (DEBUG) {
178: System.err.println("***** ConcentratedClassTestApp: " + s);
179: }
180: }
181: }
|