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