package org.jactr.eclipse.runtime.playback.internal;
/*
* default logging
*/
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.zip.GZIPInputStream;
import javolution.util.FastList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.jactr.eclipse.core.concurrent.QueueingJob;
import org.jactr.eclipse.runtime.RuntimePlugin;
import org.jactr.eclipse.runtime.debug.elements.ACTRDebugElement;
import org.jactr.eclipse.runtime.preferences.RuntimePreferences;
import org.jactr.eclipse.runtime.session.ISession;
import org.jactr.eclipse.runtime.trace.RuntimeTraceManager;
import org.jactr.tools.tracer.transformer.ITransformedEvent;
public class EventPumper extends QueueingJob
{
/**
* Logger definition
*/
static private final transient Log LOGGER = LogFactory
.getLog(EventPumper.class);
private final List<ArchivalIndex.Index> _queue;
private ISession _session;
private ArchiveController _controller;
private volatile boolean _isFree = true;
private double _maximumEventWindow = 60; // sec
public EventPumper(String name, ISession session)
{
super(name);
_session = session;
_queue = new ArrayList<ArchivalIndex.Index>();
}
public void setController(ArchiveController controller)
{
_controller = controller;
}
public void pump(ArchivalIndex.Index dataFile)
{
synchronized (_queue)
{
_queue.add(dataFile);
_isFree = false;
}
queue(150);
}
public boolean isFree()
{
synchronized (_queue)
{
return _isFree;
}
}
@Override
protected IStatus run(IProgressMonitor monitor)
{
/*
* collect the records
*/
FastList<ArchivalIndex.Index> toLoad = FastList.newInstance();
synchronized (_queue)
{
if (_queue.size() == 0) return Status.OK_STATUS;
double endOfThisEventWindow = _queue.get(0)._span[0]
+ _maximumEventWindow;
ListIterator<ArchivalIndex.Index> itr = _queue.listIterator();
while (itr.hasNext())
{
ArchivalIndex.Index index = itr.next();
if (index._span[0] < endOfThisEventWindow)
{
toLoad.add(index);
itr.remove();
}
else
break;
}
}
int blockSize = RuntimePlugin.getDefault().getPreferenceStore()
.getInt(RuntimePreferences.PLAYBACK_BLOCKSIZE);
processIndices(new SubProgressMonitor(monitor, toLoad.size()), toLoad,
blockSize);
FastList.recycle(toLoad);
synchronized (_queue)
{
_isFree = _queue.size() == 0;
}
if (isFree())
ACTRDebugElement.fireSuspendEvent(_session, 0);
else
schedule();
return Status.OK_STATUS;
}
// private void pumpRecord(IProgressMonitor monitor, ArchivalIndex.Index
// record,
// Collection<ITransformedEvent> events) throws IOException
// {
// File fp = new File(record._data.getRawLocationURI());
// FileInputStream fis = null;
//
// if (LOGGER.isDebugEnabled())
// LOGGER.debug(String.format("Pumping [%.2f, %.2f] %s", record._span[0],
// record._span[1], record._data));
//
// double lastEventTime = 0;
// try
// {
// fis = new FileInputStream(fp);
// GZIPInputStream giz = new GZIPInputStream(fis);
// ObjectInputStream ois = new ObjectInputStream(giz);
//
// ois.readDouble();
// ois.readDouble();
//
// // while (ois.available() > 0)
// boolean done = false;
// while (!done && !monitor.isCanceled() && _session.isOpen())
// try
// {
// ITransformedEvent ite = (ITransformedEvent) ois.readObject();
// double eventTime = ite.getSimulationTime();
//
// lastEventTime = eventTime;
// if (record._span[0] <= eventTime && eventTime < record._span[1])
// events.add(ite);
// else
// {
// if (LOGGER.isDebugEnabled())
// LOGGER.debug(String.format(
// "%s (%.2f) outside of range to pump (%.2f, %.2f)", ite
// .getClass().getName(), eventTime, record._span[0],
// record._span[1]));
//
// done = eventTime >= record._span[1];
// }
// }
// catch (EOFException e)
// {
// done = true;
// }
// catch (IOException e)
// {
// if (LOGGER.isWarnEnabled())
// LOGGER.warn(String.format("IOException @ %.2f (%.2f, %.2f) [%s]",
// lastEventTime, record._span[0], record._span[1], record._data),
// e);
// done = true;
// }
// catch (Exception e)
// {
// LOGGER.error("failed to read record ", e);
// }
//
// if (events.size() == 0)
// if (LOGGER.isWarnEnabled())
// LOGGER.warn(String.format(
// "Was unable to pump any events for (%.2f, %.2f): %s",
// record._span[0], record._span[1], record._data));
// }
// finally
// {
// if (fis != null) fis.close();
// }
// }
protected void processIndices(IProgressMonitor monitor,
List<ArchivalIndex.Index> indices, int eventBlockSize)
{
IResource currentResource = null;
ObjectInputStream inputStream = null;
monitor.beginTask(String.format("Loading %d indices", indices.size()),
indices.size());
try
{
for (ArchivalIndex.Index index : indices)
{
if (monitor.isCanceled()) break;
/*
* file & stream management so we only open any one file, once
*/
if (!index._data.equals(currentResource))
{
if (currentResource != null) try
{
inputStream.close();
}
catch (Exception e)
{
LOGGER.error("failed to close ", e);
}
finally
{
inputStream = null;
}
/*
* open
*/
currentResource = index._data;
try
{
FileInputStream fis = new FileInputStream(new File(
currentResource.getRawLocationURI()));
GZIPInputStream giz = new GZIPInputStream(fis);
inputStream = new ObjectInputStream(giz);
// range header
inputStream.readDouble();
inputStream.readDouble();
}
catch (Exception e)
{
LOGGER.error("failed to open ", e);
currentResource = null;
inputStream = null;
}
}
// end stream management
if (inputStream != null) try
{
pumpRecords(monitor, index, eventBlockSize, inputStream);
monitor.worked(1);
}
catch (Exception e)
{
RuntimePlugin.error("Failed to pump all records", e);
}
}
}
finally
{
monitor.done();
// final clean up
if (inputStream != null) try
{
inputStream.close();
}
catch (Exception e)
{
}
}
}
protected void pumpRecords(IProgressMonitor monitor,
ArchivalIndex.Index index, int eventBlockSize,
ObjectInputStream inputStream) throws IOException
{
RuntimeTraceManager rtm = RuntimePlugin.getDefault()
.getRuntimeTraceManager();
FastList<ITransformedEvent> events = FastList.newInstance();
boolean done = false;
long startTime = System.currentTimeMillis();
int desiredRate = RuntimePlugin.getDefault().getPreferenceStore()
.getInt(RuntimePreferences.PLAYBACK_RATE);
try
{
double lastKnownTime = 0;
while (!done && !monitor.isCanceled() && _session.isOpen())
{
/*
* read in eventBlockSize events
*/
try
{
ITransformedEvent ite = (ITransformedEvent) inputStream.readObject();
double eventTime = ite.getSimulationTime();
lastKnownTime = eventTime;
if (index._span[0] <= eventTime && eventTime < index._span[1])
events.add(ite);
// RuntimePlugin.info(String.format("read & added %s %.4f", ite
// .getClass().getSimpleName(), ite.getSimulationTime()));
else
{
if (LOGGER.isDebugEnabled())
LOGGER.debug(String.format(
"%s (%.2f) outside of range to pump (%.2f, %.2f)", ite
.getClass().getName(), eventTime, index._span[0],
index._span[1]));
done = eventTime >= index._span[1];
// RuntimePlugin.info(String.format(
// "read & skipped %s %.4f (done:%s)", ite.getClass()
// .getSimpleName(), ite.getSimulationTime(), done));
}
}
catch (EOFException e)
{
done = true;
}
catch (ClassNotFoundException e)
{
LOGGER.error("failed to read record ", e);
}
/*
* fire them off!
*/
if (events.size() >= eventBlockSize || done)
try
{
SubProgressMonitor pm = new SubProgressMonitor(monitor,
events.size());
// RuntimePlugin.info(String.format("firing %d events @ %.4f",
// events.size(), lastKnownTime));
if (LOGGER.isDebugEnabled())
LOGGER.debug(String.format("Firing %d events", events.size()));
pm.beginTask("Propogating Events", events.size());
rtm.fireEvents(pm, events, _session);
pm.done();
if (events.size() > 0) _controller.setCurrentTime(lastKnownTime);
}
catch (Exception e)
{
events.clear();
RuntimePlugin.error(String.format("failed firing %d events @ %.4f",
events.size(), lastKnownTime), e);
}
finally
{
try
{
/*
* this is all wrong and must be fixed we should put the padding
* between events
*/
long actualDelta = System.currentTimeMillis() - startTime;
long targetDelta = (long) ((double) events.size()
/ (double) desiredRate * 1000d);
long sleepTime = targetDelta - actualDelta;
if (LOGGER.isDebugEnabled())
LOGGER.debug(String.format(
"actual %d/%d | target %d/%d sleepTime %d", events.size(),
actualDelta, events.size(), targetDelta, sleepTime));
events.clear();
// RuntimePlugin.info(String.format("cleared events"));
if (sleepTime > 0)
try
{
if (LOGGER.isDebugEnabled())
LOGGER.debug(String.format("Sleeping %d ms", sleepTime));
// RuntimePlugin.info(String.format("sleeping %d",
// sleepTime));
Thread.sleep(sleepTime);
}
catch (InterruptedException e)
{
}
startTime = System.currentTimeMillis();
}
catch (Exception e2)
{
LOGGER.error("Oops in sleep! ", e2);
}
}
// else
// /*
// * not ready to flush
// */
// RuntimePlugin.info(String.format("not ready to flush events (%d) (done:%s) @ %.4f",
// events.size(), done, lastKnownTime));
}
}
finally
{
FastList.recycle(events);
}
}
}