001: /*
002: * All content copyright (c) 2003-2007 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.CyclicBarrier;
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.object.config.spec.CyclicBarrierSpec;
013: import com.tc.simulator.app.ApplicationConfig;
014: import com.tc.simulator.listener.ListenerProvider;
015: import com.tctest.runner.AbstractErrorCatchingTransparentApp;
016:
017: import java.util.HashMap;
018: import java.util.Iterator;
019: import java.util.Map;
020: import java.util.Random;
021: import java.util.TreeSet;
022:
023: public class TreeSetGCTestApp extends
024: AbstractErrorCatchingTransparentApp {
025: private static boolean DEBUG = true;
026:
027: private static final long DURATION = 1 * 60 * 1000; // 1 minutes
028: private static final long END = System.currentTimeMillis()
029: + DURATION;
030: private static final String KEY_PREFIX = "key";
031: private static final int TOTAL_COUNT = 5;
032:
033: // roots
034: private final CyclicBarrier barrier = new CyclicBarrier(
035: getParticipantCount());
036: private final Map root = new HashMap();
037: private final NextToWork nextToWork;
038:
039: private final Random random;
040: private final String appId;
041: private static AssertionError error;
042:
043: public TreeSetGCTestApp(String appId, ApplicationConfig cfg,
044: ListenerProvider listenerProvider) {
045: super (appId, cfg, listenerProvider);
046: this .appId = appId;
047: nextToWork = new NextToWork(cfg.getGlobalParticipantCount());
048: nextToWork.addParticipant(this .appId);
049:
050: long seed = new Random().nextLong();
051: System.err.println("seed for " + getApplicationId() + " is "
052: + seed);
053: random = new Random(seed);
054: }
055:
056: protected void runTest() throws Throwable {
057: final int index = barrier.barrier();
058:
059: if (index == 0) {
060: populate();
061: nextToWork.setFirstToWork(appId);
062: }
063:
064: barrier.barrier();
065:
066: if (index == 0) {
067: mutate();
068: } else {
069: read();
070: }
071:
072: if (error != null) {
073: // List list = ServerTransactionManagerImpl.applyList;
074: //for (Iterator iter = list.iterator(); iter.hasNext();) {
075: //String info = (String) iter.next();
076: //debugPrintln(info);
077: //}
078:
079: //list = ClientTransactionManagerImpl.txnList;
080: //for (Iterator iter = list.iterator(); iter.hasNext();) {
081: // String info = (String) iter.next();
082: //debugPrintln(info);
083: //}
084:
085: //list = SetManagedObjectState.addedList;
086: //for (Iterator iter = list.iterator(); iter.hasNext();) {
087: // String info = (String) iter.next();
088: //debugPrintln(info);
089: //}
090:
091: //list = SetManagedObjectState.removedList;
092: //for (Iterator iter = list.iterator(); iter.hasNext();) {
093: //String info = (String) iter.next();
094: //debugPrintln(info);
095: //}
096:
097: //list = ReceiveTransactionHandler.receivedList;
098: //for (Iterator iter = list.iterator(); iter.hasNext();) {
099: //String info = (String) iter.next();
100: //debugPrintln(info);
101: //}
102:
103: //list = HashSetApplicator.applyList;
104: //for (Iterator iter = list.iterator(); iter.hasNext();) {
105: //String applyInfo = (String) iter.next();
106: //debugPrintln(applyInfo);
107: //}
108:
109: throw error;
110: }
111: }
112:
113: private void populate() {
114: debugPrintln(wrapMessage("populate..."));
115: synchronized (root) {
116: for (int i = 0, n = TOTAL_COUNT; i < n; i++) {
117: root.put(KEY_PREFIX + i, newTreeSet(getRandomNum(),
118: getRandomNum(), i));
119: }
120: debugPrintln(wrapMessage("root size=[" + root.size() + "]"));
121: }
122: }
123:
124: public void mutate() throws InterruptedException {
125: while (!shouldEnd()) {
126: if (nextToWork.isNextToWork(appId)) {
127: synchronized (root) {
128: debugPrintln(wrapMessage("mutate... "));
129: int numToMutate = getRandomNum();
130: int numToDeleteCreate = getRandomNum();
131:
132: for (int i = 0; i < numToDeleteCreate; i++) {
133: root.remove(KEY_PREFIX + i);
134: debugPrintln(wrapMessage("deleting top-level TreeSet=["
135: + i + "]"));
136: }
137: debugPrintln(wrapMessage("deleted ["
138: + numToDeleteCreate
139: + "] TreeSets: root size=[" + root.size()
140: + "]"));
141:
142: for (int i = 0; i < numToDeleteCreate; i++) {
143: root.put(KEY_PREFIX + i, newTreeSet(
144: getRandomNum(), getRandomNum(), i));
145: }
146: debugPrintln(wrapMessage("added ["
147: + numToDeleteCreate
148: + "] TreeSets: root size=[" + root.size()
149: + "]"));
150:
151: debugPrintln(wrapMessage("mutating [" + numToMutate
152: + "] TreeSets"));
153: for (int i = 0; i < numToMutate; i++) {
154: TreeSet topLevel = (TreeSet) root
155: .get(KEY_PREFIX + i);
156: for (Iterator iter = topLevel.iterator(); iter
157: .hasNext();) {
158: TreeSetWrapper tsWrapper = (TreeSetWrapper) iter
159: .next();
160: TreeSet ts = tsWrapper.getTreeSet();
161: int size = ts.size();
162:
163: debugPrintln(wrapMessage("ts=[" + i + "]["
164: + tsWrapper.getId()
165: + "] to mutate has size=[" + size
166: + "]"));
167:
168: if (size == 0) {
169: error = new AssertionError(
170: "***** TreeSet=[" + i + "]["
171: + tsWrapper.getId()
172: + "] has size=0 !!");
173: return;
174: }
175:
176: int startPosition = random.nextInt(size);
177: if (startPosition == 0) {
178: startPosition++;
179: }
180: for (int j = startPosition; j < size; j++) {
181: boolean removedObject = ts
182: .remove(new FooObject(j));
183: if (removedObject) {
184: debugPrintln(wrapMessage("removing element=["
185: + j
186: + "] from TreeSet=["
187: + i
188: + "]["
189: + tsWrapper.getId() + "]"));
190: } else {
191: debugPrintln(wrapMessage("element=["
192: + j
193: + "] from TreeSet=["
194: + i
195: + "]["
196: + tsWrapper.getId()
197: + "] WAS NOT REMOVED!"));
198: }
199: }
200:
201: size = ts.size();
202: String s = "";
203: for (Iterator iterator = ts.iterator(); iterator
204: .hasNext();) {
205: FooObject element = (FooObject) iterator
206: .next();
207: s += "[" + element.getId() + "]";
208: }
209: debugPrintln(wrapMessage("ts=[" + i + "]["
210: + tsWrapper.getId()
211: + "] after mutate has size=["
212: + size + "] contents=[" + s + "]"));
213: }
214: }
215: }
216: nextToWork.setNextToWork();
217: } else {
218: Thread.sleep(1000);
219: }
220: }
221: }
222:
223: private void read() throws InterruptedException {
224: while (!shouldEnd()) {
225: if (nextToWork.isNextToWork(appId)) {
226: synchronized (root) {
227: debugPrintln(wrapMessage("reading..."));
228: int numToRead = getRandomNum();
229:
230: for (int i = 0; i < numToRead; i++) {
231: TreeSet topLevel = (TreeSet) root
232: .get(KEY_PREFIX + i);
233: for (Iterator iter = topLevel.iterator(); iter
234: .hasNext();) {
235: TreeSetWrapper tsWrapper = (TreeSetWrapper) iter
236: .next();
237: TreeSet ts = tsWrapper.getTreeSet();
238: int size = ts.size();
239: for (Iterator iterator = ts.iterator(); iterator
240: .hasNext();) {
241: FooObject fo = (FooObject) iterator
242: .next();
243: debugPrintln(wrapMessage("##### FO=["
244: + fo.getId() + "]"));
245: }
246: for (int j = 0; j < size; j++) {
247: if (!ts.contains(new FooObject(j))) {
248: error = new AssertionError(
249: "Element=["
250: + j
251: + "] missing from TreeSet=["
252: + i
253: + "]["
254: + tsWrapper.getId()
255: + "] with size=["
256: + size
257: + "] TreeSetContent=["
258: + getContent(ts)
259: + "]");
260: //debugPrintln("Error occurred... last txn committed in ClientTransactionManagerImpl: ["
261: // + ClientTransactionManagerImpl.txnList
262: // .get(ClientTransactionManagerImpl.txnList.size() - 1) + "]");
263: return;
264: }
265: debugPrintln(wrapMessage("reading Element=["
266: + j
267: + "] TreeSet=["
268: + i
269: + "]["
270: + tsWrapper.getId()
271: + "] with size=[" + size + "]"));
272: }
273: }
274: }
275: }
276: nextToWork.setNextToWork();
277: } else {
278: Thread.sleep(1000);
279: }
280: }
281: }
282:
283: private String getContent(TreeSet ts) {
284: StringBuffer buffer = new StringBuffer();
285: boolean first = true;
286: for (Iterator iter = ts.iterator(); iter.hasNext();) {
287: FooObject fo = (FooObject) iter.next();
288: if (first) {
289: first = false;
290: } else {
291: buffer.append(",");
292: }
293: buffer.append(fo.getId());
294: }
295: return buffer.toString();
296: }
297:
298: private String wrapMessage(String s) {
299: return "\n ##### appId[" + appId + "] " + s + "\n";
300: }
301:
302: private static void debugPrintln(String s) {
303: if (DEBUG) {
304: System.err.println("\n " + s);
305: }
306: }
307:
308: private static boolean shouldEnd() {
309: return (System.currentTimeMillis() > END) || (error != null);
310: }
311:
312: private int getRandomNum() {
313: int num = random.nextInt(TOTAL_COUNT);
314: if (num == 0) {
315: num = 1;
316: }
317: return num;
318: }
319:
320: private TreeSet newTreeSet(int treeSetCount, int treeSetSize, int id) {
321: TreeSet newTS = new TreeSet(new NullTolerantComparator());
322: for (int i = 0, n = treeSetCount; i < n; i++) {
323: newTS.add(newTreeSetWrapper(treeSetCount, treeSetSize, id,
324: i));
325: }
326: return newTS;
327: }
328:
329: private TreeSetWrapper newTreeSetWrapper(int treeSetCount,
330: int treeSetSize, int outer_id, int id) {
331: debugPrintln("creating new TreeSet=[" + outer_id + "][" + id
332: + "]: treeSetCount=[" + treeSetCount
333: + "] treeSetSize=[" + treeSetSize + "]");
334: TreeSetWrapper newTS = new TreeSetWrapper(new TreeSet(
335: new NullTolerantComparator()), id);
336: for (int i = 0, n = treeSetSize; i < n; i++) {
337: newTS.getTreeSet().add(new FooObject(i));
338: }
339: return newTS;
340: }
341:
342: public static void visitL1DSOConfig(ConfigVisitor visitor,
343: DSOClientConfigHelper config) {
344: new CyclicBarrierSpec().visit(visitor, config);
345: config.getOrCreateSpec(FooObject.class.getName());
346: config.getOrCreateSpec(NextToWork.class.getName());
347: config.getOrCreateSpec(TreeSetWrapper.class.getName());
348: config.getOrCreateSpec(NullTolerantComparator.class.getName());
349:
350: String testClassName = TreeSetGCTestApp.class.getName();
351: TransparencyClassSpec spec = config
352: .getOrCreateSpec(testClassName);
353: String methodExpression = "* " + testClassName + "*.*(..)";
354: config.addWriteAutolock(methodExpression);
355: spec.addRoot("root", "root");
356: spec.addRoot("barrier", "barrier");
357: spec.addRoot("nextToWork", "nextToWork");
358: }
359:
360: private static final class TreeSetWrapper implements Comparable {
361: private final int id;
362: private final TreeSet ts;
363:
364: public TreeSetWrapper(TreeSet ts, int id) {
365: this .id = id;
366: this .ts = ts;
367: }
368:
369: public TreeSet getTreeSet() {
370: return ts;
371: }
372:
373: public int getId() {
374: return id;
375: }
376:
377: public int compareTo(Object o) {
378: int othersId = ((TreeSetWrapper) o).getId();
379: if (id < othersId) {
380: return -1;
381: } else if (id == othersId) {
382: return 0;
383: } else {
384: return 1;
385: }
386: }
387: }
388:
389: private static final class FooObject implements Comparable {
390: private final int id;
391:
392: public FooObject(int id) {
393: this .id = id;
394: }
395:
396: public int getId() {
397: return id;
398: }
399:
400: public boolean equals(Object foo) {
401: if (foo == null) {
402: return false;
403: }
404: return ((FooObject) foo).getId() == id;
405: }
406:
407: public int hashCode() {
408: return id;
409: }
410:
411: public int compareTo(Object o) {
412: int othersId = ((FooObject) o).getId();
413: if (id < othersId) {
414: return -1;
415: } else if (id == othersId) {
416: return 0;
417: } else {
418: return 1;
419: }
420: }
421: }
422:
423: private static final class NextToWork {
424: private final String[] participants;
425: private final int participantCount;
426: private int nextToWork;
427: private int index;
428:
429: public NextToWork(int participantCount) {
430: this .participantCount = participantCount;
431: participants = new String[this .participantCount];
432: nextToWork = 0;
433: index = 0;
434: }
435:
436: public synchronized void addParticipant(String participant) {
437: debugPrintln("***** about to add participant=["
438: + participant + "]: participantsLength=[" + index
439: + "] participantCount=[" + participantCount + "]");
440: if (index == participantCount) {
441: throw new AssertionError(
442: "Participant list is full! participantCount=["
443: + participantCount + "]");
444: }
445: participants[index] = participant;
446: index++;
447: debugPrintln("***** added participant=[" + participant
448: + "]");
449: }
450:
451: public synchronized void setNextToWork() {
452: debugPrintln("***** setting next to work: before=["
453: + participants[nextToWork]
454: + "] after=["
455: + participants[((nextToWork + 1) % participantCount)]
456: + "]");
457: nextToWork = (nextToWork + 1) % participantCount;
458: }
459:
460: public synchronized boolean isNextToWork(
461: String participantToCheck) {
462: debugPrintln("***** participant=[" + participantToCheck
463: + "] is nextToWork=["
464: + (participants[nextToWork] == participantToCheck)
465: + "]");
466: return (participants[nextToWork] == participantToCheck);
467: }
468:
469: public synchronized void setFirstToWork(String participant) {
470: debugPrintln("***** setting first participant to ["
471: + participant + "]");
472: for (int i = 0; i < participantCount; i++) {
473: if (participants[i] == participant) {
474: nextToWork = i;
475: }
476: }
477: }
478: }
479: }
|