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