ctf: Make events immutable
[deliverable/tracecompass.git] / org.eclipse.linuxtools.ctf.core / src / org / eclipse / linuxtools / ctf / core / trace / StreamInputReader.java
index e6710aaad64ca30647aeb830167c4b3c571eb4b0..bcc65573d567d5d98d46b177ca02e6eef691cb7b 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2011-2012 Ericsson, Ecole Polytechnique de Montreal and others
+ * Copyright (c) 2011, 2014 Ericsson, Ecole Polytechnique de Montreal and others
  *
  * All rights reserved. This program and the accompanying materials are made
  * available under the terms of the Eclipse Public License v1.0 which
 package org.eclipse.linuxtools.ctf.core.trace;
 
 import java.nio.ByteOrder;
-import java.util.ListIterator;
 
 import org.eclipse.linuxtools.ctf.core.event.EventDefinition;
-import org.eclipse.linuxtools.ctf.core.event.types.StructDefinition;
-import org.eclipse.linuxtools.internal.ctf.core.trace.StreamInput;
+import org.eclipse.linuxtools.ctf.core.event.types.StructDeclaration;
 import org.eclipse.linuxtools.internal.ctf.core.trace.StreamInputPacketIndexEntry;
 
 /**
- * <b><u>StreamInputReader</u></b>
- * <p>
- * Reads the events of a trace file.
+ * A CTF trace event reader. Reads the events of a trace file.
+ *
+ * @version 1.0
+ * @author Matthew Khouzam
+ * @author Simon Marchi
  */
