Skip to content

Commit

Permalink
[#2886] Use parallel function for ClassLoader when using JDK7+
Browse files Browse the repository at this point in the history
  • Loading branch information
koo-taejin committed May 2, 2017
1 parent ba33263 commit 0c570a0
Show file tree
Hide file tree
Showing 12 changed files with 364 additions and 18 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 2017 NAVER Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.navercorp.pinpoint.bootstrap.classloader;

import java.net.URL;
import java.net.URLClassLoader;

/**
* @author Taejin Koo
*/
class ParallelCapablePinpointClassLoaderFactory implements InnerPinpointClassLoaderFactory {

@Override
public URLClassLoader createURLClassLoader(URL[] urls, ClassLoader parent) {
return new ParallelCapablePinpointURLClassLoader(urls, parent);
}

@Override
public URLClassLoader createURLClassLoader(URL[] urls, ClassLoader parent, LibClass libClass) {
return new ParallelCapablePinpointURLClassLoader(urls, parent, libClass);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright 2017 NAVER Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.navercorp.pinpoint.bootstrap.classloader;

import java.net.URL;
import java.net.URLClassLoader;

/**
* @author Taejin Koo
*/
class ParallelCapablePinpointURLClassLoader extends URLClassLoader {

private static final LibClass PROFILER_LIB_CLASS = new ProfilerLibClass();

private final ClassLoader parent;

private final LibClass libClass;

static {
ClassLoader.registerAsParallelCapable();
}

public ParallelCapablePinpointURLClassLoader(URL[] urls, ClassLoader parent) {
this(urls, parent, PROFILER_LIB_CLASS);
}

public ParallelCapablePinpointURLClassLoader(URL[] urls, ClassLoader parent, LibClass libClass) {
super(urls, parent);

if (parent == null) {
throw new NullPointerException("parent must not be null");
}
if (libClass == null) {
throw new NullPointerException("libClass must not be null");
}

this.parent = parent;
this.libClass = libClass;
}

@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class clazz = findLoadedClass(name);
if (clazz == null) {
if (onLoadClass(name)) {
// load a class used for Pinpoint itself by this PinpointURLClassLoader
clazz = findClass(name);
} else {
try {
// load a class by parent ClassLoader
clazz = parent.loadClass(name);
} catch (ClassNotFoundException ignore) {
}
if (clazz == null) {
// if not found, try to load a class by this PinpointURLClassLoader
clazz = findClass(name);
}
}
}
if (resolve) {
resolveClass(clazz);
}
return clazz;
}
}

// for test
boolean onLoadClass(String name) {
return libClass.onLoadClass(name);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.navercorp.pinpoint.bootstrap.classloader;

import org.junit.Assert;
import org.junit.Test;

import java.net.URL;
import java.net.URLClassLoader;

/**
* @author Taejin Koo
*/
public class ParallelCapablePinpointURLClassLoaderTest {

@Test
public void testOnLoadClass() throws Exception {

URLClassLoader cl = PinpointClassLoaderFactory.createClassLoader(new URL[]{}, Thread.currentThread().getContextClassLoader());

try {
cl.loadClass("test");
Assert.fail();
} catch (ClassNotFoundException ignored) {
}

// try {
// cl.loadClass("com.navercorp.pinpoint.profiler.DefaultAgent");
// } catch (ClassNotFoundException e) {
//
// }
// should be able to test using the above code, but it is not possible from bootstrap testcase.
// it could be possible by specifying the full path to the URL classloader, but it would be harder to maintain.
// for now, just test if DefaultAgent is specified to be loaded

if (cl instanceof ParallelCapablePinpointURLClassLoader) {
Assert.assertTrue(((ParallelCapablePinpointURLClassLoader) cl).onLoadClass("com.navercorp.pinpoint.profiler.DefaultAgent"));
} else {
Assert.fail();
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 2017 NAVER Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.navercorp.pinpoint.bootstrap.classloader;

import java.net.URL;
import java.net.URLClassLoader;

/**
* @author Taejin Koo
*/
class DefaultPinpointClassLoaderFactory implements InnerPinpointClassLoaderFactory {

@Override
public URLClassLoader createURLClassLoader(URL[] urls, ClassLoader parent) {
return new PinpointURLClassLoader(urls, parent);
}

@Override
public URLClassLoader createURLClassLoader(URL[] urls, ClassLoader parent, LibClass libClass) {
return new PinpointURLClassLoader(urls, parent, libClass);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright 2017 NAVER Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.navercorp.pinpoint.bootstrap.classloader;

import java.net.URL;
import java.net.URLClassLoader;

/**
* @author Taejin Koo
*/
interface InnerPinpointClassLoaderFactory {

URLClassLoader createURLClassLoader(URL[] urls, ClassLoader parent);

URLClassLoader createURLClassLoader(URL[] urls, ClassLoader parent, LibClass libClass);

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package com.navercorp.pinpoint.bootstrap;
package com.navercorp.pinpoint.bootstrap.classloader;

/**
* @author emeroad
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Copyright 2017 NAVER Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.navercorp.pinpoint.bootstrap.classloader;

import com.navercorp.pinpoint.bootstrap.logging.PLogger;
import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory;
import com.navercorp.pinpoint.common.util.JvmUtils;
import com.navercorp.pinpoint.common.util.JvmVersion;

import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

/**
* @author Taejin Koo
*/
public final class PinpointClassLoaderFactory {

private static final PLogger LOGGER = PLoggerFactory.getLogger(PinpointClassLoaderFactory.class);

private static final InnerPinpointClassLoaderFactory CLASS_LOADER_FACTORY = createClassLoaderFactory();

// Jdk 7+
private static final String PARALLEL_CAPABLE_CLASS_LOADER_FACTORY = "com.navercorp.pinpoint.bootstrap.classloader.ParallelCapablePinpointClassLoaderFactory";

private PinpointClassLoaderFactory() {
throw new IllegalAccessError();
}

private static InnerPinpointClassLoaderFactory createClassLoaderFactory() {
final JvmVersion jvmVersion = JvmUtils.getVersion();
if (jvmVersion == JvmVersion.JAVA_6) {
return new DefaultPinpointClassLoaderFactory();
} else if (jvmVersion.onOrAfter(JvmVersion.JAVA_7)) {
boolean hasRegisterAsParallelCapableMethod = hasRegisterAsParallelCapableMethod();
if (hasRegisterAsParallelCapableMethod) {
try {
ClassLoader classLoader = getClassLoader(PinpointClassLoaderFactory.class.getClassLoader());
final Class<? extends InnerPinpointClassLoaderFactory> parallelCapableClassLoaderFactoryClass =
(Class<? extends InnerPinpointClassLoaderFactory>) Class.forName(PARALLEL_CAPABLE_CLASS_LOADER_FACTORY, true, classLoader);
return parallelCapableClassLoaderFactoryClass.newInstance();
} catch (ClassNotFoundException e) {
logError(e);
} catch (InstantiationException e) {
logError(e);
} catch (IllegalAccessException e) {
logError(e);
}
return new DefaultPinpointClassLoaderFactory();
} else {
return new DefaultPinpointClassLoaderFactory();
}
} else {
throw new RuntimeException("Unsupported jvm version " + jvmVersion);
}
}

private static boolean hasRegisterAsParallelCapableMethod() {
Method[] methods = ClassLoader.class.getDeclaredMethods();
for (Method method : methods) {
if (method.getName().equals("registerAsParallelCapable")) {
return true;
}
}

return false;
}

private static ClassLoader getClassLoader(ClassLoader classLoader) {
if (classLoader == null) {
return ClassLoader.getSystemClassLoader();
}
return classLoader;
}

private static void logError(Exception e) {
LOGGER.info("ParallelCapablePinpointClassLoader not found.");
}

public static URLClassLoader createClassLoader(URL[] urls, ClassLoader parent) {
return CLASS_LOADER_FACTORY.createURLClassLoader(urls, parent);
}

public static URLClassLoader createClassLoader(URL[] urls, ClassLoader parent, LibClass libClass) {
return CLASS_LOADER_FACTORY.createURLClassLoader(urls, parent, libClass);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package com.navercorp.pinpoint.bootstrap;
package com.navercorp.pinpoint.bootstrap.classloader;

import java.net.URL;
import java.net.URLClassLoader;
Expand All @@ -36,12 +36,14 @@ public class PinpointURLClassLoader extends URLClassLoader {

public PinpointURLClassLoader(URL[] urls, ClassLoader parent, LibClass libClass) {
super(urls, parent);

if (parent == null) {
throw new NullPointerException("parent must not be null");
}
if (libClass == null) {
throw new NullPointerException("libClass must not be null");
}

this.parent = parent;
this.libClass = libClass;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package com.navercorp.pinpoint.bootstrap;
package com.navercorp.pinpoint.bootstrap.classloader;

/**
* @author emeroad
Expand Down
Loading

0 comments on commit 0c570a0

Please sign in to comment.