src/jdk.jfr/share/classes/jdk/jfr/consumer/ParserFactory.java
branchJEP-349-branch
changeset 57360 5d043a159d5c
parent 50113 caf115bb98ad
child 57373 400db63e4937
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
    26 package jdk.jfr.consumer;
    26 package jdk.jfr.consumer;
    27 
    27 
    28 import java.io.IOException;
    28 import java.io.IOException;
    29 import java.util.ArrayList;
    29 import java.util.ArrayList;
    30 import java.util.List;
    30 import java.util.List;
    31 import java.util.Objects;
       
    32 
    31 
    33 import jdk.jfr.EventType;
    32 import jdk.jfr.EventType;
    34 import jdk.jfr.ValueDescriptor;
    33 import jdk.jfr.ValueDescriptor;
    35 import jdk.jfr.internal.MetadataDescriptor;
    34 import jdk.jfr.internal.MetadataDescriptor;
    36 import jdk.jfr.internal.PrivateAccess;
    35 import jdk.jfr.internal.PrivateAccess;
    37 import jdk.jfr.internal.Type;
    36 import jdk.jfr.internal.Type;
       
    37 import jdk.jfr.internal.consumer.Parser;
    38 import jdk.jfr.internal.consumer.RecordingInput;
    38 import jdk.jfr.internal.consumer.RecordingInput;
    39 
    39 
    40 /**
    40 /**
    41  * Class that create parsers suitable for reading events and constant pools
    41  * Class that create parsers suitable for reading events and constant pools
    42  */
    42  */
    43 final class ParserFactory {
    43 final class ParserFactory {
    44     private final LongMap<Parser> parsers = new LongMap<>();
    44     private final LongMap<Parser> parsers = new LongMap<>();
    45     private final TimeConverter timeConverter;
    45     private final TimeConverter timeConverter;
    46     private final LongMap<Type> types = new LongMap<>();
    46     private final LongMap<Type> types = new LongMap<>();
    47     private final LongMap<ConstantMap> constantPools;
    47     private final LongMap<ConstantLookup> constantLookups;
    48 
    48 
    49     public ParserFactory(MetadataDescriptor metadata, TimeConverter timeConverter) throws IOException {
    49     public ParserFactory(MetadataDescriptor metadata, LongMap<ConstantLookup> constantLookups, TimeConverter timeConverter) throws IOException {
    50         this.constantPools = new LongMap<>();
    50         this.constantLookups = constantLookups;
    51         this.timeConverter = timeConverter;
    51         this.timeConverter = timeConverter;
    52         for (Type t : metadata.getTypes()) {
    52         for (Type t : metadata.getTypes()) {
    53             types.put(t.getId(), t);
    53             types.put(t.getId(), t);
    54         }
    54         }
    55         for (Type t : types) {
    55         List<Type> typeList = new ArrayList<>();
       
    56         types.forEach(typeList::add);
       
    57         for (Type t : typeList) {
    56             if (!t.getFields().isEmpty()) { // Avoid primitives
    58             if (!t.getFields().isEmpty()) { // Avoid primitives
    57                 CompositeParser cp = createCompositeParser(t);
    59                 CompositeParser cp = createCompositeParser(t, false);
    58                 if (t.isSimpleType()) { // Reduce to nested parser
    60                 if (t.isSimpleType()) { // Reduce to nested parser
    59                    parsers.put(t.getId(), cp.parsers[0]);
    61                     parsers.put(t.getId(), cp.parsers[0]);
    60                 }
    62                 }
    61 
    63 
    62             }
    64             }
    63         }
    65         }
    64         // Override event types with event parsers
    66         // Override event types with event parsers
    69 
    71 
    70     public LongMap<Parser> getParsers() {
    72     public LongMap<Parser> getParsers() {
    71         return parsers;
    73         return parsers;
    72     }
    74     }
    73 
    75 
    74     public LongMap<ConstantMap> getConstantPools() {
       
    75         return constantPools;
       
    76     }
       
    77 
       
    78     public LongMap<Type> getTypeMap() {
    76     public LongMap<Type> getTypeMap() {
    79         return types;
    77         return types;
    80     }
    78     }
    81 
    79 
    82     private EventParser createEventParser(EventType eventType) throws IOException {
    80     private EventParser createEventParser(EventType eventType) throws IOException {
    83         List<Parser> parsers = new ArrayList<Parser>();
    81         List<Parser> parsers = new ArrayList<Parser>();
    84         for (ValueDescriptor f : eventType.getFields()) {
    82         for (ValueDescriptor f : eventType.getFields()) {
    85             parsers.add(createParser(f));
    83             parsers.add(createParser(f, true));
    86         }
    84         }
    87         return new EventParser(timeConverter, eventType, parsers.toArray(new Parser[0]));
    85         return new EventParser(timeConverter, eventType, parsers.toArray(new Parser[0]));
    88     }
    86     }
    89 
    87 
    90     private Parser createParser(ValueDescriptor v) throws IOException {
    88     private Parser createParser(ValueDescriptor v, boolean event) throws IOException {
    91         boolean constantPool = PrivateAccess.getInstance().isConstantPool(v);
    89         boolean constantPool = PrivateAccess.getInstance().isConstantPool(v);
    92         if (v.isArray()) {
    90         if (v.isArray()) {
    93             Type valueType = PrivateAccess.getInstance().getType(v);
    91             Type valueType = PrivateAccess.getInstance().getType(v);
    94             ValueDescriptor element = PrivateAccess.getInstance().newValueDescriptor(v.getName(), valueType, v.getAnnotationElements(), 0, constantPool, null);
    92             ValueDescriptor element = PrivateAccess.getInstance().newValueDescriptor(v.getName(), valueType, v.getAnnotationElements(), 0, constantPool, null);
    95             return new ArrayParser(createParser(element));
    93             return new ArrayParser(createParser(element, event));
    96         }
    94         }
    97         long id = v.getTypeId();
    95         long id = v.getTypeId();
    98         Type type = types.get(id);
    96         Type type = types.get(id);
    99         if (type == null) {
    97         if (type == null) {
   100             throw new IOException("Type '" + v.getTypeName() + "' is not defined");
    98             throw new IOException("Type '" + v.getTypeName() + "' is not defined");
   101         }
    99         }
   102         if (constantPool) {
   100         if (constantPool) {
   103             ConstantMap pool = constantPools.get(id);
   101             ConstantLookup lookup = constantLookups.get(id);
   104             if (pool == null) {
   102             if (lookup == null) {
   105                 pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type.getName());
   103                 ConstantMap pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type.getName());
   106                 constantPools.put(id, pool);
   104                 lookup = new ConstantLookup(pool, type);
   107             }
   105                 constantLookups.put(id, lookup);
   108             return new ConstantMapValueParser(pool);
   106             }
       
   107             if (event) {
       
   108                 return new EventValueConstantParser(lookup);
       
   109             }
       
   110             return new ConstantValueParser(lookup);
   109         }
   111         }
   110         Parser parser = parsers.get(id);
   112         Parser parser = parsers.get(id);
   111         if (parser == null) {
   113         if (parser == null) {
   112             if (!v.getFields().isEmpty()) {
   114             if (!v.getFields().isEmpty()) {
   113                 return createCompositeParser(type);
   115                 return createCompositeParser(type, event);
   114             } else {
   116             } else {
   115                 return registerParserType(type, createPrimitiveParser(type));
   117                 return registerParserType(type, createPrimitiveParser(type, constantPool));
   116             }
   118             }
   117         }
   119         }
   118         return parser;
   120         return parser;
   119     }
   121     }
   120 
   122 
   121     private Parser createPrimitiveParser(Type type) throws IOException {
   123     private Parser createPrimitiveParser(Type type, boolean event) throws IOException {
   122         switch (type.getName()) {
   124         switch (type.getName()) {
   123         case "int":
   125         case "int":
   124             return new IntegerParser();
   126             return new IntegerParser();
   125         case "long":
   127         case "long":
   126             return new LongParser();
   128             return new LongParser();
   136             return new ShortParser();
   138             return new ShortParser();
   137         case "byte":
   139         case "byte":
   138             return new ByteParser();
   140             return new ByteParser();
   139         case "java.lang.String":
   141         case "java.lang.String":
   140             ConstantMap pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type.getName());
   142             ConstantMap pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type.getName());
   141             constantPools.put(type.getId(), pool);
   143             ConstantLookup lookup = new ConstantLookup(pool, type);
   142             return new StringParser(pool);
   144             constantLookups.put(type.getId(), lookup);
       
   145             return new StringParser(lookup, event);
   143         default:
   146         default:
   144             throw new IOException("Unknown primitive type " + type.getName());
   147             throw new IOException("Unknown primitive type " + type.getName());
   145         }
   148         }
   146     }
   149     }
   147 
   150 
   153         }
   156         }
   154         parsers.put(t.getId(), parser);
   157         parsers.put(t.getId(), parser);
   155         return parser;
   158         return parser;
   156     }
   159     }
   157 
   160 
   158     private CompositeParser createCompositeParser(Type type) throws IOException {
   161     private CompositeParser createCompositeParser(Type type, boolean event) throws IOException {
   159         List<ValueDescriptor> vds = type.getFields();
   162         List<ValueDescriptor> vds = type.getFields();
   160         Parser[] parsers = new Parser[vds.size()];
   163         Parser[] parsers = new Parser[vds.size()];
   161         CompositeParser composite = new CompositeParser(parsers);
   164         CompositeParser composite = new CompositeParser(parsers);
   162         // need to pre-register so recursive types can be handled
   165         // need to pre-register so recursive types can be handled
   163         registerParserType(type, composite);
   166         registerParserType(type, composite);
   164 
   167 
   165         int index = 0;
   168         int index = 0;
   166         for (ValueDescriptor vd : vds) {
   169         for (ValueDescriptor vd : vds) {
   167             parsers[index++] = createParser(vd);
   170             parsers[index++] = createParser(vd, event);
   168         }
   171         }
   169         return composite;
   172         return composite;
   170     }
   173     }
   171 
   174 
   172     private static final class BooleanParser extends Parser {
   175     private static final class BooleanParser extends Parser {
   173         @Override
   176         @Override
   174         public Object parse(RecordingInput input) throws IOException {
   177         public Object parse(RecordingInput input) throws IOException {
   175             return input.readBoolean() ? Boolean.TRUE : Boolean.FALSE;
   178             return input.readBoolean() ? Boolean.TRUE : Boolean.FALSE;
   176         }
   179         }
       
   180 
       
   181         @Override
       
   182         public void skip(RecordingInput input) throws IOException {
       
   183             input.skipBytes(1);
       
   184         }
   177     }
   185     }
   178 
   186 
   179     private static final class ByteParser extends Parser {
   187     private static final class ByteParser extends Parser {
   180         @Override
   188         @Override
   181         public Object parse(RecordingInput input) throws IOException {
   189         public Object parse(RecordingInput input) throws IOException {
   182             return Byte.valueOf(input.readByte());
   190             return Byte.valueOf(input.readByte());
   183         }
   191         }
       
   192 
       
   193         @Override
       
   194         public void skip(RecordingInput input) throws IOException {
       
   195             input.skipBytes(1);
       
   196         }
   184     }
   197     }
   185 
   198 
   186     private static final class LongParser extends Parser {
   199     private static final class LongParser extends Parser {
   187         @Override
   200         private Object lastLongObject = Long.valueOf(0);
   188         public Object parse(RecordingInput input) throws IOException {
   201         private long last = 0;
   189             return Long.valueOf(input.readLong());
   202 
       
   203         @Override
       
   204         public Object parse(RecordingInput input) throws IOException {
       
   205             long l = input.readLong();
       
   206             if (l != last) {
       
   207                 last = l;
       
   208                 lastLongObject = Long.valueOf(l);
       
   209             }
       
   210             return lastLongObject;
       
   211         }
       
   212 
       
   213         @Override
       
   214         public void skip(RecordingInput input) throws IOException {
       
   215             input.readLong();
   190         }
   216         }
   191     }
   217     }
   192 
   218 
   193     private static final class IntegerParser extends Parser {
   219     private static final class IntegerParser extends Parser {
   194         @Override
   220         private Integer lastIntegergObject = Integer.valueOf(0);
   195         public Object parse(RecordingInput input) throws IOException {
   221         private int last = 0;
   196             return Integer.valueOf(input.readInt());
   222 
       
   223         @Override
       
   224         public Object parse(RecordingInput input) throws IOException {
       
   225             int i = input.readInt();
       
   226             if (i != last) {
       
   227                 last = i;
       
   228                 lastIntegergObject = Integer.valueOf(i);
       
   229             }
       
   230             return lastIntegergObject;
       
   231         }
       
   232 
       
   233         @Override
       
   234         public void skip(RecordingInput input) throws IOException {
       
   235             input.readInt();
   197         }
   236         }
   198     }
   237     }
   199 
   238 
   200     private static final class ShortParser extends Parser {
   239     private static final class ShortParser extends Parser {
   201         @Override
   240         @Override
   202         public Object parse(RecordingInput input) throws IOException {
   241         public Object parse(RecordingInput input) throws IOException {
   203             return Short.valueOf(input.readShort());
   242             return Short.valueOf(input.readShort());
   204         }
   243         }
       
   244 
       
   245         @Override
       
   246         public void skip(RecordingInput input) throws IOException {
       
   247             input.readShort();
       
   248         }
   205     }
   249     }
   206 
   250 
   207     private static final class CharacterParser extends Parser {
   251     private static final class CharacterParser extends Parser {
   208         @Override
   252         @Override
   209         public Object parse(RecordingInput input) throws IOException {
   253         public Object parse(RecordingInput input) throws IOException {
   210             return Character.valueOf(input.readChar());
   254             return Character.valueOf(input.readChar());
   211         }
   255         }
       
   256 
       
   257         @Override
       
   258         public void skip(RecordingInput input) throws IOException {
       
   259             input.readChar();
       
   260         }
   212     }
   261     }
   213 
   262 
   214     private static final class FloatParser extends Parser {
   263     private static final class FloatParser extends Parser {
   215         @Override
   264         @Override
   216         public Object parse(RecordingInput input) throws IOException {
   265         public Object parse(RecordingInput input) throws IOException {
   217             return Float.valueOf(input.readFloat());
   266             return Float.valueOf(input.readFloat());
   218         }
   267         }
       
   268 
       
   269         @Override
       
   270         public void skip(RecordingInput input) throws IOException {
       
   271             input.skipBytes(Float.SIZE);
       
   272         }
   219     }
   273     }
   220 
   274 
   221     private static final class DoubleParser extends Parser {
   275     private static final class DoubleParser extends Parser {
   222         @Override
   276         @Override
   223         public Object parse(RecordingInput input) throws IOException {
   277         public Object parse(RecordingInput input) throws IOException {
   224             return Double.valueOf(input.readDouble());
   278             return Double.valueOf(input.readDouble());
   225         }
   279         }
   226     }
   280 
   227 
   281         @Override
   228     private static final class StringParser extends Parser {
   282         public void skip(RecordingInput input) throws IOException {
   229         private final ConstantMap stringConstantMap;
   283             input.skipBytes(Double.SIZE);
   230         private String last;
       
   231 
       
   232         StringParser(ConstantMap stringConstantMap) {
       
   233             this.stringConstantMap = stringConstantMap;
       
   234         }
       
   235 
       
   236         @Override
       
   237         public Object parse(RecordingInput input) throws IOException {
       
   238             String s = parseEncodedString(input);
       
   239             if (!Objects.equals(s, last)) {
       
   240                 last = s;
       
   241             }
       
   242             return last;
       
   243         }
       
   244 
       
   245         private String parseEncodedString(RecordingInput input) throws IOException {
       
   246             byte encoding = input.readByte();
       
   247             if (encoding == RecordingInput.STRING_ENCODING_CONSTANT_POOL) {
       
   248                 long id = input.readLong();
       
   249                 return (String) stringConstantMap.get(id);
       
   250             } else {
       
   251                 return input.readEncodedString(encoding);
       
   252             }
       
   253         }
   284         }
   254     }
   285     }
   255 
   286 
   256     private final static class ArrayParser extends Parser {
   287     private final static class ArrayParser extends Parser {
   257         private final Parser elementParser;
   288         private final Parser elementParser;
   267             for (int i = 0; i < size; i++) {
   298             for (int i = 0; i < size; i++) {
   268                 array[i] = elementParser.parse(input);
   299                 array[i] = elementParser.parse(input);
   269             }
   300             }
   270             return array;
   301             return array;
   271         }
   302         }
   272     }
   303 
   273 
   304         @Override
   274     private final static class CompositeParser extends Parser {
   305         public void skip(RecordingInput input) throws IOException {
       
   306             final int size = input.readInt();
       
   307             for (int i = 0; i < size; i++) {
       
   308                 elementParser.skip(input);
       
   309             }
       
   310         }
       
   311     }
       
   312 
       
   313     final static class CompositeParser extends Parser {
   275         private final Parser[] parsers;
   314         private final Parser[] parsers;
   276 
   315 
   277         public CompositeParser(Parser[] valueParsers) {
   316         public CompositeParser(Parser[] valueParsers) {
   278             this.parsers = valueParsers;
   317             this.parsers = valueParsers;
   279         }
   318         }
   284             for (int i = 0; i < values.length; i++) {
   323             for (int i = 0; i < values.length; i++) {
   285                 values[i] = parsers[i].parse(input);
   324                 values[i] = parsers[i].parse(input);
   286             }
   325             }
   287             return values;
   326             return values;
   288         }
   327         }
   289     }
   328 
   290 
   329         @Override
   291     private static final class ConstantMapValueParser extends Parser {
   330         public void skip(RecordingInput input) throws IOException {
   292         private final ConstantMap pool;
   331             for (int i = 0; i < parsers.length; i++) {
   293 
   332                 parsers[i].skip(input);
   294         ConstantMapValueParser(ConstantMap pool) {
   333             }
   295             this.pool = pool;
   334         }
   296         }
   335     }
   297 
   336 
   298         @Override
   337     public static final class EventValueConstantParser extends Parser {
   299         public Object parse(RecordingInput input) throws IOException {
   338         private final ConstantLookup lookup;
   300             return pool.get(input.readLong());
   339         private Object lastValue = 0;
       
   340         private long lastKey = -1;
       
   341         EventValueConstantParser(ConstantLookup lookup) {
       
   342             this.lookup = lookup;
       
   343         }
       
   344 
       
   345         @Override
       
   346         public Object parse(RecordingInput input) throws IOException {
       
   347             long key = input.readLong();
       
   348             if (key == lastKey) {
       
   349                 return lastValue;
       
   350             }
       
   351             lastKey = key;
       
   352             lastValue = lookup.getCurrentResolved(key);
       
   353             return lastValue;
       
   354         }
       
   355 
       
   356         @Override
       
   357         public void skip(RecordingInput input) throws IOException {
       
   358             input.readLong();
       
   359         }
       
   360     }
       
   361 
       
   362     public static final class ConstantValueParser extends Parser {
       
   363         private final ConstantLookup lookup;
       
   364         ConstantValueParser(ConstantLookup lookup) {
       
   365             this.lookup = lookup;
       
   366         }
       
   367 
       
   368         @Override
       
   369         public Object parse(RecordingInput input) throws IOException {
       
   370             return lookup.getCurrent(input.readLong());
       
   371         }
       
   372 
       
   373         @Override
       
   374         public void skip(RecordingInput input) throws IOException {
       
   375             input.readLong();
   301         }
   376         }
   302     }
   377     }
   303 }
   378 }