From aca0ca5483f296545dbcf267d50da41b4eee440b Mon Sep 17 00:00:00 2001 From: Marc-Andre Laperle Date: Wed, 21 Aug 2013 01:42:29 -0400 Subject: BTree index on disk Bug: 315883 Change-Id: I91be77339535a2379f4d48ab9d6e66894afb95ac Signed-off-by: Marc-Andre Laperle Reviewed-on: https://git.eclipse.org/r/15685 Tested-by: Hudson CI Reviewed-by: Alexandre Montplaisir IP-Clean: Alexandre Montplaisir Tested-by: Alexandre Montplaisir --- .../linuxtools/tmf/core/tests/AllTmfCoreTests.java | 1 + .../core/tests/event/TmfTimestampDeltaTest.java | 9 +- .../tmf/core/tests/event/TmfTimestampTest.java | 8 +- .../indexer/AbstractCheckpointCollectionTest.java | 374 ++++++++++++++++ .../tmf/core/tests/trace/indexer/AllBench.java | 251 +++++++++++ .../tmf/core/tests/trace/indexer/AllTests.java | 31 ++ .../tmf/core/tests/trace/indexer/BTreeTest.java | 118 +++++ .../core/tests/trace/indexer/FlatArrayTest.java | 86 ++++ .../tests/trace/indexer/TmfMemoryIndexTest.java | 84 ++++ .../indexer/checkpoint/AbstractIndexTest.java | 273 ++++++++++++ .../tests/trace/indexer/checkpoint/AllTests.java | 1 + .../indexer/checkpoint/TmfBTreeIndexTest.java | 69 +++ .../indexer/checkpoint/TmfCheckpointIndexTest.java | 172 +------- .../checkpoint/TmfCheckpointIndexTest2.java | 7 +- .../indexer/checkpoint/TmfCheckpointTest.java | 38 +- .../TmfExperimentCheckpointIndexTest.java | 6 +- .../tests/trace/location/TmfStringLocation.java | 9 + .../tmf/tests/stubs/trace/TmfIndexerStub.java | 6 +- .../tmf/tests/stubs/trace/TmfTraceStub.java | 26 +- .../META-INF/MANIFEST.MF | 1 + .../tmf/core/trace/TmfExperimentLocation.java | 11 + .../indexer/AbstractFileCheckpointCollection.java | 478 +++++++++++++++++++++ .../internal/tmf/core/trace/indexer/BTree.java | 383 +++++++++++++++++ .../core/trace/indexer/BTreeCheckpointVisitor.java | 76 ++++ .../internal/tmf/core/trace/indexer/BTreeNode.java | 204 +++++++++ .../tmf/core/trace/indexer/BTreeNodeCache.java | 146 +++++++ .../internal/tmf/core/trace/indexer/FlatArray.java | 142 ++++++ .../tmf/core/trace/indexer/IBTreeVisitor.java | 34 ++ .../core/trace/indexer/ICheckpointCollection.java | 99 +++++ .../internal/tmf/core/trace/indexer/Messages.java | 67 +++ .../tmf/core/trace/indexer/TmfMemoryIndex.java | 103 +++++ .../tmf/core/trace/indexer/messages.properties | 21 + .../tmf/core/ctfadaptor/CtfLocation.java | 24 ++ .../tmf/core/ctfadaptor/CtfLocationInfo.java | 28 ++ .../tmf/core/ctfadaptor/CtfTmfTrace.java | 35 +- .../tmf/core/signal/TmfTraceUpdatedSignal.java | 16 +- .../tmf/core/timestamp/TmfTimestamp.java | 25 ++ .../linuxtools/tmf/core/trace/TmfExperiment.java | 59 ++- .../linuxtools/tmf/core/trace/TmfTrace.java | 41 +- .../trace/indexer/ITmfPersistentlyIndexable.java | 46 ++ .../tmf/core/trace/indexer/TmfBTreeTraceIndex.java | 139 ++++++ .../core/trace/indexer/TmfBTreeTraceIndexer.java | 43 ++ .../core/trace/indexer/TmfFlatArrayTraceIndex.java | 112 +++++ .../trace/indexer/TmfFlatArrayTraceIndexer.java | 43 ++ .../trace/indexer/checkpoint/ITmfCheckpoint.java | 26 ++ .../indexer/checkpoint/ITmfCheckpointIndex.java | 118 +++++ .../trace/indexer/checkpoint/TmfCheckpoint.java | 58 ++- .../indexer/checkpoint/TmfCheckpointIndexer.java | 51 ++- .../tmf/core/trace/location/ITmfLocation.java | 9 + .../tmf/core/trace/location/TmfLongLocation.java | 21 + .../core/trace/location/TmfTimestampLocation.java | 23 + .../META-INF/MANIFEST.MF | 1 + .../linuxtools/tmf/ui/tests/TmfUITestPlugin.java | 84 ++++ .../tests/trace/AbstractCustomTraceIndexTest.java | 191 ++++++++ .../linuxtools/tmf/ui/tests/trace/AllTests.java | 6 +- .../tmf/ui/tests/trace/CustomTxtIndexTest.java | 75 ++++ .../tmf/ui/tests/trace/CustomXmlIndexTest.java | 77 ++++ .../tracesets/txt/testTxtDefinition.xml | 14 + .../tracesets/xml/testDefinition.xml | 16 + .../tmf/ui/parsers/custom/CustomTxtTrace.java | 32 +- .../tmf/ui/parsers/custom/CustomXmlTrace.java | 32 +- 61 files changed, 4528 insertions(+), 251 deletions(-) create mode 100644 lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/AbstractCheckpointCollectionTest.java create mode 100644 lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/AllBench.java create mode 100644 lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/AllTests.java create mode 100644 lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/BTreeTest.java create mode 100644 lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/FlatArrayTest.java create mode 100644 lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/TmfMemoryIndexTest.java create mode 100644 lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/AbstractIndexTest.java create mode 100644 lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/TmfBTreeIndexTest.java create mode 100644 lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/AbstractFileCheckpointCollection.java create mode 100644 lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/BTree.java create mode 100644 lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/BTreeCheckpointVisitor.java create mode 100644 lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/BTreeNode.java create mode 100644 lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/BTreeNodeCache.java create mode 100644 lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/FlatArray.java create mode 100644 lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/IBTreeVisitor.java create mode 100644 lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/ICheckpointCollection.java create mode 100644 lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/Messages.java create mode 100644 lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/TmfMemoryIndex.java create mode 100644 lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/messages.properties create mode 100644 lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/ITmfPersistentlyIndexable.java create mode 100644 lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/TmfBTreeTraceIndex.java create mode 100644 lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/TmfBTreeTraceIndexer.java create mode 100644 lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/TmfFlatArrayTraceIndex.java create mode 100644 lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/TmfFlatArrayTraceIndexer.java create mode 100644 lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/checkpoint/ITmfCheckpointIndex.java create mode 100644 lttng/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/TmfUITestPlugin.java create mode 100644 lttng/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/trace/AbstractCustomTraceIndexTest.java create mode 100644 lttng/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/trace/CustomTxtIndexTest.java create mode 100644 lttng/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/trace/CustomXmlIndexTest.java create mode 100644 lttng/org.eclipse.linuxtools.tmf.ui.tests/tracesets/txt/testTxtDefinition.xml create mode 100644 lttng/org.eclipse.linuxtools.tmf.ui.tests/tracesets/xml/testDefinition.xml diff --git a/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/AllTmfCoreTests.java b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/AllTmfCoreTests.java index 92d5130036..35b2945950 100644 --- a/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/AllTmfCoreTests.java +++ b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/AllTmfCoreTests.java @@ -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, diff --git a/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/event/TmfTimestampDeltaTest.java b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/event/TmfTimestampDeltaTest.java index fd0e01b002..1cc98df698 100644 --- a/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/event/TmfTimestampDeltaTest.java +++ b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/event/TmfTimestampDeltaTest.java @@ -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); } // ------------------------------------------------------------------------ diff --git a/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/event/TmfTimestampTest.java b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/event/TmfTimestampTest.java index dbc586bcda..7bf07186b2 100644 --- a/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/event/TmfTimestampTest.java +++ b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/event/TmfTimestampTest.java @@ -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/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/AbstractCheckpointCollectionTest.java b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/AbstractCheckpointCollectionTest.java new file mode 100644 index 0000000000..8601c76ad7 --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/AbstractCheckpointCollectionTest.java @@ -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 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 list = new ArrayList(); + 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 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 list = new ArrayList(); + 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/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/AllBench.java b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/AllBench.java new file mode 100644 index 0000000000..cf82cbb469 --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/AllBench.java @@ -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> 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 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>(checkpointsNums.length); + + System.out.println("DEGREE: " + BTREE_DEGREE); + + AllBench b = new AllBench(); + b.setUp(); + for (int i = 0; i < checkpointsNums.length; i++) { + ArrayList list = new ArrayList(); + generateDataFile(list, checkpointsNums[i]); + nums.add(list); + + System.out.println("*** " + checkpointsNums[i] + " checkpoints ***\n"); + + b.benchIt(list); + } + b.tearDown(); + } + + private void benchIt(ArrayList list) { + + System.out.println("Testing BTree\n"); + + testInsertAlot(list); + + System.out.println("Testing Array\n"); + + testInsertAlotArray(list); + } + + private void testInsertAlot(ArrayList list2) { + int checkpointsNum = list2.size(); + + writeCheckpoints(checkpointsNum); + + ArrayList list = new ArrayList(); + 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 list2) { + int checkpointsNum = list2.size(); + + writeCheckpointsArray(checkpointsNum); + + ArrayList list = new ArrayList(); + 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 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 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/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/AllTests.java b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/AllTests.java new file mode 100644 index 0000000000..0cc9a11dcd --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/AllTests.java @@ -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/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/BTreeTest.java b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/BTreeTest.java new file mode 100644 index 0000000000..d3cbc86316 --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/BTreeTest.java @@ -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 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/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/FlatArrayTest.java b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/FlatArrayTest.java new file mode 100644 index 0000000000..539d75bb98 --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/FlatArrayTest.java @@ -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 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/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/TmfMemoryIndexTest.java b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/TmfMemoryIndexTest.java new file mode 100644 index 0000000000..40d35621aa --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/TmfMemoryIndexTest.java @@ -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/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/AbstractIndexTest.java b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/AbstractIndexTest.java new file mode 100644 index 0000000000..6c83b91bfa --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/AbstractIndexTest.java @@ -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()); + } +} diff --git a/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/AllTests.java b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/AllTests.java index 0c5856ac8b..43ab0a43ea 100644 --- a/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/AllTests.java +++ b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/AllTests.java @@ -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/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/TmfBTreeIndexTest.java b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/TmfBTreeIndexTest.java new file mode 100644 index 0000000000..f522a95f56 --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/TmfBTreeIndexTest.java @@ -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 diff --git a/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/TmfCheckpointIndexTest.java b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/TmfCheckpointIndexTest.java index 52cd6b0d7a..6eba8a3c3c 100644 --- a/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/TmfCheckpointIndexTest.java +++ b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/TmfCheckpointIndexTest.java @@ -14,180 +14,10 @@ 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 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 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 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 diff --git a/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/TmfCheckpointIndexTest2.java b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/TmfCheckpointIndexTest2.java index 4fac680dc9..21a869789f 100644 --- a/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/TmfCheckpointIndexTest2.java +++ b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/TmfCheckpointIndexTest2.java @@ -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 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 checkpoints = fTrace.getIndexer().getCheckpoints(); + ITmfCheckpointIndex checkpoints = fTrace.getIndexer().getCheckpoints(); assertTrue("Checkpoints exist", checkpoints != null); assertEquals("Checkpoints size", NB_EVENTS / BLOCK_SIZE + 1, checkpoints.size()); diff --git a/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/TmfCheckpointTest.java b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/TmfCheckpointTest.java index cb0871cd1f..925084a7d3 100644 --- a/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/TmfCheckpointTest.java +++ b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/TmfCheckpointTest.java @@ -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()); diff --git a/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/TmfExperimentCheckpointIndexTest.java b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/TmfExperimentCheckpointIndexTest.java index 114ee2c8da..879a35f361 100644 --- a/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/TmfExperimentCheckpointIndexTest.java +++ b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/indexer/checkpoint/TmfExperimentCheckpointIndexTest.java @@ -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 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 checkpoints = experiment.getIndexer().getCheckpoints(); + ITmfCheckpointIndex checkpoints = experiment.getIndexer().getCheckpoints(); assertTrue("Checkpoints exist", checkpoints != null); assertEquals("Checkpoints size", NB_EVENTS / BLOCK_SIZE / 2, checkpoints.size()); diff --git a/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/location/TmfStringLocation.java b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/location/TmfStringLocation.java index fad258f498..c36cbc050b 100644 --- a/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/location/TmfStringLocation.java +++ b/lttng/org.eclipse.linuxtools.tmf.core.tests/src/org/eclipse/linuxtools/tmf/core/tests/trace/location/TmfStringLocation.java @@ -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(); + } } diff --git a/lttng/org.eclipse.linuxtools.tmf.core.tests/stubs/org/eclipse/linuxtools/tmf/tests/stubs/trace/TmfIndexerStub.java b/lttng/org.eclipse.linuxtools.tmf.core.tests/stubs/org/eclipse/linuxtools/tmf/tests/stubs/trace/TmfIndexerStub.java index a633f36b0a..f8258fb5e5 100644 --- a/lttng/org.eclipse.linuxtools.tmf.core.tests/stubs/org/eclipse/linuxtools/tmf/tests/stubs/trace/TmfIndexerStub.java +++ b/lttng/org.eclipse.linuxtools.tmf.core.tests/stubs/org/eclipse/linuxtools/tmf/tests/stubs/trace/TmfIndexerStub.java @@ -12,11 +12,9 @@ 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; /** * TmfIndexerStub @@ -31,7 +29,7 @@ public class TmfIndexerStub extends TmfCheckpointIndexer { super(trace, blockSize); } - public List getCheckpoints() { + public ITmfCheckpointIndex getCheckpoints() { return getTraceIndex(); } diff --git a/lttng/org.eclipse.linuxtools.tmf.core.tests/stubs/org/eclipse/linuxtools/tmf/tests/stubs/trace/TmfTraceStub.java b/lttng/org.eclipse.linuxtools.tmf.core.tests/stubs/org/eclipse/linuxtools/tmf/tests/stubs/trace/TmfTraceStub.java index 8eadfd7266..a2edc417d7 100644 --- a/lttng/org.eclipse.linuxtools.tmf.core.tests/stubs/org/eclipse/linuxtools/tmf/tests/stubs/trace/TmfTraceStub.java +++ b/lttng/org.eclipse.linuxtools.tmf.core.tests/stubs/org/eclipse/linuxtools/tmf/tests/stubs/trace/TmfTraceStub.java @@ -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; *

