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 com.tc.management.JMXConnectorProxy;
008: import com.tc.management.L2LockStatsManagerImpl.LockStackTracesStat;
009: import com.tc.management.L2LockStatsManagerImpl.LockStat;
010: import com.tc.management.beans.L2MBeanNames;
011: import com.tc.management.beans.LockStatisticsMonitorMBean;
012: import com.tc.net.groups.ClientID;
013: import com.tc.object.LiteralValues;
014: import com.tc.object.bytecode.ByteCodeUtil;
015: import com.tc.object.bytecode.ManagerUtil;
016: import com.tc.object.config.ConfigVisitor;
017: import com.tc.object.config.DSOClientConfigHelper;
018: import com.tc.object.config.TransparencyClassSpec;
019: import com.tc.object.lockmanager.api.LockLevel;
020: import com.tc.object.lockmanager.impl.TCStackTraceElement;
021: import com.tc.objectserver.lockmanager.api.LockHolder;
022: import com.tc.properties.TCProperties;
023: import com.tc.properties.TCPropertiesImpl;
024: import com.tc.simulator.app.ApplicationConfig;
025: import com.tc.simulator.listener.ListenerProvider;
026: import com.tc.util.Assert;
027: import com.tctest.runner.AbstractTransparentApp;
028:
029: import java.util.Collection;
030: import java.util.HashMap;
031: import java.util.Iterator;
032: import java.util.List;
033: import java.util.concurrent.CyclicBarrier;
034:
035: import javax.management.MBeanServerConnection;
036: import javax.management.MBeanServerInvocationHandler;
037: import javax.management.remote.JMXConnector;
038:
039: public class LockStatisticsJMXTestApp extends AbstractTransparentApp {
040: private static final LiteralValues LITERAL_VALUES = new LiteralValues();
041:
042: public static final String CONFIG_FILE = "config-file";
043: public static final String PORT_NUMBER = "port-number";
044: public static final String HOST_NAME = "host-name";
045: public static final String JMX_PORT = "jmx-port";
046:
047: private final ApplicationConfig config;
048:
049: private final int initialNodeCount = getParticipantCount();
050: private final CyclicBarrier barrier = new CyclicBarrier(
051: initialNodeCount);
052: private final CyclicBarrier barrier2 = new CyclicBarrier(2);
053: private final HashMap<Integer, Long> indexToNodeMap = new HashMap();
054:
055: private MBeanServerConnection mbsc = null;
056: private JMXConnector jmxc;
057: private LockStatisticsMonitorMBean statMBean;
058:
059: public LockStatisticsJMXTestApp(String appId,
060: ApplicationConfig config, ListenerProvider listenerProvider) {
061: super (appId, config, listenerProvider);
062: this .config = config;
063: }
064:
065: public static void visitL1DSOConfig(ConfigVisitor visitor,
066: DSOClientConfigHelper config) {
067:
068: String testClass = LockStatisticsJMXTestApp.class.getName();
069: String methodExpression = "* " + testClass + "*.*(..)";
070: config.addWriteAutolock(methodExpression);
071: TransparencyClassSpec spec = config.getOrCreateSpec(testClass);
072: config.addIncludePattern(testClass + "$*");
073:
074: // roots
075: spec.addRoot("barrier", "barrier");
076: spec.addRoot("barrier2", "barrier2");
077: spec.addRoot("indexToNodeMap", "indexToNodeMap");
078: }
079:
080: public void run() {
081: try {
082: int index = barrier.await();
083:
084: synchronized (indexToNodeMap) {
085: indexToNodeMap.put(new Integer(index), new Long(
086: ManagerUtil.getClientID()));
087: }
088: String lockName = "lock0";
089:
090: testLockAggregateWaitTime(lockName, index);
091:
092: lockName = "lock1";
093:
094: testBasicStatistics(lockName, index);
095:
096: lockName = "lock2";
097:
098: enableStackTraces(lockName, index);
099:
100: testStackTracesStatistics(lockName, index, 1);
101:
102: enableStackTraces(lockName, index, 2,
103: getClientLockStatCollectionFrequency());
104:
105: testStackTracesStatistics(lockName, index, 2);
106:
107: testLockHeldTime("lock3", "lock4", index);
108:
109: testLockWaitingTime("lock5", "lock6", index);
110: } catch (Throwable t) {
111: notifyError(t);
112: }
113: }
114:
115: private void connect() throws Exception {
116: echo("connecting to jmx server....");
117: jmxc = new JMXConnectorProxy("localhost", Integer
118: .parseInt(config.getAttribute(JMX_PORT)));
119: mbsc = jmxc.getMBeanServerConnection();
120: echo("obtained mbeanserver connection");
121: statMBean = (LockStatisticsMonitorMBean) MBeanServerInvocationHandler
122: .newProxyInstance(mbsc, L2MBeanNames.LOCK_STATISTICS,
123: LockStatisticsMonitorMBean.class, false);
124: }
125:
126: private void disconnect() throws Exception {
127: if (jmxc != null) {
128: jmxc.close();
129: }
130: }
131:
132: private void enableStackTraces(String lockName, int index)
133: throws Throwable {
134: if (index == 0) {
135: connect();
136: statMBean.enableClientStackTrace(ByteCodeUtil
137: .generateLiteralLockName(LITERAL_VALUES
138: .valueFor(lockName), lockName));
139: disconnect();
140: }
141:
142: barrier.await();
143: }
144:
145: private void enableStackTraces(String lockName, int index,
146: int stackTraceDepth, int statCollectFrequency)
147: throws Throwable {
148: if (index == 0) {
149: connect();
150: statMBean.enableClientStackTrace(ByteCodeUtil
151: .generateLiteralLockName(LITERAL_VALUES
152: .valueFor(lockName), lockName),
153: stackTraceDepth, statCollectFrequency);
154: disconnect();
155: }
156:
157: barrier.await();
158: }
159:
160: private int getClientLockStatCollectionFrequency() {
161: TCProperties tcProperties = TCPropertiesImpl.getProperties()
162: .getPropertiesFor("l1.lock");
163: return tcProperties.getInt("collectFrequency");
164: }
165:
166: private void testStackTracesStatistics(String lockName, int index,
167: int depthOfEachStackTrace) throws Throwable {
168: if (index == 0) {
169: waitForAllToMoveOn();
170: connect();
171: Thread.sleep(2000);
172: verifyStackTraces(ByteCodeUtil.generateLiteralLockName(
173: LITERAL_VALUES.valueFor(lockName), lockName), 2, 2,
174: depthOfEachStackTrace);
175: disconnect();
176: } else {
177: int clientLockStatCollectFrequency = getClientLockStatCollectionFrequency();
178: for (int i = 0; i < clientLockStatCollectFrequency + 1; i++) {
179: ManagerUtil.monitorEnter(lockName, LockLevel.READ);
180: }
181: for (int i = 0; i < clientLockStatCollectFrequency + 1; i++) {
182: ManagerUtil.monitorExit(lockName);
183: }
184:
185: waitForAllToMoveOn();
186: }
187: waitForAllToMoveOn();
188: }
189:
190: private void testLockWaitingTime(String lockName1,
191: String lockName2, int index) throws Throwable {
192: if (index == 0) {
193: connect();
194: waitForAllToMoveOn();
195: long waitTime1 = getLockWaitTime(lockName1, indexToNodeMap
196: .get(new Integer(2)).longValue());
197: long waitTime2 = getLockWaitTime(lockName2, indexToNodeMap
198: .get(new Integer(2)).longValue());
199:
200: Assert.assertTrue(waitTime2 > waitTime1);
201: } else if (index == 1) {
202: ManagerUtil.monitorEnter(lockName1, LockLevel.WRITE);
203: waitForTwoToMoveOn();
204: Thread.sleep(2000);
205: ManagerUtil.monitorExit(lockName1);
206:
207: ManagerUtil.monitorEnter(lockName2, LockLevel.WRITE);
208: waitForTwoToMoveOn();
209: Thread.sleep(4000);
210: ManagerUtil.monitorExit(lockName2);
211: waitForAllToMoveOn();
212: } else if (index == 2) {
213: waitForTwoToMoveOn();
214: ManagerUtil.monitorEnter(lockName1, LockLevel.WRITE);
215: ManagerUtil.monitorExit(lockName1);
216: waitForTwoToMoveOn();
217: ManagerUtil.monitorEnter(lockName2, LockLevel.WRITE);
218: ManagerUtil.monitorExit(lockName2);
219: waitForAllToMoveOn();
220: }
221:
222: waitForAllToMoveOn();
223: }
224:
225: private void testLockAggregateWaitTime(String lockName, int index)
226: throws Throwable {
227: if (index == 0) {
228: connect();
229: waitForAllToMoveOn();
230: long avgWaitTimeInMillis = getAggregateAverageWaitTime(lockName);
231: long avgHeldTimeInMillis = getAggregateAverageHeldTime(lockName);
232:
233: System.out.println("avgHeldTimeInMillis: "
234: + avgHeldTimeInMillis);
235: System.out.println("avgWaitTimeInMillis: "
236: + avgWaitTimeInMillis);
237: Assert.assertTrue(avgWaitTimeInMillis > 1000);
238: Assert.assertTrue(avgHeldTimeInMillis > 2000);
239: } else if (index == 1) {
240: ManagerUtil.monitorEnter(lockName, LockLevel.WRITE);
241: waitForTwoToMoveOn();
242: Thread.sleep(2000);
243: ManagerUtil.monitorExit(lockName);
244: waitForTwoToMoveOn();
245: ManagerUtil.monitorEnter(lockName, LockLevel.WRITE);
246: Thread.sleep(3000);
247: ManagerUtil.monitorExit(lockName);
248: waitForAllToMoveOn();
249: } else if (index == 2) {
250: waitForTwoToMoveOn();
251: ManagerUtil.monitorEnter(lockName, LockLevel.WRITE);
252: waitForTwoToMoveOn();
253: Thread.sleep(2000);
254: ManagerUtil.monitorExit(lockName);
255: waitForAllToMoveOn();
256: }
257: waitForAllToMoveOn();
258: }
259:
260: private void testLockHeldTime(String lockName1, String lockName2,
261: int index) throws Throwable {
262: if (index == 0) {
263: connect();
264: waitForAllToMoveOn();
265: long heldTime1 = getLockHeldTime(lockName1, indexToNodeMap
266: .get(new Integer(1)).longValue());
267: long heldTime2 = getLockHeldTime(lockName2, indexToNodeMap
268: .get(new Integer(1)).longValue());
269:
270: Assert.assertTrue(heldTime2 > heldTime1);
271: } else if (index == 1) {
272: ManagerUtil.monitorEnter(lockName1, LockLevel.WRITE);
273: waitForTwoToMoveOn();
274: Thread.sleep(2000);
275: ManagerUtil.monitorExit(lockName1);
276:
277: ManagerUtil.monitorEnter(lockName2, LockLevel.WRITE);
278: waitForTwoToMoveOn();
279: Thread.sleep(4000);
280: ManagerUtil.monitorExit(lockName2);
281: waitForAllToMoveOn();
282: } else if (index == 2) {
283: waitForTwoToMoveOn();
284: ManagerUtil.monitorEnter(lockName1, LockLevel.WRITE);
285: ManagerUtil.monitorExit(lockName1);
286: waitForTwoToMoveOn();
287: ManagerUtil.monitorEnter(lockName2, LockLevel.WRITE);
288: ManagerUtil.monitorExit(lockName2);
289: waitForAllToMoveOn();
290: }
291:
292: waitForAllToMoveOn();
293: }
294:
295: private void testBasicStatistics(String lockName, int index)
296: throws Throwable {
297: if (index == 0) {
298: connect();
299: waitForAllToMoveOn();
300:
301: verifyLockRequest(lockName, 1);
302: verifyLockHolder(lockName, indexToNodeMap.get(
303: new Integer(1)).longValue());
304: verifyLockAwarded(lockName, indexToNodeMap.get(
305: new Integer(1)).longValue(), true);
306: waitForAllToMoveOn();
307:
308: Thread.sleep(1000);
309: verifyLockContended(lockName, 1);
310: verifyLockHolder(lockName, indexToNodeMap.get(
311: new Integer(2)).longValue());
312: verifyLockAwarded(lockName, indexToNodeMap.get(
313: new Integer(2)).longValue(), false);
314: waitForTwoToMoveOn();
315:
316: waitForAllToMoveOn();
317: verifyLockRequest(lockName, 2);
318: verifyLockContended(lockName, 0);
319: verifyLockHolder(lockName, indexToNodeMap.get(
320: new Integer(1)).longValue());
321: verifyLockHolder(lockName, indexToNodeMap.get(
322: new Integer(2)).longValue());
323: verifyLockAwarded(lockName, indexToNodeMap.get(
324: new Integer(2)).longValue(), true);
325:
326: waitForAllToMoveOn();
327:
328: waitForAllToMoveOn();
329:
330: verifyLockHop(lockName, 3);
331: verifyStackTraces(lockName, 0, -1, -1);
332: waitForAllToMoveOn();
333: disconnect();
334:
335: } else if (index == 1) {
336: ManagerUtil.monitorEnter(lockName, LockLevel.WRITE);
337: waitForAllToMoveOn();
338: waitForAllToMoveOn();
339:
340: waitForTwoToMoveOn();
341: ManagerUtil.monitorExit(lockName);
342:
343: waitForAllToMoveOn();
344:
345: waitForAllToMoveOn();
346:
347: ManagerUtil.monitorEnter(lockName, LockLevel.WRITE);
348: waitForTwoToMoveOn();
349: Thread.sleep(1000);
350: ManagerUtil.monitorExit(lockName);
351: waitForTwoToMoveOn();
352: waitForAllToMoveOn();
353: waitForAllToMoveOn();
354: } else if (index == 2) {
355: waitForAllToMoveOn();
356: waitForAllToMoveOn();
357: ManagerUtil.monitorEnter(lockName, LockLevel.WRITE);
358:
359: waitForAllToMoveOn();
360:
361: waitForAllToMoveOn();
362:
363: Thread.sleep(1000);
364: ManagerUtil.monitorExit(lockName);
365: waitForTwoToMoveOn();
366: ManagerUtil.monitorEnter(lockName, LockLevel.WRITE);
367: waitForTwoToMoveOn();
368: waitForAllToMoveOn();
369: waitForAllToMoveOn();
370: ManagerUtil.monitorExit(lockName);
371: }
372:
373: waitForAllToMoveOn();
374: }
375:
376: private void waitForAllToMoveOn() throws Exception {
377: barrier.await();
378: }
379:
380: private void waitForTwoToMoveOn() throws Exception {
381: barrier2.await();
382: }
383:
384: private void verifyLockRequest(String lockName, int expectedValue) {
385: Collection c = statMBean.getTopRequested(10);
386: for (Iterator<LockStat> i = c.iterator(); i.hasNext();) {
387: LockStat s = i.next();
388: if (s.getLockID().asString().endsWith(lockName)) {
389: Assert.assertEquals(expectedValue, s
390: .getNumOfLockRequested());
391: break;
392: }
393: }
394: }
395:
396: private void verifyLockHolder(String lockName, long expectedValue) {
397: Collection c = statMBean.getTopHeld(100);
398: for (Iterator<LockHolder> i = c.iterator(); i.hasNext();) {
399: LockHolder s = i.next();
400: if (s.getLockID().asString().endsWith(lockName)) {
401: if (((ClientID) s.getNodeID()).getChannelID().toLong() == expectedValue) {
402: return;
403: }
404: }
405: }
406: throw new AssertionError("Client " + expectedValue
407: + " does not seem to hold lock " + lockName);
408: }
409:
410: private void verifyLockAwarded(String lockName, long expectedValue,
411: boolean isAwarded) {
412: Collection c = statMBean.getTopHeld(100);
413: for (Iterator<LockHolder> i = c.iterator(); i.hasNext();) {
414: LockHolder s = i.next();
415: if (s.getLockID().asString().endsWith(lockName)) {
416: if (((ClientID) s.getNodeID()).getChannelID().toLong() == expectedValue) {
417: if (isAwarded && s.getTimeAcquired() > 0) {
418: return;
419: }
420: if (!isAwarded && s.getTimeAcquired() > 0) {
421: throw new AssertionError("Client "
422: + expectedValue
423: + " should not have acquire the lock "
424: + lockName);
425: }
426: }
427: }
428: }
429:
430: if (isAwarded) {
431: throw new AssertionError("Client " + expectedValue
432: + " does not seem to acquire the lock " + lockName);
433: }
434: }
435:
436: private long getAggregateAverageHeldTime(String lockName) {
437: Collection c = statMBean.getTopAggregateLockHolderStats(500);
438: for (Iterator<LockStat> i = c.iterator(); i.hasNext();) {
439: LockStat s = i.next();
440: if (s.getLockID().asString().endsWith(lockName)) {
441: return s.getAvgHeldTimeInMillis();
442: }
443: }
444: return -1;
445: }
446:
447: private long getAggregateAverageWaitTime(String lockName) {
448: Collection c = statMBean.getTopAggregateWaitingLocks(500);
449: for (Iterator<LockStat> i = c.iterator(); i.hasNext();) {
450: LockStat s = i.next();
451: if (s.getLockID().asString().endsWith(lockName)) {
452: return s.getAvgWaitTimeInMillis();
453: }
454: }
455: return -1;
456: }
457:
458: private long getLockHeldTime(String lockName, long channelID) {
459: Collection c = statMBean.getTopHeld(500);
460: for (Iterator<LockHolder> i = c.iterator(); i.hasNext();) {
461: LockHolder s = i.next();
462: if (s.getLockID().asString().endsWith(lockName)) {
463: if (((ClientID) s.getNodeID()).getChannelID().toLong() == channelID) {
464: return s.getAndSetHeldTimeInMillis();
465: }
466: }
467: }
468: throw new AssertionError(lockName + " does not exist.");
469: }
470:
471: private long getLockWaitTime(String lockName, long channelID) {
472: Collection c = statMBean.getTopHeld(500);
473: for (Iterator<LockHolder> i = c.iterator(); i.hasNext();) {
474: LockHolder s = i.next();
475: if (s.getLockID().asString().endsWith(lockName)) {
476: if (((ClientID) s.getNodeID()).getChannelID().toLong() == channelID) {
477: return s.getAndSetWaitTimeInMillis();
478: }
479: }
480: }
481: throw new AssertionError(lockName + " does not exist.");
482: }
483:
484: private void verifyLockContended(String lockName, int expectedValue) {
485: Collection c = statMBean.getTopContendedLocks(10);
486: for (Iterator<LockStat> i = c.iterator(); i.hasNext();) {
487: LockStat s = i.next();
488: if (s.getLockID().asString().endsWith(lockName)) {
489: Assert.assertEquals(expectedValue, s
490: .getNumOfPendingRequests());
491: break;
492: }
493: }
494: }
495:
496: private void verifyLockHop(String lockName, int expectedValue) {
497: Collection c = statMBean.getTopLockHops(10);
498: for (Iterator<LockStat> i = c.iterator(); i.hasNext();) {
499: LockStat s = i.next();
500: if (s.getLockID().asString().endsWith(lockName)) {
501: Assert.assertEquals(expectedValue, s
502: .getNumOfLockHopRequests());
503: break;
504: }
505: }
506: }
507:
508: private void verifyStackTraces(String lockName,
509: int numOfClientsStackTraces, int numOfStackTraces,
510: int depthOfStackTraces) {
511: Collection c = statMBean.getStackTraces(lockName);
512: Assert.assertEquals(numOfClientsStackTraces, c.size());
513:
514: for (Iterator i = c.iterator(); i.hasNext();) {
515: LockStackTracesStat s = (LockStackTracesStat) i.next();
516: List oneStackTraces = s.getStackTraces();
517: Assert
518: .assertEquals(numOfStackTraces, oneStackTraces
519: .size());
520: for (Iterator j = oneStackTraces.iterator(); j.hasNext();) {
521: TCStackTraceElement tcStackTraceElement = (TCStackTraceElement) j
522: .next();
523: StackTraceElement[] stackTracesElement = tcStackTraceElement
524: .getStackTraceElements();
525: Assert.assertEquals(depthOfStackTraces,
526: stackTracesElement.length);
527: }
528: }
529: }
530:
531: private static void echo(String msg) {
532: System.out.println(msg);
533: }
534:
535: }
|