diff -r 2c3cc4b01880 -r c16ac7a2eba4 src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventParser.java Wed Oct 30 19:43:52 2019 +0100 @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2016, 2019, 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 static jdk.jfr.internal.EventInstrumentation.FIELD_DURATION; + +import java.io.IOException; +import java.util.List; + +import jdk.jfr.EventType; +import jdk.jfr.ValueDescriptor; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.internal.consumer.Parser; +import jdk.jfr.internal.consumer.RecordingInput; + +/** + * Parses an event and returns a {@link RecordedEvent}. + * + */ +final class EventParser extends Parser { + + private static final JdkJfrConsumer PRIVATE_ACCESS = JdkJfrConsumer.instance(); + + private final Parser[] parsers; + private final EventType eventType; + private final TimeConverter timeConverter; + private final boolean hasDuration; + private final List valueDescriptors; + private final int startIndex; + private final int length; + private final RecordedEvent unorderedEvent; + private final ObjectContext objectContext; + + private RecordedEvent[] cached; + private int cacheIndex; + + private boolean enabled = true; + private boolean ordered; + private long filterStart; + private long filterEnd = Long.MAX_VALUE; + private long thresholdNanos = -1; + + EventParser(TimeConverter timeConverter, EventType type, Parser[] parsers) { + this.timeConverter = timeConverter; + this.parsers = parsers; + this.eventType = type; + this.hasDuration = type.getField(FIELD_DURATION) != null; + this.startIndex = hasDuration ? 2 : 1; + this.length = parsers.length - startIndex; + this.valueDescriptors = type.getFields(); + this.objectContext = new ObjectContext(type, valueDescriptors, timeConverter); + this.unorderedEvent = PRIVATE_ACCESS.newRecordedEvent(objectContext, new Object[length], 0L, 0L); + } + + private RecordedEvent cachedEvent() { + if (ordered) { + if (cacheIndex == cached.length) { + RecordedEvent[] old = cached; + cached = new RecordedEvent[cached.length * 2]; + System.arraycopy(old, 0, cached, 0, old.length); + } + RecordedEvent event = cached[cacheIndex]; + if (event == null) { + event = PRIVATE_ACCESS.newRecordedEvent(objectContext, new Object[length], 0L, 0L); + cached[cacheIndex] = event; + } + cacheIndex++; + return event; + } else { + return unorderedEvent; + } + } + + public EventType getEventType() { + return eventType; + } + + public void setThresholdNanos(long thresholdNanos) { + this.thresholdNanos = thresholdNanos; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public boolean isEnabled() { + return enabled; + } + + public RecordedEvent parse(RecordingInput input) throws IOException { + if (!enabled) { + return null; + } + + long startTicks = input.readLong(); + long endTicks = startTicks; + if (hasDuration) { + long durationTicks = input.readLong(); + if (thresholdNanos > 0L) { + if (timeConverter.convertTimespan(durationTicks) < thresholdNanos) { + return null; + } + } + endTicks += durationTicks; + } + if (filterStart != 0L || filterEnd != Long.MAX_VALUE) { + long eventEnd = timeConverter.convertTimestamp(endTicks); + if (eventEnd < filterStart) { + return null; + } + if (eventEnd > filterEnd) { + return null; + } + } + + if (cached != null) { + RecordedEvent event = cachedEvent(); + JdkJfrConsumer access = PRIVATE_ACCESS; + access.setStartTicks(event, startTicks); + access.setEndTicks(event, endTicks); + Object[] values = access.eventValues(event); + for (int i = 0; i < values.length; i++) { + values[i] = parsers[startIndex + i].parse(input); + } + return event; + } + + Object[] values = new Object[length]; + for (int i = 0; i < values.length; i++) { + values[i] = parsers[startIndex + i].parse(input); + } + return PRIVATE_ACCESS.newRecordedEvent(objectContext, values, startTicks, endTicks); + } + + @Override + public void skip(RecordingInput input) throws IOException { + throw new InternalError("Should not call this method. More efficent to read event size and skip ahead"); + } + + public void resetCache() { + cacheIndex = 0; + } + + private boolean hasReuse() { + return cached != null; + } + + public void setReuse(boolean reuse) { + if (reuse == hasReuse()) { + return; + } + if (reuse) { + cached = new RecordedEvent[2]; + cacheIndex = 0; + } else { + cached = null; + } + } + + public void setFilterStart(long filterStart) { + this.filterStart = filterStart; + } + + public void setFilterEnd(long filterEnd) { + this.filterEnd = filterEnd; + } + + public void setOrdered(boolean ordered) { + if (this.ordered == ordered) { + return; + } + this.ordered = ordered; + this.cacheIndex = 0; + } +}