* 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); + } } diff --git a/lttng/org.eclipse.linuxtools.tmf.core/META-INF/MANIFEST.MF b/lttng/org.eclipse.linuxtools.tmf.core/META-INF/MANIFEST.MF index 1b7bf46056..3d4f71073e 100644 --- a/lttng/org.eclipse.linuxtools.tmf.core/META-INF/MANIFEST.MF +++ b/lttng/org.eclipse.linuxtools.tmf.core/META-INF/MANIFEST.MF @@ -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, diff --git a/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/TmfExperimentLocation.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/TmfExperimentLocation.java index bbd7b650df..4f6edec3c4 100644 --- a/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/TmfExperimentLocation.java +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/TmfExperimentLocation.java @@ -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/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/AbstractFileCheckpointCollection.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/AbstractFileCheckpointCollection.java new file mode 100644 index 0000000000..77832f1174 --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/AbstractFileCheckpointCollection.java @@ -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/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/BTree.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/BTree.java new file mode 100644 index 0000000000..d5d524207d --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/BTree.java @@ -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/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/BTreeCheckpointVisitor.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/BTreeCheckpointVisitor.java new file mode 100644 index 0000000000..20e10e2790 --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/BTreeCheckpointVisitor.java @@ -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/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/BTreeNode.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/BTreeNode.java new file mode 100644 index 0000000000..2a37b90b4d --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/BTreeNode.java @@ -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/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/BTreeNodeCache.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/BTreeNodeCache.java new file mode 100644 index 0000000000..c03ba077cf --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/BTreeNodeCache.java @@ -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 fCachedNodes = new ArrayDeque(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/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/FlatArray.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/FlatArray.java new file mode 100644 index 0000000000..de9d906888 --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/FlatArray.java @@ -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/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/IBTreeVisitor.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/IBTreeVisitor.java new file mode 100644 index 0000000000..4f4e560dca --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/IBTreeVisitor.java @@ -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/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/ICheckpointCollection.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/ICheckpointCollection.java new file mode 100644 index 0000000000..ea75482e7b --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/ICheckpointCollection.java @@ -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/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/Messages.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/Messages.java new file mode 100644 index 0000000000..f7c8631050 --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/Messages.java @@ -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/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/TmfMemoryIndex.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/TmfMemoryIndex.java new file mode 100644 index 0000000000..03fbcb2972 --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/TmfMemoryIndex.java @@ -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 fCheckpoints; + + /** + * Creates an index for the given trace + * + * @param trace the trace + */ + public TmfMemoryIndex(ITmfTrace trace) { + fCheckpoints = new ArrayList(); + } + + @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/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/messages.properties b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/messages.properties new file mode 100644 index 0000000000..6528587289 --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/internal/tmf/core/trace/indexer/messages.properties @@ -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} diff --git a/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/ctfadaptor/CtfLocation.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/ctfadaptor/CtfLocation.java index b310f822c8..55acb6b584 100644 --- a/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/ctfadaptor/CtfLocation.java +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/ctfadaptor/CtfLocation.java @@ -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); + + } } diff --git a/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/ctfadaptor/CtfLocationInfo.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/ctfadaptor/CtfLocationInfo.java index ea3f29b9e7..7a3c467815 100644 --- a/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/ctfadaptor/CtfLocationInfo.java +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/ctfadaptor/CtfLocationInfo.java @@ -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 { 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 { 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); + + } } diff --git a/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/ctfadaptor/CtfTmfTrace.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/ctfadaptor/CtfTmfTrace.java index 5edb8cda8f..f39a1a7132 100644 --- a/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/ctfadaptor/CtfTmfTrace.java +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/ctfadaptor/CtfTmfTrace.java @@ -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); + } } diff --git a/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/signal/TmfTraceUpdatedSignal.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/signal/TmfTraceUpdatedSignal.java index 176d431448..d8cb31f7b1 100644 --- a/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/signal/TmfTraceUpdatedSignal.java +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/signal/TmfTraceUpdatedSignal.java @@ -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() { diff --git a/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/timestamp/TmfTimestamp.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/timestamp/TmfTimestamp.java index 7fbe99c6a9..e3a4ecca73 100644 --- a/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/timestamp/TmfTimestamp.java +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/timestamp/TmfTimestamp.java @@ -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); + } } diff --git a/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfExperiment.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfExperiment.java index 8f5d2c6181..106492e920 100644 --- a/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfExperiment.java +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfExperiment.java @@ -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 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; + } + } diff --git a/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfTrace.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfTrace.java index 5810801fe6..f3f7c37a74 100644 --- a/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfTrace.java +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/TmfTrace.java @@ -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 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/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/ITmfPersistentlyIndexable.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/ITmfPersistentlyIndexable.java new file mode 100644 index 0000000000..b26a5b2bcc --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/ITmfPersistentlyIndexable.java @@ -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/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/TmfBTreeTraceIndex.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/TmfBTreeTraceIndex.java new file mode 100644 index 0000000000..39f2bf47e3 --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/TmfBTreeTraceIndex.java @@ -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/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/TmfBTreeTraceIndexer.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/TmfBTreeTraceIndexer.java new file mode 100644 index 0000000000..a4d76b2144 --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/TmfBTreeTraceIndexer.java @@ -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/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/TmfFlatArrayTraceIndex.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/TmfFlatArrayTraceIndex.java new file mode 100644 index 0000000000..c1fd940e5a --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/TmfFlatArrayTraceIndex.java @@ -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; + +/** + *

A checkpoint index that uses a FlatArray to store and search checkpoints by + * time stamps and by checkpoint rank.

+ * + *

Note: This index alone will not work for + * traces that have events with time stamps that are out of order.

+ * + * @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/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/TmfFlatArrayTraceIndexer.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/TmfFlatArrayTraceIndexer.java new file mode 100644 index 0000000000..7ae1cef6b1 --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/TmfFlatArrayTraceIndexer.java @@ -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); + } +} diff --git a/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/checkpoint/ITmfCheckpoint.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/checkpoint/ITmfCheckpoint.java index 9dcb499b07..e847fc2d85 100644 --- a/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/checkpoint/ITmfCheckpoint.java +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/checkpoint/ITmfCheckpoint.java @@ -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 { // 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 { @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/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/checkpoint/ITmfCheckpointIndex.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/checkpoint/ITmfCheckpointIndex.java new file mode 100644 index 0000000000..264e3604d2 --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/checkpoint/ITmfCheckpointIndex.java @@ -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(); +} diff --git a/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/checkpoint/TmfCheckpoint.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/checkpoint/TmfCheckpoint.java index e2d56243b8..b3c74722f3 100644 --- a/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/checkpoint/TmfCheckpoint.java +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/checkpoint/TmfCheckpoint.java @@ -14,7 +14,10 @@ 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; + } } diff --git a/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/checkpoint/TmfCheckpointIndexer.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/checkpoint/TmfCheckpointIndexer.java index 18ddef985d..9e830e326a 100644 --- a/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/checkpoint/TmfCheckpointIndexer.java +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/indexer/checkpoint/TmfCheckpointIndexer.java @@ -12,15 +12,12 @@ 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. *

* 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 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(); + 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 getTraceIndex() { + protected ITmfCheckpointIndex getTraceIndex() { return fTraceIndex; } diff --git a/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/location/ITmfLocation.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/location/ITmfLocation.java index 1280723a33..395c9d496a 100644 --- a/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/location/ITmfLocation.java +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/location/ITmfLocation.java @@ -13,6 +13,8 @@ package org.eclipse.linuxtools.tmf.core.trace.location; +import java.nio.ByteBuffer; + /** * The generic trace location in TMF. *

@@ -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); } diff --git a/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/location/TmfLongLocation.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/location/TmfLongLocation.java index 38877ca7ea..dd0785dff5 100644 --- a/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/location/TmfLongLocation.java +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/location/TmfLongLocation.java @@ -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()); + } + } diff --git a/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/location/TmfTimestampLocation.java b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/location/TmfTimestampLocation.java index 22c48f4535..4e76217cfe 100644 --- a/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/location/TmfTimestampLocation.java +++ b/lttng/org.eclipse.linuxtools.tmf.core/src/org/eclipse/linuxtools/tmf/core/trace/location/TmfTimestampLocation.java @@ -12,7 +12,10 @@ 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); + } } diff --git a/lttng/org.eclipse.linuxtools.tmf.ui.tests/META-INF/MANIFEST.MF b/lttng/org.eclipse.linuxtools.tmf.ui.tests/META-INF/MANIFEST.MF index 14860f0356..d364e2a652 100644 --- a/lttng/org.eclipse.linuxtools.tmf.ui.tests/META-INF/MANIFEST.MF +++ b/lttng/org.eclipse.linuxtools.tmf.ui.tests/META-INF/MANIFEST.MF @@ -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/lttng/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/TmfUITestPlugin.java b/lttng/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/TmfUITestPlugin.java new file mode 100644 index 0000000000..8988f54cc1 --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/TmfUITestPlugin.java @@ -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; + +/** + * TmfUITestPlugin + *

+ * 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/lttng/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/trace/AbstractCustomTraceIndexTest.java b/lttng/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/trace/AbstractCustomTraceIndexTest.java new file mode 100644 index 0000000000..da8138a2b7 --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/trace/AbstractCustomTraceIndexTest.java @@ -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(); + } +} diff --git a/lttng/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/trace/AllTests.java b/lttng/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/trace/AllTests.java index 4782199a5f..63f07ab917 100644 --- a/lttng/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/trace/AllTests.java +++ b/lttng/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/trace/AllTests.java @@ -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/lttng/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/trace/CustomTxtIndexTest.java b/lttng/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/trace/CustomTxtIndexTest.java new file mode 100644 index 0000000000..f6928d5296 --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/trace/CustomTxtIndexTest.java @@ -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/lttng/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/trace/CustomXmlIndexTest.java b/lttng/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/trace/CustomXmlIndexTest.java new file mode 100644 index 0000000000..3ee32c8790 --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.ui.tests/src/org/eclipse/linuxtools/tmf/ui/tests/trace/CustomXmlIndexTest.java @@ -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(""); + for (int i = 0; i < NB_EVENTS; ++i) { + SimpleDateFormat f = new SimpleDateFormat(TIMESTAMP_FORMAT); + String eventStr = "message\n"; + writer.write(eventStr); + } + writer.write(""); + 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/lttng/org.eclipse.linuxtools.tmf.ui.tests/tracesets/txt/testTxtDefinition.xml b/lttng/org.eclipse.linuxtools.tmf.ui.tests/tracesets/txt/testTxtDefinition.xml new file mode 100644 index 0000000000..ee2f9cbd73 --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.ui.tests/tracesets/txt/testTxtDefinition.xml @@ -0,0 +1,14 @@ + + + +dd/MM/yyyy HH:mm:ss:SSS + + +(\S*\s\S*) (.*\S) + + + + + + + diff --git a/lttng/org.eclipse.linuxtools.tmf.ui.tests/tracesets/xml/testDefinition.xml b/lttng/org.eclipse.linuxtools.tmf.ui.tests/tracesets/xml/testDefinition.xml new file mode 100644 index 0000000000..858f9d4e76 --- /dev/null +++ b/lttng/org.eclipse.linuxtools.tmf.ui.tests/tracesets/xml/testDefinition.xml @@ -0,0 +1,16 @@ + + + +HH:mm:ss:SSS + + + + + + + + + + + + diff --git a/lttng/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/parsers/custom/CustomTxtTrace.java b/lttng/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/parsers/custom/CustomTxtTrace.java index cfce95de46..028844c6ad 100644 --- a/lttng/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/parsers/custom/CustomTxtTrace.java +++ b/lttng/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/parsers/custom/CustomTxtTrace.java @@ -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); + } } diff --git a/lttng/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/parsers/custom/CustomXmlTrace.java b/lttng/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/parsers/custom/CustomXmlTrace.java index 4642df05f6..647212c0e6 100644 --- a/lttng/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/parsers/custom/CustomXmlTrace.java +++ b/lttng/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/internal/tmf/ui/parsers/custom/CustomXmlTrace.java @@ -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); + } } -- cgit v1.2.3