new chunky wire format-less CPU, more tps

This commit is contained in:
Erik Ostermueller 2016-04-23 02:18:21 -05:00
parent 3a1debcbb8
commit 3efda29a36
23 changed files with 986 additions and 2473 deletions

View File

@ -1,16 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="testsrc"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
<classpathentry kind="lib" path="lib/easymockclassextension-2.5.2.jar"/>
<classpathentry kind="lib" path="lib/easymock-2.5.2.jar"/>
<classpathentry kind="lib" path="lib/cglib-nodep-2.2.jar"/>
<classpathentry kind="lib" path="lib/asm-debug-all-3.3.jar"/>
<classpathentry kind="lib" path="lib/jar-in-jar-loader.jar"/>
<classpathentry kind="lib" path="lib/miglayout-swt-4.2.jar"/>
<classpathentry kind="lib" path="lib/miglayout-core-4.2.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="lib" path="lib/swt-win64-4.3.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="testsrc"/>
<classpathentry kind="lib" path="lib/cglib-nodep-2.2.jar"/>
<classpathentry kind="lib" path="lib/asm-debug-all-3.3.jar"/>
<classpathentry kind="lib" path="lib/jar-in-jar-loader.jar"/>
<classpathentry kind="lib" path="lib/miglayout-swt-4.2.jar"/>
<classpathentry kind="lib" path="lib/miglayout-core-4.2.jar"/>
<classpathentry kind="lib" path="lib/swt-win64-4.3.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
<classpathentry kind="lib" path="lib/easymock-3.4.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View File

