timing core: Support sorting in the segment Store data provider

Before this commit, segments were fetched based on start timestamp
sorting. This commit adds the possibility to fetch segment using any
given comparator in the fetch parameters.

Add test cases where some segments are fetched based on the end timestamp
comparator.

Change-Id: Ib990dc4c26fca4909a7ac56fa93ed0d5ae8ed4d8
Signed-off-by: Kyrollos Bekhet <kyrollos.bekhet@ericsson.com>
Reviewed-on: https://git.eclipse.org/r/c/tracecompass/org.eclipse.tracecompass/+/194715
Tested-by: Trace Compass Bot <tracecompass-bot@eclipse.org>
Tested-by: Bernd Hufmann <bernd.hufmann@ericsson.com>
Tested-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Reviewed-by: Bernd Hufmann <bernd.hufmann@ericsson.com>
Reviewed-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.core.tests/src/org/eclipse/tracecompass/analysis/timing/core/tests/segmentstore/SegmentStoreTableDataProviderTest.java b/analysis/org.eclipse.tracecompass.analysis.timing.core.tests/src/org/eclipse/tracecompass/analysis/timing/core/tests/segmentstore/SegmentStoreTableDataProviderTest.java
index f0f8159..57596c6 100644
--- a/analysis/org.eclipse.tracecompass.analysis.timing.core.tests/src/org/eclipse/tracecompass/analysis/timing/core/tests/segmentstore/SegmentStoreTableDataProviderTest.java
+++ b/analysis/org.eclipse.tracecompass.analysis.timing.core.tests/src/org/eclipse/tracecompass/analysis/timing/core/tests/segmentstore/SegmentStoreTableDataProviderTest.java
@@ -21,6 +21,7 @@
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.tracecompass.internal.analysis.timing.core.segmentstore.SegmentStoreTableDataProvider;
@@ -58,6 +59,8 @@
     private static final String START_TIME_COLUMN_NAME = "Start Time";
     private static final String END_TIME_COLUMN_NAME = "End Time";
     private static final String DURATION_COLUMN_NAME = "Duration";
+    private static final String TABLE_COMPARATOR_EXPRESSION_KEY = "table_comparator_expression"; //$NON-NLS-1$
+
     private static Map<String, Long> fColumns = Collections.emptyMap();
     private static TmfXmlTraceStub fTrace;
     private static final String TABLE_SEARCH_EXPRESSION_KEY = "table_search_expressions"; //$NON-NLS-1$
@@ -73,7 +76,8 @@
     @BeforeClass
     public static void init() throws TmfAnalysisException {
         fTrace = new TmfXmlTraceStubNs();
-        @NonNull StubSegmentStoreProvider fixture = getValidSegment(fTrace);
+        @NonNull
+        StubSegmentStoreProvider fixture = getValidSegment(fTrace);
         ITmfTrace trace = fTrace;
         assertNotNull(trace);
         fDataProvider = new SegmentStoreTableDataProvider(fTrace, fixture, "org.eclipse.tracecompass.analysis.timing.core.tests.segmentstore");
@@ -119,13 +123,9 @@
 
     /**
      * Test column returned by the provider.
-     *
-     * @throws InterruptedException
-     *             Exception thrown if test takes longer than 200ms.
      */
-    @SuppressWarnings("null")
-    @Test(timeout = 200)
-    public void testDataProviderFetchColumn() throws InterruptedException {
+    @Test
+    public void testDataProviderFetchColumn() {
         Long startTimeColumnId = fColumns.get(START_TIME_COLUMN_NAME);
         Long endTimeColumnId = fColumns.get(END_TIME_COLUMN_NAME);
         Long durationColumnId = fColumns.get(DURATION_COLUMN_NAME);
@@ -139,22 +139,19 @@
                 new TmfTreeDataModel(endTimeColumnId, -1, Collections.singletonList(END_TIME_COLUMN_NAME)),
                 new TmfTreeDataModel(durationColumnId, -1, Collections.singletonList(DURATION_COLUMN_NAME)));
 
-        TmfModelResponse<TmfTreeModel<@NonNull TmfTreeDataModel>> response = fDataProvider.fetchTree(FetchParametersUtils.timeQueryToMap(new TimeQueryFilter(0, 0, 1)), null);
+        TmfModelResponse<@NonNull TmfTreeModel<@NonNull TmfTreeDataModel>> response = fDataProvider.fetchTree(FetchParametersUtils.timeQueryToMap(new TimeQueryFilter(0, 0, 1)), null);
         TmfTreeModel<@NonNull TmfTreeDataModel> currentColumnModel = response.getModel();
         assertNotNull(currentColumnModel);
-        List<@NonNull TmfTreeDataModel> currentColumnEntries = currentColumnModel.getEntries();
+        List<@NonNull TmfTreeDataModel> currentColumnEntries = Objects.requireNonNull(currentColumnModel).getEntries();
         assertEquals(expectedColumnEntries, currentColumnEntries);
     }
 
     /**
      * Test lines returned by the provider if the query starts from index zero.
-     *
-     * @throws InterruptedException
-     *             Exception thrown if test takes longer than 200ms
      */
     @SuppressWarnings("null")
-    @Test(timeout = 200)
-    public void testDataProviderFetchLineZeroIndex() throws InterruptedException {
+    @Test
+    public void testDataProviderFetchLineZeroIndex() {
         VirtualTableQueryFilter queryFilter = new VirtualTableQueryFilter(Collections.emptyList(), 0, 5);
         @NonNull
         List<@NonNull SegmentStoreTableLine> expectedData = Arrays.asList(
@@ -163,7 +160,7 @@
                 new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(0)), new VirtualTableCell(lineTime(2)), new VirtualTableCell(lineDuration(2))), 2),
                 new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(0)), new VirtualTableCell(lineTime(3)), new VirtualTableCell(lineDuration(3))), 3),
                 new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(0)), new VirtualTableCell(lineTime(4)), new VirtualTableCell(lineDuration(4))), 4));
-        TmfModelResponse<ITmfVirtualTableModel<@NonNull SegmentStoreTableLine>> response = fDataProvider.fetchLines(FetchParametersUtils.virtualTableQueryToMap(queryFilter), null);
+        TmfModelResponse<@NonNull ITmfVirtualTableModel<@NonNull SegmentStoreTableLine>> response = fDataProvider.fetchLines(FetchParametersUtils.virtualTableQueryToMap(queryFilter), null);
         ITmfVirtualTableModel<@NonNull SegmentStoreTableLine> currentModel = response.getModel();
         assertNotNull(currentModel);
         ITmfVirtualTableModel<@NonNull SegmentStoreTableLine> expectedModel = new TmfVirtualTableModel<>(new ArrayList<>(fColumns.values()), expectedData, 0, 65535);
