tmf: Bug 416660: -1 long state value is not long
[deliverable/tracecompass.git] / org.eclipse.linuxtools.ctf.core / src / org / eclipse / linuxtools / ctf / core / trace / StreamInput.java
CommitLineData
866e5b51 1/*******************************************************************************
11252342 2 * Copyright (c) 2011, 2013 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
11 *******************************************************************************/
12
486efb2e 13package org.eclipse.linuxtools.ctf.core.trace;
866e5b51
FC
14
15import java.io.File;
aa3b05ef
FC
16import java.io.IOException;
17import java.nio.MappedByteBuffer;
866e5b51 18import java.nio.channels.FileChannel;
aa3b05ef 19import java.nio.channels.FileChannel.MapMode;
866e5b51
FC
20import java.util.UUID;
21
486efb2e 22import org.eclipse.linuxtools.ctf.core.event.io.BitBuffer;
866e5b51
FC
23import org.eclipse.linuxtools.ctf.core.event.types.ArrayDefinition;
24import org.eclipse.linuxtools.ctf.core.event.types.Definition;
21fb02fa
MK
25import org.eclipse.linuxtools.ctf.core.event.types.EnumDefinition;
26import org.eclipse.linuxtools.ctf.core.event.types.FloatDefinition;
866e5b51
FC
27import org.eclipse.linuxtools.ctf.core.event.types.IDefinitionScope;
28import org.eclipse.linuxtools.ctf.core.event.types.IntegerDefinition;
21fb02fa 29import org.eclipse.linuxtools.ctf.core.event.types.StringDefinition;
866e5b51 30import org.eclipse.linuxtools.ctf.core.event.types.StructDefinition;
486efb2e
AM
31import org.eclipse.linuxtools.internal.ctf.core.trace.StreamInputPacketIndex;
32import org.eclipse.linuxtools.internal.ctf.core.trace.StreamInputPacketIndexEntry;
866e5b51
FC
33
34/**
35 * <b><u>StreamInput</u></b>
36 * <p>
37 * Represents a trace file that belongs to a certain stream.
486efb2e 38 * @since 2.0
866e5b51
FC
39 */
40public class StreamInput implements IDefinitionScope {
41
42 // ------------------------------------------------------------------------
43 // Attributes
44 // ------------------------------------------------------------------------
45
46 /**
47 * The associated Stream
48 */
49 private final Stream stream;
50
51 /**
52 * FileChannel to the trace file
53 */
54 private final FileChannel fileChannel;
55
56 /**
57 * Information on the file (used for debugging)
58 */
0594c61c 59 private final File file;
866e5b51
FC
60
61 /**
62 * The packet index of this input
63 */
bfe038ff 64 private final StreamInputPacketIndex index;
866e5b51
FC
65
66 private long timestampEnd;
67
bfe038ff
MK
68 /*
69 * Definition of trace packet header
70 */
0594c61c 71 private StructDefinition tracePacketHeaderDef = null;
bfe038ff
MK
72
73 /*
74 * Definition of trace stream packet context
75 */
0594c61c 76 private StructDefinition streamPacketContextDef = null;
bfe038ff 77
132a02b0
MK
78 /*
79 * Total number of lost events in this stream
80 */
0594c61c 81 private long lostSoFar = 0;
132a02b0 82
866e5b51
FC
83 // ------------------------------------------------------------------------
84 // Constructors
85 // ------------------------------------------------------------------------
86
87 /**
88 * Constructs a StreamInput.
89 *
90 * @param stream
91 * The stream to which this StreamInput belongs to.
92 * @param fileChannel
93 * The FileChannel to the trace file.
94 * @param file
95 * Information about the trace file (for debugging purposes).
96 */
97 public StreamInput(Stream stream, FileChannel fileChannel, File file) {
98 this.stream = stream;
99 this.fileChannel = fileChannel;
100 this.file = file;
1fbaecd1 101 this.index = stream.getTrace().getIndex(this);
866e5b51
FC
102 }
103
104 // ------------------------------------------------------------------------
105 // Getters/Setters/Predicates
106 // ------------------------------------------------------------------------
107
9ac2eb62
MK
108 /**
109 * Gets the stream the streamInput wrapper is wrapping
21fb02fa 110 *
9ac2eb62
MK
111 * @return the stream the streamInput wrapper is wrapping
112 */
866e5b51
FC
113 public Stream getStream() {
114 return stream;
115 }
116
9ac2eb62 117 /**
ecb12461 118 * The common streamInput Index
21fb02fa 119 *
9ac2eb62
MK
120 * @return the stream input Index
121 */
486efb2e 122 StreamInputPacketIndex getIndex() {
866e5b51
FC
123 return index;
124 }
125
9ac2eb62 126 /**
21fb02fa 127 * Gets the filechannel of the streamInput. This is a limited Java
ecb12461 128 * resource.
21fb02fa 129 *
9ac2eb62
MK
130 * @return the filechannel
131 */
866e5b51
FC
132 public FileChannel getFileChannel() {
133 return fileChannel;
134 }
135
9ac2eb62
MK
136 /**
137 * Gets the filename of the streamInput file.
21fb02fa 138 *
9ac2eb62
MK
139 * @return the filename of the streaminput file.
140 */
866e5b51
FC
141 public String getFilename() {
142 return file.getName();
143 }
144
9ac2eb62 145 /**
ecb12461 146 * Gets the last read timestamp of a stream. (this is not necessarily the
21fb02fa
MK
147 * last time in the stream.)
148 *
9ac2eb62
MK
149 * @return the last read timestamp
150 */
866e5b51
FC
151 public long getTimestampEnd() {
152 return timestampEnd;
153 }
154
9ac2eb62 155 /**
21fb02fa
MK
156 * Sets the last read timestamp of a stream. (this is not necessarily the
157 * last time in the stream.)
158 *
159 * @param timestampEnd
160 * the last read timestamp
9ac2eb62 161 */
866e5b51
FC
162 public void setTimestampEnd(long timestampEnd) {
163 this.timestampEnd = timestampEnd;
164 }
165
9ac2eb62 166 /**
ecb12461 167 * Useless for streaminputs
9ac2eb62 168 */
866e5b51
FC
169 @Override
170 public String getPath() {
171 return ""; //$NON-NLS-1$
172 }
173
174 // ------------------------------------------------------------------------
175 // Operations
176 // ------------------------------------------------------------------------
177
178 @Override
179 public Definition lookupDefinition(String lookupPath) {
180 /* TODO: lookup in different dynamic scopes is not supported yet. */
181 return null;
182 }
183
184 /**
185 * Create the index for this trace file.
bfe038ff
MK
186 */
187 public void setupIndex() {
188
bfe038ff
MK
189 /*
190 * The BitBuffer to extract data from the StreamInput
191 */
192 BitBuffer bitBuffer = new BitBuffer();
8b8e48ed 193 bitBuffer.setByteOrder(this.getStream().getTrace().getByteOrder());
bfe038ff
MK
194
195 /*
196 * Create the definitions we need to read the packet headers + contexts
197 */
198 if (getStream().getTrace().getPacketHeader() != null) {
199 tracePacketHeaderDef = getStream().getTrace().getPacketHeader()
200 .createDefinition(this, "trace.packet.header"); //$NON-NLS-1$
201 }
202
203 if (getStream().getPacketContextDecl() != null) {
204 streamPacketContextDef = getStream().getPacketContextDecl()
205 .createDefinition(this, "stream.packet.context"); //$NON-NLS-1$
206 }
207
208 }
209
9ac2eb62
MK
210 /**
211 * Adds the next packet header index entry to the index of a stream input.
be6df2d8
AM
212 *
213 * @warning slow, can corrupt data if not used properly
9ac2eb62
MK
214 * @return true if there are more packets to add
215 * @throws CTFReaderException
be6df2d8 216 * If there was a problem reading the packed header
9ac2eb62 217 */
bfe038ff
MK
218 public boolean addPacketHeaderIndex() throws CTFReaderException {
219 long currentPos = 0L;
220 if (!index.getEntries().isEmpty()) {
221 StreamInputPacketIndexEntry pos = index.getEntries().lastElement();
222 currentPos = computeNextOffset(pos);
223 }
224 long fileSize = getStreamSize();
225 if (currentPos < fileSize) {
226 BitBuffer bitBuffer = new BitBuffer();
8b8e48ed 227 bitBuffer.setByteOrder(this.getStream().getTrace().getByteOrder());
bfe038ff
MK
228 StreamInputPacketIndexEntry packetIndex = new StreamInputPacketIndexEntry(
229 currentPos);
230 createPacketIndexEntry(fileSize, currentPos, packetIndex,
231 tracePacketHeaderDef, streamPacketContextDef, bitBuffer);
232 index.addEntry(packetIndex);
233 return true;
234 }
235 return false;
236 }
237
bfe038ff
MK
238 private long getStreamSize() {
239 return file.length();
240 }
241
bfe038ff
MK
242 private long createPacketIndexEntry(long fileSizeBytes,
243 long packetOffsetBytes, StreamInputPacketIndexEntry packetIndex,
244 StructDefinition tracePacketHeaderDef,
245 StructDefinition streamPacketContextDef, BitBuffer bitBuffer)
246 throws CTFReaderException {
0594c61c
AM
247
248 /* Ignoring the return value, but this call is needed to initialize the input */
249 createPacketBitBuffer(fileSizeBytes, packetOffsetBytes, packetIndex, bitBuffer);
bfe038ff 250
866e5b51 251 /*
bfe038ff 252 * Read the trace packet header if it exists.
866e5b51 253 */
bfe038ff
MK
254 if (tracePacketHeaderDef != null) {
255 parseTracePacketHeader(tracePacketHeaderDef, bitBuffer);
866e5b51
FC
256 }
257
258 /*
bfe038ff 259 * Read the stream packet context if it exists.
866e5b51 260 */
bfe038ff
MK
261 if (streamPacketContextDef != null) {
262 parsePacketContext(fileSizeBytes, streamPacketContextDef,
263 bitBuffer, packetIndex);
264 } else {
265 setPacketContextNull(fileSizeBytes, packetIndex);
266 }
267
268 /* Basic validation */
269 if (packetIndex.getContentSizeBits() > packetIndex.getPacketSizeBits()) {
270 throw new CTFReaderException("Content size > packet size"); //$NON-NLS-1$
271 }
866e5b51 272
bfe038ff
MK
273 if (packetIndex.getPacketSizeBits() > ((fileSizeBytes - packetIndex
274 .getOffsetBytes()) * 8)) {
275 throw new CTFReaderException(
276 "Not enough data remaining in the file for the size of this packet"); //$NON-NLS-1$
277 }
278
279 /*
280 * Offset in the file, in bits
281 */
282 packetIndex.setDataOffsetBits(bitBuffer.position());
283
284 /*
285 * Update the counting packet offset
286 */
21fb02fa 287 return computeNextOffset(packetIndex);
bfe038ff
MK
288 }
289
290 /**
291 * @param packetIndex
292 * @return
293 */
294 private static long computeNextOffset(
295 StreamInputPacketIndexEntry packetIndex) {
296 return packetIndex.getOffsetBytes()
297 + ((packetIndex.getPacketSizeBits() + 7) / 8);
298 }
299
aa3b05ef
FC
300 /**
301 * @param fileSizeBytes
302 * @param packetOffsetBytes
303 * @param packetIndex
304 * @param bitBuffer
305 * @return
306 * @throws CTFReaderException
307 */
308 private MappedByteBuffer createPacketBitBuffer(long fileSizeBytes,
309 long packetOffsetBytes, StreamInputPacketIndexEntry packetIndex,
310 BitBuffer bitBuffer) throws CTFReaderException {
311 /*
312 * Initial size, it should map at least the packet header + context
313 * size.
314 *
315 * TODO: use a less arbitrary size.
316 */
317 long mapSize = 4096;
318 /*
319 * If there is less data remaining than what we want to map, reduce the
320 * map size.
321 */
322 if ((fileSizeBytes - packetIndex.getOffsetBytes()) < mapSize) {
323 mapSize = fileSizeBytes - packetIndex.getOffsetBytes();
324 }
325
326 /*
327 * Map the packet.
328 */
329 MappedByteBuffer bb;
330
331 try {
332 bb = fileChannel.map(MapMode.READ_ONLY, packetOffsetBytes, mapSize);
333 } catch (IOException e) {
334 throw new CTFReaderException(e);
335 }
336 bitBuffer.setByteBuffer(bb);
337 return bb;
338 }
bfe038ff 339
bfe038ff
MK
340 private void parseTracePacketHeader(StructDefinition tracePacketHeaderDef,
341 BitBuffer bitBuffer) throws CTFReaderException {
342 tracePacketHeaderDef.read(bitBuffer);
866e5b51
FC
343
344 /*
bfe038ff 345 * Check the CTF magic number
866e5b51 346 */
bfe038ff
MK
347 IntegerDefinition magicDef = (IntegerDefinition) tracePacketHeaderDef
348 .lookupDefinition("magic"); //$NON-NLS-1$
349 if (magicDef != null) {
350 int magic = (int) magicDef.getValue();
351 if (magic != Utils.CTF_MAGIC) {
352 throw new CTFReaderException(
353 "CTF magic mismatch " + Integer.toHexString(magic) + " vs " + Integer.toHexString(Utils.CTF_MAGIC)); //$NON-NLS-1$//$NON-NLS-2$
354 }
866e5b51
FC
355 }
356
357 /*
bfe038ff 358 * Check the trace UUID
866e5b51 359 */
0594c61c
AM
360 ArrayDefinition uuidDef =
361 (ArrayDefinition) tracePacketHeaderDef.lookupDefinition("uuid"); //$NON-NLS-1$
bfe038ff
MK
362 if (uuidDef != null) {
363 byte[] uuidArray = new byte[16];
364
0594c61c
AM
365 for (int i = 0; i < uuidArray.length; i++) {
366 IntegerDefinition uuidByteDef = (IntegerDefinition) uuidDef.getElem(i);
bfe038ff 367 uuidArray[i] = (byte) uuidByteDef.getValue();
866e5b51 368 }
866e5b51 369
bfe038ff 370 UUID uuid = Utils.makeUUID(uuidArray);
866e5b51 371
bfe038ff
MK
372 if (!getStream().getTrace().getUUID().equals(uuid)) {
373 throw new CTFReaderException("UUID mismatch"); //$NON-NLS-1$
866e5b51 374 }
bfe038ff 375 }
866e5b51 376
bfe038ff
MK
377 /*
378 * Check that the stream id did not change
379 */
380 IntegerDefinition streamIDDef = (IntegerDefinition) tracePacketHeaderDef
381 .lookupDefinition("stream_id"); //$NON-NLS-1$
382 if (streamIDDef != null) {
383 long streamID = streamIDDef.getValue();
866e5b51 384
bfe038ff 385 if (streamID != getStream().getId()) {
866e5b51 386 throw new CTFReaderException(
bfe038ff 387 "Stream ID changing within a StreamInput"); //$NON-NLS-1$
866e5b51 388 }
bfe038ff
MK
389 }
390 }
866e5b51 391
bfe038ff
MK
392 private static void setPacketContextNull(long fileSizeBytes,
393 StreamInputPacketIndexEntry packetIndex) {
394 /*
395 * If there is no packet context, infer the content and packet size from
396 * the file size (assume that there is only one packet and no padding)
397 */
47ca6c05
SM
398 packetIndex.setContentSizeBits(fileSizeBytes * 8);
399 packetIndex.setPacketSizeBits(fileSizeBytes * 8);
bfe038ff 400 }
866e5b51 401
bfe038ff
MK
402 private void parsePacketContext(long fileSizeBytes,
403 StructDefinition streamPacketContextDef, BitBuffer bitBuffer,
404 StreamInputPacketIndexEntry packetIndex) {
405 streamPacketContextDef.read(bitBuffer);
866e5b51 406
21fb02fa
MK
407 for (String field : streamPacketContextDef.getDeclaration()
408 .getFieldsList()) {
409 Definition id = streamPacketContextDef.lookupDefinition(field);
410 if (id instanceof IntegerDefinition) {
411 packetIndex.addAttribute(field,
412 ((IntegerDefinition) id).getValue());
413 } else if (id instanceof FloatDefinition) {
414 packetIndex.addAttribute(field,
415 ((FloatDefinition) id).getValue());
416 } else if (id instanceof EnumDefinition) {
417 packetIndex.addAttribute(field,
418 ((EnumDefinition) id).getValue());
419 } else if (id instanceof StringDefinition) {
420 packetIndex.addAttribute(field,
421 ((StringDefinition) id).getValue());
422 }
21fb02fa
MK
423 }
424
425 Long contentSize = (Long) packetIndex.lookupAttribute("content_size"); //$NON-NLS-1$
426 Long packetSize = (Long) packetIndex.lookupAttribute("packet_size"); //$NON-NLS-1$
0594c61c
AM
427 Long tsBegin = (Long) packetIndex.lookupAttribute("timestamp_begin"); //$NON-NLS-1$
428 Long tsEnd = (Long) packetIndex.lookupAttribute("timestamp_end"); //$NON-NLS-1$
21fb02fa
MK
429 String device = (String) packetIndex.lookupAttribute("device"); //$NON-NLS-1$
430 // LTTng Specific
0594c61c 431 Long cpuId = (Long) packetIndex.lookupAttribute("cpu_id"); //$NON-NLS-1$
132a02b0
MK
432 Long lostEvents = (Long) packetIndex.lookupAttribute("events_discarded"); //$NON-NLS-1$
433
434 /* Read the content size in bits */
21fb02fa
MK
435 if (contentSize != null) {
436 packetIndex.setContentSizeBits(contentSize.intValue());
bfe038ff
MK
437 } else {
438 packetIndex.setContentSizeBits((int) (fileSizeBytes * 8));
439 }
866e5b51 440
132a02b0 441 /* Read the packet size in bits */
21fb02fa
MK
442 if (packetSize != null) {
443 packetIndex.setPacketSizeBits(packetSize.intValue());
bfe038ff
MK
444 } else {
445 if (packetIndex.getContentSizeBits() != 0) {
446 packetIndex.setPacketSizeBits(packetIndex.getContentSizeBits());
447 } else {
448 packetIndex.setPacketSizeBits((int) (fileSizeBytes * 8));
449 }
450 }
451
132a02b0 452 /* Read the begin timestamp */
0594c61c
AM
453 if (tsBegin != null) {
454 packetIndex.setTimestampBegin(tsBegin.longValue());
bfe038ff
MK
455 }
456
132a02b0 457 /* Read the end timestamp */
0594c61c 458 if (tsEnd != null) {
ecb12461 459 if (tsEnd == -1) {
0594c61c 460 tsEnd = Long.MAX_VALUE;
21fb02fa 461 }
0594c61c 462 packetIndex.setTimestampEnd(tsEnd.longValue());
bfe038ff 463 setTimestampEnd(packetIndex.getTimestampEnd());
866e5b51 464 }
21fb02fa
MK
465
466 if (device != null) {
467 packetIndex.setTarget(device);
468 }
469
0594c61c
AM
470 if (cpuId != null) {
471 packetIndex.setTarget("CPU" + cpuId.toString()); //$NON-NLS-1$
21fb02fa 472 }
132a02b0
MK
473
474 if (lostEvents != null) {
475 packetIndex.setLostEvents(lostEvents - lostSoFar);
476 this.lostSoFar = lostEvents;
477 }
866e5b51
FC
478 }
479
81c8e6f7
MK
480 @Override
481 public int hashCode() {
482 final int prime = 31;
483 int result = 1;
484 result = (prime * result) + ((file == null) ? 0 : file.hashCode());
485 return result;
486 }
487
81c8e6f7
MK
488 @Override
489 public boolean equals(Object obj) {
490 if (this == obj) {
491 return true;
492 }
493 if (obj == null) {
494 return false;
495 }
496 if (!(obj instanceof StreamInput)) {
497 return false;
498 }
499 StreamInput other = (StreamInput) obj;
500 if (file == null) {
501 if (other.file != null) {
502 return false;
503 }
504 } else if (!file.equals(other.file)) {
505 return false;
506 }
507 return true;
508 }
509
866e5b51 510}
This page took 0.058808 seconds and 5 git commands to generate.