1 /*******************************************************************************
2 * Copyright (c) 2011, 2014 Ericsson, Ecole Polytechnique de Montreal and others
4 * All rights reserved. This program and the accompanying materials are made
5 * available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
9 * Contributors: Matthew Khouzam - Initial API and implementation
10 * Contributors: Simon Marchi - Initial API and implementation
11 * Contributors: Etienne Bergeron <etienne.bergeron@gmail.com>
12 * Contributors: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
13 *******************************************************************************/
15 package org
.eclipse
.tracecompass
.internal
.ctf
.core
.trace
;
17 import static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
19 import java
.io
.Serializable
;
20 import java
.util
.ArrayList
;
21 import java
.util
.Collection
;
22 import java
.util
.Collections
;
23 import java
.util
.Comparator
;
24 import java
.util
.List
;
25 import java
.util
.TreeSet
;
27 import org
.eclipse
.core
.runtime
.IStatus
;
28 import org
.eclipse
.jdt
.annotation
.NonNull
;
29 import org
.eclipse
.tracecompass
.ctf
.core
.trace
.ICTFPacketDescriptor
;
30 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.Activator
;
33 * <b><u>StreamInputPacketIndex</u></b>
35 * This is a data structure containing entries, you may append to this and read
36 * it. It is not thread safe.
38 public class StreamInputPacketIndex
{
40 // ------------------------------------------------------------------------
42 // ------------------------------------------------------------------------
45 * Entries of the index. They are sorted by increasing begin timestamp.
48 private final List
<ICTFPacketDescriptor
> fEntries
= new ArrayList
<>();
50 // ------------------------------------------------------------------------
52 // ------------------------------------------------------------------------
55 * Returns the number of elements in this data structure. If this data
56 * structure contains more than {@code Integer.MAX_VALUE} elements, returns
57 * {@code Integer.MAX_VALUE}.
59 * @return the number of elements in this data structure
62 return fEntries
.size();
66 * Returns {@code true} if this data structure contains no elements.
68 * @return {@code true} if this data structure contains no elements
70 public boolean isEmpty() {
71 return fEntries
.isEmpty();
75 * Adds a collection of entries to the index, the entries must be sorted.
77 * @param preParsedIndex
78 * the pre-parsed index file
80 public void appendAll(Collection
<ICTFPacketDescriptor
> preParsedIndex
) {
81 for (ICTFPacketDescriptor sipie
: preParsedIndex
) {
82 append(checkNotNull(sipie
));
87 * Appends the specified element to the end of this data structure
90 * element to be appended to this index, cannot be null
91 * @return {@code true} (as specified by {@link Collection#add})
93 public synchronized boolean append(@NonNull ICTFPacketDescriptor entry
) {
94 ICTFPacketDescriptor entryToAdd
= entry
;
95 /* Validate consistent entry. */
96 if (entryToAdd
.getTimestampBegin() > entryToAdd
.getTimestampEnd()) {
97 Activator
.log(IStatus
.WARNING
, "Packet at offset " + entryToAdd
.getOffsetBytes() + //$NON-NLS-1$
98 " begin timestamp is after end timestamp"); //$NON-NLS-1$
99 entryToAdd
= new StreamInputPacketIndexEntry(entryToAdd
, Long
.MAX_VALUE
);
103 * Validate entries are inserted in monotonic increasing timestamp
106 if (!fEntries
.isEmpty() && (entryToAdd
.getTimestampBegin() < lastElement().getTimestampBegin())) {
110 fEntries
.add(entryToAdd
);
115 * Returns the first packet that could include the timestamp, that is the
116 * last packet with a begin timestamp smaller than the given timestamp.
119 * The timestamp to look for.
120 * @return The index of the desired packet
122 public int search(final long timestamp
) {
124 * Search using binary search.
126 * As the entries in fEntries are IndexEntries, the key to search for
127 * needs to be one too. We are looking for a timestamp though, so we use
128 * the dataOffset which is a long and use it as a timestamp holder.
130 int index
= Collections
.binarySearch(fEntries
, new StreamInputPacketIndexEntry(timestamp
, 0), new FindTimestamp());
138 * Get the last element of the index
140 * @return the last element in the index
142 public ICTFPacketDescriptor
lastElement() {
143 return fEntries
.get(fEntries
.size() - 1);
147 * Returns the element at the specified position in this data structure.
150 * index of the element to return
151 * @return the element at the specified position in this data structure
152 * @throws IndexOutOfBoundsException
153 * if the index is out of range (
154 * {@code index < 0 || index >= size()})
156 public ICTFPacketDescriptor
getElement(int index
) {
157 return fEntries
.get(index
);
161 * Returns the index of the first occurrence of the specified element in
162 * this data structure, or -1 if this data structure does not contain the
163 * element. More formally, returns the lowest index {@code i} such that, for
164 * an entry {@code o}, {@code (o==null ? get(i)==null : o.equals(get(i)))},
165 * or {@code -1} if there is no such index. This will work in log(n) time
166 * since the data structure contains elements in a non-repeating increasing
170 * element to search for
171 * @return the index of the first occurrence of the specified element in
172 * this data structure, or -1 if this data structure does not
173 * contain the element
174 * @throws ClassCastException
175 * if the type of the specified element is incompatible with
176 * this data structure (
177 * <a href="Collection.html#optional-restrictions">optional</a>)
178 * @throws NullPointerException
179 * if the specified element is null and this data structure does
180 * not permit null elements (
181 * <a href="Collection.html#optional-restrictions">optional</a>)
183 public int indexOf(ICTFPacketDescriptor element
) {
185 if (element
!= null) {
186 indexOf
= Collections
.binarySearch(fEntries
, element
, new MonotonicComparator());
188 return (indexOf
< 0) ?
-1 : indexOf
;
192 * Ordering comparator for entering entries into a data structure sorted by
195 private static class MonotonicComparator
implements Comparator
<ICTFPacketDescriptor
>, Serializable
{
197 * For {@link Serializable}, that way if we migrate to a {@link TreeSet}
198 * the comparator is serializable too.
200 private static final long serialVersionUID
= -5693064068367242076L;
203 public int compare(ICTFPacketDescriptor left
, ICTFPacketDescriptor right
) {
204 if (left
.getTimestampBegin() > right
.getTimestampBegin()) {
207 if (left
.getTimestampBegin() < right
.getTimestampBegin()) {
210 if (left
.getTimestampEnd() > right
.getTimestampEnd()) {
213 if (left
.getTimestampEnd() < right
.getTimestampEnd()) {
221 * Used for search, assumes that the second argument in the comparison is
224 private static class FindTimestamp
implements Comparator
<ICTFPacketDescriptor
>, Serializable
{
229 private static final long serialVersionUID
= 7235997205945550341L;
232 public int compare(ICTFPacketDescriptor value
, ICTFPacketDescriptor key
) {
234 * It is assumed that the second packet descriptor is the key, a
235 * wrapped timestamp in a PacketDescriptor. So we need to extract
236 * the timestamp. Then we have 3 choices, the if the timestamp is in
237 * the interval, we return 0 or found. If the timestamp is before or
238 * after, we just need to compare it to a value in the segment (like
239 * start) to know if it is greater or lesser to the current packet.
241 long ts
= key
.getOffsetBits();
242 if (value
.includes(ts
)) {
245 return Long
.compare(value
.getTimestampBegin(), ts
);