ctf: better enum and variant verification
[deliverable/tracecompass.git] / org.eclipse.linuxtools.ctf.core / src / org / eclipse / linuxtools / ctf / core / trace / StreamInputPacketReader.java
index 53e410605edd4612557065f833b907a5e417904d..f0a5d46bbf21d8d5d7dbfd7eaa6fabe6f4f71702 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2011-2012 Ericsson, Ecole Polytechnique de Montreal and others
+ * Copyright (c) 2011-2013 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
@@ -15,47 +15,55 @@ import java.io.IOException;
 import java.nio.MappedByteBuffer;
 import java.nio.channels.FileChannel.MapMode;
 import java.util.Collection;
-import java.util.HashMap;
 
-import org.eclipse.linuxtools.ctf.core.event.EventDeclaration;
+import org.eclipse.linuxtools.ctf.core.CTFStrings;
 import org.eclipse.linuxtools.ctf.core.event.EventDefinition;
+import org.eclipse.linuxtools.ctf.core.event.IEventDeclaration;
+import org.eclipse.linuxtools.ctf.core.event.io.BitBuffer;
 import org.eclipse.linuxtools.ctf.core.event.types.Definition;
-import org.eclipse.linuxtools.ctf.core.event.types.EnumDefinition;
 import org.eclipse.linuxtools.ctf.core.event.types.IDefinitionScope;
 import org.eclipse.linuxtools.ctf.core.event.types.IntegerDefinition;
+import org.eclipse.linuxtools.ctf.core.event.types.SimpleDatatypeDefinition;
 import org.eclipse.linuxtools.ctf.core.event.types.StructDeclaration;
 import org.eclipse.linuxtools.ctf.core.event.types.StructDefinition;
 import org.eclipse.linuxtools.ctf.core.event.types.VariantDefinition;
-import org.eclipse.linuxtools.internal.ctf.core.event.io.BitBuffer;
-import org.eclipse.linuxtools.internal.ctf.core.trace.Stream;
+import org.eclipse.linuxtools.internal.ctf.core.event.EventDeclaration;
 import org.eclipse.linuxtools.internal.ctf.core.trace.StreamInputPacketIndexEntry;
 
 /**
- * <b><u>StreamInputPacketReader</u></b>
- * <p>
- * Reads the events of a packet of a trace file.
+ * CTF trace packet reader. Reads the events of a packet of a trace file.
+ *
+ * @version 1.0
+ * @author Matthew Khouzam
+ * @author Simon Marchi
  */