@@ -173,13 +170,10 @@
     /**
      * Test lines returned by the provider if the query starts from a non zero
      * index.
-     *
-     * @throws InterruptedException
-     *             Exception thrown if test takes longer than 200ms.
      */
     @SuppressWarnings("null")
-    @Test(timeout = 200)
-    public void testDataProviderFetchLineNonZeroIndex() throws InterruptedException {
+    @Test
+    public void testDataProviderFetchLineNonZeroIndex() {
         VirtualTableQueryFilter queryFilter = new VirtualTableQueryFilter(Collections.emptyList(), 10, 5);
         List<@NonNull SegmentStoreTableLine> expectedData = Arrays.asList(
                 new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(7)), new VirtualTableCell(lineTime(10)), new VirtualTableCell(lineDuration(3))), 10),
@@ -187,7 +181,7 @@
                 new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(7)), new VirtualTableCell(lineTime(12)), new VirtualTableCell(lineDuration(5))), 12),
                 new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(7)), new VirtualTableCell(lineTime(13)), new VirtualTableCell(lineDuration(6))), 13),
                 new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(14)), new VirtualTableCell(lineTime(14)), new VirtualTableCell(lineDuration(0))), 14));
-        TmfModelResponse<ITmfVirtualTableModel<@NonNull SegmentStoreTableLine>> response = fDataProvider.fetchLines(FetchParametersUtils.virtualTableQueryToMap(queryFilter), null);
+        TmfModelResponse<@NonNull ITmfVirtualTableModel<@NonNull SegmentStoreTableLine>> response = fDataProvider.fetchLines(FetchParametersUtils.virtualTableQueryToMap(queryFilter), null);
         ITmfVirtualTableModel<@NonNull SegmentStoreTableLine> currentModel = response.getModel();
         assertNotNull(currentModel);
         ITmfVirtualTableModel<@NonNull SegmentStoreTableLine> expectedModel = new TmfVirtualTableModel<>(new ArrayList<>(fColumns.values()), expectedData, 10, 65535);
@@ -197,13 +191,10 @@
     /**
      * Test the performance and efficiency of the fetch method of the provider
      * by requesting a segment with a big rank in the segment store.
-     *
-     * @throws InterruptedException
-     *             Exception thrown if test takes longer than 200ms.
      */
     @SuppressWarnings("null")
-    @Test(timeout = 200)
-    public void testDataProviderFetchLineTimeOut() throws InterruptedException {
+    @Test
+    public void testDataProviderFetchLineTimeOut() {
         VirtualTableQueryFilter queryFilter = new VirtualTableQueryFilter(Collections.emptyList(), 3200, 5);
         List<@NonNull SegmentStoreTableLine> expectedData = Arrays.asList(
                 new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(3199)), new VirtualTableCell(lineTime(3200)), new VirtualTableCell(lineDuration(1))), 3200),
@@ -211,7 +202,7 @@
                 new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(3199)), new VirtualTableCell(lineTime(3202)), new VirtualTableCell(lineDuration(3))), 3202),
                 new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(3199)), new VirtualTableCell(lineTime(3203)), new VirtualTableCell(lineDuration(4))), 3203),
                 new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(3199)), new VirtualTableCell(lineTime(3204)), new VirtualTableCell(lineDuration(5))), 3204));
-        TmfModelResponse<ITmfVirtualTableModel<@NonNull SegmentStoreTableLine>> response = fDataProvider.fetchLines(FetchParametersUtils.virtualTableQueryToMap(queryFilter), null);
+        TmfModelResponse<@NonNull ITmfVirtualTableModel<@NonNull SegmentStoreTableLine>> response = fDataProvider.fetchLines(FetchParametersUtils.virtualTableQueryToMap(queryFilter), null);
         ITmfVirtualTableModel<@NonNull SegmentStoreTableLine> currentModel = response.getModel();
         assertNotNull(currentModel);
         ITmfVirtualTableModel<@NonNull SegmentStoreTableLine> expectedModel = new TmfVirtualTableModel<>(new ArrayList<>(fColumns.values()), expectedData, 3200, 65535);
@@ -220,13 +211,10 @@
 
     /**
      * Test lines returned by the provider.
-     *
-     * @throws InterruptedException
-     *             Exception thrown if test takes longer than 200ms.
      */
     @SuppressWarnings("null")
-    @Test(timeout = 200)
-    public void testDataProviderFetchLineCornerIndex() throws InterruptedException {
+    @Test
+    public void testDataProviderFetchLineCornerIndex() {
         VirtualTableQueryFilter queryFilter = new VirtualTableQueryFilter(Collections.emptyList(), 1000, 5);
         List<@NonNull SegmentStoreTableLine> expectedData = Arrays.asList(
                 new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(994)), new VirtualTableCell(lineTime(1000)), new VirtualTableCell(lineDuration(6))), 1000),
@@ -234,7 +222,7 @@
                 new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(1001)), new VirtualTableCell(lineTime(1002)), new VirtualTableCell(lineDuration(1))), 1002),
                 new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(1001)), new VirtualTableCell(lineTime(1003)), new VirtualTableCell(lineDuration(2))), 1003),
                 new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(1001)), new VirtualTableCell(lineTime(1004)), new VirtualTableCell(lineDuration(3))), 1004));
-        TmfModelResponse<ITmfVirtualTableModel<@NonNull SegmentStoreTableLine>> response = fDataProvider.fetchLines(FetchParametersUtils.virtualTableQueryToMap(queryFilter), null);
+        TmfModelResponse<@NonNull ITmfVirtualTableModel<@NonNull SegmentStoreTableLine>> response = fDataProvider.fetchLines(FetchParametersUtils.virtualTableQueryToMap(queryFilter), null);
         ITmfVirtualTableModel<@NonNull SegmentStoreTableLine> currentModel = response.getModel();
         assertNotNull(currentModel);
         ITmfVirtualTableModel<@NonNull SegmentStoreTableLine> expectedModel = new TmfVirtualTableModel<>(new ArrayList<>(fColumns.values()), expectedData, 1000, 65535);
