ctf: Make CTFTrace and its reader classes AutoCloseable
[deliverable/tracecompass.git] / org.eclipse.linuxtools.ctf.core / src / org / eclipse / linuxtools / ctf / core / trace / StreamInputReader.java
1 /*******************************************************************************
2 * Copyright (c) 2011, 2014 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
13 package org.eclipse.linuxtools.ctf.core.trace;
14
15 import java.nio.ByteOrder;
16 import java.util.Collections;
17 import java.util.HashMap;
18 import java.util.Map;
19
20 import org.eclipse.linuxtools.ctf.core.event.EventDefinition;
21 import org.eclipse.linuxtools.ctf.core.event.types.StructDefinition;
22 import org.eclipse.linuxtools.internal.ctf.core.trace.StreamInputPacketIndexEntry;
23
24 /**
25 * A CTF trace event reader. Reads the events of a trace file.
26 *
27 * @version 1.0
28 * @author Matthew Khouzam
29 * @author Simon Marchi
30 */
31 public class StreamInputReader implements AutoCloseable {
32
33 // ------------------------------------------------------------------------
34 // Attributes
35 // ------------------------------------------------------------------------
36
37 /**
38 * The StreamInput we are reading.
39 */
40 private final StreamInput fStreamInput;
41
42 /**
43 * The packet reader used to read packets from this trace file.
44 */
45 private final StreamInputPacketReader fPacketReader;
46
47 /**
48 * Iterator on the packet index
49 */
50 private int fPacketIndex;
51
52 /**
53 * Reference to the current event of this trace file (iow, the last on that
54 * was read, the next one to be returned)
55 */
56 private EventDefinition fCurrentEvent = null;
57
58 private int fId;
59
60 private CTFTraceReader fParent;
61
62 /** Map of all the event types */
63 private final Map<Long, EventDefinition> fEventDefs = new HashMap<>();
64
65 /**
66 * Live trace reading
67 */
68 private boolean fLive = false;
69
70 // ------------------------------------------------------------------------
71 // Constructors
72 // ------------------------------------------------------------------------
73
74 /**
75 * Constructs a StreamInputReader that reads a StreamInput.
76 *
77 * @param streamInput
78 * The StreamInput to read.
79 * @throws CTFReaderException
80 * if an error occurs
81 * @since 2.0
82 */
83 public StreamInputReader(StreamInput streamInput) throws CTFReaderException {
84 fStreamInput = streamInput;
85 fPacketReader = new StreamInputPacketReader(this);
86 /*
87 * Get the iterator on the packet index.
88 */
89 fPacketIndex = 0;
90 /*
91 * Make first packet the current one.
92 */
93 goToNextPacket();
94 }
95
96 /**
97 * Dispose the StreamInputReader
98 *
99 * @since 3.0
100 */
101 @Override
102 public void close() {
103 fPacketReader.close();
104 }
105
106 // ------------------------------------------------------------------------
107 // Getters/Setters/Predicates
108 // ------------------------------------------------------------------------
109
110 /**
111 * Gets the current event in this stream
112 *
113 * @return the current event in the stream, null if the stream is
114 * finished/empty/malformed
115 */
116 public EventDefinition getCurrentEvent() {
117 return fCurrentEvent;
118 }
119
120 /**
121 * Gets the current packet context
122 *
123 * @return the current packet context (size, lost events and such)
124 */
125 public StructDefinition getCurrentPacketContext() {
126 return fPacketReader.getStreamPacketContextDef();
127 }
128
129 /**
130 * Gets the byte order for a trace
131 *
132 * @return the trace byte order
133 */
134 public ByteOrder getByteOrder() {
135 return fStreamInput.getStream().getTrace().getByteOrder();
136 }
137
138 /**
139 * Gets the name of the stream (it's an id and a number)
140 *
141 * @return gets the stream name (it's a number)
142 */
143 public int getName() {
144 return fId;
145 }
146
147 /**
148 * Sets the name of the stream
149 *
150 * @param name
151 * the name of the stream, (it's a number)
152 */
153 public void setName(int name) {
154 fId = name;
155 }
156
157 /**
158 * Gets the CPU of a stream. It's the same as the one in /proc or running
159 * the asm CPUID instruction
160 *
161 * @return The CPU id (a number)
162 */
163 public int getCPU() {
164 return fPacketReader.getCPU();
165 }
166
167 /**
168 * Gets the filename of the stream being read
169 *
170 * @return The filename of the stream being read
171 */
172 public String getFilename() {
173 return fStreamInput.getFilename();
174 }
175
176 /*
177 * for internal use only
178 */
179 StreamInput getStreamInput() {
180 return fStreamInput;
181 }
182
183 /**
184 * Gets the event definition hashmap for this StreamInput
185 *
186 * @return Unmodifiable map with the event definitions
187 * @since 2.1
188 */
189 public Map<Long, EventDefinition> getEventDefinitions() {
190 return Collections.unmodifiableMap(fEventDefs);
191 }
192
193 /**
194 * Add an event definition to this stream input reader.
195 *
196 * @param id
197 * The id of the event definition. This will overwrite any
198 * existing definition with the same id.
199 * @param def
200 * The matching event definition
201 * @since 2.1
202 */
203 public void addEventDefinition(Long id, EventDefinition def) {
204 fEventDefs.put(id, def);
205 }
206
207 /**
208 * Set the trace to live mode
209 *
210 * @param live
211 * whether the trace is read live or not
212 * @since 3.0
213 */
214 public void setLive(boolean live) {
215 fLive = live;
216 }
217
218 /**
219 * Get if the trace is to read live or not
220 *
221 * @return whether the trace is live or not
222 * @since 3.0
223 */
224 public boolean isLive() {
225 return fLive;
226 }
227
228 // ------------------------------------------------------------------------
229 // Operations
230 // ------------------------------------------------------------------------
231 /**
232 * Reads the next event in the current event variable.
233 *
234 * @return If an event has been successfully read.
235 * @throws CTFReaderException
236 * if an error occurs
237 * @since 3.0
238 */
239 public CTFResponse readNextEvent() throws CTFReaderException {
240
241 /*
242 * Change packet if needed
243 */
244 if (!fPacketReader.hasMoreEvents()) {
245 final StreamInputPacketIndexEntry prevPacket = fPacketReader
246 .getCurrentPacket();
247 if (prevPacket != null || fLive ) {
248 goToNextPacket();
249 }
250
251 }
252
253 /*
254 * If an event is available, read it.
255 */
256 if (fPacketReader.hasMoreEvents()) {
257 setCurrentEvent(fPacketReader.readNextEvent());
258 return CTFResponse.OK;
259 }
260 this.setCurrentEvent(null);
261 return fLive ? CTFResponse.WAIT : CTFResponse.FINISH;
262 }
263
264 /**
265 * Change the current packet of the packet reader to the next one.
266 *
267 * @throws CTFReaderException
268 * if an error occurs
269 */
270 private void goToNextPacket() throws CTFReaderException {
271 fPacketIndex++;
272 // did we already index the packet?
273 if (getPacketSize() >= (fPacketIndex + 1)) {
274 fPacketReader.setCurrentPacket(getPacket());
275 } else {
276 // go to the next packet if there is one, index it at the same time
277 if (fStreamInput.addPacketHeaderIndex()) {
278 fPacketIndex = getPacketSize() - 1;
279 fPacketReader.setCurrentPacket(getPacket());
280 } else {
281 // out of packets
282 fPacketReader.setCurrentPacket(null);
283 }
284 }
285 }
286
287 /**
288 * @return
289 */
290 private int getPacketSize() {
291 return fStreamInput.getIndex().getEntries().size();
292 }
293
294 /**
295 * Changes the location of the trace file reader so that the current event
296 * is the first event with a timestamp greater or equal the given timestamp.
297 *
298 * @param timestamp
299 * The timestamp to seek to.
300 * @return The offset compared to the current position
301 * @throws CTFReaderException
302 * if an error occurs
303 */
304 public long seek(long timestamp) throws CTFReaderException {
305 long offset = 0;
306
307 gotoPacket(timestamp);
308
309 /*
310 * index up to the desired timestamp.
311 */
312 while ((fPacketReader.getCurrentPacket() != null)
313 && (fPacketReader.getCurrentPacket().getTimestampEnd() < timestamp)) {
314 try {
315 fStreamInput.addPacketHeaderIndex();
316 goToNextPacket();
317 } catch (CTFReaderException e) {
318 // do nothing here
319 }
320 }
321 if (fPacketReader.getCurrentPacket() == null) {
322 gotoPacket(timestamp);
323 }
324
325 /*
326 * Advance until either of these conditions are met:
327 *
328 * - reached the end of the trace file (the given timestamp is after the
329 * last event)
330 *
331 * - found the first event with a timestamp greater or equal the given
332 * timestamp.
333 */
334 readNextEvent();
335 boolean done = (this.getCurrentEvent() == null);
336 while (!done && (this.getCurrentEvent().getTimestamp() < timestamp)) {
337 readNextEvent();
338 done = (this.getCurrentEvent() == null);
339 offset++;
340 }
341 return offset;
342 }
343
344 /**
345 * @param timestamp
346 * the time to seek
347 * @throws CTFReaderException
348 * if an error occurs
349 */
350 private void gotoPacket(long timestamp) throws CTFReaderException {
351 fPacketIndex = fStreamInput.getIndex().search(timestamp)
352 .previousIndex();
353 /*
354 * Switch to this packet.
355 */
356 goToNextPacket();
357 }
358
359 /**
360 * Seeks the last event of a stream and returns it.
361 *
362 * @throws CTFReaderException
363 * if an error occurs
364 */
365 public void goToLastEvent() throws CTFReaderException {
366 /*
367 * Search in the index for the packet to search in.
368 */
369 final int len = fStreamInput.getIndex().getEntries().size();
370
371 /*
372 * Go to beginning of trace.
373 */
374 seek(0);
375 /*
376 * if the trace is empty.
377 */
378 if ((len == 0) || (fPacketReader.hasMoreEvents() == false)) {
379 /*
380 * This means the trace is empty. abort.
381 */
382 return;
383 }
384 /*
385 * Go to the last packet that contains events.
386 */
387 for (int pos = len - 1; pos > 0; pos--) {
388 fPacketIndex = pos;
389 fPacketReader.setCurrentPacket(getPacket());
390 if (fPacketReader.hasMoreEvents()) {
391 break;
392 }
393 }
394
395 /*
396 * Go until the end of that packet
397 */
398 EventDefinition prevEvent = null;
399 while (fCurrentEvent != null) {
400 prevEvent = fCurrentEvent;
401 this.readNextEvent();
402 }
403 /*
404 * Go back to the previous event
405 */
406 this.setCurrentEvent(prevEvent);
407 }
408
409 /**
410 * @return the parent
411 */
412 public CTFTraceReader getParent() {
413 return fParent;
414 }
415
416 /**
417 * @param parent
418 * the parent to set
419 */
420 public void setParent(CTFTraceReader parent) {
421 fParent = parent;
422 }
423
424 /**
425 * Sets the current event in a stream input reader
426 *
427 * @param currentEvent
428 * the event to set
429 */
430 public void setCurrentEvent(EventDefinition currentEvent) {
431 fCurrentEvent = currentEvent;
432 }
433
434 /**
435 * @return the packetIndexIt
436 */
437 private int getPacketIndex() {
438 return fPacketIndex;
439 }
440
441 private StreamInputPacketIndexEntry getPacket() {
442 return fStreamInput.getIndex().getEntries().get(getPacketIndex());
443 }
444
445 /**
446 * @return the packetReader
447 */
448 public StreamInputPacketReader getPacketReader() {
449 return fPacketReader;
450 }
451
452 @Override
453 public int hashCode() {
454 final int prime = 31;
455 int result = 1;
456 result = (prime * result) + fId;
457 result = (prime * result)
458 + ((fStreamInput == null) ? 0 : fStreamInput.hashCode());
459 return result;
460 }
461
462 @Override
463 public boolean equals(Object obj) {
464 if (this == obj) {
465 return true;
466 }
467 if (obj == null) {
468 return false;
469 }
470 if (!(obj instanceof StreamInputReader)) {
471 return false;
472 }
473 StreamInputReader other = (StreamInputReader) obj;
474 if (fId != other.fId) {
475 return false;
476 }
477 if (fStreamInput == null) {
478 if (other.fStreamInput != null) {
479 return false;
480 }
481 } else if (!fStreamInput.equals(other.fStreamInput)) {
482 return false;
483 }
484 return true;
485 }
486
487 @Override
488 public String toString() {
489 // this helps debugging
490 return fId + ' ' + fCurrentEvent.toString();
491 }
492 }
This page took 0.049686 seconds and 5 git commands to generate.