tmf: Add support for versioning state input plugins
authorAlexandre Montplaisir <alexmonthy@voxpopuli.im>
Mon, 25 Feb 2013 22:59:14 +0000 (17:59 -0500)
committerAlexandre Montplaisir <alexmonthy@voxpopuli.im>
Tue, 26 Feb 2013 19:46:43 +0000 (14:46 -0500)
As we have seen with the recent addition of WAIT_FOR_CPU and
WAIT_BLOCKED state, if the framework gets updated we need a
way to tell it to rebuild any existing (and now outdated)
state history file that can be present in the workspace.

This patch reuses the minor_version field which was present
in the history tree's file header, but wasn't used. We now
assign this int to represent the version of the specific
state input we're trying to build. If the version in the
framework and the version of the existing file don't match, it
will force a rebuild.

Since the initial value used is 0, it should keep working with
any currently-existing history files (until the framework's
handlers are modified).

Change-Id: Id321db30f2e124cf93c96205a0450cccad47a49f
Signed-off-by: Alexandre Montplaisir <alexmonthy@voxpopuli.im>
Reviewed-on: https://git.eclipse.org/r/10638
Tested-by: Hudson CI
Reviewed-by: Bernd Hufmann <bhufmann@gmail.com>
IP-Clean: Bernd Hufmann <bhufmann@gmail.com>
Tested-by: Bernd Hufmann <bhufmann@gmail.com>
org.eclipse.linuxtools.lttng2.kernel.core/src/org/eclipse/linuxtools/internal/lttng2/kernel/core/stateprovider/CtfKernelStateInput.java
org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/statesystem/StateSystemPushPopTest.java
org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/statesystem/VerifyHistoryFile.java
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/historytree/HTConfig.java
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/historytree/HistoryTree.java
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/historytree/HistoryTreeBackend.java
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/statesystem/backends/historytree/ThreadedHistoryTreeBackend.java
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/statesystem/IStateChangeInput.java
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/statesystem/StateSystemManager.java
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/statistics/StatsStateProvider.java