@@ -249,7 +237,8 @@
     @Test
     public void testDataProviderFetchLineWithSearch() {
         VirtualTableQueryFilter queryFilter = new VirtualTableQueryFilter(Collections.emptyList(), 0, 5);
-        Map<String, Object> fetchParameters = FetchParametersUtils.virtualTableQueryToMap(queryFilter);
+        @NonNull
+        Map<@NonNull String, @NonNull Object> fetchParameters = FetchParametersUtils.virtualTableQueryToMap(queryFilter);
         Map<Long, String> searchMap = new HashMap<>();
         searchMap.put(fColumns.get(START_TIME_COLUMN_NAME), lineTime(7000));
         fetchParameters.put(TABLE_SEARCH_EXPRESSION_KEY, searchMap);
@@ -261,7 +250,7 @@
                 new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(7000)), new VirtualTableCell(lineTime(7003)), new VirtualTableCell(lineDuration(3))), 7003),
                 new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(7000)), new VirtualTableCell(lineTime(7004)), new VirtualTableCell(lineDuration(4))), 7004));
         expectedData.forEach(sl -> sl.setActiveProperties(CoreFilterProperty.HIGHLIGHT));
-        TmfModelResponse<ITmfVirtualTableModel<@NonNull SegmentStoreTableLine>> response = fDataProvider.fetchLines(fetchParameters, null);
+        TmfModelResponse<@NonNull ITmfVirtualTableModel<@NonNull SegmentStoreTableLine>> response = fDataProvider.fetchLines(fetchParameters, null);
         ITmfVirtualTableModel<@NonNull SegmentStoreTableLine> currentModel = response.getModel();
         assertNotNull(currentModel);
         ITmfVirtualTableModel<@NonNull SegmentStoreTableLine> expectedModel = new TmfVirtualTableModel<>(new ArrayList<>(fColumns.values()), expectedData, 7000, 65535);
@@ -269,7 +258,8 @@
     }
 
     /**
-     * This test test the case if we went beyond the end time stored in the index
+     * This test test the case if we went beyond the end time stored in the
+     * index
      */
     @SuppressWarnings("null")
     @Test
@@ -284,13 +274,114 @@
             }
             expectedData.add(new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(previousStartTime)), new VirtualTableCell(lineTime(i)), new VirtualTableCell(lineDuration(i - previousStartTime))), i));
         }
-        TmfModelResponse<ITmfVirtualTableModel<@NonNull SegmentStoreTableLine>> response = fDataProvider.fetchLines(FetchParametersUtils.virtualTableQueryToMap(queryFilter), null);
+        TmfModelResponse<@NonNull ITmfVirtualTableModel<@NonNull SegmentStoreTableLine>> response = fDataProvider.fetchLines(FetchParametersUtils.virtualTableQueryToMap(queryFilter), null);
         ITmfVirtualTableModel<@NonNull SegmentStoreTableLine> currentModel = response.getModel();
         assertNotNull(currentModel);
         ITmfVirtualTableModel<@NonNull SegmentStoreTableLine> expectedModel = new TmfVirtualTableModel<>(new ArrayList<>(fColumns.values()), expectedData, 0, 65535);
         assertEquals(expectedModel, currentModel);
     }
 
