src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInput.java
branchJEP-349-branch
changeset 57360 5d043a159d5c
parent 50113 caf115bb98ad
child 57386 acdd0dbe37ee
equal deleted inserted replaced
57359:4cab5edc2950 57360:5d043a159d5c
     1 /*
     1 /*
     2  * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
    28 import java.io.DataInput;
    28 import java.io.DataInput;
    29 import java.io.EOFException;
    29 import java.io.EOFException;
    30 import java.io.File;
    30 import java.io.File;
    31 import java.io.IOException;
    31 import java.io.IOException;
    32 import java.io.RandomAccessFile;
    32 import java.io.RandomAccessFile;
    33 import java.nio.charset.Charset;
       
    34 
    33 
    35 public final class RecordingInput implements DataInput, AutoCloseable {
    34 public final class RecordingInput implements DataInput, AutoCloseable {
    36 
    35 
    37     public static final byte STRING_ENCODING_NULL = 0;
       
    38     public static final byte STRING_ENCODING_EMPTY_STRING = 1;
       
    39     public static final byte STRING_ENCODING_CONSTANT_POOL = 2;
       
    40     public static final byte STRING_ENCODING_UTF8_BYTE_ARRAY = 3;
       
    41     public static final byte STRING_ENCODING_CHAR_ARRAY = 4;
       
    42     public static final byte STRING_ENCODING_LATIN1_BYTE_ARRAY = 5;
       
    43 
    36 
    44     private final static int DEFAULT_BLOCK_SIZE = 16 * 1024 * 1024;
    37     private final static int DEFAULT_BLOCK_SIZE = 16 * 1024 * 1024;
    45     private final static Charset UTF8 = Charset.forName("UTF-8");
       
    46     private final static Charset LATIN1 = Charset.forName("ISO-8859-1");
       
    47 
    38 
    48     private static final class Block {
    39     private static final class Block {
    49         private byte[] bytes = new byte[0];
    40         private byte[] bytes = new byte[0];
    50         private long blockPosition;
    41         private long blockPosition;
    51 
    42         private int size;
    52         boolean contains(long position) {
    43         boolean contains(long position) {
    53             return position >= blockPosition && position < blockPosition + bytes.length;
    44             return position >= blockPosition && position < blockPosition + size;
    54         }
    45         }
    55 
    46 
    56         public void read(RandomAccessFile file, int amount) throws IOException {
    47         public void read(RandomAccessFile file, int amount) throws IOException {
    57             blockPosition = file.getFilePointer();
    48             blockPosition = file.getFilePointer();
    58             // reuse byte array, if possible
    49             // reuse byte array, if possible
    59             if (amount != bytes.length) {
    50             if (amount > bytes.length) {
    60                 bytes = new byte[amount];
    51                 bytes = new byte[amount];
    61             }
    52             }
    62             file.readFully(bytes);
    53             this.size = amount;
       
    54             file.readFully(bytes, 0 , amount);
    63         }
    55         }
    64 
    56 
    65         public byte get(long position) {
    57         public byte get(long position) {
    66             return bytes[(int) (position - blockPosition)];
    58             return bytes[(int) (position - blockPosition)];
    67         }
    59         }
    68     }
    60     }
    69 
    61 
    70     private final RandomAccessFile file;
    62     private final RandomAccessFile file;
    71     private final long size;
    63     private final String filename;
    72     private Block currentBlock = new Block();
    64     private Block currentBlock = new Block();
    73     private Block previousBlock = new Block();
    65     private Block previousBlock = new Block();
    74     private long position;
    66     private long position;
    75     private final int blockSize;
    67     private final int blockSize;
    76 
    68     private long size = -1; // Fail fast if setSize(...) has not been called before parsing
    77     private RecordingInput(File f, int blockSize) throws IOException {
    69 
    78         this.size = f.length();
    70     public RecordingInput(File f, int blockSize) throws IOException {
    79         this.blockSize = blockSize;
    71         this.blockSize = blockSize;
       
    72         this.filename = f.getAbsolutePath().toString();
    80         this.file = new RandomAccessFile(f, "r");
    73         this.file = new RandomAccessFile(f, "r");
    81         if (size < 8) {
    74         if (f.length() < 8) {
    82             throw new IOException("Not a valid Flight Recorder file. File length is only " + size + " bytes.");
    75             throw new IOException("Not a valid Flight Recorder file. File length is only " + f.length() + " bytes.");
    83         }
    76         }
    84     }
    77     }
    85 
    78 
    86     public RecordingInput(File f) throws IOException {
    79     public RecordingInput(File f) throws IOException {
    87         this(f, DEFAULT_BLOCK_SIZE);
    80         this(f, DEFAULT_BLOCK_SIZE);
       
    81     }
       
    82     public void positionPhysical(long position) throws IOException {
       
    83         file.seek(position);
       
    84     }
       
    85     public final byte readPhysicalByte() throws IOException {
       
    86         return file.readByte();
       
    87     }
       
    88     public long readPhysicalLong() throws IOException {
       
    89         return file.readLong();
    88     }
    90     }
    89 
    91 
    90     @Override
    92     @Override
    91     public final byte readByte() throws IOException {
    93     public final byte readByte() throws IOException {
    92         if (!currentBlock.contains(position)) {
    94         if (!currentBlock.contains(position)) {
   148         byte b6 = readByte();
   150         byte b6 = readByte();
   149         byte b7 = readByte();
   151         byte b7 = readByte();
   150         return ((b7 & 0xFFL)) + ((b6 & 0xFFL) << 8) + ((b5 & 0xFFL) << 16) + ((b4 & 0xFFL) << 24) + ((b3 & 0xFFL) << 32) + ((b2 & 0xFFL) << 40) + ((b1 & 0xFFL) << 48) + (((long) b0) << 56);
   152         return ((b7 & 0xFFL)) + ((b6 & 0xFFL) << 8) + ((b5 & 0xFFL) << 16) + ((b4 & 0xFFL) << 24) + ((b3 & 0xFFL) << 32) + ((b2 & 0xFFL) << 40) + ((b1 & 0xFFL) << 48) + (((long) b0) << 56);
   151     }
   153     }
   152 
   154 
   153     public final long position() throws IOException {
   155     public final long position() {
   154         return position;
   156         return position;
   155     }
   157     }
   156 
   158 
   157     public final void position(long newPosition) throws IOException {
   159     public final void position(long newPosition) throws IOException {
   158         if (!currentBlock.contains(newPosition)) {
   160         if (!currentBlock.contains(newPosition)) {
   159             if (!previousBlock.contains(newPosition)) {
   161             if (!previousBlock.contains(newPosition)) {
   160                 if (newPosition > size()) {
   162                 if (newPosition > size) {
   161                     throw new EOFException("Trying to read at " + newPosition + ", but file is only " + size() + " bytes.");
   163                     throw new EOFException("Trying to read at " + newPosition + ", but file is only " + size + " bytes.");
   162                 }
   164                 }
   163                 long blockStart = trimToFileSize(calculateBlockStart(newPosition));
   165                 long blockStart = trimToFileSize(calculateBlockStart(newPosition));
   164                 file.seek(blockStart);
   166                 file.seek(blockStart);
   165                 // trim amount to file size
   167                 // trim amount to file size
   166                 long amount = Math.min(size() - blockStart, blockSize);
   168                 long amount = Math.min(size - blockStart, blockSize);
   167                 previousBlock.read(file, (int) amount);
   169                 previousBlock.read(file, (int) amount);
   168             }
   170             }
   169             // swap previous and current
   171             // swap previous and current
   170             Block tmp = currentBlock;
   172             Block tmp = currentBlock;
   171             currentBlock = previousBlock;
   173             currentBlock = previousBlock;
   189         }
   191         }
   190         // not near current block, pick middle
   192         // not near current block, pick middle
   191         return newPosition - blockSize / 2;
   193         return newPosition - blockSize / 2;
   192     }
   194     }
   193 
   195 
   194     public final long size() throws IOException {
   196     public final long size() {
   195         return size;
   197         return size;
   196     }
   198     }
   197 
   199 
   198     public final void close() throws IOException {
   200     public final void close() throws IOException {
   199         file.close();
   201         file.close();
   243     // 2, means char array
   245     // 2, means char array
   244     // 3, means latin-1 (ISO-8859-1) encoded byte array
   246     // 3, means latin-1 (ISO-8859-1) encoded byte array
   245     // 4, means ""
   247     // 4, means ""
   246     @Override
   248     @Override
   247     public String readUTF() throws IOException {
   249     public String readUTF() throws IOException {
   248         return readEncodedString(readByte());
   250         throw new UnsupportedOperationException("Use StringParser");
   249     }
       
   250 
       
   251     public String readEncodedString(byte encoding) throws IOException {
       
   252         if (encoding == STRING_ENCODING_NULL) {
       
   253             return null;
       
   254         }
       
   255         if (encoding == STRING_ENCODING_EMPTY_STRING) {
       
   256             return "";
       
   257         }
       
   258         int size = readInt();
       
   259         if (encoding == STRING_ENCODING_CHAR_ARRAY) {
       
   260             char[] c = new char[size];
       
   261             for (int i = 0; i < size; i++) {
       
   262                 c[i] = readChar();
       
   263             }
       
   264             return new String(c);
       
   265         }
       
   266         byte[] bytes = new byte[size];
       
   267         readFully(bytes); // TODO: optimize, check size, and copy only if needed
       
   268         if (encoding == STRING_ENCODING_UTF8_BYTE_ARRAY) {
       
   269             return new String(bytes, UTF8);
       
   270         }
       
   271 
       
   272         if (encoding == STRING_ENCODING_LATIN1_BYTE_ARRAY) {
       
   273             return new String(bytes, LATIN1);
       
   274         }
       
   275         throw new IOException("Unknown string encoding " + encoding);
       
   276     }
   251     }
   277 
   252 
   278     @Override
   253     @Override
   279     public char readChar() throws IOException {
   254     public char readChar() throws IOException {
   280         return (char) readLong();
   255         return (char) readLong();
   334             return ret;
   309             return ret;
   335         }
   310         }
   336         int b8 = readByte(); // read last byte raw
   311         int b8 = readByte(); // read last byte raw
   337         return ret + (((long) (b8 & 0XFF)) << 56);
   312         return ret + (((long) (b8 & 0XFF)) << 56);
   338     }
   313     }
       
   314 
       
   315     public void setValidSize(long size) {
       
   316         if (size > this.size) {
       
   317             this.size = size;
       
   318         }
       
   319     }
       
   320 
       
   321     public long getFileSize() throws IOException {
       
   322         return file.length();
       
   323     }
       
   324 
       
   325     public String getFilename() {
       
   326         return filename;
       
   327     }
       
   328 
   339 }
   329 }