-class StreamInputPacketReader implements IDefinitionScope {
+public class StreamInputPacketReader implements IDefinitionScope {
 
     // ------------------------------------------------------------------------
-    // Constants
+    // Attributes
     // ------------------------------------------------------------------------
 
-    /**
-     * Reference to the index entry of the current packet.
-     */
-    private StreamInputPacketIndexEntry currentPacket = null;
-
-    /**
-     * BitBuffer used to read the trace file.
-     */
-    private final BitBuffer bitBuffer = new BitBuffer();
+    /** BitBuffer used to read the trace file. */
+    private final BitBuffer bitBuffer;
 
-    /**
-     * StreamInputReader that uses this StreamInputPacketReader.
-     */
+    /** StreamInputReader that uses this StreamInputPacketReader. */
     private final StreamInputReader streamInputReader;
 
+    /** Trace packet header. */
+    private final StructDefinition tracePacketHeaderDef;
+
+    /** Stream packet context definition. */
+    private final StructDefinition streamPacketContextDef;
+
+    /** Stream event header definition. */
+    private final StructDefinition streamEventHeaderDef;
+
+    /** Stream event context definition. */
+    private final StructDefinition streamEventContextDef;
+
+    /** Reference to the index entry of the current packet. */
+    private StreamInputPacketIndexEntry currentPacket = null;
+
     /**
      * Last timestamp recorded.
      *
@@ -64,38 +72,17 @@ class StreamInputPacketReader implements IDefinitionScope {
      */
     private long lastTimestamp = 0;
 
-    /**
-     * Trace packet header.
-     */
-    private StructDefinition tracePacketHeaderDef = null;
-
-    /**
-     * Stream packet context definition.
-     */
-    private StructDefinition streamPacketContextDef = null;
-
-    /**
-     * Stream event header definition.
-     */
-    private StructDefinition streamEventHeaderDef = null;
+    /** CPU id of current packet. */
+    private int currentCpu = 0;
 
-    /**
-     * Stream event context definition.
-     */
-    private StructDefinition streamEventContextDef = null;
+    private int lostEventsInThisPacket;
 
-    /**
-     * Maps event ID to event definitions.
-     */
-    private final HashMap<Long, EventDefinition> events = new HashMap<Long, EventDefinition>();
+    private long lostEventsDuration;
 
-    /**
-     * CPU id of current packet.
-     */
-    private int currentCpu = 0;
+    private boolean hasLost = false;
 
     // ------------------------------------------------------------------------
-    // Attributes
+    // Constructors
     // ------------------------------------------------------------------------
 
     /**
@@ -107,35 +94,99 @@ class StreamInputPacketReader implements IDefinitionScope {
     public StreamInputPacketReader(StreamInputReader streamInputReader) {
         this.streamInputReader = streamInputReader;
 
-        /*
-         * Set the BitBuffer's byte order.
-         */
-        getBitBuffer().setByteOrder(streamInputReader.getByteOrder());
+        /* Set the BitBuffer's byte order. */
+        bitBuffer = new BitBuffer();
+        bitBuffer.setByteOrder(streamInputReader.getByteOrder());
 
-        /*
-         * Create definitions needed to read the events.
-         */
-        createDefinitions();
+        /* Create trace packet header definition. */
+        final Stream currentStream = streamInputReader.getStreamInput().getStream();
+        StructDeclaration tracePacketHeaderDecl = currentStream.getTrace().getPacketHeader();
+        if (tracePacketHeaderDecl != null) {
+            tracePacketHeaderDef = tracePacketHeaderDecl.createDefinition(this, "trace.packet.header"); //$NON-NLS-1$
+        } else {
+            tracePacketHeaderDef = null;
+        }
+
+        /* Create stream packet context definition. */
+        StructDeclaration streamPacketContextDecl = currentStream.getPacketContextDecl();
+        if (streamPacketContextDecl != null) {
+            streamPacketContextDef = streamPacketContextDecl.createDefinition(this, "stream.packet.context"); //$NON-NLS-1$
+        } else {
+            streamPacketContextDef = null;
+        }
+
+        /* Create stream event header definition. */
+        StructDeclaration streamEventHeaderDecl = currentStream.getEventHeaderDecl();
+        if (streamEventHeaderDecl != null) {
+            streamEventHeaderDef = streamEventHeaderDecl.createDefinition(this, "stream.event.header"); //$NON-NLS-1$
+        } else {
+            streamEventHeaderDef = null;
+        }
+
+        /* Create stream event context definition. */
+        StructDeclaration streamEventContextDecl = currentStream.getEventContextDecl();
+        if (streamEventContextDecl != null) {
+            streamEventContextDef = streamEventContextDecl.createDefinition(this, "stream.event.context"); //$NON-NLS-1$
+        } else {
+            streamEventContextDef = null;
+        }
+
+        /* Create event definitions */
+        Collection<IEventDeclaration> eventDecls = streamInputReader.getStreamInput().getStream().getEvents().values();
+
+        for (IEventDeclaration event : eventDecls) {
+            if (!streamInputReader.getEventDefinitions().containsKey(event.getId())) {
+                EventDefinition eventDef = event.createDefinition(streamInputReader);
+                streamInputReader.addEventDefinition(event.getId(), eventDef);
+            }
+        }
     }
 
-    // ------------------------------------------------------------------------
-    // Constructors
-    // ------------------------------------------------------------------------
+    /**
+     * Dispose the StreamInputPacketReader
+     *
+     * @since 2.0
+     */
+    public void dispose() {
+        bitBuffer.setByteBuffer(null);
+    }
 
     // ------------------------------------------------------------------------
     // Getters/Setters/Predicates
     // ------------------------------------------------------------------------
 
-    /* Getters, setters and stuff. */
-
-    public StreamInputPacketIndexEntry getCurrentPacket() {
+    /**
+     * Gets the current packet
+     *
+     * @return the current packet
+     */
+    StreamInputPacketIndexEntry getCurrentPacket() {
         return this.currentPacket;
     }
 
+    /**
+     * Gets the steamPacketContext Definition
+     *
+     * @return steamPacketContext Definition
+     */
     public StructDefinition getStreamPacketContextDef() {
         return this.streamPacketContextDef;
     }
 
+    /**
+     * Gets the stream's event context definition.
+     *
+     * @return The streamEventContext definition
+     */
+    public StructDefinition getStreamEventContextDef() {
+        return streamEventContextDef;
+    }
+
+    /**
+     * Gets the CPU (core) number
+     *
+     * @return the CPU (core) number
+     */
     public int getCPU() {
         return this.currentCpu;
     }
@@ -149,74 +200,16 @@ class StreamInputPacketReader implements IDefinitionScope {
     // Operations
     // ------------------------------------------------------------------------
 
-    /**
-     * Creates definitions needed to read events (stream-defined and
-     * event-defined).
-     */
-    private void createDefinitions() {
-        /*
-         * Create trace packet header definition.
-         */
-        final Stream currentStream = getStreamInputReader().getStreamInput().getStream();
-        StructDeclaration tracePacketHeaderDecl = currentStream.getTrace().getPacketHeader();
-        if (tracePacketHeaderDecl != null) {
-            setTracePacketHeaderDef(tracePacketHeaderDecl.createDefinition(this,
-                    "trace.packet.header")); //$NON-NLS-1$
-        }
-
-        /*
-         * Create stream packet context definition.
-         */
-        StructDeclaration streamPacketContextDecl = currentStream.getPacketContextDecl();
-        if (streamPacketContextDecl != null) {
-            setStreamPacketContextDef(streamPacketContextDecl.createDefinition(
-                    this, "stream.packet.context")); //$NON-NLS-1$
-        }
-
-        /*
-         * Create stream event header definition.
-         */
-        StructDeclaration streamEventHeaderDecl = currentStream.getEventHeaderDecl();
-        if (streamEventHeaderDecl != null) {
-            setStreamEventHeaderDef(streamEventHeaderDecl.createDefinition(this,
-                    "stream.event.header")); //$NON-NLS-1$
-        }
-
-        /*
-         * Create stream event context definition.
-         */
-        StructDeclaration streamEventContextDecl = currentStream.getEventContextDecl();
-        if (streamEventContextDecl != null) {
-            setStreamEventContextDef(streamEventContextDecl.createDefinition(
-                    this, "stream.event.context")); //$NON-NLS-1$
-        }
-
-        createEventDefinitions();
-    }
-
-    /**
-     * Creates definitions needed to read the event. (event-defined).
-     */
-    private void createEventDefinitions() {
-        Collection<EventDeclaration> eventDecls = getStreamInputReader().getStreamInput().getStream().getEvents().values();
-
-        /*
-         * Create definitions for each event.
-         */
-        for (EventDeclaration event : eventDecls) {
-            EventDefinition eventDef = event.createDefinition(getStreamInputReader());
-
-            events.put(event.getId(), eventDef);
-        }
-    }
-
     /**
      * Changes the current packet to the given one.
      *
      * @param currentPacket
      *            The index entry of the packet to switch to.
+     * @throws CTFReaderException
+     *             If we get an error reading the packet
      */
-    public void setCurrentPacket(StreamInputPacketIndexEntry currentPacket) {
+    void setCurrentPacket(StreamInputPacketIndexEntry currentPacket) throws CTFReaderException {
+        StreamInputPacketIndexEntry prevPacket = null;
         this.currentPacket = currentPacket;
 
         if (this.currentPacket != null) {
@@ -225,34 +218,52 @@ class StreamInputPacketReader implements IDefinitionScope {
              */
             MappedByteBuffer bb = null;
             try {
-                bb = getStreamInputReader().getStreamInput().getFileChannel().map(
-                        MapMode.READ_ONLY, this.currentPacket.getOffsetBytes(),
-                        (this.currentPacket.getPacketSizeBits() + 7) / 8);
+                bb = streamInputReader.getStreamInput().getFileChannel()
+                        .map(MapMode.READ_ONLY,
+                                this.currentPacket.getOffsetBytes(),
+                                (this.currentPacket.getPacketSizeBits() + 7) / 8);
             } catch (IOException e) {
-                /*
-                 * The streamInputReader object is already allocated, so this
-                 * shouldn't fail bar some very bad kernel or RAM errors...
-                 */
-                e.printStackTrace();
+                throw new CTFReaderException(e.getMessage(), e);
             }
 
-            getBitBuffer().setByteBuffer(bb);
+            bitBuffer.setByteBuffer(bb);
 
             /*
              * Read trace packet header.
              */
-            if (getTracePacketHeaderDef() != null) {
-                getTracePacketHeaderDef().read(getBitBuffer());
+            if (tracePacketHeaderDef != null) {
+                tracePacketHeaderDef.read(bitBuffer);
             }
 
             /*
              * Read stream packet context.
              */
             if (getStreamPacketContextDef() != null) {
-                getStreamPacketContextDef().read(getBitBuffer());
-                Definition cpuiddef = getStreamPacketContextDef().lookupDefinition("cpu_id"); //$NON-NLS-1$
-                if (cpuiddef instanceof IntegerDefinition) {
-                    currentCpu = (int) ((IntegerDefinition) cpuiddef).getValue();
+                getStreamPacketContextDef().read(bitBuffer);
+
+                /* Read CPU ID */
+                if (this.getCurrentPacket().getTarget() != null) {
+                    this.currentCpu = (int) this.getCurrentPacket().getTargetId();
+                }
+
+                /* Read number of lost events */
+                lostEventsInThisPacket = (int) this.getCurrentPacket().getLostEvents();
+                if (lostEventsInThisPacket != 0) {
+                    hasLost = true;
+                    /*
+                     * Compute the duration of the lost event time range. If the
+                     * current packet is the first packet, duration will be set
+                     * to 1.
+                     */
+                    long lostEventsStartTime;
+                    int index = this.streamInputReader.getStreamInput().getIndex().getEntries().indexOf(currentPacket);
+                    if (index == 0) {
+                        lostEventsStartTime = currentPacket.getTimestampBegin() + 1;
+                    } else {
+                        prevPacket = this.streamInputReader.getStreamInput().getIndex().getEntries().get(index - 1);
+                        lostEventsStartTime = prevPacket.getTimestampEnd();
+                    }
+                    lostEventsDuration = Math.abs(lostEventsStartTime - currentPacket.getTimestampBegin());
                 }
             }
 
@@ -262,7 +273,7 @@ class StreamInputPacketReader implements IDefinitionScope {
              */
             lastTimestamp = currentPacket.getTimestampBegin();
         } else {
-            getBitBuffer().setByteBuffer(null);
+            bitBuffer.setByteBuffer(null);
 
             lastTimestamp = 0;
         }
@@ -275,7 +286,7 @@ class StreamInputPacketReader implements IDefinitionScope {
      */
     public boolean hasMoreEvents() {
         if (currentPacket != null) {
-            return getBitBuffer().position() < currentPacket.getContentSizeBits();
+            return hasLost || (bitBuffer.position() < currentPacket.getContentSizeBits());
         }
         return false;
     }
@@ -286,95 +297,102 @@ class StreamInputPacketReader implements IDefinitionScope {
      * @return The event definition containing the event data that was just
      *         read.
      * @throws CTFReaderException
+     *             If there was a problem reading the trace
      */
     public EventDefinition readNextEvent() throws CTFReaderException {
-        /* WARNING: This is very LTTng-specific. */
-
-        Long eventID = null;
+        /* Default values for those fields */
+        long eventID = EventDeclaration.UNSET_EVENT_ID;
         long timestamp = 0;
+        if (hasLost) {
+            hasLost = false;
+            EventDefinition eventDef = EventDeclaration.getLostEventDeclaration().createDefinition(streamInputReader);
+            ((IntegerDefinition) eventDef.getFields().getDefinitions().get(CTFStrings.LOST_EVENTS_FIELD)).setValue(lostEventsInThisPacket);
+            ((IntegerDefinition) eventDef.getFields().getDefinitions().get(CTFStrings.LOST_EVENTS_DURATION)).setValue(lostEventsDuration);
+            eventDef.setTimestamp(this.lastTimestamp);
+            return eventDef;
+        }
 
-        /*
-         * Read thestream event header.
-         */
-        if (getStreamEventHeaderDef() != null) {
-            getStreamEventHeaderDef().read(getBitBuffer());
+        final StructDefinition sehd = streamEventHeaderDef;
+        final BitBuffer currentBitBuffer = bitBuffer;
+        final long posStart = currentBitBuffer.position();
+        /* Read the stream event header. */
+        if (sehd != null) {
+            sehd.read(currentBitBuffer);
+
+            /* Check for the event id. */
+            Definition idDef = sehd.lookupDefinition("id"); //$NON-NLS-1$
+            if (idDef instanceof SimpleDatatypeDefinition) {
+                eventID = ((SimpleDatatypeDefinition) idDef).getIntegerValue();
+            } else if (idDef != null) {
+                throw new CTFReaderException("Incorrect event id : " + eventID); //$NON-NLS-1$
+            }
 
             /*
-             * Check for an event id.
+             * Get the timestamp from the event header (may be overridden later
+             * on)
              */
-            EnumDefinition idEnumDef = (EnumDefinition) getStreamEventHeaderDef().lookupDefinition("id"); //$NON-NLS-1$
-            assert (idEnumDef != null);
-
-            eventID = idEnumDef.getIntegerValue();
+            IntegerDefinition timestampDef = sehd.lookupInteger("timestamp"); //$NON-NLS-1$
+            if (timestampDef != null) {
+                timestamp = calculateTimestamp(timestampDef);
+            } // else timestamp remains 0
 
-            /*
-             * Check for the variant v.
-             */
-            VariantDefinition variantDef = (VariantDefinition) getStreamEventHeaderDef().lookupDefinition("v"); //$NON-NLS-1$
-            assert (variantDef != null);
+            /* Check for the variant v. */
+            Definition variantDef = sehd.lookupDefinition("v"); //$NON-NLS-1$
+            if (variantDef instanceof VariantDefinition) {
 
-            /*
-             * Get the variant current field
-             */
-            StructDefinition variantCurrentField = (StructDefinition) variantDef.getCurrentField();
-            assert (variantCurrentField != null);
+                /* Get the variant current field */
+                StructDefinition variantCurrentField = (StructDefinition) ((VariantDefinition) variantDef).getCurrentField();
 
-            /*
-             * Try to get the id field in the current field of the variant. If
-             * it is present, it overrides the previously read event id.
-             */
-            IntegerDefinition idIntegerDef = (IntegerDefinition) variantCurrentField.lookupDefinition("id"); //$NON-NLS-1$
-            if (idIntegerDef != null) {
-                eventID = idIntegerDef.getValue();
+                /*
+                 * Try to get the id field in the current field of the variant.
+                 * If it is present, it overrides the previously read event id.
+                 */
+                Definition idIntegerDef = variantCurrentField.lookupDefinition("id"); //$NON-NLS-1$
+                if (idIntegerDef instanceof IntegerDefinition) {
+                    eventID = ((IntegerDefinition) idIntegerDef).getValue();
+                }
 
+                /*
+                 * Get the timestamp. This would overwrite any previous
+                 * timestamp definition
+                 */
+                Definition def = variantCurrentField.lookupDefinition("timestamp"); //$NON-NLS-1$
+                if (def instanceof IntegerDefinition) {
+                    timestamp = calculateTimestamp((IntegerDefinition) def);
+                }
             }
-
-            /*
-             * Get the timestamp.
-             */
-            IntegerDefinition timestampDef = (IntegerDefinition) variantCurrentField.lookupDefinition("timestamp"); //$NON-NLS-1$
-            assert (timestampDef != null);
-
-            /*
-             * Calculate the event timestamp.
-             */
-            timestamp = calculateTimestamp(timestampDef);
         }
 
-        /*
-         * Read the stream event context.
-         */
-        if (getStreamEventContextDef() != null) {
-            getStreamEventContextDef().read(getBitBuffer());
+        /* Read the stream event context. */
+        if (streamEventContextDef != null) {
+            streamEventContextDef.read(currentBitBuffer);
         }
 
-        /*
-         * Get the right event definition using the event id.
-         */
-        EventDefinition eventDef = events.get(eventID);
+        /* Get the right event definition using the event id. */
+        EventDefinition eventDef = streamInputReader.getEventDefinitions().get(eventID);
         if (eventDef == null) {
             throw new CTFReaderException("Incorrect event id : " + eventID); //$NON-NLS-1$
         }
 
-        /*
-         * Read the event context.
-         */
-        if (eventDef.context != null) {
-            eventDef.context.read(getBitBuffer());
+        /* Read the event context. */
+        if (eventDef.getEventContext() != null) {
+            eventDef.getEventContext().read(currentBitBuffer);
         }
 
-        /*
-         * Read the event fields.
-         */
-        if (eventDef.fields != null) {
-            eventDef.fields.read(getBitBuffer());
+        /* Read the event fields. */
+        if (eventDef.getFields() != null) {
+            eventDef.getFields().read(currentBitBuffer);
         }
 
         /*
          * Set the event timestamp using the timestamp calculated by
          * updateTimestamp.
          */
-        eventDef.timestamp = timestamp;
+        eventDef.setTimestamp(timestamp);
+
+        if (posStart == currentBitBuffer.position()) {
+            throw new CTFReaderException("Empty event not allowed, event: " + eventDef.getDeclaration().getName()); //$NON-NLS-1$
+        }
 
         return eventDef;
     }
@@ -425,43 +443,6 @@ class StreamInputPacketReader implements IDefinitionScope {
 
     @Override
     public Definition lookupDefinition(String lookupPath) {
-        // TODO Auto-generated method stub
         return null;
     }
-
-    public StructDefinition getStreamEventContextDef() {
-        return this.streamEventContextDef;
-    }
-
-    public void setStreamEventContextDef(StructDefinition streamEventContextDef) {
-        this.streamEventContextDef = streamEventContextDef;
-    }
-
-    public StructDefinition getStreamEventHeaderDef() {
-        return this.streamEventHeaderDef;
-    }
-
-    public void setStreamEventHeaderDef(StructDefinition streamEventHeaderDef) {
-        this.streamEventHeaderDef = streamEventHeaderDef;
-    }
-
-    public void setStreamPacketContextDef(StructDefinition streamPacketContextDef) {
-        this.streamPacketContextDef = streamPacketContextDef;
-    }
-
-    public StructDefinition getTracePacketHeaderDef() {
-        return this.tracePacketHeaderDef;
-    }
-
-    public void setTracePacketHeaderDef(StructDefinition tracePacketHeaderDef) {
-        this.tracePacketHeaderDef = tracePacketHeaderDef;
-    }
-
-    public StreamInputReader getStreamInputReader() {
-        return this.streamInputReader;
-    }
-
-    public BitBuffer getBitBuffer() {
-        return bitBuffer;
-    }
 }
This page took 0.03322 seconds and 5 git commands to generate.