Clean up duplicate function
[deliverable/tracecompass.git] / org.eclipse.linuxtools.ctf.core / src / org / eclipse / linuxtools / ctf / core / trace / CTFTrace.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: Alexandre Montplaisir - Initial API and implementation
11 *******************************************************************************/
12
13package org.eclipse.linuxtools.ctf.core.trace;
14
15import java.io.File;
16import java.io.FileFilter;
17import java.io.FileInputStream;
18import java.io.IOException;
debcffff 19import java.io.Serializable;
866e5b51
FC
20import java.nio.ByteOrder;
21import java.nio.MappedByteBuffer;
22import java.nio.channels.FileChannel;
23import java.nio.channels.FileChannel.MapMode;
24import java.util.Arrays;
25import java.util.Comparator;
26import java.util.HashMap;
aa572e22 27import java.util.Iterator;
d0d3aa1b
AM
28import java.util.LinkedList;
29import java.util.List;
866e5b51 30import java.util.Map;
aa572e22 31import java.util.Map.Entry;
866e5b51
FC
32import java.util.Set;
33import java.util.UUID;
34
866e5b51 35import org.eclipse.linuxtools.ctf.core.event.CTFClock;
aa572e22 36import org.eclipse.linuxtools.ctf.core.event.EventDeclaration;
866e5b51
FC
37import org.eclipse.linuxtools.ctf.core.event.types.ArrayDefinition;
38import org.eclipse.linuxtools.ctf.core.event.types.Definition;
39import org.eclipse.linuxtools.ctf.core.event.types.IDefinitionScope;
40import org.eclipse.linuxtools.ctf.core.event.types.IntegerDefinition;
41import org.eclipse.linuxtools.ctf.core.event.types.StructDeclaration;
42import org.eclipse.linuxtools.ctf.core.event.types.StructDefinition;
a9d52b8f 43import org.eclipse.linuxtools.internal.ctf.core.Activator;
ce2388e0
FC
44import org.eclipse.linuxtools.internal.ctf.core.event.io.BitBuffer;
45import org.eclipse.linuxtools.internal.ctf.core.event.metadata.exceptions.ParseException;
46import org.eclipse.linuxtools.internal.ctf.core.trace.Stream;
47import org.eclipse.linuxtools.internal.ctf.core.trace.StreamInput;
866e5b51
FC
48
49/**
50 * <b><u>CTFTrace</u></b>
51 * <p>
52 * Represents a trace on the filesystem. It is responsible of parsing the
53 * metadata, creating declarations data structures, indexing the event packets
54 * (in other words, all the work that can be shared between readers), but the
55 * actual reading of events is left to TraceReader.
debcffff 56 *
866e5b51
FC
57 * @author Matthew Khouzam
58 * @version $Revision: 1.0 $
59 */
60public class CTFTrace implements IDefinitionScope {
61
62 // ------------------------------------------------------------------------
63 // Attributes
64 // ------------------------------------------------------------------------
65
66 /*
67 * (non-Javadoc)
debcffff 68 *
866e5b51
FC
69 * @see java.lang.Object#toString()
70 */
71 @SuppressWarnings("nls")
72 @Override
73 public String toString() {
74 /* Only for debugging, shouldn't be externalized */
75 return "CTFTrace [path=" + path + ", major=" + major + ", minor="
76 + minor + ", uuid=" + uuid + "]";
77 }
78
79 /**
80 * The trace directory on the filesystem.
81 */
82 private final File path;
83
84 /**
85 * The metadata parsing object.
86 */
87 private final Metadata metadata;
88
89 /**
90 * Major CTF version number
91 */
92 private Long major;
93
94 /**
95 * Minor CTF version number
96 */
97 private Long minor;
98
99 /**
100 * Trace UUID
101 */
102 private UUID uuid;
103
104 /**
105 * Trace byte order
106 */
107 private ByteOrder byteOrder;
108
109 /**
110 * Packet header structure declaration
111 */
debcffff 112 private StructDeclaration packetHeaderDecl = null;
866e5b51
FC
113
114 /**
115 * Packet header structure definition
debcffff 116 *
866e5b51
FC
117 * This is only used when opening the trace files, to read the first packet
118 * header and see if they are valid trace files.
119 */
120 private StructDefinition packetHeaderDef;
121
122 /**
123 * Collection of streams contained in the trace.
124 */
c88e827d 125 private final HashMap<Long, Stream> streams;
866e5b51
FC
126
127 /**
128 * Collection of environment variables set by the tracer
129 */
c88e827d 130 private final HashMap<String, String> environment;
866e5b51
FC
131
132 /**
133 * Collection of all the clocks in a system.
134 */
c88e827d 135 private final HashMap<String, CTFClock> clocks;
866e5b51 136
26ea03d2 137 /** FileChannels to the streams */
d0d3aa1b 138 private final List<FileChannel> streamFileChannels;
26ea03d2 139
c88e827d
AM
140 /** Handlers for the metadata files */
141 private final static FileFilter metadataFileFilter = new MetadataFileFilter();
8ecc80f3
MK
142 private final static Comparator<File> metadataComparator = new MetadataComparator(); // $codepro.audit.disable
143 // fieldJavadoc
866e5b51 144
aa572e22
MK
145 /** map of all the event types */
146 private final HashMap<Long, EventDeclaration> events;
147
866e5b51
FC
148 // ------------------------------------------------------------------------
149 // Constructors
150 // ------------------------------------------------------------------------
151
152 /**
153 * Trace constructor.
debcffff 154 *
866e5b51
FC
155 * @param path
156 * Filesystem path of the trace directory.
157 * @throws IOException
158 */
159 public CTFTrace(String path) throws CTFReaderException {
160 this(new File(path));
aa572e22 161
866e5b51
FC
162 }
163
164 /**
165 * Trace constructor.
debcffff 166 *
866e5b51
FC
167 * @param path
168 * Filesystem path of the trace directory.
169 * @throws CTFReaderException
170 */
866e5b51
FC
171 public CTFTrace(File path) throws CTFReaderException {
172 this.path = path;
c88e827d 173 this.metadata = new Metadata(this);
866e5b51 174
c88e827d
AM
175 /* Set up the internal containers for this trace */
176 streams = new HashMap<Long, Stream>();
177 environment = new HashMap<String, String>();
178 clocks = new HashMap<String, CTFClock>();
d0d3aa1b
AM
179 streamFileChannels = new LinkedList<FileChannel>();
180
181 if (!this.path.isDirectory()) {
182 throw new CTFReaderException("Path must be a valid directory"); //$NON-NLS-1$
183 }
c88e827d
AM
184
185 /* Open and parse the metadata file */
186 metadata.parse();
187
188 if (Activator.getDefault() != null) {
189 Activator.getDefault().log(metadata.toString());
190 }
866e5b51 191
c88e827d
AM
192 /* Open all the trace files */
193 /* Create the definitions needed to read things from the files */
194 if (packetHeaderDecl != null) {
195 packetHeaderDef = packetHeaderDecl.createDefinition(this,
196 "packet.header"); //$NON-NLS-1$
197 }
198
199 /* List files not called metadata and not hidden. */
200 File[] files = path.listFiles(metadataFileFilter);
201 Arrays.sort(files, metadataComparator);
202
203 /* Try to open each file */
d0d3aa1b
AM
204 for (File streamFile : files) {
205 openStreamInput(streamFile);
c88e827d 206 }
aa572e22 207 events = new HashMap<Long, EventDeclaration>();
c88e827d
AM
208 /* Create their index */
209 for (Map.Entry<Long, Stream> stream : streams.entrySet()) {
210 Set<StreamInput> inputs = stream.getValue().getStreamInputs();
211 for (StreamInput s : inputs) {
aa572e22
MK
212 /*
213 * Copy the events
214 */
215 Iterator<Entry<Long, EventDeclaration>> it = s.getStream()
216 .getEvents().entrySet().iterator();
217 while (it.hasNext()) {
218 Map.Entry<Long, EventDeclaration> pairs = it.next();
219 Long eventNum = pairs.getKey();
220 EventDeclaration eventDec = pairs.getValue();
221 events.put(eventNum, eventDec);
222 }
223
224 /*
225 * index the trace
226 */
bfe038ff 227 s.setupIndex();
c88e827d
AM
228 }
229 }
866e5b51
FC
230 }
231
26ea03d2 232 @Override
8ecc80f3 233 protected void finalize() throws Throwable {
26ea03d2
AM
234 /* If this trace gets closed, release the descriptors to the streams */
235 for (FileChannel fc : streamFileChannels) {
236 if (fc != null) {
237 try {
238 fc.close();
239 } catch (IOException e) {
aa572e22 240 // do nothing it's ok, we tried to close it.
26ea03d2
AM
241 }
242 }
243 }
787bc247
MK
244 super.finalize();
245
26ea03d2
AM
246 }
247
866e5b51
FC
248 // ------------------------------------------------------------------------
249 // Getters/Setters/Predicates
250 // ------------------------------------------------------------------------
251
aa572e22
MK
252 /**
253 * Get an event by it's ID
254 *
255 * @param id
256 * the ID of the event
257 * @return the event declaration
258 */
259 public EventDeclaration getEventType(long id) {
260 return events.get(id);
261 }
262
263 /**
264 * Get the number of events in the trace so far.
265 *
266 * @return the number of events in the trace
267 */
268 public int getNbEventTypes() {
269 return events.size();
270 }
271
866e5b51
FC
272 /**
273 * Method getStream gets the stream for a given id
debcffff 274 *
866e5b51
FC
275 * @param id
276 * Long the id of the stream
277 * @return Stream the stream that we need
278 */
279 public Stream getStream(Long id) {
280 return streams.get(id);
281 }
282
283 /**
284 * Method nbStreams gets the number of available streams
debcffff 285 *
866e5b51
FC
286 * @return int the number of streams
287 */
288 public int nbStreams() {
289 return streams.size();
290 }
291
292 /**
293 * Method setMajor sets the major version of the trace (DO NOT USE)
debcffff 294 *
866e5b51
FC
295 * @param major
296 * long the major version
297 */
298 public void setMajor(long major) {
299 this.major = major;
300 }
301
302 /**
303 * Method setMinor sets the minor version of the trace (DO NOT USE)
debcffff 304 *
866e5b51
FC
305 * @param minor
306 * long the minor version
307 */
308 public void setMinor(long minor) {
309 this.minor = minor;
310 }
311
312 /**
313 * Method setUUID sets the UUID of a trace
debcffff 314 *
866e5b51
FC
315 * @param uuid
316 * UUID
317 */
318 public void setUUID(UUID uuid) {
319 this.uuid = uuid;
320 }
321
322 /**
323 * Method setByteOrder sets the byte order
debcffff 324 *
866e5b51
FC
325 * @param byteOrder
326 * ByteOrder of the trace, can be little-endian or big-endian
327 */
328 public void setByteOrder(ByteOrder byteOrder) {
329 this.byteOrder = byteOrder;
330 }
331
332 /**
333 * Method setPacketHeader sets the packet header of a trace (DO NOT USE)
debcffff 334 *
866e5b51
FC
335 * @param packetHeader
336 * StructDeclaration the header in structdeclaration form
337 */
338 public void setPacketHeader(StructDeclaration packetHeader) {
339 this.packetHeaderDecl = packetHeader;
340 }
341
342 /**
343 * Method majortIsSet is the major version number set?
debcffff 344 *
866e5b51
FC
345 * @return boolean is the major set?
346 */
347 public boolean majortIsSet() {
348 return major != null;
349 }
350
351 /**
352 * Method minorIsSet. is the minor version number set?
debcffff 353 *
866e5b51
FC
354 * @return boolean is the minor set?
355 */
356 public boolean minorIsSet() {
357 return minor != null;
358 }
359
360 /**
361 * Method UUIDIsSet is the UUID set?
debcffff 362 *
866e5b51
FC
363 * @return boolean is the UUID set?
364 */
365 public boolean UUIDIsSet() {
366 return uuid != null;
367 }
368
369 /**
370 * Method byteOrderIsSet is the byteorder set?
debcffff 371 *
866e5b51
FC
372 * @return boolean is the byteorder set?
373 */
374 public boolean byteOrderIsSet() {
375 return byteOrder != null;
376 }
377
378 /**
379 * Method packetHeaderIsSet is the packet header set?
debcffff 380 *
866e5b51
FC
381 * @return boolean is the packet header set?
382 */
383 public boolean packetHeaderIsSet() {
384 return packetHeaderDecl != null;
385 }
386
387 /**
388 * Method getUUID gets the trace UUID
debcffff 389 *
866e5b51
FC
390 * @return UUID gets the trace UUID
391 */
392 public UUID getUUID() {
393 return uuid;
394 }
395
396 /**
397 * Method getMajor gets the trace major version
debcffff 398 *
866e5b51
FC
399 * @return long gets the trace major version
400 */
401 public long getMajor() {
402 return major;
403 }
404
405 /**
406 * Method getMinor gets the trace minor version
debcffff 407 *
866e5b51
FC
408 * @return long gets the trace minor version
409 */
410 public long getMinor() {
411 return minor;
412 }
413
414 /**
415 * Method getByteOrder gets the trace byte order
debcffff 416 *
866e5b51
FC
417 * @return ByteOrder gets the trace byte order
418 */
419 public ByteOrder getByteOrder() {
420 return byteOrder;
421 }
422
423 /**
424 * Method getPacketHeader gets the trace packet header
debcffff 425 *
866e5b51
FC
426 * @return StructDeclaration gets the trace packet header
427 */
428 public StructDeclaration getPacketHeader() {
429 return packetHeaderDecl;
430 }
431
432 /**
433 * Method getTraceDirectory gets the trace directory
debcffff 434 *
866e5b51
FC
435 * @return File the path in "File" format.
436 */
437 public File getTraceDirectory() {
438 return path;
439 }
440
441 /**
442 * Method getStreams get all the streams in a map format.
debcffff 443 *
866e5b51
FC
444 * @return Map<Long,Stream> a map of all the streams.
445 */
446 public Map<Long, Stream> getStreams() {
447 return streams;
448 }
449
450 /**
451 * Method getPath gets the path of the trace directory
debcffff 452 *
866e5b51
FC
453 * @return String the path of the trace directory, in string format.
454 * @see java.io.File#getPath()
455 */
456 @Override
457 public String getPath() {
458 return path.getPath();
459 }
460
461 // ------------------------------------------------------------------------
462 // Operations
463 // ------------------------------------------------------------------------
464
866e5b51
FC
465 /**
466 * Tries to open the given file, reads the first packet header of the file
467 * and check its validity.
debcffff 468 *
866e5b51
FC
469 * @param streamFile
470 * A trace file in the trace directory.
26ea03d2
AM
471 * @param index
472 * Which index in the class' streamFileChannel array this file
473 * must use
866e5b51
FC
474 * @throws CTFReaderException
475 */
aa572e22 476 private void openStreamInput(File streamFile) throws CTFReaderException {
866e5b51
FC
477 MappedByteBuffer byteBuffer;
478 BitBuffer streamBitBuffer;
d0d3aa1b
AM
479 Stream stream;
480 FileChannel fc;
866e5b51
FC
481
482 if (!streamFile.canRead()) {
483 throw new CTFReaderException("Unreadable file : " //$NON-NLS-1$
484 + streamFile.getPath());
485 }
486
487 try {
488 /* Open the file and get the FileChannel */
d0d3aa1b
AM
489 fc = new FileInputStream(streamFile).getChannel();
490 streamFileChannels.add(fc);
866e5b51
FC
491
492 /* Map one memory page of 4 kiB */
d0d3aa1b 493 byteBuffer = fc.map(MapMode.READ_ONLY, 0, 4096);
866e5b51
FC
494 } catch (IOException e) {
495 /* Shouldn't happen at this stage if every other check passed */
496 throw new CTFReaderException();
497 }
498
499 /* Create a BitBuffer with this mapping and the trace byte order */
500 streamBitBuffer = new BitBuffer(byteBuffer, this.getByteOrder());
501
502 if (packetHeaderDef != null) {
503 /* Read the packet header */
504 packetHeaderDef.read(streamBitBuffer);
505
506 /* Check the magic number */
aa572e22
MK
507 IntegerDefinition magicDef = (IntegerDefinition) packetHeaderDef
508 .lookupDefinition("magic"); //$NON-NLS-1$
866e5b51
FC
509 int magic = (int) magicDef.getValue();
510 if (magic != Utils.CTF_MAGIC) {
511 throw new CTFReaderException("CTF magic mismatch"); //$NON-NLS-1$
512 }
513
514 /* Check UUID */
aa572e22
MK
515 ArrayDefinition uuidDef = (ArrayDefinition) packetHeaderDef
516 .lookupDefinition("uuid"); //$NON-NLS-1$
866e5b51
FC
517 if (uuidDef != null) {
518 byte[] uuidArray = new byte[Utils.UUID_LEN];
519
520 for (int i = 0; i < Utils.UUID_LEN; i++) {
aa572e22
MK
521 IntegerDefinition uuidByteDef = (IntegerDefinition) uuidDef
522 .getElem(i);
866e5b51
FC
523 uuidArray[i] = (byte) uuidByteDef.getValue();
524 }
525
526 UUID otheruuid = Utils.makeUUID(uuidArray);
527
528 if (!this.uuid.equals(otheruuid)) {
529 throw new CTFReaderException("UUID mismatch"); //$NON-NLS-1$
530 }
531 }
532
533 /* Read stream ID */
534 // TODO: it hasn't been checked that the stream_id field exists and
535 // is an unsigned
536 // integer
aa572e22
MK
537 IntegerDefinition streamIDDef = (IntegerDefinition) packetHeaderDef
538 .lookupDefinition("stream_id"); //$NON-NLS-1$
866e5b51
FC
539 assert (streamIDDef != null);
540
541 long streamID = streamIDDef.getValue();
542
543 /* Get the stream to which this trace file belongs to */
d0d3aa1b 544 stream = streams.get(streamID);
866e5b51
FC
545 } else {
546 /* No packet header, we suppose there is only one stream */
d0d3aa1b
AM
547 stream = streams.get(null);
548 }
866e5b51 549
d0d3aa1b
AM
550 /* Create the stream input */
551 StreamInput streamInput = new StreamInput(stream, fc, streamFile);
866e5b51 552
d0d3aa1b
AM
553 /* Add a reference to the streamInput in the stream */
554 stream.addInput(streamInput);
866e5b51
FC
555 }
556
557 /**
558 * Looks up a definition from packet
debcffff 559 *
866e5b51
FC
560 * @param lookupPath
561 * String
562 * @return Definition
563 * @see org.eclipse.linuxtools.ctf.core.event.types.IDefinitionScope#lookupDefinition(String)
564 */
565 @Override
566 public Definition lookupDefinition(String lookupPath) {
567 if (lookupPath.equals("trace.packet.header")) { //$NON-NLS-1$
568 return packetHeaderDef;
569 }
570 return null;
571 }
572
573 /**
574 * Adds a new stream to the trace.
debcffff 575 *
866e5b51
FC
576 * @param stream
577 * A stream object.
debcffff 578 *
866e5b51
FC
579 * @throws ParseException
580 */
581 public void addStream(Stream stream) throws ParseException {
582
583 /*
584 * If there is already a stream without id (the null key), it must be
585 * the only one
586 */
587 if (streams.get(null) != null) {
588 throw new ParseException("Stream without id with multiple streams"); //$NON-NLS-1$
589 }
590
591 /*
592 * If the stream we try to add has the null key, it must be the only
593 * one. Thus, if the streams container is not empty, it is not valid.
594 */
595 if ((stream.getId() == null) && (streams.size() != 0)) {
596 throw new ParseException("Stream without id with multiple streams"); //$NON-NLS-1$
597 }
598
599 /* If a stream with the same ID already exists, it is not valid. */
600 if (streams.get(stream.getId()) != null) {
601 throw new ParseException("Stream id already exists"); //$NON-NLS-1$
602 }
603
604 /* It should be ok now. */
605 streams.put(stream.getId(), stream);
606 }
607
608 public HashMap<String, String> getEnvironment() {
609 return environment;
610 }
611
c88e827d 612 public String lookupEnvironment(String key) {
866e5b51
FC
613 return environment.get(key);
614 }
615
c88e827d 616 public void addEnvironmentVar(String varName, String varValue) {
866e5b51
FC
617 environment.put(varName, varValue);
618 }
619
620 public void addClock(String nameValue, CTFClock ctfClock) {
c88e827d 621 clocks.put(nameValue, ctfClock);
866e5b51
FC
622 }
623
c88e827d 624 public CTFClock getClock(String name) {
866e5b51
FC
625 return clocks.get(name);
626 }
627
8ecc80f3
MK
628 private CTFClock singleClock;
629 private long singleOffset;
630
631 public final CTFClock getClock() {
c88e827d 632 if (clocks.size() == 1) {
8ecc80f3
MK
633 if (singleClock == null) {
634 singleClock = clocks.get(clocks.keySet().toArray()[0]);
635 singleOffset = (Long) getClock().getProperty("offset"); //$NON-NLS-1$
636 }
637 return singleClock;
866e5b51
FC
638 }
639 return null;
640 }
641
8ecc80f3 642 public final long getOffset() {
c88e827d 643 if (getClock() == null) {
ce2388e0
FC
644 return 0;
645 }
8ecc80f3 646 return singleOffset;
ce2388e0
FC
647 }
648
866e5b51 649}
c88e827d
AM
650
651class MetadataFileFilter implements FileFilter {
652
653 @Override
654 public boolean accept(File pathname) {
655 if (pathname.isDirectory()) {
656 return false;
657 }
658 if (pathname.isHidden()) {
659 return false;
660 }
661 if (pathname.getName().equals("metadata")) { //$NON-NLS-1$
662 return false;
663 }
664 return true;
665 }
666
667}
668
debcffff 669class MetadataComparator implements Comparator<File>, Serializable {
c88e827d 670
8fd82db5
FC
671 private static final long serialVersionUID = 1L;
672
c88e827d
AM
673 @Override
674 public int compare(File o1, File o2) {
675 return o1.getName().compareTo(o2.getName());
676 }
677}
This page took 0.08607 seconds and 5 git commands to generate.