src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInput.java
changeset 58863 c16ac7a2eba4
parent 50113 caf115bb98ad
equal deleted inserted replaced
58861:2c3cc4b01880 58863:c16ac7a2eba4
     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;
    33 import java.nio.file.Path;
    34 
    34 
    35 public final class RecordingInput implements DataInput, AutoCloseable {
    35 public final class RecordingInput implements DataInput, AutoCloseable {
    36 
    36 
    37     public static final byte STRING_ENCODING_NULL = 0;
    37     private final static int DEFAULT_BLOCK_SIZE = 64_000;
    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 
       
    44     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;
       
    42         private long blockPositionEnd;
    51 
    43 
    52         boolean contains(long position) {
    44         boolean contains(long position) {
    53             return position >= blockPosition && position < blockPosition + bytes.length;
    45             return position >= blockPosition && position < blockPositionEnd;
    54         }
    46         }
    55 
    47 
    56         public void read(RandomAccessFile file, int amount) throws IOException {
    48         public void read(RandomAccessFile file, int amount) throws IOException {
    57             blockPosition = file.getFilePointer();
    49             blockPosition = file.getFilePointer();
    58             // reuse byte array, if possible
    50             // reuse byte array, if possible
    59             if (amount != bytes.length) {
    51             if (amount > bytes.length) {
    60                 bytes = new byte[amount];
    52                 bytes = new byte[amount];
    61             }
    53             }
    62             file.readFully(bytes);
    54             this.blockPositionEnd = blockPosition + amount;
       
    55             file.readFully(bytes, 0, amount);
    63         }
    56         }
    64 
    57 
    65         public byte get(long position) {
    58         public byte get(long position) {
    66             return bytes[(int) (position - blockPosition)];
    59             return bytes[(int) (position - blockPosition)];
    67         }
    60         }
    68     }
    61 
    69 
    62         public void reset() {
    70     private final RandomAccessFile file;
    63             blockPosition = 0;
    71     private final long size;
    64             blockPositionEnd = 0;
       
    65         }
       
    66     }
       
    67     private final int blockSize;
       
    68     private final FileAccess fileAccess;
       
    69     private RandomAccessFile file;
       
    70     private String filename;
    72     private Block currentBlock = new Block();
    71     private Block currentBlock = new Block();
    73     private Block previousBlock = new Block();
    72     private Block previousBlock = new Block();
    74     private long position;
    73     private long position;
    75     private final int blockSize;
    74     private long size = -1; // Fail fast if setSize(...) has not been called
    76 
    75                             // before parsing
    77     private RecordingInput(File f, int blockSize) throws IOException {
    76 
    78         this.size = f.length();
    77     RecordingInput(File f, FileAccess fileAccess, int blockSize) throws IOException {
    79         this.blockSize = blockSize;
    78         this.blockSize = blockSize;
    80         this.file = new RandomAccessFile(f, "r");
    79         this.fileAccess = fileAccess;
    81         if (size < 8) {
    80         initialize(f);
    82             throw new IOException("Not a valid Flight Recorder file. File length is only " + size + " bytes.");
    81     }
    83         }
    82 
    84     }
    83     private void initialize(File f) throws IOException {
    85 
    84         this.filename = fileAccess.getAbsolutePath(f);
    86     public RecordingInput(File f) throws IOException {
    85         this.file = fileAccess.openRAF(f, "r");
    87         this(f, DEFAULT_BLOCK_SIZE);
    86         this.position = 0;
       
    87         this.size = -1;
       
    88         this.currentBlock.reset();
       
    89         previousBlock.reset();
       
    90         if (fileAccess.length(f) < 8) {
       
    91             throw new IOException("Not a valid Flight Recorder file. File length is only " + fileAccess.length(f) + " bytes.");
       
    92         }
       
    93     }
       
    94 
       
    95     public RecordingInput(File f, FileAccess fileAccess) throws IOException {
       
    96         this(f, fileAccess, DEFAULT_BLOCK_SIZE);
       
    97     }
       
    98 
       
    99     void positionPhysical(long position) throws IOException {
       
   100         file.seek(position);
       
   101     }
       
   102 
       
   103     byte readPhysicalByte() throws IOException {
       
   104         return file.readByte();
       
   105     }
       
   106 
       
   107     long readPhysicalLong() throws IOException {
       
   108         return file.readLong();
    88     }
   109     }
    89 
   110 
    90     @Override
   111     @Override
    91     public final byte readByte() throws IOException {
   112     public final byte readByte() throws IOException {
    92         if (!currentBlock.contains(position)) {
   113         if (!currentBlock.contains(position)) {
   107     @Override
   128     @Override
   108     public final void readFully(byte[] dst) throws IOException {
   129     public final void readFully(byte[] dst) throws IOException {
   109         readFully(dst, 0, dst.length);
   130         readFully(dst, 0, dst.length);
   110     }
   131     }
   111 
   132 
   112     public final short readRawShort() throws IOException {
   133     short readRawShort() throws IOException {
   113         // copied from java.io.Bits
   134         // copied from java.io.Bits
   114         byte b0 = readByte();
   135         byte b0 = readByte();
   115         byte b1 = readByte();
   136         byte b1 = readByte();
   116         return (short) ((b1 & 0xFF) + (b0 << 8));
   137         return (short) ((b1 & 0xFF) + (b0 << 8));
   117     }
   138     }
   118 
   139 
   119     @Override
   140     @Override
   120     public final double readDouble() throws IOException {
   141     public double readDouble() throws IOException {
   121         // copied from java.io.Bits
   142         // copied from java.io.Bits
   122         return Double.longBitsToDouble(readRawLong());
   143         return Double.longBitsToDouble(readRawLong());
   123     }
   144     }
   124 
   145 
   125     @Override
   146     @Override
   126     public final float readFloat() throws IOException {
   147     public float readFloat() throws IOException {
   127         // copied from java.io.Bits
   148         // copied from java.io.Bits
   128         return Float.intBitsToFloat(readRawInt());
   149         return Float.intBitsToFloat(readRawInt());
   129     }
   150     }
   130 
   151 
   131     public final int readRawInt() throws IOException {
   152     int readRawInt() throws IOException {
   132         // copied from java.io.Bits
   153         // copied from java.io.Bits
   133         byte b0 = readByte();
   154         byte b0 = readByte();
   134         byte b1 = readByte();
   155         byte b1 = readByte();
   135         byte b2 = readByte();
   156         byte b2 = readByte();
   136         byte b3 = readByte();
   157         byte b3 = readByte();
   137         return ((b3 & 0xFF)) + ((b2 & 0xFF) << 8) + ((b1 & 0xFF) << 16) + ((b0) << 24);
   158         return ((b3 & 0xFF)) + ((b2 & 0xFF) << 8) + ((b1 & 0xFF) << 16) + ((b0) << 24);
   138     }
   159     }
   139 
   160 
   140     public final long readRawLong() throws IOException {
   161     long readRawLong() throws IOException {
   141         // copied from java.io.Bits
   162         // copied from java.io.Bits
   142         byte b0 = readByte();
   163         byte b0 = readByte();
   143         byte b1 = readByte();
   164         byte b1 = readByte();
   144         byte b2 = readByte();
   165         byte b2 = readByte();
   145         byte b3 = readByte();
   166         byte b3 = readByte();
   148         byte b6 = readByte();
   169         byte b6 = readByte();
   149         byte b7 = readByte();
   170         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);
   171         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     }
   172     }
   152 
   173 
   153     public final long position() throws IOException {
   174     public final long position() {
   154         return position;
   175         return position;
   155     }
   176     }
   156 
   177 
   157     public final void position(long newPosition) throws IOException {
   178     public final void position(long newPosition) throws IOException {
   158         if (!currentBlock.contains(newPosition)) {
   179         if (!currentBlock.contains(newPosition)) {
   159             if (!previousBlock.contains(newPosition)) {
   180             if (!previousBlock.contains(newPosition)) {
   160                 if (newPosition > size()) {
   181                 if (newPosition > size) {
   161                     throw new EOFException("Trying to read at " + newPosition + ", but file is only " + size() + " bytes.");
   182                     throw new EOFException("Trying to read at " + newPosition + ", but file is only " + size + " bytes.");
   162                 }
   183                 }
   163                 long blockStart = trimToFileSize(calculateBlockStart(newPosition));
   184                 long blockStart = trimToFileSize(calculateBlockStart(newPosition));
   164                 file.seek(blockStart);
   185                 file.seek(blockStart);
   165                 // trim amount to file size
   186                 // trim amount to file size
   166                 long amount = Math.min(size() - blockStart, blockSize);
   187                 long amount = Math.min(size - blockStart, blockSize);
   167                 previousBlock.read(file, (int) amount);
   188                 previousBlock.read(file, (int) amount);
   168             }
   189             }
   169             // swap previous and current
   190             // swap previous and current
   170             Block tmp = currentBlock;
   191             Block tmp = currentBlock;
   171             currentBlock = previousBlock;
   192             currentBlock = previousBlock;
   189         }
   210         }
   190         // not near current block, pick middle
   211         // not near current block, pick middle
   191         return newPosition - blockSize / 2;
   212         return newPosition - blockSize / 2;
   192     }
   213     }
   193 
   214 
   194     public final long size() throws IOException {
   215     long size() {
   195         return size;
   216         return size;
   196     }
   217     }
   197 
   218 
   198     public final void close() throws IOException {
   219     @Override
       
   220     public void close() throws IOException {
   199         file.close();
   221         file.close();
   200     }
   222     }
   201 
   223 
   202     @Override
   224     @Override
   203     public final int skipBytes(int n) throws IOException {
   225     public final int skipBytes(int n) throws IOException {
   243     // 2, means char array
   265     // 2, means char array
   244     // 3, means latin-1 (ISO-8859-1) encoded byte array
   266     // 3, means latin-1 (ISO-8859-1) encoded byte array
   245     // 4, means ""
   267     // 4, means ""
   246     @Override
   268     @Override
   247     public String readUTF() throws IOException {
   269     public String readUTF() throws IOException {
   248         return readEncodedString(readByte());
   270         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     }
   271     }
   277 
   272 
   278     @Override
   273     @Override
   279     public char readChar() throws IOException {
   274     public char readChar() throws IOException {
   280         return (char) readLong();
   275         return (char) readLong();
   290         return (int) readLong();
   285         return (int) readLong();
   291     }
   286     }
   292 
   287 
   293     @Override
   288     @Override
   294     public long readLong() throws IOException {
   289     public long readLong() throws IOException {
   295         // can be optimized by branching checks, but will do for now
   290         final byte[] bytes = currentBlock.bytes;
       
   291         final int index = (int) (position - currentBlock.blockPosition);
       
   292 
       
   293         if (index + 8 < bytes.length && index >= 0) {
       
   294             byte b0 = bytes[index];
       
   295             long ret = (b0 & 0x7FL);
       
   296             if (b0 >= 0) {
       
   297                 position += 1;
       
   298                 return ret;
       
   299             }
       
   300             int b1 = bytes[index + 1];
       
   301             ret += (b1 & 0x7FL) << 7;
       
   302             if (b1 >= 0) {
       
   303                 position += 2;
       
   304                 return ret;
       
   305             }
       
   306             int b2 = bytes[index + 2];
       
   307             ret += (b2 & 0x7FL) << 14;
       
   308             if (b2 >= 0) {
       
   309                 position += 3;
       
   310                 return ret;
       
   311             }
       
   312             int b3 = bytes[index + 3];
       
   313             ret += (b3 & 0x7FL) << 21;
       
   314             if (b3 >= 0) {
       
   315                 position += 4;
       
   316                 return ret;
       
   317             }
       
   318             int b4 = bytes[index + 4];
       
   319             ret += (b4 & 0x7FL) << 28;
       
   320             if (b4 >= 0) {
       
   321                 position += 5;
       
   322                 return ret;
       
   323             }
       
   324             int b5 = bytes[index + 5];
       
   325             ret += (b5 & 0x7FL) << 35;
       
   326             if (b5 >= 0) {
       
   327                 position += 6;
       
   328                 return ret;
       
   329             }
       
   330             int b6 = bytes[index + 6];
       
   331             ret += (b6 & 0x7FL) << 42;
       
   332             if (b6 >= 0) {
       
   333                 position += 7;
       
   334                 return ret;
       
   335             }
       
   336             int b7 = bytes[index + 7];
       
   337             ret += (b7 & 0x7FL) << 49;
       
   338             if (b7 >= 0) {
       
   339                 position += 8;
       
   340                 return ret;
       
   341             }
       
   342             int b8 = bytes[index + 8];// read last byte raw
       
   343             position += 9;
       
   344             return ret + (((long) (b8 & 0XFF)) << 56);
       
   345         } else {
       
   346             return readLongSlow();
       
   347         }
       
   348     }
       
   349 
       
   350     private long readLongSlow() throws IOException {
   296         byte b0 = readByte();
   351         byte b0 = readByte();
   297         long ret = (b0 & 0x7FL);
   352         long ret = (b0 & 0x7FL);
   298         if (b0 >= 0) {
   353         if (b0 >= 0) {
   299             return ret;
   354             return ret;
   300         }
   355         }
       
   356 
   301         int b1 = readByte();
   357         int b1 = readByte();
   302         ret += (b1 & 0x7FL) << 7;
   358         ret += (b1 & 0x7FL) << 7;
   303         if (b1 >= 0) {
   359         if (b1 >= 0) {
   304             return ret;
   360             return ret;
   305         }
   361         }
       
   362 
   306         int b2 = readByte();
   363         int b2 = readByte();
   307         ret += (b2 & 0x7FL) << 14;
   364         ret += (b2 & 0x7FL) << 14;
   308         if (b2 >= 0) {
   365         if (b2 >= 0) {
   309             return ret;
   366             return ret;
   310         }
   367         }
       
   368 
   311         int b3 = readByte();
   369         int b3 = readByte();
   312         ret += (b3 & 0x7FL) << 21;
   370         ret += (b3 & 0x7FL) << 21;
   313         if (b3 >= 0) {
   371         if (b3 >= 0) {
   314             return ret;
   372             return ret;
   315         }
   373         }
       
   374 
   316         int b4 = readByte();
   375         int b4 = readByte();
   317         ret += (b4 & 0x7FL) << 28;
   376         ret += (b4 & 0x7FL) << 28;
   318         if (b4 >= 0) {
   377         if (b4 >= 0) {
   319             return ret;
   378             return ret;
   320         }
   379         }
       
   380 
   321         int b5 = readByte();
   381         int b5 = readByte();
   322         ret += (b5 & 0x7FL) << 35;
   382         ret += (b5 & 0x7FL) << 35;
   323         if (b5 >= 0) {
   383         if (b5 >= 0) {
   324             return ret;
   384             return ret;
   325         }
   385         }
       
   386 
   326         int b6 = readByte();
   387         int b6 = readByte();
   327         ret += (b6 & 0x7FL) << 42;
   388         ret += (b6 & 0x7FL) << 42;
   328         if (b6 >= 0) {
   389         if (b6 >= 0) {
   329             return ret;
   390             return ret;
   330         }
   391         }
       
   392 
   331         int b7 = readByte();
   393         int b7 = readByte();
   332         ret += (b7 & 0x7FL) << 49;
   394         ret += (b7 & 0x7FL) << 49;
   333         if (b7 >= 0) {
   395         if (b7 >= 0) {
   334             return ret;
   396             return ret;
   335         }
   397 
       
   398         }
       
   399 
   336         int b8 = readByte(); // read last byte raw
   400         int b8 = readByte(); // read last byte raw
   337         return ret + (((long) (b8 & 0XFF)) << 56);
   401         return ret + (((long) (b8 & 0XFF)) << 56);
   338     }
   402     }
       
   403 
       
   404     public void setValidSize(long size) {
       
   405         if (size > this.size) {
       
   406             this.size = size;
       
   407         }
       
   408     }
       
   409 
       
   410     public long getFileSize() throws IOException {
       
   411         return file.length();
       
   412     }
       
   413 
       
   414     public String getFilename() {
       
   415         return filename;
       
   416     }
       
   417 
       
   418     // Purpose of this method is to reuse block cache from a
       
   419     // previous RecordingInput
       
   420     public void setFile(Path path) throws IOException {
       
   421         try {
       
   422             file.close();
       
   423         } catch (IOException e) {
       
   424             // perhaps deleted
       
   425         }
       
   426         file = null;
       
   427         initialize(path.toFile());
       
   428     }
       
   429 /*
       
   430 
       
   431 
       
   432 
       
   433 
       
   434 
       
   435  *
       
   436  *
       
   437  */
   339 }
   438 }