src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java
changeset 50113 caf115bb98ad
child 52850 f527b24990d7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java	Tue May 15 20:24:34 2018 +0200
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.consumer;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+import jdk.jfr.internal.LogLevel;
+import jdk.jfr.internal.LogTag;
+import jdk.jfr.internal.Logger;
+import jdk.jfr.internal.MetadataDescriptor;
+
+public final class ChunkHeader {
+    private static final long METADATA_TYPE_ID = 0;
+    private static final byte[] FILE_MAGIC = { 'F', 'L', 'R', '\0' };
+
+    private final short major;
+    private final short minor;
+    private final long chunkSize;
+    private final long chunkStartTicks;
+    private final long ticksPerSecond;
+    private final long chunkStartNanos;
+    private final long metadataPosition;
+ //   private final long absoluteInitialConstantPoolPosition;
+    private final long absoluteChunkEnd;
+    private final long absoluteEventStart;
+    private final long absoluteChunkStart;
+    private final boolean lastChunk;
+    private final RecordingInput input;
+    private final long durationNanos;
+    private final long id;
+    private long constantPoolPosition;
+
+    public ChunkHeader(RecordingInput input) throws IOException {
+        this(input, 0, 0);
+    }
+
+    private ChunkHeader(RecordingInput input, long absoluteChunkStart, long id) throws IOException {
+        input.position(absoluteChunkStart);
+        if (input.position() >= input.size()) {
+            throw new IOException("Chunk contains no data");
+        }
+        verifyMagic(input);
+        this.input = input;
+        this.id = id;
+        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk " + id);
+        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: startPosition=" + absoluteChunkStart);
+        major = input.readRawShort();
+        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: major=" + major);
+        minor = input.readRawShort();
+        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: minor=" + minor);
+        if (major != 1 && major != 2) {
+            throw new IOException("File version " + major + "." + minor + ". Only Flight Recorder files of version 1.x and 2.x can be read by this JDK.");
+        }
+        chunkSize = input.readRawLong();
+        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: chunkSize=" + chunkSize);
+        this.constantPoolPosition = input.readRawLong();
+        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: constantPoolPosition=" + constantPoolPosition);
+        metadataPosition = input.readRawLong();
+        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: metadataPosition=" + metadataPosition);
+        chunkStartNanos = input.readRawLong(); // nanos since epoch
+        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: startNanos=" + chunkStartNanos);
+        durationNanos = input.readRawLong(); // duration nanos, not used
+        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: durationNanos=" + durationNanos);
+        chunkStartTicks = input.readRawLong();
+        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: startTicks=" + chunkStartTicks);
+        ticksPerSecond = input.readRawLong();
+        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: ticksPerSecond=" + ticksPerSecond);
+        input.readRawInt(); // features, not used
+
+        // set up boundaries
+        this.absoluteChunkStart = absoluteChunkStart;
+        absoluteChunkEnd = absoluteChunkStart + chunkSize;
+        lastChunk = input.size() == absoluteChunkEnd;
+        absoluteEventStart = input.position();
+
+        // read metadata
+        input.position(absoluteEventStart);
+    }
+
+    public ChunkHeader nextHeader() throws IOException {
+        return new ChunkHeader(input, absoluteChunkEnd, id + 1);
+    }
+
+    public MetadataDescriptor readMetadata() throws IOException {
+        input.position(absoluteChunkStart + metadataPosition);
+        input.readInt(); // size
+        long id = input.readLong(); // event type id
+        if (id != METADATA_TYPE_ID) {
+            throw new IOException("Expected metadata event. Type id=" + id + ", should have been " + METADATA_TYPE_ID);
+        }
+        input.readLong(); // start time
+        input.readLong(); // duration
+        long metadataId = input.readLong();
+        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.TRACE, "Metadata id=" + metadataId);
+        // No need to read if metadataId == lastMetadataId, but we
+        // do it for verification purposes.
+        return MetadataDescriptor.read(input);
+    }
+
+    public boolean isLastChunk() {
+        return lastChunk;
+    }
+
+    public short getMajor() {
+        return major;
+    }
+
+    public short getMinor() {
+        return minor;
+    }
+
+    public long getAbsoluteChunkStart() {
+        return absoluteChunkStart;
+    }
+
+    public long getConstantPoolPosition() {
+        return constantPoolPosition;
+    }
+
+    public long getStartTicks() {
+        return chunkStartTicks;
+    }
+
+    public double getTicksPerSecond() {
+        return ticksPerSecond;
+    }
+
+    public long getStartNanos() {
+        return chunkStartNanos;
+    }
+
+    public long getEnd() {
+        return absoluteChunkEnd;
+    }
+
+    public long getSize() {
+        return chunkSize;
+    }
+
+    public long getDuration() {
+        return durationNanos;
+    }
+
+    public RecordingInput getInput() {
+        return input;
+    }
+
+    private static void verifyMagic(DataInput input) throws IOException {
+        for (byte c : FILE_MAGIC) {
+            if (input.readByte() != c) {
+                throw new IOException("Not a Flight Recorder file");
+            }
+        }
+    }
+
+    public long getEventStart() {
+        return absoluteEventStart;
+    }
+
+}