BTree index on disk
authorMarc-Andre Laperle <marc-andre.laperle@ericsson.com>
Wed, 21 Aug 2013 05:42:29 +0000 (01:42 -0400)
committerAlexandre Montplaisir <alexmonthy@voxpopuli.im>
Thu, 3 Oct 2013 22:13:16 +0000 (18:13 -0400)
Bug: 315883

Change-Id: I91be77339535a2379f4d48ab9d6e66894afb95ac
Signed-off-by: Marc-Andre Laperle <marc-andre.laperle@ericsson.com>
Reviewed-on: https://git.eclipse.org/r/15685
Tested-by: Hudson CI
Reviewed-by: Alexandre Montplaisir <alexmonthy@voxpopuli.im>
IP-Clean: Alexandre Montplaisir <alexmonthy@voxpopuli.im>
Tested-by: Alexandre Montplaisir <alexmonthy@voxpopuli.im>
61 files changed:
org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/AllTmfCoreTests.java
org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/event/TmfTimestampDeltaTest.java
org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/event/TmfTimestampTest.java
org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/AbstractCheckpointCollectionTest.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/AllBench.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/AllTests.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/BTreeTest.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/FlatArrayTest.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/TmfMemoryIndexTest.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/AbstractIndexTest.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/AllTests.java
org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/TmfBTreeIndexTest.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/TmfCheckpointIndexTest.java
org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/TmfCheckpointIndexTest2.java
org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/TmfCheckpointTest.java
org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/TmfExperimentCheckpointIndexTest.java
org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/location/TmfStringLocation.java
org.eclipse.linuxtools.tmf.core.tests/stubs/org/eclipse/linuxtools/tmf/tests/stubs/trace/TmfIndexerStub.java
org.eclipse.linuxtools.tmf.core.tests/stubs/org/eclipse/linuxtools/tmf/tests/stubs/trace/TmfTraceStub.java
org.eclipse.linuxtools.tmf.core/META-INF/MANIFEST.MF
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/TmfExperimentLocation.java
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/AbstractFileCheckpointCollection.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/BTree.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/BTreeCheckpointVisitor.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/BTreeNode.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/BTreeNodeCache.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/FlatArray.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/IBTreeVisitor.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/ICheckpointCollection.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/Messages.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/TmfMemoryIndex.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/messages.properties [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/ctfadaptor/CtfLocation.java
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/ctfadaptor/CtfLocationInfo.java
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/ctfadaptor/CtfTmfTrace.java
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/signal/TmfTraceUpdatedSignal.java
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/timestamp/TmfTimestamp.java
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfExperiment.java
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfTrace.java
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/ITmfPersistentlyIndexable.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/TmfBTreeTraceIndex.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/TmfBTreeTraceIndexer.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/TmfFlatArrayTraceIndex.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/TmfFlatArrayTraceIndexer.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/checkpoint/ITmfCheckpoint.java
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/checkpoint/ITmfCheckpointIndex.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/checkpoint/TmfCheckpoint.java
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/checkpoint/TmfCheckpointIndexer.java
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/location/ITmfLocation.java
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/location/TmfLongLocation.java
org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/location/TmfTimestampLocation.java
org.eclipse.linuxtools.tmf.ui.tests/META-INF/MANIFEST.MF
org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/TmfUITestPlugin.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/trace/AbstractCustomTraceIndexTest.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/trace/AllTests.java
org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/trace/CustomTxtIndexTest.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/trace/CustomXmlIndexTest.java [new file with mode: 0644]
org.eclipse.linuxtools.tmf.ui.tests/tracesets/txt/testTxtDefinition.xml [new file with mode: 0644]
org.eclipse.linuxtools.tmf.ui.tests/tracesets/xml/testDefinition.xml [new file with mode: 0644]
org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/parsers/custom/CustomTxtTrace.java
org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/parsers/custom/CustomXmlTrace.java

index 92d5130036525d72d5ee87925ee58dd15ee6ff12..35b29459505bf10b2e904525b380ab918948c5fe 100644 (file)
@@ -34,6 +34,7 @@ import org.junit.runners.Suite;
     org.eclipse.linuxtools.tmf.core.tests.statistics.AllTests.class,
     org.eclipse.linuxtools.tmf.core.tests.synchronization.AllTests.class,
     org.eclipse.linuxtools.tmf.core.tests.trace.AllTests.class,
+    org.eclipse.linuxtools.tmf.core.tests.trace.indexer.AllTests.class,
     org.eclipse.linuxtools.tmf.core.tests.trace.indexer.checkpoint.AllTests.class,
     org.eclipse.linuxtools.tmf.core.tests.trace.location.AllTests.class,
     org.eclipse.linuxtools.tmf.core.tests.uml2sd.AllTests.class,
index fd0e01b002ff06dadfa67bde4ac86c98ffffe022..1cc98df698322c3f5cdd2a7dbcd60522983820a0 100644 (file)
@@ -15,7 +15,6 @@ package org.eclipse.linuxtools.tmf.core.tests.event;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 
 import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp;
 import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
@@ -89,13 +88,9 @@ public class TmfTimestampDeltaTest {
         assertEquals("getPrecision", 5, copy.getPrecision());
     }
 
-    @Test
+    @Test(expected=IllegalArgumentException.class)
     public void testCopyNullConstructor() {
-        try {
-            new TmfTimestamp(null);
-            fail("TmfIntervalTimestamp: null argument");
-        } catch (final IllegalArgumentException e) {
-        }
+        new TmfTimestamp((TmfTimestamp) null);
     }
 
     // ------------------------------------------------------------------------
index dbc586bcda6a77834eb2d0aae09b96f4c3c3e240..7bf07186b2bae5f242efc189aa25f9a1cf4d5076 100644 (file)
@@ -96,13 +96,9 @@ public class TmfTimestampTest {
         assertEquals("getPrecision", 5, copy.getPrecision());
     }
 
-    @Test
+    @Test(expected=IllegalArgumentException.class)
     public void testCopyNullConstructor() {
-        try {
-            new TmfTimestamp(null);
-            fail("TmfTimestamp: null argument");
-        } catch (final IllegalArgumentException e) {
-        }
+        new TmfTimestamp((TmfTimestamp) null);
     }
 
     @Test
diff --git a/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/AbstractCheckpointCollectionTest.java b/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/AbstractCheckpointCollectionTest.java
new file mode 100644 (file)
index 0000000..8601c76
--- /dev/null
@@ -0,0 +1,374 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * 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
+ *
+ * Contributors:
+ *     Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.core.tests.trace.indexer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.ArrayList;
+import java.util.Random;
+
+import org.eclipse.linuxtools.internal.tmf.core.trace.indexer.ICheckpointCollection;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.TmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.location.TmfLongLocation;
+import org.eclipse.linuxtools.tmf.tests.stubs.trace.TmfTraceStub;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Common code for ICheckpointCollection test classes
+ *
+ * @author Marc-Andre Laperle
+ */
+public abstract class AbstractCheckpointCollectionTest {
+
+    private static final String INDEX_FILE_NAME = "checkpoint.idx"; //$NON-NLS-1$
+
+    /**
+     * The number of checkpoints to be inserted in insert tests
+     */
+    protected static final int CHECKPOINTS_INSERT_NUM = 50000;
+    /**
+     * The collection being tested
+     */
+    protected ICheckpointCollection fCheckpointCollection = null;
+
+    private TmfTraceStub fTrace;
+    private File fFile = new File(INDEX_FILE_NAME);
+
+    /**
+     * Setup the test. Make sure the index is deleted.
+     */
+    @Before
+    public void setUp() {
+        fTrace = new TmfTraceStub();
+        if (fFile.exists()) {
+            fFile.delete();
+        }
+        fCheckpointCollection = createCollection();
+    }
+
+    /**
+     * Tear down the test. Make sure the index is deleted.
+     */
+    @After
+    public void tearDown() {
+        fTrace.dispose();
+        fTrace = null;
+        if (fCheckpointCollection != null) {
+            fCheckpointCollection.dispose();
+        }
+        if (fFile.exists()) {
+            fFile.delete();
+        }
+    }
+
+    /**
+     * Get the trace being tested.
+     *
+     * @return the trace being tested.
+     */
+    public ITmfTrace getTrace() {
+        return fTrace;
+    }
+
+    /**
+     * Returns whether or not the collection is persisted to disk
+     *
+     * @return true if the collection is persisted to disk, false otherwise
+     */
+    public boolean isPersistableCollection() {
+        return false;
+    }
+
+    /**
+     * Get the file used for the index being tested.
+     *
+     * @return the file used for the index being tested.
+     */
+    public File getFile() {
+        return fFile;
+    }
+
+    /**
+     * Test constructing a new checkpoint collection
+     */
+    @Test
+    public void testConstructor() {
+        if (isPersistableCollection()) {
+            assertTrue(fFile.exists());
+        }
+        assertTrue(fCheckpointCollection.isCreatedFromScratch());
+    }
+
+    /**
+     * Test constructing a new checkpoint collection, existing file
+     */
+    @Test
+    public void testConstructorExistingFile() {
+        if (isPersistableCollection()) {
+            assertTrue(fFile.exists());
+            fCheckpointCollection.setIndexComplete();
+            fCheckpointCollection.dispose();
+
+            fCheckpointCollection = createCollection();
+            assertFalse(fCheckpointCollection.isCreatedFromScratch());
+        }
+    }
+
+    /**
+     * Test that a new checkpoint collection is considered created from scratch
+     * and vice versa
+     */
+    @Test
+    public void testIsCreatedFromScratch() {
+        assertTrue(fCheckpointCollection.isCreatedFromScratch());
+        fCheckpointCollection.setIndexComplete();
+
+        if (isPersistableCollection()) {
+            fCheckpointCollection.dispose();
+            fCheckpointCollection = createCollection();
+            assertFalse(fCheckpointCollection.isCreatedFromScratch());
+        }
+    }
+
+    /**
+     * Test setTimeRange, getTimeRange
+     */
+    @Test
+    public void testSetGetTimeRange() {
+        if (isPersistableCollection()) {
+            TmfTimeRange timeRange = new TmfTimeRange(new TmfTimestamp(0), new TmfTimestamp(100));
+            fCheckpointCollection.setTimeRange(timeRange);
+            assertEquals(timeRange, fCheckpointCollection.getTimeRange());
+        }
+    }
+
+    /**
+     * Create a collection for the test
+     *
+     * @return the collection
+     */
+    abstract protected ICheckpointCollection createCollection();
+
+    /**
+     * Test setNbEvents, getNbEvents
+     */
+    @Test
+    public void testSetGetNbEvents() {
+        if (isPersistableCollection()) {
+            int expected = 12345;
+            fCheckpointCollection.setNbEvents(expected);
+            assertEquals(expected, fCheckpointCollection.getNbEvents());
+        }
+    }
+
+    /**
+     * Test setSize, size
+     */
+    @Test
+    public void testSetGetSize() {
+        assertEquals(0, fCheckpointCollection.size());
+        int expected = CHECKPOINTS_INSERT_NUM;
+        for (int i = 0; i < expected; ++i) {
+            fCheckpointCollection.insert(new TmfCheckpoint(new TmfTimestamp(0), new TmfLongLocation(0L), 0));
+        }
+        assertEquals(expected, fCheckpointCollection.size());
+    }
+
+    /**
+     * Test delete
+     */
+    @Test
+    public void testDelete() {
+        if (isPersistableCollection()) {
+            assertTrue(fFile.exists());
+            fCheckpointCollection.delete();
+            assertFalse(fFile.exists());
+        }
+    }
+
+    /**
+     * Test version change
+     *
+     * @throws IOException
+     *             can throw this
+     */
+    @Test
+    public void testVersionChange() throws IOException {
+        fCheckpointCollection.setIndexComplete();
+        fCheckpointCollection.dispose();
+        RandomAccessFile f = new RandomAccessFile(fFile, "rw");
+        f.writeInt(-1);
+        f.close();
+
+        fCheckpointCollection = createCollection();
+        assertTrue(fCheckpointCollection.isCreatedFromScratch());
+    }
+
+    /**
+     * Test a single insertion
+     */
+    @Test
+    public void testInsert() {
+        TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(12345), new TmfLongLocation(123456L), 0);
+        fCheckpointCollection.insert(checkpoint);
+
+        long found = fCheckpointCollection.binarySearch(checkpoint);
+        assertEquals(0, found);
+    }
+
+    /**
+     * Generate many checkpoints and insert them in the collection
+     *
+     * @return the list of generated checkpoints
+     */
+    protected ArrayList<Integer> insertAlot() {
+        for (int i = 0; i < CHECKPOINTS_INSERT_NUM; i++) {
+            TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(12345 + i), new TmfLongLocation(123456L + i), i);
+            fCheckpointCollection.insert(checkpoint);
+        }
+
+        fCheckpointCollection.setIndexComplete();
+        if (isPersistableCollection()) {
+            fCheckpointCollection.dispose();
+        }
+
+        boolean random = true;
+        ArrayList<Integer> list = new ArrayList<Integer>();
+        for (int i = 0; i < CHECKPOINTS_INSERT_NUM; i++) {
+            if (random) {
+                Random rand = new Random();
+                list.add(rand.nextInt(CHECKPOINTS_INSERT_NUM));
+            } else {
+                list.add(i);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Test many checkpoint insertions. Make sure they can be found after
+     * re-opening the file
+     */
+    @Test
+    public void testInsertAlot() {
+        ArrayList<Integer> list = insertAlot();
+
+        if (isPersistableCollection()) {
+            fCheckpointCollection = createCollection();
+        }
+
+        for (int i = 0; i < CHECKPOINTS_INSERT_NUM; i++) {
+            Integer randomCheckpoint = list.get(i);
+            TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(12345 + randomCheckpoint), new TmfLongLocation(123456L + randomCheckpoint), 0);
+            long found = fCheckpointCollection.binarySearch(checkpoint);
+            assertEquals(randomCheckpoint.intValue(), found);
+        }
+    }
+
+    /**
+     * Test many checkpoint insertions using the same timestamp. Make sure they
+     * can be found after re-opening the file
+     */
+    @Test
+    public void testInsertSameTimestamp() {
+        for (int i = 0; i < CHECKPOINTS_INSERT_NUM; i++) {
+            TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(12345), new TmfLongLocation(123456L + i), i);
+            fCheckpointCollection.insert(checkpoint);
+        }
+
+        fCheckpointCollection.setIndexComplete();
+        if (isPersistableCollection()) {
+            fCheckpointCollection.dispose();
+        }
+
+        boolean random = true;
+        ArrayList<Integer> list = new ArrayList<Integer>();
+        for (int i = 0; i < CHECKPOINTS_INSERT_NUM; i++) {
+            if (random) {
+                Random rand = new Random();
+                list.add(rand.nextInt(CHECKPOINTS_INSERT_NUM));
+            } else {
+                list.add(i);
+            }
+        }
+
+        if (isPersistableCollection()) {
+            fCheckpointCollection = createCollection();
+        }
+
+        for (int i = 0; i < CHECKPOINTS_INSERT_NUM; i++) {
+            Integer randomCheckpoint = list.get(i);
+            TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(12345), new TmfLongLocation(123456L + randomCheckpoint), 0);
+            long found = fCheckpointCollection.binarySearch(checkpoint);
+            assertEquals(randomCheckpoint.intValue(), found);
+        }
+    }
+
+    /**
+     * Tests that binarySearch find the correct checkpoint when the time stamp
+     * is between checkpoints
+     */
+    @Test
+    public void testBinarySearchFindInBetween() {
+        for (long i = 0; i < CHECKPOINTS_INSERT_NUM; i++) {
+            TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(2 * i), new TmfLongLocation(2 * i), i);
+            fCheckpointCollection.insert(checkpoint);
+        }
+
+        TmfCheckpoint searchedCheckpoint = new TmfCheckpoint(new TmfTimestamp(123), new TmfLongLocation(123L), 123);
+        int expectedInsertionPoint = 61;
+        int expectedRank = -(expectedInsertionPoint + 2);
+
+        long rank = fCheckpointCollection.binarySearch(searchedCheckpoint);
+        assertEquals(expectedRank, rank);
+    }
+
+
+    /**
+     * Tests that binarySearch finds the correct checkpoint when searching for a
+     * checkpoint with a null location. It should return the previous checkpoint
+     * from the first checkpoint that matches the timestamp.
+     */
+    @Test
+    public void testBinarySearchInBetweenSameTimestamp() {
+        int checkpointNum = 0;
+        for (; checkpointNum < 100; checkpointNum++) {
+            TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(0), new TmfLongLocation((long) checkpointNum), checkpointNum);
+            fCheckpointCollection.insert(checkpoint);
+        }
+
+        for (; checkpointNum < 200; checkpointNum++) {
+            TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(1), new TmfLongLocation((long) checkpointNum), checkpointNum);
+            fCheckpointCollection.insert(checkpoint);
+        }
+
+        final TmfCheckpoint searchedCheckpoint = new TmfCheckpoint(new TmfTimestamp(1), null, 0);
+
+        long found = fCheckpointCollection.binarySearch(searchedCheckpoint);
+
+        int expectedInsertionPoint = 99;
+        int expectedRank = -(expectedInsertionPoint + 2);
+
+        assertEquals(expectedRank, found);
+    }
+}
diff --git a/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/AllBench.java b/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/AllBench.java
new file mode 100644 (file)
index 0000000..cf82cbb
--- /dev/null
@@ -0,0 +1,251 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * 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
+ *
+ * Contributors:
+ *     Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.core.tests.trace.indexer;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.ArrayList;
+import java.util.Random;
+
+import org.eclipse.linuxtools.internal.tmf.core.trace.indexer.BTree;
+import org.eclipse.linuxtools.internal.tmf.core.trace.indexer.BTreeCheckpointVisitor;
+import org.eclipse.linuxtools.internal.tmf.core.trace.indexer.FlatArray;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.TmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.location.TmfLongLocation;
+import org.eclipse.linuxtools.tmf.tests.stubs.trace.TmfTraceStub;
+
+/**
+ * A class to benchmark different algoritms for storing the
+ * checkpoint index on disk
+ *
+ * @author Marc-Andre Laperle
+ */
+public class AllBench {
+
+    private static final boolean reportProgress = true;
+    private static ArrayList<ArrayList<Integer>> nums;
+    private TmfTraceStub fTrace;
+    private File file = new File("index.idx");
+
+    static int BTREE_DEGREE = 10;
+
+    private void setUp() {
+        fTrace = new TmfTraceStub();
+        if (file.exists()) {
+            file.delete();
+        }
+    }
+
+    private void tearDown() {
+        fTrace.dispose();
+        fTrace = null;
+        if (file.exists()) {
+            file.delete();
+        }
+    }
+
+    private static void generateDataFile(ArrayList<Integer> list, int checkpointsNums) throws IOException {
+        File randomDataFile = new File("data" + checkpointsNums);
+        RandomAccessFile f = new RandomAccessFile(randomDataFile, "rw");
+        if (randomDataFile.exists()) {
+            for (int i = 0; i < checkpointsNums; i++) {
+                Random rand = new Random();
+                int nextInt = rand.nextInt(checkpointsNums);
+                list.add(nextInt);
+                f.writeInt(nextInt);
+            }
+        } else {
+            for (int i = 0; i < checkpointsNums; i++) {
+                list.add(f.readInt());
+            }
+        }
+        f.close();
+    }
+
+    @SuppressWarnings("javadoc")
+    public static void main(String[] args) throws IOException {
+        int checkpointsNums [] = new int [] { 5000, 50000, 500000, 1000000 };
+        nums = new ArrayList<ArrayList<Integer>>(checkpointsNums.length);
+
+        System.out.println("DEGREE: " + BTREE_DEGREE);
+
+        AllBench b = new AllBench();
+        b.setUp();
+        for (int i = 0; i < checkpointsNums.length; i++) {
+            ArrayList<Integer> list = new ArrayList<Integer>();
+            generateDataFile(list, checkpointsNums[i]);
+            nums.add(list);
+
+            System.out.println("*** " + checkpointsNums[i] + " checkpoints ***\n");
+
+            b.benchIt(list);
+        }
+        b.tearDown();
+    }
+
+    private void benchIt(ArrayList<Integer> list) {
+
+        System.out.println("Testing BTree\n");
+
+        testInsertAlot(list);
+
+        System.out.println("Testing Array\n");
+
+        testInsertAlotArray(list);
+    }
+
+    private void testInsertAlot(ArrayList<Integer> list2) {
+        int checkpointsNum = list2.size();
+
+        writeCheckpoints(checkpointsNum);
+
+        ArrayList<Integer> list = new ArrayList<Integer>();
+        for (int i = 0; i < checkpointsNum; i++) {
+            list.add(i);
+        }
+
+        readCheckpoints(checkpointsNum, list, false);
+        readCheckpoints(checkpointsNum, list2, true);
+
+        file.delete();
+
+        System.out.println();
+    }
+
+    private void testInsertAlotArray(ArrayList<Integer> list2) {
+        int checkpointsNum = list2.size();
+
+        writeCheckpointsArray(checkpointsNum);
+
+        ArrayList<Integer> list = new ArrayList<Integer>();
+        for (int i = 0; i < checkpointsNum; i++) {
+            list.add(i);
+        }
+
+        readCheckpointsArray(checkpointsNum, list, false);
+        readCheckpointsArray(checkpointsNum, list2, true);
+
+        file.delete();
+
+        System.out.println();
+    }
+
+    private void writeCheckpoints(int checkpointsNum) {
+        BTree bTree;
+        int REPEAT = 10;
+        long time = 0;
+        for (int j = 0; j < REPEAT; j++) {
+            long old = System.currentTimeMillis();
+            bTree = new BTree(BTREE_DEGREE, file, fTrace);
+            for (int i = 0; i < checkpointsNum; i++) {
+                TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(12345 + i), new TmfLongLocation(123456L + i), i);
+                bTree.insert(checkpoint);
+            }
+
+            time += (System.currentTimeMillis() - old);
+            bTree.setIndexComplete();
+            bTree.dispose();
+            if (j != REPEAT - 1) {
+                file.delete();
+            }
+            if (reportProgress) {
+                System.out.print(".");
+            }
+        }
+
+        System.out.println("Write time average: " + (float) time / REPEAT);
+    }
+
+    private void writeCheckpointsArray(int checkpointsNum) {
+        FlatArray array;
+        int REPEAT = 10;
+        long time = 0;
+        for (int j = 0; j < REPEAT; j++) {
+            long old = System.currentTimeMillis();
+            array = new FlatArray(file, fTrace);
+            for (int i = 0; i < checkpointsNum; i++) {
+                TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(12345 + i), new TmfLongLocation(123456L + i), i);
+                array.insert(checkpoint);
+            }
+
+            time += (System.currentTimeMillis() - old);
+            array.setIndexComplete();
+            array.dispose();
+            if (j != REPEAT - 1) {
+                file.delete();
+            }
+            if (reportProgress) {
+                System.out.print(".");
+            }
+        }
+
+        System.out.println("Write time average: " + (float) time / REPEAT);
+    }
+
+
+    private void readCheckpoints(int checkpointsNum, ArrayList<Integer> list, boolean random) {
+        BTree bTree;
+        int REPEAT = 10;
+        long time = 0;
+        long cacheMisses = 0;
+        for (int j = 0; j < REPEAT; j++) {
+            long old = System.currentTimeMillis();
+            bTree = new BTree(BTREE_DEGREE, file, fTrace);
+            for (int i = 0; i < checkpointsNum; i++) {
+                Integer randomCheckpoint = list.get(i);
+                TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(12345 + randomCheckpoint), new TmfLongLocation(123456L + randomCheckpoint), 0);
+                BTreeCheckpointVisitor treeVisitor = new BTreeCheckpointVisitor(checkpoint);
+                bTree.accept(treeVisitor);
+                assertEquals(randomCheckpoint.intValue(), treeVisitor.getCheckpoint().getCheckpointRank());
+            }
+            time += (System.currentTimeMillis() - old);
+            cacheMisses = bTree.getCacheMisses();
+            bTree.dispose();
+            if (reportProgress) {
+                System.out.print(".");
+            }
+        }
+
+        System.out.println("Read " + (random ? "(random)" : "(linear)") + "time average: " + (float) time / REPEAT + "            (cache miss: " + cacheMisses + ")");
+    }
+
+    private void readCheckpointsArray(int checkpointsNum, ArrayList<Integer> list, boolean random) {
+        FlatArray array;
+        int REPEAT = 10;
+        long time = 0;
+        long cacheMisses = 0;
+        for (int j = 0; j < REPEAT; j++) {
+            long old = System.currentTimeMillis();
+            array = new FlatArray(file, fTrace);
+            for (int i = 0; i < checkpointsNum; i++) {
+                Integer randomCheckpoint = list.get(i);
+                TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(12345 + randomCheckpoint), new TmfLongLocation(123456L + randomCheckpoint), 0);
+                long found = array.binarySearch(checkpoint);
+                assertEquals(randomCheckpoint.intValue(), found);
+            }
+            time += (System.currentTimeMillis() - old);
+            cacheMisses = array.getCacheMisses();
+            array.dispose();
+            if (reportProgress) {
+                System.out.print(".");
+            }
+        }
+
+        System.out.println("Read " + (random ? "(random)" : "(linear)") + "time average: " + (float) time / REPEAT + "            (cache miss: " + cacheMisses + ")");
+    }
+
+}
diff --git a/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/AllTests.java b/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/AllTests.java
new file mode 100644 (file)
index 0000000..0cc9a11
--- /dev/null
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * 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
+ *
+ * Contributors:
+ *     Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.core.tests.trace.indexer;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+/**
+ * Test suite indexer classes
+ *
+ * @author Marc-Andre Laperle
+ */
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+    BTreeTest.class,
+    FlatArrayTest.class,
+    TmfMemoryIndexTest.class
+})
+public class AllTests {
+
+}
\ No newline at end of file
diff --git a/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/BTreeTest.java b/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/BTreeTest.java
new file mode 100644 (file)
index 0000000..d3cbc86
--- /dev/null
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * 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
+ *
+ * Contributors:
+ *     Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.core.tests.trace.indexer;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+
+import org.eclipse.linuxtools.internal.tmf.core.trace.indexer.BTree;
+import org.eclipse.linuxtools.internal.tmf.core.trace.indexer.BTreeCheckpointVisitor;
+import org.eclipse.linuxtools.internal.tmf.core.trace.indexer.IBTreeVisitor;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.ITmfPersistentlyIndexable;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.TmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.location.TmfLongLocation;
+import org.junit.Test;
+
+/**
+ * Tests for the BTree class
+ *
+ * @author Marc-Andre Laperle
+ */
+public class BTreeTest extends AbstractCheckpointCollectionTest {
+
+    private final int DEGREE = 15;
+    private BTree fBTree;
+
+    @Override
+    protected BTree createCollection() {
+        fBTree = new BTree(DEGREE, getFile(), (ITmfPersistentlyIndexable) getTrace());
+        return fBTree;
+    }
+
+    @Override
+    public boolean isPersistableCollection() {
+        return true;
+    }
+
+    /**
+     * Tests that accepts find the correct checkpoint and ends with a perfect
+     * match
+     */
+    @Test
+    public void testAccept() {
+        for (int i = 0; i < CHECKPOINTS_INSERT_NUM; i++) {
+            TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(i), new TmfLongLocation((long) i), 0);
+            fBTree.insert(checkpoint);
+        }
+
+        final TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(123), new TmfLongLocation(123L), 0);
+
+        class TestVisitor implements IBTreeVisitor {
+            public int fLastCompare = 0;
+            ITmfCheckpoint fFoundCheckpoint;
+
+            @Override
+            public int compare(ITmfCheckpoint checkRec) {
+                fLastCompare = checkRec.compareTo(checkpoint);
+                if (fLastCompare == 0) {
+                    fFoundCheckpoint = checkRec;
+                }
+                return fLastCompare;
+            }
+        }
+        final TestVisitor t = new TestVisitor();
+
+        fBTree.accept(t);
+
+        assertEquals(checkpoint, t.fFoundCheckpoint);
+        assertEquals(0, t.fLastCompare);
+    }
+
+    /**
+     * Test many checkpoint insertions. Make sure they can be found after
+     * re-opening the file
+     */
+    @Test
+    public void testInsertAlotCheckEquals() {
+        ArrayList<Integer> list = insertAlot();
+
+        fBTree = createCollection();
+
+        for (int i = 0; i < CHECKPOINTS_INSERT_NUM; i++) {
+            Integer checkpointIndex = list.get(i);
+            TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(12345 + checkpointIndex), new TmfLongLocation(123456L + checkpointIndex), 0);
+            BTreeCheckpointVisitor treeVisitor = new BTreeCheckpointVisitor(checkpoint);
+            fBTree.accept(treeVisitor);
+            assertEquals(checkpoint, treeVisitor.getCheckpoint());
+        }
+    }
+
+    /**
+     * Test setSize, size
+     */
+    @Override
+    @Test
+    public void testSetGetSize() {
+        assertEquals(0, fBTree.size());
+        int expected = CHECKPOINTS_INSERT_NUM;
+        for (int i = 0; i < expected; ++i) {
+            fBTree.insert(new TmfCheckpoint(new TmfTimestamp(0), new TmfLongLocation(0L), 0));
+            fBTree.setSize(fBTree.size() + 1);
+        }
+        assertEquals(expected, fBTree.size());
+    }
+
+}
diff --git a/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/FlatArrayTest.java b/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/FlatArrayTest.java
new file mode 100644 (file)
index 0000000..539d75b
--- /dev/null
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * 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
+ *
+ * Contributors:
+ *     Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.core.tests.trace.indexer;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+
+import org.eclipse.linuxtools.internal.tmf.core.trace.indexer.FlatArray;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.ITmfPersistentlyIndexable;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.TmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.location.TmfLongLocation;
+import org.junit.Test;
+
+/**
+ * Tests for the FlatArray class
+ *
+ * @author Marc-Andre Laperle
+ */
+public class FlatArrayTest extends AbstractCheckpointCollectionTest {
+
+    private FlatArray fFlatArray;
+
+    @Override
+    protected FlatArray createCollection() {
+        fFlatArray = new FlatArray(getFile(), (ITmfPersistentlyIndexable) getTrace());
+        return fFlatArray;
+    }
+
+    @Override
+    public boolean isPersistableCollection() {
+        return true;
+    }
+
+    /**
+     * Tests that binarySearch find the correct checkpoint and ends with a
+     * perfect match
+     */
+    @Test
+    public void testBinarySearch() {
+        for (long i = 0; i < CHECKPOINTS_INSERT_NUM; i++) {
+            TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(i), new TmfLongLocation(i), 0);
+            fFlatArray.insert(checkpoint);
+        }
+
+        TmfCheckpoint expectedCheckpoint = new TmfCheckpoint(new TmfTimestamp(122), new TmfLongLocation(122L), 0);
+        int expectedRank = 122;
+
+        long rank = fFlatArray.binarySearch(expectedCheckpoint);
+        ITmfCheckpoint found = fFlatArray.get(rank);
+
+        assertEquals(expectedRank, rank);
+        assertEquals(found, expectedCheckpoint);
+    }
+
+    /**
+     * Test many checkpoint insertions. Make sure they can be found after
+     * re-opening the file
+     */
+    @Test
+    public void testInsertAlotCheckEquals() {
+        ArrayList<Integer> list = insertAlot();
+
+        fFlatArray = createCollection();
+
+        for (int i = 0; i < CHECKPOINTS_INSERT_NUM; i++) {
+            Integer checkpointIndex = list.get(i);
+            TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(12345 + checkpointIndex), new TmfLongLocation(123456L + checkpointIndex), checkpointIndex);
+            ITmfCheckpoint found = fFlatArray.get(checkpointIndex);
+            assertEquals(checkpoint, found);
+        }
+    }
+
+}
diff --git a/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/TmfMemoryIndexTest.java b/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/TmfMemoryIndexTest.java
new file mode 100644 (file)
index 0000000..40d3562
--- /dev/null
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * 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
+ *
+ * Contributors:
+ *     Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.core.tests.trace.indexer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.linuxtools.internal.tmf.core.trace.indexer.TmfMemoryIndex;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.TmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.location.TmfLongLocation;
+import org.junit.Test;
+
+/**
+ * Test for the TmfMemoryIndex class
+ *
+ * @author Marc-Andre Laperle
+ */
+public class TmfMemoryIndexTest extends AbstractCheckpointCollectionTest {
+
+    private TmfMemoryIndex fMemoryIndex;
+
+    @Override
+    protected TmfMemoryIndex createCollection() {
+        fMemoryIndex = new TmfMemoryIndex(getTrace());
+        return fMemoryIndex;
+    }
+
+    /**
+     * Test a single insertion
+     */
+    @Override
+    @Test
+    public void testInsert() {
+        TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(12345), new TmfLongLocation(123456L), 0);
+        fMemoryIndex.insert(checkpoint);
+
+        ITmfCheckpoint indexCheckpoint = fMemoryIndex.get(0);
+        assertEquals(checkpoint, indexCheckpoint);
+
+        long found = fMemoryIndex.binarySearch(checkpoint);
+        assertEquals(0, found);
+    }
+
+    /**
+     * Tests that binarySearch find the correct checkpoint and ends with a perfect match
+     */
+    @Test
+    public void testBinarySearch() {
+        for (long i = 0; i < CHECKPOINTS_INSERT_NUM; i++) {
+            TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(i), new TmfLongLocation(i), 0);
+            fMemoryIndex.insert(checkpoint);
+        }
+
+        TmfCheckpoint expectedCheckpoint = new TmfCheckpoint(new TmfTimestamp(122), new TmfLongLocation(122L), 0);
+        int expectedRank = 122;
+
+        long rank = fMemoryIndex.binarySearch(expectedCheckpoint);
+        ITmfCheckpoint found = fMemoryIndex.get(rank);
+
+        assertEquals(expectedRank, rank);
+        assertEquals(found, expectedCheckpoint);
+    }
+
+    /**
+     * Test dispose
+     */
+    @Test
+    public void testDispose() {
+        fMemoryIndex.dispose();
+        assertTrue(fMemoryIndex.isEmpty());
+    }
+}
diff --git a/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/AbstractIndexTest.java b/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/AbstractIndexTest.java
new file mode 100644 (file)
index 0000000..6c83b91
--- /dev/null
@@ -0,0 +1,273 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2013 Ericsson
+ *
+ * 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
+ *
+ * Contributors:
+ *   Francois Chouinard - Initial API and implementation
+ *   Francois Chouinard - Adapted for TMF Trace Model 1.0
+ *   Alexandre Montplaisir - Port to JUnit4
+ *   Marc-Andre Laperle - Extracted to a common class from TmfCheckpointIndexTest
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.core.tests.trace.indexer.checkpoint;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
+import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException;
+import org.eclipse.linuxtools.tmf.core.tests.TmfCoreTestPlugin;
+import org.eclipse.linuxtools.tmf.core.tests.shared.TmfTestTrace;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
+import org.eclipse.linuxtools.tmf.core.trace.TmfContext;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.ITmfTraceIndexer;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpointIndex;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.TmfCheckpointIndexer;
+import org.eclipse.linuxtools.tmf.tests.stubs.trace.TmfEmptyTraceStub;
+import org.eclipse.linuxtools.tmf.tests.stubs.trace.TmfTraceStub;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Common code for index testing
+ *
+ * @author Marc-Andre Laperle
+ */
+public abstract class AbstractIndexTest {
+
+    // ------------------------------------------------------------------------
+    // Variables
+    // ------------------------------------------------------------------------
+
+    /**
+     *
+     */
+    protected static final int BLOCK_SIZE = 100;
+    private static final int NB_EVENTS = 10000;
+    /**
+     * The trace being tested
+     */
+    protected static TestTrace fTrace = null;
+    private static EmptyTestTrace fEmptyTrace = null;
+
+    // ------------------------------------------------------------------------
+    // Housekeeping
+    // ------------------------------------------------------------------------
+
+    /**
+     * Setup the test
+     */
+    @Before
+    public void setUp() {
+        setupTrace(getTracePath());
+    }
+
+    /**
+     * Get the trace path
+     *
+     * @return the trace path
+     */
+    protected String getTracePath() {
+        return TmfTestTrace.A_TEST_10K.getFullPath();
+    }
+
+    /**
+     * Tear down the test
+     */
+    @After
+    public void tearDown() {
+        fTrace.dispose();
+        fTrace = null;
+        fEmptyTrace.dispose();
+        fEmptyTrace = null;
+    }
+
+    interface TestIndexerInterface extends ITmfTraceIndexer {
+        ITmfCheckpointIndex getCheckpoints();
+    }
+
+    // ------------------------------------------------------------------------
+    // Helper classes
+    // ------------------------------------------------------------------------
+
+    /**
+     * A test indexer
+     */
+    protected static class TestIndexer extends TmfCheckpointIndexer implements TestIndexerInterface {
+        /**
+         * Constructs the test indexer for a normal test trace
+         *
+         * @param testTrace
+         *            the test trace
+         */
+        public TestIndexer(ITmfTrace testTrace) {
+            super(testTrace, BLOCK_SIZE);
+        }
+
+        @Override
+        public ITmfCheckpointIndex getCheckpoints() {
+            return getTraceIndex();
+        }
+    }
+
+    /**
+     * Create the indexer for testing
+     *
+     * @param trace
+     *            the trace
+     * @return the indexer for testing
+     */
+    protected TestIndexerInterface createTestIndexer(TestTrace trace) {
+        return new TestIndexer(trace);
+    }
+
+    /**
+     * A test trace
+     */
+    protected class TestTrace extends TmfTraceStub {
+        /**
+         *
+         * @param path
+         *            the path
+         * @param blockSize
+         *            the block size
+         * @throws TmfTraceException
+         *             when error occurs
+         */
+        public TestTrace(String path, int blockSize) throws TmfTraceException {
+            super(path, blockSize, false, null, null);
+            setIndexer(createTestIndexer(this));
+        }
+
+        @Override
+        public TestIndexerInterface getIndexer() {
+            return (TestIndexerInterface) super.getIndexer();
+        }
+    }
+
+    private class EmptyTestTrace extends TmfEmptyTraceStub {
+        public EmptyTestTrace() {
+            super();
+            setIndexer(new TestIndexer(this));
+        }
+
+        @Override
+        public TestIndexer getIndexer() {
+            return (TestIndexer) super.getIndexer();
+        }
+    }
+
+    // ------------------------------------------------------------------------
+    // Helper functions
+    // ------------------------------------------------------------------------
+
+    /**
+     * Creates the trace for the specified path
+     *
+     * @param path
+     *            the path
+     * @return the created trace
+     * @throws URISyntaxException
+     *             when error occurs
+     * @throws IOException
+     *             when error occurs
+     * @throws TmfTraceException
+     *             when error occurs
+     */
+    protected TestTrace createTrace(final String path) throws URISyntaxException, IOException, TmfTraceException {
+        final URL location = FileLocator.find(TmfCoreTestPlugin.getDefault().getBundle(), new Path(path), null);
+        final File test = new File(FileLocator.toFileURL(location).toURI());
+        TestTrace trace = new TestTrace(test.toURI().getPath(), BLOCK_SIZE);
+        trace.indexTrace(true);
+        return trace;
+    }
+
+    private synchronized void setupTrace(final String path) {
+        if (fTrace == null) {
+            try {
+                fTrace = createTrace(path);
+            } catch (final TmfTraceException e) {
+                fail(e.getMessage());
+            } catch (final URISyntaxException e) {
+                fail(e.getMessage());
+            } catch (final IOException e) {
+                fail(e.getMessage());
+            }
+        }
+
+        if (fEmptyTrace == null) {
+            fEmptyTrace = new EmptyTestTrace();
+            fEmptyTrace.indexTrace(true);
+        }
+    }
+
+    // ------------------------------------------------------------------------
+    // Verify checkpoints
+    // ------------------------------------------------------------------------
+
+    /**
+     * Test the content of the index after building the full index
+     */
+    @Test
+    public void testTmfTraceIndexing() {
+        verifyIndexContent();
+    }
+
+    /**
+     * Verify the content of the index
+     */
+    protected static void verifyIndexContent() {
+        assertEquals(BLOCK_SIZE, fTrace.getCacheSize());
+        assertEquals(NB_EVENTS, fTrace.getNbEvents());
+        assertEquals(1, fTrace.getTimeRange().getStartTime().getValue());
+        assertEquals(NB_EVENTS, fTrace.getTimeRange().getEndTime().getValue());
+        assertEquals(1, fTrace.getStartTime().getValue());
+        assertEquals(NB_EVENTS, fTrace.getEndTime().getValue());
+
+        ITmfCheckpointIndex checkpoints = fTrace.getIndexer().getCheckpoints();
+        int pageSize = fTrace.getCacheSize();
+        assertTrue(checkpoints != null);
+        assertEquals(NB_EVENTS / BLOCK_SIZE, checkpoints.size());
+
+        // Validate that each checkpoint points to the right event
+        for (int i = 0; i < checkpoints.size(); i++) {
+            ITmfCheckpoint checkpoint = checkpoints.get(i);
+            TmfContext context = new TmfContext(checkpoint.getLocation(), i * pageSize);
+            ITmfEvent event = fTrace.parseEvent(context);
+            assertEquals(context.getRank(), i * pageSize);
+            assertTrue((checkpoint.getTimestamp().compareTo(event.getTimestamp(), false) == 0));
+        }
+    }
+
+    /**
+     * Test that a empty trace has the correct content
+     */
+    @Test
+    public void testEmptyTmfTraceIndexing() {
+        assertEquals(ITmfTrace.DEFAULT_TRACE_CACHE_SIZE, fEmptyTrace.getCacheSize());
+        assertEquals(0, fEmptyTrace.getNbEvents());
+        assertEquals(TmfTimestamp.BIG_BANG, fEmptyTrace.getTimeRange().getStartTime());
+        assertEquals(TmfTimestamp.BIG_BANG, fEmptyTrace.getTimeRange().getEndTime());
+        assertEquals(TmfTimestamp.BIG_BANG, fEmptyTrace.getStartTime());
+        assertEquals(TmfTimestamp.BIG_BANG, fEmptyTrace.getEndTime());
+
+        ITmfCheckpointIndex checkpoints = fEmptyTrace.getIndexer().getCheckpoints();
+        assertTrue(checkpoints != null);
+        assertEquals(0, checkpoints.size());
+    }
+}
index 0c5856ac8b8c358876eb740c2521d667b79a6b1c..43ab0a43ea5a10f9dddac0730bf8f5c358d1914c 100644 (file)
@@ -20,6 +20,7 @@ import org.junit.runners.Suite;
  */
 @RunWith(Suite.class)
 @Suite.SuiteClasses({
+    TmfBTreeIndexTest.class,
     TmfCheckpointIndexTest.class,
     TmfCheckpointIndexTest2.class,
     TmfCheckpointTest.class,
diff --git a/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/TmfBTreeIndexTest.java b/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/TmfBTreeIndexTest.java
new file mode 100644 (file)
index 0000000..f522a95
--- /dev/null
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2013 Ericsson
+ *
+ * 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
+ *
+ * Contributors:
+ *   Francois Chouinard - Initial API and implementation
+ *   Francois Chouinard - Adapted for TMF Trace Model 1.0
+ *   Alexandre Montplaisir - Port to JUnit4
+ *   Marc-Andre Laperle - Adapted to BTree indexer from TmfCheckpointIndexTest
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.core.tests.trace.indexer.checkpoint;
+
+import static org.junit.Assert.assertFalse;
+
+import org.eclipse.linuxtools.tmf.core.trace.indexer.TmfBTreeTraceIndexer;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpointIndex;
+import org.junit.Test;
+
+/**
+ * Test suite for the TmfBTreeTraceIndexer class.
+ *
+ * @author Marc-Andre Laperle
+ */
+public class TmfBTreeIndexTest extends AbstractIndexTest {
+
+    /**
+     * Create the indexer for testing
+     *
+     * @param trace
+     *            the trace
+     * @return the indexer for testing
+     */
+    @Override
+    protected TestIndexerInterface createTestIndexer(TestTrace trace) {
+        return new TestBTreeIndexer(trace);
+    }
+
+    private static class TestBTreeIndexer extends TmfBTreeTraceIndexer implements TestIndexerInterface {
+        public TestBTreeIndexer(TestTrace testTrace) {
+            super(testTrace, BLOCK_SIZE);
+        }
+
+        @Override
+        public ITmfCheckpointIndex getCheckpoints() {
+            return getTraceIndex();
+        }
+    }
+
+    /**
+     * Test that a fully built index has the same content when reloaded from disk
+     *
+     * @throws Exception when error occurs
+     */
+    @Test
+    public void testReopenIndex() throws Exception {
+        fTrace.dispose();
+        fTrace = createTrace(getTracePath());
+        assertFalse(fTrace.getIndexer().getCheckpoints().isCreatedFromScratch());
+        fTrace.indexTrace(true);
+
+        verifyIndexContent();
+    }
+
+}
\ No newline at end of file
index 52cd6b0d7ab1495d9c1fdfa0b6da03c0166dcf5d..6eba8a3c3c5be6cbbcefd52b0ded04369e37e580 100644 (file)
 
 package org.eclipse.linuxtools.tmf.core.tests.trace.indexer.checkpoint;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.util.List;
-
-import org.eclipse.core.runtime.FileLocator;
-import org.eclipse.core.runtime.Path;
-import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
-import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException;
-import org.eclipse.linuxtools.tmf.core.tests.TmfCoreTestPlugin;
-import org.eclipse.linuxtools.tmf.core.tests.shared.TmfTestTrace;
-import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
-import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
-import org.eclipse.linuxtools.tmf.core.trace.TmfContext;
-import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.TmfCheckpointIndexer;
-import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
-import org.eclipse.linuxtools.tmf.tests.stubs.trace.TmfEmptyTraceStub;
-import org.eclipse.linuxtools.tmf.tests.stubs.trace.TmfTraceStub;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
 
 /**
  * Test suite for the TmfCheckpointIndexTest class.
  */
-@SuppressWarnings("javadoc")
-public class TmfCheckpointIndexTest {
-
-    // ------------------------------------------------------------------------
-    // Variables
-    // ------------------------------------------------------------------------
-
-    private static final int       BLOCK_SIZE  = 100;
-    private static final int       NB_EVENTS   = 10000;
-    private static TestTrace       fTrace      = null;
-    private static EmptyTestTrace  fEmptyTrace = null;
-
-    // ------------------------------------------------------------------------
-    // Housekeeping
-    // ------------------------------------------------------------------------
-
-    @Before
-    public void setUp() {
-        setupTrace(TmfTestTrace.A_TEST_10K.getFullPath());
-    }
-
-    @After
-    public void tearDown() {
-        fTrace.dispose();
-        fTrace = null;
-        fEmptyTrace.dispose();
-        fEmptyTrace = null;
-    }
-
-    // ------------------------------------------------------------------------
-    // Helper classes
-    // ------------------------------------------------------------------------
-
-    private static class TestIndexer extends TmfCheckpointIndexer {
-        @SuppressWarnings({ })
-        public TestIndexer(TestTrace testTrace) {
-            super(testTrace, BLOCK_SIZE);
-        }
-        @SuppressWarnings({ })
-        public TestIndexer(EmptyTestTrace testTrace) {
-            super(testTrace, BLOCK_SIZE);
-        }
-        public List<ITmfCheckpoint> getCheckpoints() {
-            return getTraceIndex();
-        }
-    }
-
-    private class TestTrace extends TmfTraceStub {
-        public TestTrace(String path, int blockSize) throws TmfTraceException {
-            super(path, blockSize, false, null, null);
-            setIndexer(new TestIndexer(this));
-        }
-        @Override
-        public TestIndexer getIndexer() {
-            return (TestIndexer) super.getIndexer();
-        }
-    }
-
-    private class EmptyTestTrace extends TmfEmptyTraceStub {
-        public EmptyTestTrace() {
-            super();
-            setIndexer(new TestIndexer(this));
-        }
-        @Override
-        public TestIndexer getIndexer() {
-            return (TestIndexer) super.getIndexer();
-        }
-    }
-
-    // ------------------------------------------------------------------------
-    // Helper functions
-    // ------------------------------------------------------------------------
-
-    private synchronized void setupTrace(final String path) {
-        if (fTrace == null) {
-            try {
-                final URL location = FileLocator.find(TmfCoreTestPlugin.getDefault().getBundle(), new Path(path), null);
-                final File test = new File(FileLocator.toFileURL(location).toURI());
-                fTrace = new TestTrace(test.toURI().getPath(), BLOCK_SIZE);
-                fTrace.indexTrace(true);
-            } catch (final TmfTraceException e) {
-                e.printStackTrace();
-            } catch (final URISyntaxException e) {
-                e.printStackTrace();
-            } catch (final IOException e) {
-                e.printStackTrace();
-            }
-        }
-
-        if (fEmptyTrace == null) {
-            fEmptyTrace = new EmptyTestTrace();
-            fEmptyTrace.indexTrace(true);
-        }
-    }
-
-    // ------------------------------------------------------------------------
-    // Verify checkpoints
-    // ------------------------------------------------------------------------
-
-    @Test
-    public void testTmfTraceIndexing() {
-        assertEquals("getCacheSize",   BLOCK_SIZE, fTrace.getCacheSize());
-        assertEquals("getTraceSize",   NB_EVENTS,  fTrace.getNbEvents());
-        assertEquals("getRange-start", 1,          fTrace.getTimeRange().getStartTime().getValue());
-        assertEquals("getRange-end",   NB_EVENTS,  fTrace.getTimeRange().getEndTime().getValue());
-        assertEquals("getStartTime",   1,          fTrace.getStartTime().getValue());
-        assertEquals("getEndTime",     NB_EVENTS,  fTrace.getEndTime().getValue());
-
-        List<ITmfCheckpoint> checkpoints = fTrace.getIndexer().getCheckpoints();
-        int pageSize = fTrace.getCacheSize();
-        assertTrue("Checkpoints exist",  checkpoints != null);
-        assertEquals("Checkpoints size", NB_EVENTS / BLOCK_SIZE, checkpoints.size());
-
-        // Validate that each checkpoint points to the right event
-        for (int i = 0; i < checkpoints.size(); i++) {
-            ITmfCheckpoint checkpoint = checkpoints.get(i);
-            TmfContext context = new TmfContext(checkpoint.getLocation(), i * pageSize);
-            ITmfEvent event = fTrace.parseEvent(context);
-            assertTrue(context.getRank() == i * pageSize);
-            assertTrue((checkpoint.getTimestamp().compareTo(event.getTimestamp(), false) == 0));
-        }
-    }
-
-    @Test
-    public void testEmptyTmfTraceIndexing() {
-        assertEquals("getCacheSize",   ITmfTrace.DEFAULT_TRACE_CACHE_SIZE, fEmptyTrace.getCacheSize());
-        assertEquals("getTraceSize",   0,  fEmptyTrace.getNbEvents());
-        assertEquals("getRange-start", TmfTimestamp.BIG_BANG, fEmptyTrace.getTimeRange().getStartTime());
-        assertEquals("getRange-end",   TmfTimestamp.BIG_BANG, fEmptyTrace.getTimeRange().getEndTime());
-        assertEquals("getStartTime",   TmfTimestamp.BIG_BANG, fEmptyTrace.getStartTime());
-        assertEquals("getEndTime",     TmfTimestamp.BIG_BANG, fEmptyTrace.getEndTime());
-
-        List<ITmfCheckpoint> checkpoints = fEmptyTrace.getIndexer().getCheckpoints();
-        int pageSize = fEmptyTrace.getCacheSize();
-        assertTrue("Checkpoints exist",  checkpoints != null);
-        assertEquals("Checkpoints size", 0, checkpoints.size());
-
-        // Validate that each checkpoint points to the right event
-        for (int i = 0; i < checkpoints.size(); i++) {
-            ITmfCheckpoint checkpoint = checkpoints.get(i);
-            TmfContext context = new TmfContext(checkpoint.getLocation(), i * pageSize);
-            ITmfEvent event = fEmptyTrace.parseEvent(context);
-            assertTrue(context.getRank() == i * pageSize);
-            assertTrue((checkpoint.getTimestamp().compareTo(event.getTimestamp(), false) == 0));
-        }
-    }
+public class TmfCheckpointIndexTest extends AbstractIndexTest {
 
 }
\ No newline at end of file
index 4fac680dc9e92118755bfd79527cc768b7da5a34..21a869789f2b7b6974aa9c72159f7a499a4a5654 100644 (file)
@@ -21,7 +21,6 @@ import java.io.File;
 import java.io.IOException;
 import java.net.URISyntaxException;
 import java.net.URL;
-import java.util.List;
 
 import org.eclipse.core.runtime.FileLocator;
 import org.eclipse.core.runtime.Path;
@@ -31,8 +30,8 @@ import org.eclipse.linuxtools.tmf.core.tests.TmfCoreTestPlugin;
 import org.eclipse.linuxtools.tmf.core.tests.shared.TmfTestTrace;
 import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
 import org.eclipse.linuxtools.tmf.core.trace.ITmfContext;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpointIndex;
 import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.TmfCheckpointIndexer;
-import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
 import org.eclipse.linuxtools.tmf.tests.stubs.trace.TmfEmptyTraceStub;
 import org.eclipse.linuxtools.tmf.tests.stubs.trace.TmfTraceStub;
 import org.junit.After;
@@ -87,7 +86,7 @@ public class TmfCheckpointIndexTest2 {
         public TestIndexer(EmptyTestTrace testTrace) {
             super(testTrace, BLOCK_SIZE);
         }
-        public List<ITmfCheckpoint> getCheckpoints() {
+        public ITmfCheckpointIndex getCheckpoints() {
             return getTraceIndex();
         }
     }
@@ -153,7 +152,7 @@ public class TmfCheckpointIndexTest2 {
         assertEquals("getStartTime",   1,          fTrace.getStartTime().getValue());
         assertEquals("getEndTime",     102,        fTrace.getEndTime().getValue());
 
-        List<ITmfCheckpoint> checkpoints = fTrace.getIndexer().getCheckpoints();
+        ITmfCheckpointIndex checkpoints = fTrace.getIndexer().getCheckpoints();
         assertTrue("Checkpoints exist",  checkpoints != null);
         assertEquals("Checkpoints size", NB_EVENTS / BLOCK_SIZE + 1, checkpoints.size());
 
index cb0871cd1fc92365f8a2c98ca9a0087154e0cda9..925084a7d331b1b2d6311b8fe8b165ac3c40ae09 100644 (file)
@@ -44,13 +44,17 @@ public class TmfCheckpointTest {
     private Long aLong1 = 12345L;
     private Long aLong2 = 23456L;
     private Long aLong3 = 34567L;
+    private Long RANK1 = 1L;
+    private Long RANK2 = 2L;
+    private Long RANK3 = 3L;
+
     private ITmfLocation fLocation1 = new TmfLongLocation(aLong1);
     private ITmfLocation fLocation2 = new TmfLongLocation(aLong2);
     private ITmfLocation fLocation3 = new TmfLongLocation(aLong3);
 
-    private TmfCheckpoint fCheckpoint1 = new TmfCheckpoint(fTimestamp1, fLocation1);
-    private TmfCheckpoint fCheckpoint2 = new TmfCheckpoint(fTimestamp2, fLocation2);
-    private TmfCheckpoint fCheckpoint3 = new TmfCheckpoint(fTimestamp3, fLocation3);
+    private TmfCheckpoint fCheckpoint1 = new TmfCheckpoint(fTimestamp1, fLocation1, RANK1);
+    private TmfCheckpoint fCheckpoint2 = new TmfCheckpoint(fTimestamp2, fLocation2, RANK2);
+    private TmfCheckpoint fCheckpoint3 = new TmfCheckpoint(fTimestamp3, fLocation3, RANK3);
 
     // ------------------------------------------------------------------------
     // Constructors
@@ -104,10 +108,10 @@ public class TmfCheckpointTest {
 
     @Test
     public void testCompareToNull() {
-        final TmfCheckpoint checkpoint1 = new TmfCheckpoint(null, fLocation1);
-        final TmfCheckpoint checkpoint2 = new TmfCheckpoint(null, fLocation2);
-        final TmfCheckpoint checkpoint3 = new TmfCheckpoint(null, fLocation3);
-        final TmfCheckpoint checkpoint4 = new TmfCheckpoint(null, fLocation1);
+        final TmfCheckpoint checkpoint1 = new TmfCheckpoint(null, fLocation1, RANK1);
+        final TmfCheckpoint checkpoint2 = new TmfCheckpoint(null, fLocation2, RANK2);
+        final TmfCheckpoint checkpoint3 = new TmfCheckpoint(null, fLocation3, RANK3);
+        final TmfCheckpoint checkpoint4 = new TmfCheckpoint(null, fLocation1, RANK1);
 
         // Test the various 'null' vs. '!null' combinations
         assertEquals("compareTo",  0, checkpoint1.compareTo(fCheckpoint1));
@@ -144,8 +148,8 @@ public class TmfCheckpointTest {
 
     @Test
     public void testHashCodeNull() {
-        final TmfCheckpoint checkpoint1 = new TmfCheckpoint(null, fLocation1);
-        final TmfCheckpoint checkpoint2 = new TmfCheckpoint(fTimestamp1, null);
+        final TmfCheckpoint checkpoint1 = new TmfCheckpoint(null, fLocation1, RANK1);
+        final TmfCheckpoint checkpoint2 = new TmfCheckpoint(fTimestamp1, null, RANK1);
         final TmfCheckpoint checkpoint3 = new TmfCheckpoint(checkpoint1);
         final TmfCheckpoint checkpoint4 = new TmfCheckpoint(checkpoint2);
 
@@ -195,11 +199,11 @@ public class TmfCheckpointTest {
     @Test
     public void testNotEqual() {
         // Various checkpoints
-        final TmfCheckpoint checkpoint1 = new TmfCheckpoint(fTimestamp1, fLocation1);
-        final TmfCheckpoint checkpoint2 = new TmfCheckpoint(fTimestamp2, fLocation1);
-        final TmfCheckpoint checkpoint3 = new TmfCheckpoint(fTimestamp1, fLocation2);
-        final TmfCheckpoint checkpoint4 = new TmfCheckpoint(fTimestamp1, null);
-        final TmfCheckpoint checkpoint5 = new TmfCheckpoint(null, fLocation1);
+        final TmfCheckpoint checkpoint1 = new TmfCheckpoint(fTimestamp1, fLocation1, RANK1);
+        final TmfCheckpoint checkpoint2 = new TmfCheckpoint(fTimestamp2, fLocation1, RANK1);
+        final TmfCheckpoint checkpoint3 = new TmfCheckpoint(fTimestamp1, fLocation2, RANK2);
+        final TmfCheckpoint checkpoint4 = new TmfCheckpoint(fTimestamp1, null, RANK1);
+        final TmfCheckpoint checkpoint5 = new TmfCheckpoint(null, fLocation1, RANK1);
 
         // Null check
         assertFalse("equals", checkpoint1.equals(null));
@@ -225,11 +229,11 @@ public class TmfCheckpointTest {
     @Test
     public void testToString() {
         final String expected1 = "TmfCheckpoint [fLocation=" + fCheckpoint1.getLocation() +
-                ", fTimestamp=" + fCheckpoint1.getTimestamp() + "]";
+                ", fTimestamp=" + fCheckpoint1.getTimestamp() + ", fCheckpointRank=" + fCheckpoint1.getCheckpointRank() + "]";
         final String expected2 = "TmfCheckpoint [fLocation=" + fCheckpoint2.getLocation() +
-                ", fTimestamp=" + fCheckpoint2.getTimestamp() + "]";
+                ", fTimestamp=" + fCheckpoint2.getTimestamp() + ", fCheckpointRank=" + fCheckpoint2.getCheckpointRank() + "]";
         final String expected3 = "TmfCheckpoint [fLocation=" + fCheckpoint3.getLocation() +
-                ", fTimestamp=" + fCheckpoint3.getTimestamp() + "]";
+                ", fTimestamp=" + fCheckpoint3.getTimestamp() + ", fCheckpointRank=" + fCheckpoint3.getCheckpointRank() + "]";
 
         assertEquals("toString", expected1, fCheckpoint1.toString());
         assertEquals("toString", expected2, fCheckpoint2.toString());
index 114ee2c8dacd5475cf707b4d2c791157a52239a6..879a35f3614ed9475f1f9ece01973b47deb86027 100644 (file)
@@ -21,7 +21,6 @@ import java.io.File;
 import java.io.IOException;
 import java.net.URISyntaxException;
 import java.net.URL;
-import java.util.List;
 
 import org.eclipse.core.runtime.FileLocator;
 import org.eclipse.core.runtime.Path;
@@ -34,6 +33,7 @@ import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
 import org.eclipse.linuxtools.tmf.core.trace.ITmfContext;
 import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
 import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpointIndex;
 import org.eclipse.linuxtools.tmf.core.trace.location.ITmfLocation;
 import org.eclipse.linuxtools.tmf.tests.stubs.trace.TmfExperimentStub;
 import org.eclipse.linuxtools.tmf.tests.stubs.trace.TmfTraceStub;
@@ -115,7 +115,7 @@ public class TmfExperimentCheckpointIndexTest {
         assertEquals("getStartTime",   1,          fExperiment.getStartTime().getValue());
         assertEquals("getEndTime",     NB_EVENTS,  fExperiment.getEndTime().getValue());
 
-        List<ITmfCheckpoint> checkpoints = fExperiment.getIndexer().getCheckpoints();
+        ITmfCheckpointIndex checkpoints = fExperiment.getIndexer().getCheckpoints();
         int pageSize = fExperiment.getCacheSize();
         assertTrue("Checkpoints exist",  checkpoints != null);
         assertEquals("Checkpoints size", NB_EVENTS / BLOCK_SIZE, checkpoints.size());
@@ -163,7 +163,7 @@ public class TmfExperimentCheckpointIndexTest {
         experiment.getIndexer().buildIndex(0, range, true);
 
         // Validate that each checkpoint points to the right event
-        List<ITmfCheckpoint> checkpoints = experiment.getIndexer().getCheckpoints();
+        ITmfCheckpointIndex checkpoints = experiment.getIndexer().getCheckpoints();
         assertTrue("Checkpoints exist",  checkpoints != null);
         assertEquals("Checkpoints size", NB_EVENTS / BLOCK_SIZE / 2, checkpoints.size());
 
index fad258f49849ed872dcddeabf4b3a611694caa36..c36cbc050bdc304b2d5ca823ef32db380b3d692a 100644 (file)
@@ -12,6 +12,8 @@
 
 package org.eclipse.linuxtools.tmf.core.tests.trace.location;
 
+import java.nio.ByteBuffer;
+
 import org.eclipse.linuxtools.tmf.core.trace.location.TmfLocation;
 
 /**
@@ -41,4 +43,11 @@ public class TmfStringLocation extends TmfLocation {
         return (String) super.getLocationInfo();
     }
 
+    /**
+     * @since 3.0
+     */
+    @Override
+    public void serialize(ByteBuffer bufferOut) {
+        throw new UnsupportedOperationException();
+    }
 }
index a633f36b0a3c97544c485310d95af631164e2a82..f8258fb5e532cc790fe94dd4818891f7d684e2b4 100644 (file)
 
 package org.eclipse.linuxtools.tmf.tests.stubs.trace;
 
-import java.util.List;
-
 import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpointIndex;
 import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.TmfCheckpointIndexer;
-import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
 
 /**
  * <b><u>TmfIndexerStub</u></b>
@@ -31,7 +29,7 @@ public class TmfIndexerStub extends TmfCheckpointIndexer {
         super(trace, blockSize);
     }
 
-    public List<ITmfCheckpoint> getCheckpoints() {
+    public ITmfCheckpointIndex getCheckpoints() {
         return getTraceIndex();
     }
 
index 8eadfd7266143002b390a6e1bbb575dac5bc9bdf..a2edc417d7c2a8f5265e464fb63f4a915f46b9ec 100644 (file)
@@ -16,6 +16,7 @@ package org.eclipse.linuxtools.tmf.tests.stubs.trace;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
 import java.util.concurrent.locks.ReentrantLock;
 
 import org.eclipse.core.resources.IProject;
@@ -27,11 +28,15 @@ import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
 import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException;
 import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp;
 import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
 import org.eclipse.linuxtools.tmf.core.trace.ITmfContext;
 import org.eclipse.linuxtools.tmf.core.trace.ITmfEventParser;
 import org.eclipse.linuxtools.tmf.core.trace.TmfContext;
 import org.eclipse.linuxtools.tmf.core.trace.TmfTrace;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.ITmfPersistentlyIndexable;
 import org.eclipse.linuxtools.tmf.core.trace.indexer.ITmfTraceIndexer;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.TmfCheckpoint;
 import org.eclipse.linuxtools.tmf.core.trace.location.ITmfLocation;
 import org.eclipse.linuxtools.tmf.core.trace.location.TmfLongLocation;
 
@@ -40,7 +45,7 @@ import org.eclipse.linuxtools.tmf.core.trace.location.TmfLongLocation;
  * <p>
  * Dummy test trace. Use in conjunction with TmfEventParserStub.
  */
-public class TmfTraceStub extends TmfTrace implements ITmfEventParser {
+public class TmfTraceStub extends TmfTrace implements ITmfEventParser, ITmfPersistentlyIndexable {
 
     // ------------------------------------------------------------------------
     // Attributes
@@ -347,4 +352,23 @@ public class TmfTraceStub extends TmfTrace implements ITmfEventParser {
         return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "File does not exist: " + path);
     }
 
+    private static int fCheckpointSize = -1;
+
+    @Override
+    public synchronized int getCheckpointSize() {
+        if (fCheckpointSize == -1) {
+            TmfCheckpoint c = new TmfCheckpoint(new TmfTimestamp(0L), new TmfLongLocation(0L), 0);
+            ByteBuffer b = ByteBuffer.allocate(ITmfCheckpoint.MAX_SERIALIZE_SIZE);
+            b.clear();
+            c.serialize(b);
+            fCheckpointSize = b.position();
+        }
+
+        return fCheckpointSize;
+    }
+
+    @Override
+    public ITmfLocation restoreLocation(ByteBuffer bufferIn) {
+        return new TmfLongLocation(bufferIn);
+    }
 }
index 1b7bf46056df26f4652dabb7a6cc397d3bb7e02e..3d4f71073e342cb3a526ec03528db4f0598338da 100644 (file)
@@ -20,6 +20,7 @@ Export-Package: org.eclipse.linuxtools.internal.tmf.core;x-friends:="org.eclipse
  org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.partial;x-internal:=true,
  org.eclipse.linuxtools.internal.tmf.core.statesystem.mipmap;x-friends:="org.eclipse.linuxtools.tmf.core.tests",
  org.eclipse.linuxtools.internal.tmf.core.trace;x-friends:="org.eclipse.linuxtools.tmf.core.tests",
+ org.eclipse.linuxtools.internal.tmf.core.trace.indexer;x-friends:="org.eclipse.linuxtools.tmf.core.tests",
  org.eclipse.linuxtools.tmf.core,
  org.eclipse.linuxtools.tmf.core.callstack,
  org.eclipse.linuxtools.tmf.core.component,
index bbd7b650dfdcfbaf2624ac6461057f140538833f..4f6edec3c4b2b34c7e9c4a0c0ce8eeabb4e5ebc1 100644 (file)
@@ -14,6 +14,8 @@
 
 package org.eclipse.linuxtools.internal.tmf.core.trace;
 
+import java.nio.ByteBuffer;
+
 import org.eclipse.linuxtools.tmf.core.trace.location.ITmfLocation;
 
 
@@ -106,4 +108,13 @@ public final class TmfExperimentLocation implements ITmfLocation {
         return fLocation;
     }
 
+    @Override
+    public void serialize(ByteBuffer bufferOut) {
+        ITmfLocation[] locations = fLocation.getLocations();
+        long[] ranks = fLocation.getRanks();
+        for (int i = 0; i < locations.length; ++i) {
+            locations[i].serialize(bufferOut);
+            bufferOut.putLong(ranks[i]);
+        }
+    }
 }
diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/AbstractFileCheckpointCollection.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/AbstractFileCheckpointCollection.java
new file mode 100644 (file)
index 0000000..77832f1
--- /dev/null
@@ -0,0 +1,478 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * 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
+ *
+ * Contributors:
+ *     Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.internal.tmf.core.trace.indexer;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.text.MessageFormat;
+
+import org.eclipse.linuxtools.internal.tmf.core.Activator;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.ITmfPersistentlyIndexable;
+
+/**
+ * Common implementation of file-based checkpoint collection
+ *
+ * @author Marc-Andre Laperle
+ */
+public abstract class AbstractFileCheckpointCollection implements ICheckpointCollection {
+
+    private static final int VERSION = 1;
+    private static final int SUB_VERSION_NONE = -1;
+
+    /**
+     * The base file header, can be extended
+     */
+    protected class CheckpointCollectionFileHeader {
+        private final static int SIZE = INT_SIZE +
+                INT_SIZE +
+                LONG_SIZE +
+                LONG_SIZE;
+
+        /**
+         * Get the size of the header in bytes. This should be overridden if the
+         * header is augmented with more data
+         *
+         * @return the size of the header in bytes
+         */
+        public int getSize() {
+            return SIZE;
+        }
+
+        /**
+         * Get the sub version of this header
+         *
+         * @return the sub version
+         */
+        public int getSubVersion() {
+            return SUB_VERSION_NONE;
+        }
+
+        /**
+         * Constructs a new file header for an existing file
+         *
+         * @param randomAccessFile
+         *            the existing file
+         * @throws IOException
+         *             if an I/O error occurs reading from the file
+         */
+        public CheckpointCollectionFileHeader(RandomAccessFile randomAccessFile) throws IOException {
+            fVersion = randomAccessFile.readInt();
+            fSize = randomAccessFile.readInt();
+            fNbEvents = randomAccessFile.readLong();
+            fTimeRangeOffset = randomAccessFile.readLong();
+        }
+
+        /**
+         * Constructs a new file header for the given version
+         *
+         * @param version
+         *            the version
+         */
+        public CheckpointCollectionFileHeader(int version) {
+            fVersion = version;
+        }
+
+        /**
+         * Serialize the header to a file
+         *
+         * @param randomAccessFile
+         *            the existing file
+         * @throws IOException
+         *             if an I/O error occurs writing to the file
+         */
+        public void serialize(RandomAccessFile randomAccessFile) throws IOException {
+            randomAccessFile.seek(0);
+            randomAccessFile.writeInt(getVersion());
+            randomAccessFile.writeInt(fSize);
+            randomAccessFile.writeLong(fNbEvents);
+            randomAccessFile.writeLong(fTimeRangeOffset);
+        }
+
+        /**
+         * The version of the collection. Should be incremented if a binary
+         * incompatible change occurs.
+         */
+        protected final int fVersion;
+        /**
+         * The size of the collection expressed in a number of checkpoints.
+         */
+        protected int fSize = 0;
+        /**
+         * Offset in bytes where the time range is store
+         */
+        protected long fTimeRangeOffset;
+        /**
+         * The total number of events in the trace
+         */
+        protected long fNbEvents;
+    }
+
+    /**
+     * The size of an int in bytes
+     */
+    protected static final int INT_SIZE = 4;
+    /**
+     * The size of a long in bytes
+     */
+    protected static final int LONG_SIZE = 8;
+
+    /**
+     * The maximum size of the serialize buffer when writing the time range
+     */
+    protected static final int MAX_TIME_RANGE_SERIALIZE_SIZE = 1024;
+
+    /**
+     * The originating trace
+     */
+    private ITmfPersistentlyIndexable fTrace;
+
+    private long fCacheMisses = 0;
+    private boolean fCreatedFromScratch;
+
+    /**
+     * File handle for the file being read/written
+     */
+    private RandomAccessFile fRandomAccessFile;
+    /**
+     * File handle for the file being read/written
+     */
+    private File fFile;
+
+    /**
+     * The base file header
+     */
+    private final CheckpointCollectionFileHeader fHeader;
+
+    // Cached values
+    private FileChannel fFileChannel;
+    private TmfTimeRange fTimeRange;
+
+    /**
+     * Constructs a checkpoint collection for a given trace from scratch or from
+     * an existing file. When the checkpoint collection is created from scratch,
+     * it is populated by subsequent calls to {@link #insert}.
+     *
+     * @param file
+     *            the file to use as the persistent storage
+     * @param trace
+     *            the trace
+     */
+    public AbstractFileCheckpointCollection(File file, ITmfPersistentlyIndexable trace) {
+        fTrace = trace;
+        fFile = file;
+        setCreatedFromScratch(!fFile.exists());
+
+        CheckpointCollectionFileHeader header = null;
+
+        if (!isCreatedFromScratch()) {
+            header = tryRestore();
+            if (header == null) {
+                fFile.delete();
+                dispose();
+            }
+        }
+
+        if (isCreatedFromScratch()) {
+            header = initialize();
+        }
+
+        fHeader = header;
+    }
+
+    /**
+     * Creates a new basic file header with the version field initialized. This
+     * should be overridden if the file header is extended
+     *
+     * @return the created file header
+     */
+    protected CheckpointCollectionFileHeader createHeader() {
+        return new CheckpointCollectionFileHeader(VERSION);
+    }
+
+    /**
+     * Creates a new basic file header for an existing file. This should be
+     * overridden if the file header is extended
+     *
+     * @param randomAccessFile
+     *            the existing file
+     * @return the created file header
+     * @throws IOException
+     *             if an I/O error occurs reading from the file
+     */
+    protected CheckpointCollectionFileHeader createHeader(RandomAccessFile randomAccessFile) throws IOException {
+        return new CheckpointCollectionFileHeader(randomAccessFile);
+    }
+
+    /**
+     * Get the version of the collection.
+     *
+     * @return the version of the collection.
+     */
+    protected int getVersion() {
+        return VERSION;
+    }
+
+    /**
+     * Get the sub version of the collection.
+     *
+     * @return the sub version of the collection.
+     */
+    protected int getSubVersion() {
+        return SUB_VERSION_NONE;
+    }
+
+    private CheckpointCollectionFileHeader initialize() {
+        CheckpointCollectionFileHeader header = null;
+        try {
+            fRandomAccessFile = new RandomAccessFile(fFile, "rw"); //$NON-NLS-1$
+            fFileChannel = fRandomAccessFile.getChannel();
+            header = createHeader();
+
+            // Reserve space for header
+            fRandomAccessFile.setLength(header.getSize());
+
+            fTimeRange = new TmfTimeRange(new TmfTimestamp(0), new TmfTimestamp(0));
+        } catch (IOException e) {
+            Activator.logError(MessageFormat.format(Messages.ErrorOpeningIndex, fFile), e);
+            return null;
+        }
+
+        return header;
+    }
+
+    /**
+     * Try to restore the index from disk. Try to open the file and check the
+     * version. Returns the loaded header or null if it could not be loaded.
+     *
+     * @return the loaded header or null if it could not be loaded.
+     */
+    private CheckpointCollectionFileHeader tryRestore() {
+        CheckpointCollectionFileHeader header = null;
+
+        try {
+            fRandomAccessFile = new RandomAccessFile(fFile, "r"); //$NON-NLS-1$
+            fFileChannel = fRandomAccessFile.getChannel();
+        } catch (FileNotFoundException e) {
+            Activator.logError(MessageFormat.format(Messages.ErrorOpeningIndex, fFile), e);
+            return null;
+        }
+
+        try {
+            header = createHeader(fRandomAccessFile);
+            if (header.fVersion != VERSION || header.getSubVersion() != getSubVersion()) {
+                return null;
+            }
+            serializeInTimeRange(header);
+        } catch (IOException e) {
+            Activator.logError(MessageFormat.format(Messages.IOErrorReadingHeader, fFile), e);
+            return null;
+        }
+
+        return header;
+    }
+
+    private void serializeInTimeRange(CheckpointCollectionFileHeader header) throws IOException {
+        ByteBuffer b = ByteBuffer.allocate(MAX_TIME_RANGE_SERIALIZE_SIZE);
+        b.clear();
+        fFileChannel.read(b, header.fTimeRangeOffset);
+        b.flip();
+        fTimeRange = new TmfTimeRange(new TmfTimestamp(b), new TmfTimestamp(b));
+    }
+
+    private void serializeOutTimeRange() throws IOException {
+        fHeader.fTimeRangeOffset = fRandomAccessFile.length();
+        ByteBuffer b = ByteBuffer.allocate(MAX_TIME_RANGE_SERIALIZE_SIZE);
+        b.clear();
+        new TmfTimestamp(fTimeRange.getStartTime()).serialize(b);
+        new TmfTimestamp(fTimeRange.getEndTime()).serialize(b);
+        b.flip();
+        fFileChannel.write(b, fHeader.fTimeRangeOffset);
+    }
+
+    /**
+     * Set the index as complete. No more checkpoints will be inserted.
+     */
+    @Override
+    public void setIndexComplete() {
+        try {
+            serializeOutTimeRange();
+
+            fHeader.serialize(fRandomAccessFile);
+        } catch (IOException e) {
+            Activator.logError(MessageFormat.format(Messages.IOErrorWritingHeader, fFile), e);
+        }
+    }
+
+    /**
+     *
+     * @return true if the checkpoint collection was created from scratch, false
+     *         otherwise
+     */
+    @Override
+    public boolean isCreatedFromScratch() {
+        return fCreatedFromScratch;
+    }
+
+    /**
+     * Set whether or not the collection is created from scratch
+     *
+     * @param isCreatedFromScratch
+     *            whether or not the collection is created from scratch
+     */
+    protected void setCreatedFromScratch(boolean isCreatedFromScratch) {
+        fCreatedFromScratch = isCreatedFromScratch;
+    }
+
+    /**
+     * @return the number of cache misses.
+     */
+    public long getCacheMisses() {
+        return fCacheMisses;
+    }
+
+    /**
+     * Increment the number of cache misses.
+     */
+    protected void incCacheMisses() {
+        ++fCacheMisses;
+    }
+
+    /**
+     * Returns the size of the checkpoint collection expressed as a number of
+     * checkpoints.
+     *
+     * @return the size of the checkpoint collection
+     */
+    @Override
+    public int size() {
+        return fHeader.fSize;
+    }
+
+    /**
+     * Set the trace time range
+     *
+     * @param timeRange
+     *            the trace time range
+     */
+    @Override
+    public void setTimeRange(TmfTimeRange timeRange) {
+        fTimeRange = timeRange;
+    }
+
+    /**
+     * Get the trace time range
+     *
+     * @return the trace time range
+     */
+    @Override
+    public TmfTimeRange getTimeRange() {
+        return fTimeRange;
+    }
+
+    /**
+     * Set the number of events in the trace
+     *
+     * @param nbEvents
+     *            the number of events in the trace
+     */
+    @Override
+    public void setNbEvents(long nbEvents) {
+        fHeader.fNbEvents = nbEvents;
+    }
+
+    /**
+     * Get the number of events in the trace
+     *
+     * @return the number of events in the trace
+     */
+    @Override
+    public long getNbEvents() {
+        return fHeader.fNbEvents;
+    }
+
+    /**
+     * Get the trace
+     *
+     * @return the trace
+     */
+    protected ITmfPersistentlyIndexable getTrace() {
+        return fTrace;
+    }
+
+    /**
+     * Get the random access file currently opened
+     *
+     * @return the file
+     */
+    protected RandomAccessFile getRandomAccessFile() {
+        return fRandomAccessFile;
+    }
+
+    /**
+     * Get the file channel currently used for the index
+     *
+     * @return the file channel
+     */
+    protected FileChannel getFileChannel() {
+        return fRandomAccessFile.getChannel();
+    }
+
+    /**
+     * Get the file handle for the index
+     *
+     * @return the file
+     */
+    protected File getFile() {
+        return fFile;
+    }
+
+    /**
+     * Get the header for this collection
+     *
+     * @return the header
+     */
+    public CheckpointCollectionFileHeader getHeader() {
+        return fHeader;
+    }/**
+     * Dispose and delete the checkpoint collection
+     */
+    @Override
+    public void delete() {
+        dispose();
+        if (fFile.exists()) {
+            fFile.delete();
+        }
+    }
+
+    /**
+     * Dispose the collection and its resources
+     */
+    @Override
+    public void dispose() {
+        try {
+            if (fRandomAccessFile != null) {
+                fRandomAccessFile.close();
+            }
+            setCreatedFromScratch(true);
+            fRandomAccessFile = null;
+        } catch (IOException e) {
+            Activator.logError(MessageFormat.format(Messages.IOErrorClosingIndex, fFile), e);
+        }
+    }
+}
diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/BTree.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/BTree.java
new file mode 100644 (file)
index 0000000..d5d5242
--- /dev/null
@@ -0,0 +1,383 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * 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
+ *
+ * Contributors:
+ *     Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.internal.tmf.core.trace.indexer;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.text.MessageFormat;
+
+import org.eclipse.linuxtools.internal.tmf.core.Activator;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.ITmfPersistentlyIndexable;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
+
+/**
+ * A BTree made of BTreeNodes representing a series of ITmfCheckpoints ordered
+ * by time stamps. {@link BTreeNodeCache } is used to improve performance by
+ * caching some nodes in memory and the other nodes are kept on disk.
+ *
+ * @author Marc-Andre Laperle
+ */
+public class BTree extends AbstractFileCheckpointCollection {
+
+    /**
+     * Typical BTree file name
+     */
+    public static final String INDEX_FILE_NAME = "checkpoint_btree.idx"; //$NON-NLS-1$
+    private static final int SUB_VERSION = 4;
+    private static final boolean ALWAYS_CACHE_ROOT = true;
+
+    private final int fMaxNumEntries;
+    private final int fMaxNumChildren;
+    private final int fMedianEntry;
+
+    private BTreeHeader fBTreeHeader;
+
+    // Cached values
+    private int nodeSize = -1;
+    private final ByteBuffer fNodeByteBuffer;
+    private final BTreeNodeCache fNodeCache;
+
+    private class BTreeHeader extends CheckpointCollectionFileHeader {
+        private static final int SIZE = LONG_SIZE + INT_SIZE;
+        private long fRoot;
+        private final int fSubVersion;
+
+        private BTreeHeader(int version, int subVersion) {
+            super(version);
+            fSubVersion = subVersion;
+        }
+
+        private BTreeHeader(RandomAccessFile randomAccessFile) throws IOException {
+            super(randomAccessFile);
+
+            fRoot = randomAccessFile.readLong();
+            fSubVersion = randomAccessFile.readInt();
+        }
+
+        @Override
+        public int getSubVersion() {
+            return fSubVersion;
+        }
+
+        @Override
+        public int getSize() {
+            return SIZE + super.getSize();
+        }
+
+        @Override
+        public void serialize(RandomAccessFile randomAccessFile) throws IOException {
+            super.serialize(randomAccessFile);
+
+            randomAccessFile.writeLong(fRoot);
+            randomAccessFile.writeInt(fSubVersion);
+        }
+    }
+
+    @Override
+    protected CheckpointCollectionFileHeader createHeader() {
+        fBTreeHeader = new BTreeHeader(getVersion(), SUB_VERSION);
+        return fBTreeHeader;
+    }
+
+    @Override
+    protected CheckpointCollectionFileHeader createHeader(RandomAccessFile randomAccessFile) throws IOException {
+        fBTreeHeader = new BTreeHeader(randomAccessFile);
+        return fBTreeHeader;
+    }
+
+    @Override
+    protected int getSubVersion() {
+        return SUB_VERSION;
+    }
+
+    /**
+     * Constructs a BTree for a given trace from scratch or from an existing
+     * file. The degree is used to calibrate the number of entries in each node
+     * which can affect performance. When the BTree is created from scratch, it
+     * is populated by subsequent calls to {@link #insert}.
+     *
+     * @param degree
+     *            the degree to use in the tree
+     * @param file
+     *            the file to use as the persistent storage
+     * @param trace
+     *            the trace
+     */
+    public BTree(int degree, File file, ITmfPersistentlyIndexable trace) {
+        super(file, trace);
+
+        fMaxNumEntries = 2 * degree - 1;
+        fMaxNumChildren = 2 * degree;
+        fMedianEntry = degree - 1;
+
+        fNodeByteBuffer = ByteBuffer.allocate(getNodeSize());
+        fNodeByteBuffer.clear();
+        fNodeCache = new BTreeNodeCache(this);
+        BTreeNode rootNode = isCreatedFromScratch() ? allocateNode() : fNodeCache.getNode(fBTreeHeader.fRoot);
+        setRootNode(rootNode);
+    }
+
+    /**
+     * Insert a checkpoint into the file-backed BTree
+     *
+     * @param checkpoint
+     *            the checkpoint to insert
+     */
+    @Override
+    public void insert(ITmfCheckpoint checkpoint) {
+        insert(checkpoint, fBTreeHeader.fRoot, null, 0);
+    }
+
+    private void setRootNode(BTreeNode newRootNode) {
+        fBTreeHeader.fRoot = newRootNode.getOffset();
+        if (ALWAYS_CACHE_ROOT) {
+            fNodeCache.setRootNode(newRootNode);
+        } else {
+            fNodeCache.addNode(newRootNode);
+        }
+    }
+
+    private void insert(ITmfCheckpoint checkpoint, long nodeOffset, BTreeNode pParent, int iParent) {
+        BTreeNode parent = pParent;
+        BTreeNode node = fNodeCache.getNode(nodeOffset);
+
+        // If this node is full (last entry isn't null), split it
+        if (node.getEntry(fMaxNumEntries - 1) != null) {
+
+            ITmfCheckpoint median = node.getEntry(fMedianEntry);
+            if (median.compareTo(checkpoint) == 0) {
+                // Found it
+                return;
+            }
+
+            // Split it.
+            // Create the new node and move the larger entries over.
+            BTreeNode newnode = allocateNode();
+            fNodeCache.addNode(newnode);
+            long newNodeOffset = newnode.getOffset();
+            for (int i = 0; i < fMedianEntry; ++i) {
+                newnode.setEntry(i, node.getEntry(fMedianEntry + 1 + i));
+                node.setEntry(fMedianEntry + 1 + i, null);
+                newnode.setChild(i, node.getChild(fMedianEntry + 1 + i));
+                node.setChild(fMedianEntry + 1 + i, BTreeNode.NULL_CHILD);
+            }
+            newnode.setChild(fMedianEntry, node.getChild(fMaxNumEntries));
+            node.setChild(fMaxNumEntries, BTreeNode.NULL_CHILD);
+
+            if (parent == null) {
+                parent = allocateNode();
+                setRootNode(parent);
+                parent.setChild(0, nodeOffset);
+            } else {
+                // Insert the median into the parent.
+                for (int i = fMaxNumEntries - 2; i >= iParent; --i) {
+                    ITmfCheckpoint r = parent.getEntry(i);
+                    if (r != null) {
+                        parent.setEntry(i + 1, r);
+                        parent.setChild(i + 2, parent.getChild(i + 1));
+                    }
+                }
+            }
+
+            fNodeCache.getNode(parent.getOffset());
+
+            parent.setEntry(iParent, median);
+            parent.setChild(iParent + 1, newNodeOffset);
+
+            node.setEntry(fMedianEntry, null);
+
+            // Set the node to the correct one to follow.
+            if (checkpoint.compareTo(median) > 0) {
+                node = newnode;
+            }
+        }
+
+        // Binary search to find the insert point.
+        int lower = 0;
+        int upper = fMaxNumEntries - 1;
+        while (lower < upper && node.getEntry(upper - 1) == null) {
+            upper--;
+        }
+
+        while (lower < upper) {
+            int middle = (lower + upper) / 2;
+            ITmfCheckpoint check = node.getEntry(middle);
+            if (check == null) {
+                upper = middle;
+            } else {
+                int compare = check.compareTo(checkpoint);
+                if (compare > 0) {
+                    upper = middle;
+                } else if (compare < 0) {
+                    lower = middle + 1;
+                } else {
+                    // Found it, no insert
+                    return;
+                }
+            }
+        }
+        final int i = lower;
+        long child = node.getChild(i);
+        if (child != BTreeNode.NULL_CHILD) {
+            // Visit the children.
+            insert(checkpoint, child, node, i);
+        } else {
+            // We are at the leaf, add us in.
+            // First copy everything after over one.
+            for (int j = fMaxNumEntries - 2; j >= i; --j) {
+                ITmfCheckpoint r = node.getEntry(j);
+                if (r != null) {
+                    node.setEntry(j + 1, r);
+                }
+            }
+            node.setEntry(i, checkpoint);
+            return;
+        }
+    }
+
+    int getNodeSize() {
+        if (nodeSize == -1) {
+            nodeSize = INT_SIZE; // num entries
+            nodeSize += getTrace().getCheckpointSize() * fMaxNumEntries;
+            nodeSize += LONG_SIZE * fMaxNumChildren;
+        }
+
+        return nodeSize;
+    }
+
+    private BTreeNode allocateNode() {
+        try {
+            long offset = getRandomAccessFile().length();
+            getRandomAccessFile().setLength(offset + getNodeSize());
+            BTreeNode node = new BTreeNode(this, offset);
+            return node;
+        } catch (IOException e) {
+            Activator.logError(MessageFormat.format(Messages.BTree_IOErrorAllocatingNode, getFile()), e);
+        }
+        return null;
+    }
+
+    @Override
+    public long binarySearch(ITmfCheckpoint checkpoint) {
+        BTreeCheckpointVisitor v = new BTreeCheckpointVisitor(checkpoint);
+        accept(v);
+        return v.getCheckpointRank();
+    }
+
+    /**
+     * Accept a visitor. This visitor is used to search through the whole tree.
+     *
+     * @param treeVisitor
+     *            the visitor to accept
+     */
+    public void accept(IBTreeVisitor treeVisitor) {
+        accept(fBTreeHeader.fRoot, treeVisitor);
+    }
+
+    private void accept(long nodeOffset, IBTreeVisitor visitor) {
+
+        if (nodeOffset == BTreeNode.NULL_CHILD) {
+            return;
+        }
+
+        BTreeNode node = fNodeCache.getNode(nodeOffset);
+
+        // Binary search to find first entry greater or equal.
+        int lower = 0;
+        int upper = fMaxNumEntries - 1;
+        while (lower < upper && node.getEntry(upper - 1) == null) {
+            upper--;
+        }
+        while (lower < upper) {
+            int middle = (lower + upper) / 2;
+            ITmfCheckpoint middleCheckpoint = node.getEntry(middle);
+            if (middleCheckpoint == null) {
+                upper = middle;
+            } else {
+                int compare = visitor.compare(middleCheckpoint);
+                if (compare == 0) {
+                    return;
+                } else if (compare > 0) {
+                    upper = middle;
+                } else {
+                    lower = middle + 1;
+                }
+            }
+        }
+
+        // Start with first record greater or equal, reuse comparison
+        // results.
+        int i = lower;
+        for (; i < fMaxNumEntries; ++i) {
+            ITmfCheckpoint record = node.getEntry(i);
+            if (record == null) {
+                break;
+            }
+
+            int compare = visitor.compare(record);
+            if (compare > 0) {
+                // Start point is to the left.
+                accept(node.getChild(i), visitor);
+                return;
+            } else if (compare == 0) {
+                return;
+            }
+        }
+        accept(node.getChild(i), visitor);
+        return;
+    }
+
+    /**
+     * Set the index as complete. No more checkpoints will be inserted.
+     */
+    @Override
+    public void setIndexComplete() {
+        super.setIndexComplete();
+
+        fNodeCache.serialize();
+    }
+
+    /**
+     * Get the maximum number of entries in a node
+     *
+     * @return the maximum number of entries in a node
+     */
+    int getMaxNumEntries() {
+        return fMaxNumEntries;
+    }
+
+    /**
+     * Set the size of the BTree, expressed as a number of checkpoints
+     *
+     * @param size
+     *            the size of the BTree
+     */
+    public void setSize(int size) {
+        fBTreeHeader.fSize = size;
+    }
+
+    /**
+     * Get the maximum number of children in a node
+     *
+     * @return the maximum number of children in a node
+     */
+    int getMaxNumChildren() {
+        return fMaxNumChildren;
+    }
+
+    ByteBuffer getNodeByteBuffer() {
+        return fNodeByteBuffer;
+    }
+}
diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/BTreeCheckpointVisitor.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/BTreeCheckpointVisitor.java
new file mode 100644 (file)
index 0000000..20e10e2
--- /dev/null
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * 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
+ *
+ * Contributors:
+ *     Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.internal.tmf.core.trace.indexer;
+
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
+
+/**
+ * A visitor that searches for a specific checkpoint
+ *
+ * @author Marc-Andre Laperle
+ */
+public class BTreeCheckpointVisitor implements IBTreeVisitor {
+
+    private long rank = -1;
+    private ITmfCheckpoint found;
+    private ITmfCheckpoint search;
+    private boolean exactFound = false;
+
+    /**
+     * Constructs the checkpoint visitor
+     *
+     * @param search
+     *            the checkpoint to search for
+     */
+    public BTreeCheckpointVisitor(ITmfCheckpoint search) {
+        this.search = search;
+    }
+
+    @Override
+    public int compare(ITmfCheckpoint currentCheckpoint) {
+        int compareTo = currentCheckpoint.compareTo(search);
+        if (compareTo <= 0 && !exactFound) {
+            rank = currentCheckpoint.getCheckpointRank();
+            found = currentCheckpoint;
+            if (compareTo == 0) {
+                exactFound = true;
+            }
+        }
+        return compareTo;
+    }
+
+    /**
+     * Return the found checkpoint
+     *
+     * @return the found checkpoint
+     */
+    public ITmfCheckpoint getCheckpoint() {
+        return found;
+    }
+
+    /**
+     * Returns the checkpoint rank of the searched checkpoint, if it is
+     *         contained in the index; otherwise, (-(insertion point) - 1).
+     *
+     * @return the checkpoint rank of the searched checkpoint, if it is
+     *         contained in the index; otherwise, (-(insertion point) - 1).
+     */
+    public long getCheckpointRank() {
+        if (!exactFound) {
+            long insertionPoint = rank + 1;
+            return -insertionPoint - 1;
+        }
+
+        return rank;
+    }
+}
\ No newline at end of file
diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/BTreeNode.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/BTreeNode.java
new file mode 100644 (file)
index 0000000..2a37b90
--- /dev/null
@@ -0,0 +1,204 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * 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
+ *
+ * Contributors:
+ *     Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.internal.tmf.core.trace.indexer;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.text.MessageFormat;
+import java.util.Arrays;
+
+import org.eclipse.linuxtools.internal.tmf.core.Activator;
+import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.TmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.location.ITmfLocation;
+
+/**
+ * A node in the BTree. A node contains entries and pointers to other nodes.
+ * The layout can be illustrated like this:
+ *
+ *               |
+ *   ___________Node__________
+ *   |  e  |  e  |  e  |  e  |
+ *   p     p     p     p     p
+ *   |
+ *   |
+ *  Node  ...
+ *
+ *  Where e is an entry, p is a pointer to another node.
+ *
+ *  A pointer on the left side of an entry points to a node containing entries
+ *  that are of lesser value than the entry and a pointer on the right side of
+ *  an entry points to a node containing entries that are of greater value
+ *  than the entry. In this implementation, entries are ITmfCheckpoints and
+ *  pointers are file offsets (long).
+ *
+ * @author Marc-Andre Laperle
+ */
+class BTreeNode {
+
+    /**
+     * Integer to represent a null child
+     */
+    static final int NULL_CHILD = -1;
+
+    private final ITmfCheckpoint fEntries[];
+    private final long fChildrenFileOffsets[];
+    private final long fFileOffset;
+    private final BTree fTree;
+
+    private int fNumEntries = 0;
+    private boolean fIsDirty = false;
+
+    /**
+     * Construct a node for the specified tree for the specified file offset
+     *
+     * @param tree
+     *            the BTree
+     * @param offset
+     *            the file offset
+     */
+    BTreeNode(BTree tree, long offset) {
+        fTree = tree;
+        fFileOffset = offset;
+        fEntries = new ITmfCheckpoint[fTree.getMaxNumEntries()];
+        fChildrenFileOffsets = new long[fTree.getMaxNumChildren()];
+        Arrays.fill(fChildrenFileOffsets, NULL_CHILD);
+    }
+
+    /**
+     * Get the file offset for this node
+     *
+     * @return the file offset
+     */
+    long getOffset() {
+        return fFileOffset;
+    }
+
+    /**
+     * Read the node data from disk
+     */
+    void serializeIn() {
+        try {
+            fTree.getRandomAccessFile().seek(fFileOffset);
+
+            ByteBuffer bb;
+            bb = fTree.getNodeByteBuffer();
+            bb.clear();
+            fTree.getRandomAccessFile().read(bb.array());
+
+            for (int i = 0; i < fTree.getMaxNumChildren(); ++i) {
+                fChildrenFileOffsets[i] = bb.getLong();
+            }
+            fNumEntries = bb.getInt();
+
+            for (int i = 0; i < fNumEntries; ++i) {
+
+                ITmfLocation location = fTree.getTrace().restoreLocation(bb);
+                ITmfTimestamp timeStamp = new TmfTimestamp(bb);
+                TmfCheckpoint c = new TmfCheckpoint(timeStamp, location, bb);
+                fEntries[i] = c;
+            }
+
+        } catch (IOException e) {
+            Activator.logError(MessageFormat.format(Messages.BTreeNode_IOErrorLoading, fFileOffset, fTree.getRandomAccessFile()), e);
+        }
+    }
+
+    /**
+     * Write the node data to disk
+     */
+    void serializeOut() {
+        try {
+            fTree.getRandomAccessFile().seek(fFileOffset);
+
+            ByteBuffer bb = fTree.getNodeByteBuffer();
+            bb.clear();
+
+            for (int i = 0; i < fTree.getMaxNumChildren(); ++i) {
+                bb.putLong(fChildrenFileOffsets[i]);
+            }
+            bb.putInt(fNumEntries);
+
+            for (int i = 0; i < fNumEntries; ++i) {
+                ITmfCheckpoint key = fEntries[i];
+                key.serialize(bb);
+            }
+
+            fTree.getRandomAccessFile().write(bb.array());
+
+            fIsDirty = false;
+        } catch (IOException e) {
+            Activator.logError(MessageFormat.format(Messages.BTreeNode_IOErrorWriting, fFileOffset, fTree.getRandomAccessFile()), e);
+        }
+    }
+
+    /**
+     * Get the entry at the given index
+     *
+     * @param index
+     *            the index where to get the entry
+     * @return the entry at the index
+     */
+    ITmfCheckpoint getEntry(int index) {
+        return fEntries[index];
+    }
+
+    long getChild(int index) {
+        return fChildrenFileOffsets[index];
+    }
+
+    /**
+     * Set the checkpoint entry at the given index
+     *
+     * @param index
+     *            the index where to set the entry
+     * @param checkpoint
+     *            the checkpoint to set at the index
+     */
+    void setEntry(int index, ITmfCheckpoint checkpoint) {
+        fIsDirty = true;
+        // Update number of entries
+        if (fEntries[index] == null && checkpoint != null) {
+            ++fNumEntries;
+        } else if (fEntries[index] != null && checkpoint == null) {
+            fNumEntries = Math.max(0, fNumEntries - 1);
+        }
+
+        fEntries[index] = checkpoint;
+    }
+
+    /**
+     * Set the child file offset at the given index
+     *
+     * @param index
+     *            the index where to set the child offset
+     * @param offset
+     *            the child offset
+     */
+    void setChild(int index, long offset) {
+        fIsDirty = true;
+        fChildrenFileOffsets[index] = offset;
+    }
+
+    /**
+     * Returns whether or not the node is dirty, that is, if the node has been
+     * modified since it first has been loaded into memory
+     *
+     * @return true if the node is dirty, false otherwise
+     */
+    boolean isDirty() {
+        return fIsDirty;
+    }
+}
diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/BTreeNodeCache.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/BTreeNodeCache.java
new file mode 100644 (file)
index 0000000..c03ba07
--- /dev/null
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * 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
+ *
+ * Contributors:
+ *     Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.internal.tmf.core.trace.indexer;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+
+/**
+ * A simple LRU node cache. The BTree request a node from the cache and the
+ * cache load it from disk if it's not already in memory.
+ *
+ * This cache could be improved considerably by allowing bigger caches.
+ *
+ * @author Marc-Andre Laperle
+ */
+public class BTreeNodeCache {
+
+    /**
+     * Cache size obtained by experimentation. An improved cache could set this
+     * dynamically or using a user preference.
+     */
+    private static final int CACHE_SIZE = 15;
+
+    private final BTree fTree;
+    /**
+     * The root node is always kept in memory when {@link
+     * BTree#ALWAYS_CACHE_ROOT} is set to true
+     */
+    private BTreeNode fRootNode = null;
+    /**
+     * The collection keeping the nodes in memory. The most recently used is
+     * kept at the front of the double-ended queue and the least recently used
+     * node is kept at the back.
+     */
+    private final Deque<BTreeNode> fCachedNodes = new ArrayDeque<BTreeNode>(CACHE_SIZE);
+
+    private int fCcheMisses = 0;
+
+    /**
+     * Construct a new node cache for the given BTree
+     *
+     * @param tree
+     *            the BTree that will use the cache
+     */
+    BTreeNodeCache(BTree tree) {
+        fTree = tree;
+    }
+
+    /**
+     * Get the node at the offset from the cache. If the node is not found in
+     * memory, it is loaded from disk.
+     *
+     * @param offset
+     * @return
+     */
+    BTreeNode getNode(long offset) {
+        if (fRootNode != null && fRootNode.getOffset() == offset) {
+            return fRootNode;
+        }
+
+        for (BTreeNode nodeSearch : fCachedNodes) {
+            if (nodeSearch.getOffset() == offset) {
+                // This node is now the most recently used
+                fCachedNodes.remove(nodeSearch);
+                fCachedNodes.push(nodeSearch);
+
+                return nodeSearch;
+            }
+        }
+
+        ++fCcheMisses;
+
+        BTreeNode node = new BTreeNode(fTree, offset);
+        node.serializeIn();
+        addNode(node);
+
+        return node;
+    }
+
+    /**
+     * Write all in-memory nodes to disk if they are dirty
+     */
+    void serialize() {
+        if (fRootNode != null && fRootNode.isDirty()) {
+            fRootNode.serializeOut();
+        }
+        for (BTreeNode nodeSearch : fCachedNodes) {
+            if (nodeSearch.isDirty()) {
+                nodeSearch.serializeOut();
+            }
+        }
+    }
+
+    /**
+     * Add a node to the cache. If the cache has reached the size specified with
+     * {@link #CACHE_SIZE}, the least recently used node is removed from memory.
+     *
+     * @param node
+     *            the node to add to the cache
+     */
+    void addNode(BTreeNode node) {
+        if (fCachedNodes.size() >= CACHE_SIZE) {
+            BTreeNode removed = fCachedNodes.removeLast();
+            if (removed.isDirty()) {
+                removed.serializeOut();
+            }
+        }
+        fCachedNodes.push(node);
+    }
+
+    /**
+     * Set the root node. See {@link #fRootNode}
+     *
+     * @param newRootNode
+     *            the new root node
+     */
+    void setRootNode(BTreeNode newRootNode) {
+        BTreeNode oldRootNode = fRootNode;
+        fRootNode = newRootNode;
+        if (oldRootNode != null) {
+            addNode(oldRootNode);
+        }
+        return;
+    }
+
+    /**
+     * Useful for benchmarks. Get the number of cache misses for the whole BTree
+     * instance lifetime. Cache misses occur when a node is requested and it's
+     * not in memory therefore it has to be read from disk.
+     *
+     * @return the number of cache misses.
+     */
+    int getCacheMisses() {
+        return fCcheMisses;
+    }
+}
diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/FlatArray.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/FlatArray.java
new file mode 100644 (file)
index 0000000..de9d906
--- /dev/null
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * 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
+ *
+ * Contributors:
+ *     Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.internal.tmf.core.trace.indexer;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.text.MessageFormat;
+
+import org.eclipse.linuxtools.internal.tmf.core.Activator;
+import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.ITmfPersistentlyIndexable;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.TmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.location.ITmfLocation;
+
+/**
+ * An array of checkpoints stored on disk. It is very efficient for searching
+ * checkpoints by rank (O(1))
+ *
+ * @author Marc-Andre Laperle
+ */
+public class FlatArray extends AbstractFileCheckpointCollection {
+    /**
+     * Typical FlatArray file name
+     */
+    public static final String INDEX_FILE_NAME = "checkpoint_flatarray.idx"; //$NON-NLS-1$
+
+    // Cached values
+    private int fCheckpointSize = 0;
+    private ByteBuffer fByteBuffer;
+
+    /**
+     * Constructs a FlatArray for a given trace from scratch or from an existing
+     * file. When the FlatArray is created from scratch, it is populated by
+     * subsequent calls to {@link #insert}.
+     *
+     * @param file
+     *            the file to use as the persistent storage
+     * @param trace
+     *            the trace
+     */
+    public FlatArray(File file, ITmfPersistentlyIndexable trace) {
+        super(file, trace);
+
+        fCheckpointSize = getTrace().getCheckpointSize();
+        fByteBuffer = ByteBuffer.allocate(fCheckpointSize);
+        fByteBuffer.clear();
+    }
+
+    /**
+     * Insert a checkpoint into the file-backed array
+     *
+     * @param checkpoint
+     *            the checkpoint to insert
+     */
+    @Override
+    public void insert(ITmfCheckpoint checkpoint) {
+        try {
+            CheckpointCollectionFileHeader header = getHeader();
+            ++header.fSize;
+            getRandomAccessFile().seek(getRandomAccessFile().length());
+            fByteBuffer.clear();
+            checkpoint.serialize(fByteBuffer);
+            getRandomAccessFile().write(fByteBuffer.array());
+        } catch (IOException e) {
+            Activator.logError(MessageFormat.format(Messages.FlatArray_IOErrorWriting, getFile()), e);
+        }
+    }
+
+    /**
+     * Get a checkpoint from a rank
+     *
+     * @param rank
+     *            the rank to search
+     * @return the checkpoint that has been found or null if not found
+     */
+    public ITmfCheckpoint get(long rank) {
+        ITmfCheckpoint checkpoint = null;
+        try {
+            long pos = getHeader().getSize() + fCheckpointSize * rank;
+            getRandomAccessFile().seek(pos);
+            fByteBuffer.clear();
+            getRandomAccessFile().read(fByteBuffer.array());
+            ITmfLocation location = getTrace().restoreLocation(fByteBuffer);
+            ITmfTimestamp timeStamp = new TmfTimestamp(fByteBuffer);
+            checkpoint = new TmfCheckpoint(timeStamp, location, fByteBuffer);
+        } catch (IOException e) {
+            Activator.logError(MessageFormat.format(Messages.FlatArray_IOErrorReading, getFile()), e);
+        }
+        return checkpoint;
+    }
+
+    /**
+     * Search for a checkpoint and return the rank.
+     *
+     * @param checkpoint
+     *            the checkpoint to search
+     * @return the checkpoint rank of the searched checkpoint, if it is
+     *         contained in the index; otherwise, (-(insertion point) - 1).
+     */
+    @Override
+    public long binarySearch(ITmfCheckpoint checkpoint) {
+        if (getHeader().fSize == 1) {
+            return 0;
+        }
+
+        long lower = 0;
+        long upper = getHeader().fSize - 1;
+        long lastMiddle = -1;
+        long middle = 0;
+        while (lower <= upper && lastMiddle != middle) {
+            lastMiddle = middle;
+            middle = (lower + upper) / 2;
+            ITmfCheckpoint found = get(middle);
+            incCacheMisses();
+            int compare = checkpoint.compareTo(found);
+            if (compare == 0) {
+                return middle;
+            }
+
+            if (compare < 0) {
+                upper = middle;
+            } else {
+                lower = middle + 1;
+            }
+        }
+        long insertionPoint = lower;
+        return -(insertionPoint) - 1;
+    }
+}
diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/IBTreeVisitor.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/IBTreeVisitor.java
new file mode 100644 (file)
index 0000000..4f4e560
--- /dev/null
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * 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
+ *
+ * Contributors:
+ *     Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.internal.tmf.core.trace.indexer;
+
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
+
+/**
+ * A BTree visitor goes through the tree using a comparator for
+ * optimal searches.
+ *
+ * @author Marc-Andre Laperle
+ */
+public interface IBTreeVisitor {
+
+    /**
+     * The current checkpoint being compared against an internally held key.
+     *
+     * @param checkpoint
+     *            the current checkpoint
+     * @return -1 if checkpoint < key, 0 if checkpoint == key, 1 if checkpoint >
+     *         key
+     */
+    int compare(ITmfCheckpoint checkpoint);
+}
diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/ICheckpointCollection.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/ICheckpointCollection.java
new file mode 100644 (file)
index 0000000..ea75482
--- /dev/null
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * 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
+ *
+ * Contributors:
+ *     Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.internal.tmf.core.trace.indexer;
+
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
+
+/**
+ * A common interface for collections containing checkpoints
+ *
+ * @author Marc-Andre Laperle
+ */
+public interface ICheckpointCollection {
+
+    /**
+     * Insert a checkpoint into the collection
+     *
+     * @param checkpoint
+     *            the checkpoint to insert
+     */
+    void insert(ITmfCheckpoint checkpoint);
+
+    /**
+     * Search for a checkpoint and return the rank.
+     *
+     * @param checkpoint
+     *            the checkpoint to search
+     * @return the checkpoint rank of the searched checkpoint, if it is
+     *         contained in the index; otherwise, (-(insertion point) - 1).
+     */
+    long binarySearch(ITmfCheckpoint checkpoint);
+
+    /**
+     * @return true if the collection was created from scratch, false otherwise
+     */
+    boolean isCreatedFromScratch();
+
+    /**
+     * Returns the size of the collection expressed as a number of checkpoints.
+     *
+     * @return the size of the collection
+     */
+    int size();
+
+    /**
+     * Set the trace time range
+     *
+     * @param timeRange
+     *            the trace time range
+     */
+    void setTimeRange(TmfTimeRange timeRange);
+
+    /**
+     * Get the trace time range
+     *
+     * @return the trace time range
+     */
+    TmfTimeRange getTimeRange();
+
+    /**
+     * Set the number of events in the trace
+     *
+     * @param nbEvents
+     *            the number of events in the trace
+     */
+    void setNbEvents(long nbEvents);
+
+    /**
+     * Get the number of events in the trace
+     *
+     * @return the number of events in the trace
+     */
+    long getNbEvents();
+
+    /**
+     * Set the index as complete. No more checkpoints will be inserted.
+     */
+    void setIndexComplete();
+
+    /**
+     * Dispose the collection and delete persistent data (file)
+     */
+    void delete();
+
+    /**
+     * Dispose the structure and its resources
+     */
+    void dispose();
+}
diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/Messages.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/Messages.java
new file mode 100644 (file)
index 0000000..f7c8631
--- /dev/null
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * 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
+ *
+ * Contributors:
+ *     Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.internal.tmf.core.trace.indexer;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Message bundle for tmf.core.trace.index
+ *
+ * @author Marc-Andre Laperle
+ */
+public class Messages extends NLS {
+    private static final String BUNDLE_NAME = "org.eclipse.linuxtools.internal.tmf.core.trace.indexer.messages"; //$NON-NLS-1$
+    /**
+     * Error opening index
+     */
+    public static String ErrorOpeningIndex;
+    /**
+     * I/O Error allocating a node
+     */
+    public static String BTree_IOErrorAllocatingNode;
+    /**
+     * I/O Error closing the index
+     */
+    public static String IOErrorClosingIndex;
+    /**
+     * I/O Error reading header from disk
+     */
+    public static String IOErrorReadingHeader;
+    /**
+     * I/O Error writing header from disk
+     */
+    public static String IOErrorWritingHeader;
+    /**
+     * I/O Error reading node from disk
+     */
+    public static String BTreeNode_IOErrorLoading;
+    /**
+     * I/O Error writing node to disk
+     */
+    public static String BTreeNode_IOErrorWriting;
+    /**
+     * I/O Error reading from disk
+     */
+    public static String FlatArray_IOErrorReading;
+    /**
+     * I/O Error writing to disk
+     */
+    public static String FlatArray_IOErrorWriting;
+    static {
+        // initialize resource bundle
+        NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+    }
+
+    private Messages() {
+    }
+}
diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/TmfMemoryIndex.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/TmfMemoryIndex.java
new file mode 100644 (file)
index 0000000..03fbcb2
--- /dev/null
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * 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
+ *
+ * Contributors:
+ *     Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.internal.tmf.core.trace.indexer;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpointIndex;
+
+/**
+ * A checkpoint index that store all checkpoints in memory.
+ *
+ * @since 3.0
+ * @author Marc-Andre Laperle
+ */
+public class TmfMemoryIndex implements ITmfCheckpointIndex, ICheckpointCollection {
+
+    private final List<ITmfCheckpoint> fCheckpoints;
+
+    /**
+     * Creates an index for the given trace
+     *
+     * @param trace the trace
+     */
+    public TmfMemoryIndex(ITmfTrace trace) {
+        fCheckpoints = new ArrayList<ITmfCheckpoint>();
+    }
+
+    @Override
+    public void dispose() {
+        fCheckpoints.clear();
+    }
+
+    @Override
+    public void insert(ITmfCheckpoint checkpoint) {
+        fCheckpoints.add(checkpoint);
+    }
+
+    @Override
+    public ITmfCheckpoint get(long checkpoint) {
+        return fCheckpoints.get((int)checkpoint);
+    }
+
+    @Override
+    public long binarySearch(ITmfCheckpoint checkpoint) {
+        return Collections.binarySearch(fCheckpoints, checkpoint);
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return fCheckpoints.isEmpty();
+    }
+
+    @Override
+    public int size() {
+        return fCheckpoints.size();
+    }
+
+    @Override
+    public boolean isCreatedFromScratch() {
+        return true;
+    }
+
+    @Override
+    public void setTimeRange(TmfTimeRange timeRange) {
+    }
+
+    @Override
+    public void setNbEvents(long nbEvents) {
+    }
+
+    @Override
+    public TmfTimeRange getTimeRange() {
+        return null;
+    }
+
+    @Override
+    public long getNbEvents() {
+        return 0;
+    }
+
+    @Override
+    public void setIndexComplete() {
+    }
+
+    @Override
+    public void delete() {
+    }
+}
diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/messages.properties b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/messages.properties
new file mode 100644 (file)
index 0000000..6528587
--- /dev/null
@@ -0,0 +1,21 @@
+###############################################################################
+# Copyright (c) 2013 Ericsson
+#
+# 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
+#
+# Contributors:
+#     Ericsson - Initial API and implementation
+###############################################################################
+
+ErrorOpeningIndex=Error opening index. File: {0}
+BTree_IOErrorAllocatingNode=I/O error allocating index node. File: {0}
+IOErrorClosingIndex=Error closing index. File: {0}
+IOErrorReadingHeader=Error reading index header. File: {0}
+IOErrorWritingHeader=Error writing index header. File: {0}
+BTreeNode_IOErrorLoading=I/O error loading index node. Offset: {0} file: {1}
+BTreeNode_IOErrorWriting=I/O error writing index node. Offset: {0} file: {1}
+FlatArray_IOErrorReading=I/O error reading index checkpoint. File: {0}
+FlatArray_IOErrorWriting=I/O error writing index checkpoint. File: {0}
index b310f822c81eb433697b861498e3a631c88f7817..55acb6b584382a21a33ff39af0dfd5142b6136ce 100644 (file)
@@ -12,6 +12,8 @@
  *******************************************************************************/
 package org.eclipse.linuxtools.tmf.core.ctfadaptor;
 
+import java.nio.ByteBuffer;
+
 import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp;
 import org.eclipse.linuxtools.tmf.core.trace.location.TmfLocation;
 
@@ -101,6 +103,18 @@ public final class CtfLocation extends TmfLocation {
     // TmfLocation
     // ------------------------------------------------------------------------
 
+    /**
+     * Construct the location from the ByteBuffer.
+     *
+     * @param bufferIn
+     *            the buffer to read from
+     *
+     * @since 3.0
+     */
+    public CtfLocation(ByteBuffer bufferIn) {
+        super(new CtfLocationInfo(bufferIn));
+    }
+
     /**
      * @since 2.0
      */
@@ -121,4 +135,14 @@ public final class CtfLocation extends TmfLocation {
         return super.toString();
     }
 
+    /**
+     * Constructs the location from the ByteBuffer. This typically happens when reading from disk.
+     *
+     * @since 3.0
+     */
+    @Override
+    public void serialize(ByteBuffer bufferOut) {
+        getLocationInfo().serialize(bufferOut);
+
+    }
 }
index ea3f29b9e7f3615d2962468fc45ee9676777d236..7a3c4678159f4809cb523253fb9607fa9c05f594 100644 (file)
@@ -10,6 +10,8 @@
  *******************************************************************************/
 package org.eclipse.linuxtools.tmf.core.ctfadaptor;
 
+import java.nio.ByteBuffer;
+
 /**
  * The data object to go in a {@link CtfLocation}.
  *
@@ -33,6 +35,19 @@ public class CtfLocationInfo implements Comparable<CtfLocationInfo> {
         this.index = index;
     }
 
+    /**
+     * Construct the location from the ByteBuffer.
+     *
+     * @param bufferIn
+     *            the buffer to read from
+     *
+     * @since 3.0
+     */
+    public CtfLocationInfo(ByteBuffer bufferIn) {
+        timestamp = bufferIn.getLong();
+        index = bufferIn.getLong();
+    }
+
     /**
      * @return The timestamp
      */
@@ -107,4 +122,17 @@ public class CtfLocationInfo implements Comparable<CtfLocationInfo> {
         return 0;
     }
 
+    /**
+     * Write the location to the ByteBuffer so that it can be saved to disk.
+     *
+     * @param bufferOut
+     *            the buffer to write to
+     *
+     * @since 3.0
+     */
+    public void serialize(ByteBuffer bufferOut) {
+        bufferOut.putLong(timestamp);
+        bufferOut.putLong(index);
+
+    }
 }
index 5edb8cda8f8ea3f3cc713fa6541945d4cf06b346..f39a1a71324195c5f14a809f922a62f74f80440c 100644 (file)
@@ -15,6 +15,7 @@
 package org.eclipse.linuxtools.tmf.core.ctfadaptor;
 
 import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
 import java.util.Collections;
 import java.util.Map;
 
@@ -22,8 +23,8 @@ import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Status;
-import org.eclipse.linuxtools.ctf.core.event.IEventDeclaration;
 import org.eclipse.linuxtools.ctf.core.event.CTFClock;
+import org.eclipse.linuxtools.ctf.core.event.IEventDeclaration;
 import org.eclipse.linuxtools.ctf.core.trace.CTFReaderException;
 import org.eclipse.linuxtools.ctf.core.trace.CTFTrace;
 import org.eclipse.linuxtools.ctf.core.trace.CTFTraceReader;
@@ -36,6 +37,11 @@ import org.eclipse.linuxtools.tmf.core.trace.ITmfContext;
 import org.eclipse.linuxtools.tmf.core.trace.ITmfEventParser;
 import org.eclipse.linuxtools.tmf.core.trace.ITmfTraceProperties;
 import org.eclipse.linuxtools.tmf.core.trace.TmfTrace;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.ITmfPersistentlyIndexable;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.ITmfTraceIndexer;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.TmfBTreeTraceIndexer;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.TmfCheckpoint;
 import org.eclipse.linuxtools.tmf.core.trace.location.ITmfLocation;
 
 /**
@@ -45,7 +51,7 @@ import org.eclipse.linuxtools.tmf.core.trace.location.ITmfLocation;
  * @author Matthew khouzam
  */
 public class CtfTmfTrace extends TmfTrace
-        implements ITmfEventParser, ITmfTraceProperties {
+        implements ITmfEventParser, ITmfTraceProperties, ITmfPersistentlyIndexable {
 
     // -------------------------------------------
     // Constants
@@ -447,4 +453,29 @@ public class CtfTmfTrace extends TmfTrace
     public CtfTmfTimestamp createTimestamp(long ts) {
         return new CtfTmfTimestamp(getTimestampTransform().transform(ts));
     }
+
+    private static int fCheckpointSize = -1;
+
+    @Override
+    public synchronized int getCheckpointSize() {
+        if (fCheckpointSize == -1) {
+            TmfCheckpoint c = new TmfCheckpoint(new CtfTmfTimestamp(0), new CtfLocation(0, 0), 0);
+            ByteBuffer b = ByteBuffer.allocate(ITmfCheckpoint.MAX_SERIALIZE_SIZE);
+            b.clear();
+            c.serialize(b);
+            fCheckpointSize = b.position();
+        }
+
+        return fCheckpointSize;
+    }
+
+    @Override
+    protected ITmfTraceIndexer createIndexer(int interval) {
+        return new TmfBTreeTraceIndexer(this, interval);
+    }
+
+    @Override
+    public ITmfLocation restoreLocation(ByteBuffer bufferIn) {
+        return new CtfLocation(bufferIn);
+    }
 }
index 176d43144891942208d0b6e912a1a7f770e1f91a..d8cb31f7b1cf96aa1a6b6f28041c7c5dd0f3b647 100644 (file)
@@ -27,6 +27,7 @@ public class TmfTraceUpdatedSignal extends TmfSignal {
 
     private final ITmfTrace fTrace;
     private final TmfTimeRange fTimeRange;
+    private final long fNbEvents;
 
     /**
      * Constructor
@@ -37,12 +38,14 @@ public class TmfTraceUpdatedSignal extends TmfSignal {
      *            The trace that was updated
      * @param range
      *            The new time range of the trace
-     * @since 2.0
+     * @param nbEvents
+     *            The number of events in the trace
      */
-    public TmfTraceUpdatedSignal(Object source, ITmfTrace trace, TmfTimeRange range) {
+    public TmfTraceUpdatedSignal(Object source, ITmfTrace trace, TmfTimeRange range, long nbEvents) {
         super(source);
         fTrace = trace;
         fTimeRange = range;
+        fNbEvents = nbEvents;
     }
 
     /**
@@ -60,6 +63,15 @@ public class TmfTraceUpdatedSignal extends TmfSignal {
         return fTimeRange;
     }
 
+    /**
+     * Returns the number of events indicated by this signal
+     *
+     * @return the number of events indicated by this signal
+     */
+    public long getNbEvents() {
+        return fNbEvents;
+    }
+
     @Override
     @SuppressWarnings("nls")
     public String toString() {
index 7fbe99c6a9b1c5c5f9f3a5770ad90ae6ec7bb54f..e3a4ecca737c69eb7028b5ec86d9aff8b7185e17 100644 (file)
@@ -16,6 +16,8 @@
 
 package org.eclipse.linuxtools.tmf.core.timestamp;
 
+import java.nio.ByteBuffer;
+
 /**
  * A generic timestamp implementation. The timestamp is represented by the
  * tuple { value, scale, precision }. By default, timestamps are scaled in
@@ -157,6 +159,18 @@ public class TmfTimestamp implements ITmfTimestamp {
     // ITmfTimestamp
     // ------------------------------------------------------------------------
 
+    /**
+     * Construct the timestamp from the ByteBuffer.
+     *
+     * @param bufferIn
+     *            the buffer to read from
+     *
+     * @since 3.0
+     */
+    public TmfTimestamp(ByteBuffer bufferIn) {
+        this(bufferIn.getLong(), bufferIn.getInt(), bufferIn.getInt());
+    }
+
     @Override
     public long getValue() {
         return fValue;
@@ -356,4 +370,15 @@ public class TmfTimestamp implements ITmfTimestamp {
         }
     }
 
+    /**
+     * Write the time stamp to the ByteBuffer so that it can be saved to disk.
+     * @param bufferOut the buffer to write to
+     *
+     * @since 3.0
+     */
+    public void serialize(ByteBuffer bufferOut) {
+        bufferOut.putLong(fValue);
+        bufferOut.putInt(fScale);
+        bufferOut.putInt(fPrecision);
+    }
 }
index 8f5d2c6181951ba0cb410f92a3b65814f1f8e0d2..106492e92069d8c1f7df8882c90a302ba0ea52b1 100644 (file)
@@ -17,6 +17,7 @@
 package org.eclipse.linuxtools.tmf.core.trace;
 
 import java.io.File;
+import java.nio.ByteBuffer;
 
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IProject;
@@ -42,7 +43,9 @@ import org.eclipse.linuxtools.tmf.core.synchronization.SynchronizationManager;
 import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp;
 import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
 import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
-import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.TmfCheckpointIndexer;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.ITmfPersistentlyIndexable;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.ITmfTraceIndexer;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.TmfBTreeTraceIndexer;
 import org.eclipse.linuxtools.tmf.core.trace.location.ITmfLocation;
 
 /**
@@ -52,7 +55,7 @@ import org.eclipse.linuxtools.tmf.core.trace.location.ITmfLocation;
  * @version 1.0
  * @author Francois Chouinard
  */
-public class TmfExperiment extends TmfTrace implements ITmfEventParser {
+public class TmfExperiment extends TmfTrace implements ITmfEventParser, ITmfPersistentlyIndexable {
 
     // ------------------------------------------------------------------------
     // Constants
@@ -153,16 +156,14 @@ public class TmfExperiment extends TmfTrace implements ITmfEventParser {
     public TmfExperiment(final Class<? extends ITmfEvent> type, final String path, final ITmfTrace[] traces, final int indexPageSize, IResource resource) {
         setCacheSize(indexPageSize);
         setStreamingInterval(0);
-        setIndexer(new TmfCheckpointIndexer(this, indexPageSize));
         setParser(this);
+        fTraces = traces;
         try {
             super.initialize(resource, path, type);
         } catch (TmfTraceException e) {
             e.printStackTrace();
         }
 
-        fTraces = traces;
-
         if (resource != null) {
             try {
                 this.synchronizeTraces();
@@ -172,6 +173,14 @@ public class TmfExperiment extends TmfTrace implements ITmfEventParser {
         }
     }
 
+    @Override
+    protected ITmfTraceIndexer createIndexer(int interval) {
+        if (getCheckpointSize() > 0) {
+            return new TmfBTreeTraceIndexer(this, interval);
+        }
+        return super.createIndexer(interval);
+    }
+
     /**
      * Clears the experiment
      */
@@ -615,4 +624,44 @@ public class TmfExperiment extends TmfTrace implements ITmfEventParser {
         }
     }
 
+    @Override
+    public synchronized int getCheckpointSize() {
+        int totalCheckpointSize = 0;
+        try {
+            if (fTraces != null) {
+                for (final ITmfTrace trace : fTraces) {
+                    if (!(trace instanceof ITmfPersistentlyIndexable)) {
+                        return 0;
+                    }
+
+                    ITmfPersistentlyIndexable persistableIndexTrace = (ITmfPersistentlyIndexable) trace;
+                    int currentTraceCheckpointSize = persistableIndexTrace.getCheckpointSize();
+                    if (currentTraceCheckpointSize <= 0) {
+                        return 0;
+                    }
+                    totalCheckpointSize += currentTraceCheckpointSize;
+                    totalCheckpointSize += 8; // each entry in the TmfLocationArray has a rank in addition of the location
+                }
+            }
+        } catch (UnsupportedOperationException e) {
+            return 0;
+        }
+
+        return totalCheckpointSize;
+    }
+
+    @Override
+    public ITmfLocation restoreLocation(ByteBuffer bufferIn) {
+        ITmfLocation[] locations = new ITmfLocation[fTraces.length];
+        long[] ranks = new long[fTraces.length];
+        for (int i = 0; i < fTraces.length; ++i) {
+            final ITmfTrace trace = fTraces[i];
+            locations[i] = ((ITmfPersistentlyIndexable) trace).restoreLocation(bufferIn);
+            ranks[i] = bufferIn.getLong();
+        }
+        TmfLocationArray arr = new TmfLocationArray(locations, ranks);
+        TmfExperimentLocation l = new TmfExperimentLocation(arr);
+        return l;
+    }
+
 }
index 5810801fe64ca18b45a4b2e9f4cd56a9e85d030e..f3f7c37a74a066e4bc9ade24d69b38f0786d7121 100644 (file)
@@ -30,9 +30,9 @@ import java.util.Map;
 import org.eclipse.core.resources.IFolder;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Path;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.linuxtools.internal.tmf.core.Activator;
 import org.eclipse.linuxtools.tmf.core.TmfCommonConstants;
@@ -45,6 +45,7 @@ import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler;
 import org.eclipse.linuxtools.tmf.core.signal.TmfSignalManager;
 import org.eclipse.linuxtools.tmf.core.signal.TmfTraceOpenedSignal;
 import org.eclipse.linuxtools.tmf.core.signal.TmfTraceRangeUpdatedSignal;
+import org.eclipse.linuxtools.tmf.core.signal.TmfTraceUpdatedSignal;
 import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystem;
 import org.eclipse.linuxtools.tmf.core.statistics.ITmfStatistics;
 import org.eclipse.linuxtools.tmf.core.statistics.TmfStateStatistics;
@@ -178,8 +179,8 @@ public abstract class TmfTrace extends TmfEventProvider implements ITmfTrace {
         super();
         fCacheSize = (cacheSize > 0) ? cacheSize : ITmfTrace.DEFAULT_TRACE_CACHE_SIZE;
         fStreamingInterval = interval;
-        fIndexer = (indexer != null) ? indexer : new TmfCheckpointIndexer(this, fCacheSize);
         fParser = parser;
+        fIndexer = indexer;
         initialize(resource, path, type);
     }
 
@@ -196,18 +197,29 @@ public abstract class TmfTrace extends TmfEventProvider implements ITmfTrace {
         }
         fCacheSize = trace.getCacheSize();
         fStreamingInterval = trace.getStreamingInterval();
-        fIndexer = new TmfCheckpointIndexer(this);
         fParser = trace.fParser;
         initialize(trace.getResource(), trace.getPath(), trace.getEventType());
     }
 
+    /**
+     * Creates the indexer instance. Classes extending this class can override
+     * this to provide a different indexer implementation.
+     *
+     * @param interval the checkpoints interval
+     *
+     * @return the indexer
+     * @since 3.0
+     */
+    protected ITmfTraceIndexer createIndexer(int interval) {
+        return new TmfCheckpointIndexer(this, interval);
+    }
+
     // ------------------------------------------------------------------------
     // ITmfTrace - Initializers
     // ------------------------------------------------------------------------
 
     @Override
     public void initTrace(final IResource resource, final String path, final Class<? extends ITmfEvent> type) throws TmfTraceException {
-        fIndexer = new TmfCheckpointIndexer(this, fCacheSize);
         initialize(resource, path, type);
     }
 
@@ -232,8 +244,7 @@ public abstract class TmfTrace extends TmfEventProvider implements ITmfTrace {
         String traceName = (resource != null) ? resource.getName() : null;
         // If no resource was provided, extract the display name the trace path
         if (traceName == null) {
-            final int sep = path.lastIndexOf(IPath.SEPARATOR);
-            traceName = (sep >= 0) ? path.substring(sep + 1) : path;
+            traceName = new Path(path).lastSegment();
         }
         if (fParser == null) {
             if (this instanceof ITmfEventParser) {
@@ -245,6 +256,9 @@ public abstract class TmfTrace extends TmfEventProvider implements ITmfTrace {
         super.init(traceName, type);
         // register as VIP after super.init() because TmfComponent registers to signal manager there
         TmfSignalManager.registerVIP(this);
+        if (fIndexer == null) {
+            fIndexer = createIndexer(fCacheSize);
+        }
     }
 
     /**
@@ -750,6 +764,21 @@ public abstract class TmfTrace extends TmfEventProvider implements ITmfTrace {
         }
     }
 
+    /**
+     * Signal handler for the TmfTraceUpdatedSignal signal
+     *
+     * @param signal The incoming signal
+     * @since 2.0
+     */
+    @TmfSignalHandler
+    public void traceUpdated(final TmfTraceUpdatedSignal signal) {
+        if (signal.getSource() == getIndexer()) {
+            fNbEvents = signal.getNbEvents();
+            fStartTime = signal.getRange().getStartTime();
+            fEndTime = signal.getRange().getEndTime();
+        }
+    }
+
     /**
      * Returns the file resource used to store synchronization formula. The file
      * may not exist.
diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/ITmfPersistentlyIndexable.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/ITmfPersistentlyIndexable.java
new file mode 100644 (file)
index 0000000..b26a5b2
--- /dev/null
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * 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
+ *
+ * Contributors:
+ *     Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.core.trace.indexer;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.linuxtools.tmf.core.trace.location.ITmfLocation;
+
+/**
+ * A trace implementing this interface can be indexed and its index can be
+ * persisted to disk.
+ *
+ * @author Marc-Andre Laperle
+ */
+public interface ITmfPersistentlyIndexable {
+
+    /**
+     * Instantiate a ITmfLocation from a ByteBuffer, typically from disk.
+     *
+     * @param bufferIn
+     *            the buffer to read from
+     * @return the instantiated location
+     *
+     * @since 3.0
+     */
+    ITmfLocation restoreLocation(ByteBuffer bufferIn);
+
+    /**
+     * Get the checkpoint size for this trace
+     *
+     * @return the checkpoint size
+     *
+     * @since 3.0
+     */
+    public int getCheckpointSize();
+}
diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/TmfBTreeTraceIndex.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/TmfBTreeTraceIndex.java
new file mode 100644 (file)
index 0000000..39f2bf4
--- /dev/null
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * 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
+ *
+ * Contributors:
+ *     Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.core.trace.indexer;
+
+import java.io.File;
+
+import org.eclipse.linuxtools.internal.tmf.core.trace.indexer.BTree;
+import org.eclipse.linuxtools.internal.tmf.core.trace.indexer.FlatArray;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
+import org.eclipse.linuxtools.tmf.core.trace.TmfTraceManager;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpointIndex;
+
+/**
+ * A checkpoint index that uses a BTree to store and search checkpoints by time stamps.
+ * It's possible to have the checkpoints time stamps in a different order than their checkpoint ranks.
+ * Because of that, we use a separate structure FlatArray that is better suited for searching
+ * by checkpoint rank (O(1)).
+ *
+ * @since 3.0
+ * @author Marc-Andre Laperle
+ */
+public class TmfBTreeTraceIndex implements ITmfCheckpointIndex {
+
+    private final BTree fCheckpoints;
+    private final FlatArray fCheckpointRanks;
+
+    private static final int BTREE_DEGREE = 15;
+
+    /**
+     * Creates an index for the given trace
+     *
+     * @param trace the trace
+     */
+    public TmfBTreeTraceIndex(ITmfTrace trace) {
+        BTree bTree = createBTree(trace);
+        FlatArray flatArray = createFlatArray(trace);
+
+        // If one of the files is created from scratch, make sure we rebuild the other one too
+        if (bTree.isCreatedFromScratch() != flatArray.isCreatedFromScratch()) {
+            bTree.delete();
+            flatArray.delete();
+            bTree = createBTree(trace);
+            flatArray = createFlatArray(trace);
+        }
+
+        fCheckpoints = bTree;
+        fCheckpointRanks = flatArray;
+    }
+
+    private static FlatArray createFlatArray(ITmfTrace trace) {
+        return new FlatArray(getIndexFile(trace, FlatArray.INDEX_FILE_NAME), (ITmfPersistentlyIndexable)trace);
+    }
+
+    private static BTree createBTree(ITmfTrace trace) {
+        return new BTree(BTREE_DEGREE, getIndexFile(trace, BTree.INDEX_FILE_NAME), (ITmfPersistentlyIndexable)trace);
+    }
+
+    private static File getIndexFile(ITmfTrace trace, String fileName) {
+        String directory = TmfTraceManager.getSupplementaryFileDir(trace);
+        return new File(directory + fileName);
+    }
+
+    @Override
+    public void dispose() {
+        fCheckpoints.dispose();
+        fCheckpointRanks.dispose();
+    }
+
+    @Override
+    public void insert(ITmfCheckpoint checkpoint) {
+        fCheckpoints.insert(checkpoint);
+        fCheckpointRanks.insert(checkpoint);
+        fCheckpoints.setSize(fCheckpoints.size() + 1);
+    }
+
+    @Override
+    public ITmfCheckpoint get(long checkpoint) {
+        return fCheckpointRanks.get(checkpoint);
+    }
+
+    @Override
+    public long binarySearch(ITmfCheckpoint checkpoint) {
+        return fCheckpoints.binarySearch(checkpoint);
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return size() == 0;
+    }
+
+    @Override
+    public int size() {
+        return fCheckpoints.size();
+    }
+
+    @Override
+    public boolean isCreatedFromScratch() {
+        return fCheckpoints.isCreatedFromScratch();
+    }
+
+    @Override
+    public void setTimeRange(TmfTimeRange timeRange) {
+        fCheckpoints.setTimeRange(timeRange);
+    }
+
+    @Override
+    public void setNbEvents(long nbEvents) {
+        fCheckpoints.setNbEvents(nbEvents);
+    }
+
+    @Override
+    public TmfTimeRange getTimeRange() {
+        return fCheckpoints.getTimeRange();
+    }
+
+    @Override
+    public long getNbEvents() {
+        return fCheckpoints.getNbEvents();
+    }
+
+    @Override
+    public void setIndexComplete() {
+        fCheckpoints.setIndexComplete();
+        fCheckpointRanks.setIndexComplete();
+    }
+
+}
diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/TmfBTreeTraceIndexer.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/TmfBTreeTraceIndexer.java
new file mode 100644 (file)
index 0000000..a4d76b2
--- /dev/null
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * 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
+ *
+ * Contributors:
+ *     Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.core.trace.indexer;
+
+import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpointIndex;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.TmfCheckpointIndexer;
+
+/**
+ * An indexer that uses a Btree index to store checkpoints
+ *
+ * @since 3.0
+ * @author Marc-Andre Laperle
+ */
+public class TmfBTreeTraceIndexer extends TmfCheckpointIndexer {
+
+    /**
+     * Full trace indexer
+     *
+     * @param trace
+     *            the trace to index
+     * @param interval
+     *            the checkpoints interval
+     */
+    public TmfBTreeTraceIndexer(ITmfTrace trace, int interval) {
+        super(trace, interval);
+    }
+
+    @Override
+    protected ITmfCheckpointIndex createIndex(ITmfTrace trace) {
+        return new TmfBTreeTraceIndex(trace);
+    }
+}
diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/TmfFlatArrayTraceIndex.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/TmfFlatArrayTraceIndex.java
new file mode 100644 (file)
index 0000000..c1fd940
--- /dev/null
@@ -0,0 +1,112 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * 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
+ *
+ * Contributors:
+ *     Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.core.trace.indexer;
+
+import java.io.File;
+
+import org.eclipse.linuxtools.internal.tmf.core.trace.indexer.FlatArray;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
+import org.eclipse.linuxtools.tmf.core.trace.TmfTraceManager;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpointIndex;
+
+/**
+ * <p>A checkpoint index that uses a FlatArray to store and search checkpoints by
+ * time stamps and by checkpoint rank.</p>
+ *
+ * <p>Note: This index alone will not work for
+ * traces that have events with time stamps that are out of order.</p>
+ *
+ * @since 3.0
+ * @author Marc-Andre Laperle
+ */
+public class TmfFlatArrayTraceIndex implements ITmfCheckpointIndex {
+
+    private final FlatArray fCheckpoints;
+
+    /**
+     * Creates an index for the given trace
+     *
+     * @param trace the trace
+     */
+    public TmfFlatArrayTraceIndex(ITmfTrace trace) {
+        fCheckpoints = new FlatArray(getIndexFile(trace, FlatArray.INDEX_FILE_NAME), (ITmfPersistentlyIndexable)trace);
+    }
+
+    private static File getIndexFile(ITmfTrace trace, String fileName) {
+        String directory = TmfTraceManager.getSupplementaryFileDir(trace);
+        return new File(directory + fileName);
+    }
+
+    @Override
+    public void dispose() {
+        fCheckpoints.dispose();
+    }
+
+    @Override
+    public void insert(ITmfCheckpoint checkpoint) {
+        fCheckpoints.insert(checkpoint);
+    }
+
+    @Override
+    public ITmfCheckpoint get(long checkpoint) {
+        return fCheckpoints.get(checkpoint);
+    }
+
+    @Override
+    public long binarySearch(ITmfCheckpoint checkpoint) {
+        return fCheckpoints.binarySearch(checkpoint);
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return size() == 0;
+    }
+
+    @Override
+    public int size() {
+        return fCheckpoints.size();
+    }
+
+    @Override
+    public boolean isCreatedFromScratch() {
+        return fCheckpoints.isCreatedFromScratch();
+    }
+
+    @Override
+    public void setTimeRange(TmfTimeRange timeRange) {
+        fCheckpoints.setTimeRange(timeRange);
+    }
+
+    @Override
+    public void setNbEvents(long nbEvents) {
+        fCheckpoints.setNbEvents(nbEvents);
+    }
+
+    @Override
+    public TmfTimeRange getTimeRange() {
+        return fCheckpoints.getTimeRange();
+    }
+
+    @Override
+    public long getNbEvents() {
+        return fCheckpoints.getNbEvents();
+    }
+
+    @Override
+    public void setIndexComplete() {
+        fCheckpoints.setIndexComplete();
+    }
+
+}
diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/TmfFlatArrayTraceIndexer.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/TmfFlatArrayTraceIndexer.java
new file mode 100644 (file)
index 0000000..7ae1cef
--- /dev/null
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * 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
+ *
+ * Contributors:
+ *     Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.core.trace.indexer;
+
+import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpointIndex;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.TmfCheckpointIndexer;
+
+/**
+ * An indexer that uses a FlatArray index to store checkpoints
+ *
+ * @since 3.0
+ * @author Marc-Andre Laperle
+ */
+public class TmfFlatArrayTraceIndexer extends TmfCheckpointIndexer {
+
+    /**
+     * Full trace indexer
+     *
+     * @param trace
+     *            the trace to index
+     * @param interval
+     *            the checkpoints interval
+     */
+    public TmfFlatArrayTraceIndexer(ITmfTrace trace, int interval) {
+        super(trace, interval);
+    }
+
+    @Override
+    protected ITmfCheckpointIndex createIndex(ITmfTrace trace) {
+        return new TmfFlatArrayTraceIndex(trace);
+    }
+}
index 9dcb499b071d36f522fad7a1226ec83d8c03a35d..e847fc2d85dd615542a608ebb3bc042cf41553df 100644 (file)
@@ -13,6 +13,8 @@
 
 package org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint;
 
+import java.nio.ByteBuffer;
+
 import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp;
 import org.eclipse.linuxtools.tmf.core.trace.location.ITmfLocation;
 
@@ -32,6 +34,12 @@ public interface ITmfCheckpoint extends Comparable<ITmfCheckpoint> {
     // Getters
     // ------------------------------------------------------------------------
 
+    /**
+     * The maximum size of the serialize buffer when determining the checkpoint
+     * size
+     */
+    static final int MAX_SERIALIZE_SIZE = 1024;
+
     /**
      * @return the timestamp of the event referred to by the context
      * @since 2.0
@@ -50,4 +58,22 @@ public interface ITmfCheckpoint extends Comparable<ITmfCheckpoint> {
     @Override
     int compareTo(ITmfCheckpoint checkpoint);
 
+    /**
+     * Returns the checkpoint rank for this checkpoint. The checkpoint rank can
+     * be seen as the index of the checkpoint in the order it was added.
+     *
+     * @return the checkpoint rank for this checkpoint
+     * @since 3.0
+     */
+    long getCheckpointRank();
+
+    /**
+     * Write the checkpoint to the ByteBuffer so that it can be saved to disk.
+     *
+     * @param bufferOut
+     *            the buffer to write to
+     *
+     * @since 3.0
+     */
+    void serialize(ByteBuffer bufferOut);
 }
diff --git a/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/checkpoint/ITmfCheckpointIndex.java b/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/checkpoint/ITmfCheckpointIndex.java
new file mode 100644 (file)
index 0000000..264e360
--- /dev/null
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * 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
+ *
+ * Contributors:
+ *     Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint;
+
+import java.util.Collections;
+
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
+
+/**
+ * A trace index contains the data (checkpoints) needed by the indexer so that it can perform
+ * its operations. Implementors can store checkpoints in various ways and
+ * optionally restore them later, see ({@link #isCreatedFromScratch})
+ *
+ * @since 3.0
+ * @author Marc-Andre Laperle
+ */
+public interface ITmfCheckpointIndex {
+
+    /**
+     * Add a checkpoint to the index
+     *
+     * @param checkpoint
+     *            the checkpoint to add
+     */
+    void insert(ITmfCheckpoint checkpoint);
+
+    /**
+     * Get a checkpoint by checkpoint rank
+     *
+     * @param checkpointRank
+     *            the checkpoint rank to search for
+     * @return the checkpoint found for the given checkpoint rank
+     */
+    ITmfCheckpoint get(long checkpointRank);
+
+    /**
+     * Find the checkpoint rank of a checkpoint. Implementors must respect the
+     * contract of {@link Collections#binarySearch}
+     *
+     * @param checkpoint
+     *            the checkpoint to search for
+     * @return the checkpoint rank of the searched checkpoint, if it is
+     *         contained in the index; otherwise, (-(insertion point) - 1).
+     */
+    long binarySearch(ITmfCheckpoint checkpoint);
+
+    /**
+     * Returns whether or not the index is empty
+     *
+     * @return true if empty false otherwise
+     */
+    boolean isEmpty();
+
+    /**
+     * Returns the number of checkpoints in the index
+     *
+     * @return the number of checkpoints
+     */
+    int size();
+
+    /**
+     * Dispose the index and its resources
+     */
+    void dispose();
+
+    /**
+     * Returns whether or not the index was created from scratch. An index not
+     * created from scratch was typically loaded from disk.
+     *
+     * @return true if the index was created from scratch, false otherwise
+     */
+    boolean isCreatedFromScratch();
+
+    /**
+     * Set trace time range to be stored in the index
+     *
+     * @param timeRange
+     *            the time range to be stored in the index
+     */
+    void setTimeRange(TmfTimeRange timeRange);
+
+    /**
+     * Set the total number of events in the trace to be stored in the index
+     *
+     * @param nbEvents
+     *            the total number of events
+     */
+    void setNbEvents(long nbEvents);
+
+    /**
+     * Get the trace time range stored in the index
+     *
+     * @return the trace time range
+     */
+    TmfTimeRange getTimeRange();
+
+    /**
+     * Get the total number of events in the trace stored in the index
+     *
+     * @return the total number of events
+     */
+    long getNbEvents();
+
+    /**
+     * Set the index as complete. No more checkpoints will be inserted.
+     */
+    void setIndexComplete();
+}
index e2d56243b8a9a3ba960a368c2c3a868696f384ee..b3c74722f3ab7158211c992c16a70a1d71171341 100644 (file)
 
 package org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint;
 
+import java.nio.ByteBuffer;
+
 import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
 import org.eclipse.linuxtools.tmf.core.trace.location.ITmfLocation;
 
 /**
@@ -39,6 +42,8 @@ public class TmfCheckpoint implements ITmfCheckpoint {
     // The checkpoint timestamp
     private final ITmfTimestamp fTimestamp;
 
+    private final long fCheckpointRank;
+
     // ------------------------------------------------------------------------
     // Constructors
     // ------------------------------------------------------------------------
@@ -46,13 +51,37 @@ public class TmfCheckpoint implements ITmfCheckpoint {
     /**
      * Full constructor
      *
-     * @param timestamp the checkpoint timestamp
-     * @param location the corresponding trace location
+     * @param timestamp
+     *            the checkpoint timestamp
+     * @param location
+     *            the corresponding trace location
+     * @param checkpointRank
+     *            the rank of the checkpoint
+     * @since 3.0
+     */
+    public TmfCheckpoint(final ITmfTimestamp timestamp, final ITmfLocation location, long checkpointRank) {
+        fTimestamp = timestamp;
+        fLocation = location;
+        fCheckpointRank = checkpointRank;
+    }
+
+    /**
+     * Constructs a checkpoint using also a byte buffer to read the rank from
+     * disk.
+     *
+     * @param timestamp
+     *            the checkpoint timestamp
+     * @param location
+     *            the corresponding trace location
+     * @param bufferIn
+     *            the byte buffer to read from
+     *
      * @since 3.0
      */
-    public TmfCheckpoint(final ITmfTimestamp timestamp, final ITmfLocation location) {
+    public TmfCheckpoint(final ITmfTimestamp timestamp, final ITmfLocation location, ByteBuffer bufferIn) {
         fTimestamp = timestamp;
         fLocation = location;
+        fCheckpointRank = bufferIn.getLong();
     }
 
     /**
@@ -66,6 +95,7 @@ public class TmfCheckpoint implements ITmfCheckpoint {
         }
         fTimestamp = other.fTimestamp;
         fLocation = other.fLocation;
+        fCheckpointRank = other.fCheckpointRank;
     }
 
     // ------------------------------------------------------------------------
@@ -166,7 +196,27 @@ public class TmfCheckpoint implements ITmfCheckpoint {
     @Override
     @SuppressWarnings("nls")
     public String toString() {
-        return getClass().getSimpleName() + " [fLocation=" + fLocation + ", fTimestamp=" + fTimestamp + "]";
+        return getClass().getSimpleName() + " [fLocation=" + fLocation + ", fTimestamp=" + fTimestamp + ", fCheckpointRank=" + fCheckpointRank + "]";
     }
 
+    /**
+     * @since 3.0
+     */
+    @Override
+    public void serialize(ByteBuffer bufferOut) {
+        fLocation.serialize(bufferOut);
+        // Always serialize as base TmfTimestamp, this should be sufficient for indexing.
+        // If not, we can add API for the test to restore the time stamp, similarly to the location.
+        TmfTimestamp t = new TmfTimestamp(fTimestamp);
+        t.serialize(bufferOut);
+        bufferOut.putLong(fCheckpointRank);
+    }
+
+    /**
+     * @since 3.0
+     */
+    @Override
+    public long getCheckpointRank() {
+        return fCheckpointRank;
+    }
 }
index 18ddef985d063a69171649711a3f09b7e79272c4..9e830e326a38353c8af5043bc9eafc81176938e1 100644 (file)
 
 package org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.core.runtime.jobs.Job;
 import org.eclipse.linuxtools.internal.tmf.core.Messages;
+import org.eclipse.linuxtools.internal.tmf.core.trace.indexer.TmfMemoryIndex;
 import org.eclipse.linuxtools.tmf.core.component.TmfDataProvider;
 import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
 import org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest;
@@ -37,7 +34,7 @@ import org.eclipse.linuxtools.tmf.core.trace.location.ITmfLocation;
 
 /**
  * A simple indexer that manages the trace index as an array of trace
- * checkpoints. Checkpoints are stored at fixed intervals (event rank) in
+ * checkpoints. Checkpoints are stored in memory at fixed intervals (event rank) in
  * ascending timestamp order.
  * <p>
  * The goal being to access a random trace event reasonably fast from the user's
@@ -73,7 +70,7 @@ public class TmfCheckpointIndexer implements ITmfTraceIndexer {
      * The trace index. It is composed of checkpoints taken at intervals of
      * fCheckpointInterval events.
      */
-    protected final List<ITmfCheckpoint> fTraceIndex;
+    protected final ITmfCheckpointIndex fTraceIndex;
 
     /**
      * The indexing request
@@ -103,16 +100,29 @@ public class TmfCheckpointIndexer implements ITmfTraceIndexer {
     public TmfCheckpointIndexer(final ITmfTrace trace, final int interval) {
         fTrace = trace;
         fCheckpointInterval = interval;
-        fTraceIndex = new ArrayList<ITmfCheckpoint>();
+        fTraceIndex = createIndex(trace);
         fIsIndexing = false;
     }
 
+    /**
+     * Creates the index instance. Classes extending this class
+     * can override this to provide a different index implementation.
+     *
+     * @param trace the trace to index
+     * @return the index
+     * @since 3.0
+     */
+    protected ITmfCheckpointIndex createIndex(final ITmfTrace trace) {
+        return new TmfMemoryIndex(trace);
+    }
+
     @Override
     public void dispose() {
         if ((fIndexingRequest != null) && !fIndexingRequest.isCompleted()) {
             fIndexingRequest.cancel();
-            fTraceIndex.clear();
         }
+
+        fTraceIndex.dispose();
     }
 
     // ------------------------------------------------------------------------
@@ -142,6 +152,13 @@ public class TmfCheckpointIndexer implements ITmfTraceIndexer {
             fIsIndexing = true;
         }
 
+        // No need to build the index, it has been restored
+        if (!fTraceIndex.isCreatedFromScratch()) {
+            // Set some trace attributes that depends on indexing
+            fTrace.broadcast(new TmfTraceUpdatedSignal(this, fTrace, new TmfTimeRange(fTraceIndex.getTimeRange().getStartTime(), fTraceIndex.getTimeRange().getEndTime()), fTraceIndex.getNbEvents()));
+            return;
+        }
+
         // The monitoring job
         final Job job = new Job("Indexing " + fTrace.getName() + "...") { //$NON-NLS-1$ //$NON-NLS-2$
             @Override
@@ -184,6 +201,9 @@ public class TmfCheckpointIndexer implements ITmfTraceIndexer {
 
             @Override
             public void handleSuccess() {
+                fTraceIndex.setTimeRange(fTrace.getTimeRange());
+                fTraceIndex.setNbEvents(fTrace.getNbEvents());
+                fTraceIndex.setIndexComplete();
                 updateTraceStatus();
             }
 
@@ -218,7 +238,7 @@ public class TmfCheckpointIndexer implements ITmfTraceIndexer {
      * @param endTime the new end time
      */
     private void signalNewTimeRange(final ITmfTimestamp startTime, final ITmfTimestamp endTime) {
-        fTrace.broadcast(new TmfTraceUpdatedSignal(fTrace, fTrace, new TmfTimeRange(startTime, endTime)));
+        fTrace.broadcast(new TmfTraceUpdatedSignal(fTrace, fTrace, new TmfTimeRange(startTime, endTime), fTrace.getNbEvents()));
     }
 
     // ------------------------------------------------------------------------
@@ -235,7 +255,7 @@ public class TmfCheckpointIndexer implements ITmfTraceIndexer {
             final long position = context.getRank() / fCheckpointInterval;
             // Add new entry at proper location (if empty)
             if (fTraceIndex.size() == position) {
-                fTraceIndex.add(new TmfCheckpoint(timestamp, context.getLocation()));
+                fTraceIndex.insert(new TmfCheckpoint(timestamp, context.getLocation(), position));
             }
         }
     }
@@ -259,7 +279,7 @@ public class TmfCheckpointIndexer implements ITmfTraceIndexer {
         // In the very likely event that the timestamp is not at a checkpoint
         // boundary, bsearch will return index = (- (insertion point + 1)).
         // It is then trivial to compute the index of the previous checkpoint.
-        int index = Collections.binarySearch(fTraceIndex, new TmfCheckpoint(timestamp, null));
+        long index = fTraceIndex.binarySearch(new TmfCheckpoint(timestamp, null, 0));
         if (index < 0) {
             index = Math.max(0, -(index + 2));
         } else {
@@ -293,9 +313,9 @@ public class TmfCheckpointIndexer implements ITmfTraceIndexer {
      * @param checkpoint the checkpoint index
      * @return the corresponding context
      */
-    private ITmfContext restoreCheckpoint(final int checkpoint) {
+    private ITmfContext restoreCheckpoint(final long checkpoint) {
         ITmfLocation location = null;
-        int index = 0;
+        long index = 0;
         synchronized (fTraceIndex) {
             if (!fTraceIndex.isEmpty()) {
                 index = checkpoint;
@@ -306,7 +326,7 @@ public class TmfCheckpointIndexer implements ITmfTraceIndexer {
             }
         }
         final ITmfContext context = fTrace.seekEvent(location);
-        context.setRank((long) index * fCheckpointInterval);
+        context.setRank(index * fCheckpointInterval);
         return context;
     }
 
@@ -316,8 +336,9 @@ public class TmfCheckpointIndexer implements ITmfTraceIndexer {
 
     /**
      * @return the trace index
+     * @since 3.0
      */
-    protected List<ITmfCheckpoint> getTraceIndex() {
+    protected ITmfCheckpointIndex getTraceIndex() {
         return fTraceIndex;
     }
 
index 1280723a33676a8226e4d9310efa80e6308dc7f0..395c9d496a1b2930d04bc1952baa963fc07a1eec 100644 (file)
@@ -13,6 +13,8 @@
 
 package org.eclipse.linuxtools.tmf.core.trace.location;
 
+import java.nio.ByteBuffer;
+
 /**
  * The generic trace location in TMF.
  * <p>
@@ -39,4 +41,11 @@ public interface ITmfLocation {
      */
     Comparable<?> getLocationInfo();
 
+    /**
+     * Write the location to the ByteBuffer so that it can be saved to disk.
+     * @param bufferOut the buffer to write to
+     *
+     * @since 3.0
+     */
+    void serialize(ByteBuffer bufferOut);
 }
index 38877ca7ea1e1493425b26d5ad19e635127cf4e0..dd0785dff58c1afc3bf93e3cf9749f39bb1fd10e 100644 (file)
@@ -12,6 +12,7 @@
 
 package org.eclipse.linuxtools.tmf.core.trace.location;
 
+import java.nio.ByteBuffer;
 
 /**
  * A concrete implementation of TmfLocation based on Long:s
@@ -39,9 +40,29 @@ public final class TmfLongLocation extends TmfLocation {
         super(other.getLocationInfo());
     }
 
+    /**
+     * Construct the location from the ByteBuffer.
+     *
+     * @param bufferIn
+     *            the buffer to read from
+     *
+     * @since 3.0
+     */
+    public TmfLongLocation(ByteBuffer bufferIn) {
+        super(bufferIn.getLong());
+    }
+
     @Override
     public Long getLocationInfo() {
         return (Long) super.getLocationInfo();
     }
 
+    /**
+     * @since 3.0
+     */
+    @Override
+    public void serialize(ByteBuffer bufferOut) {
+        bufferOut.putLong(getLocationInfo().longValue());
+    }
+
 }
index 22c48f453536218ea6b125dd91f3d4ef25904854..4e76217cfe6a2d69562e2cf53e67fe1b9960e22f 100644 (file)
 
 package org.eclipse.linuxtools.tmf.core.trace.location;
 
+import java.nio.ByteBuffer;
+
 import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
 
 /**
  * A concrete implementation of TmfLocation based on ITmfTimestamp:s
@@ -40,9 +43,29 @@ public final class TmfTimestampLocation extends TmfLocation {
         super(other.getLocationInfo());
     }
 
+    /**
+     * Construct the location from the ByteBuffer.
+     *
+     * @param bufferIn
+     *            the buffer to read from
+     *
+     * @since 3.0
+     */
+    public TmfTimestampLocation(ByteBuffer bufferIn) {
+        super(new TmfTimestamp(bufferIn));
+    }
+
     @Override
     public ITmfTimestamp getLocationInfo() {
         return (ITmfTimestamp) super.getLocationInfo();
     }
 
+    /**
+     * @since 3.0
+     */
+    @Override
+    public void serialize(ByteBuffer bufferOut) {
+        TmfTimestamp t = new TmfTimestamp(getLocationInfo());
+        t.serialize(bufferOut);
+    }
 }
index 14860f03565a8ab41cbff9152bd678d77400198b..d364e2a652ad87daf36a85ebb382e8f96a39fd95 100644 (file)
@@ -15,3 +15,4 @@ Require-Bundle: org.junit;bundle-version="4.0.0",
  org.eclipse.linuxtools.tmf.ui;bundle-version="3.0.0",
  org.eclipse.linuxtools.tmf.core.tests;bundle-version="3.0.0"
 Export-Package: org.eclipse.linuxtools.tmf.ui.tests
+Bundle-Activator: org.eclipse.linuxtools.tmf.ui.tests.TmfUITestPlugin
diff --git a/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/TmfUITestPlugin.java b/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/TmfUITestPlugin.java
new file mode 100644 (file)
index 0000000..8988f54
--- /dev/null
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * 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
+ *
+ * Contributors:
+ *   Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.ui.tests;
+
+import org.eclipse.core.runtime.Plugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * <b><u>TmfUITestPlugin</u></b>
+ * <p>
+ * The activator class controls the plug-in life cycle
+ *
+ * @author Marc-Andre Laperle
+ */
+public class TmfUITestPlugin extends Plugin {
+
+    // ------------------------------------------------------------------------
+    // Attributes
+    // ------------------------------------------------------------------------
+
+    /**
+     *  The plug-in ID
+     */
+    public static final String PLUGIN_ID = "org.eclipse.linuxtools.tmf.ui.tests";
+
+    // The shared instance
+    private static TmfUITestPlugin fPlugin;
+
+    // ------------------------------------------------------------------------
+    // Constructors
+    // ------------------------------------------------------------------------
+
+    /**
+     * The constructor
+     */
+    public TmfUITestPlugin() {
+        setDefault(this);
+    }
+
+    // ------------------------------------------------------------------------
+    // Accessors
+    // ------------------------------------------------------------------------
+
+    /**
+     * @return the shared instance
+     */
+    public static TmfUITestPlugin getDefault() {
+        return fPlugin;
+    }
+
+    /**
+     * @param plugin the shared instance
+     */
+    private static void setDefault(TmfUITestPlugin plugin) {
+        fPlugin = plugin;
+    }
+
+    // ------------------------------------------------------------------------
+    // Operations
+    // ------------------------------------------------------------------------
+
+    @Override
+    public void start(BundleContext context) throws Exception {
+        super.start(context);
+        setDefault(this);
+    }
+
+    @Override
+    public void stop(BundleContext context) throws Exception {
+        setDefault(null);
+        super.stop(context);
+    }
+
+}
diff --git a/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/trace/AbstractCustomTraceIndexTest.java b/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/trace/AbstractCustomTraceIndexTest.java
new file mode 100644 (file)
index 0000000..da8138a
--- /dev/null
@@ -0,0 +1,191 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * 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
+ *
+ * Contributors:
+ *   Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.ui.tests.trace;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+
+import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
+import org.eclipse.linuxtools.tmf.core.trace.ITmfEventParser;
+import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
+import org.eclipse.linuxtools.tmf.core.trace.TmfContext;
+import org.eclipse.linuxtools.tmf.core.trace.TmfTraceManager;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.TmfBTreeTraceIndexer;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpointIndex;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Common test code for custom trace indexes
+ *
+ * @author Marc-Andre Laperle
+ */
+public abstract class AbstractCustomTraceIndexTest {
+
+    /**
+     * Time format use for event creation
+     */
+    protected static final String TIMESTAMP_FORMAT = "dd/MM/yyyy HH:mm:ss:SSS";
+    /**
+     * Block size used for the indexer
+     */
+    protected static final int BLOCK_SIZE = 100;
+    /**
+     * The total number of events in the generated trace
+     */
+    protected static final int NB_EVENTS = 10000;
+    private TestTrace fTrace = null;
+
+    /**
+     * A common test indexer for custom trace index tests
+     */
+    protected static class TestIndexer extends TmfBTreeTraceIndexer {
+
+        /**
+         * Constructs a new test indexer
+         *
+         * @param trace the trace
+         * @param interval the checkpoint interval
+         */
+        public TestIndexer(ITmfTrace trace, int interval) {
+            super(trace, interval);
+        }
+
+        /**
+         * Get the index
+         *
+         * @return the index
+         */
+        public ITmfCheckpointIndex getCheckpoints() {
+            return getTraceIndex();
+        }
+    }
+
+    interface TestTrace extends ITmfTrace {
+        TestIndexer getIndexer();
+    }
+
+    /**
+     * Setup the test
+     *
+     * @throws Exception when error occurs
+     */
+    @Before
+    public void setUp() throws Exception {
+        setupTrace();
+    }
+
+    private synchronized void setupTrace() throws Exception {
+        File traceDirectory = new File(getTraceDirectory());
+        if (traceDirectory.exists()) {
+            traceDirectory.delete();
+        }
+        traceDirectory.mkdir();
+        if (fTrace == null) {
+            fTrace = createTrace();
+            fTrace.indexTrace(true);
+        }
+    }
+
+    /**
+     * Create a test trace, varies between tests
+     *
+     * @return the test trace
+     * @throws Exception when error occurs
+     */
+    abstract protected TestTrace createTrace() throws Exception;
+    /**
+     * Return the trace directory for the generated trace
+     *
+     * @return the trace directory for the generated trace
+     */
+    abstract protected String getTraceDirectory();
+
+    /**
+     * Tear down the test
+     */
+    @After
+    public void tearDown() {
+        String directory = TmfTraceManager.getSupplementaryFileDir(fTrace);
+        try {
+            fTrace.dispose();
+            fTrace = null;
+        } finally {
+            File dir = new File(directory);
+            if (dir.exists()) {
+                File[] files = dir.listFiles();
+                for (File file : files) {
+                    file.delete();
+                }
+                dir.delete();
+            }
+
+            File trace = new File(getTraceDirectory());
+            if (trace.exists()) {
+                trace.delete();
+            }
+        }
+
+    }
+
+    /**
+     * Test the content of the index after building the full index
+     */
+    @Test
+    public void testTmfTraceIndexing() {
+        verifyIndexContent();
+    }
+
+    private void verifyIndexContent() {
+        assertEquals("getCacheSize", BLOCK_SIZE, fTrace.getCacheSize());
+        assertEquals("getTraceSize", NB_EVENTS, fTrace.getNbEvents());
+        assertEquals("getRange-start", 0, fTrace.getTimeRange().getStartTime().getValue());
+        assertEquals("getRange-end", NB_EVENTS - 1, fTrace.getTimeRange().getEndTime().getValue());
+        assertEquals("getStartTime", 0, fTrace.getStartTime().getValue());
+        assertEquals("getEndTime", NB_EVENTS - 1, fTrace.getEndTime().getValue());
+
+        ITmfCheckpointIndex checkpoints = fTrace.getIndexer().getCheckpoints();
+        int pageSize = fTrace.getCacheSize();
+        assertTrue("Checkpoints exist", checkpoints != null);
+        assertEquals("Checkpoints size", NB_EVENTS / BLOCK_SIZE, checkpoints.size());
+
+        // Validate that each checkpoint points to the right event
+        for (int i = 0; i < checkpoints.size(); i++) {
+            ITmfCheckpoint checkpoint = checkpoints.get(i);
+            TmfContext context = new TmfContext(checkpoint.getLocation(), i * pageSize);
+            ITmfEvent event = ((ITmfEventParser)fTrace).parseEvent(context);
+            assertTrue(context.getRank() == i * pageSize);
+            assertTrue((checkpoint.getTimestamp().compareTo(event.getTimestamp(), false) == 0));
+        }
+    }
+
+    /**
+     * Test that a fully built index has the same content when reloaded from disk
+     *
+     * @throws Exception when error occurs
+     */
+    @Test
+    public void testReopenIndex() throws Exception {
+        fTrace.dispose();
+        fTrace = createTrace();
+        assertFalse(fTrace.getIndexer().getCheckpoints().isCreatedFromScratch());
+        fTrace.indexTrace(true);
+
+        verifyIndexContent();
+    }
+}
index 4782199a5f301e24124397a1aab7659a233ce6c9..63f07ab9171a25fcdaad78f348a1de5bc4874dc1 100644 (file)
@@ -16,7 +16,7 @@ import org.junit.runner.RunWith;
 import org.junit.runners.Suite;
 
 /**
- * Test suite for Xml parser validation
+ * Test suite for custom parsers
  * @author Matthew Khouzam
  *
  */
@@ -24,7 +24,9 @@ import org.junit.runners.Suite;
 @Suite.SuiteClasses({
         CustomXmlTraceInvalidTest.class,
         CustomXmlTraceBadlyFormedTest.class,
-        CustomXmlTraceValidTest.class
+        CustomXmlTraceValidTest.class,
+        CustomXmlIndexTest.class,
+        CustomTxtIndexTest.class
 })
 public class AllTests {
 }
diff --git a/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/trace/CustomTxtIndexTest.java b/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/trace/CustomTxtIndexTest.java
new file mode 100644 (file)
index 0000000..f6928d5
--- /dev/null
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2013 Ericsson
+ *
+ * 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
+ *
+ * Contributors:
+ *   Francois Chouinard - Initial API and implementation
+ *   Francois Chouinard - Adapted for TMF Trace Model 1.0
+ *   Alexandre Montplaisir - Port to JUnit4
+ *   Marc-Andre Laperle - Adapted to CustomTxtTrace
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.ui.tests.trace;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.eclipse.linuxtools.internal.tmf.ui.parsers.custom.CustomTxtTrace;
+import org.eclipse.linuxtools.internal.tmf.ui.parsers.custom.CustomTxtTraceDefinition;
+import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException;
+
+/**
+ * Test suite for indexing using a CustomTxtTrace.
+ *
+ * @author Marc-Andre Laperle
+ */
+public class CustomTxtIndexTest extends AbstractCustomTraceIndexTest {
+
+    private static final String TRACE_DIRECTORY = System.getProperty("java.io.tmpdir") + File.separator + "dummyTxtTrace";
+    private static final String TRACE_PATH = TRACE_DIRECTORY + File.separator + "test.txt";
+    private static final String DEFINITION_PATH = "tracesets" + File.separator + "txt" + File.separator + "testTxtDefinition.xml";
+
+    private static CustomTxtTraceDefinition createDefinition() {
+        CustomTxtTraceDefinition[] definitions = CustomTxtTraceDefinition.loadAll(new File(DEFINITION_PATH).toString());
+        return definitions[0];
+    }
+
+    @Override
+    protected String getTraceDirectory() {
+        return TRACE_DIRECTORY;
+    }
+
+    @Override
+    protected TestTrace createTrace() throws Exception {
+        CustomTxtTraceDefinition definition = createDefinition();
+        final File file = new File(TRACE_PATH);
+        BufferedWriter writer = new BufferedWriter(new FileWriter(file));
+        for (int i = 0; i < NB_EVENTS; ++i) {
+            SimpleDateFormat f = new SimpleDateFormat(TIMESTAMP_FORMAT);
+            String eventStr = f.format(new Date(i)) + " hello world\n";
+            writer.write(eventStr);
+        }
+        writer.close();
+
+        return new TestTxtTrace(file.toString(), definition, BLOCK_SIZE);
+    }
+
+    private class TestTxtTrace extends CustomTxtTrace implements TestTrace {
+        public TestTxtTrace(String path, CustomTxtTraceDefinition createDefinition, int blockSize) throws TmfTraceException {
+            super(null, createDefinition, path, blockSize);
+            setIndexer(new TestIndexer(this, blockSize));
+        }
+
+        @Override
+        public TestIndexer getIndexer() {
+            return (TestIndexer) super.getIndexer();
+        }
+    }
+}
\ No newline at end of file
diff --git a/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/trace/CustomXmlIndexTest.java b/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/trace/CustomXmlIndexTest.java
new file mode 100644 (file)
index 0000000..3ee32c8
--- /dev/null
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2013 Ericsson
+ *
+ * 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
+ *
+ * Contributors:
+ *   Francois Chouinard - Initial API and implementation
+ *   Francois Chouinard - Adapted for TMF Trace Model 1.0
+ *   Alexandre Montplaisir - Port to JUnit4
+ *   Marc-Andre Laperle - Adapted to CustomXmlTrace
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.ui.tests.trace;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.eclipse.linuxtools.internal.tmf.ui.parsers.custom.CustomXmlTrace;
+import org.eclipse.linuxtools.internal.tmf.ui.parsers.custom.CustomXmlTraceDefinition;
+import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException;
+
+/**
+ * Test suite for indexing using a CustomXmlTrace.
+ *
+ * @author Marc-Andre Laperle
+ */
+public class CustomXmlIndexTest extends AbstractCustomTraceIndexTest {
+
+    private static final String TRACE_DIRECTORY = System.getProperty("java.io.tmpdir") + File.separator + "dummyXmlTrace";
+    private static final String TRACE_PATH = TRACE_DIRECTORY + File.separator + "test.xml";
+    private static final String DEFINITION_PATH = "tracesets" + File.separator + "xml" + File.separator + "testDefinition.xml";
+
+    private static CustomXmlTraceDefinition createDefinition() {
+        CustomXmlTraceDefinition[] definitions = CustomXmlTraceDefinition.loadAll(new File(DEFINITION_PATH).toString());
+        return definitions[0];
+    }
+
+    @Override
+    protected String getTraceDirectory() {
+        return TRACE_DIRECTORY;
+    }
+
+    @Override
+    protected TestTrace createTrace() throws Exception {
+        CustomXmlTraceDefinition definition = createDefinition();
+        final File file = new File(TRACE_PATH);
+        BufferedWriter writer = new BufferedWriter(new FileWriter(file));
+        writer.write("<trace>");
+        for (int i = 0; i < NB_EVENTS; ++i) {
+            SimpleDateFormat f = new SimpleDateFormat(TIMESTAMP_FORMAT);
+            String eventStr = "<element time=\"" + f.format(new Date(i)) + "\">message</element>\n";
+            writer.write(eventStr);
+        }
+        writer.write("</trace>");
+        writer.close();
+
+        return new TestXmlTrace(file.toString(), definition, BLOCK_SIZE);
+    }
+
+    private class TestXmlTrace extends CustomXmlTrace implements TestTrace {
+        public TestXmlTrace(String path, CustomXmlTraceDefinition createDefinition, int blockSize) throws TmfTraceException {
+            super(null, createDefinition, path, blockSize);
+            setIndexer(new TestIndexer(this, blockSize));
+        }
+
+        @Override
+        public TestIndexer getIndexer() {
+            return (TestIndexer) super.getIndexer();
+        }
+    }
+}
\ No newline at end of file
diff --git a/org.eclipse.linuxtools.tmf.ui.tests/tracesets/txt/testTxtDefinition.xml b/org.eclipse.linuxtools.tmf.ui.tests/tracesets/txt/testTxtDefinition.xml
new file mode 100644 (file)
index 0000000..ee2f9cb
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<CustomTxtTraceDefinitionList>
+<Definition name="testtxt">
+<TimeStampOutputFormat>dd/MM/yyyy HH:mm:ss:SSS</TimeStampOutputFormat>
+<InputLine>
+<Cardinality max="2147483647" min="0"/>
+<RegEx>(\S*\s\S*) (.*\S)</RegEx>
+<InputData action="0" format="dd/MM/yyyy HH:mm:ss:SSS" name="Time Stamp"/>
+<InputData action="0" format="" name="Message"/>
+</InputLine>
+<OutputColumn name="Time Stamp"/>
+<OutputColumn name="Message"/>
+</Definition>
+</CustomTxtTraceDefinitionList>
diff --git a/org.eclipse.linuxtools.tmf.ui.tests/tracesets/xml/testDefinition.xml b/org.eclipse.linuxtools.tmf.ui.tests/tracesets/xml/testDefinition.xml
new file mode 100644 (file)
index 0000000..858f9d4
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<CustomXMLTraceDefinitionList>
+<Definition name="myxml">
+<TimeStampOutputFormat>HH:mm:ss:SSS</TimeStampOutputFormat>
+<InputElement name="trace">
+<InputElement logentry="true" name="element">
+<InputData action="0" format="" name="Message"/>
+<Attribute name="time">
+<InputData action="0" format="dd/MM/yyyy HH:mm:ss:SSS" name="Time Stamp"/>
+</Attribute>
+</InputElement>
+</InputElement>
+<OutputColumn name="Time Stamp"/>
+<OutputColumn name="Message"/>
+</Definition>
+</CustomXMLTraceDefinitionList>
index cfce95de468b223d94390b14b82891ebbd0bd1a2..028844c6ad7d1560b73fdab418e20a9289a7f05f 100644 (file)
@@ -15,6 +15,7 @@ package org.eclipse.linuxtools.internal.tmf.ui.parsers.custom;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.nio.ByteBuffer;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -35,7 +36,11 @@ import org.eclipse.linuxtools.tmf.core.trace.ITmfContext;
 import org.eclipse.linuxtools.tmf.core.trace.ITmfEventParser;
 import org.eclipse.linuxtools.tmf.core.trace.TmfContext;
 import org.eclipse.linuxtools.tmf.core.trace.TmfTrace;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.ITmfPersistentlyIndexable;
 import org.eclipse.linuxtools.tmf.core.trace.indexer.ITmfTraceIndexer;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.TmfBTreeTraceIndexer;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.TmfCheckpoint;
 import org.eclipse.linuxtools.tmf.core.trace.location.ITmfLocation;
 import org.eclipse.linuxtools.tmf.core.trace.location.TmfLongLocation;
 
@@ -44,7 +49,7 @@ import org.eclipse.linuxtools.tmf.core.trace.location.TmfLongLocation;
  *
  * @author Patrick Tassé
  */
-public class CustomTxtTrace extends TmfTrace implements ITmfEventParser {
+public class CustomTxtTrace extends TmfTrace implements ITmfEventParser, ITmfPersistentlyIndexable {
 
     private static final TmfLongLocation NULL_LOCATION = new TmfLongLocation((Long) null);
     private static final int DEFAULT_CACHE_SIZE = 100;
@@ -397,4 +402,29 @@ public class CustomTxtTrace extends TmfTrace implements ITmfEventParser {
         }
         return new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.CustomTrace_FileNotFound + ": " + path); //$NON-NLS-1$
     }
+
+    private static int fCheckpointSize = -1;
+
+    @Override
+    public synchronized int getCheckpointSize() {
+        if (fCheckpointSize == -1) {
+            TmfCheckpoint c = new TmfCheckpoint(TmfTimestamp.ZERO, new TmfLongLocation(0L), 0);
+            ByteBuffer b = ByteBuffer.allocate(ITmfCheckpoint.MAX_SERIALIZE_SIZE);
+            b.clear();
+            c.serialize(b);
+            fCheckpointSize = b.position();
+        }
+
+        return fCheckpointSize;
+    }
+
+    @Override
+    public ITmfLocation restoreLocation(ByteBuffer bufferIn) {
+        return new TmfLongLocation(bufferIn);
+    }
+
+    @Override
+    protected ITmfTraceIndexer createIndexer(int interval) {
+        return new TmfBTreeTraceIndexer(this, interval);
+    }
 }
index 4642df05f648bb907eb8b4bd10c53bc816f7770a..647212c0e6769455faf2f66274487086f09f9d16 100644 (file)
@@ -18,6 +18,7 @@ import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
 
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
@@ -38,7 +39,11 @@ import org.eclipse.linuxtools.tmf.core.trace.ITmfContext;
 import org.eclipse.linuxtools.tmf.core.trace.ITmfEventParser;
 import org.eclipse.linuxtools.tmf.core.trace.TmfContext;
 import org.eclipse.linuxtools.tmf.core.trace.TmfTrace;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.ITmfPersistentlyIndexable;
 import org.eclipse.linuxtools.tmf.core.trace.indexer.ITmfTraceIndexer;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.TmfBTreeTraceIndexer;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.TmfCheckpoint;
 import org.eclipse.linuxtools.tmf.core.trace.location.ITmfLocation;
 import org.eclipse.linuxtools.tmf.core.trace.location.TmfLongLocation;
 import org.w3c.dom.Document;
@@ -56,7 +61,7 @@ import org.xml.sax.SAXParseException;
  *
  * @author Patrick Tassé
  */
-public class CustomXmlTrace extends TmfTrace implements ITmfEventParser {
+public class CustomXmlTrace extends TmfTrace implements ITmfEventParser, ITmfPersistentlyIndexable {
 
     private static final TmfLongLocation NULL_LOCATION = new TmfLongLocation((Long) null);
     private static final int DEFAULT_CACHE_SIZE = 100;
@@ -545,4 +550,29 @@ public class CustomXmlTrace extends TmfTrace implements ITmfEventParser {
         }
         return new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.CustomTrace_FileNotFound + ": " + path); //$NON-NLS-1$
     }
+
+    private static int fCheckpointSize = -1;
+
+    @Override
+    public synchronized int getCheckpointSize() {
+        if (fCheckpointSize == -1) {
+            TmfCheckpoint c = new TmfCheckpoint(TmfTimestamp.ZERO, new TmfLongLocation(0L), 0);
+            ByteBuffer b = ByteBuffer.allocate(ITmfCheckpoint.MAX_SERIALIZE_SIZE);
+            b.clear();
+            c.serialize(b);
+            fCheckpointSize = b.position();
+        }
+
+        return fCheckpointSize;
+    }
+
+    @Override
+    public ITmfLocation restoreLocation(ByteBuffer bufferIn) {
+        return new TmfLongLocation(bufferIn);
+    }
+
+    @Override
+    protected ITmfTraceIndexer createIndexer(int interval) {
+        return new TmfBTreeTraceIndexer(this, interval);
+    }
 }
This page took 0.091995 seconds and 5 git commands to generate.