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 com.tc.object.bytecode.Manageable;
007: //import com.tc.object.bytecode.ManagerUtil;
008: import com.tc.object.config.ConfigVisitor;
009: import com.tc.object.config.DSOClientConfigHelper;
010: import com.tc.object.config.TransparencyClassSpec;
011: import com.tc.simulator.app.ApplicationConfig;
012: import com.tc.simulator.listener.ListenerProvider;
013: import com.tc.util.Assert;
014: import com.tctest.runner.AbstractTransparentApp;
015:
016: import java.util.HashMap;
017: import java.util.Iterator;
018: import java.util.LinkedList;
019: import java.util.Map;
020: import java.util.Set;
021: import java.util.Map.Entry;
022: import java.util.concurrent.ConcurrentHashMap;
023: import java.util.concurrent.CyclicBarrier;
024:
025: public class ConcurrentHashMapSyncTestApp extends
026: AbstractTransparentApp {
027:
028: private final DataKey[] keyRoots = new DataKey[] { new DataKey(1),
029: new DataKey(2), new DataKey(3), new DataKey(4) };
030: private final DataValue[] valueRoots = new DataValue[] {
031: new DataValue(10), new DataValue(20), new DataValue(30),
032: new DataValue(40) };
033:
034: private final CyclicBarrier barrier;
035: private final ConcurrentHashMap mapRoot = new ConcurrentHashMap();
036:
037: private final HashKey myKey = new HashKey(101);
038: private final LinkedList<Integer> sharedList = new LinkedList<Integer>();
039:
040: public ConcurrentHashMapSyncTestApp(String appId,
041: ApplicationConfig cfg, ListenerProvider listenerProvider) {
042: super (appId, cfg, listenerProvider);
043: barrier = new CyclicBarrier(getParticipantCount());
044: }
045:
046: public void run() {
047: try {
048: int index = barrier.await();
049:
050: testConcurrentSync(index);
051: testConcurrentPingpong(index);
052:
053: } catch (Throwable t) {
054: notifyError(t);
055: }
056: }
057:
058: /**
059: * Multiple threads to change shared at different parts object cocurrently.
060: */
061: private void testConcurrentSync(int index) throws Exception {
062:
063: // make change to mapRoot concurrently
064: synchronized (mapRoot) {
065: mapRoot.put(keyRoots[index % 4], valueRoots[index % 4]);
066: }
067:
068: // threads sync here
069: barrier.await();
070:
071: // verify
072: Map newMap = new HashMap();
073: newMap.put(keyRoots[0], valueRoots[0]);
074: newMap.put(keyRoots[1], valueRoots[1]);
075: newMap.put(keyRoots[2], valueRoots[2]);
076: newMap.put(keyRoots[3], valueRoots[3]);
077:
078: assertMappingsEqual(newMap, mapRoot);
079:
080: barrier.await();
081: }
082:
083: /**
084: * Even threads to make number even and odd threads to make number odd.
085: * Uses a LinkedList to verify correct synchronization behaving.
086: */
087: private void testConcurrentPingpong(int index) throws Exception {
088:
089: int upbound = 1000;
090:
091: if (index == 0) {
092: synchronized (sharedList) {
093: sharedList.clear();
094: }
095: synchronized (mapRoot) {
096: mapRoot.put(myKey, new DataValue(0));
097: sharedList.add(0);
098: }
099: // int d = ((DataValue)mapRoot.get(myKey)).getInt();
100: // System.out.println("*** Init data=["+d+"]");
101: }
102:
103: barrier.await();
104:
105: if ((index % 2) == 0) { // this one makes number even
106: boolean done = false;
107: int d;
108: while (!done) {
109: synchronized (mapRoot) {
110: if ((d = ((DataValue) mapRoot.get(myKey)).getInt()) < upbound) {
111: if ((d % 2) != 0) {
112: mapRoot.put(myKey, new DataValue(++d));
113: sharedList.add(d);
114: // System.out.println("*** Thread["+index+"] value="+d);
115: mapRoot.notifyAll();
116: }
117: if (d < upbound)
118: mapRoot.wait();
119: } else {
120: done = true;
121: }
122: }
123: Thread.sleep((int) (Math.random() * 10));
124: }
125: }
126:
127: if ((index % 2) != 0) { // this one makes number odd
128: boolean done = false;
129: int d;
130: while (!done) {
131: synchronized (mapRoot) {
132: if ((d = ((DataValue) mapRoot.get(myKey)).getInt()) < upbound) {
133: if ((d % 2) == 0) {
134: mapRoot.put(myKey, new DataValue(++d));
135: sharedList.add(d);
136: // System.out.println("*** Thread["+index+"] value="+d);
137: mapRoot.notifyAll();
138: }
139: if (d < upbound)
140: mapRoot.wait();
141: } else {
142: done = true;
143: }
144: }
145: Thread.sleep((int) (Math.random() * 10));
146: }
147: }
148:
149: barrier.await();
150:
151: // verify
152: if (index == 0) {
153: for (int i = 0; i < upbound; ++i) {
154: // System.out.println("*** Verify["+i+"] value="+sharedList.get(i));
155: Assert.assertTrue(i == sharedList.get(i));
156: }
157: }
158:
159: barrier.await();
160: }
161:
162: void assertMappingsEqual(Map expect, Map actual) {
163: Assert.assertEquals(expect.size(), actual.size());
164:
165: Set expectEntries = expect.entrySet();
166: Set actualEntries = actual.entrySet();
167:
168: for (Iterator i = expectEntries.iterator(); i.hasNext();) {
169: Entry entry = (Entry) i.next();
170: Assert.assertEquals(
171: ((DataValue) entry.getValue()).getInt(),
172: ((DataValue) actual.get(entry.getKey())).getInt());
173: }
174:
175: for (Iterator i = actualEntries.iterator(); i.hasNext();) {
176: Entry entry = (Entry) i.next();
177: Assert.assertEquals(
178: ((DataValue) entry.getValue()).getInt(),
179: ((DataValue) expect.get(entry.getKey())).getInt());
180: }
181: }
182:
183: public static void visitL1DSOConfig(ConfigVisitor visitor,
184: DSOClientConfigHelper config) {
185: String testClass = ConcurrentHashMapSyncTestApp.class.getName();
186: TransparencyClassSpec spec = config.getOrCreateSpec(testClass);
187:
188: config.addIncludePattern(testClass + "$*", false, false, true);
189:
190: String methodExpression = "* " + testClass + "*.*(..)";
191: config.addWriteAutolock(methodExpression);
192:
193: spec.addRoot("barrier", "barrier");
194: spec.addRoot("mapRoot", "mapRoot");
195: spec.addRoot("sharedRoot", "sharedRoot");
196: spec.addRoot("keyRoots", "keyRoots");
197: spec.addRoot("valueRoots", "valueRoots");
198: spec.addRoot("sharedList", "sharedList");
199: }
200:
201: private static class DataKey {
202: private int i;
203:
204: public DataKey(int i) {
205: super ();
206: this .i = i;
207: }
208:
209: public int getInt() {
210: return this .i;
211: }
212:
213: public String toString() {
214: return super .toString() + ", i: " + i;
215: }
216: }
217:
218: private static class DataValue {
219: private int i;
220:
221: public DataValue(int i) {
222: super ();
223: this .i = i;
224: }
225:
226: public int getInt() {
227: return this .i;
228: }
229:
230: public String toString() {
231: return super .toString() + ", i: " + i;
232: }
233: }
234:
235: private static class HashKey {
236: private int i;
237:
238: public HashKey(int i) {
239: super ();
240: this .i = i;
241: }
242:
243: public int getInt() {
244: return this .i;
245: }
246:
247: public int hashCode() {
248: return i;
249: }
250:
251: public boolean equals(Object obj) {
252: if (obj == null)
253: return false;
254: if (!(obj instanceof HashKey))
255: return false;
256: return ((HashKey) obj).i == i;
257: }
258:
259: public String toString() {
260: return super .toString() + ", i: " + i;
261: }
262: }
263:
264: }
|