ss: History trees can define their own node types
[deliverable/tracecompass.git] / statesystem / org.eclipse.tracecompass.statesystem.core / src / org / eclipse / tracecompass / internal / statesystem / core / backend / historytree / HistoryTreeBackend.java
index 6f0148e4f7c229700f662ef6d82955301cf3c436..2aaa1e390c6ed9e271ef8a9566daaac781f50a76 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012, 2015 Ericsson
+ * Copyright (c) 2012, 2016 Ericsson
  * Copyright (c) 2010, 2011 École Polytechnique de Montréal
  * Copyright (c) 2010, 2011 Alexandre Montplaisir <alexandre.montplaisir@gmail.com>
  *
@@ -18,16 +18,13 @@ package org.eclipse.tracecompass.internal.statesystem.core.backend.historytree;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
-import java.io.PrintWriter;
 import java.nio.channels.ClosedChannelException;
+import java.util.Deque;
+import java.util.LinkedList;
 import java.util.List;
 
 import org.eclipse.jdt.annotation.NonNull;
-import org.eclipse.tracecompass.internal.statesystem.core.backend.historytree.CoreNode;
-import org.eclipse.tracecompass.internal.statesystem.core.backend.historytree.HTConfig;
-import org.eclipse.tracecompass.internal.statesystem.core.backend.historytree.HTInterval;
-import org.eclipse.tracecompass.internal.statesystem.core.backend.historytree.HTNode;
-import org.eclipse.tracecompass.internal.statesystem.core.backend.historytree.HistoryTree;
+import org.eclipse.tracecompass.internal.statesystem.core.Activator;
 import org.eclipse.tracecompass.statesystem.core.backend.IStateHistoryBackend;
 import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
 import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
@@ -35,6 +32,8 @@ import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
 import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
 import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
 