index 2dd8659e2ec1483b053a62ac43604021efdc323b..da98205b78a8666f268a197cd1642d316498dd13 100644 (file)
@@ -40,6 +40,12 @@ import org.eclipse.linuxtools.tmf.core.statevalue.TmfStateValue;
  */
 public class CtfKernelStateInput extends AbstractStateChangeInput {
 
+    /**
+     * Version number of this state provider. Please bump this if you modify the
+     * contents of the generated state history in some way.
+     */
+    private static final int VERSION = 0;
+
     /* Event names HashMap. TODO: This can be discarded once we move to Java 7 */
     private final HashMap<String, Integer> knownEventNames;
 
@@ -61,6 +67,11 @@ public class CtfKernelStateInput extends AbstractStateChangeInput {
         knownEventNames = fillEventNames();
     }
 
+    @Override
+    public int getVersion() {
+        return VERSION;
+    }
+
     @Override
     public void assignTargetStateSystem(ITmfStateSystemBuilder ssb) {
         /* We can only set up the locations once the state system is assigned */
index 6744ecac904ee0af49f2eb86235fdc4a06024929..e0447d03c55178cab7fb7ff252f380b9844aca1d 100644 (file)
@@ -90,7 +90,7 @@ public class StateSystemPushPopTest {
             AttributeNotFoundException, StateValueTypeException {
         ITmfStateValue value;
 
-        IStateHistoryBackend backend = new HistoryTreeBackend(testHtFile, 0);
+        IStateHistoryBackend backend = new HistoryTreeBackend(testHtFile, 0, 0L);
         ss = new StateSystem(backend, true);
 
         /* Build the thing */
index aba79a9e4196e566a2af1313ccb656c81887e6c6..63c8b0049e06da767c8e1d89d95653237126794c 100644 (file)
@@ -23,6 +23,7 @@ import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException;
 import org.eclipse.linuxtools.tmf.core.exceptions.StateSystemDisposedException;
 import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
 import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval;
+import org.eclipse.linuxtools.tmf.core.statesystem.IStateChangeInput;
 import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystem;
 
 /**
@@ -37,7 +38,7 @@ import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystem;
 public class VerifyHistoryFile {
 
     // Enter the .ht file name to test here
-    public final static String pathToHistoryFile = "";
+    public static final String pathToHistoryFile = "";
 
     private static File htFile;
     private static IStateHistoryBackend htBackend;
@@ -51,7 +52,7 @@ public class VerifyHistoryFile {
             TimeRangeException, AttributeNotFoundException,
             StateSystemDisposedException {
         htFile = new File(pathToHistoryFile);
-        htBackend = new HistoryTreeBackend(htFile);
+        htBackend = new HistoryTreeBackend(htFile, IStateChangeInput.IGNORE_PROVIDER_VERSION);
         ss = HistoryBuilder.openExistingHistory(htBackend);
 
         startTime = ss.getStartTime();
index 9bdbfb336610fdd277f9986bfdd9c156e1d77ec9..586bae086da5ce6759ad5b2a3fea9406827e75a6 100644 (file)
@@ -2,12 +2,12 @@
  * Copyright (c) 2012 Ericsson
  * Copyright (c) 2010, 2011 École Polytechnique de Montréal
  * Copyright (c) 2010, 2011 Alexandre Montplaisir <alexandre.montplaisir@gmail.com>
- * 
+ *
  * All rights reserved. This program and the accompanying materials are
  * made available under the terms of the Eclipse Public License v1.0 which
  * accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
- * 
+ *
  *******************************************************************************/
 
 package org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.historytree;
@@ -16,31 +16,34 @@ import java.io.File;
 
 /**
  * Configuration object for a StateHistoryTree.
- * 
+ *
  * @author alexmont
- * 
+ *
  */
 final class HTConfig {
 
     public final File stateFile;
     public final int blockSize;
     public final int maxChildren;
+    public final int providerVersion;
     public final long treeStart;
 
-    HTConfig(File newStateFile, int blockSize, int maxChildren, long startTime) {
+    HTConfig(File newStateFile, int blockSize, int maxChildren,
+            int providerVersion, long startTime) {
         this.stateFile = newStateFile;
         this.blockSize = blockSize;
         this.maxChildren = maxChildren;
+        this.providerVersion = providerVersion;
         this.treeStart = startTime;
     }
 
     /**
      * Version using default values for blocksize and maxchildren
-     * 
+     *
      * @param stateFileName
      * @param startTime
      */
-    HTConfig(File newStateFile, long startTime) {
-        this(newStateFile, 64 * 1024, 50, startTime);
+    HTConfig(File newStateFile, int providerVersion, long startTime) {
+        this(newStateFile, 64 * 1024, 50, providerVersion, startTime);
     }
 }
index 39f516d15404b131318e74db76881a11618559d6..8592e1d0a4c4b935e86cd19b63bd7dba65d29d36 100644 (file)
@@ -23,6 +23,7 @@ import java.nio.channels.FileChannel;
 import java.util.Vector;
 
 import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
+import org.eclipse.linuxtools.tmf.core.statesystem.IStateChangeInput;
 
 /**
  * Meta-container for the History Tree. This structure contains all the
@@ -35,12 +36,8 @@ class HistoryTree {
 
     private static final int HISTORY_FILE_MAGIC_NUMBER = 0x05FFA900;
 
-    /*
-     * File format version. Increment minor on backwards-compatible changes.
-     * Increment major + set minor back to 0 when breaking compatibility.
-     */
-    private static final int MAJOR_VERSION = 3;
-    private static final byte MINOR_VERSION = 0;
+    /** File format version. Increment when breaking compatibility. */
+    private static final int FILE_VERSION = 3;
 
     // ------------------------------------------------------------------------
     // Tree-specific configuration
@@ -101,9 +98,11 @@ class HistoryTree {
      *
      * @param existingFileName
      *            Path/filename of the history-file we are to open
+     * @param expProviderVersion
+     *            The expected version of the state provider
      * @throws IOException
      */
-    HistoryTree(File existingStateFile) throws IOException {
+    HistoryTree(File existingStateFile, int expProviderVersion) throws IOException {
         /*
          * Open the file ourselves, get the tree header information we need,
          * then pass on the descriptor to the TreeIO object.
@@ -117,8 +116,7 @@ class HistoryTree {
             throw new IOException("Selected state file does not exist"); //$NON-NLS-1$
         }
         if (existingStateFile.length() <= 0) {
-            throw new IOException("Invalid state file selected, " + //$NON-NLS-1$
-                    "target file is empty"); //$NON-NLS-1$
+            throw new IOException("Empty target file"); //$NON-NLS-1$
         }
 
         FileInputStream fis = new FileInputStream(existingStateFile);
@@ -137,20 +135,28 @@ class HistoryTree {
         if (res != HISTORY_FILE_MAGIC_NUMBER) {
             fc.close();
             fis.close();
-            throw new IOException("Selected file does not" + //$NON-NLS-1$
-                    "look like a History Tree file"); //$NON-NLS-1$
+            throw new IOException("Wrong magic number"); //$NON-NLS-1$
         }
 
-        res = buffer.getInt(); /* Major version number */
-        if (res != MAJOR_VERSION) {
+        res = buffer.getInt(); /* File format version number */
+        if (res != FILE_VERSION) {
             fc.close();
             fis.close();
-            throw new IOException("Select History Tree file is of an older " //$NON-NLS-1$
-                    + "format. Please use a previous version of " //$NON-NLS-1$
-                    + "the parser to open it."); //$NON-NLS-1$
+            throw new IOException("Mismatching History Tree file format versions"); //$NON-NLS-1$
         }
 
-        res = buffer.getInt(); /* Minor version number */
+        res = buffer.getInt(); /* Event handler's version number */
+        if (res != expProviderVersion &&
+                expProviderVersion != IStateChangeInput.IGNORE_PROVIDER_VERSION) {
+            /*
+             * The existing history was built using a event handler that doesn't
+             * match the current one in the framework. Information could be all
+             * wrong, so we'll force a rebuild of the history file instead.
+             */
+            fc.close();
+            fis.close();
+            throw new IOException("Mismatching event handler versions"); //$NON-NLS-1$
+        }
 
         bs = buffer.getInt(); /* Block Size */
         maxc = buffer.getInt(); /* Max nb of children per node */
@@ -159,7 +165,7 @@ class HistoryTree {
         rootNodeSeqNb = buffer.getInt();
         startTime = buffer.getLong();
 
-        this.config = new HTConfig(existingStateFile, bs, maxc, startTime);
+        this.config = new HTConfig(existingStateFile, bs, maxc, expProviderVersion, startTime);
         fc.close();
         fis.close();
         /*
@@ -226,8 +232,8 @@ class HistoryTree {
 
             buffer.putInt(HISTORY_FILE_MAGIC_NUMBER);
 
-            buffer.putInt(MAJOR_VERSION);
-            buffer.putInt(MINOR_VERSION);
+            buffer.putInt(FILE_VERSION);
+            buffer.putInt(config.providerVersion);
 
             buffer.putInt(config.blockSize);
             buffer.putInt(config.maxChildren);
index c3e6b9d1f2773c56c78d5777294f863bd8f8b0ff..a8f6ab02c161c0136bdda1ba7daefe6b7c83fde2 100644 (file)
@@ -56,14 +56,19 @@ public class HistoryTreeBackend implements IStateHistoryBackend {
      *            multiple of 4096.
      * @param maxChildren
      *            The maximum number of children each core node can have
+     * @param providerVersion
+     *            Version of of the state provider. We will only try to reopen
+     *            existing files if this version matches the one in the
+     *            framework.
      * @param startTime
      *            The earliest time stamp that will be stored in the history
      * @throws IOException
      *             Thrown if we can't create the file for some reason
      */
     public HistoryTreeBackend(File newStateFile, int blockSize,
-            int maxChildren, long startTime) throws IOException {
-        final HTConfig conf = new HTConfig(newStateFile, blockSize, maxChildren, startTime);
+            int maxChildren, int providerVersion, long startTime) throws IOException {
+        final HTConfig conf = new HTConfig(newStateFile, blockSize, maxChildren,
+                providerVersion, startTime);
         sht = new HistoryTree(conf);
         treeIO = sht.getTreeIO();
     }
@@ -76,14 +81,18 @@ public class HistoryTreeBackend implements IStateHistoryBackend {
      * @param newStateFile
      *            The filename/location where to store the state history (Should
      *            end in .ht)
+     * @param providerVersion
+     *            Version of of the state provider. We will only try to reopen
+     *            existing files if this version matches the one in the
+     *            framework.
      * @param startTime
      *            The earliest time stamp that will be stored in the history
      * @throws IOException
      *             Thrown if we can't create the file for some reason
      */
-    public HistoryTreeBackend(File newStateFile, long startTime)
+    public HistoryTreeBackend(File newStateFile, int providerVersion, long startTime)
             throws IOException {
-        this(newStateFile, 64 * 1024, 50, startTime);
+        this(newStateFile, 64 * 1024, 50, providerVersion, startTime);
     }
 
     /**
@@ -91,12 +100,16 @@ public class HistoryTreeBackend implements IStateHistoryBackend {
      *
      * @param existingStateFile
      *            Filename/location of the history we want to load
+     * @param providerVersion
+     *            Expected version of of the state provider plugin.
      * @throws IOException
-     *             If we can't read the file, if it doesn't exist or is not
-     *             recognized
+     *             If we can't read the file, if it doesn't exist, is not
+     *             recognized, or if the version of the file does not match the
+     *             expected providerVersion.
      */
-    public HistoryTreeBackend(File existingStateFile) throws IOException {
-        sht = new HistoryTree(existingStateFile);
+    public HistoryTreeBackend(File existingStateFile, int providerVersion)
+            throws IOException {
+        sht = new HistoryTree(existingStateFile, providerVersion);
         treeIO = sht.getTreeIO();
         isFinishedBuilding = true;
     }
index 2bf82f9bd93bb80988f6fe7cc5d5ba71b6ec48b8..4a2e6dadb93b58ed85756198164905dbfef3b798 100644 (file)
@@ -56,6 +56,10 @@ public final class ThreadedHistoryTreeBackend extends HistoryTreeBackend
      *            The maximum number of children allowed for each core node
      * @param startTime
      *            The earliest timestamp stored in the history
+     * @param providerVersion
+     *            Version of of the state provider. We will only try to reopen
+     *            existing files if this version matches the one in the
+     *            framework.
      * @param queueSize
      *            The size of the interval insertion queue. 2000 - 10000 usually
      *            works well
@@ -63,8 +67,9 @@ public final class ThreadedHistoryTreeBackend extends HistoryTreeBackend
      *             If there was a problem opening the history file for writing
      */
     public ThreadedHistoryTreeBackend(File newStateFile, int blockSize,
-            int maxChildren, long startTime, int queueSize) throws IOException {
-        super(newStateFile, blockSize, maxChildren, startTime);
+            int maxChildren, long startTime, int providerVersion, int queueSize)
+                    throws IOException {
+        super(newStateFile, blockSize, maxChildren, providerVersion, startTime);
 
         intervalQueue = new ArrayBlockingQueue<HTInterval>(queueSize);
         shtThread = new Thread(this, "History Tree Thread"); //$NON-NLS-1$
@@ -80,6 +85,10 @@ public final class ThreadedHistoryTreeBackend extends HistoryTreeBackend
      *            in ".ht"
      * @param startTime
      *            The earliest timestamp stored in the history
+     * @param providerVersion
+     *            Version of of the state provider. We will only try to reopen
+     *            existing files if this version matches the one in the
+     *            framework.
      * @param queueSize
      *            The size of the interval insertion queue. 2000 - 10000 usually
      *            works well
@@ -87,8 +96,8 @@ public final class ThreadedHistoryTreeBackend extends HistoryTreeBackend
      *             If there was a problem opening the history file for writing
      */
     public ThreadedHistoryTreeBackend(File newStateFile, long startTime,
-            int queueSize) throws IOException {
-        super(newStateFile, startTime);
+            int providerVersion, int queueSize) throws IOException {
+        super(newStateFile, providerVersion, startTime);
 
         intervalQueue = new ArrayBlockingQueue<HTInterval>(queueSize);
         shtThread = new Thread(this, "History Tree Thread"); //$NON-NLS-1$
index c19eb7317a1d5eb714920c97732be2ec0d7ecea2..0fdcf37fe2d245927a24d44192ad994e753f2b44 100644 (file)
@@ -27,6 +27,25 @@ import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
  */
 public interface IStateChangeInput {
 
+    /**
+     * Special state provider version number that will tell the backend to
+     * ignore the version check and open an existing file even if the versions
+     * don't match.
+     * @since 2.0
+     */
+    public final static int IGNORE_PROVIDER_VERSION = -42;
+
+    /**
+     * Event handler plugins should provide a version number. This is used to
+     * determine if a potential existing file can be re-opened later (if the
+     * versions in the file and in the viewer match), or if the file should be
+     * rebuilt from scratch (if the versions don't match).
+     *
+     * @return The version number of the input plugin
+     * @since 2.0
+     */
+    public int getVersion();
+
     /**
      * Get the trace with which this state input plugin is associated.
      *
index 4d8f8e0cdf84a085ea6466aecfdb6a5c5fe797e7..f8a50d398f133795d01816d66fc1a84fddf20124 100644 (file)
@@ -72,8 +72,11 @@ public abstract class StateSystemManager extends TmfComponent {
         // at least if its range matches the trace's range.
         if (htFile.exists()) {
             /* Load an existing history */
+            final int version = (htInput == null) ?
+                    IStateChangeInput.IGNORE_PROVIDER_VERSION :
+                    htInput.getVersion();
             try {
-                htBackend = new HistoryTreeBackend(htFile);
+                htBackend = new HistoryTreeBackend(htFile, version);
                 ITmfStateSystem ss = HistoryBuilder.openExistingHistory(htBackend);
                 return ss;
             } catch (IOException e) {
@@ -92,7 +95,8 @@ public abstract class StateSystemManager extends TmfComponent {
             return null;
         }
         try {
-            htBackend = new ThreadedHistoryTreeBackend(htFile, htInput.getStartTime(), QUEUE_SIZE);
+            htBackend = new ThreadedHistoryTreeBackend(htFile,
+                    htInput.getStartTime(), htInput.getVersion(), QUEUE_SIZE);
             StateSystem ss = new StateSystem(htBackend);
             htInput.assignTargetStateSystem(ss);
             builder = new HistoryBuilder(htInput, ss, htBackend, buildManually);
index c5be16a5cb9df97cb02411374251c5434a0b8a56..0177945b096d923d6a9bf6f925660b44a62dd64f 100644 (file)
@@ -44,6 +44,12 @@ import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
  */
 class StatsStateProvider extends AbstractStateChangeInput {
 
+    /**
+     * Version number of this input handler. Please bump this if you modify the
+     * contents of the generated state history in some way.
+     */
+    private static final int VERSION = 0;
+
     /* Commonly-used attributes */
     private int typeAttribute = -1;
 
@@ -57,6 +63,11 @@ class StatsStateProvider extends AbstractStateChangeInput {
         super(trace, ITmfEvent.class ,"TMF Statistics"); //$NON-NLS-1$
     }
 
+    @Override
+    public int getVersion() {
+        return VERSION;
+    }
+
     @Override
     public void assignTargetStateSystem(ITmfStateSystemBuilder ssb) {
         super.assignTargetStateSystem(ssb);
This page took 0.033836 seconds and 5 git commands to generate.