package org.jactr.eclipse.runtime.playback.internal; /* * default logging */ import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.SortedMap; import java.util.TreeMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.core.resources.IResource; public class ArchivalIndex { /** * Logger definition */ static private final transient Log LOGGER = LogFactory .getLog(ArchivalIndex.class); final private IResource _indexFile; final private TreeMap<Double, Index> _timeIndex; private double _readRecordRange; final private double[] _span = { Double.MAX_VALUE, Double.MIN_VALUE }; public ArchivalIndex(IResource resource) { _indexFile = resource; _timeIndex = new TreeMap<Double, Index>(); } public IResource getIndexFile() { return _indexFile; } public void open() { read(_indexFile); } public void close() { _timeIndex.clear(); } /** * pump out all the events from startTime to endTime. * * @param startTime * @param endTime * @param pumper */ public void pump(double startTime, double endTime, EventPumper pumper) { double min = Math.max(startTime, _span[0]); double max = Math.min(endTime, _span[1]); if (LOGGER.isDebugEnabled()) LOGGER.debug(String.format("Will pump %.2f-%.2f (%.2f, %.2f)", startTime, endTime, min, max)); /* * determine which time blocks will be needed, then pump the relevant * subsections and full blocks. */ SortedMap<Double, Index> subset = _timeIndex.tailMap(min); if (subset.size() == 0) { if (LOGGER.isDebugEnabled()) LOGGER.debug(String.format("No data available to pump")); return; } /* * we need to grow the range */ if (min < subset.firstKey()) subset = _timeIndex.tailMap(min - _readRecordRange); if (LOGGER.isDebugEnabled()) LOGGER.debug(String.format("tailSubset : %s", subset.keySet())); /* * constraining at the max end doesn't quite work. Let's say you've pumped * events up to 5s. But there is a large cycle skip from 5-100s. Any pump * request in that range will be ignored by this constraint. We need to go * the the next key. Instead we want the next larger end time. */ Double nextHigherKey = _timeIndex.ceilingKey(max + _readRecordRange / 2); if (nextHigherKey != null) { nextHigherKey += 0.05; subset = subset.headMap(nextHigherKey); max = nextHigherKey; } if (LOGGER.isDebugEnabled()) LOGGER.debug(String.format("headSubset : %s", subset.keySet())); for (Index index : subset.values()) { Index idx = new Index(); idx._span = new double[2]; idx._span[0] = Math.max(min, index._span[0]); idx._span[1] = Math.min(max, index._span[1]); if (idx._span[0] > idx._span[1]) { if (LOGGER.isDebugEnabled()) LOGGER.debug(String.format("Span invert?")); continue; } idx._data = index._data; if (LOGGER.isDebugEnabled()) LOGGER.debug(String.format("Pumping [%.2f, %.2f) %s", idx._span[0], idx._span[1], idx._data.getLocationURI())); pumper.pump(idx); } } public double getStartTime() { return _span[0]; } public double getEndTime() { return _span[1]; } private boolean read(IResource index) { File fp = new File(index.getRawLocationURI()); FileInputStream fis = null; try { fis = new FileInputStream(fp); // GZIPInputStream giz = new GZIPInputStream(fis); DataInputStream dis = new DataInputStream(fis); while (dis.available() > 0) { double[] range = new double[2]; for (int i = 0; i < range.length; i++) range[i] = dis.readDouble(); Index record = new Index(); record._span = range; _readRecordRange = range[1] - range[0]; String path = dis.readUTF(); record._data = index.getParent().findMember(path); _timeIndex.put(range[0], record); _span[0] = Math.min(_span[0], range[0]); _span[1] = Math.max(_span[1], range[1]); if (LOGGER.isDebugEnabled()) LOGGER.debug(String.format("read [%.2f, %.2f] %s", range[0], range[1], record._data)); } return true; } catch (Exception e) { LOGGER.error("Failed to read index ", e); return false; } finally { if (fis != null) try { fis.close(); } catch (IOException e1) { LOGGER.error("ArchivalIndex.read threw IOException : ", e1); } } } public class Index { public double[] _span; public IResource _data; } }