+    /**
+     * Test lines returned by the provider with an end comparator requested in
+     * the query parameters.
+     */
+    @SuppressWarnings("null")
+    @Test
+    public void testDataProviderFetchLineWithEndTimeComparator() {
+        VirtualTableQueryFilter queryFilter = new VirtualTableQueryFilter(Collections.emptyList(), 0, 5);
+        @NonNull
+        Map<@NonNull String, @NonNull Object> fetchParameters = FetchParametersUtils.virtualTableQueryToMap(queryFilter);
+        Object endTimeColumnID = fColumns.get(END_TIME_COLUMN_NAME);
+        assertNotNull(endTimeColumnID);
+        fetchParameters.put(TABLE_COMPARATOR_EXPRESSION_KEY, endTimeColumnID);
+        List<@NonNull SegmentStoreTableLine> expectedData = Arrays.asList(
+                new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(65534)), new VirtualTableCell(lineTime(65534)), new VirtualTableCell(lineDuration(0))), 0),
+                new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(65527)), new VirtualTableCell(lineTime(65533)), new VirtualTableCell(lineDuration(6))), 1),
+                new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(65527)), new VirtualTableCell(lineTime(65532)), new VirtualTableCell(lineDuration(5))), 2),
+                new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(65527)), new VirtualTableCell(lineTime(65531)), new VirtualTableCell(lineDuration(4))), 3),
+                new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(65527)), new VirtualTableCell(lineTime(65530)), new VirtualTableCell(lineDuration(3))), 4));
+        TmfModelResponse<@NonNull ITmfVirtualTableModel<@NonNull SegmentStoreTableLine>> response = fDataProvider.fetchLines(fetchParameters, null);
+        ITmfVirtualTableModel<@NonNull SegmentStoreTableLine> currentModel = response.getModel();
+        assertNotNull(currentModel);
+        ITmfVirtualTableModel<@NonNull SegmentStoreTableLine> expectedModel = new TmfVirtualTableModel<>(new ArrayList<>(fColumns.values()), expectedData, 0, 65535);
+        assertEquals(expectedModel, currentModel);
+    }
+
+    /**
+     * Test lines returned by the provider with a duration comparator requested
+     * in the query parameters.
+     */
+    @SuppressWarnings("null")
+    @Test
+    public void testDataProviderFetchLineWithDurationComparator() {
+        VirtualTableQueryFilter queryFilter = new VirtualTableQueryFilter(Collections.emptyList(), 0, 5);
+        Map<String, Object> fetchParameters = FetchParametersUtils.virtualTableQueryToMap(queryFilter);
+        Object durationColumnID = fColumns.get(DURATION_COLUMN_NAME);
+        assertNotNull(durationColumnID);
+        fetchParameters.put(TABLE_COMPARATOR_EXPRESSION_KEY, durationColumnID);
+        List<@NonNull SegmentStoreTableLine> expectedData = Arrays.asList(
+                new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(0)), new VirtualTableCell(lineTime(0)), new VirtualTableCell(lineDuration(0))), 0),
+                new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(7)), new VirtualTableCell(lineTime(7)), new VirtualTableCell(lineDuration(0))), 1),
+                new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(14)), new VirtualTableCell(lineTime(14)), new VirtualTableCell(lineDuration(0))), 2),
+                new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(21)), new VirtualTableCell(lineTime(21)), new VirtualTableCell(lineDuration(0))), 3),
+                new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(28)), new VirtualTableCell(lineTime(28)), new VirtualTableCell(lineDuration(0))), 4));
+        TmfModelResponse<@NonNull ITmfVirtualTableModel<@NonNull SegmentStoreTableLine>> response = fDataProvider.fetchLines(fetchParameters, null);
+        ITmfVirtualTableModel<@NonNull SegmentStoreTableLine> currentModel = response.getModel();
+        assertNotNull(currentModel);
+        ITmfVirtualTableModel<@NonNull SegmentStoreTableLine> expectedModel = new TmfVirtualTableModel<>(new ArrayList<>(fColumns.values()), expectedData, 0, 65535);
+        assertEquals(expectedModel, currentModel);
+    }
+
+    /**
+     * Test last lines in the segment store returned by the provider with an end
+     * comparator requested in the query parameters.
+     */
+    @SuppressWarnings("null")
+    @Test
+    public void testDataProviderFetchLastLinesWithEndComparator() {
+        VirtualTableQueryFilter queryFilter = new VirtualTableQueryFilter(Collections.emptyList(), 65529, 5);
+        Map<String, Object> fetchParameters = FetchParametersUtils.virtualTableQueryToMap(queryFilter);
+        Object endTimeColumnID = fColumns.get(END_TIME_COLUMN_NAME);
+        assertNotNull(endTimeColumnID);
+        fetchParameters.put(TABLE_COMPARATOR_EXPRESSION_KEY, endTimeColumnID);
+        List<@NonNull SegmentStoreTableLine> expectedData = Arrays.asList(
+                new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(0)), new VirtualTableCell(lineTime(5)), new VirtualTableCell(lineDuration(5))), 65529),
+                new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(0)), new VirtualTableCell(lineTime(4)), new VirtualTableCell(lineDuration(4))), 65530),
+                new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(0)), new VirtualTableCell(lineTime(3)), new VirtualTableCell(lineDuration(3))), 65531),
+                new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(0)), new VirtualTableCell(lineTime(2)), new VirtualTableCell(lineDuration(2))), 65532),
+                new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(0)), new VirtualTableCell(lineTime(1)), new VirtualTableCell(lineDuration(1))), 65533));
+        TmfModelResponse<@NonNull ITmfVirtualTableModel<@NonNull SegmentStoreTableLine>> response = fDataProvider.fetchLines(fetchParameters, null);
+        ITmfVirtualTableModel<@NonNull SegmentStoreTableLine> currentModel = response.getModel();
+        assertNotNull(currentModel);
+        ITmfVirtualTableModel<@NonNull SegmentStoreTableLine> expectedModel = new TmfVirtualTableModel<>(new ArrayList<>(fColumns.values()), expectedData, 65529, 65535);
+        assertEquals(expectedModel, currentModel);
+    }
+
+    /**
+     * Test last lines in the segment store returned by the provider with a
+     * duration comparator requested in the query parameters.
+     */
+    @SuppressWarnings("null")
+    @Test
+    public void testDataProviderFetchLastLinesWithDurationComparator() {
+        VirtualTableQueryFilter queryFilter = new VirtualTableQueryFilter(Collections.emptyList(), 65529, 5);
+        Map<String, Object> fetchParameters = FetchParametersUtils.virtualTableQueryToMap(queryFilter);
+        Object durationColumnID = fColumns.get(DURATION_COLUMN_NAME);
+        assertNotNull(durationColumnID);
+        fetchParameters.put(TABLE_COMPARATOR_EXPRESSION_KEY, durationColumnID);
+        List<@NonNull SegmentStoreTableLine> expectedData = Arrays.asList(
+                new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(65492)), new VirtualTableCell(lineTime(65498)), new VirtualTableCell(lineDuration(6))), 65529),
+                new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(65499)), new VirtualTableCell(lineTime(65505)), new VirtualTableCell(lineDuration(6))), 65530),
+                new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(65506)), new VirtualTableCell(lineTime(65512)), new VirtualTableCell(lineDuration(6))), 65531),
+                new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(65513)), new VirtualTableCell(lineTime(65519)), new VirtualTableCell(lineDuration(6))), 65532),
+                new SegmentStoreTableLine(Arrays.asList(new VirtualTableCell(lineTime(65520)), new VirtualTableCell(lineTime(65526)), new VirtualTableCell(lineDuration(6))), 65533));
+        TmfModelResponse<@NonNull ITmfVirtualTableModel<@NonNull SegmentStoreTableLine>> response = fDataProvider.fetchLines(fetchParameters, null);
+        ITmfVirtualTableModel<@NonNull SegmentStoreTableLine> currentModel = response.getModel();
+        assertNotNull(currentModel);
+        ITmfVirtualTableModel<@NonNull SegmentStoreTableLine> expectedModel = new TmfVirtualTableModel<>(new ArrayList<>(fColumns.values()), expectedData, 65529, 65535);
+        assertEquals(expectedModel, currentModel);
+    }
+
     // helper methods
     private static String lineTime(long milliseconds) {
         return TmfTimestamp.fromNanos(milliseconds).toString();
diff --git a/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/segmentstore/SegmentStoreTableDataProvider.java b/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/segmentstore/SegmentStoreTableDataProvider.java
index a0e8cc7..d311fb0 100644
--- a/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/segmentstore/SegmentStoreTableDataProvider.java
+++ b/analysis/org.eclipse.tracecompass.analysis.timing.core/src/org/eclipse/tracecompass/internal/analysis/timing/core/segmentstore/SegmentStoreTableDataProvider.java
@@ -60,6 +60,8 @@
 import org.eclipse.tracecompass.tmf.core.response.ITmfResponse;
 import org.eclipse.tracecompass.tmf.core.response.TmfModelResponse;
 import org.eclipse.tracecompass.tmf.core.segment.ISegmentAspect;
+import org.eclipse.tracecompass.tmf.core.segment.SegmentDurationAspect;
+import org.eclipse.tracecompass.tmf.core.segment.SegmentEndTimeAspect;
 import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
 import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
 
@@ -83,10 +85,12 @@
     private static class SegmentStoreIndex {
         private long fCounter;
         private long fStartTimestamp;
+        private long fLength;
 
-        public SegmentStoreIndex(long startTimeStamp, long counter) {
+        public SegmentStoreIndex(long startTimeStamp, long counter, long length) {
             fStartTimestamp = startTimeStamp;
             fCounter = counter;
+            fLength = length;
         }
 
         public long getStartTimestamp() {
@@ -96,6 +100,10 @@
         public long getCounter() {
             return fCounter;
         }
+
+        public long getLength() {
+            return fLength;
+        }
     }
 
     /**
@@ -108,26 +116,41 @@
     private static class SegmentPredicate implements Predicate<ISegment> {
         private final long fStartTime;
         private long fCount;
+        private long fLength;
+        private boolean fDurationComparator;
 
-        public SegmentPredicate(SegmentStoreIndex segmentIndex) {
+        public SegmentPredicate(SegmentStoreIndex segmentIndex, String aspectName) {
             fStartTime = segmentIndex.getStartTimestamp();
             fCount = segmentIndex.getCounter();
+            fLength = segmentIndex.getLength();
+            fDurationComparator = aspectName.equals(SegmentDurationAspect.SEGMENT_DURATION_ASPECT.getName());
         }
 
         @Override
         public boolean test(ISegment segment) {
-            if (segment.getStart() > fStartTime) {
-                return true;
-            }
-            if (segment.getStart() == fStartTime) {
-                if (fCount == 0) {
+            if (isDurationValid(segment.getLength())) {
+                if (segment.getStart() > fStartTime) {
                     return true;
                 }
-                fCount--;
+                if (segment.getStart() == fStartTime) {
+                    if (fCount == 0) {
+                        return true;
+                    }
+                    fCount--;
+                }
             }
             return false;
         }
 
+        private boolean isDurationValid(long segmentLength) {
+            if (!fDurationComparator) {
+                return true;
+            }
+            if (segmentLength == fLength) {
+                return true;
+            }
+            return false;
+        }
     }
 
     /**
@@ -162,6 +185,44 @@
     }
 
     /**
+     * A wrapper class to encapsulate the indexes with the comparator that was
+     * used to create the indexes.
+     *
+     * @author Kyrollos Bekhet
+     *
+     */
+    private class SegmentIndexesComparatorWrapper {
+        private List<SegmentStoreIndex> fIndexes;
+        private Comparator<ISegment> fComparator;
+        private String fAspectName;
+
+        @SuppressWarnings("null")
+        public SegmentIndexesComparatorWrapper() {
+            fComparator = SegmentComparators.INTERVAL_START_COMPARATOR.thenComparing(Comparator.comparingLong(ISegment::getLength));
+            fIndexes = new ArrayList<>();
+            fAspectName = StringUtils.EMPTY;
+        }
+
+        public SegmentIndexesComparatorWrapper(List<SegmentStoreIndex> indexes, Comparator<ISegment> comparator, String aspectName) {
+            fIndexes = indexes;
+            fComparator = comparator;
+            fAspectName = aspectName;
+        }
+
+        public List<SegmentStoreIndex> getIndexes() {
+            return fIndexes;
+        }
+
+        public Comparator<ISegment> getComparator() {
+            return fComparator;
+        }
+
+        public String getAspectName() {
+            return fAspectName;
+        }
+    }
+
+    /**
      * The id of the data provider
      */
     public static final String ID = "org.eclipse.tracecompass.analysis.timing.core.segmentstore.SegmentStoreTableDataProvider"; //$NON-NLS-1$
@@ -172,12 +233,14 @@
     private static final Logger LOGGER = TraceCompassLog.getLogger(SegmentStoreTableDataProvider.class);
     private static final String TABLE_SEARCH_EXPRESSION_KEY = "table_search_expressions"; //$NON-NLS-1$
     private static final String TABLE_SEARCH_DIRECTION_KEY = "table_search_direction"; //$NON-NLS-1$
+    private static final String TABLE_COMPARATOR_EXPRESSION_KEY = "table_comparator_expression"; //$NON-NLS-1$
 
-    private final Object fLock = new Object();
+    private Map<Long, SegmentIndexesComparatorWrapper> fAllIndexes;
+    private SegmentIndexesComparatorWrapper fDefaultWrapper;
     private final String fId;
-    private final Comparator<ISegment> fComparator;
-    private List<SegmentStoreIndex> fIndexes = new ArrayList<>();
     private @Nullable ISegmentStoreProvider fSegmentProvider = null;
+    private boolean fIsFirstAspect;
+    private final int fSegmentStoreSize;
 
     /**
      * Constructor
@@ -191,22 +254,21 @@
      * @param analysisId
      *            The analysis identifier.
      */
-    @SuppressWarnings("null")
     public SegmentStoreTableDataProvider(ITmfTrace trace, ISegmentStoreProvider segmentProvider, String analysisId) {
         super(trace);
         TraceCompassLogUtils.traceObjectCreation(LOGGER, Level.FINE, this);
         fId = analysisId;
-        fComparator = SegmentComparators.INTERVAL_START_COMPARATOR.thenComparing(Comparator.comparingLong(ISegment::getLength));
-        ISegmentStore<ISegment> segments = segmentProvider.getSegmentStore();
-        if (segments == null && segmentProvider instanceof IAnalysisModule) {
+        fIsFirstAspect = true;
+        fAllIndexes = new HashMap<>();
+        fDefaultWrapper = new SegmentIndexesComparatorWrapper();
+        ISegmentStore<ISegment> segmentStore = segmentProvider.getSegmentStore();
+        if (segmentStore == null && segmentProvider instanceof IAnalysisModule) {
             ((IAnalysisModule) segmentProvider).schedule();
             ((IAnalysisModule) segmentProvider).waitForCompletion();
+            segmentStore = segmentProvider.getSegmentStore();
         }
         fSegmentProvider = segmentProvider;
-        segments = segmentProvider.getSegmentStore();
-        if (segments != null) {
-            buildIndex(segments);
-        }
+        fSegmentStoreSize = segmentStore != null? segmentStore.size() : 0;
     }
 
     @Override
@@ -217,20 +279,38 @@
     /**
      * Build the indexes which will act like checkpoints for the data provider.
      *
-     * @param segmentProvider
-     *            The segment provider to use.
+     * @param id
+     *            the id of the aspect in the {@link fAspectToIdMap}.
+     * @param comparator
+     *            The comparator used to build the indexes array
+     * @param aspectName
+     *            The name of the aspect.
      */
-    private void buildIndex(ISegmentStore<ISegment> segments) {
-        TraceCompassLogUtils.traceAsyncStart(LOGGER, Level.FINE, "SegmentStoreTableDataProvider#buildIndex", fId, 0); //$NON-NLS-1$
-        synchronized (fLock) {
-            try (FlowScopeLog scope = new FlowScopeLogBuilder(LOGGER, Level.FINE, "SegmentStoreTableDataProvider#buildIndex.buildingIndexes").build()) { //$NON-NLS-1$
-                TraceCompassLogUtils.traceObjectCreation(LOGGER, Level.FINE, fLock);
-                Iterable<ISegment> sortedSegmentStore = segments.iterator(fComparator);
-                fIndexes = getIndexes(sortedSegmentStore);
-            } catch (Exception ex) {
-                TraceCompassLogUtils.traceInstant(LOGGER, Level.SEVERE, "error build index", ex.getMessage()); //$NON-NLS-1$
-            } finally {
-                TraceCompassLogUtils.traceObjectDestruction(LOGGER, Level.FINE, fLock);
+    private void buildIndex(long id, Comparator<ISegment> comparator, String aspectName) {
+        if (fAllIndexes.containsKey(id)) {
+            return;
+        }
+        if (fSegmentProvider != null) {
+            ISegmentStore<ISegment> segStore = fSegmentProvider.getSegmentStore();
+            if (segStore != null) {
+                synchronized (fAllIndexes) {
+                    try (FlowScopeLog scope = new FlowScopeLogBuilder(LOGGER, Level.FINE, "SegmentStoreTableDataProvider#buildIndex.buildingIndexes").build()) { //$NON-NLS-1$
+                        TraceCompassLogUtils.traceObjectCreation(LOGGER, Level.FINE, fAllIndexes);
+                        Iterable<ISegment> sortedSegmentStore = segStore.iterator(comparator);
+                        List<SegmentStoreIndex> indexes = getIndexes(sortedSegmentStore);
+                        if (fIsFirstAspect) {
+                            fDefaultWrapper = new SegmentIndexesComparatorWrapper(indexes, comparator, aspectName);
+                            fIsFirstAspect = false;
+                            fAllIndexes.put(id, fDefaultWrapper);
+                        } else {
+                            fAllIndexes.put(id, new SegmentIndexesComparatorWrapper(indexes, comparator, aspectName));
+                        }
+                    } catch (Exception ex) {
+                        TraceCompassLogUtils.traceInstant(LOGGER, Level.SEVERE, "error build index", ex.getMessage()); //$NON-NLS-1$
+                    } finally {
+                        TraceCompassLogUtils.traceObjectDestruction(LOGGER, Level.FINE, fAllIndexes);
+                    }
+                }
             }
         }
     }
@@ -248,7 +328,7 @@
                 counter = 0;
             }
             if (i % STEP == 0) {
-                indexes.add(new SegmentStoreIndex(segment.getStart(), counter));
+                indexes.add(new SegmentStoreIndex(segment.getStart(), counter, segment.getLength()));
             }
             i++;
         }
@@ -260,12 +340,20 @@
         return fId;
     }
 
+    @SuppressWarnings("unchecked")
     @Override
     public TmfModelResponse<TmfTreeModel<TmfTreeDataModel>> fetchTree(Map<String, Object> fetchParameters, @Nullable IProgressMonitor monitor) {
         List<TmfTreeDataModel> model = new ArrayList<>();
         for (final ISegmentAspect aspect : ISegmentStoreProvider.getBaseSegmentAspects()) {
             synchronized (fAspectToIdMap) {
                 long id = fAspectToIdMap.computeIfAbsent(aspect, a -> fAtomicLong.getAndIncrement());
+                Comparator<ISegment> comparator = (Comparator<ISegment>) aspect.getComparator();
+                if (comparator != null && aspect.getName().equals(SegmentEndTimeAspect.SEGMENT_END_TIME_ASPECT.getName())) {
+                    comparator = comparator.reversed();
+                }
+                if (comparator != null) {
+                    buildIndex(id, comparator, aspect.getName());
+                }
                 model.add(new TmfTreeDataModel(id, -1, Collections.singletonList(aspect.getName())));
             }
         }
@@ -273,6 +361,10 @@
             synchronized (fAspectToIdMap) {
                 for (final ISegmentAspect aspect : fSegmentProvider.getSegmentAspects()) {
                     long id = fAspectToIdMap.computeIfAbsent(aspect, a -> fAtomicLong.getAndIncrement());
+                    Comparator<ISegment> comparator = (Comparator<ISegment>) aspect.getComparator();
+                    if (comparator != null) {
+                        buildIndex(id, comparator, aspect.getName());
+                    }
                     model.add(new TmfTreeDataModel(id, -1, Collections.singletonList(aspect.getName())));
                 }
             }
@@ -288,6 +380,7 @@
         if (queryFilter == null) {
             return new TmfModelResponse<>(null, ITmfResponse.Status.FAILED, CommonStatusMessage.INCORRECT_QUERY_PARAMETERS);
         }
+        SegmentIndexesComparatorWrapper indexesComparatorWrapper = getIndexesComparatorOrDefault(fetchParameters);
         Map<Long, ISegmentAspect> aspects = getAspectsFromColumnId(queryFilter.getColumnsId());
         if (aspects.isEmpty()) {
             return new TmfModelResponse<>(new TmfVirtualTableModel<>(Collections.emptyList(), Collections.emptyList(), queryFilter.getIndex(), 0), ITmfResponse.Status.COMPLETED, CommonStatusMessage.COMPLETED);
@@ -299,17 +392,17 @@
                 if (segStore.isEmpty()) {
                     return new TmfModelResponse<>(new TmfVirtualTableModel<>(columnIds, Collections.emptyList(), queryFilter.getIndex(), 0), ITmfResponse.Status.COMPLETED, CommonStatusMessage.COMPLETED);
                 }
-                if (queryFilter.getIndex() > segStore.size()) {
+                if (queryFilter.getIndex() >= fSegmentStoreSize) {
                     return new TmfModelResponse<>(null, ITmfResponse.Status.COMPLETED, CommonStatusMessage.COMPLETED);
                 }
-                synchronized (fLock) {
+                synchronized (fAllIndexes) {
                     try (FlowScopeLog scope = new FlowScopeLogBuilder(LOGGER, Level.FINE, "SegmentStoreTableDataProvider#fetchLines").build()) { //$NON-NLS-1$
-                        TraceCompassLogUtils.traceObjectCreation(LOGGER, Level.FINE, fLock);
-                        return extractRequestedLines(queryFilter, fetchParameters, segStore, aspects);
+                        TraceCompassLogUtils.traceObjectCreation(LOGGER, Level.FINE, fAllIndexes);
+                        return extractRequestedLines(queryFilter, fetchParameters, segStore, aspects, indexesComparatorWrapper);
                     } catch (Exception ex) {
                         TraceCompassLogUtils.traceInstant(LOGGER, Level.SEVERE, "error fetching lines ", ex.getMessage()); //$NON-NLS-1$
                     } finally {
-                        TraceCompassLogUtils.traceObjectDestruction(LOGGER, Level.FINE, fLock);
+                        TraceCompassLogUtils.traceObjectDestruction(LOGGER, Level.FINE, fAllIndexes);
                     }
                 }
             }
@@ -317,18 +410,19 @@
         return new TmfModelResponse<>(null, ITmfResponse.Status.FAILED, CommonStatusMessage.INCORRECT_QUERY_PARAMETERS);
     }
 
-    private TmfModelResponse<ITmfVirtualTableModel<SegmentStoreTableLine>> extractRequestedLines(VirtualTableQueryFilter queryFilter, Map<String, Object> fetchParameters, ISegmentStore<ISegment> segmentStore, Map<Long, ISegmentAspect> aspects) {
+    private static TmfModelResponse<ITmfVirtualTableModel<SegmentStoreTableLine>> extractRequestedLines(VirtualTableQueryFilter queryFilter, Map<String, Object> fetchParameters, ISegmentStore<ISegment> segmentStore, Map<Long, ISegmentAspect> aspects,
+            SegmentIndexesComparatorWrapper indexesComparatorWrapper) {
         VirtualTableQueryFilter localQueryFilter = queryFilter;
         @Nullable Predicate<ISegment> searchFilter = generateFilter(fetchParameters);
         List<Long> columnIds = new ArrayList<>(aspects.keySet());
         List<SegmentStoreTableLine> lines = new ArrayList<>();
         int startIndexRank = (int) (localQueryFilter.getIndex() / STEP);
-        int actualStartQueryIndex = (int) (queryFilter.getIndex() % STEP);
-        SegmentStoreIndex segIndex = fIndexes.get(startIndexRank);
+        int actualStartQueryIndex = (int) (localQueryFilter.getIndex() % STEP);
+        SegmentStoreIndex segIndex = indexesComparatorWrapper.getIndexes().get(startIndexRank);
         long start = segIndex.getStartTimestamp();
-        SegmentPredicate filter = new SegmentPredicate(segIndex);
+        SegmentPredicate filter = new SegmentPredicate(segIndex, indexesComparatorWrapper.getAspectName());
         int endIndexRank = (int) ((localQueryFilter.getIndex() + localQueryFilter.getCount() + STEP - 1) / STEP);
-        long end = getEndTimestamp(endIndexRank);
+        long end = getEndTimestamp(endIndexRank, indexesComparatorWrapper);
         /*
          * Search for the next or previous segment starting from the given
          * segment index
@@ -338,9 +432,9 @@
             Direction direction = directionValue.equals(Direction.PREVIOUS.name()) ? Direction.PREVIOUS : Direction.NEXT;
             @Nullable WrappedSegment segment = null;
             if (direction == Direction.NEXT) {
-                segment = getNextWrappedSegmentMatching(searchFilter, queryFilter.getIndex(), segmentStore);
+                segment = getNextWrappedSegmentMatching(searchFilter, queryFilter.getIndex(), segmentStore, indexesComparatorWrapper);
             } else {
-                segment = getPreviousWrappedSegmentMatching(searchFilter, queryFilter.getIndex(), segmentStore);
+                segment = getPreviousWrappedSegmentMatching(searchFilter, queryFilter.getIndex(), segmentStore, indexesComparatorWrapper);
             }
             if (segment != null) {
                 lines.add(buildSegmentStoreTableLine(aspects, segment.getOriginalSegment(), segment.getRank(), searchFilter));
@@ -348,16 +442,16 @@
                 long nextSegmentRank = segment.getRank() + 1;
                 startIndexRank = (int) (nextSegmentRank / STEP);
                 actualStartQueryIndex = (int) (nextSegmentRank % STEP);
-                segIndex = fIndexes.get(startIndexRank);
+                segIndex = indexesComparatorWrapper.getIndexes().get(startIndexRank);
                 start = segIndex.getStartTimestamp();
                 endIndexRank = (int) ((nextSegmentRank + localQueryFilter.getCount() + STEP - 1) / STEP);
-                end = getEndTimestamp(endIndexRank);
+                end = getEndTimestamp(endIndexRank, indexesComparatorWrapper);
             }
             if ((queryFilter.getCount() == 1) || (segment == null)) {
                 return new TmfModelResponse<>(new TmfVirtualTableModel<>(columnIds, lines, localQueryFilter.getIndex(), segmentStore.size()), ITmfResponse.Status.COMPLETED, CommonStatusMessage.COMPLETED);
             }
         }
-        List<ISegment> newSegStore = segmentStore.getIntersectingElements(start, end, fComparator, filter);
+        List<ISegment> newSegStore = segmentStore.getIntersectingElements(start, end, indexesComparatorWrapper.getComparator(), filter);
         for (int i = actualStartQueryIndex; i < newSegStore.size(); i++) {
             if (queryFilter.getCount() == lines.size()) {
                 break;
@@ -369,6 +463,11 @@
         return new TmfModelResponse<>(new TmfVirtualTableModel<>(columnIds, lines, localQueryFilter.getIndex(), segmentStore.size()), ITmfResponse.Status.COMPLETED, CommonStatusMessage.COMPLETED);
     }
 
+    private SegmentIndexesComparatorWrapper getIndexesComparatorOrDefault(Map<String, Object> fetchParameters) {
+        @Nullable Long key = extractColumnId(fetchParameters.get(TABLE_COMPARATOR_EXPRESSION_KEY));
+        return fAllIndexes.getOrDefault(key, fDefaultWrapper);
+    }
+
     /**
      * Retrieve from a segment store the next segment starting from a given
      * index, matching the given predicate.
@@ -383,15 +482,16 @@
      * @return A {@link WrappedSegment} that contains the matching next segment
      *         found after a given index.
      */
-    private @Nullable WrappedSegment getNextWrappedSegmentMatching(Predicate<ISegment> searchFilter, long startQueryIndex, ISegmentStore<ISegment> segmentStore) {
+    private static @Nullable WrappedSegment getNextWrappedSegmentMatching(Predicate<ISegment> searchFilter, long startQueryIndex, ISegmentStore<ISegment> segmentStore, SegmentIndexesComparatorWrapper indexesComparatorWrapper) {
         int startTimeIndexRank = (int) (startQueryIndex / STEP);
         int actualStartQueryIndex = (int) (startQueryIndex % STEP);
         int endTimeIndexRank = startTimeIndexRank + 1;
-        while (startTimeIndexRank < fIndexes.size()) {
-            SegmentStoreIndex segIndex = fIndexes.get(startTimeIndexRank);
-            SegmentPredicate filter = new SegmentPredicate(segIndex);
-            long end = getEndTimestamp(endTimeIndexRank);
-            List<ISegment> segments = segmentStore.getIntersectingElements(segIndex.getStartTimestamp(), end, fComparator, filter);
+        List<SegmentStoreIndex> indexes = indexesComparatorWrapper.getIndexes();
+        while (startTimeIndexRank < indexes.size()) {
+            SegmentStoreIndex segIndex = indexes.get(startTimeIndexRank);
+            SegmentPredicate filter = new SegmentPredicate(segIndex, indexesComparatorWrapper.getAspectName());
+            long end = getEndTimestamp(endTimeIndexRank, indexesComparatorWrapper);
+            List<ISegment> segments = segmentStore.getIntersectingElements(segIndex.getStartTimestamp(), end, indexesComparatorWrapper.getComparator(), filter);
             for (int i = actualStartQueryIndex; i < segments.size(); i++) {
                 ISegment segment = segments.get(i);
                 if (searchFilter.test(segment)) {
@@ -420,15 +520,16 @@
      * @return A {@link WrappedSegment} that contains the matching previous
      *         segment found before a given index.
      */
-    private @Nullable WrappedSegment getPreviousWrappedSegmentMatching(Predicate<ISegment> searchFilter, long endQueryIndex, ISegmentStore<ISegment> segmentStore) {
+
+    private static @Nullable WrappedSegment getPreviousWrappedSegmentMatching(Predicate<ISegment> searchFilter, long endQueryIndex, ISegmentStore<ISegment> segmentStore, SegmentIndexesComparatorWrapper indexesWrapper) {
         int actualEndQueryIndex = (int) (endQueryIndex % STEP);
         int startTimeIndexRank = (int) (endQueryIndex / STEP);
         int endTimeIndexRank = startTimeIndexRank + 1;
         while (endTimeIndexRank > 0) {
-            SegmentStoreIndex segIndex = fIndexes.get(startTimeIndexRank);
-            SegmentPredicate filter = new SegmentPredicate(segIndex);
-            long end = getEndTimestamp(endTimeIndexRank);
-            List<ISegment> segments = segmentStore.getIntersectingElements(segIndex.getStartTimestamp(), end, fComparator, filter);
+            SegmentStoreIndex segIndex = indexesWrapper.getIndexes().get(startTimeIndexRank);
+            SegmentPredicate filter = new SegmentPredicate(segIndex, indexesWrapper.getAspectName());
+            long end = getEndTimestamp(endTimeIndexRank, indexesWrapper);
+            List<ISegment> segments = segmentStore.getIntersectingElements(segIndex.getStartTimestamp(), end, indexesWrapper.getComparator(), filter);
             for (int i = Math.min(segments.size() - 1, actualEndQueryIndex); i >= 0; i--) {
                 if (searchFilter.test(segments.get(i))) {
                     long rank = i + ((long) startTimeIndexRank * STEP);
@@ -600,11 +701,16 @@
         return aspectParsed;
     }
 
-    private long getEndTimestamp(int index) {
-        if (index >= fIndexes.size()) {
+    private static long getEndTimestamp(int position, SegmentIndexesComparatorWrapper indexComparatorWrapper) {
+        List<SegmentStoreIndex> indexes = indexComparatorWrapper.getIndexes();
+        if (position >= indexes.size()) {
+            boolean isEndTimeComparatorUsed = indexComparatorWrapper.getAspectName().equals(SegmentEndTimeAspect.SEGMENT_END_TIME_ASPECT.getName());
+            if (isEndTimeComparatorUsed) {
+                return 0;
+            }
             return Long.MAX_VALUE;
         }
-        return fIndexes.get(index).getStartTimestamp();
+        return indexes.get(position).getStartTimestamp();
     }
 
 }
diff --git a/statesystem/org.eclipse.tracecompass.segmentstore.core/src/org/eclipse/tracecompass/segmentstore/core/ISegmentStore.java b/statesystem/org.eclipse.tracecompass.segmentstore.core/src/org/eclipse/tracecompass/segmentstore/core/ISegmentStore.java
index 4805ebe..6695375 100644
--- a/statesystem/org.eclipse.tracecompass.segmentstore.core/src/org/eclipse/tracecompass/segmentstore/core/ISegmentStore.java
+++ b/statesystem/org.eclipse.tracecompass.segmentstore.core/src/org/eclipse/tracecompass/segmentstore/core/ISegmentStore.java
@@ -150,7 +150,14 @@
      * @since 3.0
      */
     default List<E> getIntersectingElements(long start, long end, Comparator<ISegment> order, Predicate<ISegment> filter) {
-        Iterable<E> segments = getIntersectingElements(start, end, order);
+        long startTime = start;
+        long endTime = end;
+        if(start > end) {
+            long tmp = endTime;
+            endTime = startTime;
+            startTime = tmp;
+        }
+        Iterable<E> segments = getIntersectingElements(startTime, endTime, order);
         List ret;
         long i = 0;
         for (E segment : segments) {
@@ -161,7 +168,6 @@
         }
         if (segments instanceof ArrayList<?>) {
             ret = ((ArrayList) segments).subList((int) i, ((ArrayList) segments).size());
-            ret.stream().filter(filter);
         } else {
             List tmp = Lists.newArrayList(segments);
             ret = tmp.subList((int) i, tmp.size());