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,
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;
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);
}
// ------------------------------------------------------------------------
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
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.core.tests.trace.indexer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.ArrayList;
+import java.util.Random;
+
+import org.eclipse.linuxtools.internal.tmf.core.trace.indexer.ICheckpointCollection;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.TmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.location.TmfLongLocation;
+import org.eclipse.linuxtools.tmf.tests.stubs.trace.TmfTraceStub;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Common code for ICheckpointCollection test classes
+ *
+ * @author Marc-Andre Laperle
+ */
+public abstract class AbstractCheckpointCollectionTest {
+
+ private static final String INDEX_FILE_NAME = "checkpoint.idx"; //$NON-NLS-1$
+
+ /**
+ * The number of checkpoints to be inserted in insert tests
+ */
+ protected static final int CHECKPOINTS_INSERT_NUM = 50000;
+ /**
+ * The collection being tested
+ */
+ protected ICheckpointCollection fCheckpointCollection = null;
+
+ private TmfTraceStub fTrace;
+ private File fFile = new File(INDEX_FILE_NAME);
+
+ /**
+ * Setup the test. Make sure the index is deleted.
+ */
+ @Before
+ public void setUp() {
+ fTrace = new TmfTraceStub();
+ if (fFile.exists()) {
+ fFile.delete();
+ }
+ fCheckpointCollection = createCollection();
+ }
+
+ /**
+ * Tear down the test. Make sure the index is deleted.
+ */
+ @After
+ public void tearDown() {
+ fTrace.dispose();
+ fTrace = null;
+ if (fCheckpointCollection != null) {
+ fCheckpointCollection.dispose();
+ }
+ if (fFile.exists()) {
+ fFile.delete();
+ }
+ }
+
+ /**
+ * Get the trace being tested.
+ *
+ * @return the trace being tested.
+ */
+ public ITmfTrace getTrace() {
+ return fTrace;
+ }
+
+ /**
+ * Returns whether or not the collection is persisted to disk
+ *
+ * @return true if the collection is persisted to disk, false otherwise
+ */
+ public boolean isPersistableCollection() {
+ return false;
+ }
+
+ /**
+ * Get the file used for the index being tested.
+ *
+ * @return the file used for the index being tested.
+ */
+ public File getFile() {
+ return fFile;
+ }
+
+ /**
+ * Test constructing a new checkpoint collection
+ */
+ @Test
+ public void testConstructor() {
+ if (isPersistableCollection()) {
+ assertTrue(fFile.exists());
+ }
+ assertTrue(fCheckpointCollection.isCreatedFromScratch());
+ }
+
+ /**
+ * Test constructing a new checkpoint collection, existing file
+ */
+ @Test
+ public void testConstructorExistingFile() {
+ if (isPersistableCollection()) {
+ assertTrue(fFile.exists());
+ fCheckpointCollection.setIndexComplete();
+ fCheckpointCollection.dispose();
+
+ fCheckpointCollection = createCollection();
+ assertFalse(fCheckpointCollection.isCreatedFromScratch());
+ }
+ }
+
+ /**
+ * Test that a new checkpoint collection is considered created from scratch
+ * and vice versa
+ */
+ @Test
+ public void testIsCreatedFromScratch() {
+ assertTrue(fCheckpointCollection.isCreatedFromScratch());
+ fCheckpointCollection.setIndexComplete();
+
+ if (isPersistableCollection()) {
+ fCheckpointCollection.dispose();
+ fCheckpointCollection = createCollection();
+ assertFalse(fCheckpointCollection.isCreatedFromScratch());
+ }
+ }
+
+ /**
+ * Test setTimeRange, getTimeRange
+ */
+ @Test
+ public void testSetGetTimeRange() {
+ if (isPersistableCollection()) {
+ TmfTimeRange timeRange = new TmfTimeRange(new TmfTimestamp(0), new TmfTimestamp(100));
+ fCheckpointCollection.setTimeRange(timeRange);
+ assertEquals(timeRange, fCheckpointCollection.getTimeRange());
+ }
+ }
+
+ /**
+ * Create a collection for the test
+ *
+ * @return the collection
+ */
+ abstract protected ICheckpointCollection createCollection();
+
+ /**
+ * Test setNbEvents, getNbEvents
+ */
+ @Test
+ public void testSetGetNbEvents() {
+ if (isPersistableCollection()) {
+ int expected = 12345;
+ fCheckpointCollection.setNbEvents(expected);
+ assertEquals(expected, fCheckpointCollection.getNbEvents());
+ }
+ }
+
+ /**
+ * Test setSize, size
+ */
+ @Test
+ public void testSetGetSize() {
+ assertEquals(0, fCheckpointCollection.size());
+ int expected = CHECKPOINTS_INSERT_NUM;
+ for (int i = 0; i < expected; ++i) {
+ fCheckpointCollection.insert(new TmfCheckpoint(new TmfTimestamp(0), new TmfLongLocation(0L), 0));
+ }
+ assertEquals(expected, fCheckpointCollection.size());
+ }
+
+ /**
+ * Test delete
+ */
+ @Test
+ public void testDelete() {
+ if (isPersistableCollection()) {
+ assertTrue(fFile.exists());
+ fCheckpointCollection.delete();
+ assertFalse(fFile.exists());
+ }
+ }
+
+ /**
+ * Test version change
+ *
+ * @throws IOException
+ * can throw this
+ */
+ @Test
+ public void testVersionChange() throws IOException {
+ fCheckpointCollection.setIndexComplete();
+ fCheckpointCollection.dispose();
+ RandomAccessFile f = new RandomAccessFile(fFile, "rw");
+ f.writeInt(-1);
+ f.close();
+
+ fCheckpointCollection = createCollection();
+ assertTrue(fCheckpointCollection.isCreatedFromScratch());
+ }
+
+ /**
+ * Test a single insertion
+ */
+ @Test
+ public void testInsert() {
+ TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(12345), new TmfLongLocation(123456L), 0);
+ fCheckpointCollection.insert(checkpoint);
+
+ long found = fCheckpointCollection.binarySearch(checkpoint);
+ assertEquals(0, found);
+ }
+
+ /**
+ * Generate many checkpoints and insert them in the collection
+ *
+ * @return the list of generated checkpoints
+ */
+ protected ArrayList<Integer> insertAlot() {
+ for (int i = 0; i < CHECKPOINTS_INSERT_NUM; i++) {
+ TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(12345 + i), new TmfLongLocation(123456L + i), i);
+ fCheckpointCollection.insert(checkpoint);
+ }
+
+ fCheckpointCollection.setIndexComplete();
+ if (isPersistableCollection()) {
+ fCheckpointCollection.dispose();
+ }
+
+ boolean random = true;
+ ArrayList<Integer> list = new ArrayList<Integer>();
+ for (int i = 0; i < CHECKPOINTS_INSERT_NUM; i++) {
+ if (random) {
+ Random rand = new Random();
+ list.add(rand.nextInt(CHECKPOINTS_INSERT_NUM));
+ } else {
+ list.add(i);
+ }
+ }
+ return list;
+ }
+
+ /**
+ * Test many checkpoint insertions. Make sure they can be found after
+ * re-opening the file
+ */
+ @Test
+ public void testInsertAlot() {
+ ArrayList<Integer> list = insertAlot();
+
+ if (isPersistableCollection()) {
+ fCheckpointCollection = createCollection();
+ }
+
+ for (int i = 0; i < CHECKPOINTS_INSERT_NUM; i++) {
+ Integer randomCheckpoint = list.get(i);
+ TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(12345 + randomCheckpoint), new TmfLongLocation(123456L + randomCheckpoint), 0);
+ long found = fCheckpointCollection.binarySearch(checkpoint);
+ assertEquals(randomCheckpoint.intValue(), found);
+ }
+ }
+
+ /**
+ * Test many checkpoint insertions using the same timestamp. Make sure they
+ * can be found after re-opening the file
+ */
+ @Test
+ public void testInsertSameTimestamp() {
+ for (int i = 0; i < CHECKPOINTS_INSERT_NUM; i++) {
+ TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(12345), new TmfLongLocation(123456L + i), i);
+ fCheckpointCollection.insert(checkpoint);
+ }
+
+ fCheckpointCollection.setIndexComplete();
+ if (isPersistableCollection()) {
+ fCheckpointCollection.dispose();
+ }
+
+ boolean random = true;
+ ArrayList<Integer> list = new ArrayList<Integer>();
+ for (int i = 0; i < CHECKPOINTS_INSERT_NUM; i++) {
+ if (random) {
+ Random rand = new Random();
+ list.add(rand.nextInt(CHECKPOINTS_INSERT_NUM));
+ } else {
+ list.add(i);
+ }
+ }
+
+ if (isPersistableCollection()) {
+ fCheckpointCollection = createCollection();
+ }
+
+ for (int i = 0; i < CHECKPOINTS_INSERT_NUM; i++) {
+ Integer randomCheckpoint = list.get(i);
+ TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(12345), new TmfLongLocation(123456L + randomCheckpoint), 0);
+ long found = fCheckpointCollection.binarySearch(checkpoint);
+ assertEquals(randomCheckpoint.intValue(), found);
+ }
+ }
+
+ /**
+ * Tests that binarySearch find the correct checkpoint when the time stamp
+ * is between checkpoints
+ */
+ @Test
+ public void testBinarySearchFindInBetween() {
+ for (long i = 0; i < CHECKPOINTS_INSERT_NUM; i++) {
+ TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(2 * i), new TmfLongLocation(2 * i), i);
+ fCheckpointCollection.insert(checkpoint);
+ }
+
+ TmfCheckpoint searchedCheckpoint = new TmfCheckpoint(new TmfTimestamp(123), new TmfLongLocation(123L), 123);
+ int expectedInsertionPoint = 61;
+ int expectedRank = -(expectedInsertionPoint + 2);
+
+ long rank = fCheckpointCollection.binarySearch(searchedCheckpoint);
+ assertEquals(expectedRank, rank);
+ }
+
+
+ /**
+ * Tests that binarySearch finds the correct checkpoint when searching for a
+ * checkpoint with a null location. It should return the previous checkpoint
+ * from the first checkpoint that matches the timestamp.
+ */
+ @Test
+ public void testBinarySearchInBetweenSameTimestamp() {
+ int checkpointNum = 0;
+ for (; checkpointNum < 100; checkpointNum++) {
+ TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(0), new TmfLongLocation((long) checkpointNum), checkpointNum);
+ fCheckpointCollection.insert(checkpoint);
+ }
+
+ for (; checkpointNum < 200; checkpointNum++) {
+ TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(1), new TmfLongLocation((long) checkpointNum), checkpointNum);
+ fCheckpointCollection.insert(checkpoint);
+ }
+
+ final TmfCheckpoint searchedCheckpoint = new TmfCheckpoint(new TmfTimestamp(1), null, 0);
+
+ long found = fCheckpointCollection.binarySearch(searchedCheckpoint);
+
+ int expectedInsertionPoint = 99;
+ int expectedRank = -(expectedInsertionPoint + 2);
+
+ assertEquals(expectedRank, found);
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.core.tests.trace.indexer;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.ArrayList;
+import java.util.Random;
+
+import org.eclipse.linuxtools.internal.tmf.core.trace.indexer.BTree;
+import org.eclipse.linuxtools.internal.tmf.core.trace.indexer.BTreeCheckpointVisitor;
+import org.eclipse.linuxtools.internal.tmf.core.trace.indexer.FlatArray;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.TmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.location.TmfLongLocation;
+import org.eclipse.linuxtools.tmf.tests.stubs.trace.TmfTraceStub;
+
+/**
+ * A class to benchmark different algoritms for storing the
+ * checkpoint index on disk
+ *
+ * @author Marc-Andre Laperle
+ */
+public class AllBench {
+
+ private static final boolean reportProgress = true;
+ private static ArrayList<ArrayList<Integer>> nums;
+ private TmfTraceStub fTrace;
+ private File file = new File("index.idx");
+
+ static int BTREE_DEGREE = 10;
+
+ private void setUp() {
+ fTrace = new TmfTraceStub();
+ if (file.exists()) {
+ file.delete();
+ }
+ }
+
+ private void tearDown() {
+ fTrace.dispose();
+ fTrace = null;
+ if (file.exists()) {
+ file.delete();
+ }
+ }
+
+ private static void generateDataFile(ArrayList<Integer> list, int checkpointsNums) throws IOException {
+ File randomDataFile = new File("data" + checkpointsNums);
+ RandomAccessFile f = new RandomAccessFile(randomDataFile, "rw");
+ if (randomDataFile.exists()) {
+ for (int i = 0; i < checkpointsNums; i++) {
+ Random rand = new Random();
+ int nextInt = rand.nextInt(checkpointsNums);
+ list.add(nextInt);
+ f.writeInt(nextInt);
+ }
+ } else {
+ for (int i = 0; i < checkpointsNums; i++) {
+ list.add(f.readInt());
+ }
+ }
+ f.close();
+ }
+
+ @SuppressWarnings("javadoc")
+ public static void main(String[] args) throws IOException {
+ int checkpointsNums [] = new int [] { 5000, 50000, 500000, 1000000 };
+ nums = new ArrayList<ArrayList<Integer>>(checkpointsNums.length);
+
+ System.out.println("DEGREE: " + BTREE_DEGREE);
+
+ AllBench b = new AllBench();
+ b.setUp();
+ for (int i = 0; i < checkpointsNums.length; i++) {
+ ArrayList<Integer> list = new ArrayList<Integer>();
+ generateDataFile(list, checkpointsNums[i]);
+ nums.add(list);
+
+ System.out.println("*** " + checkpointsNums[i] + " checkpoints ***\n");
+
+ b.benchIt(list);
+ }
+ b.tearDown();
+ }
+
+ private void benchIt(ArrayList<Integer> list) {
+
+ System.out.println("Testing BTree\n");
+
+ testInsertAlot(list);
+
+ System.out.println("Testing Array\n");
+
+ testInsertAlotArray(list);
+ }
+
+ private void testInsertAlot(ArrayList<Integer> list2) {
+ int checkpointsNum = list2.size();
+
+ writeCheckpoints(checkpointsNum);
+
+ ArrayList<Integer> list = new ArrayList<Integer>();
+ for (int i = 0; i < checkpointsNum; i++) {
+ list.add(i);
+ }
+
+ readCheckpoints(checkpointsNum, list, false);
+ readCheckpoints(checkpointsNum, list2, true);
+
+ file.delete();
+
+ System.out.println();
+ }
+
+ private void testInsertAlotArray(ArrayList<Integer> list2) {
+ int checkpointsNum = list2.size();
+
+ writeCheckpointsArray(checkpointsNum);
+
+ ArrayList<Integer> list = new ArrayList<Integer>();
+ for (int i = 0; i < checkpointsNum; i++) {
+ list.add(i);
+ }
+
+ readCheckpointsArray(checkpointsNum, list, false);
+ readCheckpointsArray(checkpointsNum, list2, true);
+
+ file.delete();
+
+ System.out.println();
+ }
+
+ private void writeCheckpoints(int checkpointsNum) {
+ BTree bTree;
+ int REPEAT = 10;
+ long time = 0;
+ for (int j = 0; j < REPEAT; j++) {
+ long old = System.currentTimeMillis();
+ bTree = new BTree(BTREE_DEGREE, file, fTrace);
+ for (int i = 0; i < checkpointsNum; i++) {
+ TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(12345 + i), new TmfLongLocation(123456L + i), i);
+ bTree.insert(checkpoint);
+ }
+
+ time += (System.currentTimeMillis() - old);
+ bTree.setIndexComplete();
+ bTree.dispose();
+ if (j != REPEAT - 1) {
+ file.delete();
+ }
+ if (reportProgress) {
+ System.out.print(".");
+ }
+ }
+
+ System.out.println("Write time average: " + (float) time / REPEAT);
+ }
+
+ private void writeCheckpointsArray(int checkpointsNum) {
+ FlatArray array;
+ int REPEAT = 10;
+ long time = 0;
+ for (int j = 0; j < REPEAT; j++) {
+ long old = System.currentTimeMillis();
+ array = new FlatArray(file, fTrace);
+ for (int i = 0; i < checkpointsNum; i++) {
+ TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(12345 + i), new TmfLongLocation(123456L + i), i);
+ array.insert(checkpoint);
+ }
+
+ time += (System.currentTimeMillis() - old);
+ array.setIndexComplete();
+ array.dispose();
+ if (j != REPEAT - 1) {
+ file.delete();
+ }
+ if (reportProgress) {
+ System.out.print(".");
+ }
+ }
+
+ System.out.println("Write time average: " + (float) time / REPEAT);
+ }
+
+
+ private void readCheckpoints(int checkpointsNum, ArrayList<Integer> list, boolean random) {
+ BTree bTree;
+ int REPEAT = 10;
+ long time = 0;
+ long cacheMisses = 0;
+ for (int j = 0; j < REPEAT; j++) {
+ long old = System.currentTimeMillis();
+ bTree = new BTree(BTREE_DEGREE, file, fTrace);
+ for (int i = 0; i < checkpointsNum; i++) {
+ Integer randomCheckpoint = list.get(i);
+ TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(12345 + randomCheckpoint), new TmfLongLocation(123456L + randomCheckpoint), 0);
+ BTreeCheckpointVisitor treeVisitor = new BTreeCheckpointVisitor(checkpoint);
+ bTree.accept(treeVisitor);
+ assertEquals(randomCheckpoint.intValue(), treeVisitor.getCheckpoint().getCheckpointRank());
+ }
+ time += (System.currentTimeMillis() - old);
+ cacheMisses = bTree.getCacheMisses();
+ bTree.dispose();
+ if (reportProgress) {
+ System.out.print(".");
+ }
+ }
+
+ System.out.println("Read " + (random ? "(random)" : "(linear)") + "time average: " + (float) time / REPEAT + " (cache miss: " + cacheMisses + ")");
+ }
+
+ private void readCheckpointsArray(int checkpointsNum, ArrayList<Integer> list, boolean random) {
+ FlatArray array;
+ int REPEAT = 10;
+ long time = 0;
+ long cacheMisses = 0;
+ for (int j = 0; j < REPEAT; j++) {
+ long old = System.currentTimeMillis();
+ array = new FlatArray(file, fTrace);
+ for (int i = 0; i < checkpointsNum; i++) {
+ Integer randomCheckpoint = list.get(i);
+ TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(12345 + randomCheckpoint), new TmfLongLocation(123456L + randomCheckpoint), 0);
+ long found = array.binarySearch(checkpoint);
+ assertEquals(randomCheckpoint.intValue(), found);
+ }
+ time += (System.currentTimeMillis() - old);
+ cacheMisses = array.getCacheMisses();
+ array.dispose();
+ if (reportProgress) {
+ System.out.print(".");
+ }
+ }
+
+ System.out.println("Read " + (random ? "(random)" : "(linear)") + "time average: " + (float) time / REPEAT + " (cache miss: " + cacheMisses + ")");
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.core.tests.trace.indexer;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+
+import org.eclipse.linuxtools.internal.tmf.core.trace.indexer.BTree;
+import org.eclipse.linuxtools.internal.tmf.core.trace.indexer.BTreeCheckpointVisitor;
+import org.eclipse.linuxtools.internal.tmf.core.trace.indexer.IBTreeVisitor;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.ITmfPersistentlyIndexable;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.TmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.location.TmfLongLocation;
+import org.junit.Test;
+
+/**
+ * Tests for the BTree class
+ *
+ * @author Marc-Andre Laperle
+ */
+public class BTreeTest extends AbstractCheckpointCollectionTest {
+
+ private final int DEGREE = 15;
+ private BTree fBTree;
+
+ @Override
+ protected BTree createCollection() {
+ fBTree = new BTree(DEGREE, getFile(), (ITmfPersistentlyIndexable) getTrace());
+ return fBTree;
+ }
+
+ @Override
+ public boolean isPersistableCollection() {
+ return true;
+ }
+
+ /**
+ * Tests that accepts find the correct checkpoint and ends with a perfect
+ * match
+ */
+ @Test
+ public void testAccept() {
+ for (int i = 0; i < CHECKPOINTS_INSERT_NUM; i++) {
+ TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(i), new TmfLongLocation((long) i), 0);
+ fBTree.insert(checkpoint);
+ }
+
+ final TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(123), new TmfLongLocation(123L), 0);
+
+ class TestVisitor implements IBTreeVisitor {
+ public int fLastCompare = 0;
+ ITmfCheckpoint fFoundCheckpoint;
+
+ @Override
+ public int compare(ITmfCheckpoint checkRec) {
+ fLastCompare = checkRec.compareTo(checkpoint);
+ if (fLastCompare == 0) {
+ fFoundCheckpoint = checkRec;
+ }
+ return fLastCompare;
+ }
+ }
+ final TestVisitor t = new TestVisitor();
+
+ fBTree.accept(t);
+
+ assertEquals(checkpoint, t.fFoundCheckpoint);
+ assertEquals(0, t.fLastCompare);
+ }
+
+ /**
+ * Test many checkpoint insertions. Make sure they can be found after
+ * re-opening the file
+ */
+ @Test
+ public void testInsertAlotCheckEquals() {
+ ArrayList<Integer> list = insertAlot();
+
+ fBTree = createCollection();
+
+ for (int i = 0; i < CHECKPOINTS_INSERT_NUM; i++) {
+ Integer checkpointIndex = list.get(i);
+ TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(12345 + checkpointIndex), new TmfLongLocation(123456L + checkpointIndex), 0);
+ BTreeCheckpointVisitor treeVisitor = new BTreeCheckpointVisitor(checkpoint);
+ fBTree.accept(treeVisitor);
+ assertEquals(checkpoint, treeVisitor.getCheckpoint());
+ }
+ }
+
+ /**
+ * Test setSize, size
+ */
+ @Override
+ @Test
+ public void testSetGetSize() {
+ assertEquals(0, fBTree.size());
+ int expected = CHECKPOINTS_INSERT_NUM;
+ for (int i = 0; i < expected; ++i) {
+ fBTree.insert(new TmfCheckpoint(new TmfTimestamp(0), new TmfLongLocation(0L), 0));
+ fBTree.setSize(fBTree.size() + 1);
+ }
+ assertEquals(expected, fBTree.size());
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.core.tests.trace.indexer;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+
+import org.eclipse.linuxtools.internal.tmf.core.trace.indexer.FlatArray;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.ITmfPersistentlyIndexable;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.TmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.location.TmfLongLocation;
+import org.junit.Test;
+
+/**
+ * Tests for the FlatArray class
+ *
+ * @author Marc-Andre Laperle
+ */
+public class FlatArrayTest extends AbstractCheckpointCollectionTest {
+
+ private FlatArray fFlatArray;
+
+ @Override
+ protected FlatArray createCollection() {
+ fFlatArray = new FlatArray(getFile(), (ITmfPersistentlyIndexable) getTrace());
+ return fFlatArray;
+ }
+
+ @Override
+ public boolean isPersistableCollection() {
+ return true;
+ }
+
+ /**
+ * Tests that binarySearch find the correct checkpoint and ends with a
+ * perfect match
+ */
+ @Test
+ public void testBinarySearch() {
+ for (long i = 0; i < CHECKPOINTS_INSERT_NUM; i++) {
+ TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(i), new TmfLongLocation(i), 0);
+ fFlatArray.insert(checkpoint);
+ }
+
+ TmfCheckpoint expectedCheckpoint = new TmfCheckpoint(new TmfTimestamp(122), new TmfLongLocation(122L), 0);
+ int expectedRank = 122;
+
+ long rank = fFlatArray.binarySearch(expectedCheckpoint);
+ ITmfCheckpoint found = fFlatArray.get(rank);
+
+ assertEquals(expectedRank, rank);
+ assertEquals(found, expectedCheckpoint);
+ }
+
+ /**
+ * Test many checkpoint insertions. Make sure they can be found after
+ * re-opening the file
+ */
+ @Test
+ public void testInsertAlotCheckEquals() {
+ ArrayList<Integer> list = insertAlot();
+
+ fFlatArray = createCollection();
+
+ for (int i = 0; i < CHECKPOINTS_INSERT_NUM; i++) {
+ Integer checkpointIndex = list.get(i);
+ TmfCheckpoint checkpoint = new TmfCheckpoint(new TmfTimestamp(12345 + checkpointIndex), new TmfLongLocation(123456L + checkpointIndex), checkpointIndex);
+ ITmfCheckpoint found = fFlatArray.get(checkpointIndex);
+ assertEquals(checkpoint, found);
+ }
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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());
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * 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());
+ }
+}
*/
@RunWith(Suite.class)
@Suite.SuiteClasses({
+ TmfBTreeIndexTest.class,
TmfCheckpointIndexTest.class,
TmfCheckpointIndexTest2.class,
TmfCheckpointTest.class,
--- /dev/null
+/*******************************************************************************
+ * 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
package org.eclipse.linuxtools.tmf.core.tests.trace.indexer.checkpoint;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.util.List;
-
-import org.eclipse.core.runtime.FileLocator;
-import org.eclipse.core.runtime.Path;
-import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
-import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException;
-import org.eclipse.linuxtools.tmf.core.tests.TmfCoreTestPlugin;
-import org.eclipse.linuxtools.tmf.core.tests.shared.TmfTestTrace;
-import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
-import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
-import org.eclipse.linuxtools.tmf.core.trace.TmfContext;
-import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.TmfCheckpointIndexer;
-import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
-import org.eclipse.linuxtools.tmf.tests.stubs.trace.TmfEmptyTraceStub;
-import org.eclipse.linuxtools.tmf.tests.stubs.trace.TmfTraceStub;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
/**
* Test suite for the TmfCheckpointIndexTest class.
*/
-@SuppressWarnings("javadoc")
-public class TmfCheckpointIndexTest {
-
- // ------------------------------------------------------------------------
- // Variables
- // ------------------------------------------------------------------------
-
- private static final int BLOCK_SIZE = 100;
- private static final int NB_EVENTS = 10000;
- private static TestTrace fTrace = null;
- private static EmptyTestTrace fEmptyTrace = null;
-
- // ------------------------------------------------------------------------
- // Housekeeping
- // ------------------------------------------------------------------------
-
- @Before
- public void setUp() {
- setupTrace(TmfTestTrace.A_TEST_10K.getFullPath());
- }
-
- @After
- public void tearDown() {
- fTrace.dispose();
- fTrace = null;
- fEmptyTrace.dispose();
- fEmptyTrace = null;
- }
-
- // ------------------------------------------------------------------------
- // Helper classes
- // ------------------------------------------------------------------------
-
- private static class TestIndexer extends TmfCheckpointIndexer {
- @SuppressWarnings({ })
- public TestIndexer(TestTrace testTrace) {
- super(testTrace, BLOCK_SIZE);
- }
- @SuppressWarnings({ })
- public TestIndexer(EmptyTestTrace testTrace) {
- super(testTrace, BLOCK_SIZE);
- }
- public List<ITmfCheckpoint> getCheckpoints() {
- return getTraceIndex();
- }
- }
-
- private class TestTrace extends TmfTraceStub {
- public TestTrace(String path, int blockSize) throws TmfTraceException {
- super(path, blockSize, false, null, null);
- setIndexer(new TestIndexer(this));
- }
- @Override
- public TestIndexer getIndexer() {
- return (TestIndexer) super.getIndexer();
- }
- }
-
- private class EmptyTestTrace extends TmfEmptyTraceStub {
- public EmptyTestTrace() {
- super();
- setIndexer(new TestIndexer(this));
- }
- @Override
- public TestIndexer getIndexer() {
- return (TestIndexer) super.getIndexer();
- }
- }
-
- // ------------------------------------------------------------------------
- // Helper functions
- // ------------------------------------------------------------------------
-
- private synchronized void setupTrace(final String path) {
- if (fTrace == null) {
- try {
- final URL location = FileLocator.find(TmfCoreTestPlugin.getDefault().getBundle(), new Path(path), null);
- final File test = new File(FileLocator.toFileURL(location).toURI());
- fTrace = new TestTrace(test.toURI().getPath(), BLOCK_SIZE);
- fTrace.indexTrace(true);
- } catch (final TmfTraceException e) {
- e.printStackTrace();
- } catch (final URISyntaxException e) {
- e.printStackTrace();
- } catch (final IOException e) {
- e.printStackTrace();
- }
- }
-
- if (fEmptyTrace == null) {
- fEmptyTrace = new EmptyTestTrace();
- fEmptyTrace.indexTrace(true);
- }
- }
-
- // ------------------------------------------------------------------------
- // Verify checkpoints
- // ------------------------------------------------------------------------
-
- @Test
- public void testTmfTraceIndexing() {
- assertEquals("getCacheSize", BLOCK_SIZE, fTrace.getCacheSize());
- assertEquals("getTraceSize", NB_EVENTS, fTrace.getNbEvents());
- assertEquals("getRange-start", 1, fTrace.getTimeRange().getStartTime().getValue());
- assertEquals("getRange-end", NB_EVENTS, fTrace.getTimeRange().getEndTime().getValue());
- assertEquals("getStartTime", 1, fTrace.getStartTime().getValue());
- assertEquals("getEndTime", NB_EVENTS, fTrace.getEndTime().getValue());
-
- List<ITmfCheckpoint> checkpoints = fTrace.getIndexer().getCheckpoints();
- int pageSize = fTrace.getCacheSize();
- assertTrue("Checkpoints exist", checkpoints != null);
- assertEquals("Checkpoints size", NB_EVENTS / BLOCK_SIZE, checkpoints.size());
-
- // Validate that each checkpoint points to the right event
- for (int i = 0; i < checkpoints.size(); i++) {
- ITmfCheckpoint checkpoint = checkpoints.get(i);
- TmfContext context = new TmfContext(checkpoint.getLocation(), i * pageSize);
- ITmfEvent event = fTrace.parseEvent(context);
- assertTrue(context.getRank() == i * pageSize);
- assertTrue((checkpoint.getTimestamp().compareTo(event.getTimestamp(), false) == 0));
- }
- }
-
- @Test
- public void testEmptyTmfTraceIndexing() {
- assertEquals("getCacheSize", ITmfTrace.DEFAULT_TRACE_CACHE_SIZE, fEmptyTrace.getCacheSize());
- assertEquals("getTraceSize", 0, fEmptyTrace.getNbEvents());
- assertEquals("getRange-start", TmfTimestamp.BIG_BANG, fEmptyTrace.getTimeRange().getStartTime());
- assertEquals("getRange-end", TmfTimestamp.BIG_BANG, fEmptyTrace.getTimeRange().getEndTime());
- assertEquals("getStartTime", TmfTimestamp.BIG_BANG, fEmptyTrace.getStartTime());
- assertEquals("getEndTime", TmfTimestamp.BIG_BANG, fEmptyTrace.getEndTime());
-
- List<ITmfCheckpoint> checkpoints = fEmptyTrace.getIndexer().getCheckpoints();
- int pageSize = fEmptyTrace.getCacheSize();
- assertTrue("Checkpoints exist", checkpoints != null);
- assertEquals("Checkpoints size", 0, checkpoints.size());
-
- // Validate that each checkpoint points to the right event
- for (int i = 0; i < checkpoints.size(); i++) {
- ITmfCheckpoint checkpoint = checkpoints.get(i);
- TmfContext context = new TmfContext(checkpoint.getLocation(), i * pageSize);
- ITmfEvent event = fEmptyTrace.parseEvent(context);
- assertTrue(context.getRank() == i * pageSize);
- assertTrue((checkpoint.getTimestamp().compareTo(event.getTimestamp(), false) == 0));
- }
- }
+public class TmfCheckpointIndexTest extends AbstractIndexTest {
}
\ No newline at end of file
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.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;
public TestIndexer(EmptyTestTrace testTrace) {
super(testTrace, BLOCK_SIZE);
}
- public List<ITmfCheckpoint> getCheckpoints() {
+ public ITmfCheckpointIndex getCheckpoints() {
return getTraceIndex();
}
}
assertEquals("getStartTime", 1, fTrace.getStartTime().getValue());
assertEquals("getEndTime", 102, fTrace.getEndTime().getValue());
- List<ITmfCheckpoint> checkpoints = fTrace.getIndexer().getCheckpoints();
+ ITmfCheckpointIndex checkpoints = fTrace.getIndexer().getCheckpoints();
assertTrue("Checkpoints exist", checkpoints != null);
assertEquals("Checkpoints size", NB_EVENTS / BLOCK_SIZE + 1, checkpoints.size());
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
@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));
@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);
@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));
@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());
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.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;
assertEquals("getStartTime", 1, fExperiment.getStartTime().getValue());
assertEquals("getEndTime", NB_EVENTS, fExperiment.getEndTime().getValue());
- List<ITmfCheckpoint> checkpoints = fExperiment.getIndexer().getCheckpoints();
+ ITmfCheckpointIndex checkpoints = fExperiment.getIndexer().getCheckpoints();
int pageSize = fExperiment.getCacheSize();
assertTrue("Checkpoints exist", checkpoints != null);
assertEquals("Checkpoints size", NB_EVENTS / BLOCK_SIZE, checkpoints.size());
experiment.getIndexer().buildIndex(0, range, true);
// Validate that each checkpoint points to the right event
- List<ITmfCheckpoint> checkpoints = experiment.getIndexer().getCheckpoints();
+ ITmfCheckpointIndex checkpoints = experiment.getIndexer().getCheckpoints();
assertTrue("Checkpoints exist", checkpoints != null);
assertEquals("Checkpoints size", NB_EVENTS / BLOCK_SIZE / 2, checkpoints.size());
package org.eclipse.linuxtools.tmf.core.tests.trace.location;
+import java.nio.ByteBuffer;
+
import org.eclipse.linuxtools.tmf.core.trace.location.TmfLocation;
/**
return (String) super.getLocationInfo();
}
+ /**
+ * @since 3.0
+ */
+ @Override
+ public void serialize(ByteBuffer bufferOut) {
+ throw new UnsupportedOperationException();
+ }
}
package org.eclipse.linuxtools.tmf.tests.stubs.trace;
-import java.util.List;
-
import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpointIndex;
import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.TmfCheckpointIndexer;
-import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
/**
* <b><u>TmfIndexerStub</u></b>
super(trace, blockSize);
}
- public List<ITmfCheckpoint> getCheckpoints() {
+ public ITmfCheckpointIndex getCheckpoints() {
return getTraceIndex();
}
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;
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;
* <p>
* Dummy test trace. Use in conjunction with TmfEventParserStub.
*/
-public class TmfTraceStub extends TmfTrace implements ITmfEventParser {
+public class TmfTraceStub extends TmfTrace implements ITmfEventParser, ITmfPersistentlyIndexable {
// ------------------------------------------------------------------------
// Attributes
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);
+ }
}
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,
package org.eclipse.linuxtools.internal.tmf.core.trace;
+import java.nio.ByteBuffer;
+
import org.eclipse.linuxtools.tmf.core.trace.location.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]);
+ }
+ }
}
--- /dev/null
+/*******************************************************************************
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * 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
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.internal.tmf.core.trace.indexer;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+
+/**
+ * A simple LRU node cache. The BTree request a node from the cache and the
+ * cache load it from disk if it's not already in memory.
+ *
+ * This cache could be improved considerably by allowing bigger caches.
+ *
+ * @author Marc-Andre Laperle
+ */
+public class BTreeNodeCache {
+
+ /**
+ * Cache size obtained by experimentation. An improved cache could set this
+ * dynamically or using a user preference.
+ */
+ private static final int CACHE_SIZE = 15;
+
+ private final BTree fTree;
+ /**
+ * The root node is always kept in memory when {@link
+ * BTree#ALWAYS_CACHE_ROOT} is set to true
+ */
+ private BTreeNode fRootNode = null;
+ /**
+ * The collection keeping the nodes in memory. The most recently used is
+ * kept at the front of the double-ended queue and the least recently used
+ * node is kept at the back.
+ */
+ private final Deque<BTreeNode> fCachedNodes = new ArrayDeque<BTreeNode>(CACHE_SIZE);
+
+ private int fCcheMisses = 0;
+
+ /**
+ * Construct a new node cache for the given BTree
+ *
+ * @param tree
+ * the BTree that will use the cache
+ */
+ BTreeNodeCache(BTree tree) {
+ fTree = tree;
+ }
+
+ /**
+ * Get the node at the offset from the cache. If the node is not found in
+ * memory, it is loaded from disk.
+ *
+ * @param offset
+ * @return
+ */
+ BTreeNode getNode(long offset) {
+ if (fRootNode != null && fRootNode.getOffset() == offset) {
+ return fRootNode;
+ }
+
+ for (BTreeNode nodeSearch : fCachedNodes) {
+ if (nodeSearch.getOffset() == offset) {
+ // This node is now the most recently used
+ fCachedNodes.remove(nodeSearch);
+ fCachedNodes.push(nodeSearch);
+
+ return nodeSearch;
+ }
+ }
+
+ ++fCcheMisses;
+
+ BTreeNode node = new BTreeNode(fTree, offset);
+ node.serializeIn();
+ addNode(node);
+
+ return node;
+ }
+
+ /**
+ * Write all in-memory nodes to disk if they are dirty
+ */
+ void serialize() {
+ if (fRootNode != null && fRootNode.isDirty()) {
+ fRootNode.serializeOut();
+ }
+ for (BTreeNode nodeSearch : fCachedNodes) {
+ if (nodeSearch.isDirty()) {
+ nodeSearch.serializeOut();
+ }
+ }
+ }
+
+ /**
+ * Add a node to the cache. If the cache has reached the size specified with
+ * {@link #CACHE_SIZE}, the least recently used node is removed from memory.
+ *
+ * @param node
+ * the node to add to the cache
+ */
+ void addNode(BTreeNode node) {
+ if (fCachedNodes.size() >= CACHE_SIZE) {
+ BTreeNode removed = fCachedNodes.removeLast();
+ if (removed.isDirty()) {
+ removed.serializeOut();
+ }
+ }
+ fCachedNodes.push(node);
+ }
+
+ /**
+ * Set the root node. See {@link #fRootNode}
+ *
+ * @param newRootNode
+ * the new root node
+ */
+ void setRootNode(BTreeNode newRootNode) {
+ BTreeNode oldRootNode = fRootNode;
+ fRootNode = newRootNode;
+ if (oldRootNode != null) {
+ addNode(oldRootNode);
+ }
+ return;
+ }
+
+ /**
+ * Useful for benchmarks. Get the number of cache misses for the whole BTree
+ * instance lifetime. Cache misses occur when a node is requested and it's
+ * not in memory therefore it has to be read from disk.
+ *
+ * @return the number of cache misses.
+ */
+ int getCacheMisses() {
+ return fCcheMisses;
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * 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);
+}
--- /dev/null
+/*******************************************************************************
+ * 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();
+}
--- /dev/null
+/*******************************************************************************
+ * 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() {
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.internal.tmf.core.trace.indexer;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpointIndex;
+
+/**
+ * A checkpoint index that store all checkpoints in memory.
+ *
+ * @since 3.0
+ * @author Marc-Andre Laperle
+ */
+public class TmfMemoryIndex implements ITmfCheckpointIndex, ICheckpointCollection {
+
+ private final List<ITmfCheckpoint> fCheckpoints;
+
+ /**
+ * Creates an index for the given trace
+ *
+ * @param trace the trace
+ */
+ public TmfMemoryIndex(ITmfTrace trace) {
+ fCheckpoints = new ArrayList<ITmfCheckpoint>();
+ }
+
+ @Override
+ public void dispose() {
+ fCheckpoints.clear();
+ }
+
+ @Override
+ public void insert(ITmfCheckpoint checkpoint) {
+ fCheckpoints.add(checkpoint);
+ }
+
+ @Override
+ public ITmfCheckpoint get(long checkpoint) {
+ return fCheckpoints.get((int)checkpoint);
+ }
+
+ @Override
+ public long binarySearch(ITmfCheckpoint checkpoint) {
+ return Collections.binarySearch(fCheckpoints, checkpoint);
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return fCheckpoints.isEmpty();
+ }
+
+ @Override
+ public int size() {
+ return fCheckpoints.size();
+ }
+
+ @Override
+ public boolean isCreatedFromScratch() {
+ return true;
+ }
+
+ @Override
+ public void setTimeRange(TmfTimeRange timeRange) {
+ }
+
+ @Override
+ public void setNbEvents(long nbEvents) {
+ }
+
+ @Override
+ public TmfTimeRange getTimeRange() {
+ return null;
+ }
+
+ @Override
+ public long getNbEvents() {
+ return 0;
+ }
+
+ @Override
+ public void setIndexComplete() {
+ }
+
+ @Override
+ public void delete() {
+ }
+}
--- /dev/null
+###############################################################################
+# 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}
*******************************************************************************/
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;
// 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
*/
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);
+
+ }
}
*******************************************************************************/
package org.eclipse.linuxtools.tmf.core.ctfadaptor;
+import java.nio.ByteBuffer;
+
/**
* The data object to go in a {@link CtfLocation}.
*
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
*/
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);
+
+ }
}
package org.eclipse.linuxtools.tmf.core.ctfadaptor;
import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.Map;
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;
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;
/**
* @author Matthew khouzam
*/
public class CtfTmfTrace extends TmfTrace
- implements ITmfEventParser, ITmfTraceProperties {
+ implements ITmfEventParser, ITmfTraceProperties, ITmfPersistentlyIndexable {
// -------------------------------------------
// Constants
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);
+ }
}
private final ITmfTrace fTrace;
private final TmfTimeRange fTimeRange;
+ private final long fNbEvents;
/**
* Constructor
* 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;
}
/**
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() {
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
// 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;
}
}
+ /**
+ * 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);
+ }
}
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;
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;
/**
* @version 1.0
* @author Francois Chouinard
*/
-public class TmfExperiment extends TmfTrace implements ITmfEventParser {
+public class TmfExperiment extends TmfTrace implements ITmfEventParser, ITmfPersistentlyIndexable {
// ------------------------------------------------------------------------
// Constants
public TmfExperiment(final Class<? extends ITmfEvent> type, final String path, final ITmfTrace[] traces, final int indexPageSize, IResource resource) {
setCacheSize(indexPageSize);
setStreamingInterval(0);
- setIndexer(new TmfCheckpointIndexer(this, indexPageSize));
setParser(this);
+ fTraces = traces;
try {
super.initialize(resource, path, type);
} catch (TmfTraceException e) {
e.printStackTrace();
}
- fTraces = traces;
-
if (resource != null) {
try {
this.synchronizeTraces();
}
}
+ @Override
+ protected ITmfTraceIndexer createIndexer(int interval) {
+ if (getCheckpointSize() > 0) {
+ return new TmfBTreeTraceIndexer(this, interval);
+ }
+ return super.createIndexer(interval);
+ }
+
/**
* Clears the experiment
*/
}
}
+ @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;
+ }
+
}
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;
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;
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);
}
}
fCacheSize = trace.getCacheSize();
fStreamingInterval = trace.getStreamingInterval();
- fIndexer = new TmfCheckpointIndexer(this);
fParser = trace.fParser;
initialize(trace.getResource(), trace.getPath(), trace.getEventType());
}
+ /**
+ * Creates the indexer instance. Classes extending this class can override
+ * this to provide a different indexer implementation.
+ *
+ * @param interval the checkpoints interval
+ *
+ * @return the indexer
+ * @since 3.0
+ */
+ protected ITmfTraceIndexer createIndexer(int interval) {
+ return new TmfCheckpointIndexer(this, interval);
+ }
+
// ------------------------------------------------------------------------
// ITmfTrace - Initializers
// ------------------------------------------------------------------------
@Override
public void initTrace(final IResource resource, final String path, final Class<? extends ITmfEvent> type) throws TmfTraceException {
- fIndexer = new TmfCheckpointIndexer(this, fCacheSize);
initialize(resource, path, type);
}
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) {
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);
+ }
}
/**
}
}
+ /**
+ * 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.
--- /dev/null
+/*******************************************************************************
+ * 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();
+}
--- /dev/null
+/*******************************************************************************
+ * 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();
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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);
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.core.trace.indexer;
+
+import java.io.File;
+
+import org.eclipse.linuxtools.internal.tmf.core.trace.indexer.FlatArray;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
+import org.eclipse.linuxtools.tmf.core.trace.TmfTraceManager;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
+import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.ITmfCheckpointIndex;
+
+/**
+ * <p>A checkpoint index that uses a FlatArray to store and search checkpoints by
+ * time stamps and by checkpoint rank.</p>
+ *
+ * <p>Note: This index alone will not work for
+ * traces that have events with time stamps that are out of order.</p>
+ *
+ * @since 3.0
+ * @author Marc-Andre Laperle
+ */
+public class TmfFlatArrayTraceIndex implements ITmfCheckpointIndex {
+
+ private final FlatArray fCheckpoints;
+
+ /**
+ * Creates an index for the given trace
+ *
+ * @param trace the trace
+ */
+ public TmfFlatArrayTraceIndex(ITmfTrace trace) {
+ fCheckpoints = new FlatArray(getIndexFile(trace, FlatArray.INDEX_FILE_NAME), (ITmfPersistentlyIndexable)trace);
+ }
+
+ private static File getIndexFile(ITmfTrace trace, String fileName) {
+ String directory = TmfTraceManager.getSupplementaryFileDir(trace);
+ return new File(directory + fileName);
+ }
+
+ @Override
+ public void dispose() {
+ fCheckpoints.dispose();
+ }
+
+ @Override
+ public void insert(ITmfCheckpoint checkpoint) {
+ fCheckpoints.insert(checkpoint);
+ }
+
+ @Override
+ public ITmfCheckpoint get(long checkpoint) {
+ return fCheckpoints.get(checkpoint);
+ }
+
+ @Override
+ public long binarySearch(ITmfCheckpoint checkpoint) {
+ return fCheckpoints.binarySearch(checkpoint);
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return size() == 0;
+ }
+
+ @Override
+ public int size() {
+ return fCheckpoints.size();
+ }
+
+ @Override
+ public boolean isCreatedFromScratch() {
+ return fCheckpoints.isCreatedFromScratch();
+ }
+
+ @Override
+ public void setTimeRange(TmfTimeRange timeRange) {
+ fCheckpoints.setTimeRange(timeRange);
+ }
+
+ @Override
+ public void setNbEvents(long nbEvents) {
+ fCheckpoints.setNbEvents(nbEvents);
+ }
+
+ @Override
+ public TmfTimeRange getTimeRange() {
+ return fCheckpoints.getTimeRange();
+ }
+
+ @Override
+ public long getNbEvents() {
+ return fCheckpoints.getNbEvents();
+ }
+
+ @Override
+ public void setIndexComplete() {
+ fCheckpoints.setIndexComplete();
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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);
+ }
+}
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;
// 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
@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);
}
--- /dev/null
+/*******************************************************************************
+ * 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();
+}
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;
/**
// The checkpoint timestamp
private final ITmfTimestamp fTimestamp;
+ private final long fCheckpointRank;
+
// ------------------------------------------------------------------------
// Constructors
// ------------------------------------------------------------------------
/**
* 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();
}
/**
}
fTimestamp = other.fTimestamp;
fLocation = other.fLocation;
+ fCheckpointRank = other.fCheckpointRank;
}
// ------------------------------------------------------------------------
@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;
+ }
}
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;
/**
* A simple indexer that manages the trace index as an array of trace
- * checkpoints. Checkpoints are stored at fixed intervals (event rank) in
+ * checkpoints. Checkpoints are stored in memory at fixed intervals (event rank) in
* ascending timestamp order.
* <p>
* The goal being to access a random trace event reasonably fast from the user's
* The trace index. It is composed of checkpoints taken at intervals of
* fCheckpointInterval events.
*/
- protected final List<ITmfCheckpoint> fTraceIndex;
+ protected final ITmfCheckpointIndex fTraceIndex;
/**
* The indexing request
public TmfCheckpointIndexer(final ITmfTrace trace, final int interval) {
fTrace = trace;
fCheckpointInterval = interval;
- fTraceIndex = new ArrayList<ITmfCheckpoint>();
+ fTraceIndex = createIndex(trace);
fIsIndexing = false;
}
+ /**
+ * Creates the index instance. Classes extending this class
+ * can override this to provide a different index implementation.
+ *
+ * @param trace the trace to index
+ * @return the index
+ * @since 3.0
+ */
+ protected ITmfCheckpointIndex createIndex(final ITmfTrace trace) {
+ return new TmfMemoryIndex(trace);
+ }
+
@Override
public void dispose() {
if ((fIndexingRequest != null) && !fIndexingRequest.isCompleted()) {
fIndexingRequest.cancel();
- fTraceIndex.clear();
}
+
+ fTraceIndex.dispose();
}
// ------------------------------------------------------------------------
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
@Override
public void handleSuccess() {
+ fTraceIndex.setTimeRange(fTrace.getTimeRange());
+ fTraceIndex.setNbEvents(fTrace.getNbEvents());
+ fTraceIndex.setIndexComplete();
updateTraceStatus();
}
* @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()));
}
// ------------------------------------------------------------------------
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));
}
}
}
// 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 {
* @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;
}
}
final ITmfContext context = fTrace.seekEvent(location);
- context.setRank((long) index * fCheckpointInterval);
+ context.setRank(index * fCheckpointInterval);
return context;
}
/**
* @return the trace index
+ * @since 3.0
*/
- protected List<ITmfCheckpoint> getTraceIndex() {
+ protected ITmfCheckpointIndex getTraceIndex() {
return fTraceIndex;
}
package org.eclipse.linuxtools.tmf.core.trace.location;
+import java.nio.ByteBuffer;
+
/**
* The generic trace location in TMF.
* <p>
*/
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);
}
package org.eclipse.linuxtools.tmf.core.trace.location;
+import java.nio.ByteBuffer;
/**
* A concrete implementation of TmfLocation based on Long:s
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());
+ }
+
}
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
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);
+ }
}
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
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Marc-Andre Laperle - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.ui.tests;
+
+import org.eclipse.core.runtime.Plugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * <b><u>TmfUITestPlugin</u></b>
+ * <p>
+ * The activator class controls the plug-in life cycle
+ *
+ * @author Marc-Andre Laperle
+ */
+public class TmfUITestPlugin extends Plugin {
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ /**
+ * The plug-in ID
+ */
+ public static final String PLUGIN_ID = "org.eclipse.linuxtools.tmf.ui.tests";
+
+ // The shared instance
+ private static TmfUITestPlugin fPlugin;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * The constructor
+ */
+ public TmfUITestPlugin() {
+ setDefault(this);
+ }
+
+ // ------------------------------------------------------------------------
+ // Accessors
+ // ------------------------------------------------------------------------
+
+ /**
+ * @return the shared instance
+ */
+ public static TmfUITestPlugin getDefault() {
+ return fPlugin;
+ }
+
+ /**
+ * @param plugin the shared instance
+ */
+ private static void setDefault(TmfUITestPlugin plugin) {
+ fPlugin = plugin;
+ }
+
+ // ------------------------------------------------------------------------
+ // Operations
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ setDefault(this);
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ setDefault(null);
+ super.stop(context);
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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();
+ }
+}
import org.junit.runners.Suite;
/**
- * Test suite for Xml parser validation
+ * Test suite for custom parsers
* @author Matthew Khouzam
*
*/
@Suite.SuiteClasses({
CustomXmlTraceInvalidTest.class,
CustomXmlTraceBadlyFormedTest.class,
- CustomXmlTraceValidTest.class
+ CustomXmlTraceValidTest.class,
+ CustomXmlIndexTest.class,
+ CustomTxtIndexTest.class
})
public class AllTests {
}
--- /dev/null
+/*******************************************************************************
+ * 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
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2009, 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Francois Chouinard - Initial API and implementation
+ * Francois Chouinard - Adapted for TMF Trace Model 1.0
+ * Alexandre Montplaisir - Port to JUnit4
+ * Marc-Andre Laperle - Adapted to CustomXmlTrace
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.tmf.ui.tests.trace;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.eclipse.linuxtools.internal.tmf.ui.parsers.custom.CustomXmlTrace;
+import org.eclipse.linuxtools.internal.tmf.ui.parsers.custom.CustomXmlTraceDefinition;
+import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException;
+
+/**
+ * Test suite for indexing using a CustomXmlTrace.
+ *
+ * @author Marc-Andre Laperle
+ */
+public class CustomXmlIndexTest extends AbstractCustomTraceIndexTest {
+
+ private static final String TRACE_DIRECTORY = System.getProperty("java.io.tmpdir") + File.separator + "dummyXmlTrace";
+ private static final String TRACE_PATH = TRACE_DIRECTORY + File.separator + "test.xml";
+ private static final String DEFINITION_PATH = "tracesets" + File.separator + "xml" + File.separator + "testDefinition.xml";
+
+ private static CustomXmlTraceDefinition createDefinition() {
+ CustomXmlTraceDefinition[] definitions = CustomXmlTraceDefinition.loadAll(new File(DEFINITION_PATH).toString());
+ return definitions[0];
+ }
+
+ @Override
+ protected String getTraceDirectory() {
+ return TRACE_DIRECTORY;
+ }
+
+ @Override
+ protected TestTrace createTrace() throws Exception {
+ CustomXmlTraceDefinition definition = createDefinition();
+ final File file = new File(TRACE_PATH);
+ BufferedWriter writer = new BufferedWriter(new FileWriter(file));
+ writer.write("<trace>");
+ for (int i = 0; i < NB_EVENTS; ++i) {
+ SimpleDateFormat f = new SimpleDateFormat(TIMESTAMP_FORMAT);
+ String eventStr = "<element time=\"" + f.format(new Date(i)) + "\">message</element>\n";
+ writer.write(eventStr);
+ }
+ writer.write("</trace>");
+ writer.close();
+
+ return new TestXmlTrace(file.toString(), definition, BLOCK_SIZE);
+ }
+
+ private class TestXmlTrace extends CustomXmlTrace implements TestTrace {
+ public TestXmlTrace(String path, CustomXmlTraceDefinition createDefinition, int blockSize) throws TmfTraceException {
+ super(null, createDefinition, path, blockSize);
+ setIndexer(new TestIndexer(this, blockSize));
+ }
+
+ @Override
+ public TestIndexer getIndexer() {
+ return (TestIndexer) super.getIndexer();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<CustomTxtTraceDefinitionList>
+<Definition name="testtxt">
+<TimeStampOutputFormat>dd/MM/yyyy HH:mm:ss:SSS</TimeStampOutputFormat>
+<InputLine>
+<Cardinality max="2147483647" min="0"/>
+<RegEx>(\S*\s\S*) (.*\S)</RegEx>
+<InputData action="0" format="dd/MM/yyyy HH:mm:ss:SSS" name="Time Stamp"/>
+<InputData action="0" format="" name="Message"/>
+</InputLine>
+<OutputColumn name="Time Stamp"/>
+<OutputColumn name="Message"/>
+</Definition>
+</CustomTxtTraceDefinitionList>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<CustomXMLTraceDefinitionList>
+<Definition name="myxml">
+<TimeStampOutputFormat>HH:mm:ss:SSS</TimeStampOutputFormat>
+<InputElement name="trace">
+<InputElement logentry="true" name="element">
+<InputData action="0" format="" name="Message"/>
+<Attribute name="time">
+<InputData action="0" format="dd/MM/yyyy HH:mm:ss:SSS" name="Time Stamp"/>
+</Attribute>
+</InputElement>
+</InputElement>
+<OutputColumn name="Time Stamp"/>
+<OutputColumn name="Message"/>
+</Definition>
+</CustomXMLTraceDefinitionList>
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;
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;
*
* @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;
}
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);
+ }
}
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;
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;
*
* @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;
}
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);
+ }
}