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.tc.management;
006:
007: import com.tc.async.api.Sink;
008: import com.tc.exception.TCRuntimeException;
009: import com.tc.net.protocol.tcm.ClientMessageChannel;
010: import com.tc.net.protocol.tcm.TCMessageType;
011: import com.tc.object.bytecode.ByteCodeUtil;
012: import com.tc.object.lockmanager.api.LockID;
013: import com.tc.object.lockmanager.impl.TCStackTraceElement;
014: import com.tc.object.msg.LockStatisticsResponseMessage;
015: import com.tc.object.net.DSOClientMessageChannel;
016:
017: import java.lang.reflect.Field;
018: import java.util.ArrayList;
019: import java.util.HashMap;
020: import java.util.HashSet;
021: import java.util.Iterator;
022: import java.util.LinkedList;
023: import java.util.List;
024: import java.util.Map;
025: import java.util.Set;
026:
027: // Methods in this class are not synchronized. They should be called from a proper synchronized
028: // context.
029: public class ClientLockStatManagerImpl implements ClientLockStatManager {
030: private final static Set IGNORE_STACK_TRACES_PACKAGE = new HashSet();
031:
032: private final Map stackTracesMap = new HashMap();
033: private final Map statEnabledLocks = new HashMap();
034: private Sink sink;
035: private DSOClientMessageChannel channel;
036:
037: static {
038: IGNORE_STACK_TRACES_PACKAGE.add("com.tc.");
039: IGNORE_STACK_TRACES_PACKAGE.add("com.tcclient.");
040: }
041:
042: private static LockStatisticsResponseMessage createLockStatisticsResponseMessage(
043: ClientMessageChannel channel, LockID lockID,
044: List stackTraces) {
045: LockStatisticsResponseMessage message = (LockStatisticsResponseMessage) channel
046: .createMessage(TCMessageType.LOCK_STATISTICS_RESPONSE_MESSAGE);
047: message.initialize(lockID, stackTraces);
048: return message;
049: }
050:
051: public void start(DSOClientMessageChannel channel, Sink sink) {
052: this .channel = channel;
053: this .sink = sink;
054: }
055:
056: public void recordStackTrace(LockID lockID) {
057: ClientLockStatContext lockStatContext = (ClientLockStatContext) statEnabledLocks
058: .get(lockID);
059: if (lockStatContext.shouldRecordStackTrace()) {
060:
061: Set stackTraces = (Set) stackTracesMap.get(lockID);
062: if (stackTraces == null) {
063: stackTraces = new HashSet();
064: stackTracesMap.put(lockID, stackTraces);
065: }
066:
067: StackTraceElement[] stackTraceElements = getStackTraceElements(lockStatContext
068: .getStackTraceDepth());
069: TCStackTraceElement tcStackTraceElement = new TCStackTraceElement(
070: stackTraceElements);
071:
072: boolean added = stackTraces.add(tcStackTraceElement);
073:
074: if (added) {
075: List stackTracesList = new ArrayList();
076: stackTracesList.add(tcStackTraceElement);
077: send(lockID, stackTracesList);
078: }
079: }
080: lockStatContext.updateCollectTimer();
081: }
082:
083: private StackTraceElement[] getStackTraceElements(
084: int stackTraceDepth) {
085: StackTraceElement[] stackTraces = (new Exception())
086: .getStackTrace();
087: return filterStackTracesElement(stackTraces, stackTraceDepth);
088: }
089:
090: private StackTraceElement[] filterStackTracesElement(
091: StackTraceElement[] stackTraces, int stackTraceDepth) {
092: stackTraces = fixTCInstrumentationStackTraces(stackTraces);
093:
094: List list = new ArrayList();
095: int numOfStackTraceCollected = 0;
096: for (int i = 0; i < stackTraces.length; i++) {
097: if (shouldIgnoreClass(stackTraces[i].getClassName())) {
098: continue;
099: }
100: list.add(stackTraces[i]);
101: numOfStackTraceCollected++;
102: if (numOfStackTraceCollected >= stackTraceDepth) {
103: break;
104: }
105: }
106: StackTraceElement[] rv = new StackTraceElement[list.size()];
107: return (StackTraceElement[]) list.toArray(rv);
108: }
109:
110: private StackTraceElement[] fixTCInstrumentationStackTraces(
111: StackTraceElement[] stackTraces) {
112: LinkedList list = new LinkedList();
113: for (int i = 0; i < stackTraces.length; i++) {
114: if (isTCInstrumentationStackTrace(stackTraces, i)) {
115: setStackTraceLineNumber(stackTraces[i + 1],
116: stackTraces[i].getLineNumber());
117: list.addLast(stackTraces[i + 1]);
118: i++;
119: } else {
120: list.addLast(stackTraces[i]);
121: }
122: }
123: StackTraceElement[] rv = new StackTraceElement[list.size()];
124: return (StackTraceElement[]) list.toArray(rv);
125: }
126:
127: private boolean isTCInstrumentationStackTrace(
128: StackTraceElement[] stackTraces, int index) {
129: if (stackTraces[index].getMethodName().startsWith(
130: ByteCodeUtil.TC_METHOD_PREFIX)) {
131: if (!stackTraces[index + 1].getMethodName().startsWith(
132: ByteCodeUtil.TC_METHOD_PREFIX)) {
133: if (stackTraces[index].getMethodName().endsWith(
134: stackTraces[index + 1].getMethodName())) {
135: return true;
136: }
137: }
138: }
139: return false;
140: }
141:
142: private void setStackTraceLineNumber(StackTraceElement se,
143: int newLineNumber) {
144: try {
145: Field f = StackTraceElement.class
146: .getDeclaredField("lineNumber");
147: f.setAccessible(true);
148: f.set(se, new Integer(newLineNumber));
149: } catch (SecurityException e) {
150: throw new TCRuntimeException(e);
151: } catch (NoSuchFieldException e) {
152: throw new TCRuntimeException(e);
153: } catch (IllegalArgumentException e) {
154: throw new TCRuntimeException(e);
155: } catch (IllegalAccessException e) {
156: throw new TCRuntimeException(e);
157: }
158: }
159:
160: private boolean shouldIgnoreClass(String className) {
161: for (Iterator i = IGNORE_STACK_TRACES_PACKAGE.iterator(); i
162: .hasNext();) {
163: String ignorePackage = (String) i.next();
164: if (className.startsWith(ignorePackage)) {
165: return true;
166: }
167: }
168: return false;
169: }
170:
171: private void send(LockID lockID, List stackTraces) {
172: sink.add(createLockStatisticsResponseMessage(channel.channel(),
173: lockID, stackTraces));
174: }
175:
176: public void enableStackTrace(LockID lockID,
177: int lockStackTraceDepth, int lockStatCollectFrequency) {
178: statEnabledLocks.remove(lockID);
179: stackTracesMap.remove(lockID);
180:
181: ClientLockStatContext lockStatContext = new ClientLockStatContext(
182: lockStatCollectFrequency, lockStackTraceDepth);
183: statEnabledLocks.put(lockID, lockStatContext);
184: }
185:
186: public void disableStackTrace(LockID lockID) {
187: statEnabledLocks.remove(lockID);
188: stackTracesMap.remove(lockID);
189: }
190:
191: public boolean isStatEnabled(LockID lockID) {
192: return statEnabledLocks.containsKey(lockID);
193: }
194: }
|