lttng: Support live updating of Control Flow view and Resources view
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / internal / tmf / core / statesystem / StateSystem.java
index c783eb40554089919ab72893f0ffb92faeb1032c..ecba187de8ab85d725a11b22d290780690cefc59 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * 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>
  *
@@ -18,17 +18,23 @@ import java.io.PrintWriter;
 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.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;
 
 /**
@@ -44,25 +50,44 @@ import org.eclipse.linuxtools.tmf.core.statevalue.TmfStateValue;
  * @author alexmont
  *
  */
-public class StateSystem implements IStateSystemBuilder {
+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);
@@ -73,39 +98,82 @@ public class StateSystem implements IStateSystemBuilder {
             /* 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();
-    }
-
-    @Override
-    public boolean isLastAttribute(int quark) {
-        return (quark == getNbAttributes() - 1) ? true : false;
+        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);
     }
 
     //--------------------------------------------------------------------------
@@ -145,8 +213,9 @@ public class StateSystem implements IStateSystemBuilder {
              * 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 */
     }
 
     //--------------------------------------------------------------------------
@@ -156,36 +225,36 @@ public class StateSystem implements IStateSystemBuilder {
     @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;
@@ -220,7 +289,7 @@ public class StateSystem implements IStateSystemBuilder {
          * 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);
@@ -242,8 +311,7 @@ public class StateSystem implements IStateSystemBuilder {
             } 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;
@@ -281,10 +349,11 @@ public class StateSystem implements IStateSystemBuilder {
     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);
@@ -294,7 +363,7 @@ public class StateSystem implements IStateSystemBuilder {
     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);
 
@@ -303,7 +372,8 @@ public class StateSystem implements IStateSystemBuilder {
              * 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 {
@@ -311,9 +381,9 @@ public class StateSystem implements IStateSystemBuilder {
             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$
@@ -321,61 +391,63 @@ public class StateSystem implements IStateSystemBuilder {
         }
 
         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();
         }
 
-        if (stackDepth < 0) {
+        Integer stackDepth = previousSV.unboxInt();
+
+        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
@@ -388,7 +460,7 @@ public class StateSystem implements IStateSystemBuilder {
          * "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);
@@ -402,7 +474,7 @@ public class StateSystem implements IStateSystemBuilder {
              * 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);
         }
     }
 
@@ -416,13 +488,29 @@ public class StateSystem implements IStateSystemBuilder {
         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)
@@ -430,12 +518,15 @@ public class StateSystem implements IStateSystemBuilder {
 
     @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);
         }
 
@@ -457,7 +548,6 @@ public class StateSystem implements IStateSystemBuilder {
          */
         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()));
             }
         }
@@ -466,12 +556,18 @@ public class StateSystem implements IStateSystemBuilder {
 
     @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);
         }
 
@@ -480,23 +576,49 @@ public class StateSystem implements IStateSystemBuilder {
          * 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();
         }
 
@@ -508,7 +630,7 @@ public class StateSystem implements IStateSystemBuilder {
         }
 
         /* Get the initial state at time T1 */
-        intervals = new ArrayList<ITmfStateInterval>();
+        intervals = new ArrayList<>();
         currentInterval = querySingleState(t1, attributeQuark);
         intervals.add(currentInterval);
 
@@ -526,13 +648,19 @@ public class StateSystem implements IStateSystemBuilder {
     @Override
     public List<ITmfStateInterval> queryHistoryRange(int attributeQuark,
             long t1, long t2, long resolution, IProgressMonitor monitor)
-            throws TimeRangeException, AttributeNotFoundException {
+            throws TimeRangeException, AttributeNotFoundException,
+            StateSystemDisposedException {
+        if (isDisposed) {
+            throw new StateSystemDisposedException();
+        }
+
         List<ITmfStateInterval> intervals;
         ITmfStateInterval currentInterval;
         long ts, tEnd;
 
-        if (monitor == null) {
-            monitor = new NullProgressMonitor();
+        IProgressMonitor mon = monitor;
+        if (mon == null) {
+            mon = new NullProgressMonitor();
         }
 
         /* Make sure the time range makes sense */
@@ -548,7 +676,7 @@ public class StateSystem implements IStateSystemBuilder {
         }
 
         /* Get the initial state at time T1 */
-        intervals = new ArrayList<ITmfStateInterval>();
+        intervals = new ArrayList<>();
         currentInterval = querySingleState(t1, attributeQuark);
         intervals.add(currentInterval);
 
@@ -558,7 +686,7 @@ public class StateSystem implements IStateSystemBuilder {
          */
         for (ts = t1; (currentInterval.getEndTime() != -1) && (ts < tEnd);
                 ts += resolution) {
-            if (monitor.isCanceled()) {
+            if (mon.isCanceled()) {
                 return intervals;
             }
             if (ts <= currentInterval.getEndTime()) {
@@ -581,7 +709,7 @@ public class StateSystem implements IStateSystemBuilder {
     //--------------------------------------------------------------------------
 
     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$
     }
@@ -593,7 +721,7 @@ public class StateSystem implements IStateSystemBuilder {
      *            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);
     }
This page took 0.034504 seconds and 5 git commands to generate.