0001: /*
0002: * All content copyright (c) 2003-2007 Terracotta, Inc., except as may otherwise be noted in a separate copyright
0003: * notice. All rights reserved.
0004: */
0005: package com.tc.management;
0006:
0007: import org.apache.commons.lang.builder.HashCodeBuilder;
0008:
0009: import com.tc.async.api.Sink;
0010: import com.tc.management.stats.LRUMap;
0011: import com.tc.management.stats.TopN;
0012: import com.tc.net.groups.NodeID;
0013: import com.tc.object.lockmanager.api.LockID;
0014: import com.tc.object.lockmanager.api.ThreadID;
0015: import com.tc.object.lockmanager.impl.TCStackTraceElement;
0016: import com.tc.object.net.DSOChannelManager;
0017: import com.tc.objectserver.lockmanager.api.LockHolder;
0018: import com.tc.objectserver.lockmanager.api.LockManager;
0019: import com.tc.properties.TCProperties;
0020: import com.tc.properties.TCPropertiesImpl;
0021: import com.tc.util.Assert;
0022:
0023: import java.io.Serializable;
0024: import java.util.ArrayList;
0025: import java.util.Collection;
0026: import java.util.Collections;
0027: import java.util.Comparator;
0028: import java.util.HashMap;
0029: import java.util.Iterator;
0030: import java.util.LinkedList;
0031: import java.util.List;
0032: import java.util.Map;
0033: import java.util.Set;
0034:
0035: public class L2LockStatsManagerImpl implements L2LockStatsManager {
0036: private final static int TOP_N = 100;
0037: private final static Comparator LOCK_REQUESTED_COMPARATOR = new Comparator() {
0038: public int compare(Object o1, Object o2) {
0039: LockStat s1 = (LockStat) o1;
0040: LockStat s2 = (LockStat) o2;
0041: if (s1 == s2) {
0042: return 0;
0043: }
0044: if (s1.getNumOfLockRequested() <= s2
0045: .getNumOfLockRequested()) {
0046: return -1;
0047: }
0048: return 1;
0049: }
0050: };
0051: private final static Comparator LOCK_HOP_REQUESTED_COMPARATOR = new Comparator() {
0052: public int compare(Object o1, Object o2) {
0053: LockStat s1 = (LockStat) o1;
0054: LockStat s2 = (LockStat) o2;
0055: if (s1 == s2) {
0056: return 0;
0057: }
0058: if (s1.getNumOfLockHopRequests() <= s2
0059: .getNumOfLockHopRequests()) {
0060: return -1;
0061: }
0062: return 1;
0063: }
0064: };
0065: private final static Comparator LOCK_HELD_COMPARATOR = new Comparator() {
0066: public int compare(Object o1, Object o2) {
0067: LockHolder s1 = (LockHolder) o1;
0068: LockHolder s2 = (LockHolder) o2;
0069: if (s1 == s2) {
0070: return 0;
0071: }
0072: if (s1.getHeldTimeInMillis() <= s2.getHeldTimeInMillis()) {
0073: return -1;
0074: }
0075: return 1;
0076: }
0077: };
0078: private final static Comparator PENDING_LOCK_REQUESTS_COMPARATOR = new Comparator() {
0079: public int compare(Object o1, Object o2) {
0080: LockStat s1 = (LockStat) o1;
0081: LockStat s2 = (LockStat) o2;
0082: if (s1 == s2) {
0083: return 0;
0084: }
0085: if (s1.getNumOfPendingRequests() <= s2
0086: .getNumOfPendingRequests()) {
0087: return -1;
0088: }
0089: return 1;
0090: }
0091: };
0092: private final static Comparator LOCK_ACQUIRED_WAITING_COMPARATOR = new Comparator() {
0093: public int compare(Object o1, Object o2) {
0094: LockHolder s1 = (LockHolder) o1;
0095: LockHolder s2 = (LockHolder) o2;
0096: if (s1 == s2) {
0097: return 0;
0098: }
0099: if (s1.getWaitTimeInMillis() <= s2.getWaitTimeInMillis()) {
0100: return -1;
0101: }
0102: return 1;
0103: }
0104: };
0105: private final static Comparator AVERAGE_LOCK_HELD_COMPARATOR = new Comparator() {
0106: public int compare(Object o1, Object o2) {
0107: LockStat s1 = (LockStat) o1;
0108: LockStat s2 = (LockStat) o2;
0109: if (s1 == s2) {
0110: return 0;
0111: }
0112: if (s1.getAvgHeldTimeInMillis() <= s2
0113: .getAvgHeldTimeInMillis()) {
0114: return -1;
0115: }
0116: return 1;
0117: }
0118: };
0119: private final static Comparator AVERAGE_LOCK_ACQUIRED_WAITING_COMPARATOR = new Comparator() {
0120: public int compare(Object o1, Object o2) {
0121: LockStat s1 = (LockStat) o1;
0122: LockStat s2 = (LockStat) o2;
0123: if (s1 == s2) {
0124: return 0;
0125: }
0126: if (s1.getAvgWaitTimeInMillis() <= s2
0127: .getAvgWaitTimeInMillis()) {
0128: return -1;
0129: }
0130: return 1;
0131: }
0132: };
0133:
0134: private final LockHolderStats holderStats;
0135: private final Map<LockID, LockStat> lockStats;
0136: private DSOChannelManager channelManager;
0137: private LockManager lockManager;
0138: private Sink sink;
0139: private final int topN;
0140: private final Map<LockID, ClientLockStatContext> clientStatEnabledLock;
0141: private final Map<LockID, Map<LockKey, LockStackTracesStat>> lockStackTraces;
0142: private boolean lockStatEnabled;
0143:
0144: public L2LockStatsManagerImpl() {
0145: TCProperties tcProperties = TCPropertiesImpl.getProperties()
0146: .getPropertiesFor("lock.statistics");
0147: if (tcProperties == null) {
0148: this .lockStatEnabled = false;
0149: this .topN = TOP_N;
0150: } else {
0151: if (tcProperties.getProperty("enabled") == null) {
0152: this .lockStatEnabled = false;
0153: } else {
0154: this .lockStatEnabled = tcProperties
0155: .getBoolean("enabled");
0156: }
0157: this .topN = tcProperties.getInt("max", TOP_N);
0158: }
0159: this .clientStatEnabledLock = new HashMap<LockID, ClientLockStatContext>();
0160: this .holderStats = new LockHolderStats(topN);
0161: this .lockStats = new LRUMap(topN);
0162: this .lockStackTraces = new LRUMap(topN);
0163: }
0164:
0165: private void clearAllStatistics() {
0166: this .clientStatEnabledLock.clear();
0167: this .holderStats.clear();
0168: this .lockStats.clear();
0169: this .lockStackTraces.clear();
0170: }
0171:
0172: public synchronized void start(DSOChannelManager channelManager,
0173: LockManager lockManager, Sink sink) {
0174: this .channelManager = channelManager;
0175: this .lockManager = lockManager;
0176: this .sink = sink;
0177: }
0178:
0179: public synchronized boolean isLockStatisticsEnabled() {
0180: return this .lockStatEnabled;
0181: }
0182:
0183: public synchronized void setLockStatisticsEnabled(
0184: boolean lockStatEnabled) {
0185: if ((this .lockStatEnabled = lockStatEnabled) == false) {
0186: for (Iterator i = clientStatEnabledLock.keySet().iterator(); i
0187: .hasNext();) {
0188: LockID lockID = (LockID) i.next();
0189: disableClientStackTrace(lockID);
0190: }
0191: clearAllStatistics();
0192: }
0193: }
0194:
0195: public synchronized void enableLockStatistics() {
0196: this .lockStatEnabled = true;
0197: }
0198:
0199: public synchronized void disableLockStatistics() {
0200: this .lockStatEnabled = false;
0201: for (Iterator i = clientStatEnabledLock.keySet().iterator(); i
0202: .hasNext();) {
0203: LockID lockID = (LockID) i.next();
0204: disableClientStackTrace(lockID);
0205: }
0206: clearAllStatistics();
0207: }
0208:
0209: private LockHolder newLockHolder(LockID lockID, NodeID nodeID,
0210: ThreadID threadID, int lockLevel, long timeStamp) {
0211: return new LockHolder(lockID, nodeID, channelManager
0212: .getChannelAddress(nodeID), threadID, lockLevel,
0213: timeStamp);
0214: }
0215:
0216: private LockKey newLockKey(LockID lockID, NodeID nodeID,
0217: ThreadID threadID) {
0218: return new LockKey(lockID, nodeID, threadID);
0219: }
0220:
0221: public void enableClientStackTrace(LockID lockID) {
0222: ClientLockStatContext clientLockStatContext = new ClientLockStatContext();
0223: enableClientStat(lockID, clientLockStatContext);
0224: }
0225:
0226: public void enableClientStackTrace(LockID lockID,
0227: int stackTraceDepth, int statCollectFrequency) {
0228: ClientLockStatContext clientLockStatContext = new ClientLockStatContext(
0229: statCollectFrequency, stackTraceDepth);
0230: enableClientStat(lockID, clientLockStatContext);
0231: }
0232:
0233: private void enableClientStat(LockID lockID,
0234: ClientLockStatContext clientLockStatContext) {
0235: if (clientLockStatContext.getStackTraceDepth() == 0) {
0236: disableClientStackTrace(lockID);
0237: return;
0238: }
0239:
0240: synchronized (this ) {
0241: if (!lockStatEnabled) {
0242: return;
0243: }
0244:
0245: lockStackTraces.remove(lockID);
0246: clientStatEnabledLock.put(lockID, clientLockStatContext);
0247: }
0248: lockManager.enableClientStat(lockID, sink,
0249: clientLockStatContext.getStackTraceDepth(),
0250: clientLockStatContext.getCollectFrequency());
0251: }
0252:
0253: public void disableClientStackTrace(LockID lockID) {
0254: Set statEnabledClients = null;
0255: synchronized (this ) {
0256: if (!lockStatEnabled) {
0257: return;
0258: }
0259:
0260: lockStackTraces.remove(lockID);
0261: ClientLockStatContext clientLockStatContext = clientStatEnabledLock
0262: .remove(lockID);
0263: statEnabledClients = clientLockStatContext
0264: .getStatEnabledClients();
0265: }
0266: if (statEnabledClients != null) {
0267: lockManager.disableClientStat(lockID, statEnabledClients,
0268: sink);
0269: }
0270: }
0271:
0272: public synchronized boolean isClientLockStackTraceEnable(
0273: LockID lockID) {
0274: return clientStatEnabledLock.containsKey(lockID);
0275: }
0276:
0277: public synchronized int getLockStackTraceDepth(LockID lockID) {
0278: ClientLockStatContext clientLockStatContext = clientStatEnabledLock
0279: .get(lockID);
0280: return clientLockStatContext.getStackTraceDepth();
0281: }
0282:
0283: public synchronized int getLockStatCollectFrequency(LockID lockID) {
0284: ClientLockStatContext clientLockStatContext = clientStatEnabledLock
0285: .get(lockID);
0286: return clientLockStatContext.getCollectFrequency();
0287: }
0288:
0289: public synchronized boolean isLockStackTraceEnabledInClient(
0290: LockID lockID, NodeID nodeID) {
0291: ClientLockStatContext clientLockStatContext = clientStatEnabledLock
0292: .get(lockID);
0293: if (clientLockStatContext == null) {
0294: return false;
0295: }
0296: return clientLockStatContext.isClientLockStatEnabled(nodeID);
0297: }
0298:
0299: public synchronized void recordClientStackTraceEnabled(
0300: LockID lockID, NodeID nodeID) {
0301: if (!lockStatEnabled) {
0302: return;
0303: }
0304:
0305: ClientLockStatContext clientLockStatContext = clientStatEnabledLock
0306: .get(lockID);
0307: Assert.assertNotNull(clientLockStatContext);
0308: clientLockStatContext.addClient(nodeID);
0309: }
0310:
0311: public synchronized void lockHopped(LockID lockID) {
0312: if (!lockStatEnabled) {
0313: return;
0314: }
0315:
0316: LockStat lockStat = lockStats.get(lockID);
0317: if (lockStat != null) {
0318: lockStat.lockHop();
0319: }
0320: }
0321:
0322: public synchronized void lockRequested(LockID lockID,
0323: NodeID nodeID, ThreadID threadID, int lockLevel) {
0324: if (!lockStatEnabled) {
0325: return;
0326: }
0327:
0328: LockStat lockStat = lockStats.get(lockID);
0329: if (lockStat == null) {
0330: lockStat = new LockStat(lockID);
0331: lockStats.put(lockID, lockStat);
0332: }
0333: lockStat.lockRequested();
0334:
0335: LockHolder lockHolder = newLockHolder(lockID, nodeID, threadID,
0336: lockLevel, System.currentTimeMillis());
0337: addLockHolder(newLockKey(lockID, nodeID, threadID), lockHolder);
0338: }
0339:
0340: private LockHolder getLockHolder(LockKey key) {
0341: return (LockHolder) holderStats.get(key);
0342: }
0343:
0344: public void addLockHolder(LockKey key, LockHolder lockHolder) {
0345: holderStats.put(key, lockHolder);
0346: }
0347:
0348: public synchronized void lockAwarded(LockID lockID, NodeID nodeID,
0349: ThreadID threadID, boolean isGreedy, long lockAwardTimestamp) {
0350: if (!lockStatEnabled) {
0351: return;
0352: }
0353:
0354: LockKey lockKey = newLockKey(lockID, nodeID, threadID);
0355: LockHolder lockHolder = getLockHolder(lockKey);
0356:
0357: if (lockHolder != null) { // a lock holder could be null if jmx is enabled during runtime
0358: lockHolder.lockAcquired(lockAwardTimestamp);
0359: if (isGreedy) {
0360: holderStats.remove(lockKey, lockHolder);
0361: lockKey = newLockKey(lockID, nodeID, ThreadID.VM_ID);
0362: holderStats.put(lockKey, lockHolder);
0363: }
0364: }
0365:
0366: LockStat lockStat = lockStats.get(lockID);
0367: if (lockStat != null) {
0368: lockStat.lockAwarded();
0369:
0370: if (lockHolder != null) {
0371: lockStat.aggregateWaitTime(lockHolder
0372: .getAndSetWaitTimeInMillis());
0373: }
0374: }
0375: }
0376:
0377: public synchronized void lockReleased(LockID lockID, NodeID nodeID,
0378: ThreadID threadID) {
0379: if (!lockStatEnabled) {
0380: return;
0381: }
0382:
0383: LockStat lockStat = lockStats.get(lockID);
0384:
0385: LockHolder lockHolder = lockReleasedInternal(lockID, nodeID,
0386: threadID);
0387: if (lockHolder == null) {
0388: return;
0389: }
0390:
0391: if (lockStat != null) {
0392: lockStat.lockReleased();
0393: lockStat.aggregateHeldTime(lockHolder
0394: .getAndSetHeldTimeInMillis());
0395: }
0396: }
0397:
0398: private LockHolder lockReleasedInternal(LockID lockID,
0399: NodeID nodeID, ThreadID threadID) {
0400: LockKey lockKey = newLockKey(lockID, nodeID, threadID);
0401: LockHolder lockHolder = getLockHolder(lockKey);
0402: if (lockHolder == null) {
0403: return null;
0404: }
0405:
0406: lockHolder.lockReleased();
0407: holderStats.moveToHistory(lockKey, lockHolder);
0408:
0409: return lockHolder;
0410: }
0411:
0412: public synchronized void lockRejected(LockID lockID, NodeID nodeID,
0413: ThreadID threadID) {
0414: if (!lockStatEnabled) {
0415: return;
0416: }
0417:
0418: LockStat lockStat = lockStats.get(lockID);
0419: if (lockStat != null) {
0420: lockStat.lockRejected();
0421: }
0422:
0423: lockReleasedInternal(lockID, nodeID, threadID);
0424: }
0425:
0426: public synchronized void lockWait(LockID lockID) {
0427: if (!lockStatEnabled) {
0428: return;
0429: }
0430:
0431: LockStat lockStat = lockStats.get(lockID);
0432: if (lockStat != null) {
0433: lockStat.lockWaited();
0434: }
0435: }
0436:
0437: public synchronized void lockNotified(LockID lockID, int n) {
0438: if (!lockStatEnabled) {
0439: return;
0440: }
0441:
0442: LockStat lockStat = lockStats.get(lockID);
0443: if (lockStat != null) {
0444: lockStat.lockNotified(n);
0445: }
0446: }
0447:
0448: public synchronized void recordStackTraces(LockID lockID,
0449: NodeID nodeID, List stackTraces) {
0450: if (!lockStatEnabled) {
0451: return;
0452: }
0453:
0454: Map<LockKey, LockStackTracesStat> existingStackTraces = lockStackTraces
0455: .get(lockID);
0456: LockKey lockKey = new LockKey(lockID, nodeID);
0457: if (existingStackTraces == null) {
0458: existingStackTraces = new LRUMap(topN);
0459: existingStackTraces.put(lockKey, new LockStackTracesStat(
0460: nodeID, lockID, stackTraces, topN));
0461: lockStackTraces.put(lockID, existingStackTraces);
0462: } else {
0463: LockStackTracesStat stackTracesStat = existingStackTraces
0464: .get(lockKey);
0465: if (stackTracesStat == null) {
0466: stackTracesStat = new LockStackTracesStat(nodeID,
0467: lockID, stackTraces, topN);
0468: existingStackTraces.put(lockKey, stackTracesStat);
0469: } else {
0470: stackTracesStat.addStackTraces(stackTraces);
0471: }
0472: }
0473: }
0474:
0475: public synchronized long getNumberOfLockRequested(LockID lockID) {
0476: if (!lockStatEnabled) {
0477: return 0;
0478: }
0479:
0480: return lockStats.get(lockID).getNumOfLockRequested();
0481: }
0482:
0483: public synchronized long getNumberOfLockReleased(LockID lockID) {
0484: if (!lockStatEnabled) {
0485: return 0;
0486: }
0487:
0488: return lockStats.get(lockID).getNumOfLockReleased();
0489: }
0490:
0491: public synchronized long getNumberOfPendingRequests(LockID lockID) {
0492: if (!lockStatEnabled) {
0493: return 0;
0494: }
0495:
0496: return lockStats.get(lockID).getNumOfPendingRequests();
0497: }
0498:
0499: public synchronized LockHolder getLockHolder(LockID lockID,
0500: NodeID nodeID, ThreadID threadID) {
0501: if (!lockStatEnabled) {
0502: return null;
0503: }
0504:
0505: return getLockHolder(newLockKey(lockID, nodeID, threadID));
0506: }
0507:
0508: public synchronized long getNumberOfLockHopRequests(LockID lockID) {
0509: if (!lockStatEnabled) {
0510: return 0;
0511: }
0512:
0513: return lockStats.get(lockID).getNumOfLockHopRequests();
0514: }
0515:
0516: public synchronized Collection getTopLockStats(int n) {
0517: if (!lockStatEnabled) {
0518: return Collections.EMPTY_LIST;
0519: }
0520:
0521: Collection allLockStats = lockStats.values();
0522: TopN topNLockStats = new TopN(LOCK_REQUESTED_COMPARATOR, n);
0523: topNLockStats.evaluate(allLockStats);
0524: return topNLockStats.getDataSnapshot();
0525: }
0526:
0527: public synchronized Collection getTopAggregateLockHolderStats(int n) {
0528: if (!lockStatEnabled) {
0529: return Collections.EMPTY_LIST;
0530: }
0531:
0532: return holderStats.aggregateTopN(lockStats, n,
0533: AVERAGE_LOCK_HELD_COMPARATOR);
0534: }
0535:
0536: public synchronized Collection getTopLockHoldersStats(int n) {
0537: if (!lockStatEnabled) {
0538: return Collections.EMPTY_LIST;
0539: }
0540:
0541: return holderStats.topN(n, LOCK_HELD_COMPARATOR);
0542: }
0543:
0544: public synchronized Collection getTopAggregateWaitingLocks(int n) {
0545: if (!lockStatEnabled) {
0546: return Collections.EMPTY_LIST;
0547: }
0548:
0549: return holderStats.aggregateTopN(lockStats, n,
0550: AVERAGE_LOCK_ACQUIRED_WAITING_COMPARATOR);
0551: }
0552:
0553: public synchronized Collection getTopWaitingLocks(int n) {
0554: if (!lockStatEnabled) {
0555: return Collections.EMPTY_LIST;
0556: }
0557:
0558: return holderStats.topN(n, LOCK_ACQUIRED_WAITING_COMPARATOR);
0559: }
0560:
0561: public synchronized Collection getTopContendedLocks(int n) {
0562: if (!lockStatEnabled) {
0563: return Collections.EMPTY_LIST;
0564: }
0565:
0566: Collection allLockStats = lockStats.values();
0567: TopN topNLockStats = new TopN(PENDING_LOCK_REQUESTS_COMPARATOR,
0568: n);
0569: topNLockStats.evaluate(allLockStats);
0570: return topNLockStats.getDataSnapshot();
0571: }
0572:
0573: public synchronized Collection getTopLockHops(int n) {
0574: if (!lockStatEnabled) {
0575: return Collections.EMPTY_LIST;
0576: }
0577:
0578: Collection allLockStats = lockStats.values();
0579: TopN topNLockStats = new TopN(LOCK_HOP_REQUESTED_COMPARATOR, n);
0580: topNLockStats.evaluate(allLockStats);
0581: return topNLockStats.getDataSnapshot();
0582: }
0583:
0584: public synchronized Collection getStackTraces(LockID lockID) {
0585: if (!lockStatEnabled) {
0586: return Collections.EMPTY_LIST;
0587: }
0588:
0589: Map<?, LockStackTracesStat> stackTraces = lockStackTraces
0590: .get(lockID);
0591: if (stackTraces == null) {
0592: return Collections.EMPTY_LIST;
0593: }
0594: return new ArrayList<LockStackTracesStat>(stackTraces.values());
0595: }
0596:
0597: public synchronized void clearAllStatsFor(NodeID nodeID) {
0598: if (!lockStatEnabled) {
0599: return;
0600: }
0601:
0602: this .holderStats.clearAllStatsFor(nodeID);
0603: }
0604:
0605: private static class LockKey {
0606: private LockID lockID;
0607: private NodeID nodeID;
0608: private ThreadID threadID;
0609: private int hashCode;
0610:
0611: private LockKey subKey;
0612:
0613: public LockKey(LockID lockID, NodeID nodeID) {
0614: this .lockID = lockID;
0615: this .nodeID = nodeID;
0616: this .threadID = null;
0617: this .subKey = null;
0618: this .hashCode = new HashCodeBuilder(5503, 6737).append(
0619: lockID).append(nodeID).toHashCode();
0620: }
0621:
0622: public LockKey(LockID lockID, NodeID nodeID, ThreadID threadID) {
0623: this .lockID = lockID;
0624: this .nodeID = nodeID;
0625: this .threadID = threadID;
0626: this .hashCode = new HashCodeBuilder(5503, 6737).append(
0627: lockID).append(nodeID).append(threadID)
0628: .toHashCode();
0629: this .subKey = new LockKey(lockID, nodeID);
0630: }
0631:
0632: public String toString() {
0633: return "LockKey [ " + lockID + ", " + nodeID + ", "
0634: + threadID + ", " + hashCode + "] ";
0635: }
0636:
0637: public NodeID getNodeID() {
0638: return nodeID;
0639: }
0640:
0641: public LockID getLockID() {
0642: return lockID;
0643: }
0644:
0645: public ThreadID getThreadID() {
0646: return threadID;
0647: }
0648:
0649: public LockKey subKey() {
0650: return subKey;
0651: }
0652:
0653: public boolean equals(Object o) {
0654: if (o == this )
0655: return true;
0656: if (!(o instanceof LockKey))
0657: return false;
0658: LockKey cmp = (LockKey) o;
0659: if (threadID != null) {
0660: return lockID.equals(cmp.lockID)
0661: && nodeID.equals(cmp.nodeID)
0662: && threadID.equals(cmp.threadID);
0663: } else {
0664: return lockID.equals(cmp.lockID)
0665: && nodeID.equals(cmp.nodeID);
0666: }
0667: }
0668:
0669: public int hashCode() {
0670: return hashCode;
0671: }
0672: }
0673:
0674: private static class LockHolderStats {
0675: private static class PendingStat {
0676: private long numOfHolders;
0677: private long totalWaitTimeInMillis;
0678: private long totalHeldTimeInMillis;
0679:
0680: public PendingStat(long waitTimeInMillis,
0681: long heldTimeInMillis) {
0682: addPendingHolderData(waitTimeInMillis, heldTimeInMillis);
0683: }
0684:
0685: public void addPendingHolderData(long waitTimeInMillis,
0686: long heldTimeInMillis) {
0687: this .numOfHolders++;
0688: this .totalHeldTimeInMillis += heldTimeInMillis;
0689: this .totalWaitTimeInMillis += waitTimeInMillis;
0690: }
0691: }
0692:
0693: private final static int NO_LIMIT = -1;
0694:
0695: private final Map<LockKey, Map<LockKey, LockHolder>> pendingData; // map<LockKey.subKey, map<LockKey, LockHolder>>
0696: private final LinkedList<LockHolder> historyData; // list of LockHolder
0697: private final int maxSize;
0698:
0699: public LockHolderStats() {
0700: this (NO_LIMIT);
0701: }
0702:
0703: public LockHolderStats(int maxSize) {
0704: pendingData = new HashMap<LockKey, Map<LockKey, LockHolder>>();
0705: historyData = new LinkedList<LockHolder>();
0706: this .maxSize = maxSize;
0707: }
0708:
0709: public void clear() {
0710: this .pendingData.clear();
0711: this .historyData.clear();
0712: }
0713:
0714: public void put(LockKey key, LockHolder value) {
0715: LockKey subKey = key.subKey();
0716: Map<LockKey, LockHolder> lockHolders = pendingData
0717: .get(subKey);
0718: if (lockHolders == null) {
0719: lockHolders = new HashMap<LockKey, LockHolder>();
0720: pendingData.put(subKey, lockHolders);
0721: }
0722: lockHolders.put(key, value);
0723: }
0724:
0725: public void remove(LockKey key, Object value) {
0726: LockKey subKey = key.subKey();
0727: Map lockHolders = pendingData.get(subKey);
0728: lockHolders.remove(key);
0729: }
0730:
0731: public void moveToHistory(LockKey key, Object value) {
0732: LockKey subKey = key.subKey();
0733: Map lockHolders = pendingData.get(subKey);
0734: LockHolder o = (LockHolder) lockHolders.remove(key);
0735: historyData.addLast(o);
0736: removeOldDataIfNeeded();
0737: }
0738:
0739: private void removeOldDataIfNeeded() {
0740: if (maxSize != NO_LIMIT && historyData.size() > maxSize) {
0741: historyData.removeFirst();
0742: }
0743: }
0744:
0745: public Object get(LockKey key) {
0746: LockKey subKey = key.subKey();
0747: Map lockHolders = pendingData.get(subKey);
0748: if (lockHolders == null)
0749: return null;
0750: if (lockHolders.size() == 0)
0751: return null;
0752:
0753: return lockHolders.get(key);
0754: }
0755:
0756: public boolean contains(LockKey key) {
0757: LockKey subKey = key.subKey();
0758: Map lockHolders = pendingData.get(subKey);
0759: return lockHolders.containsKey(key);
0760: }
0761:
0762: public Collection aggregateTopN(Map lockStats, int n,
0763: Comparator comparator) {
0764: Map<LockID, PendingStat> aggregateData = new HashMap<LockID, PendingStat>(); // map<LockID, PendingStat>
0765:
0766: Collection val = pendingData.values();
0767: for (Iterator i = val.iterator(); i.hasNext();) {
0768: Map lockHolders = (Map) i.next();
0769: for (Iterator j = lockHolders.values().iterator(); j
0770: .hasNext();) {
0771: LockHolder lockHolder = (LockHolder) j.next();
0772: updateAggregateLockHolder(aggregateData, lockHolder);
0773: }
0774: }
0775: for (Iterator i = aggregateData.keySet().iterator(); i
0776: .hasNext();) {
0777: LockID lockID = (LockID) i.next();
0778: PendingStat pendingStat = aggregateData.get(lockID);
0779: LockStat lockStat = (LockStat) lockStats.get(lockID);
0780: lockStat.aggregateAvgWaitTimeInMillis(
0781: pendingStat.totalWaitTimeInMillis,
0782: pendingStat.numOfHolders);
0783: lockStat.aggregateAvgHeldTimeInMillis(
0784: pendingStat.totalHeldTimeInMillis,
0785: pendingStat.numOfHolders);
0786: }
0787: TopN topN = new TopN(comparator, n);
0788: topN.evaluate(lockStats.values());
0789: return topN.getDataSnapshot();
0790: }
0791:
0792: private void updateAggregateLockHolder(
0793: Map<LockID, PendingStat> aggregateData,
0794: LockHolder lockHolder) {
0795: PendingStat pendingStat = aggregateData.get(lockHolder
0796: .getLockID());
0797: if (pendingStat == null) {
0798: pendingStat = new PendingStat(lockHolder
0799: .getAndSetWaitTimeInMillis(), lockHolder
0800: .getAndSetHeldTimeInMillis());
0801: aggregateData.put(lockHolder.getLockID(), pendingStat);
0802: } else {
0803: pendingStat.addPendingHolderData(lockHolder
0804: .getAndSetWaitTimeInMillis(), lockHolder
0805: .getAndSetHeldTimeInMillis());
0806: }
0807: }
0808:
0809: public Collection topN(int n, Comparator comparator) {
0810: Collection val = pendingData.values();
0811:
0812: TopN topN = new TopN(comparator, n);
0813: for (Iterator i = val.iterator(); i.hasNext();) {
0814: Map lockHolders = (Map) i.next();
0815: for (Iterator j = lockHolders.values().iterator(); j
0816: .hasNext();) {
0817: LockHolder lockHolder = (LockHolder) j.next();
0818: lockHolder.getAndSetHeldTimeInMillis();
0819: lockHolder.getAndSetWaitTimeInMillis();
0820: topN.evaluate(lockHolder);
0821: }
0822: }
0823: topN.evaluate(historyData);
0824: return topN.getDataSnapshot();
0825: }
0826:
0827: public void clearAllStatsFor(NodeID nodeID) {
0828: Set<LockKey> lockKeys = pendingData.keySet();
0829: for (Iterator<LockKey> i = lockKeys.iterator(); i.hasNext();) {
0830: LockKey key = i.next();
0831: if (nodeID.equals(key.getNodeID())) {
0832: i.remove();
0833: }
0834: }
0835: }
0836:
0837: public String toString() {
0838: return pendingData.toString();
0839: }
0840: }
0841:
0842: public static class LockStackTracesStat implements Serializable {
0843: private final NodeID nodeID;
0844: private final LockID lockID;
0845: private final LinkedList<TCStackTraceElement> stackTraces;
0846: private final int maxNumOfStackTraces;
0847:
0848: public LockStackTracesStat(NodeID nodeID, LockID lockID,
0849: List newStackTraces, int maxNumOfStackTraces) {
0850: this .nodeID = nodeID;
0851: this .lockID = lockID;
0852: this .stackTraces = new LinkedList<TCStackTraceElement>();
0853: this .maxNumOfStackTraces = maxNumOfStackTraces;
0854: addStackTraces(newStackTraces);
0855: }
0856:
0857: public void addStackTraces(List newStackTraces) {
0858: for (Iterator i = newStackTraces.iterator(); i.hasNext();) {
0859: this .stackTraces.addFirst((TCStackTraceElement) i
0860: .next());
0861: }
0862: removeIfOverFlow();
0863: }
0864:
0865: private void removeIfOverFlow() {
0866: while (this .stackTraces.size() > maxNumOfStackTraces) {
0867: this .stackTraces.removeLast();
0868: }
0869: }
0870:
0871: public NodeID getNodeID() {
0872: return this .nodeID;
0873: }
0874:
0875: public List getStackTraces() {
0876: return this .stackTraces;
0877: }
0878:
0879: public String toString() {
0880: StringBuffer sb = new StringBuffer(nodeID.toString());
0881: sb.append(" ");
0882: sb.append(lockID);
0883: sb.append("\n");
0884: for (Iterator i = stackTraces.iterator(); i.hasNext();) {
0885: sb.append(i.next().toString());
0886: sb.append("\n\n");
0887: }
0888: return sb.toString();
0889: }
0890: }
0891:
0892: public static class LockStat implements Serializable {
0893: private final static long NON_SET_TIME_MILLIS = -1;
0894: private static final long serialVersionUID = 618840956490853662L;
0895:
0896: private final LockID lockID;
0897: private long numOfPendingRequests;
0898: private long numOfPendingWaiters;
0899: private long numOfRequested;
0900: private long numOfReleased;
0901: private long numOfRejected;
0902: private long numOfLockHopRequests;
0903: private long numOfAwarded;
0904: private long totalWaitTimeInMillis;
0905: private long totalHeldTimeInMillis;
0906: private long avgWaitTimeInMillis;
0907: private long avgHeldTimeInMillis;
0908:
0909: public LockStat(LockID lockID) {
0910: this .lockID = lockID;
0911: numOfRequested = 0;
0912: numOfReleased = 0;
0913: numOfPendingRequests = 0;
0914: numOfPendingWaiters = 0;
0915: numOfLockHopRequests = 0;
0916: numOfAwarded = 0;
0917: totalWaitTimeInMillis = 0;
0918: totalHeldTimeInMillis = 0;
0919: avgWaitTimeInMillis = NON_SET_TIME_MILLIS;
0920: avgHeldTimeInMillis = NON_SET_TIME_MILLIS;
0921: }
0922:
0923: public LockID getLockID() {
0924: return lockID;
0925: }
0926:
0927: public void lockRequested() {
0928: numOfRequested++;
0929: numOfPendingRequests++;
0930: }
0931:
0932: public void lockAwarded() {
0933: numOfPendingRequests--;
0934: numOfAwarded++;
0935: }
0936:
0937: public void lockRejected() {
0938: numOfPendingRequests--;
0939: numOfRejected++;
0940: }
0941:
0942: public void lockWaited() {
0943: numOfPendingWaiters++;
0944: }
0945:
0946: public void lockNotified(int n) {
0947: numOfPendingWaiters -= n;
0948: }
0949:
0950: public void lockHop() {
0951: numOfLockHopRequests++;
0952: }
0953:
0954: public long getNumOfLockRequested() {
0955: return numOfRequested;
0956: }
0957:
0958: public void lockReleased() {
0959: numOfReleased++;
0960: }
0961:
0962: public long getNumOfLockReleased() {
0963: return numOfReleased;
0964: }
0965:
0966: public long getNumOfPendingRequests() {
0967: return numOfPendingRequests;
0968: }
0969:
0970: public long getNumOfPendingWaiters() {
0971: return numOfPendingWaiters;
0972: }
0973:
0974: public long getNumOfLockHopRequests() {
0975: return numOfLockHopRequests;
0976: }
0977:
0978: public void aggregateWaitTime(long waitTimeInMillis) {
0979: this .totalWaitTimeInMillis += waitTimeInMillis;
0980: }
0981:
0982: public void aggregateHeldTime(long heldTimeInMillis) {
0983: this .totalHeldTimeInMillis += heldTimeInMillis;
0984: }
0985:
0986: public long getAvgWaitTimeInMillis() {
0987: if (avgWaitTimeInMillis == NON_SET_TIME_MILLIS) {
0988: aggregateAvgWaitTimeInMillis(0, 0);
0989: }
0990: return avgWaitTimeInMillis;
0991: }
0992:
0993: public long getAvgHeldTimeInMillis() {
0994: if (avgHeldTimeInMillis == NON_SET_TIME_MILLIS) {
0995: aggregateAvgHeldTimeInMillis(0, 0);
0996: }
0997: return avgHeldTimeInMillis;
0998: }
0999:
1000: public void aggregateAvgHeldTimeInMillis(
1001: long totalHeldTimeInMillis, long numOfReleased) {
1002: avgHeldTimeInMillis = NON_SET_TIME_MILLIS;
1003: numOfReleased += this .numOfReleased;
1004: totalHeldTimeInMillis += this .totalHeldTimeInMillis;
1005: if (numOfReleased > 0) {
1006: avgHeldTimeInMillis = totalHeldTimeInMillis
1007: / numOfReleased;
1008: }
1009: }
1010:
1011: public void aggregateAvgWaitTimeInMillis(
1012: long totalWaitTimeInMillis, long numOfAwarded) {
1013: avgWaitTimeInMillis = NON_SET_TIME_MILLIS;
1014: numOfAwarded += this .numOfAwarded;
1015: totalWaitTimeInMillis += this .totalWaitTimeInMillis;
1016: if (numOfAwarded > 0) {
1017: avgWaitTimeInMillis = totalWaitTimeInMillis
1018: / numOfAwarded;
1019: }
1020: }
1021:
1022: public String toString() {
1023: StringBuffer sb = new StringBuffer("[LockID: ");
1024: sb.append(lockID);
1025: sb.append(", number of requested: ");
1026: sb.append(numOfRequested);
1027: sb.append(", number of released: ");
1028: sb.append(numOfReleased);
1029: sb.append(", number of pending requests: ");
1030: sb.append(numOfPendingRequests);
1031: sb.append(", number of pending waiters: ");
1032: sb.append(numOfPendingWaiters);
1033: sb.append(", number of lock hop: ");
1034: sb.append(numOfLockHopRequests);
1035: sb.append("]");
1036: return sb.toString();
1037: }
1038: }
1039:
1040: }
|