-public class StreamInputReader {
+public class StreamInputReader implements AutoCloseable {
 
     // ------------------------------------------------------------------------
     // Attributes
@@ -34,25 +34,32 @@ public class StreamInputReader {
     /**
      * The StreamInput we are reading.
      */
-    private final StreamInput streamInput;
+    private final StreamInput fStreamInput;
 
     /**
      * The packet reader used to read packets from this trace file.
      */
-    private final StreamInputPacketReader packetReader;
+    private final StreamInputPacketReader fPacketReader;
 
     /**
      * Iterator on the packet index
      */
-    private ListIterator<StreamInputPacketIndexEntry> packetIndexIt;
+    private int fPacketIndex;
 
     /**
      * Reference to the current event of this trace file (iow, the last on that
      * was read, the next one to be returned)
      */
-    private EventDefinition currentEvent = null;
+    private EventDefinition fCurrentEvent = null;
+
+    private int fId;
 
-    private int name;
+    private CTFTraceReader fParent;
+
+    /**
+     * Live trace reading
+     */
+    private boolean fLive = false;
 
     // ------------------------------------------------------------------------
     // Constructors
@@ -63,59 +70,130 @@ public class StreamInputReader {
      *
      * @param streamInput
      *            The StreamInput to read.
+     * @throws CTFReaderException
+     *             if an error occurs
+     * @since 2.0
      */
-    public StreamInputReader(StreamInput streamInput) {
-        this.streamInput = streamInput;
-        this.packetReader = new StreamInputPacketReader(this);
-
+    public StreamInputReader(StreamInput streamInput) throws CTFReaderException {
+        fStreamInput = streamInput;
+        fPacketReader = new StreamInputPacketReader(this);
         /*
          * Get the iterator on the packet index.
          */
-        this.packetIndexIt = streamInput.getIndex().listIterator();
-
+        fPacketIndex = 0;
         /*
          * Make first packet the current one.
          */
         goToNextPacket();
     }
 
+    /**
+     * Dispose the StreamInputReader
+     *
+     * @since 3.0
+     */
+    @Override
+    public void close() {
+        fPacketReader.close();
+    }
+
     // ------------------------------------------------------------------------
     // Getters/Setters/Predicates
     // ------------------------------------------------------------------------
 
+    /**
+     * Gets the current event in this stream
+     *
+     * @return the current event in the stream, null if the stream is
+     *         finished/empty/malformed
+     */
     public EventDefinition getCurrentEvent() {
-        return this.currentEvent;
-    }
-
-    public StructDefinition getCurrentPacketContext() {
-        return this.packetReader.getStreamPacketContextDef();
+        return fCurrentEvent;
     }
 
+    /**
+     * Gets the byte order for a trace
+     *
+     * @return the trace byte order
+     */
     public ByteOrder getByteOrder() {
-        return streamInput.getStream().getTrace().getByteOrder();
+        return fStreamInput.getStream().getTrace().getByteOrder();
     }
 
+    /**
+     * Gets the name of the stream (it's an id and a number)
+     *
+     * @return gets the stream name (it's a number)
+     */
     public int getName() {
-        return this.name;
+        return fId;
     }
 
+    /**
+     * Sets the name of the stream
+     *
+     * @param name
+     *            the name of the stream, (it's a number)
+     */
     public void setName(int name) {
-        this.name = name;
+        fId = name;
     }
 
+    /**
+     * Gets the CPU of a stream. It's the same as the one in /proc or running
+     * the asm CPUID instruction
+     *
+     * @return The CPU id (a number)
+     */
     public int getCPU() {
-        return this.packetReader.getCPU();
+        return fPacketReader.getCPU();
     }
 
+    /**
+     * Gets the filename of the stream being read
+     *
+     * @return The filename of the stream being read
+     */
     public String getFilename() {
-        return streamInput.getFilename();
+        return fStreamInput.getFilename();
     }
 
     /*
      * for internal use only
      */
     StreamInput getStreamInput() {
-        return streamInput;
+        return fStreamInput;
+    }
+
+    /**
+     * Set the trace to live mode
+     *
+     * @param live
+     *            whether the trace is read live or not
+     * @since 3.0
+     */
+    public void setLive(boolean live) {
+        fLive = live;
+    }
+
+    /**
+     * Get if the trace is to read live or not
+     *
+     * @return whether the trace is live or not
+     * @since 3.0
+     */
+    public boolean isLive() {
+        return fLive;
+    }
+
+    /**
+     * Get the event context of the stream
+     *
+     * @return the event context declaration of the stream
+     * @since 3.0
+     */
+    public StructDeclaration getStreamEventContextDecl() {
+        return getStreamInput().getStream().getEventContextDecl();
     }
 
     // ------------------------------------------------------------------------
@@ -125,70 +203,108 @@ public class StreamInputReader {
      * Reads the next event in the current event variable.
      *
      * @return If an event has been successfully read.
+     * @throws CTFReaderException
+     *             if an error occurs
+     * @since 3.0
      */
-    public boolean readNextEvent() {
+    public CTFResponse readNextEvent() throws CTFReaderException {
+
         /*
          * Change packet if needed
          */
-        if (!this.packetReader.hasMoreEvents()) {
-            goToNextPacket();
+        if (!fPacketReader.hasMoreEvents()) {
+            final StreamInputPacketIndexEntry prevPacket = fPacketReader
+                    .getCurrentPacket();
+            if (prevPacket != null || fLive) {
+                goToNextPacket();
+            }
+
         }
 
         /*
          * If an event is available, read it.
          */
-        if (this.packetReader.hasMoreEvents()) {
-            try {
-                this.setCurrentEvent(this.packetReader.readNextEvent());
-            } catch (CTFReaderException e) {
-                /* Some problem happened, we'll assume there is no more events */
-                return false;
-            }
-            return true;
+        if (fPacketReader.hasMoreEvents()) {
+            setCurrentEvent(fPacketReader.readNextEvent());
+            return CTFResponse.OK;
         }
         this.setCurrentEvent(null);
-        return false;
+        return fLive ? CTFResponse.WAIT : CTFResponse.FINISH;
     }
 
     /**
      * Change the current packet of the packet reader to the next one.
+     *
+     * @throws CTFReaderException
+     *             if an error occurs
      */
-    private void goToNextPacket() {
-        if (getPacketIndexIt().hasNext()) {
-            StreamInputPacketIndexEntry nextPacket = getPacketIndexIt().next();
-            this.packetReader.setCurrentPacket(nextPacket);
+    private void goToNextPacket() throws CTFReaderException {
+        fPacketIndex++;
+        // did we already index the packet?
+        if (getPacketSize() >= (fPacketIndex + 1)) {
+            fPacketReader.setCurrentPacket(getPacket());
         } else {
-            this.packetReader.setCurrentPacket(null);
+            // go to the next packet if there is one, index it at the same time
+            if (fStreamInput.addPacketHeaderIndex()) {
+                fPacketIndex = getPacketSize() - 1;
+                fPacketReader.setCurrentPacket(getPacket());
+            } else {
+                // out of packets
+                fPacketReader.setCurrentPacket(null);
+            }
         }
     }
 
+    /**
+     * @return
+     */
+    private int getPacketSize() {
+        return fStreamInput.getIndex().getEntries().size();
+    }
+
     /**
      * Changes the location of the trace file reader so that the current event
-     * is the first event with a timestamp greater than the given timestamp.
+     * is the first event with a timestamp greater or equal the given timestamp.
      *
      * @param timestamp
      *            The timestamp to seek to.
+     * @return The offset compared to the current position
+     * @throws CTFReaderException
+     *             if an error occurs
      */
-    public long seek(long timestamp) {
+    public long seek(long timestamp) throws CTFReaderException {
         long offset = 0;
-        /*
-         * Search in the index for the packet to search in.
-         */
-        this.packetIndexIt = this.streamInput.getIndex().search(timestamp);
+
+        gotoPacket(timestamp);
 
         /*
-         * Switch to this packet.
+         * index up to the desired timestamp.
          */
-        goToNextPacket();
+        while ((fPacketReader.getCurrentPacket() != null)
+                && (fPacketReader.getCurrentPacket().getTimestampEnd() < timestamp)) {
+            try {
+                fStreamInput.addPacketHeaderIndex();
+                goToNextPacket();
+            } catch (CTFReaderException e) {
+                // do nothing here
+            }
+        }
+        if (fPacketReader.getCurrentPacket() == null) {
+            gotoPacket(timestamp);
+        }
 
         /*
-         * Advance until A. we reached the end of the trace file (which means
-         * the given timestamp is after the last event), or B. we found the
-         * first event with a timestamp greater than the given timestamp.
+         * Advance until either of these conditions are met:
+         *
+         * - reached the end of the trace file (the given timestamp is after the
+         * last event)
+         *
+         * - found the first event with a timestamp greater or equal the given
+         * timestamp.
          */
         readNextEvent();
         boolean done = (this.getCurrentEvent() == null);
-        while (!done && (this.getCurrentEvent().timestamp < timestamp)) {
+        while (!done && (this.getCurrentEvent().getTimestamp() < timestamp)) {
             readNextEvent();
             done = (this.getCurrentEvent() == null);
             offset++;
@@ -196,103 +312,124 @@ public class StreamInputReader {
         return offset;
     }
 
-    public long seekIndex(long index) throws CTFReaderException {
+    /**
+     * @param timestamp
+     *            the time to seek
+     * @throws CTFReaderException
+     *             if an error occurs
+     */
+    private void gotoPacket(long timestamp) throws CTFReaderException {
+        fPacketIndex = fStreamInput.getIndex().search(timestamp)
+                .previousIndex();
         /*
-         * we need to check if a trace is empty too.
+         * Switch to this packet.
          */
-        StreamInputPacketIndexEntry sipie = null;
+        goToNextPacket();
+    }
+
+    /**
+     * Seeks the last event of a stream and returns it.
+     *
+     * @throws CTFReaderException
+     *             if an error occurs
+     */
+    public void goToLastEvent() throws CTFReaderException {
         /*
          * Search in the index for the packet to search in.
          */
-        this.packetIndexIt = this.streamInput.getIndex().searchIndex(index);
+        final int len = fStreamInput.getIndex().getEntries().size();
+
         /*
-         * Switch to this packet.
+         * Go to beginning of trace.
          */
-        goToNextPacket();
-
-        sipie = this.packetReader.getCurrentPacket();
+        seek(0);
         /*
-         * Read the first packet
+         * if the trace is empty.
          */
-        readNextEvent();
+        if ((len == 0) || (fPacketReader.hasMoreEvents() == false)) {
+            /*
+             * This means the trace is empty. abort.
+             */
+            return;
+        }
         /*
-         * get the current index
+         * Go to the last packet that contains events.
          */
-        if (this.packetReader.getCurrentPacket() == null)  {
-            if( !((sipie.getIndexBegin() == 0) && (sipie.getIndexEnd() == Long.MAX_VALUE))) {
-                throw new CTFReaderException(
-                        "Current packet null in index seek, did you index your trace yet?"); //$NON-NLS-1$
+        for (int pos = len - 1; pos > 0; pos--) {
+            fPacketIndex = pos;
+            fPacketReader.setCurrentPacket(getPacket());
+            if (fPacketReader.hasMoreEvents()) {
+                break;
             }
-            return 0;
         }
-        return this.packetReader.getCurrentPacket().getIndexBegin();
 
-    }
-
-    public void goToLastEvent() throws CTFReaderException {
         /*
-         * Search in the index for the packet to search in.
+         * Go until the end of that packet
          */
-        int len = this.streamInput.getIndex().getEntries().size();
-        int back = 0;
-        long desired_timestamp = -1;
-        do {
-            back++;
-            StreamInputPacketIndexEntry entry = this.streamInput.getIndex()
-                    .getEntries().get(len - back);
-            desired_timestamp = entry.getTimestampBegin() + 1;
-            seek(desired_timestamp);
-
-        } while (!this.packetReader.hasMoreEvents());
+        EventDefinition prevEvent = null;
+        while (fCurrentEvent != null) {
+            prevEvent = fCurrentEvent;
+            this.readNextEvent();
+        }
         /*
-         * Go until the end of that packet
+         * Go back to the previous event
          */
+        this.setCurrentEvent(prevEvent);
+    }
 
-        int packet_size = 0;
-        while (this.packetReader.hasMoreEvents()) {
-            this.packetReader.readNextEvent();
-            packet_size++;
-        }
-        seek(desired_timestamp);
-        for (int i = 0; i < (packet_size - 1); i++) {
-            this.packetReader.readNextEvent();
-        }
+    /**
+     * @return the parent
+     */
+    public CTFTraceReader getParent() {
+        return fParent;
     }
 
+    /**
+     * @param parent
+     *            the parent to set
+     */
+    public void setParent(CTFTraceReader parent) {
+        fParent = parent;
+    }
+
+    /**
+     * Sets the current event in a stream input reader
+     *
+     * @param currentEvent
+     *            the event to set
+     */
     public void setCurrentEvent(EventDefinition currentEvent) {
-        this.currentEvent = currentEvent;
+        fCurrentEvent = currentEvent;
     }
 
     /**
      * @return the packetIndexIt
      */
-    private ListIterator<StreamInputPacketIndexEntry> getPacketIndexIt() {
-        return packetIndexIt;
+    private int getPacketIndex() {
+        return fPacketIndex;
+    }
+
+    private StreamInputPacketIndexEntry getPacket() {
+        return fStreamInput.getIndex().getEntries().get(getPacketIndex());
     }
 
     /**
      * @return the packetReader
      */
     public StreamInputPacketReader getPacketReader() {
-        return packetReader;
+        return fPacketReader;
     }
 
-    /* (non-Javadoc)
-     * @see java.lang.Object#hashCode()
-     */
     @Override
     public int hashCode() {
         final int prime = 31;
         int result = 1;
-        result = (prime * result) + name;
+        result = (prime * result) + fId;
         result = (prime * result)
-                + ((streamInput == null) ? 0 : streamInput.hashCode());
+                + ((fStreamInput == null) ? 0 : fStreamInput.hashCode());
         return result;
     }
 
-    /* (non-Javadoc)
-     * @see java.lang.Object#equals(java.lang.Object)
-     */
     @Override
     public boolean equals(Object obj) {
         if (this == obj) {
@@ -305,17 +442,22 @@ public class StreamInputReader {
             return false;
         }
         StreamInputReader other = (StreamInputReader) obj;
-        if (name != other.name) {
+        if (fId != other.fId) {
             return false;
         }
-        if (streamInput == null) {
-            if (other.streamInput != null) {
+        if (fStreamInput == null) {
+            if (other.fStreamInput != null) {
                 return false;
             }
-        } else if (!streamInput.equals(other.streamInput)) {
+        } else if (!fStreamInput.equals(other.fStreamInput)) {
             return false;
         }
         return true;
     }
 
+    @Override
+    public String toString() {
+        // this helps debugging
+        return fId + ' ' + fCurrentEvent.toString();
+    }
 }
This page took 0.030506 seconds and 5 git commands to generate.