8253505: JFR: onFlush invoked out of order with a sorted event stream

Reviewed-by: mgronlun
This commit is contained in:
Erik Gahlin 2021-01-14 21:26:13 +00:00
parent 0148adf20e
commit 4307fa68b7
6 changed files with 54 additions and 50 deletions

View File

@ -103,6 +103,9 @@ public final class RecordingFile implements Closeable {
isLastEventInChunk = false;
RecordedEvent event = nextEvent;
nextEvent = chunkParser.readEvent();
while (nextEvent == ChunkParser.FLUSH_MARKER) {
nextEvent = chunkParser.readEvent();
}
if (nextEvent == null) {
isLastEventInChunk = true;
findNext();
@ -251,6 +254,9 @@ public final class RecordingFile implements Closeable {
return;
}
nextEvent = chunkParser.readEvent();
while (nextEvent == ChunkParser.FLUSH_MARKER) {
nextEvent = chunkParser.readEvent();
}
}
}

View File

@ -233,6 +233,14 @@ public abstract class AbstractEventStream implements EventStream {
return flushOperation;
}
final protected void onFlush() {
Runnable r = getFlushOperation();
if (r != null) {
r.run();
}
}
private void startInternal(long startNanos) {
synchronized (streamConfiguration) {
if (streamConfiguration.started) {
@ -291,7 +299,7 @@ public abstract class AbstractEventStream implements EventStream {
streamConfiguration.addMetadataAction(action);
}
protected final void emitMetadataEvent(ChunkParser parser) {
protected final void onMetadata(ChunkParser parser) {
if (parser.hasStaleMetadata()) {
if (dispatcher.hasMetadataHandler()) {
List<EventType> ce = parser.getEventTypes();

View File

@ -91,6 +91,7 @@ public final class ChunkParser {
return (mask & flags) != 0;
}
}
public final static RecordedEvent FLUSH_MARKER = JdkJfrConsumer.instance().newRecordedEvent(null, null, 0L, 0L);
private static final long CONSTANT_POOL_TYPE_ID = 1;
private static final String CHUNKHEADER = "jdk.types.ChunkHeader";
@ -104,7 +105,6 @@ public final class ChunkParser {
private LongMap<Parser> parsers;
private boolean chunkFinished;
private Runnable flushOperation;
private ParserConfiguration configuration;
private volatile boolean closed;
private MetadataDescriptor previousMetadata;
@ -194,6 +194,9 @@ public final class ChunkParser {
RecordedEvent readStreamingEvent() throws IOException {
long absoluteChunkEnd = chunkHeader.getEnd();
RecordedEvent event = readEvent();
if (event == ChunkParser.FLUSH_MARKER) {
return null;
}
if (event != null) {
return event;
}
@ -253,8 +256,9 @@ public final class ChunkParser {
// Not accepted by filter
} else {
if (typeId == 1) { // checkpoint event
if (flushOperation != null) {
parseCheckpoint();
if (CheckPointType.FLUSH.is(parseCheckpointType())) {
input.position(pos + size);
return FLUSH_MARKER;
}
} else {
if (typeId != 0) { // Not metadata event
@ -267,16 +271,11 @@ public final class ChunkParser {
return null;
}
private void parseCheckpoint() throws IOException {
// Content has been parsed previously. This
// is to trigger flush
private byte parseCheckpointType() throws IOException {
input.readLong(); // timestamp
input.readLong(); // duration
input.readLong(); // delta
byte typeFlags = input.readByte();
if (CheckPointType.FLUSH.is(typeFlags)) {
flushOperation.run();
}
return input.readByte();
}
private boolean awaitUpdatedHeader(long absoluteChunkEnd, long filterEnd) throws IOException {
@ -451,10 +450,6 @@ public final class ChunkParser {
return chunkFinished;
}
public void setFlushOperation(Runnable flushOperation) {
this.flushOperation = flushOperation;
}
public long getChunkDuration() {
return chunkHeader.getDurationNanos();
}

View File

@ -38,8 +38,6 @@ import jdk.jfr.internal.consumer.ChunkParser.ParserConfiguration;
final class Dispatcher {
public final static RecordedEvent FLUSH_MARKER = JdkJfrConsumer.instance().newRecordedEvent(null, null, 0L, 0L);
final static class EventDispatcher {
private final static EventDispatcher[] NO_DISPATCHERS = new EventDispatcher[0];

View File

@ -143,7 +143,7 @@ public class EventDirectoryStream extends AbstractEventStream {
long filterEnd = disp.endTime != null ? disp.endNanos : Long.MAX_VALUE;
while (!isClosed()) {
emitMetadataEvent(currentParser);
onMetadata(currentParser);
while (!isClosed() && !currentParser.isChunkFinished()) {
disp = dispatcher();
if (disp != lastDisp) {
@ -151,7 +151,6 @@ public class EventDirectoryStream extends AbstractEventStream {
pc.filterStart = filterStart;
pc.filterEnd = filterEnd;
currentParser.updateConfiguration(pc, true);
currentParser.setFlushOperation(getFlushOperation());
lastDisp = disp;
}
if (disp.parserConfiguration.isOrdered()) {
@ -221,9 +220,10 @@ public class EventDirectoryStream extends AbstractEventStream {
}
sortedCache[index++] = e;
}
emitMetadataEvent(currentParser);
onMetadata(currentParser);
// no events found
if (index == 0 && currentParser.isChunkFinished()) {
onFlush();
return;
}
// at least 2 events, sort them
@ -233,6 +233,7 @@ public class EventDirectoryStream extends AbstractEventStream {
for (int i = 0; i < index; i++) {
c.dispatch(sortedCache[i]);
}
onFlush();
return;
}
@ -240,11 +241,11 @@ public class EventDirectoryStream extends AbstractEventStream {
while (true) {
RecordedEvent e = currentParser.readStreamingEvent();
if (e == null) {
emitMetadataEvent(currentParser);
onFlush();
return true;
} else {
c.dispatch(e);
}
onMetadata(currentParser);
c.dispatch(e);
}
}

View File

@ -28,6 +28,7 @@ package jdk.jfr.internal.consumer;
import java.io.IOException;
import java.nio.file.Path;
import java.security.AccessControlContext;
import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
@ -87,7 +88,7 @@ public final class EventFileStream extends AbstractEventStream {
currentParser = new ChunkParser(input, disp.parserConfiguration);
while (!isClosed()) {
emitMetadataEvent(currentParser);
onMetadata(currentParser);
if (currentParser.getStartNanos() > end) {
close();
return;
@ -96,7 +97,6 @@ public final class EventFileStream extends AbstractEventStream {
disp.parserConfiguration.filterStart = start;
disp.parserConfiguration.filterEnd = end;
currentParser.updateConfiguration(disp.parserConfiguration, true);
currentParser.setFlushOperation(getFlushOperation());
if (disp.parserConfiguration.isOrdered()) {
processOrdered(disp);
} else {
@ -116,46 +116,42 @@ public final class EventFileStream extends AbstractEventStream {
}
RecordedEvent event;
int index = 0;
while (true) {
event = currentParser.readEvent();
if (event == Dispatcher.FLUSH_MARKER) {
emitMetadataEvent(currentParser);
dispatchOrdered(c, index);
index = 0;
continue;
while (!currentParser.isChunkFinished()) {
while ((event = currentParser.readStreamingEvent()) != null) {
if (index == cacheSorted.length) {
RecordedEvent[] tmp = cacheSorted;
cacheSorted = new RecordedEvent[2 * tmp.length];
System.arraycopy(tmp, 0, cacheSorted, 0, tmp.length);
}
cacheSorted[index++] = event;
}
if (event == null) {
emitMetadataEvent(currentParser);
dispatchOrdered(c, index);
return;
}
if (index == cacheSorted.length) {
RecordedEvent[] tmp = cacheSorted;
cacheSorted = new RecordedEvent[2 * tmp.length];
System.arraycopy(tmp, 0, cacheSorted, 0, tmp.length);
}
cacheSorted[index++] = event;
dispatchOrdered(c, index);
index = 0;
}
}
private void dispatchOrdered(Dispatcher c, int index) {
onMetadata(currentParser);
Arrays.sort(cacheSorted, 0, index, EVENT_COMPARATOR);
for (int i = 0; i < index; i++) {
c.dispatch(cacheSorted[i]);
}
onFlush();
}
private void processUnordered(Dispatcher c) throws IOException {
onMetadata(currentParser);
while (!isClosed()) {
RecordedEvent event = currentParser.readEvent();
RecordedEvent event = currentParser.readStreamingEvent();
if (event == null) {
emitMetadataEvent(currentParser);
return;
}
if (event != Dispatcher.FLUSH_MARKER) {
c.dispatch(event);
onFlush();
if (currentParser.isChunkFinished()) {
return;
}
continue;
}
onMetadata(currentParser);
c.dispatch(event);
}
}
}