8234671: JFR api/consumer/recordingstream/TestStart.java failed due to timeout at testStartTwice()
Reviewed-by: mgronlun
This commit is contained in:
parent
7b02e24b65
commit
b3ea416824
@ -76,9 +76,10 @@ abstract class AbstractEventStream implements EventStream {
|
|||||||
abstract public void close();
|
abstract public void close();
|
||||||
|
|
||||||
protected final Dispatcher dispatcher() {
|
protected final Dispatcher dispatcher() {
|
||||||
if (configuration.hasChanged()) {
|
if (configuration.hasChanged()) { // quick check
|
||||||
synchronized (configuration) {
|
synchronized (configuration) {
|
||||||
dispatcher = new Dispatcher(configuration);
|
dispatcher = new Dispatcher(configuration);
|
||||||
|
configuration.setChanged(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return dispatcher;
|
return dispatcher;
|
||||||
|
@ -190,44 +190,40 @@ public final class ChunkParser {
|
|||||||
*
|
*
|
||||||
* @param awaitNewEvents wait for new data.
|
* @param awaitNewEvents wait for new data.
|
||||||
*/
|
*/
|
||||||
RecordedEvent readStreamingEvent(boolean awaitNewEvents) throws IOException {
|
RecordedEvent readStreamingEvent() throws IOException {
|
||||||
long absoluteChunkEnd = chunkHeader.getEnd();
|
long absoluteChunkEnd = chunkHeader.getEnd();
|
||||||
while (true) {
|
RecordedEvent event = readEvent();
|
||||||
RecordedEvent event = readEvent();
|
if (event != null) {
|
||||||
if (event != null) {
|
return event;
|
||||||
return event;
|
|
||||||
}
|
|
||||||
if (!awaitNewEvents) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
long lastValid = absoluteChunkEnd;
|
|
||||||
long metadataPoistion = chunkHeader.getMetataPosition();
|
|
||||||
long contantPosition = chunkHeader.getConstantPoolPosition();
|
|
||||||
chunkFinished = awaitUpdatedHeader(absoluteChunkEnd, configuration.filterEnd);
|
|
||||||
if (chunkFinished) {
|
|
||||||
Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "At chunk end");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
absoluteChunkEnd = chunkHeader.getEnd();
|
|
||||||
// Read metadata and constant pools for the next segment
|
|
||||||
if (chunkHeader.getMetataPosition() != metadataPoistion) {
|
|
||||||
Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Found new metadata in chunk. Rebuilding types and parsers");
|
|
||||||
MetadataDescriptor metadata = chunkHeader.readMetadata(previousMetadata);
|
|
||||||
ParserFactory factory = new ParserFactory(metadata, constantLookups, timeConverter);
|
|
||||||
parsers = factory.getParsers();
|
|
||||||
typeMap = factory.getTypeMap();
|
|
||||||
updateConfiguration();;
|
|
||||||
}
|
|
||||||
if (contantPosition != chunkHeader.getConstantPoolPosition()) {
|
|
||||||
Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Found new constant pool data. Filling up pools with new values");
|
|
||||||
constantLookups.forEach(c -> c.getLatestPool().setAllResolved(false));
|
|
||||||
fillConstantPools(contantPosition + chunkHeader.getAbsoluteChunkStart());
|
|
||||||
constantLookups.forEach(c -> c.getLatestPool().setResolving());
|
|
||||||
constantLookups.forEach(c -> c.getLatestPool().resolve());
|
|
||||||
constantLookups.forEach(c -> c.getLatestPool().setResolved());
|
|
||||||
}
|
|
||||||
input.position(lastValid);
|
|
||||||
}
|
}
|
||||||
|
long lastValid = absoluteChunkEnd;
|
||||||
|
long metadataPosition = chunkHeader.getMetataPosition();
|
||||||
|
long contantPosition = chunkHeader.getConstantPoolPosition();
|
||||||
|
chunkFinished = awaitUpdatedHeader(absoluteChunkEnd, configuration.filterEnd);
|
||||||
|
if (chunkFinished) {
|
||||||
|
Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "At chunk end");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
absoluteChunkEnd = chunkHeader.getEnd();
|
||||||
|
// Read metadata and constant pools for the next segment
|
||||||
|
if (chunkHeader.getMetataPosition() != metadataPosition) {
|
||||||
|
Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Found new metadata in chunk. Rebuilding types and parsers");
|
||||||
|
MetadataDescriptor metadata = chunkHeader.readMetadata(previousMetadata);
|
||||||
|
ParserFactory factory = new ParserFactory(metadata, constantLookups, timeConverter);
|
||||||
|
parsers = factory.getParsers();
|
||||||
|
typeMap = factory.getTypeMap();
|
||||||
|
updateConfiguration();
|
||||||
|
}
|
||||||
|
if (contantPosition != chunkHeader.getConstantPoolPosition()) {
|
||||||
|
Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Found new constant pool data. Filling up pools with new values");
|
||||||
|
constantLookups.forEach(c -> c.getLatestPool().setAllResolved(false));
|
||||||
|
fillConstantPools(contantPosition + chunkHeader.getAbsoluteChunkStart());
|
||||||
|
constantLookups.forEach(c -> c.getLatestPool().setResolving());
|
||||||
|
constantLookups.forEach(c -> c.getLatestPool().resolve());
|
||||||
|
constantLookups.forEach(c -> c.getLatestPool().setResolved());
|
||||||
|
}
|
||||||
|
input.position(lastValid);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -105,8 +105,8 @@ public class EventDirectoryStream extends AbstractEventStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void processRecursionSafe() throws IOException {
|
protected void processRecursionSafe() throws IOException {
|
||||||
|
Dispatcher lastDisp = null;
|
||||||
Dispatcher disp = dispatcher();
|
Dispatcher disp = dispatcher();
|
||||||
|
|
||||||
Path path;
|
Path path;
|
||||||
boolean validStartTime = recording != null || disp.startTime != null;
|
boolean validStartTime = recording != null || disp.startTime != null;
|
||||||
if (validStartTime) {
|
if (validStartTime) {
|
||||||
@ -125,18 +125,20 @@ public class EventDirectoryStream extends AbstractEventStream {
|
|||||||
long filterEnd = disp.endTime != null ? disp.endNanos: Long.MAX_VALUE;
|
long filterEnd = disp.endTime != null ? disp.endNanos: Long.MAX_VALUE;
|
||||||
|
|
||||||
while (!isClosed()) {
|
while (!isClosed()) {
|
||||||
boolean awaitnewEvent = false;
|
|
||||||
while (!isClosed() && !currentParser.isChunkFinished()) {
|
while (!isClosed() && !currentParser.isChunkFinished()) {
|
||||||
disp = dispatcher();
|
disp = dispatcher();
|
||||||
ParserConfiguration pc = disp.parserConfiguration;
|
if (disp != lastDisp) {
|
||||||
pc.filterStart = filterStart;
|
ParserConfiguration pc = disp.parserConfiguration;
|
||||||
pc.filterEnd = filterEnd;
|
pc.filterStart = filterStart;
|
||||||
currentParser.updateConfiguration(pc, true);
|
pc.filterEnd = filterEnd;
|
||||||
currentParser.setFlushOperation(getFlushOperation());
|
currentParser.updateConfiguration(pc, true);
|
||||||
if (pc.isOrdered()) {
|
currentParser.setFlushOperation(getFlushOperation());
|
||||||
awaitnewEvent = processOrdered(disp, awaitnewEvent);
|
lastDisp = disp;
|
||||||
|
}
|
||||||
|
if (disp.parserConfiguration.isOrdered()) {
|
||||||
|
processOrdered(disp);
|
||||||
} else {
|
} else {
|
||||||
awaitnewEvent = processUnordered(disp, awaitnewEvent);
|
processUnordered(disp);
|
||||||
}
|
}
|
||||||
if (currentParser.getStartNanos() + currentParser.getChunkDuration() > filterEnd) {
|
if (currentParser.getStartNanos() + currentParser.getChunkDuration() > filterEnd) {
|
||||||
close();
|
close();
|
||||||
@ -182,29 +184,24 @@ public class EventDirectoryStream extends AbstractEventStream {
|
|||||||
return recording.getFinalChunkStartNanos() >= currentParser.getStartNanos();
|
return recording.getFinalChunkStartNanos() >= currentParser.getStartNanos();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean processOrdered(Dispatcher c, boolean awaitNewEvents) throws IOException {
|
private void processOrdered(Dispatcher c) throws IOException {
|
||||||
if (sortedCache == null) {
|
if (sortedCache == null) {
|
||||||
sortedCache = new RecordedEvent[100_000];
|
sortedCache = new RecordedEvent[100_000];
|
||||||
}
|
}
|
||||||
int index = 0;
|
int index = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
RecordedEvent e = currentParser.readStreamingEvent(awaitNewEvents);
|
RecordedEvent e = currentParser.readStreamingEvent();
|
||||||
if (e == null) {
|
if (e == null) {
|
||||||
// wait for new event with next call to
|
|
||||||
// readStreamingEvent()
|
|
||||||
awaitNewEvents = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
awaitNewEvents = false;
|
|
||||||
if (index == sortedCache.length) {
|
if (index == sortedCache.length) {
|
||||||
sortedCache = Arrays.copyOf(sortedCache, sortedCache.length * 2);
|
sortedCache = Arrays.copyOf(sortedCache, sortedCache.length * 2);
|
||||||
}
|
}
|
||||||
sortedCache[index++] = e;
|
sortedCache[index++] = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
// no events found
|
// no events found
|
||||||
if (index == 0 && currentParser.isChunkFinished()) {
|
if (index == 0 && currentParser.isChunkFinished()) {
|
||||||
return awaitNewEvents;
|
return;
|
||||||
}
|
}
|
||||||
// at least 2 events, sort them
|
// at least 2 events, sort them
|
||||||
if (index > 1) {
|
if (index > 1) {
|
||||||
@ -213,12 +210,12 @@ public class EventDirectoryStream extends AbstractEventStream {
|
|||||||
for (int i = 0; i < index; i++) {
|
for (int i = 0; i < index; i++) {
|
||||||
c.dispatch(sortedCache[i]);
|
c.dispatch(sortedCache[i]);
|
||||||
}
|
}
|
||||||
return awaitNewEvents;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean processUnordered(Dispatcher c, boolean awaitNewEvents) throws IOException {
|
private boolean processUnordered(Dispatcher c) throws IOException {
|
||||||
while (true) {
|
while (true) {
|
||||||
RecordedEvent e = currentParser.readStreamingEvent(awaitNewEvents);
|
RecordedEvent e = currentParser.readStreamingEvent();
|
||||||
if (e == null) {
|
if (e == null) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -121,4 +121,8 @@ final class StreamConfiguration {
|
|||||||
public boolean hasChanged() {
|
public boolean hasChanged() {
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setChanged(boolean changed) {
|
||||||
|
this.changed = changed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,9 +26,7 @@
|
|||||||
package jdk.jfr.api.consumer.recordingstream;
|
package jdk.jfr.api.consumer.recordingstream;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import jdk.jfr.Event;
|
import jdk.jfr.Event;
|
||||||
@ -41,7 +39,7 @@ import jdk.jfr.consumer.RecordingStream;
|
|||||||
* @summary Tests RecordingStream::close()
|
* @summary Tests RecordingStream::close()
|
||||||
* @key jfr
|
* @key jfr
|
||||||
* @requires vm.hasJFR
|
* @requires vm.hasJFR
|
||||||
* @library /test/lib
|
* @library /test/lib /test/jdk
|
||||||
* @run main/othervm jdk.jfr.api.consumer.recordingstream.TestClose
|
* @run main/othervm jdk.jfr.api.consumer.recordingstream.TestClose
|
||||||
*/
|
*/
|
||||||
public class TestClose {
|
public class TestClose {
|
||||||
@ -58,96 +56,82 @@ public class TestClose {
|
|||||||
testCloseNoEvents();
|
testCloseNoEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void testCloseMySelf() throws Exception {
|
private static void testCloseUnstarted() {
|
||||||
log("Entering testCloseMySelf()");
|
System.out.println("testCloseUnstarted()");
|
||||||
CountDownLatch l1 = new CountDownLatch(1);
|
|
||||||
CountDownLatch l2 = new CountDownLatch(1);
|
|
||||||
RecordingStream r = new RecordingStream();
|
|
||||||
r.onEvent(e -> {
|
|
||||||
try {
|
|
||||||
l1.await();
|
|
||||||
r.close();
|
|
||||||
l2.countDown();
|
|
||||||
} catch (InterruptedException ie) {
|
|
||||||
throw new Error(ie);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
r.startAsync();
|
|
||||||
CloseEvent c = new CloseEvent();
|
|
||||||
c.commit();
|
|
||||||
l1.countDown();
|
|
||||||
l2.await();
|
|
||||||
log("Leaving testCloseMySelf()");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void testCloseStreaming() throws Exception {
|
try (RecordingStream r = new RecordingStream()) {
|
||||||
log("Entering testCloseStreaming()");
|
r.close();
|
||||||
CountDownLatch streaming = new CountDownLatch(1);
|
}
|
||||||
RecordingStream r = new RecordingStream();
|
|
||||||
AtomicLong count = new AtomicLong();
|
|
||||||
r.onEvent(e -> {
|
|
||||||
if (count.incrementAndGet() > 100) {
|
|
||||||
streaming.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
r.startAsync();
|
|
||||||
var streamingLoop = CompletableFuture.runAsync(() -> {
|
|
||||||
while (true) {
|
|
||||||
CloseEvent c = new CloseEvent();
|
|
||||||
c.commit();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
streaming.await();
|
|
||||||
r.close();
|
|
||||||
streamingLoop.cancel(true);
|
|
||||||
log("Leaving testCloseStreaming()");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void testCloseStarted() {
|
private static void testCloseStarted() {
|
||||||
log("Entering testCloseStarted()");
|
System.out.println("testCloseStarted()");
|
||||||
RecordingStream r = new RecordingStream();
|
|
||||||
r.startAsync();
|
|
||||||
r.close();
|
|
||||||
log("Leaving testCloseStarted()");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void testCloseUnstarted() {
|
try (RecordingStream r = new RecordingStream()) {
|
||||||
log("Entering testCloseUnstarted()");
|
r.startAsync();
|
||||||
RecordingStream r = new RecordingStream();
|
} // <- Close
|
||||||
r.close();
|
|
||||||
log("Leaving testCloseUnstarted()");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void testCloseTwice() {
|
private static void testCloseTwice() {
|
||||||
log("Entering testCloseTwice()");
|
System.out.println("Entering testCloseTwice()");
|
||||||
RecordingStream r = new RecordingStream();
|
|
||||||
r.startAsync();
|
try (RecordingStream r = new RecordingStream()) {
|
||||||
r.close();
|
r.startAsync();
|
||||||
r.close();
|
r.close();
|
||||||
log("Leaving testCloseTwice()");
|
} // <- Second close
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testCloseStreaming() throws Exception {
|
||||||
|
System.out.println("Entering testCloseStreaming()");
|
||||||
|
|
||||||
|
EventProducer p = new EventProducer();
|
||||||
|
p.start();
|
||||||
|
CountDownLatch streaming = new CountDownLatch(1);
|
||||||
|
try (RecordingStream r = new RecordingStream()) {
|
||||||
|
r.onEvent(e -> {
|
||||||
|
streaming.countDown();
|
||||||
|
});
|
||||||
|
r.startAsync();
|
||||||
|
streaming.await();
|
||||||
|
} // <- Close
|
||||||
|
p.kill();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testCloseMySelf() throws Exception {
|
||||||
|
System.out.println("testCloseMySelf()");
|
||||||
|
|
||||||
|
CountDownLatch closed = new CountDownLatch(1);
|
||||||
|
try (RecordingStream r = new RecordingStream()) {
|
||||||
|
r.onEvent(e -> {
|
||||||
|
r.close(); // <- Close
|
||||||
|
closed.countDown();
|
||||||
|
});
|
||||||
|
r.startAsync();
|
||||||
|
CloseEvent c = new CloseEvent();
|
||||||
|
c.commit();
|
||||||
|
closed.await();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void testCloseNoEvents() throws Exception {
|
private static void testCloseNoEvents() throws Exception {
|
||||||
|
System.out.println("testCloseNoEvents()");
|
||||||
|
|
||||||
try (Recording r = new Recording()) {
|
try (Recording r = new Recording()) {
|
||||||
r.start();
|
r.start();
|
||||||
CountDownLatch finished = new CountDownLatch(2);
|
CountDownLatch finished = new CountDownLatch(2);
|
||||||
AtomicReference<Thread> streamingThread = new AtomicReference<>();
|
AtomicReference<Thread> streamingThread = new AtomicReference<>();
|
||||||
try (EventStream es = EventStream.openRepository()) {
|
try (EventStream es = EventStream.openRepository()) {
|
||||||
es.setStartTime(Instant.EPOCH);
|
es.setStartTime(Instant.EPOCH);
|
||||||
es.onFlush( () -> {
|
es.onFlush(() -> {
|
||||||
streamingThread.set(Thread.currentThread());
|
streamingThread.set(Thread.currentThread());
|
||||||
finished.countDown();;
|
finished.countDown();
|
||||||
});
|
});
|
||||||
es.startAsync();
|
es.startAsync();
|
||||||
finished.await();
|
finished.await();
|
||||||
} // <- EventStream::close should terminate thread
|
} // <- Close should terminate thread
|
||||||
while (streamingThread.get().isAlive()) {
|
while (streamingThread.get().isAlive()) {
|
||||||
Thread.sleep(10);
|
Thread.sleep(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void log(String msg) {
|
|
||||||
System.out.println(msg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ import jdk.jfr.consumer.RecordingStream;
|
|||||||
* @summary Tests RecordingStream::onEvent(...)
|
* @summary Tests RecordingStream::onEvent(...)
|
||||||
* @key jfr
|
* @key jfr
|
||||||
* @requires vm.hasJFR
|
* @requires vm.hasJFR
|
||||||
* @library /test/lib
|
* @library /test/lib /test/jdk
|
||||||
* @run main/othervm jdk.jfr.api.consumer.recordingstream.TestOnEvent
|
* @run main/othervm jdk.jfr.api.consumer.recordingstream.TestOnEvent
|
||||||
*/
|
*/
|
||||||
public class TestOnEvent {
|
public class TestOnEvent {
|
||||||
@ -58,6 +58,7 @@ public class TestOnEvent {
|
|||||||
testOnEvent();
|
testOnEvent();
|
||||||
testNamedEvent();
|
testNamedEvent();
|
||||||
testTwoEventWithSameName();
|
testTwoEventWithSameName();
|
||||||
|
testOnEventAfterStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void testOnEventNull() {
|
private static void testOnEventNull() {
|
||||||
@ -149,6 +150,29 @@ public class TestOnEvent {
|
|||||||
log("Leaving testOnEvent()");
|
log("Leaving testOnEvent()");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void testOnEventAfterStart() {
|
||||||
|
try (RecordingStream r = new RecordingStream()) {
|
||||||
|
EventProducer p = new EventProducer();
|
||||||
|
p.start();
|
||||||
|
Thread addHandler = new Thread(() -> {
|
||||||
|
r.onEvent(e -> {
|
||||||
|
// Got event, close stream
|
||||||
|
r.close();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
r.onFlush(() -> {
|
||||||
|
// Only add handler once
|
||||||
|
if (!"started".equals(addHandler.getName())) {
|
||||||
|
addHandler.setName("started");
|
||||||
|
addHandler.start();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
r.start();
|
||||||
|
p.kill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private static void log(String msg) {
|
private static void log(String msg) {
|
||||||
System.out.println(msg);
|
System.out.println(msg);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user