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.longrunning;
006:
007: import com.tc.exception.TCRuntimeException;
008: import com.tc.net.proxy.TCPProxy;
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.objectserver.control.ServerControl;
013: import com.tc.simulator.app.Application;
014: import com.tc.simulator.app.ApplicationConfig;
015: import com.tc.simulator.app.ApplicationConfigBuilder;
016: import com.tc.simulator.container.ContainerBuilderConfig;
017: import com.tc.simulator.listener.ListenerProvider;
018: import com.tc.simulator.listener.ResultsListener;
019: import com.tc.util.Assert;
020:
021: import java.text.DateFormat;
022: import java.text.SimpleDateFormat;
023: import java.util.ArrayList;
024: import java.util.Arrays;
025: import java.util.Collection;
026: import java.util.Date;
027: import java.util.HashMap;
028: import java.util.Iterator;
029: import java.util.List;
030: import java.util.Map;
031: import java.util.Random;
032:
033: public class LargeGraphTestApp implements Application,
034: ApplicationConfigBuilder {
035:
036: private static final DateFormat df = new SimpleDateFormat(
037: "yyyy-MM=dd HH:mm:ss,SSS Z");
038:
039: private final String appId;
040: private final ResultsListener resultsListener;
041: private final Random random = new Random();
042: private int idCounter;
043:
044: private final Map graph = new HashMap();
045: private final Collection references;
046: private final Map referencesByNodeID;
047: private final Map nodesByNodeID;
048: private final List objectCount = new ArrayList(1);
049:
050: private ConfigVisitor visitor;
051:
052: /**
053: * This ctor is for when it's an ApplicationConfigBuilder
054: */
055: public LargeGraphTestApp(
056: ContainerBuilderConfig containerBuilderConfig) {
057: this ("", null, null);
058: visitor = new ConfigVisitor();
059: }
060:
061: /**
062: * This ctor is for when it's an Application
063: */
064: public LargeGraphTestApp(String appId, ApplicationConfig cfg,
065: ListenerProvider listeners) {
066: this .appId = appId;
067: if (listeners != null)
068: this .resultsListener = listeners.getResultsListener();
069: else
070: this .resultsListener = null;
071:
072: if (doVerify()) {
073: referencesByNodeID = new HashMap();
074: nodesByNodeID = new HashMap();
075: references = new ArrayList();
076: } else {
077: referencesByNodeID = null;
078: nodesByNodeID = null;
079: references = null;
080: }
081: }
082:
083: public static void visitL1DSOConfig(ConfigVisitor visitor,
084: DSOClientConfigHelper config) {
085: String testClassName = LargeGraphTestApp.class.getName();
086: TransparencyClassSpec spec = config
087: .getOrCreateSpec(testClassName);
088:
089: spec.addRoot("graph", testClassName + ".graph");
090: spec.addRoot("objectCount", testClassName + ".objectCount");
091: if (doVerify()) {
092: spec.addRoot("references", testClassName + ".references");
093: spec.addRoot("referencesByNodeID", testClassName
094: + ".referencesByNodeID");
095: spec.addRoot("nodesByNodeID", testClassName
096: + ".nodesByNodeID");
097: }
098:
099: config.addWriteAutolock("public void " + testClassName
100: + ".growGraph(int, int)");
101: config.addWriteAutolock("private void " + testClassName
102: + ".incrementObjectCount()");
103: config.addWriteAutolock("* " + testClassName
104: + ".newGraphNode()");
105: config.addReadAutolock("* " + testClassName
106: + ".getObjectCount()");
107: config.addReadAutolock("* " + testClassName + ".verifyGraph()");
108: config.addReadAutolock("* " + testClassName
109: + ".verifyReferences()");
110: config.addReadAutolock("* " + testClassName + ".touchGraph()");
111:
112: spec.addTransient("resultsListener");
113: spec.addTransient("outputListener");
114: spec.addTransient("appId");
115: spec.addTransient("random");
116: spec.addTransient("idCounter");
117:
118: config.getOrCreateSpec(GraphNode.class.getName());
119: config.getOrCreateSpec(NodeReference.class.getName());
120: }
121:
122: public String getApplicationId() {
123: return this .appId;
124: }
125:
126: public boolean interpretResult(Object result) {
127: return ((Boolean) result).booleanValue();
128: }
129:
130: static boolean doVerify() {
131: return false;
132: }
133:
134: public void run() {
135: try {
136: int iteration = 0;
137: while (true) {
138: int batchSize = random.nextInt(1000);
139: println("About to grow graph by " + batchSize
140: + " nodes...");
141: growGraph(batchSize, 50);
142: if (random.nextInt(10) > 5) {
143: touchGraph();
144: }
145: if (doVerify()) {
146: verifyGraph();
147: verifyReferences();
148: }
149: println("completed " + (++iteration)
150: + " iteration(s); There are now "
151: + getObjectCount() + " objects.");
152: }
153: } catch (Throwable t) {
154: t.printStackTrace();
155: resultsListener.notifyResult(Boolean.FALSE);
156: throw new TCRuntimeException(t);
157: }
158: }
159:
160: private void println(Object o) {
161: System.out.println(df.format(new Date()) + ": "
162: + Thread.currentThread() + "[" + appId + "] " + o);
163: }
164:
165: /**
166: * Causes at least one second-level object to be read. requires read autolocks
167: */
168: public void touchGraph() throws Exception {
169: println("About to touch graph...");
170: synchronized (graph) {
171: GraphNode node = (GraphNode) graph.get(appId);
172: if (node != null) {
173: println("root node has: " + node.getReferenceCount()
174: + " references.");
175: for (int i = 0; i < node.getReferenceCount(); i++) {
176: GraphNode child = node.getReference(i);
177: println("Child " + i + ": " + child);
178: }
179: } else {
180: println("No starting node for: " + appId);
181: }
182: }
183: }
184:
185: /**
186: * Requires write autolocks.
187: */
188: public void growGraph(int theObjectCount, int bushyness)
189: throws Exception {
190: Assert.eval(
191: "Bushyness should be between zero and 100, inclusive.",
192: bushyness <= 100 && bushyness >= 0);
193: GraphNode node = null;
194: synchronized (graph) {
195: try {
196: println("Growing graph: objectCount=" + theObjectCount
197: + ", bushyness=" + bushyness + "...");
198: node = (GraphNode) graph.get(appId);
199: if (node == null) {
200: node = newGraphNode();
201: theObjectCount--;
202: graph.put(appId, node);
203: incrementObjectCount();
204: }
205:
206: Collection newRoots = new ArrayList();
207: newRoots.add(node);
208:
209: while (theObjectCount > 0) {
210: newRoots = growGraph(theObjectCount, newRoots,
211: bushyness);
212: theObjectCount -= newRoots.size();
213: }
214: } catch (Throwable t) {
215: t.printStackTrace();
216: throw new TCRuntimeException(t);
217: }
218: }
219: println("Done growing graph.");
220: }
221:
222: private Collection growGraph(int theObjectCount, Collection roots,
223: int bushyness) {
224: Collection newRoots = new ArrayList();
225: for (Iterator i = roots.iterator(); i.hasNext();) {
226: GraphNode root = (GraphNode) i.next();
227: boolean first = true;
228: while (first || (beBushy(bushyness)) && theObjectCount > 0) {
229: first = false;
230: GraphNode newNode = newGraphNode();
231: theObjectCount--;
232: root.addReference(references, referencesByNodeID,
233: newNode);
234: incrementObjectCount();
235: newRoots.add(newNode);
236: }
237: if (theObjectCount == 0)
238: break;
239: }
240: return newRoots;
241: }
242:
243: private boolean beBushy(int bushyness) {
244: return random.nextInt(100) <= bushyness;
245: }
246:
247: /**
248: * I need write autolocks
249: */
250: private GraphNode newGraphNode() {
251: String id = nextID();
252: GraphNode node = new GraphNode(id);
253: if (doVerify()) {
254: List l = new ArrayList();
255: synchronized (referencesByNodeID) {
256: referencesByNodeID.put(id, l);
257: }
258: synchronized (nodesByNodeID) {
259: nodesByNodeID.put(id, node);
260: }
261: }
262: return node;
263: }
264:
265: private synchronized String nextID() {
266: return appId + ":" + idCounter++;
267: }
268:
269: /**
270: * I need read autolocks
271: */
272: public int getObjectCount() {
273: synchronized (objectCount) {
274: try {
275: if (objectCount.size() > 0) {
276: return ((Integer) objectCount.get(0)).intValue();
277: } else {
278: return 0;
279: }
280: } catch (Throwable t) {
281: t.printStackTrace();
282: throw new TCRuntimeException(t);
283: }
284: }
285: }
286:
287: private void incrementObjectCount() {
288: synchronized (objectCount) {
289: try {
290: Integer newValue = new Integer(getObjectCount() + 1);
291: if (objectCount.size() == 0) {
292: objectCount.add(newValue);
293: } else {
294: objectCount.set(0, newValue);
295: }
296: } catch (Throwable t) {
297: t.printStackTrace();
298: }
299: }
300: }
301:
302: /**
303: * I need read autolocks
304: */
305: public void verifyGraph() throws VerifyException {
306: if (!doVerify())
307: return;
308: Collection newRoots = null;
309: synchronized (graph) {
310: println("Starting to verify graph...");
311: newRoots = graph.values();
312: while (true) {
313: newRoots = verifyGraph(newRoots);
314: if (newRoots.size() == 0) {
315: println("Done verifying graph.");
316: return;
317: }
318: }
319: }
320: }
321:
322: private Collection verifyGraph(Collection roots)
323: throws VerifyException {
324: Collection newRoots = new ArrayList();
325: for (Iterator i = roots.iterator(); i.hasNext();) {
326: visitNode((GraphNode) i.next(), newRoots);
327: }
328: return newRoots;
329: }
330:
331: private void visitNode(GraphNode node, Collection newRoots)
332: throws VerifyException {
333: List nodeReferences = (List) referencesByNodeID.get(node
334: .getID());
335:
336: for (int i = 0; i < node.getReferenceCount(); i++) {
337: GraphNode child = node.getReference(i);
338: if (nodeReferences.size() < i + 1) {
339: throw new VerifyException(
340: "There are not enough references for this node: "
341: + child + "; nodeReferences.size(): "
342: + nodeReferences.size());
343: }
344: NodeReference reference = (NodeReference) nodeReferences
345: .get(i);
346: Assert.eval(node.getID().equals(reference.getReferrerID()));
347: Assert.assertNotNull("Child at " + i + " for node: " + node
348: + " was null!", child);
349: Assert.assertNotNull("Reference at " + i + " for node: "
350: + node + " was null!", reference);
351: if (!child.getID().equals(reference.getReferredID())) {
352: String message = "Child id: " + child.getID()
353: + " not equal to reference.getReferredID(): "
354: + reference.getReferredID();
355: throw new VerifyException(message);
356: }
357: newRoots.add(child);
358: }
359: }
360:
361: /**
362: * I need read autolocks
363: */
364: public void verifyReferences() throws VerifyException {
365: if (!doVerify())
366: return;
367: synchronized (graph) {
368: println("Starting to verify references...");
369: for (Iterator i = references.iterator(); i.hasNext();) {
370: NodeReference reference = (NodeReference) i.next();
371: GraphNode referrer = (GraphNode) nodesByNodeID
372: .get(reference.getReferrerID());
373: GraphNode referred = referrer.getReference(reference
374: .index());
375: if (!reference.getReferredID().equals(referred.getID())) {
376: String message = "reference.getRefferedID(): "
377: + reference.getReferredID()
378: + " is not equal to referred.getID(): "
379: + referred.getID();
380: throw new VerifyException(message);
381: }
382: }
383: println("Done verifying references...");
384: }
385: }
386:
387: public static class GraphNode {
388: private final String id;
389:
390: private GraphNode[] children = new GraphNode[0];
391:
392: public GraphNode(String id) {
393: this .id = id;
394: }
395:
396: public String toString() {
397: return "GraphNode[id=" + id + ", children="
398: + enumerateChildren(new StringBuffer());
399: }
400:
401: private StringBuffer enumerateChildren(StringBuffer buf) {
402: buf.append("[");
403: if (children == null) {
404: buf.append("null");
405: } else {
406: for (int i = 0; i < children.length; i++) {
407: if (i > 0) {
408: buf.append(",");
409: }
410: if (children[i] != null)
411: buf.append(children[i].getID());
412: else
413: buf.append("null");
414: }
415: }
416: buf.append("]");
417: return buf;
418: }
419:
420: public String getID() {
421: return this .id;
422: }
423:
424: public synchronized void addReference(Collection references,
425: Map index, GraphNode referred) {
426:
427: List l = new ArrayList(Arrays.asList(children));
428: l.add(referred);
429: children = new GraphNode[l.size()];
430: // XXX: Put this back when the System.arraycopy(...) bug is fixed. --Orion 3/11/2005
431: // l.toArray(children);
432: for (int i = 0; i < children.length; i++) {
433: children[i] = (GraphNode) l.get(i);
434: }
435: if (doVerify()) {
436: NodeReference rv = new NodeReference(this , referred,
437: children.length - 1);
438: references.add(rv);
439: l = (List) index.get(getID());
440: l.add(rv);
441: }
442: }
443:
444: public synchronized int getReferenceCount() {
445: return children.length;
446: }
447:
448: public synchronized GraphNode getReference(int index) {
449: return children[index];
450: }
451:
452: }
453:
454: public static class VerifyException extends Exception {
455: VerifyException(String m) {
456: super (m);
457: }
458: }
459:
460: public static class NodeReference {
461: private final String referrer;
462: private final String referred;
463: private final int index;
464:
465: public NodeReference(GraphNode referrer, GraphNode referred,
466: int index) {
467: this .index = index;
468: this .referrer = referrer.getID();
469: this .referred = referred.getID();
470: }
471:
472: public String getReferrerID() {
473: return referrer;
474: }
475:
476: public int index() {
477: return this .index;
478: }
479:
480: public String getReferredID() {
481: return referred;
482: }
483:
484: }
485:
486: /*********************************************************************************************************************
487: * ApplicationConfigBuilder interface
488: */
489: public void visitClassLoaderConfig(DSOClientConfigHelper config) {
490: this .visitor.visit(config, getClass());
491: }
492:
493: public ApplicationConfig newApplicationConfig() {
494: return new ApplicationConfig() {
495:
496: public String getApplicationClassname() {
497: return LargeGraphTestApp.class.getName();
498: }
499:
500: public void setAttribute(String key, String value) {
501: //
502: }
503:
504: public String getAttribute(String key) {
505: return null;
506: }
507:
508: public int getIntensity() {
509: throw new AssertionError();
510: }
511:
512: public int getGlobalParticipantCount() {
513: throw new AssertionError();
514: }
515:
516: public ApplicationConfig copy() {
517: throw new AssertionError();
518: }
519:
520: public ServerControl getServerControl() {
521: throw new AssertionError();
522: }
523:
524: public int getValidatorCount() {
525: throw new AssertionError();
526: }
527:
528: public int getGlobalValidatorCount() {
529: throw new AssertionError();
530: }
531:
532: public TCPProxy[] getProxies() {
533: throw new AssertionError();
534: }
535:
536: public ServerControl[] getServerControls() {
537: throw new AssertionError();
538: }
539:
540: public Object getAttributeObject(String key) {
541: throw new AssertionError();
542: }
543: };
544: }
545: }
|