@ -23,7 +23,7 @@
classpath="./lib/jarbundler-2.2.0.jar"/>
<property name="findbugs.home" value="./lib/findbugs" />
<property name="asm.jar.file" value="./lib/asm-debug-all-3.3.jar" />
<target name="help">
<java classname="org.apache.tools.ant.Main">
@ -44,7 +44,7 @@
<mkdir dir="./build" />
<mkdir dir="./build/classes" />
<javac destdir="./build/classes" debug="true" source="1.6" target="1.6"
<javac destdir="./build/classes" debug="true" source="1.7" target="1.7"
includeantruntime="false">
<src path="./src"/>
<classpath>
@ -94,7 +94,7 @@
<fileset dir="./build/classes" includes="**/agent/**/*.class" />
<fileset dir="./build/classes" includes="**/output/**/*.class" />
<fileset dir="./build/classes" includes="**/shared/*.class" />
<zipfileset excludes="META-INF/*.MF" src="./lib/asm-debug-all-3.3.jar"/>
<zipfileset excludes="META-INF/*.MF" src="${asm.jar.file}"/>
<rule pattern="org.objectweb.asm.**" result="org.intrace.internal.objectweb.asm.@1"/>
</jarjar>
<copy file="./build/jars/intrace-agent.jar" todir="./lib/" />
@ -175,7 +175,7 @@
</target>
<target name="test" description="Run Tests" depends="build" >
<property name="emma.enabled" value="true" />
<property name="emma.enabled" value="false" />
<mkdir dir="./reports" />
<mkdir dir="./reports/junit" />
@ -186,7 +186,7 @@
<mkdir dir="./build/test" />
<mkdir dir="./build/classes_instr" />
<javac destdir="./build/test" debug="true" source="1.6" target="1.6"
<javac destdir="./build/test" debug="true" source="1.7" target="1.7"
includeantruntime="false">
<src path="./testsrc"/>
<classpath>
@ -220,7 +220,7 @@
<fileset dir="./build/classes_instr" includes="**/agent/**/*.class" />
<fileset dir="./build/classes_instr" includes="**/output/**/*.class" />
<fileset dir="./build/classes_instr" includes="**/shared/*.class" />
<zipfileset excludes="META-INF/*.MF" src="./lib/asm-debug-all-3.3.jar"/>
<zipfileset excludes="META-INF/*.MF" src="${asm.jar.file}"/>
</jar>
<junit printsummary="yes" failureproperty="test.failure">
@ -233,7 +233,7 @@
<jvmarg value="-Demma.coverage.out.merge=true" />
<jvmarg value="-javaagent:./build/tmp/intrace-agent-instr.jar"/>
<jvmarg value="-Xbootclasspath/a:./lib/emma.jar" />
<jvmarg value="-noverify" />
<formatter type="xml"/>
<formatter type="plain"/>

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -23,7 +23,6 @@ public class AgentSettings
private int actualServerPort = -1;
// Dynamic settings
private boolean gzipEnabled = false;
private String[] classRegex = new String[0];
private String[] excludeClassRegex = new String[0];
private boolean instruEnabled = true;
@ -39,7 +38,6 @@ public class AgentSettings
{
// Copy all static state and dynamic settings
actualServerPort = oldInstance.getActualServerPort();
gzipEnabled = oldInstance.isGzipEnabled();
classRegex = oldInstance.getClassRegex();
excludeClassRegex = oldInstance.getExcludeClassRegex();
instruEnabled = oldInstance.isInstrumentationEnabled();
@ -47,12 +45,6 @@ public class AgentSettings
verboseMode = oldInstance.isVerboseMode();
}
public boolean isGzipEnabled() {
return gzipEnabled;
}
public void setGzipEnabled(boolean val) {
gzipEnabled = val;
}
public void parseArgs(String args)
{
@ -116,14 +108,6 @@ public void parseArgs(String args)
{
waitStart = false;
}
else if (arg.toLowerCase(Locale.ROOT).equals(AgentConfigConstants.GZIP + "true"))
{
gzipEnabled = true;
}
else if (arg.toLowerCase(Locale.ROOT).equals(AgentConfigConstants.GZIP + "false"))
{
gzipEnabled = false;
}
else if (arg.startsWith(AgentConfigConstants.CLASS_REGEX))
{
String classRegexStr = arg.replace(AgentConfigConstants.CLASS_REGEX, "");
@ -194,7 +178,6 @@ public void parseArgs(String args)
{
// Output key settings
String currentSettings = "";
currentSettings += "GZip Enabled : " + gzipEnabled + "\n";
currentSettings += "Class Regex : " + Arrays.toString(classRegex) + "\n";
currentSettings += "Exclude Class Regex : " + Arrays.toString(excludeClassRegex) + "\n";
currentSettings += "Tracing Enabled : " + instruEnabled + "\n";
@ -208,8 +191,6 @@ public void parseArgs(String args)
Map<String, String> settingsMap = new HashMap<String, String>();
settingsMap.put(AgentConfigConstants.INSTRU_ENABLED,
Boolean.toString(instruEnabled));
settingsMap.put(AgentConfigConstants.GZIP,
Boolean.toString(gzipEnabled));
settingsMap.put(AgentConfigConstants.CLASS_REGEX,
getPatternString(classRegex));
settingsMap.put(AgentConfigConstants.EXCLUDE_CLASS_REGEX,

View File

@ -308,8 +308,9 @@ public class ClassTransformer implements ClassFileTransformer
originalClassfile);
if (shouldInstrument && !"java.lang.Thread".equals(className))
{
// System.out.println("!! Instrumenting class: " + compclass);
if (settings.isVerboseMode())
TraceHandler.INSTANCE.writeTraceOutput("DEBUG: !! Instrumenting class: " + compclass);
if (settings.saveTracedClassfiles())
{
writeClassBytes(originalClassfile, internalClassName + "_src.class");
@ -528,9 +529,6 @@ public class ClassTransformer implements ClassFileTransformer
Integer.toString(modifiedClasses.size()));
return settingsMap;
}
public boolean isGzipEnabled() {
return settings.isGzipEnabled();
}
/**
* Handle a message and return a response.
@ -556,12 +554,6 @@ public class ClassTransformer implements ClassFileTransformer
// System.out.println("## Settings Changed");
setInstrumentationEnabled(settings.isInstrumentationEnabled());
}
else if (oldSettings.isGzipEnabled() != settings.isGzipEnabled())
{
//For coding simplicity and user clarity, the gzip parameter can only be set on agent side
//So, return to the old setting, which originated with the intrace agent command line parameter -- [gzip-true
settings.setGzipEnabled(oldSettings.isGzipEnabled());
}
else if (!Arrays.equals(oldSettings.getClassRegex(), settings.getClassRegex()))
{
// System.out.println("## Settings Changed");
@ -693,20 +685,24 @@ public class ClassTransformer implements ClassFileTransformer
broadcastProgress(countNumClasses, totalNumClasses);
for (ComparableClass klass : klasses)
{
if (settings.isVerboseMode())
TraceHandler.INSTANCE.writeTraceOutput("DEBUG: !! ClassTransformer#instrumentKlasses [" + klass.klass.getName() + "]");
try
{
inst.retransformClasses(klass.klass);
countNumClasses++;
if ((countNumClasses % 10) == 0)
if ((countNumClasses % 100) == 0)
{
broadcastProgress(countNumClasses, totalNumClasses);
}
}
catch (Throwable e)
{
// Write exception to stdout
// System.out.println(klass.klass.getName());
String error = "Error instrumenting [" + klass.klass.getName() + "]";
if (settings.isVerboseMode())
TraceHandler.INSTANCE.writeTraceOutput("DEBUG: !! " + error);
System.err.println(error);
e.printStackTrace();
}
}

View File

@ -2042,11 +2042,6 @@ public class InTraceUI implements ISocketCallback, IControlConnectionListener
{
return settingsData.netOutEnabled;
}
@Override
public boolean isGzipEnabled()
{
return settingsData.gzipEnabled;
}
};
networkTraceThread = new NetworkDataReceiverThread(remoteAddress,
networkTracePort, config, outputTabs.textOutputTab.filterThread);

View File

@ -6,7 +6,7 @@ import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import org.intrace.shared.Base64;
import org.intrace.shared.SerializationHelper;
public class NetworkDataReceiverThread implements Runnable
@ -14,7 +14,6 @@ public class NetworkDataReceiverThread implements Runnable
public static interface INetworkOutputConfig
{
public boolean isNetOutputEnabled();
public boolean isGzipEnabled();
}
private final Socket traceSocket;
@ -57,13 +56,13 @@ public class NetworkDataReceiverThread implements Runnable
{
if (outputConfig.isNetOutputEnabled())
{
if (outputConfig.isGzipEnabled()) {
byte[] tmp = Base64.decode(traceLine);
traceLine = new String(tmp);
}
traceThread.addTraceLine(traceLine);
}
}
} else if ( data instanceof byte[]) {
String[] myObj1 = SerializationHelper.fromWire( (byte[])data);
for(String s : myObj1)
traceThread.addTraceLine(s);
}
}
}

View File

@ -16,7 +16,6 @@ public class ParsedSettingsData
public boolean entryExitEnabled;
public boolean branchEnabled;
public boolean gzipEnabled = false;
public boolean truncArraysEnabled;
public boolean argsEnabled;
public boolean exitStackTrace = false;
@ -37,15 +36,6 @@ public class ParsedSettingsData
public ParsedSettingsData(Map<String, String> settingsMap)
{
this.settingsMap = settingsMap;
if ("true".equals(settingsMap.get(AgentConfigConstants.GZIP)))
{
gzipEnabled = true;
}
else
{
gzipEnabled = false;
}
if ("true".equals(settingsMap.get(AgentConfigConstants.EXIT_STACK_TRACE)))
{

View File

@ -0,0 +1,42 @@
package org.intrace.output;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
/**
* Given an arrival time (millis), calculate departure time (millis).
* An instance of this object that arrives in a particular time window will depart in the
* -- current window, if BatchWindowMultiplier = 1
* -- subsequent window , if BatchWindowMultiplier = 2
* where window size is defined by the given IBatchSchedulerConfig.
*
* Designed to work with java.util.concurrent.DelayQueue
* https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/DelayQueue.html
* @author erikostermueller
*
*/
public class BatchScheduler {
IBatchSchedulerConfig config = null;
private long arrivalTimeMillis = 0L;
public BatchScheduler(long val, IBatchSchedulerConfig config) {
this.arrivalTimeMillis = val;
this.config = config;
}
public long getArrivalTimeMillis() {
return this.arrivalTimeMillis;
}
public long getDepartureTimeMillis() {
long aLittleTooFarIntoFuture =
this.getArrivalTimeMillis() +
(this.config.getDrainInterval() * this.config.getDrainIntervalMultiplier() );
long offset = aLittleTooFarIntoFuture % this.config.getDrainInterval();
return aLittleTooFarIntoFuture - offset;
}
}

View File

@ -0,0 +1,7 @@
package org.intrace.output;
public interface IBatchSchedulerConfig {
int getDrainInterval();
int getDrainIntervalMultiplier();
}

View File

@ -4,139 +4,343 @@ import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
//import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.TimeUnit;
import org.intrace.agent.server.AgentClientConnection;
import org.intrace.shared.Base64;
import org.intrace.shared.SerializationHelper;
public class NetworkDataSenderThread extends InstruRunnable
{
private boolean alive = true;
private final ServerSocket networkSocket;
private Socket traceSendingSocket = null;
private final BlockingQueue<Object> outgoingData = new LinkedBlockingQueue<Object>(30);
private Map<NetworkDataSenderThread, Object> set = new HashMap<NetworkDataSenderThread, Object>();
private final AgentClientConnection connection;
public class NetworkDataSenderThread extends InstruRunnable {
private long traceEventSequence = 0;
private static final int EST_EVENT_COUNT_PER_BATCH = 16 * 1024;
private static final int BURST_SIZE = 16 * 1024;
private static final int DRAIN_INTERVAL_MS = 1000;
/**
* All BatchQueueEle instances will point to this singleton, to avoid
* unnecessary GC overhead. I made this public so that in the future, the
* parameters could be changed on the fly.
*/
public static IBatchSchedulerConfig batchSchedulerConfig = new IBatchSchedulerConfig() {
@Override
public int getDrainInterval() {
return DRAIN_INTERVAL_MS;
}
public NetworkDataSenderThread(AgentClientConnection connection, ServerSocket networkSocket)
{
this.connection = connection;
this.networkSocket = networkSocket;
}
@Override
public int getDrainIntervalMultiplier() {
return 1;
}
};
public void start(Map<NetworkDataSenderThread, Object> set)
{
this.set = set;
/**
* An internal wrapper class for an individual trace event. Enables use of
* java.util.concurrent.DelayQueue to schedule multiples of these to be
* shipped to the client in a single batch, to avoid previous chatty and
* poorly performing behavior of a single socket write per trace event.
*
* Because of the excess GC required, I'm not thrilled about needing this
* wrapper instance for every trace event. However, the DelayQueue solution
* is otherwise pretty elegant.
*
* @author erikostermueller
*
*/
public static class TraceEventForBatch implements Delayed {
private Object traceEventText = null;
private long arrivalTimeMillis = 0L;
private long traceEventSequence = 0L;
private BatchScheduler batchScheduler = null;
Thread networkThread = new Thread(this);
networkThread.setDaemon(true);
networkThread.setName(Thread.currentThread().getName()
+ " - Network Data Sender");
networkThread.start();
}
public TraceEventForBatch(Object val, long arrivalTimeMillis,
long traceEventSequence) {
this.traceEventText = val;
this.batchScheduler = new BatchScheduler(arrivalTimeMillis,
batchSchedulerConfig);
this.traceEventSequence = traceEventSequence;
}
private void stop()
{
try
{
if (connection != null)
{
connection.setTraceConnEstablished(false);
}
alive = false;
networkSocket.close();
if (traceSendingSocket != null)
{
traceSendingSocket.close();
}
}
catch (IOException e)
{
// Throw away
}
set.remove(this);
// System.out.println("## Trace Connection Disconnected");
}
public Object getTraceEvent() {
return this.traceEventText;
}
public void queueData(Object data)
{
try
{
while (alive && !outgoingData.offer(data, 100, TimeUnit.MILLISECONDS))
{
// Do nothing - work is done above
}
}
catch (InterruptedException e)
{
// Throw away
}
}
public void runMethod()
{
try
{
traceSendingSocket = networkSocket.accept();
// System.out.println("## Trace Connection Established");
traceSendingSocket.setKeepAlive(true);
if (connection != null)
{
connection.setTraceConnEstablished(true);
}
ObjectOutputStream traceWriter = new ObjectOutputStream(
traceSendingSocket
.getOutputStream());
// Ready to handle data
set.put(this, new Object());
while (true)
{
Object traceLine = outgoingData.poll(5, TimeUnit.SECONDS);
if (traceLine != null)
{
if (traceLine instanceof String && connection.getTransformer().isGzipEnabled()) {
String tmp = (String)traceLine;
traceLine = Base64.encodeBytes(tmp.getBytes(), Base64.GZIP);
}
traceWriter.writeObject(traceLine);
}
else
{
traceWriter.writeObject("NOOP");
}
traceWriter.flush();
traceWriter.reset();
}
}
catch (InterruptedException ex)
{
stop();
}
catch (IOException ex)
{
stop();
}
}
@Override
public int compareTo(Delayed o) {
long rc = this.getDelay(TimeUnit.MILLISECONDS)
- o.getDelay(TimeUnit.MILLISECONDS);
return (int) rc;
}
public void gracefulShutdown()
{
while(!outgoingData.isEmpty())
{
try
{
Thread.sleep(100);
}
catch (InterruptedException e)
{
// Ignore
}
}
}
public long getTraceEventSequence() {
return this.traceEventSequence;
}
/**
* "Expiration occurs when an element's getDelay(TimeUnit.NANOSECONDS) method returns a value less than or equal to zero."
* ....taken from here:
* https://docs.oracle.com/javase/7/docs/api/java/util
* /concurrent/DelayQueue.html
*/
@Override
public long getDelay(TimeUnit unit) {
long delay = this.batchScheduler.getDepartureTimeMillis()
- System.currentTimeMillis();
return unit.convert(delay, TimeUnit.MILLISECONDS);
}
}
private boolean alive = true;
private final ServerSocket networkSocket;
private Socket traceSendingSocket = null;
// private final BlockingQueue<Object> outgoingData = new
// LinkedTransferQueue<Object>();
private final BlockingQueue<TraceEventForBatch> outgoingData = new DelayQueue<TraceEventForBatch>();
private Map<NetworkDataSenderThread, Object> set = new HashMap<NetworkDataSenderThread, Object>();
private final AgentClientConnection connection;
public NetworkDataSenderThread(AgentClientConnection connection,
ServerSocket networkSocket) {
this.connection = connection;
this.networkSocket = networkSocket;
}
public void start(Map<NetworkDataSenderThread, Object> set) {
this.set = set;
Thread networkThread = new Thread(this);
networkThread.setDaemon(true);
networkThread.setName(Thread.currentThread().getName()
+ " - Network Data Sender");
networkThread.start();
}
private void stop() {
try {
if (connection != null) {
connection.setTraceConnEstablished(false);
}
alive = false;
networkSocket.close();
if (traceSendingSocket != null) {
traceSendingSocket.close();
}
} catch (IOException e) {
// Throw away
}
set.remove(this);
// System.out.println("## Trace Connection Disconnected");
}
public void queueData(Object data) {
TraceEventForBatch dataWrapper = new TraceEventForBatch(data,
System.currentTimeMillis(), traceEventSequence++);
if (alive)
outgoingData.offer(dataWrapper);
}
public void runMethod_OLD() {
final int HEARTBEAT_TIME_SECONDS = 5;
try {
traceSendingSocket = networkSocket.accept();
// System.out.println("## Trace Connection Established");
traceSendingSocket.setKeepAlive(true);
if (connection != null) {
connection.setTraceConnEstablished(true);
}
ObjectOutputStream traceWriter = new ObjectOutputStream(
traceSendingSocket.getOutputStream());
// Ready to handle data
set.put(this, new Object());
List<String> traceEventsForSingleBatch = new ArrayList<String>(
EST_EVENT_COUNT_PER_BATCH);
List<TraceEventForBatch> tmp = new ArrayList<TraceEventForBatch>(
EST_EVENT_COUNT_PER_BATCH);
while (true) {
TraceEventForBatch traceLineWrapper = outgoingData.poll(
HEARTBEAT_TIME_SECONDS, TimeUnit.SECONDS);
if (traceLineWrapper != null) {
if (traceLineWrapper.getTraceEvent() instanceof String) {
traceEventsForSingleBatch.clear();
tmp.clear();
traceEventsForSingleBatch.add((String) traceLineWrapper
.getTraceEvent());
outgoingData.drainTo(tmp, BURST_SIZE);
Collections.sort(tmp,
new Comparator<TraceEventForBatch>() { // It all
// ends
// badly
// without
// this
// sort.
@Override
public int compare(TraceEventForBatch o1,
TraceEventForBatch o2) {
return (int) (o1
.getTraceEventSequence() - o2
.getTraceEventSequence());
}
});
/**
* This copy from-TraceEventForBatch-to-string-array is
* required to avoid 2 things: -- wire format where each
* trace event has the extra overhead/space of one long
* timestamp (the one used for DelayQueue.getDelay() ).
* -- Requiring TraceEventForBatch .class to be in
* client JVM. This will avoid versioning conflicts.
*/
for (TraceEventForBatch tefb : tmp)
traceEventsForSingleBatch.add((String) tefb
.getTraceEvent());
String[] eventsForOneBatch = new String[traceEventsForSingleBatch
.size()];
traceEventsForSingleBatch.toArray(eventsForOneBatch);
byte[] wireData = SerializationHelper
.toWire(eventsForOneBatch);
traceWriter.writeObject(wireData);
}
} else {
traceWriter.writeObject("NOOP"); // If no events in the last
// HEARTBEAT_TIME_SECONDS,
// then send a NOOP to
// keep the tcp
// connection alive.
}
traceWriter.flush();
traceWriter.reset();
}
} catch (InterruptedException ex) {
stop();
} catch (IOException ex) {
stop();
}
}
public void runMethod() {
final int HEARTBEAT_TIME_SECONDS = 5;
try {
traceSendingSocket = networkSocket.accept();
// System.out.println("## Trace Connection Established");
traceSendingSocket.setKeepAlive(true);
if (connection != null) {
connection.setTraceConnEstablished(true);
}
ObjectOutputStream traceWriter = new ObjectOutputStream(
traceSendingSocket.getOutputStream());
// Ready to handle data
set.put(this, new Object());
while (true) {
TraceEventForBatch traceLineWrapper = outgoingData.poll(
HEARTBEAT_TIME_SECONDS, TimeUnit.SECONDS);
if (traceLineWrapper != null) {
if (traceLineWrapper.getTraceEvent() instanceof String) {
List<TraceEventForBatch> typedAndSortedList = new ArrayList<TraceEventForBatch>(
EST_EVENT_COUNT_PER_BATCH);
typedAndSortedList.add(traceLineWrapper);
while (outgoingData.drainTo(typedAndSortedList, BURST_SIZE) > 0)
;
// It all ends badly without this sort
Collections.sort(typedAndSortedList,
new Comparator<TraceEventForBatch>() {
@Override
public int compare(TraceEventForBatch o1,
TraceEventForBatch o2) {
return (int) (o1
.getTraceEventSequence() - o2
.getTraceEventSequence());
}
});
transmitBatch(traceWriter, typedAndSortedList, BURST_SIZE);
} else {
throw new RuntimeException(
"Found unsupported trace event of type ["
+ traceLineWrapper.getTraceEvent()
.getClass().getName() + "]");
}
} else {
traceWriter.writeObject("NOOP"); // If no events in the last
// HEARTBEAT_TIME_SECONDS,
// then send a NOOP to
// keep the tcp
// connection alive.
}
traceWriter.flush();
traceWriter.reset();
}
} catch (InterruptedException ex) {
stop();
} catch (IOException ex) {
stop();
}
}
/**
* Using the give ObjectOutputStream, transmit the given list of events
* in one or more successive bursts of no more than burstSize events.
*
* This copy from-TraceEventForBatch-to-string-array is required to
* avoid 2 things:
* -- Wire format where each trace event has the extra
* overhead/space of one long timestamp (the one used for
* DelayQueue.getDelay() ).
* -- More complicated wire format that will
* diminish the effectiveness of compression
* -- Requiring TraceEventForBatch .class to be in client JVM.
* This will avoid versioning conflicts.
* @param traceWriter
* @param sortedAndTypedEventList
* @throws IOException
*/
public int transmitBatch(ObjectOutputStream traceWriter,
List<TraceEventForBatch> sortedAndTypedEventList, int burstSize)
throws IOException {
List<String> eventsForSingleBurst = new ArrayList<String>(
burstSize);
int remaining = sortedAndTypedEventList.size();
int burstCount = 0;
for (TraceEventForBatch tefb : sortedAndTypedEventList) {
eventsForSingleBurst.add( (String) tefb.getTraceEvent() );
remaining--;
if (eventsForSingleBurst.size() % burstSize == 0
|| remaining ==0 ) {
String[] aryEventsForSingleBurst = new String[eventsForSingleBurst.size()];
eventsForSingleBurst.toArray(aryEventsForSingleBurst);
byte[] wireData = SerializationHelper.toWire(aryEventsForSingleBurst);
traceWriter.writeObject(wireData);
burstCount++;
eventsForSingleBurst.clear();
}
}
System.out.println("stranded items [" + remaining + "]");
return burstCount;
}
public void gracefulShutdown() {
while (!outgoingData.isEmpty()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// Ignore
}
}
}
}

View File

@ -416,13 +416,25 @@ private static final Object STACK_ELE_DELIM = ",";
StringBuilder sb = new StringBuilder();
int counter = 0;
for(StackTraceElement ste : Thread.currentThread().getStackTrace() ) {
if ( ste.getClassName().indexOf(INTRACE_PACKAGE) <0
&& (ste.getClassName().indexOf(THREAD) < 0) && ste.getMethodName().indexOf(GET_STACK_TRACE)<0) {
boolean disqualify = false;
if (ste != null) {
if ( (ste.getClassName() !=null) &&
( (ste.getClassName().indexOf(INTRACE_PACKAGE) >= 0)
|| (ste.getClassName().indexOf(THREAD) >= 0) )
)
disqualify = true;
if (ste.getMethodName()!=null
&& ste.getMethodName().indexOf(GET_STACK_TRACE) >=0)
disqualify = true;
}
if ( !disqualify) {
if (counter++>0) sb.append(STACK_ELE_DELIM); //Just like Arrays.toString(), place a comma between each stack trace ele.
sb.append(ste.toString());
}
}
return sb.toString();
}
@Override

View File

@ -16,7 +16,6 @@ public class AgentConfigConstants
public static final String SERVER_PORT = "SERVER_PORT";
public static final String GZIP = "[gzip-"; //Default is not enabled (false).
public static final String CLASS_REGEX = "[regex-";
public static final String EXCLUDE_CLASS_REGEX = "[exclude-regex-";
public static final String INSTRU_ENABLED = "[instru-";
@ -39,7 +38,6 @@ public class AgentConfigConstants
COMMANDS.add(VERBOSE_MODE + "<true/false>");
COMMANDS.add(OPT_SERVER_PORT + "<int>");
COMMANDS.add(CALLBACK_PORT + "<int>");
COMMANDS.add(GZIP + "<true/false>");
COMMANDS.add(EXIT_STACK_TRACE + "<true/false>");
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,46 @@
package org.intrace.shared;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
/**
* Round trip serialization and gzip compression for an array of strings.
* This array is a list of intrace 'events' that are batched up for a single
* transmission over a socket.
* @author erikostermueller
*
*/
public class SerializationHelper {
/**
*
* @param eventsForOneBurst
* @return
* @throws IOException
*/
public static byte[] toWire(String[] eventsForOneBurst) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gzipOut = new GZIPOutputStream(baos);
ObjectOutputStream objectOut = new ObjectOutputStream(gzipOut);
objectOut.writeObject(eventsForOneBurst);
objectOut.close();
byte[] bytes = baos.toByteArray();
return bytes;
}
public static String[] fromWire(byte[] bytes) throws IOException, ClassNotFoundException {
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
GZIPInputStream gzipIn = new GZIPInputStream(bais);
ObjectInputStream objectIn = new ObjectInputStream(gzipIn);
String[] myObj1 = (String[]) objectIn.readObject();
objectIn.close();
return myObj1;
}
}

View File

@ -21,7 +21,7 @@ import java.util.concurrent.LinkedBlockingQueue;
import junit.framework.TestCase;
import org.easymock.IAnswer;
import org.easymock.classextension.EasyMock;
import org.easymock.EasyMock;
import org.intrace.output.AgentHelper;
import org.intrace.output.IInstrumentationHandler;
import org.intrace.shared.AgentConfigConstants;
@ -109,22 +109,6 @@ public class AgentTest extends TestCase
assertEquals(helpResponse, expectedHelpResponse);
}
/**
Intentionally, testSetting(AgentConfigConstants.GZIP, "true") does not work.
For simplicity's sake, this setting can only be configured as an intrace agent command line parameter -- [gzip-true
Note that there is no GUI checkbox to enabled Gzip.
To instead enable the client to change this, just change how ClassTransformer#getResponse() deals with a new gzip parameter.
The following simply confirms that
<ul>
<li> getsettings works for gzip parm </li>
<li> b) by default, GZIP is turned off. </li>
</ul>
*
* @throws Exception
*/
public void testRetrievalOfGzipSetting() throws Exception {
testGetSetting(AgentConfigConstants.GZIP, "false");
}
public void testSettings() throws Exception
{
// Boolean settings
@ -149,6 +133,7 @@ public class AgentTest extends TestCase
//testSetting(TraceConfigConstants.BRANCH, "false");
}
private BlockingQueue<String> capturedTrace = null;
public void testBranchPatterns() throws Throwable
{
// Create and init the mock
@ -160,7 +145,8 @@ public class AgentTest extends TestCase
.andReturn(new HashMap<String, String>()).anyTimes();
// Capture objects
final BlockingQueue<String> capturedTrace = new LinkedBlockingQueue<String>();
//final BlockingQueue<String> capturedTrace = new LinkedBlockingQueue<String>();
capturedTrace = new LinkedBlockingQueue<String>();
IAnswer<Object> entryTraceWriter = new IAnswer<Object>()
{
@Override
@ -228,7 +214,6 @@ public class AgentTest extends TestCase
// Setup agent
testSetting(AgentConfigConstants.INSTRU_ENABLED, "false");
testSetting(AgentConfigConstants.GZIP, "false");
testSetting(AgentConfigConstants.CLASS_REGEX, "BranchPatterns");
testSetting(AgentConfigConstants.VERBOSE_MODE, "false");
testSetting(AgentConfigConstants.SAVE_TRACED_CLASSFILES, "true");
@ -344,7 +329,6 @@ public class AgentTest extends TestCase
// Setup agent
testSetting(AgentConfigConstants.INSTRU_ENABLED, "false");
testSetting(AgentConfigConstants.GZIP, "false");
testSetting(AgentConfigConstants.CLASS_REGEX, "ArgumentTypes");
testSetting(AgentConfigConstants.VERBOSE_MODE, "false");
testSetting(AgentConfigConstants.SAVE_TRACED_CLASSFILES, "true");

View File

@ -1,185 +0,0 @@
package org.intracetest.agent;
import java.io.IOException;
import junit.framework.TestCase;
import org.intrace.shared.Base64;
/**
This test proves out the following API using text data from an intrace Event
* <code>String encoded = Base64.encode( myByteArray );</code>
* <br />
* <code>byte[] myByteArray = Base64.decode( encoded );</code>
<pre>
Plain ASCII Base64 Base64+GZIP
-----------------------------------------
Tiny | 70 96 116
|
Small | 248 332 256
|
Big | 2306 3076 904
|
Huge | 12591 16788 1036
</pre>
How small can we compress the InTrace event text for various sized InTrace events?
<ul>
<li>Base64 without GZIP was detrimental to small compression size in all cases</li>
<li>The 70 and 248 byte events were slightly larger with both Base64 and Base64+GZIP -- bad but a not horrible show stopper.</li>
<li>The Big event was more than 2x as small with Base64+GZIP -- good.</li>
<li>The Huge event was more than 10x as small with Base64+GZIP -- great.</li>
<li> </li>
</ul>
Conclusions:
Will not use Base64 alone -- doesn't provide any compression with these samples.
Base64+GZIP doesn't hurt much with smaller event
*/
public class CompressionTest extends TestCase
{
private static final String ORIGINAL_TINY_INTRACE_EVENT = "[18:07:53.683]:[67]:org.hsqldb.jdbc.jdbcConnection:prepareStatement: {";
private static final String ORIGINAL_SMALL_INTRACE_EVENT = "[18:07:53.683]:[67]:org.hsqldb.jdbc.jdbcConnection:prepareStatement" +
": Return: org.hsqldb.jdbc.jdbcPreparedStatement@4b8efa2f[sql=" +
"[INSERT INTO Event (name, description, date, location) VALUES(?, ?, ?, ?)]" +
", parameters=[[null], [null], [null], [null]]]";
/**
* This isn't a real event (yet)...just adding some text to assess compression for larger messages.
*/
private static final String ORIGINAL_LARGE_STACK_TRACE = "[18:07:53.683]:[67]:org.hsqldb.jdbc.jdbcConnection:prepareStatement" +
": Return: org.hsqldb.jdbc.jdbcPreparedStatement@4b8efa2f[sql=" +
"[INSERT INTO Event (name, description, date, location) VALUES(?, ?, ?, ?)]" +
", parameters=[[null], [null], [null], [null]]]" +
"~java.lang.Thread.getStackTrace(Thread.java:1567) example.webapp.servlet.HelloWorld.doGet(HelloWorld.java:38) javax.servlet.http.HttpServlet.service(HttpServlet.java:668) javax.servlet.http.HttpServlet.service(HttpServlet.java:770) org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:669) org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:455) org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137) org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:560) org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:231) org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1072) org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:382) org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193) org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1006) org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135) org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116) org.eclipse.jetty.server.Server.handle(Server.java:365) org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:485) org.eclipse.jetty.server.BlockingHttpConnection.handleRequest(BlockingHttpConnection.java:53) org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:926) org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:988) org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:635) org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:235) org.eclipse.jetty.server.BlockingHttpConnection.handle(BlockingHttpConnection.java:72) org.eclipse.jetty.server.bio.SocketConnector$ConnectorEndPoint.run(SocketConnector.java:264) org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608) org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543) java.lang.Thread.run(Thread.java:722) ";
/**
* This isn't a real event at all...just adding some text to assess compression for msg with more bytes.
*/
private static final String ORIGINAL_HUGE_STACK_TRACE = "[18:07:53.683]:[67]:org.hsqldb.jdbc.jdbcConnection:prepareStatement" +
": Return: org.hsqldb.jdbc.jdbcPreparedStatement@4b8efa2f[sql=" +
"[INSERT INTO Event (name, description, date, location) VALUES(?, ?, ?, ?)]" +
", parameters=[[null], [null], [null], [null]]]" +
"~java.lang.Thread.getStackTrace(Thread.java:1567) example.webapp.servlet.HelloWorld.doGet(HelloWorld.java:38) javax.servlet.http.HttpServlet.service(HttpServlet.java:668) javax.servlet.http.HttpServlet.service(HttpServlet.java:770) org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:669) org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:455) org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137) org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:560) org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:231) org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1072) org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:382) org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193) org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1006) org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135) org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116) org.eclipse.jetty.server.Server.handle(Server.java:365) org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:485) org.eclipse.jetty.server.BlockingHttpConnection.handleRequest(BlockingHttpConnection.java:53) org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:926) org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:988) org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:635) org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:235) org.eclipse.jetty.server.BlockingHttpConnection.handle(BlockingHttpConnection.java:72) org.eclipse.jetty.server.bio.SocketConnector$ConnectorEndPoint.run(SocketConnector.java:264) org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608) org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543) java.lang.Thread.run(Thread.java:722) "+
"java.lang.Thread.getStackTrace(Thread.java:1567) example.webapp.servlet.HelloWorld.doGet(HelloWorld.java:38) javax.servlet.http.HttpServlet.service(HttpServlet.java:668) javax.servlet.http.HttpServlet.service(HttpServlet.java:770) org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:669) org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:455) org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137) org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:560) org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:231) org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1072) org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:382) org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193) org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1006) org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135) org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116) org.eclipse.jetty.server.Server.handle(Server.java:365) org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:485) org.eclipse.jetty.server.BlockingHttpConnection.handleRequest(BlockingHttpConnection.java:53) org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:926) org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:988) org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:635) org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:235) org.eclipse.jetty.server.BlockingHttpConnection.handle(BlockingHttpConnection.java:72) org.eclipse.jetty.server.bio.SocketConnector$ConnectorEndPoint.run(SocketConnector.java:264) org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608) org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543) java.lang.Thread.run(Thread.java:722) "+
"java.lang.Thread.getStackTrace(Thread.java:1567) example.webapp.servlet.HelloWorld.doGet(HelloWorld.java:38) javax.servlet.http.HttpServlet.service(HttpServlet.java:668) javax.servlet.http.HttpServlet.service(HttpServlet.java:770) org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:669) org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:455) org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137) org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:560) org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:231) org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1072) org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:382) org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193) org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1006) org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135) org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116) org.eclipse.jetty.server.Server.handle(Server.java:365) org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:485) org.eclipse.jetty.server.BlockingHttpConnection.handleRequest(BlockingHttpConnection.java:53) org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:926) org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:988) org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:635) org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:235) org.eclipse.jetty.server.BlockingHttpConnection.handle(BlockingHttpConnection.java:72) org.eclipse.jetty.server.bio.SocketConnector$ConnectorEndPoint.run(SocketConnector.java:264) org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608) org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543) java.lang.Thread.run(Thread.java:722) "+
"java.lang.Thread.getStackTrace(Thread.java:1567) example.webapp.servlet.HelloWorld.doGet(HelloWorld.java:38) javax.servlet.http.HttpServlet.service(HttpServlet.java:668) javax.servlet.http.HttpServlet.service(HttpServlet.java:770) org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:669) org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:455) org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137) org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:560) org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:231) org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1072) org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:382) org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193) org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1006) org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135) org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116) org.eclipse.jetty.server.Server.handle(Server.java:365) org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:485) org.eclipse.jetty.server.BlockingHttpConnection.handleRequest(BlockingHttpConnection.java:53) org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:926) org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:988) org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:635) org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:235) org.eclipse.jetty.server.BlockingHttpConnection.handle(BlockingHttpConnection.java:72) org.eclipse.jetty.server.bio.SocketConnector$ConnectorEndPoint.run(SocketConnector.java:264) org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608) org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543) java.lang.Thread.run(Thread.java:722) "+
"java.lang.Thread.getStackTrace(Thread.java:1567) example.webapp.servlet.HelloWorld.doGet(HelloWorld.java:38) javax.servlet.http.HttpServlet.service(HttpServlet.java:668) javax.servlet.http.HttpServlet.service(HttpServlet.java:770) org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:669) org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:455) org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137) org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:560) org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:231) org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1072) org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:382) org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193) org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1006) org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135) org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116) org.eclipse.jetty.server.Server.handle(Server.java:365) org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:485) org.eclipse.jetty.server.BlockingHttpConnection.handleRequest(BlockingHttpConnection.java:53) org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:926) org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:988) org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:635) org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:235) org.eclipse.jetty.server.BlockingHttpConnection.handle(BlockingHttpConnection.java:72) org.eclipse.jetty.server.bio.SocketConnector$ConnectorEndPoint.run(SocketConnector.java:264) org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608) org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543) java.lang.Thread.run(Thread.java:722) "+
"java.lang.Thread.getStackTrace(Thread.java:1567) example.webapp.servlet.HelloWorld.doGet(HelloWorld.java:38) javax.servlet.http.HttpServlet.service(HttpServlet.java:668) javax.servlet.http.HttpServlet.service(HttpServlet.java:770) org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:669) org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:455) org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137) org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:560) org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:231) org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1072) org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:382) org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193) org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1006) org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135) org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116) org.eclipse.jetty.server.Server.handle(Server.java:365) org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:485) org.eclipse.jetty.server.BlockingHttpConnection.handleRequest(BlockingHttpConnection.java:53) org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:926) org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:988) org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:635) org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:235) org.eclipse.jetty.server.BlockingHttpConnection.handle(BlockingHttpConnection.java:72) org.eclipse.jetty.server.bio.SocketConnector$ConnectorEndPoint.run(SocketConnector.java:264) org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608) org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543) java.lang.Thread.run(Thread.java:722) ";
public void testBasicCompressionAndDecompression_smallerWithGZip() throws IOException
{
// System.out.println("Original length of short data [" + ORIGINAL_SMALL_INTRACE_EVENT.length() + "]");
// System.out.println("Original length of long data [" + ORIGINAL_LARGE_STACK_TRACE.length() + "]");
byte[] eventData = ORIGINAL_SMALL_INTRACE_EVENT.getBytes();
String compressedString = Base64.encodeBytes(eventData, Base64.GZIP);
byte[] reconstitutedData = Base64.decode(compressedString, Base64.GZIP);
String reconstitutedString = new String(reconstitutedData);
assertEquals("Size of original text", 248, ORIGINAL_SMALL_INTRACE_EVENT.length() );
assertEquals("Size of compressed text", 256, compressedString.length() );
// System.out.println("Compressed data [" + compressedString + "]");
// System.out.println("Compressed with GZIP length - small data [" + compressedString.length() + "]");
assertEquals("Unable to compress and decompress intrace event data", ORIGINAL_SMALL_INTRACE_EVENT, reconstitutedString);
}
public void testBasicCompressionAndDecompression_largerWithGZip() throws IOException
{
byte[] eventData = ORIGINAL_LARGE_STACK_TRACE.getBytes();
String compressedData = Base64.encodeBytes(eventData, Base64.GZIP);
//String compressedData = Base64.encodeBytes(eventData, Base64.NO_OPTIONS);
byte[] reconstitutedData = Base64.decode(compressedData, Base64.GZIP);
String reconstitutedString = new String(reconstitutedData);
assertEquals("Size of original text", 2306, ORIGINAL_LARGE_STACK_TRACE.length() );
assertEquals("Size of compressed text", 904, compressedData.length() );
// System.out.println("Compressed data [" + compressedData + "]");
// System.out.println("Compressed with GZIP data - long data [" + compressedData.length() + "]");
assertEquals("Unable to compress and decompress intrace event data", ORIGINAL_LARGE_STACK_TRACE, reconstitutedString);
}
public void testBasicCompressionAndDecompression_smallerWithoutGZip() throws IOException
{
byte[] eventData = ORIGINAL_SMALL_INTRACE_EVENT.getBytes();
String compressedString = Base64.encodeBytes(eventData, Base64.NO_OPTIONS);
byte[] reconstitutedData = Base64.decode(compressedString, Base64.NO_OPTIONS);
String reconstitutedString = new String(reconstitutedData);
assertEquals("Size of original text", 248, ORIGINAL_SMALL_INTRACE_EVENT.length() );
assertEquals("Size of compressed text", 332, compressedString.length() );
// System.out.println("Compressed data [" + compressedString + "]");
// System.out.println("Compressed without gzip data - small data [" + compressedString.length() + "]");
assertEquals("Unable to compress and decompress intrace event data", ORIGINAL_SMALL_INTRACE_EVENT, reconstitutedString);
}
public void testBasicCompressionAndDecompression_largerWithoutGZip() throws IOException
{
byte[] eventData = ORIGINAL_LARGE_STACK_TRACE.getBytes();
String compressedData = Base64.encodeBytes(eventData, Base64.NO_OPTIONS);
//String compressedData = Base64.encodeBytes(eventData, Base64.NO_OPTIONS);
byte[] reconstitutedData = Base64.decode(compressedData, Base64.NO_OPTIONS);
String reconstitutedString = new String(reconstitutedData);
assertEquals("Size of original text", 2306, ORIGINAL_LARGE_STACK_TRACE.length() );
assertEquals("Size of compressed text", 3076, compressedData.length() );
// System.out.println("Compressed data [" + compressedData + "]");
// System.out.println("Compressed without gzip - large data [" + compressedData.length() + "]");
assertEquals("Unable to compress and decompress intrace event data", ORIGINAL_LARGE_STACK_TRACE, reconstitutedString);
}
public void testBasicCompressionAndDecompression_tinyWithGZip() throws IOException
{
byte[] eventData = ORIGINAL_TINY_INTRACE_EVENT.getBytes();
String compressedString = Base64.encodeBytes(eventData, Base64.GZIP);
byte[] reconstitutedData = Base64.decode(compressedString, Base64.GZIP);
String reconstitutedString = new String(reconstitutedData);
assertEquals("Size of original text", 70, ORIGINAL_TINY_INTRACE_EVENT.length() );
assertEquals("Size of compressed text", 116, compressedString.length() );
assertEquals("Unable to compress and decompress intrace event data", ORIGINAL_TINY_INTRACE_EVENT, reconstitutedString);
}
public void testBasicCompressionAndDecompression_tinyWithoutGZip() throws IOException
{
byte[] eventData = ORIGINAL_TINY_INTRACE_EVENT.getBytes();
String compressedString = Base64.encodeBytes(eventData, Base64.NO_OPTIONS);
byte[] reconstitutedData = Base64.decode(compressedString, Base64.NO_OPTIONS);
String reconstitutedString = new String(reconstitutedData);
assertEquals("Size of original text", 70, ORIGINAL_TINY_INTRACE_EVENT.length() );
assertEquals("Size of compressed text", 96, compressedString.length() );
assertEquals("Unable to compress and decompress intrace event data", ORIGINAL_TINY_INTRACE_EVENT, reconstitutedString);
}
public void testBasicCompressionAndDecompression_hugeWithGZip() throws IOException
{
byte[] eventData = ORIGINAL_HUGE_STACK_TRACE.getBytes();
String compressedString = Base64.encodeBytes(eventData, Base64.GZIP);
byte[] reconstitutedData = Base64.decode(compressedString, Base64.GZIP);
String reconstitutedString = new String(reconstitutedData);
assertEquals("Size of original text", 12591, ORIGINAL_HUGE_STACK_TRACE.length() );
assertEquals("Size of compressed text", 1036, compressedString.length() );
assertEquals("Unable to compress and decompress intrace event data", ORIGINAL_HUGE_STACK_TRACE, reconstitutedString);
}
public void testBasicCompressionAndDecompression_hugeWithoutGZip() throws IOException
{
byte[] eventData = ORIGINAL_HUGE_STACK_TRACE.getBytes();
String compressedString = Base64.encodeBytes(eventData, Base64.NO_OPTIONS);
byte[] reconstitutedData = Base64.decode(compressedString, Base64.NO_OPTIONS);
String reconstitutedString = new String(reconstitutedData);
assertEquals("Size of original text", 12591, ORIGINAL_HUGE_STACK_TRACE.length() );
assertEquals("Size of compressed text", 16788, compressedString.length() );
assertEquals("Unable to compress and decompress intrace event data", ORIGINAL_HUGE_STACK_TRACE, reconstitutedString);
}
}

View File

@ -0,0 +1,123 @@
package org.intracetest.agent;
import static org.junit.Assert.assertEquals;
import java.util.concurrent.Delayed;
import org.intrace.output.BatchScheduler;
import org.intrace.output.IBatchSchedulerConfig;
import org.junit.Test;
public class DelayQueueBatchTest {
@Test
public void canCalculateDepartureTimes_currentInterval() {
final int INTERVAL = 250; // I N T E R V A L =======> Z E R O t o 2 4 9
final int DEPARTURE_TIME_MILLIS = INTERVAL;
IBatchSchedulerConfig config1 = new IBatchSchedulerConfig() {
@Override
public int getDrainInterval() {return INTERVAL;}
@Override
public int getDrainIntervalMultiplier() { return 1; }
};
//First milli of the interval
BatchScheduler batchScheduler = new BatchScheduler(0L, config1);
assertEquals("Departure time was not calculated correctcly", DEPARTURE_TIME_MILLIS, batchScheduler.getDepartureTimeMillis() );
//Last milli of the interval
batchScheduler = new BatchScheduler( (INTERVAL-1), config1);
assertEquals("Departure time was not calculated correctcly", DEPARTURE_TIME_MILLIS, batchScheduler.getDepartureTimeMillis() );
//First milli of subsequent interval
batchScheduler = new BatchScheduler( INTERVAL, config1);
assertEquals("Departure time was not calculated correctcly", 2*DEPARTURE_TIME_MILLIS, batchScheduler.getDepartureTimeMillis() );
}
@Test
public void canCalculateDepartureTimes_subsequentInterval() {
final int INTERVAL = 250; // I N T E R V A L =======> Z E R O t o 2 4 9
final int DEPARTURE = INTERVAL;
final int MULTIPLIER = 2;
IBatchSchedulerConfig config1 = new IBatchSchedulerConfig() {
@Override
public int getDrainInterval() {return INTERVAL;}
@Override
public int getDrainIntervalMultiplier() { return MULTIPLIER; }
};
BatchScheduler batchScheduler = new BatchScheduler(0L, config1);
assertEquals("Departure time was not calculated correctcly", MULTIPLIER*DEPARTURE, batchScheduler.getDepartureTimeMillis() );
batchScheduler = new BatchScheduler( (INTERVAL-1), config1);
assertEquals("Departure time was not calculated correctcly", MULTIPLIER*DEPARTURE, batchScheduler.getDepartureTimeMillis() );
batchScheduler = new BatchScheduler( INTERVAL, config1);
assertEquals("Departure time was not calculated correctcly", MULTIPLIER*DEPARTURE+INTERVAL, batchScheduler.getDepartureTimeMillis() );
}
IBatchSchedulerConfig config2 = new IBatchSchedulerConfig() {
@Override
public int getDrainInterval() {return 1000;}
@Override
public int getDrainIntervalMultiplier() { return 2; }
};
/**
* First num goes in one batch, 2nd two numbers go in the subsequent batch.
*/
@Test
public void canCalculateSubsequentBatchedDepartureTimes() {
BatchScheduler batchScheduler = new BatchScheduler(2352819999L, this.config2);
assertEquals("Departure time was not calculated correctcly", 2352821000L, batchScheduler.getDepartureTimeMillis() );
batchScheduler = new BatchScheduler(2352820000L, this.config2);
assertEquals("Departure time was not calculated correctcly", 2352822000L, batchScheduler.getDepartureTimeMillis() );
batchScheduler = new BatchScheduler(2352820001L, this.config2);
assertEquals("Departure time was not calculated correctcly", 2352822000L, batchScheduler.getDepartureTimeMillis() );
}
@Test
public void canCalculateBatchedDepartureTimes() {
BatchScheduler batchScheduler = new BatchScheduler(899079228, this.config2);
assertEquals("Departure time was not calculated correctcly", 899081000L, batchScheduler.getDepartureTimeMillis() );
batchScheduler = new BatchScheduler(899079473L, this.config2);
assertEquals("Departure time was not calculated correctcly", 899081000L, batchScheduler.getDepartureTimeMillis() );
batchScheduler = new BatchScheduler(2293479377L, this.config2);
assertEquals("Departure time was not calculated correctcly", 2293481000L, batchScheduler.getDepartureTimeMillis() );
batchScheduler = new BatchScheduler(902521357L, this.config2);
assertEquals("Departure time was not calculated correctcly", 902523000L, batchScheduler.getDepartureTimeMillis() );
batchScheduler = new BatchScheduler(902756592L, this.config2);
assertEquals("Departure time was not calculated correctcly", 902758000L, batchScheduler.getDepartureTimeMillis() );
batchScheduler = new BatchScheduler(2294063215L, this.config2);
assertEquals("Departure time was not calculated correctcly", 2294065000L, batchScheduler.getDepartureTimeMillis() );
}
/**
* First num goes in one batch, 2nd two numbers go in the subsequent batch.
*
*/
@Test
public void canCalculateSubsequentBatchedDepartureTimes_smallerInterval() {
IBatchSchedulerConfig config1 = new IBatchSchedulerConfig() {
@Override
public int getDrainInterval() {return 250;}
@Override
public int getDrainIntervalMultiplier() { return 2; }
};
BatchScheduler batchScheduler = new BatchScheduler(2352819999L, config1);
assertEquals("Departure time was not calculated correctcly", 2352820250L, batchScheduler.getDepartureTimeMillis() );
batchScheduler = new BatchScheduler(2352820000L, config1);
assertEquals("Departure time was not calculated correctcly", 2352820500L, batchScheduler.getDepartureTimeMillis() );
batchScheduler = new BatchScheduler(2352820001L, config1);
assertEquals("Departure time was not calculated correctcly", 2352820500L, batchScheduler.getDepartureTimeMillis() );
}
}

View File

@ -0,0 +1,164 @@
package org.intracetest.agent;
import java.util.List;
import java.util.ArrayList;
import java.util.concurrent.Delayed;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
import org.junit.Before;
import static org.junit.Assert.assertTrue;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.DelayQueue;
import org.intrace.output.trace.TraceHandler;
import static org.junit.Assert.assertEquals;
/** This is a 'proof of concept' test that demonstrates how to use a DelayQueue to emit
* data in batches, instead of individual queue items. Only jdk code and test code is exercised here.
*
* This test sticks 9 items into a DelayQueue. These items comes out in 3 batches.
* The delays (in milliseconds) between the batches are defined in the offsetA, offsetB, and offsetC variables.
*/
public class DelayQueueProofOfConceptTest
{
public static final int POISON_PILL = 3;
private static long offsetA = 53L;
private static long offsetB = 109L;
private static long offsetC = 150L;
private static long baseline = 0;
BlockingQueue<Pizza> pizzaQueue = new DelayQueue<Pizza>();
PizzaEaterRunnable pizzaEater = new PizzaEaterRunnable(pizzaQueue);
List<Long> expectedArrivalTimestamps = new ArrayList<Long>();
@Before
public void setup() throws java.lang.InterruptedException {
baseline = System.currentTimeMillis();
/**
* B A T C H # 1
*/
pizzaQueue.put( createTypeOne(baseline) ); expectedArrivalTimestamps.add( new Long(baseline+offsetA) );
pizzaQueue.put( createTypeOne(baseline) ); expectedArrivalTimestamps.add( new Long(baseline+offsetA) );
pizzaQueue.put( createTypeOne(baseline) ); expectedArrivalTimestamps.add( new Long(baseline+offsetA) );
pizzaQueue.put( createTypeOne(baseline) ); expectedArrivalTimestamps.add( new Long(baseline+offsetA) );
pizzaQueue.put( createTypeOne(baseline) ); expectedArrivalTimestamps.add( new Long(baseline+offsetA) );
/**
* B A T C H # 2
*/
pizzaQueue.put( createTypeTwo(baseline) ); expectedArrivalTimestamps.add( new Long(baseline+offsetB) );
pizzaQueue.put( createTypeTwo(baseline) ); expectedArrivalTimestamps.add( new Long(baseline+offsetB) );
pizzaQueue.put( createTypeTwo(baseline) ); expectedArrivalTimestamps.add( new Long(baseline+offsetB) );
/**
* B A T C H # 3
*/
pizzaQueue.put( createTypeThree(baseline) ); expectedArrivalTimestamps.add( new Long(baseline+offsetC) );
}
private Pizza createTypeOne(long baseline) {
Pizza newPizza = new Pizza( baseline + offsetA, 1 );
return newPizza;
}
private Pizza createTypeTwo(long baseline) {
Pizza newPizza = new Pizza( baseline + offsetB, 2 );
return newPizza;
}
private Pizza createTypeThree(long baseline) {
Pizza newPizza = new Pizza( baseline + offsetC, POISON_PILL );
return newPizza;
}
@Test
public void testDelayQueueBurst() {
try {
PizzaEaterRunnable eater = new PizzaEaterRunnable(pizzaQueue);//queue was filled in setup method
Thread t = new Thread(eater);
t.start();
//Time will elapse as DelayQueue emits
//a three bursts of pizzas from the queue, 1 second between each burst.
//The thread will finish when a 'poison pill' is detected by the thread.
t.join();
boolean compare = eater.arrivalTimestamps.equals(expectedArrivalTimestamps);
String actual = eater.arrivalTimestamps.toString();
String expected = expectedArrivalTimestamps.toString();
assertTrue("did not get expected arrival times. Expected [" + expected + "] Actual [" + actual + "]",compare);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
public static class Pizza implements Delayed {
private long departureTimestampMillis = 0L;
private int type = 0;
public Pizza(long val, int type) {
this.departureTimestampMillis = val;
this.type = type;
System.out.println("New Pizza [" + this.toString() + "]");
}
public String toString() {
return "Pizza {departureTimestampMillis=" + this.departureTimestampMillis + ",type=" + this.type + "}";
}
public int getType() {
return this.type;
}
@Override
public long getDelay(TimeUnit unit) {
long ts = System.currentTimeMillis();
//System.out.println("current [" + ts + "] " + this.toString()) ;
return this.departureTimestampMillis - ts;
}
@Override
public int compareTo(Delayed o) {
long rc = this.getDelay( TimeUnit.MILLISECONDS ) - o.getDelay( TimeUnit.MILLISECONDS );
return (int)rc;
}
}
class PizzaEaterRunnable implements Runnable {
private static final int batchSize = 1000000;//Only concerned with huge/horrible events, otherwise monitoring is required to tune batch size.
public List<Long> arrivalTimestamps = new ArrayList<Long>();
BlockingQueue<Pizza> pizzaQueue;
public volatile boolean stopRequested = false;
public PizzaEaterRunnable(BlockingQueue<Pizza> val) {
this.pizzaQueue = val;
}
private void eatMany(List<Pizza> manyPizzas) {
for(Pizza pizza : manyPizzas)
eat(pizza);
}
private void eat(Pizza pizza) {
arrivalTimestamps.add( new Long(System.currentTimeMillis()) );
if (pizza.getType() == DelayQueueProofOfConceptTest.POISON_PILL) {
this.stopRequested = true;
}
}
@Override
public void run() {
List<Pizza> manyPizzas = new ArrayList<Pizza>();
while (!stopRequested) {
try {
//System.out.println(Thread.currentThread().getName() + " eating up bread ");
Pizza pizza = pizzaQueue.poll(100, TimeUnit.MILLISECONDS);
if (pizza !=null) {
manyPizzas.add(pizza);
pizzaQueue.drainTo(manyPizzas,batchSize);
eatMany(manyPizzas);
manyPizzas.clear();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}

View File

@ -0,0 +1,222 @@
package org.intracetest.agent;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.List;
import org.intrace.shared.SerializationHelper;
import org.intrace.output.NetworkDataSenderThread.TraceEventForBatch;
import org.intrace.output.NetworkDataSenderThread;
import org.junit.Before;
import org.junit.Test;
public class SerializationTest {
String[] myData = { "foo", "bar" };
String sampleEvent = "[00:48:55.797]:[19]:org.hsqldb.jdbc.jdbcStatement:<init>: }~org.hsqldb.jdbc.jdbcStatement.<init>(Unknown Source),org.hsqldb.jdbc.jdbcConnection.createStatement(Unknown Source),org.apache.commons.dbcp.DelegatingConnection.createStatement(DelegatingConnection.java:257),org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.createStatement(PoolingDataSource.java:216),org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:389),org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:455),org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:463),org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:471),org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:476),org.springframework.jdbc.core.JdbcTemplate.queryForInt(JdbcTemplate.java:485),example.webapp.dao.JdbcEventDAO.countAll(JdbcEventDAO.java:64),sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method),sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57),sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43),java.lang.reflect.Method.invoke(Method.java:606),org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309),org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183),org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150),org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110),org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172),org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202),com.sun.proxy.$Proxy6.countAll(Unknown Source),example.webapp.servlet.HelloExecuteQuery.doGet(HelloExecuteQuery.java:25),javax.servlet.http.HttpServlet.service(HttpServlet.java:668),javax.servlet.http.HttpServlet.service(HttpServlet.java:770),org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:669),org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:455),org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137),org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:560),org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:231),org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1072),org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:382),org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193),org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1006),org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135),org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116),org.eclipse.jetty.server.Server.handle(Server.java:365),org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:485),org.eclipse.jetty.server.BlockingHttpConnection.handleRequest(BlockingHttpConnection.java:53),org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:926),org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:988),org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:635),org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:235),org.eclipse.jetty.server.BlockingHttpConnection.handle(BlockingHttpConnection.java:72),org.eclipse.jetty.server.bio.SocketConnector$ConnectorEndPoint.run(SocketConnector.java:264),org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608),org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543)";
@Before
public void setup() {
sampleEvents[0] = "[00:48:55.797]:[19]:org.hsqldb.jdbc.jdbcStatement:<init>: }~org.hsqldb.jdbc.jdbcStatement.<init>(Unknown Source),org.hsqldb.jdbc.jdbcConnection.createStatement(Unknown Source),org.apache.commons.dbcp.DelegatingConnection.createStatement(DelegatingConnection.java:257),org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.createStatement(PoolingDataSource.java:216),org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:389),org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:455),org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:463),org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:471),org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:476),org.springframework.jdbc.core.JdbcTemplate.queryForInt(JdbcTemplate.java:485),example.webapp.dao.JdbcEventDAO.countAll(JdbcEventDAO.java:64),sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method),sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57),sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43),java.lang.reflect.Method.invoke(Method.java:606),org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309),org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183),org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150),org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110),org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172),org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202),com.sun.proxy.$Proxy6.countAll(Unknown Source),example.webapp.servlet.HelloExecuteQuery.doGet(HelloExecuteQuery.java:25),javax.servlet.http.HttpServlet.service(HttpServlet.java:668),javax.servlet.http.HttpServlet.service(HttpServlet.java:770),org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:669),org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:455),org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137),org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:560),org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:231),org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1072),org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:382),org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193),org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1006),org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135),org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116),org.eclipse.jetty.server.Server.handle(Server.java:365),org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:485),org.eclipse.jetty.server.BlockingHttpConnection.handleRequest(BlockingHttpConnection.java:53),org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:926),org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:988),org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:635),org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:235),org.eclipse.jetty.server.BlockingHttpConnection.handle(BlockingHttpConnection.java:72),org.eclipse.jetty.server.bio.SocketConnector$ConnectorEndPoint.run(SocketConnector.java:264),org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608),org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543)";
sampleEvents[1] = "[00:48:55.797]:[19]:org.apache.commons.dbcp.DelegatingStatement:<init>: {:61";
sampleEvents[2] = "[00:48:55.797]:[19]:org.apache.commons.dbcp.DelegatingStatement:<init>: Arg (c): jdbc:hsqldb:mem:event, UserName=SA, HSQL Database Engine Driver";
sampleEvents[3] = "[00:48:55.797]:[19]:org.apache.commons.dbcp.DelegatingStatement:<init>: Arg (s): org.hsqldb.jdbc.jdbcStatement@2300de71";
sampleEvents[4] = "[00:48:55.798]:[19]:org.apache.commons.dbcp.DelegatingStatement:<init>: }:64~org.apache.commons.dbcp.DelegatingStatement.<init>(DelegatingStatement.java:64),org.apache.commons.dbcp.DelegatingConnection.createStatement(DelegatingConnection.java:257),org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.createStatement(PoolingDataSource.java:216),org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:389),org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:455),org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:463),org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:471),org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:476),org.springframework.jdbc.core.JdbcTemplate.queryForInt(JdbcTemplate.java:485),example.webapp.dao.JdbcEventDAO.countAll(JdbcEventDAO.java:64),sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method),sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57),sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43),java.lang.reflect.Method.invoke(Method.java:606),org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309),org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183),org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150),org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110),org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172),org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202),com.sun.proxy.$Proxy6.countAll(Unknown Source),example.webapp.servlet.HelloExecuteQuery.doGet(HelloExecuteQuery.java:25),javax.servlet.http.HttpServlet.service(HttpServlet.java:668),javax.servlet.http.HttpServlet.service(HttpServlet.java:770),org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:669),org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:455),org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137),org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:560),org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:231),org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1072),org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:382),org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193),org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1006),org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135),org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116),org.eclipse.jetty.server.Server.handle(Server.java:365),org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:485),org.eclipse.jetty.server.BlockingHttpConnection.handleRequest(BlockingHttpConnection.java:53),org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:926),org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:988),org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:635),org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:235),org.eclipse.jetty.server.BlockingHttpConnection.handle(BlockingHttpConnection.java:72),org.eclipse.jetty.server.bio.SocketConnector$ConnectorEndPoint.run(SocketConnector.java:264),org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608),org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543)";
sampleEvents[5] = "[00:48:55.798]:[19]:org.apache.commons.dbcp.DelegatingStatement:<init>: {:61";
sampleEvents[6] = "[00:48:55.798]:[19]:org.apache.commons.dbcp.DelegatingStatement:<init>: Arg (c): jdbc:hsqldb:mem:event, UserName=SA, HSQL Database Engine Driver";
sampleEvents[7] = "[00:48:55.799]:[19]:org.apache.commons.dbcp.DelegatingStatement:<init>: Arg (s): org.hsqldb.jdbc.jdbcStatement@2300de71";
sampleEvents[8] = "[00:48:55.799]:[19]:org.apache.commons.dbcp.DelegatingStatement:<init>: }:64~org.apache.commons.dbcp.DelegatingStatement.<init>(DelegatingStatement.java:64),org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.createStatement(PoolingDataSource.java:216),org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:389),org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:455),org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:463),org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:471),org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:476),org.springframework.jdbc.core.JdbcTemplate.queryForInt(JdbcTemplate.java:485),example.webapp.dao.JdbcEventDAO.countAll(JdbcEventDAO.java:64),sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method),sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57),sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43),java.lang.reflect.Method.invoke(Method.java:606),org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309),org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183),org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150),org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110),org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172),org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202),com.sun.proxy.$Proxy6.countAll(Unknown Source),example.webapp.servlet.HelloExecuteQuery.doGet(HelloExecuteQuery.java:25),javax.servlet.http.HttpServlet.service(HttpServlet.java:668),javax.servlet.http.HttpServlet.service(HttpServlet.java:770),org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:669),org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:455),org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137),org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:560),org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:231),org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1072),org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:382),org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193),org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1006),org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135),org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116),org.eclipse.jetty.server.Server.handle(Server.java:365),org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:485),org.eclipse.jetty.server.BlockingHttpConnection.handleRequest(BlockingHttpConnection.java:53),org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:926),org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:988),org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:635),org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:235),org.eclipse.jetty.server.BlockingHttpConnection.handle(BlockingHttpConnection.java:72),org.eclipse.jetty.server.bio.SocketConnector$ConnectorEndPoint.run(SocketConnector.java:264),org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608),org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543)";
sampleEvents[9] = "[00:48:55.799]:[19]:org.apache.commons.dbcp.DelegatingStatement:executeQuery: {:206";
}
@Test
public void canSerializeAndDeserializeEvents() throws IOException, ClassNotFoundException {
byte[] myBytes = SerializationHelper.toWire(this.myData);
assertEquals("Didn't find right size of data-on-the-wire.", 75, myBytes.length) ;
String[] surprise = SerializationHelper.fromWire(myBytes);
assertEquals("Could not find 1st element in deserialized array of strings","foo",surprise[0]);
assertEquals("Could not find 2nd element in deserialized array of strings","bar",surprise[1]);
}
/**
* These are typical times for serializing/compressing about 12mb of events
* on my 2.3Ghz i7 MacBook
* Serialize time [199]
* Deserialize time [171]
* @throws IOException
* @throws ClassNotFoundException
*/
@Test
public void canCalculateSizeOfDataSerializedAndCompressed() throws IOException, ClassNotFoundException {
List<String> myEvents = new ArrayList<String>();
int unCompressedByteCount = 0;
for(int i = 0; i < 10000;i++) {
long timestamp = System.currentTimeMillis();
Long longTimestamp = new Long(timestamp);
String tmp =
longTimestamp.toString() //Throw in some randomness, more realism for the compression algo.
+ sampleEvents [ i % 10 ]
+ Long.toHexString(2*timestamp) ;
unCompressedByteCount+=tmp.length(); //Throw in some randomness, more realism for the compression algo.
myEvents.add(tmp);
}
assertTrue("Did not find correct total size for 10k uncompressed strings ",unCompressedByteCount > 12000000 );
assertTrue("Did not find correct total size for 10k uncompressed strings ",unCompressedByteCount < 12500000 );
String[] myEventsArray;// = new String[myEvents.size()];
myEventsArray = myEvents.toArray(new String[0]);
assertEquals("Unable to create array from list", 10000,myEventsArray.length);
long start = System.currentTimeMillis();
byte[] myBytes = SerializationHelper.toWire(myEventsArray);
long finish = System.currentTimeMillis();
System.out.println("Serialize time [" + (finish-start) + "]");
assertTrue("Did not find correct size for String array compressed into a byte array",myBytes.length > 80000);
assertTrue("Did not find correct size for String array compressed into a byte array",myBytes.length < 90000);
start = System.currentTimeMillis();
String[] surprise = SerializationHelper.fromWire(myBytes);
finish = System.currentTimeMillis();
System.out.println("Deserialize time [" + (finish-start) + "]");
}
@Test
public void canSendOneBurstsOfEvents() throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream o = new ObjectOutputStream(baos);
List<TraceEventForBatch> events = new ArrayList<TraceEventForBatch>();
events.add( new TraceEventForBatch("foo",System.currentTimeMillis(), 1));
events.add( new TraceEventForBatch("bar",System.currentTimeMillis(), 2));
NetworkDataSenderThread sender = new NetworkDataSenderThread(null,null);
int numBursts = sender.transmitBatch( o, events, 10 );
assertEquals("Sent just two events with a larger burst size. should have sent exactly 1 burst.", 1, numBursts);
//o.close();
byte[] compressedObjects = baos.toByteArray() ;
assertTrue( "didn't find enough raw compressed data", compressedObjects.length > 4);//surely the data has to be bigger than 4 bytes, right?
ByteArrayInputStream bais = new ByteArrayInputStream(compressedObjects);
ObjectInputStream ois = new ObjectInputStream(bais);
Object objectFromWire = ois.readObject();
ois.close();
if (objectFromWire instanceof byte[]) {
byte[] freshFromWire = (byte[]) objectFromWire;
assertEquals("Didn't find size of byte array on wire", 75, freshFromWire.length);
String results[] = SerializationHelper.fromWire( freshFromWire );
assertEquals( "Didn't find right count of String in the array after sending bursts", 2, results.length );
assertEquals( "Couldn't receive multiple bursts with just two events", "foo", results[0] );
assertEquals( "Couldn't receive multiple bursts with just two events", "bar", results[1] );
} else {
fail("Didn't serialize right kind of object");
}
}
@Test
public void canSendThreeBurstsOfEvents() throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream o = new ObjectOutputStream(baos);
List<TraceEventForBatch> events = new ArrayList<TraceEventForBatch>();
events.add( new TraceEventForBatch("yankee",System.currentTimeMillis(), 1));
events.add( new TraceEventForBatch("doodle",System.currentTimeMillis(), 2));
events.add( new TraceEventForBatch("went",System.currentTimeMillis(), 2));
events.add( new TraceEventForBatch("to",System.currentTimeMillis(), 2));
events.add( new TraceEventForBatch("town", System.currentTimeMillis(), 2));
events.add( new TraceEventForBatch("riding",System.currentTimeMillis(), 2));
events.add( new TraceEventForBatch("on",System.currentTimeMillis(), 2));
events.add( new TraceEventForBatch("a",System.currentTimeMillis(), 2));
events.add( new TraceEventForBatch("pony",System.currentTimeMillis(), 2));
NetworkDataSenderThread sender = new NetworkDataSenderThread(null,null);
int numBursts = sender.transmitBatch( o, events, 3 );
assertEquals("Sent just 9 events with a burst size of 3. should have sent exactly 3 burst.", 3, numBursts);
//o.close();
byte[] compressedObjects = baos.toByteArray() ;
assertTrue( "didn't find enough raw compressed data", compressedObjects.length > 4);//surely the data has to be bigger than 4 bytes, right?
ByteArrayInputStream bais = new ByteArrayInputStream(compressedObjects);
ObjectInputStream ois = new ObjectInputStream(bais);
Object objectFromWire1 = ois.readObject();
Object objectFromWire2 = ois.readObject();
Object objectFromWire3 = ois.readObject();
ois.close();
if (objectFromWire1 instanceof byte[]) {
byte[] freshFromWire = (byte[]) objectFromWire1;
assertEquals("Didn't find size of byte array on wire", 87, freshFromWire.length);
String results[] = SerializationHelper.fromWire( freshFromWire );
assertEquals( "Didn't find right count of String in the array after sending bursts", 3, results.length );
assertEquals( "Couldn't receive multiple bursts with just 9 events", "yankee", results[0] );
assertEquals( "Couldn't receive multiple bursts with just 9 events", "doodle", results[1] );
assertEquals( "Couldn't receive multiple bursts with just 9 events", "went", results[2] );
} else {
fail("Didn't serialize right kind of object");
}
if (objectFromWire2 instanceof byte[]) {
byte[] freshFromWire = (byte[]) objectFromWire2;
assertEquals("Didn't find size of byte array on wire", 84, freshFromWire.length);
String results[] = SerializationHelper.fromWire( freshFromWire );
assertEquals( "Didn't find right count of String in the array for the 2nd burst", 3, results.length );
assertEquals( "Couldn't receive multiple bursts with just 9 events", "to", results[0] );
assertEquals( "Couldn't receive multiple bursts with just 9 events", "town", results[1] );
assertEquals( "Couldn't receive multiple bursts with just 9 events", "riding", results[2] );
} else {
fail("Didn't serialize right kind of object");
}
if (objectFromWire1 instanceof byte[]) {
byte[] freshFromWire = (byte[]) objectFromWire3;
assertEquals("Didn't find size of byte array on wire", 80, freshFromWire.length);
String results[] = SerializationHelper.fromWire( freshFromWire );
assertEquals( "Didn't find right count of String in the array for the 3rd burst", 3, results.length );
assertEquals( "Couldn't receive multiple bursts with just 9 events", "on", results[0] );
assertEquals( "Couldn't receive multiple bursts with just 9 events", "a", results[1] );
assertEquals( "Couldn't receive multiple bursts with just 9 events", "pony", results[2] );
} else {
fail("Didn't serialize right kind of object");
}
}
private String[] sampleEvents = new String[10];
}