ctf: Move plugins to their own sub-directory
[deliverable/tracecompass.git] / ctf / org.eclipse.tracecompass.ctf.core / src / org / eclipse / tracecompass / ctf / core / trace / CTFStreamInput.java
1 /*******************************************************************************
2 * Copyright (c) 2011, 2014 Ericsson, Ecole Polytechnique de Montreal and others
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
11 *******************************************************************************/
12
13 package org.eclipse.tracecompass.ctf.core.trace;
14
15 import java.io.File;
16 import java.io.IOException;
17 import java.nio.ByteBuffer;
18 import java.nio.channels.FileChannel;
19 import java.nio.channels.FileChannel.MapMode;
20 import java.nio.file.StandardOpenOption;
21 import java.util.UUID;
22
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.eclipse.tracecompass.ctf.core.CTFException;
26 import org.eclipse.tracecompass.ctf.core.event.io.BitBuffer;
27 import org.eclipse.tracecompass.ctf.core.event.scope.IDefinitionScope;
28 import org.eclipse.tracecompass.ctf.core.event.scope.ILexicalScope;
29 import org.eclipse.tracecompass.ctf.core.event.scope.LexicalScope;
30 import org.eclipse.tracecompass.ctf.core.event.types.AbstractArrayDefinition;
31 import org.eclipse.tracecompass.ctf.core.event.types.Definition;
32 import org.eclipse.tracecompass.ctf.core.event.types.IntegerDefinition;
33 import org.eclipse.tracecompass.ctf.core.event.types.StructDeclaration;
34 import org.eclipse.tracecompass.ctf.core.event.types.StructDefinition;
35 import org.eclipse.tracecompass.internal.ctf.core.SafeMappedByteBuffer;
36 import org.eclipse.tracecompass.internal.ctf.core.trace.StreamInputPacketIndex;
37 import org.eclipse.tracecompass.internal.ctf.core.trace.StreamInputPacketIndexEntry;
38 import org.eclipse.tracecompass.internal.ctf.core.trace.Utils;
39
40 /**
41 * <b><u>StreamInput</u></b>
42 * <p>
43 * Represents a trace file that belongs to a certain stream.
44 */
45 @NonNullByDefault
46 public class CTFStreamInput implements IDefinitionScope {
47
48 // ------------------------------------------------------------------------
49 // Attributes
50 // ------------------------------------------------------------------------
51
52 private static final int MAP_SIZE = 4096;
53
54 /**
55 * The associated Stream
56 */
57 private final CTFStream fStream;
58
59 /**
60 * Information on the file (used for debugging)
61 */
62 private final File fFile;
63
64 /**
65 * The packet index of this input
66 */
67 private final StreamInputPacketIndex fIndex;
68
69 private long fTimestampEnd;
70
71 /**
72 * Definition of trace packet header
73 */
74 private final StructDeclaration fTracePacketHeaderDecl;
75
76 /**
77 * Definition of trace stream packet context
78 */
79 private final StructDeclaration fStreamPacketContextDecl;
80
81 /**
82 * Total number of lost events in this stream
83 */
84 private long fLostSoFar = 0;
85
86 // ------------------------------------------------------------------------
87 // Constructors
88 // ------------------------------------------------------------------------
89
90 /**
91 * Constructs a StreamInput.
92 *
93 * @param stream
94 * The stream to which this StreamInput belongs to.
95 * @param file
96 * Information about the trace file (for debugging purposes).
97 */
98 public CTFStreamInput(CTFStream stream, File file) {
99 fStream = stream;
100 fFile = file;
101 fIndex = new StreamInputPacketIndex();
102 /*
103 * Create the definitions we need to read the packet headers + contexts
104 */
105 StructDeclaration packetHeader = getStream().getTrace().getPacketHeader();
106 if (packetHeader != null) {
107 fTracePacketHeaderDecl = packetHeader;
108 } else {
109 fTracePacketHeaderDecl = new StructDeclaration(1);
110 }
111 StructDeclaration packetContextDecl = getStream().getPacketContextDecl();
112 if (packetContextDecl != null) {
113 fStreamPacketContextDecl = packetContextDecl;
114 } else {
115 fStreamPacketContextDecl = new StructDeclaration(1);
116 }
117 }
118
119 // ------------------------------------------------------------------------
120 // Getters/Setters/Predicates
121 // ------------------------------------------------------------------------
122
123 /**
124 * Gets the stream the streamInput wrapper is wrapping
125 *
126 * @return the stream the streamInput wrapper is wrapping
127 */
128 public CTFStream getStream() {
129 return fStream;
130 }
131
132 /**
133 * The common streamInput Index
134 *
135 * @return the stream input Index
136 */
137 StreamInputPacketIndex getIndex() {
138 return fIndex;
139 }
140
141 /**
142 * Gets the filename of the streamInput file.
143 *
144 * @return the filename of the streaminput file.
145 */
146 public String getFilename() {
147 String name = fFile.getName();
148 if (name == null) {
149 throw new IllegalStateException("File cannot have a null name"); //$NON-NLS-1$
150 }
151 return name;
152 }
153
154 /**
155 * Gets the last read timestamp of a stream. (this is not necessarily the
156 * last time in the stream.)
157 *
158 * @return the last read timestamp
159 */
160 public long getTimestampEnd() {
161 return fTimestampEnd;
162 }
163
164 /**
165 * Sets the last read timestamp of a stream. (this is not necessarily the
166 * last time in the stream.)
167 *
168 * @param timestampEnd
169 * the last read timestamp
170 */
171 public void setTimestampEnd(long timestampEnd) {
172 fTimestampEnd = timestampEnd;
173 }
174
175 /**
176 * Useless for streaminputs
177 */
178 @Override
179 public LexicalScope getScopePath() {
180 return ILexicalScope.STREAM;
181 }
182
183 // ------------------------------------------------------------------------
184 // Operations
185 // ------------------------------------------------------------------------
186
187 @Override
188 public @Nullable Definition lookupDefinition(@Nullable String lookupPath) {
189 /* TODO: lookup in different dynamic scopes is not supported yet. */
190 return null;
191 }
192
193 /**
194 * Create the index for this trace file.
195 */
196 public void setupIndex() {
197
198 /*
199 * The BitBuffer to extract data from the StreamInput
200 */
201 BitBuffer bitBuffer = new BitBuffer();
202 bitBuffer.setByteOrder(getStream().getTrace().getByteOrder());
203
204 }
205
206 /**
207 * Adds the next packet header index entry to the index of a stream input.
208 *
209 * <strong>This method is slow and can corrupt data if not used
210 * properly</strong>
211 *
212 * @return true if there are more packets to add
213 * @throws CTFException
214 * If there was a problem reading the packed header
215 */
216 public boolean addPacketHeaderIndex() throws CTFException {
217 long currentPosBits = 0L;
218 if (!fIndex.isEmpty()) {
219 ICTFPacketDescriptor pos = fIndex.lastElement();
220 if (pos == null) {
221 throw new IllegalStateException("Index contains null packet entries"); //$NON-NLS-1$
222 }
223 currentPosBits = pos.getOffsetBits() + pos.getPacketSizeBits();
224 }
225 if (currentPosBits < getStreamSizeBits()) {
226 fIndex.append(createPacketIndexEntry(currentPosBits));
227 return true;
228 }
229 return false;
230 }
231
232 private long getStreamSizeBits() {
233 return fFile.length() * Byte.SIZE;
234 }
235
236 private ICTFPacketDescriptor createPacketIndexEntry(long dataOffsetbits)
237 throws CTFException {
238
239 try (FileChannel fc = FileChannel.open(fFile.toPath(), StandardOpenOption.READ)) {
240 if (fc == null) {
241 throw new IOException("Failed to create FileChannel"); //$NON-NLS-1$
242 }
243 BitBuffer bitBuffer = createBitBufferForPacketHeader(fc, dataOffsetbits);
244 /*
245 * Read the trace packet header if it exists.
246 */
247 parseTracePacketHeader(bitBuffer);
248
249 /*
250 * Read the stream packet context if it exists.
251 */
252 long size = fc.size();
253 ICTFPacketDescriptor packetIndex = parsePacketContext(dataOffsetbits, size, bitBuffer);
254
255 /* Basic validation */
256 if (packetIndex.getContentSizeBits() > packetIndex.getPacketSizeBits()) {
257 throw new CTFException("Content size > packet size"); //$NON-NLS-1$
258 }
259
260 if (packetIndex.getPacketSizeBits() > ((size * Byte.SIZE - packetIndex.getOffsetBits()))) {
261 throw new CTFException("Not enough data remaining in the file for the size of this packet"); //$NON-NLS-1$
262 }
263 return packetIndex;
264 } catch (IOException e) {
265 throw new CTFException("Failed to create packet index entry", e); //$NON-NLS-1$
266 }
267 }
268
269 private BitBuffer createBitBufferForPacketHeader(FileChannel fc, long dataOffsetbits) throws CTFException, IOException {
270 /*
271 * create a packet bit buffer to read the packet header
272 */
273 int maximumSize = fStreamPacketContextDecl.getMaximumSize() + fTracePacketHeaderDecl.getMaximumSize();
274 BitBuffer bitBuffer = new BitBuffer(createPacketBitBuffer(fc, dataOffsetbits/Byte.SIZE, maximumSize));
275 bitBuffer.setByteOrder(getStream().getTrace().getByteOrder());
276 return bitBuffer;
277 }
278
279 private static ByteBuffer getByteBufferAt(FileChannel fc, long position, long size) throws CTFException, IOException {
280 ByteBuffer map = SafeMappedByteBuffer.map(fc, MapMode.READ_ONLY, position, size);
281 if (map == null) {
282 throw new CTFException("Failed to allocate mapped byte buffer"); //$NON-NLS-1$
283 }
284 return map;
285 }
286
287 private static ByteBuffer createPacketBitBuffer(FileChannel fc,
288 long packetOffsetBytes, long maxSize) throws CTFException, IOException {
289 /*
290 * If there is less data remaining than what we want to map, reduce the
291 * map size.
292 */
293 long remain = fc.size() - packetOffsetBytes;
294 /*
295 * Initial size, it is the minimum of the the file size and the maximum
296 * possible size of the
297 */
298 long mapSize = Math.min(remain, MAP_SIZE);
299 if (maxSize < mapSize) {
300 mapSize = maxSize;
301 }
302
303 /*
304 * Map the packet.
305 */
306 try {
307 return getByteBufferAt(fc, packetOffsetBytes, mapSize);
308 } catch (IllegalArgumentException | IOException e) {
309 throw new CTFException(e);
310 }
311 }
312
313 private StructDefinition parseTracePacketHeader(
314 BitBuffer bitBuffer) throws CTFException {
315
316 StructDefinition tracePacketHeaderDef = fTracePacketHeaderDecl.createDefinition(fStream.getTrace(), ILexicalScope.TRACE_PACKET_HEADER, bitBuffer);
317
318 /*
319 * Check the CTF magic number
320 */
321 IntegerDefinition magicDef = (IntegerDefinition) tracePacketHeaderDef
322 .lookupDefinition("magic"); //$NON-NLS-1$
323 if (magicDef != null) {
324 int magic = (int) magicDef.getValue();
325 if (magic != Utils.CTF_MAGIC) {
326 throw new CTFException(
327 "CTF magic mismatch " + Integer.toHexString(magic) + " vs " + Integer.toHexString(Utils.CTF_MAGIC)); //$NON-NLS-1$//$NON-NLS-2$
328 }
329 }
330
331 /*
332 * Check the trace UUID
333 */
334 AbstractArrayDefinition uuidDef =
335 (AbstractArrayDefinition) tracePacketHeaderDef.lookupDefinition("uuid"); //$NON-NLS-1$
336 if (uuidDef != null) {
337 UUID uuid = Utils.getUUIDfromDefinition(uuidDef);
338
339 if (!getStream().getTrace().getUUID().equals(uuid)) {
340 throw new CTFException("UUID mismatch"); //$NON-NLS-1$
341 }
342 }
343
344 /*
345 * Check that the stream id did not change
346 */
347 IntegerDefinition streamIDDef = (IntegerDefinition) tracePacketHeaderDef
348 .lookupDefinition("stream_id"); //$NON-NLS-1$
349 if (streamIDDef != null) {
350 long streamID = streamIDDef.getValue();
351
352 if (streamID != getStream().getId()) {
353 throw new CTFException("Stream ID changing within a StreamInput"); //$NON-NLS-1$
354 }
355 }
356 return tracePacketHeaderDef;
357 }
358
359 private ICTFPacketDescriptor parsePacketContext(long dataOffsetBits, long fileSizeBytes,
360 BitBuffer bitBuffer) throws CTFException {
361 ICTFPacketDescriptor packetIndex;
362 StructDefinition streamPacketContextDef = fStreamPacketContextDecl.createDefinition(this, ILexicalScope.STREAM_PACKET_CONTEXT, bitBuffer);
363 packetIndex = new StreamInputPacketIndexEntry(dataOffsetBits, streamPacketContextDef, fileSizeBytes, fLostSoFar);
364 fLostSoFar = packetIndex.getLostEvents() + fLostSoFar;
365 setTimestampEnd(packetIndex.getTimestampEnd());
366 return packetIndex;
367 }
368
369 /**
370 * Get the file
371 *
372 * @return the file
373 * @since 1.0
374 */
375 public File getFile() {
376 return fFile;
377 }
378
379 @Override
380 public int hashCode() {
381 final int prime = 31;
382 int result = 1;
383 result = (prime * result) + fFile.hashCode();
384 return result;
385 }
386
387 @Override
388 public boolean equals(@Nullable Object obj) {
389 if (this == obj) {
390 return true;
391 }
392 if (obj == null) {
393 return false;
394 }
395 if (!(obj instanceof CTFStreamInput)) {
396 return false;
397 }
398 CTFStreamInput other = (CTFStreamInput) obj;
399 if (!fFile.equals(other.fFile)) {
400 return false;
401 }
402 return true;
403 }
404 }
This page took 0.040813 seconds and 5 git commands to generate.