CTF: Enhance CTF validation for invalid CTF traces (Bug 464329)
[deliverable/tracecompass.git] / org.eclipse.tracecompass.ctf.core / src / org / eclipse / tracecompass / internal / ctf / core / trace / StreamInputPacketIndex.java
CommitLineData
866e5b51 1/*******************************************************************************
60ae41e1 2 * Copyright (c) 2011, 2014 Ericsson, Ecole Polytechnique de Montreal and others
866e5b51
FC
3 *
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
8 *
9 * Contributors: Matthew Khouzam - Initial API and implementation
10 * Contributors: Simon Marchi - Initial API and implementation
d68f46c2
EB
11 * Contributors: Etienne Bergeron <etienne.bergeron@gmail.com>
12 * Contributors: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
866e5b51
FC
13 *******************************************************************************/
14
f357bcd4 15package org.eclipse.tracecompass.internal.ctf.core.trace;
866e5b51 16
3f02ac64 17import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
c1d0f6ca 18
bf7f1af6 19import java.io.Serializable;
3f02ac64
MK
20import java.util.ArrayList;
21import java.util.Collection;
22import java.util.Collections;
c1d0f6ca 23import java.util.Comparator;
3f02ac64 24import java.util.List;
866e5b51 25import java.util.ListIterator;
bf7f1af6 26import java.util.TreeSet;
866e5b51 27
3f02ac64 28import org.eclipse.jdt.annotation.NonNull;
680f9173 29import org.eclipse.tracecompass.ctf.core.CTFException;
ce2388e0 30
866e5b51
FC
31/**
32 * <b><u>StreamInputPacketIndex</u></b>
33 * <p>
3f02ac64
MK
34 * This is a data structure containing entries, you may append to this and read
35 * it. It is not thread safe.
866e5b51
FC
36 */
37public class StreamInputPacketIndex {
38
39 // ------------------------------------------------------------------------
40 // Attributes
41 // ------------------------------------------------------------------------
42
43 /**
44 * Entries of the index. They are sorted by increasing begin timestamp.
45 * index builder.
46 */
3f02ac64 47 private final List<StreamInputPacketIndexEntry> fEntries = new ArrayList<>();
866e5b51
FC
48
49 // ------------------------------------------------------------------------
3f02ac64 50 // Operations
866e5b51
FC
51 // ------------------------------------------------------------------------
52
9ac2eb62 53 /**
3f02ac64
MK
54 * Returns the number of elements in this data structure. If this data
55 * structure contains more than {@code Integer.MAX_VALUE} elements, returns
56 * {@code Integer.MAX_VALUE}.
b73145e2 57 *
3f02ac64 58 * @return the number of elements in this data structure
9ac2eb62 59 */
3f02ac64
MK
60 public int size() {
61 return fEntries.size();
866e5b51
FC
62 }
63
9ac2eb62 64 /**
3f02ac64 65 * Returns {@code true} if this data structure contains no elements.
b73145e2 66 *
3f02ac64 67 * @return {@code true} if this data structure contains no elements
9ac2eb62 68 */
3f02ac64
MK
69 public boolean isEmpty() {
70 return fEntries.isEmpty();
866e5b51
FC
71 }
72
9ac2eb62 73 /**
3f02ac64
MK
74 * Adds a collection of entries to the index, the entries must be sorted.
75 *
76 * @param preParsedIndex
77 * the pre-parsed index file
b73145e2 78 *
680f9173 79 * @throws CTFException
3f02ac64 80 * If there was a problem reading the entry
9ac2eb62 81 */
3f02ac64 82 public void appendAll(Collection<StreamInputPacketIndexEntry> preParsedIndex)
680f9173 83 throws CTFException {
3f02ac64
MK
84 for (StreamInputPacketIndexEntry sipie : preParsedIndex) {
85 append(checkNotNull(sipie));
86 }
866e5b51
FC
87 }
88
866e5b51 89 /**
3f02ac64 90 * Appends the specified element to the end of this data structure
866e5b51
FC
91 *
92 * @param entry
3f02ac64
MK
93 * element to be appended to this index, cannot be null
94 * @return {@code true} (as specified by {@link Collection#add})
680f9173 95 * @throws CTFException
be6df2d8 96 * If there was a problem reading the entry
866e5b51 97 */
3f02ac64 98 public boolean append(@NonNull StreamInputPacketIndexEntry entry)
680f9173 99 throws CTFException {
866e5b51 100
ecb12461 101 /* Validate consistent entry. */
ce2388e0 102 if (entry.getTimestampBegin() > entry.getTimestampEnd()) {
680f9173 103 throw new CTFException("Packet begin timestamp is after end timestamp"); //$NON-NLS-1$
866e5b51
FC
104 }
105
3f02ac64
MK
106 /*
107 * Validate entries are inserted in monotonic increasing timestamp
108 * order.
109 */
110 if (!fEntries.isEmpty() && (entry.getTimestampBegin() < lastElement().getTimestampBegin())) {
680f9173 111 throw new CTFException("Packets begin timestamp decreasing"); //$NON-NLS-1$
866e5b51 112 }
3f02ac64
MK
113
114 fEntries.add(entry);
115 return true;
866e5b51
FC
116 }
117
118 /**
3f02ac64
MK
119 * Returns the first PacketIndexEntry that could include the timestamp, that
120 * is the last packet with a begin timestamp smaller than the given
121 * timestamp.
866e5b51
FC
122 *
123 * @param timestamp
124 * The timestamp to look for.
125 * @return The StreamInputPacketEntry that corresponds to the packet that
126 * includes the given timestamp.
127 */
128 public ListIterator<StreamInputPacketIndexEntry> search(final long timestamp) {
129 /*
130 * Start with min and max covering all the elements.
131 */
3f02ac64 132 int max = fEntries.size() - 1;
866e5b51
FC
133 int min = 0;
134
135 int guessI;
136 StreamInputPacketIndexEntry guessEntry = null;
137
4a110860
AM
138 /*
139 * If the index is empty, return the iterator at the very beginning.
140 */
3f02ac64
MK
141 if (isEmpty()) {
142 return fEntries.listIterator();
4a110860
AM
143 }
144
866e5b51
FC
145 if (timestamp < 0) {
146 throw new IllegalArgumentException("timestamp is negative"); //$NON-NLS-1$
147 }
148
d68f46c2 149 /* Binary search */
866e5b51
FC
150 for (;;) {
151 /*
d68f46c2 152 * Guess in the middle of min and max.
866e5b51 153 */
d68f46c2 154 guessI = min + ((max - min) / 2);
3f02ac64 155 guessEntry = fEntries.get(guessI);
866e5b51
FC
156
157 /*
158 * If we reached the point where we focus on a single packet, our
159 * search is done.
160 */
161 if (min == max) {
162 break;
163 }
164
d68f46c2 165 if (timestamp <= guessEntry.getTimestampEnd()) {
866e5b51 166 /*
3f02ac64
MK
167 * If the timestamp is lower or equal to the end of the guess
168 * packet, then the guess packet becomes the new inclusive max.
866e5b51 169 */
d68f46c2
EB
170 max = guessI;
171 } else {
866e5b51 172 /*
3f02ac64
MK
173 * If the timestamp is greater than the end of the guess packet,
174 * then the new inclusive min is the packet after the guess
175 * packet.
866e5b51 176 */
d68f46c2 177 min = guessI + 1;
866e5b51
FC
178 }
179 }
180
3f02ac64 181 return fEntries.listIterator(guessI);
ce2388e0 182 }
3f02ac64
MK
183
184 /**
185 * Get the last element of the index
186 *
187 * @return the last element in the index
188 */
189 public StreamInputPacketIndexEntry lastElement() {
190 return fEntries.get(fEntries.size() - 1);
191 }
192
193 /**
194 * Returns the element at the specified position in this data structure.
195 *
196 * @param index
197 * index of the element to return
198 * @return the element at the specified position in this data structure
199 * @throws IndexOutOfBoundsException
200 * if the index is out of range (
201 * {@code index < 0 || index >= size()})
202 */
203 public StreamInputPacketIndexEntry getElement(int index) {
204 return fEntries.get(index);
205 }
206
207 /**
208 * Returns the index of the first occurrence of the specified element in
209 * this data structure, or -1 if this data structure does not contain the
210 * element. More formally, returns the lowest index {@code i} such that, for
211 * an entry {@code o}, {@code (o==null ? get(i)==null : o.equals(get(i)))},
212 * or {@code -1} if there is no such index. This will work in log(n) time
213 * since the data structure contains elements in a non-repeating increasing
214 * manner.
215 *
216 * @param element
217 * element to search for
218 * @return the index of the first occurrence of the specified element in
219 * this data structure, or -1 if this data structure does not
220 * contain the element
221 * @throws ClassCastException
222 * if the type of the specified element is incompatible with
223 * this data structure (<a
224 * href="Collection.html#optional-restrictions">optional</a>)
225 * @throws NullPointerException
226 * if the specified element is null and this data structure does
227 * not permit null elements (<a
228 * href="Collection.html#optional-restrictions">optional</a>)
229 */
230 public int indexOf(StreamInputPacketIndexEntry element) {
231 int indexOf = -1;
232 if (element != null) {
c1d0f6ca 233 indexOf = Collections.binarySearch(fEntries, element, new MonotonicComparator());
3f02ac64
MK
234 }
235 return (indexOf < 0) ? -1 : indexOf;
236 }
237
c1d0f6ca 238 /**
bf7f1af6
MK
239 * Ordering comparator for entering entries into a data structure sorted by
240 * timestamp.
c1d0f6ca 241 */
bf7f1af6
MK
242 private static class MonotonicComparator implements Comparator<StreamInputPacketIndexEntry>, Serializable {
243 /**
244 * For {@link Serializable}, that way if we migrate to a {@link TreeSet}
245 * the comparator is serializable too.
246 */
247 private static final long serialVersionUID = -5693064068367242076L;
c1d0f6ca
MK
248
249 @Override
250 public int compare(StreamInputPacketIndexEntry left, StreamInputPacketIndexEntry right) {
251 if (left.getTimestampBegin() > right.getTimestampBegin()) {
252 return 1;
253 }
254 if (left.getTimestampBegin() < right.getTimestampBegin()) {
255 return -1;
256 }
257 if (left.getTimestampEnd() > right.getTimestampEnd()) {
258 return 1;
259 }
260 if (left.getTimestampEnd() < right.getTimestampEnd()) {
261 return -1;
262 }
263 return 0;
264 }
265 }
266
866e5b51 267}
This page took 0.068501 seconds and 5 git commands to generate.