/*******************************************************************************
- * Copyright (c) 2012 Ericsson
+ * Copyright (c) 2012, 2013 Ericsson
* Copyright (c) 2010, 2011 École Polytechnique de Montréal
* Copyright (c) 2010, 2011 Alexandre Montplaisir <alexandre.montplaisir@gmail.com>
*
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
-import org.eclipse.linuxtools.internal.tmf.core.Tracer;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.linuxtools.internal.tmf.core.Activator;
+import org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.IStateHistoryBackend;
import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException;
+import org.eclipse.linuxtools.tmf.core.exceptions.StateSystemDisposedException;
import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException;
import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval;
import org.eclipse.linuxtools.tmf.core.interval.TmfStateInterval;
-import org.eclipse.linuxtools.tmf.core.statesystem.IStateSystemBuilder;
-import org.eclipse.linuxtools.tmf.core.statesystem.IStateSystemQuerier2;
+import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystemBuilder;
import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue;
+import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue.Type;
import org.eclipse.linuxtools.tmf.core.statevalue.TmfStateValue;
/**
* @author alexmont
*
*/
-public class StateSystem implements IStateSystemBuilder, IStateSystemQuerier2{
+public class StateSystem implements ITmfStateSystemBuilder {
/* References to the inner structures */
private final AttributeTree attributeTree;
private final TransientState transState;
private final IStateHistoryBackend backend;
+ /* Latch tracking if the state history is done building or not */
+ private final CountDownLatch finishedLatch = new CountDownLatch(1);
+
+ private boolean buildCancelled = false;
+ private boolean isDisposed = false;
+
+ /**
+ * New-file constructor. For when you build a state system with a new file,
+ * or if the back-end does not require a file on disk.
+ *
+ * @param backend
+ * Back-end plugin to use
+ */
+ public StateSystem(@NonNull IStateHistoryBackend backend) {
+ this.backend = backend;
+ this.transState = new TransientState(backend);
+ this.attributeTree = new AttributeTree(this);
+ }
+
/**
* General constructor
*
* @param backend
- * The "state history storage" backend to use.
+ * The "state history storage" back-end to use.
* @param newFile
* Put true if this is a new history started from scratch. It is
* used to tell the state system where to get its attribute tree.
* @throws IOException
* If there was a problem creating the new history file
*/
- public StateSystem(IStateHistoryBackend backend, boolean newFile)
+ public StateSystem(@NonNull IStateHistoryBackend backend, boolean newFile)
throws IOException {
this.backend = backend;
this.transState = new TransientState(backend);
/* We're opening an existing file */
this.attributeTree = new AttributeTree(this, backend.supplyAttributeTreeReader());
transState.setInactive();
+ finishedLatch.countDown(); /* The history is already built */
}
}
+ @Override
+ public boolean isCancelled() {
+ return buildCancelled;
+ }
+
+ @Override
+ public void waitUntilBuilt() {
+ try {
+ finishedLatch.await();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public boolean waitUntilBuilt(long timeout) {
+ boolean ret = false;
+ try {
+ ret = finishedLatch.await(timeout, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ return ret;
+ }
+
+ @Override
+ public synchronized void dispose() {
+ isDisposed = true;
+ if (transState.isActive()) {
+ transState.setInactive();
+ buildCancelled = true;
+ }
+ backend.dispose();
+ }
+
//--------------------------------------------------------------------------
// General methods related to the attribute tree
//--------------------------------------------------------------------------
+ /**
+ * Get the attribute tree associated with this state system. This should be
+ * the only way of accessing it (and if subclasses want to point to a
+ * different attribute tree than their own, they should only need to
+ * override this).
+ *
+ * @return The attribute tree
+ */
+ public AttributeTree getAttributeTree() {
+ return attributeTree;
+ }
+
/**
* Method used by the attribute tree when creating new attributes, to keep
* the attribute count in the transient state in sync.
*/
- void addEmptyAttribute() {
+ protected void addEmptyAttribute() {
transState.addEmptyEntry();
}
@Override
public int getNbAttributes() {
- return attributeTree.getNbAttributes();
+ return getAttributeTree().getNbAttributes();
}
@Override
public String getAttributeName(int attributeQuark) {
- return attributeTree.getAttributeName(attributeQuark);
+ return getAttributeTree().getAttributeName(attributeQuark);
}
@Override
public String getFullAttributePath(int attributeQuark) {
- return attributeTree.getFullAttributeName(attributeQuark);
+ return getAttributeTree().getFullAttributeName(attributeQuark);
}
//--------------------------------------------------------------------------
* If null was returned, we simply won't save the attribute tree,
* too bad!
*/
- attributeTree.writeSelf(attributeTreeFile, attributeTreeFilePos);
+ getAttributeTree().writeSelf(attributeTreeFile, attributeTreeFilePos);
}
+ finishedLatch.countDown(); /* Mark the history as finished building */
}
//--------------------------------------------------------------------------
@Override
public int getQuarkAbsolute(String... attribute)
throws AttributeNotFoundException {
- return attributeTree.getQuarkDontAdd(-1, attribute);
+ return getAttributeTree().getQuarkDontAdd(-1, attribute);
}
@Override
public int getQuarkAbsoluteAndAdd(String... attribute) {
- return attributeTree.getQuarkAndAdd(-1, attribute);
+ return getAttributeTree().getQuarkAndAdd(-1, attribute);
}
@Override
public int getQuarkRelative(int startingNodeQuark, String... subPath)
throws AttributeNotFoundException {
- return attributeTree.getQuarkDontAdd(startingNodeQuark, subPath);
+ return getAttributeTree().getQuarkDontAdd(startingNodeQuark, subPath);
}
@Override
public int getQuarkRelativeAndAdd(int startingNodeQuark, String... subPath) {
- return attributeTree.getQuarkAndAdd(startingNodeQuark, subPath);
+ return getAttributeTree().getQuarkAndAdd(startingNodeQuark, subPath);
}
@Override
public List<Integer> getSubAttributes(int quark, boolean recursive)
throws AttributeNotFoundException {
- return attributeTree.getSubAttributes(quark, recursive);
+ return getAttributeTree().getSubAttributes(quark, recursive);
}
@Override
public List<Integer> getQuarks(String... pattern) {
- List<Integer> quarks = new LinkedList<Integer>();
- List<String> prefix = new LinkedList<String>();
- List<String> suffix = new LinkedList<String>();
+ List<Integer> quarks = new LinkedList<>();
+ List<String> prefix = new LinkedList<>();
+ List<String> suffix = new LinkedList<>();
boolean split = false;
String[] prefixStr;
String[] suffixStr;
* If there was no wildcard, we'll only return the one matching
* attribute, if there is one.
*/
- if (split == false) {
+ if (!split) {
int quark;
try {
quark = getQuarkAbsolute(prefixStr);
} else {
startingAttribute = getQuarkAbsolute(prefixStr);
}
- directChildren = attributeTree.getSubAttributes(startingAttribute,
- false);
+ directChildren = getSubAttributes(startingAttribute, false);
} catch (AttributeNotFoundException e) {
/* That attribute path did not exist, return the empty array */
return quarks;
public void incrementAttribute(long t, int attributeQuark)
throws StateValueTypeException, TimeRangeException,
AttributeNotFoundException {
- int prevValue = queryOngoingState(attributeQuark).unboxInt();
- if (prevValue == -1) {
- /* if the attribute was previously null, start counting at 0 */
- prevValue = 0;
+ ITmfStateValue stateValue = queryOngoingState(attributeQuark);
+ int prevValue = 0;
+ /* if the attribute was previously null, start counting at 0 */
+ if (!stateValue.isNull()) {
+ prevValue = stateValue.unboxInt();
}
modifyAttribute(t, TmfStateValue.newValueInt(prevValue + 1),
attributeQuark);
public void pushAttribute(long t, ITmfStateValue value, int attributeQuark)
throws TimeRangeException, AttributeNotFoundException,
StateValueTypeException {
- Integer stackDepth = 0;
+ Integer stackDepth;
int subAttributeQuark;
ITmfStateValue previousSV = transState.getOngoingStateValue(attributeQuark);
* If the StateValue was null, this means this is the first time we
* use this attribute. Leave stackDepth at 0.
*/
- } else if (previousSV.getType() == 0) {
+ stackDepth = 0;
+ } else if (previousSV.getType() == Type.INTEGER) {
/* Previous value was an integer, all is good, use it */
stackDepth = previousSV.unboxInt();
} else {
throw new StateValueTypeException();
}
- if (stackDepth >= 10) {
+ if (stackDepth >= 100000) {
/*
- * Limit stackDepth to 10, to avoid having Attribute Trees grow out
+ * Limit stackDepth to 100000, to avoid having Attribute Trees grow out
* of control due to buggy insertions
*/
String message = "Stack limit reached, not pushing"; //$NON-NLS-1$
}
stackDepth++;
- subAttributeQuark = getQuarkRelativeAndAdd(attributeQuark,
- stackDepth.toString());
+ subAttributeQuark = getQuarkRelativeAndAdd(attributeQuark, stackDepth.toString());
- modifyAttribute(t, TmfStateValue.newValueInt(stackDepth),
- attributeQuark);
+ modifyAttribute(t, TmfStateValue.newValueInt(stackDepth), attributeQuark);
modifyAttribute(t, value, subAttributeQuark);
}
@Override
- public void popAttribute(long t, int attributeQuark)
+ public ITmfStateValue popAttribute(long t, int attributeQuark)
throws AttributeNotFoundException, TimeRangeException,
StateValueTypeException {
- Integer stackDepth;
- int subAttributeQuark;
- ITmfStateValue previousSV = transState.getOngoingStateValue(attributeQuark);
+ /* These are the state values of the stack-attribute itself */
+ ITmfStateValue previousSV = queryOngoingState(attributeQuark);
if (previousSV.isNull()) {
- /* Same as if stackDepth == 0, see below */
- return;
- }
- if (previousSV.getType() != 0) {
- /*
- * The existing value was a string, this doesn't look like a valid
- * stack attribute.
- */
- throw new StateValueTypeException();
- }
-
- stackDepth = previousSV.unboxInt();
-
- if (stackDepth == 0) {
/*
* Trying to pop an empty stack. This often happens at the start of
* traces, for example when we see a syscall_exit, without having
* the corresponding syscall_entry in the trace. Just ignore
* silently.
*/
- return;
+ return null;
}
+ if (previousSV.getType() != Type.INTEGER) {
+ /*
+ * The existing value was not an integer (which is expected for
+ * stack tops), this doesn't look like a valid stack attribute.
+ */
+ throw new StateValueTypeException();
+ }
+
+ Integer stackDepth = previousSV.unboxInt();
- if (stackDepth < 0) {
+ if (stackDepth <= 0) {
/* This on the other hand should not happen... */
- String message = "A top-level stack attribute " + //$NON-NLS-1$
- "cannot have a negative integer value."; //$NON-NLS-1$
+ String message = "A top-level stack attribute cannot " + //$NON-NLS-1$
+ "have a value of 0 or less."; //$NON-NLS-1$
throw new StateValueTypeException(message);
}
- /* The attribute should already exist... */
- subAttributeQuark = getQuarkRelative(attributeQuark,
- stackDepth.toString());
+ /* The attribute should already exist at this point */
+ int subAttributeQuark = getQuarkRelative(attributeQuark, stackDepth.toString());
+ ITmfStateValue poppedValue = queryOngoingState(subAttributeQuark);
- stackDepth--;
- modifyAttribute(t, TmfStateValue.newValueInt(stackDepth),
- attributeQuark);
+ /* Update the state value of the stack-attribute */
+ ITmfStateValue nextSV;
+ if (--stackDepth == 0 ) {
+ /* Store a null state value */
+ nextSV = TmfStateValue.nullValue();
+ } else {
+ nextSV = TmfStateValue.newValueInt(stackDepth);
+ }
+ modifyAttribute(t, nextSV, attributeQuark);
+
+ /* Delete the sub-attribute that contained the user's state value */
removeAttribute(t, subAttributeQuark);
+
+ return poppedValue;
}
@Override
* "Nullify our children first, recursively. We pass 'false' because we
* handle the recursion ourselves.
*/
- childAttributes = attributeTree.getSubAttributes(attributeQuark, false);
+ childAttributes = getSubAttributes(attributeQuark, false);
for (Integer childNodeQuark : childAttributes) {
assert (attributeQuark != childNodeQuark);
removeAttribute(t, childNodeQuark);
* Will not happen since we're inserting null values only, but poor
* compiler has no way of knowing this...
*/
- e.printStackTrace();
+ throw new IllegalStateException(e);
}
}
return transState.getOngoingStateValue(attributeQuark);
}
+ @Override
+ public long getOngoingStartTime(int attribute)
+ throws AttributeNotFoundException {
+ return transState.getOngoingStartTime(attribute);
+ }
+
@Override
public void updateOngoingState(ITmfStateValue newValue, int attributeQuark)
throws AttributeNotFoundException {
transState.changeOngoingStateValue(attributeQuark, newValue);
}
-
+ /**
+ * Modify the whole "ongoing state" (state values + start times). This can
+ * be used when "seeking" a state system to a different point in the trace
+ * (and restoring the known stateInfo at this location). Use with care!
+ *
+ * @param newStateIntervals
+ * The new List of state values to use as ongoing state info
+ */
+ protected void replaceOngoingState(List<ITmfStateInterval> newStateIntervals) {
+ transState.replaceOngoingState(newStateIntervals);
+ }
//--------------------------------------------------------------------------
// Regular query methods (sent to the back-end)
@Override
public synchronized List<ITmfStateInterval> queryFullState(long t)
- throws TimeRangeException {
- List<ITmfStateInterval> stateInfo = new ArrayList<ITmfStateInterval>(
- attributeTree.getNbAttributes());
+ throws TimeRangeException, StateSystemDisposedException {
+ if (isDisposed) {
+ throw new StateSystemDisposedException();
+ }
+
+ List<ITmfStateInterval> stateInfo = new ArrayList<>(getNbAttributes());
/* Bring the size of the array to the current number of attributes */
- for (int i = 0; i < attributeTree.getNbAttributes(); i++) {
+ for (int i = 0; i < getNbAttributes(); i++) {
stateInfo.add(null);
}
*/
for (int i = 0; i < stateInfo.size(); i++) {
if (stateInfo.get(i) == null) {
- //logMissingInterval(i, t);
stateInfo.set(i, new TmfStateInterval(t, t, i, TmfStateValue.nullValue()));
}
}
@Override
public ITmfStateInterval querySingleState(long t, int attributeQuark)
- throws AttributeNotFoundException, TimeRangeException {
- ITmfStateInterval ret;
+ throws AttributeNotFoundException, TimeRangeException,
+ StateSystemDisposedException {
+ if (isDisposed) {
+ throw new StateSystemDisposedException();
+ }
- if (transState.hasInfoAboutStateOf(t, attributeQuark)) {
- ret = transState.getOngoingInterval(attributeQuark);
- } else {
+ ITmfStateInterval ret = transState.getIntervalAt(t, attributeQuark);
+ if (ret == null) {
+ /*
+ * The transient state did not have the information, let's look into
+ * the backend next.
+ */
ret = backend.doSingularQuery(t, attributeQuark);
}
* We do NOT want to return 'null' here.
*/
if (ret == null) {
- //logMissingInterval(attributeQuark, t);
return new TmfStateInterval(t, this.getCurrentEndTime(),
attributeQuark, TmfStateValue.nullValue());
}
return ret;
}
+ @Override
+ public ITmfStateInterval querySingleStackTop(long t, int stackAttributeQuark)
+ throws StateValueTypeException, AttributeNotFoundException,
+ TimeRangeException, StateSystemDisposedException {
+ ITmfStateValue curStackStateValue = querySingleState(t, stackAttributeQuark).getStateValue();
+
+ if (curStackStateValue.isNull()) {
+ /* There is nothing stored in this stack at this moment */
+ return null;
+ }
+ Integer curStackDepth = curStackStateValue.unboxInt();
+ if (curStackDepth <= 0) {
+ /*
+ * This attribute is an integer attribute, but it doesn't seem like
+ * it's used as a stack-attribute...
+ */
+ throw new StateValueTypeException();
+ }
+
+ int subAttribQuark = getQuarkRelative(stackAttributeQuark, curStackDepth.toString());
+ return querySingleState(t, subAttribQuark);
+ }
+
@Override
public List<ITmfStateInterval> queryHistoryRange(int attributeQuark,
long t1, long t2) throws TimeRangeException,
- AttributeNotFoundException {
+ AttributeNotFoundException, StateSystemDisposedException {
+ if (isDisposed) {
+ throw new StateSystemDisposedException();
+ }
+
List<ITmfStateInterval> intervals;
ITmfStateInterval currentInterval;
long ts, tEnd;
/* Make sure the time range makes sense */
- if (t2 <= t1) {
+ if (t2 < t1) {
throw new TimeRangeException();
}
}
/* Get the initial state at time T1 */
- intervals = new ArrayList<ITmfStateInterval>();
+ intervals = new ArrayList<>();
currentInterval = querySingleState(t1, attributeQuark);
intervals.add(currentInterval);
@Override
public List<ITmfStateInterval> queryHistoryRange(int attributeQuark,
- long t1, long t2, long resolution) throws TimeRangeException,
- AttributeNotFoundException {
- return queryHistoryRange(attributeQuark, t1, t2, resolution, new NullProgressMonitor());
- }
+ long t1, long t2, long resolution, IProgressMonitor monitor)
+ throws TimeRangeException, AttributeNotFoundException,
+ StateSystemDisposedException {
+ if (isDisposed) {
+ throw new StateSystemDisposedException();
+ }
- @Override
- public List<ITmfStateInterval> queryHistoryRange(int attributeQuark,
- long t1, long t2, long resolution, IProgressMonitor monitor) throws TimeRangeException,
- AttributeNotFoundException {
List<ITmfStateInterval> intervals;
ITmfStateInterval currentInterval;
long ts, tEnd;
+ IProgressMonitor mon = monitor;
+ if (mon == null) {
+ mon = new NullProgressMonitor();
+ }
+
/* Make sure the time range makes sense */
if (t2 < t1 || resolution <= 0) {
throw new TimeRangeException();
}
/* Get the initial state at time T1 */
- intervals = new ArrayList<ITmfStateInterval>();
+ intervals = new ArrayList<>();
currentInterval = querySingleState(t1, attributeQuark);
intervals.add(currentInterval);
*/
for (ts = t1; (currentInterval.getEndTime() != -1) && (ts < tEnd);
ts += resolution) {
- if (monitor.isCanceled()) {
+ if (mon.isCanceled()) {
return intervals;
}
if (ts <= currentInterval.getEndTime()) {
//--------------------------------------------------------------------------
static void logMissingInterval(int attribute, long timestamp) {
- Tracer.traceInfo("No data found in history for attribute " + //$NON-NLS-1$
+ Activator.logInfo("No data found in history for attribute " + //$NON-NLS-1$
attribute + " at time " + timestamp + //$NON-NLS-1$
", returning dummy interval"); //$NON-NLS-1$
}
* The PrintWriter in which to print the output
*/
public void debugPrint(PrintWriter writer) {
- attributeTree.debugPrint(writer);
+ getAttributeTree().debugPrint(writer);
transState.debugPrint(writer);
backend.debugPrint(writer);
}