+import com.google.common.annotations.VisibleForTesting;
+
 /**
  * History Tree backend for storing a state history. This is the basic version
  * that runs in the same thread as the class creating it.
@@ -43,12 +42,12 @@ import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
  */
 public class HistoryTreeBackend implements IStateHistoryBackend {
 
-    private final @NonNull String ssid;
+    private final @NonNull String fSsid;
 
     /**
      * The history tree that sits underneath.
      */
-    private final HistoryTree sht;
+    private final @NonNull IHistoryTree fSht;
 
     /** Indicates if the history tree construction is done */
     private volatile boolean fFinishedBuilding = false;
@@ -69,7 +68,7 @@ public class HistoryTreeBackend implements IStateHistoryBackend {
      *            is the history tree finished building
      */
     protected void setFinishedBuilding(boolean isFinishedBuilding) {
-        this.fFinishedBuilding = isFinishedBuilding;
+        fFinishedBuilding = isFinishedBuilding;
     }
 
     /**
@@ -101,10 +100,10 @@ public class HistoryTreeBackend implements IStateHistoryBackend {
             long startTime,
             int blockSize,
             int maxChildren) throws IOException {
-        this.ssid = ssid;
+        fSsid = ssid;
         final HTConfig conf = new HTConfig(newStateFile, blockSize, maxChildren,
                 providerVersion, startTime);
-        sht = new HistoryTree(conf);
+        fSht = initializeSHT(conf);
     }
 
     /**
@@ -146,35 +145,71 @@ public class HistoryTreeBackend implements IStateHistoryBackend {
      *             recognized, or if the version of the file does not match the
      *             expected providerVersion.
      */
-    public HistoryTreeBackend(@NonNull String ssid, File existingStateFile, int providerVersion)
+    public HistoryTreeBackend(@NonNull String ssid, @NonNull File existingStateFile, int providerVersion)
             throws IOException {
-        this.ssid = ssid;
-        sht = new HistoryTree(existingStateFile, providerVersion);
+        fSsid = ssid;
+        fSht = initializeSHT(existingStateFile, providerVersion);
         fFinishedBuilding = true;
     }
 
+    /**
+     * New-tree initializer for the History Tree wrapped by this backend. Can be
+     * overriden to use different implementations.
+     *
+     * @param conf
+     *            The HTConfig configuration object
+     * @return The new history tree
+     * @throws IOException
+     *             If there was a problem during creation
+     */
+    @VisibleForTesting
+    protected @NonNull IHistoryTree initializeSHT(@NonNull HTConfig conf) throws IOException {
+        return HistoryTreeFactory.createHistoryTree(conf);
+    }
+
+    /**
+     * Existing-tree initializer for the History Tree wrapped by this backend.
+     * Can be overriden to use different implementations.
+     *
+     * @param existingStateFile
+     *            The file to open
+     * @param providerVersion
+     *            The expected state provider version
+     * @return The history tree opened from the given file
+     * @throws IOException
+     *             If there was a problem during creation
+     */
+    @VisibleForTesting
+    protected @NonNull IHistoryTree initializeSHT(@NonNull File existingStateFile, int providerVersion) throws IOException {
+        return HistoryTreeFactory.createFromFile(existingStateFile.toPath(), providerVersion);
+    }
+
     /**
      * Get the History Tree built by this backend.
      *
+     * Note: Do not override this method. If you want to extend the class to use
+     * a different History Tree implementation, override both variants of
+     * {@link #initializeSHT} instead.
+     *
      * @return The history tree
      */
-    protected HistoryTree getSHT() {
-        return sht;
+    protected final @NonNull IHistoryTree getSHT() {
+        return fSht;
     }
 
     @Override
     public String getSSID() {
-        return ssid;
+        return fSsid;
     }
 
     @Override
     public long getStartTime() {
-        return sht.getTreeStart();
+        return getSHT().getTreeStart();
     }
 
     @Override
     public long getEndTime() {
-        return sht.getTreeEnd();
+        return getSHT().getTreeEnd();
     }
 
     @Override
@@ -184,46 +219,46 @@ public class HistoryTreeBackend implements IStateHistoryBackend {
                 quark, (TmfStateValue) value);
 
         /* Start insertions at the "latest leaf" */
-        sht.insertInterval(interval);
+        getSHT().insertInterval(interval);
     }
 
     @Override
     public void finishedBuilding(long endTime) {
-        sht.closeTree(endTime);
+        getSHT().closeTree(endTime);
         fFinishedBuilding = true;
     }
 
     @Override
     public FileInputStream supplyAttributeTreeReader() {
-        return sht.supplyATReader();
+        return getSHT().supplyATReader();
     }
 
     @Override
     public File supplyAttributeTreeWriterFile() {
-        return sht.supplyATWriterFile();
+        return getSHT().supplyATWriterFile();
     }
 
     @Override
     public long supplyAttributeTreeWriterFilePosition() {
-        return sht.supplyATWriterFilePos();
+        return getSHT().supplyATWriterFilePos();
     }
 
     @Override
     public void removeFiles() {
-        sht.deleteFile();
+        getSHT().deleteFile();
     }
 
     @Override
     public void dispose() {
         if (fFinishedBuilding) {
-            sht.closeFile();
+            getSHT().closeFile();
         } else {
             /*
              * The build is being interrupted, delete the file we partially
              * built since it won't be complete, so shouldn't be re-used in the
              * future (.deleteFile() will close the file first)
              */
-            sht.deleteFile();
+            getSHT().deleteFile();
         }
     }
 
@@ -232,14 +267,20 @@ public class HistoryTreeBackend implements IStateHistoryBackend {
             throws TimeRangeException, StateSystemDisposedException {
         checkValidTime(t);
 
+        /* Queue is a stack of nodes containing nodes intersecting t */
+        Deque<HTNode> queue = new LinkedList<>();
+
         /* We start by reading the information in the root node */
-        HTNode currentNode = sht.getRootNode();
-        currentNode.writeInfoFromNode(stateInfo, t);
+        queue.add(getSHT().getRootNode());
 
-        /* Then we follow the branch down in the relevant children */
+        /* Then we follow the down in the relevant children */
         try {
-            while (currentNode.getNodeType() == HTNode.NodeType.CORE) {
-                currentNode = sht.selectNextChild((CoreNode) currentNode, t);
+            while (!queue.isEmpty()) {
+                HTNode currentNode = queue.pop();
+                if (currentNode.getNodeType() == HTNode.NodeType.CORE) {
+                    /*Here we add the relevant children nodes for BFS*/
+                    queue.addAll(getSHT().selectNextChildren((ParentNode) currentNode, t));
+                }
                 currentNode.writeInfoFromNode(stateInfo, t);
             }
         } catch (ClosedChannelException e) {
@@ -250,45 +291,44 @@ public class HistoryTreeBackend implements IStateHistoryBackend {
          * The stateInfo should now be filled with everything needed, we pass
          * the control back to the State System.
          */
-        return;
     }
 
     @Override
     public ITmfStateInterval doSingularQuery(long t, int attributeQuark)
             throws TimeRangeException, StateSystemDisposedException {
-        return getRelevantInterval(t, attributeQuark);
+        try {
+            return getRelevantInterval(t, attributeQuark);
+        } catch (ClosedChannelException e) {
+            throw new StateSystemDisposedException(e);
+        }
     }
 
     private void checkValidTime(long t) {
-        long treeStart = sht.getTreeStart();
-        long treeEnd = sht.getTreeEnd();
-        if (t < treeStart || t > treeEnd) {
-            throw new TimeRangeException(ssid + " Time:" + t + ", Start:" + treeStart + ", End:" + treeEnd); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        long startTime = getStartTime();
+        long endTime = getEndTime();
+        if (t < startTime || t > endTime) {
+            throw new TimeRangeException(String.format("%s Time:%d, Start:%d, End:%d", //$NON-NLS-1$
+                    fSsid, t, startTime, endTime));
         }
     }
 
     /**
      * Inner method to find the interval in the tree containing the requested
      * key/timestamp pair, wherever in which node it is.
-     *
-     * @param t
-     * @param key
-     * @return The node containing the information we want
      */
     private HTInterval getRelevantInterval(long t, int key)
-            throws TimeRangeException, StateSystemDisposedException {
+            throws TimeRangeException, ClosedChannelException {
         checkValidTime(t);
 
-        HTNode currentNode = sht.getRootNode();
-        HTInterval interval = currentNode.getRelevantInterval(key, t);
-
-        try {
-            while (interval == null && currentNode.getNodeType() == HTNode.NodeType.CORE) {
-                currentNode = sht.selectNextChild((CoreNode) currentNode, t);
-                interval = currentNode.getRelevantInterval(key, t);
+        Deque<HTNode> queue = new LinkedList<>();
+        queue.add(getSHT().getRootNode());
+        HTInterval interval = null;
+        while (interval == null && !queue.isEmpty()) {
+            HTNode currentNode = queue.pop();
+            if (currentNode.getNodeType() == HTNode.NodeType.CORE) {
+                queue.addAll(getSHT().selectNextChildren((ParentNode) currentNode, t));
             }
-        } catch (ClosedChannelException e) {
-            throw new StateSystemDisposedException(e);
+            interval = currentNode.getRelevantInterval(key, t);
         }
         return interval;
     }
@@ -299,7 +339,7 @@ public class HistoryTreeBackend implements IStateHistoryBackend {
      * @return The current size of the history file in bytes
      */
     public long getFileSize() {
-        return sht.getFileSize();
+        return getSHT().getFileSize();
     }
 
     /**
@@ -313,45 +353,20 @@ public class HistoryTreeBackend implements IStateHistoryBackend {
         long ret;
 
         try {
-            for (int seq = 0; seq < sht.getNodeCount(); seq++) {
-                node = sht.readNode(seq);
+            for (int seq = 0; seq < getSHT().getNodeCount(); seq++) {
+                node = getSHT().readNode(seq);
                 total += node.getNodeUsagePercent();
             }
         } catch (ClosedChannelException e) {
-            e.printStackTrace();
+            Activator.getDefault().logError(e.getMessage(), e);
         }
 
-        ret = total / sht.getNodeCount();
-        assert (ret >= 0 && ret <= 100);
+        ret = total / getSHT().getNodeCount();
+        /* The return value should be a percentage */
+        if (ret < 0 || ret > 100) {
+            throw new IllegalStateException("Average node usage is not a percentage: " + ret); //$NON-NLS-1$
+        }
         return (int) ret;
     }
 
-    @Override
-    public void debugPrint(PrintWriter writer) {
-        /* By default don't print out all the intervals */
-        this.debugPrint(writer, false);
-    }
-
-    /**
-     * The basic debugPrint method will print the tree structure, but not their
-     * contents.
-     *
-     * This method here print the contents (the intervals) as well.
-     *
-     * @param writer
-     *            The PrintWriter to which the debug info will be written
-     * @param printIntervals
-     *            Should we also print every contained interval individually?
-     */
-    public void debugPrint(PrintWriter writer, boolean printIntervals) {
-        /* Only used for debugging, shouldn't be externalized */
-        writer.println("------------------------------"); //$NON-NLS-1$
-        writer.println("State History Tree:\n"); //$NON-NLS-1$
-        writer.println(sht.toString());
-        writer.println("Average node utilization: " //$NON-NLS-1$
-                + this.getAverageNodeUsage());
-        writer.println(""); //$NON-NLS-1$
-
-        sht.debugPrintFullTree(writer, printIntervals);
-    }
 }
This page took 0.028593 seconds and 5 git commands to generate.