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