Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Oracle JDK8 support #2551

Merged
merged 4 commits into from
Apr 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,30 @@ public class Agent {
private static ClassLoader AGENT_CLASSLOADER = null;
private static ClassLoader JMXFETCH_CLASSLOADER = null;
private static ClassLoader PROFILING_CLASSLOADER = null;
private static volatile AgentTaskScheduler.Task<URL> PROFILER_INIT_AFTER_JMX = null;

public static void start(final Instrumentation inst, final URL bootstrapURL) {
createParentClassloader(bootstrapURL);

// Profiling agent startup code is written in a way to allow `startProfilingAgent` be called
// multiple times
// If early profiling is enabled then this call will start profiling.
// If early profiling is disabled then later call will do this.
startProfilingAgent(bootstrapURL, true);
if (!isOracleJDK8()) {
// Profiling agent startup code is written in a way to allow `startProfilingAgent` be called
// multiple times
// If early profiling is enabled then this call will start profiling.
// If early profiling is disabled then later call will do this.
startProfilingAgent(bootstrapURL, true);
} else {
log.debug("Oracle JDK 8 detected. Delaying profiler initialization.");
// Profiling can not run early on Oracle JDK 8 because it will cause JFR initialization
// deadlock.
// Oracle JDK 8 JFR controller requires JMX so register an 'after-jmx-initialized' callback.
PROFILER_INIT_AFTER_JMX =
new AgentTaskScheduler.Task<URL>() {
@Override
public void run(URL target) {
startProfilingAgent(target, false);
}
};
}

startDatadogAgent(inst, bootstrapURL);

Expand Down Expand Up @@ -121,27 +136,23 @@ public static void start(final Instrumentation inst, final URL bootstrapURL) {
}

/*
* Similar thing happens with Profiler:
* a) on zulu-8 because it is using OkHttp which indirectly loads JFR events which in turn loads LogManager. This is not a problem on newer JDKs because there JFR uses different logging facility.
* b) on Oracle JDK 8 because we need JMX to communicate with JFR engine and initializing JMX will cause an attempt to load LogManager.
* Similar thing happens with Profiler on zulu-8 because it is using OkHttp which indirectly loads JFR events which in turn loads LogManager. This is not a problem on newer JDKs because there JFR uses different logging facility.
*/
boolean shouldDelayProfilerStartup = false;
if (!isJavaVersionAtLeast(9)) {
if (appUsingCustomLogManager) {
log.debug("Custom logger detected. Delaying Profiling Agent startup.");
shouldDelayProfilerStartup = true;
}
if (System.getProperty("java.vendor").contains("Oracle")
&& !System.getProperty("java.runtime.name").contains("OpenJDK")) {
log.debug("Oracle JDK 8 detected. Delaying Profiling Agent startup");
shouldDelayProfilerStartup = true;
if (!isOracleJDK8()) {
if (!isJavaVersionAtLeast(9) && appUsingCustomLogManager) {
log.debug("Custom logger detected. Delaying JMXFetch initialization.");
registerLogManagerCallback(new StartProfilingAgentCallback(inst, bootstrapURL));
} else {
// Anything above 8 is OpenJDK implementation and is safe to run synchronously
startProfilingAgent(bootstrapURL, false);
}
}
if (shouldDelayProfilerStartup) {
registerLogManagerCallback(new StartProfilingAgentCallback(inst, bootstrapURL));
} else {
startProfilingAgent(bootstrapURL, false);
}
}

private static boolean isOracleJDK8() {
return !isJavaVersionAtLeast(9)
&& System.getProperty("java.vendor").contains("Oracle")
&& !System.getProperty("java.runtime.name").contains("OpenJDK");
}

private static void registerLogManagerCallback(final ClassLoadCallBack callback) {
Expand Down Expand Up @@ -343,6 +354,17 @@ private static synchronized void startJmx(final URL bootstrapURL) {
startJmxFetch(bootstrapURL);
initializeJmxSystemAccessProvider(AGENT_CLASSLOADER);
registerDeadlockDetectionEvent(bootstrapURL);
if (PROFILER_INIT_AFTER_JMX != null) {
if (getJmxStartDelay() == 0) {
log.debug("Waiting for profiler initialization");
AgentTaskScheduler.INSTANCE.scheduleWithJitter(
PROFILER_INIT_AFTER_JMX, bootstrapURL, 500, TimeUnit.MILLISECONDS);
} else {
log.debug("Initializing profiler");
PROFILER_INIT_AFTER_JMX.run(bootstrapURL);
}
PROFILER_INIT_AFTER_JMX = null;
}
}

private static synchronized void registerDeadlockDetectionEvent(URL bootstrapUrl) {
Expand Down Expand Up @@ -397,8 +419,7 @@ private static synchronized void startJmxFetch(final URL bootstrapURL) {
}
}

private static synchronized void startProfilingAgent(
final URL bootstrapURL, final boolean isStartingFirst) {
private static void startProfilingAgent(final URL bootstrapURL, final boolean isStartingFirst) {
final ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
try {
final ClassLoader classLoader = getProfilingClassloader(bootstrapURL);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ final class JfrMBeanHelper {
private final MBeanServer server;

private static void initialize() throws IOException {
log.warn("Initializing MBean helper");
log.debug("Initializing MBean helper");
if (initPhase.compareAndSet(0, 1)) {
registerMBeans();

Expand All @@ -129,7 +129,7 @@ private static void registerMBeans() throws IOException {
try {
try {
server.createMBean(MC_BEAN_CLASS, MC_BEAN_NAME);
log.warn("MissionControl MBean created");
log.debug("MissionControl MBean created");
} catch (InstanceAlreadyExistsException iaee) {
// Ok, it already exists.
} catch (MBeanException mbe) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public final class OracleJdkController implements Controller {
*/
public OracleJdkController(@Nonnull final Config config) throws ConfigurationException {
try {
log.debug("Initiating Oracle JFR controller");
log.debug("Initializing Oracle JFR controller");
helper = new JfrMBeanHelper();
eventSettings =
JfpUtils.readNamedJfpResource(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ public final void start() {
private void startProfilingRecording() {
try {
final Instant now = Instant.now();

log.debug("Initiating profiling recording");
recording = controller.createRecording(RECORDING_NAME);
scheduler.scheduleAtFixedRate(
SnapshotRecording::snapshot,
Expand Down Expand Up @@ -189,6 +189,7 @@ private final class SnapshotRecording {
public void snapshot() {
final RecordingType recordingType = RecordingType.CONTINUOUS;
try {
log.debug("Creating profiler snapshot");
final RecordingData recordingData = recording.snapshot(lastSnapshot, Instant.now());
// The hope here is that we do not get chunk rotated after taking snapshot and before we
// take this timestamp otherwise we will start losing data.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,16 @@ private void attemptWrite(@Nonnull InputStream inputStream, @Nonnull OutputStrea
throws IOException {
try (OutputStream sinkStream =
isCompressed(inputStream)
? outputStream
? new BufferedOutputStream(outputStream) {
@Override
public void close() throws IOException {
// Do not propagate close; call 'flush()' instead.
// Compression streams must be 'closed' because they finalize the
// compression
// in that method.
flush();
}
}
: new BufferedOutputStream(
outputStreamMapper.apply(
new BufferedOutputStream(outputStream) {
Expand Down
Loading