This is an automated email from the ASF dual-hosted git repository. ifesdjeen pushed a commit to branch trunk in repository https://gitbox.apache.org/repos/asf/cassandra-in-jvm-dtest-api.git
The following commit(s) were added to refs/heads/trunk by this push: new acaabaf Add support for JMX acaabaf is described below commit acaabaf87928442c9d8a8741deac11b5a590f1d8 Author: Doug Rohrer <d...@therohrers.org> AuthorDate: Tue May 9 11:21:54 2023 -0400 Add support for JMX Additionally, adds some code to help clean up the InstanceClassLoader more efficiently and may be helpful for future features, even though it is not necessary for this set of changes. --- .../apache/cassandra/distributed/api/Feature.java | 2 +- .../cassandra/distributed/api/IInstanceConfig.java | 2 + .../distributed/shared/InstanceClassLoader.java | 61 +++++++++++++++++++++- 3 files changed, 63 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/apache/cassandra/distributed/api/Feature.java b/src/main/java/org/apache/cassandra/distributed/api/Feature.java index 6ba4a43..ad53355 100644 --- a/src/main/java/org/apache/cassandra/distributed/api/Feature.java +++ b/src/main/java/org/apache/cassandra/distributed/api/Feature.java @@ -20,5 +20,5 @@ package org.apache.cassandra.distributed.api; public enum Feature { - NETWORK, GOSSIP, NATIVE_PROTOCOL, BLANK_GOSSIP + NETWORK, GOSSIP, NATIVE_PROTOCOL, BLANK_GOSSIP, JMX } diff --git a/src/main/java/org/apache/cassandra/distributed/api/IInstanceConfig.java b/src/main/java/org/apache/cassandra/distributed/api/IInstanceConfig.java index f88e761..36c741a 100644 --- a/src/main/java/org/apache/cassandra/distributed/api/IInstanceConfig.java +++ b/src/main/java/org/apache/cassandra/distributed/api/IInstanceConfig.java @@ -47,6 +47,8 @@ public interface IInstanceConfig String localDatacenter(); + int jmxPort(); + /** * write the specified parameters to the Config object; we do not specify Config as the type to support a Config * from any ClassLoader; the implementation must not directly access any fields of the Object, or cast it, but diff --git a/src/main/java/org/apache/cassandra/distributed/shared/InstanceClassLoader.java b/src/main/java/org/apache/cassandra/distributed/shared/InstanceClassLoader.java index 7420f5e..e41b6cc 100644 --- a/src/main/java/org/apache/cassandra/distributed/shared/InstanceClassLoader.java +++ b/src/main/java/org/apache/cassandra/distributed/shared/InstanceClassLoader.java @@ -22,6 +22,8 @@ import org.apache.cassandra.distributed.api.IClassTransformer; import java.io.IOException; import java.io.InputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.net.JarURLConnection; import java.net.URL; import java.net.URLClassLoader; @@ -29,7 +31,8 @@ import java.net.URLConnection; import java.security.CodeSigner; import java.security.CodeSource; import java.util.Arrays; -import java.util.function.BiFunction; +import java.util.List; +import java.util.Map; import java.util.function.Predicate; import java.util.jar.Manifest; @@ -217,5 +220,61 @@ public class InstanceClassLoader extends URLClassLoader { isClosed = true; super.close(); + try + { + // The JVM really wants to prevent Class instances from being GCed until the + // classloader which loaded them is GCed. It therefore maintains a list + // of Class instances for the sole purpose of providing a GC root for them. + // Here, we actually want the class instances to be GCed even if this classloader + // somehow gets stuck with a GC root, so we clear the class list via reflection. + // The current features implemented technically work without this, but the Garbage + // Collector works more efficiently with it here, and it may provide value to new + // feature developers. + Field f = getField(ClassLoader.class, "classes"); + f.setAccessible(true); + List<Class<?>> classes = (List<Class<?>>) f.get(this); + classes.clear(); + // Same problem with packages - without clearing this, + // the instance classloader can't unload + f = getField(ClassLoader.class, "packages"); + f.setAccessible(true); + Map<?,?> packageMap = (Map<?, ?>) f.get(this); + packageMap.clear(); + } + catch (Throwable e) + { + throw new RuntimeException(e); + } + } + + public static Field getField(Class<?> clazz, String fieldName) throws NoSuchFieldException + { + // below code works before Java 12 + try + { + return clazz.getDeclaredField(fieldName); + } + catch (NoSuchFieldException e) + { + // this is mitigation for JDK 17 (https://bugs.openjdk.org/browse/JDK-8210522) + try + { + Method getDeclaredFields0 = Class.class.getDeclaredMethod("getDeclaredFields0", boolean.class); + getDeclaredFields0.setAccessible(true); + Field[] fields = (Field[]) getDeclaredFields0.invoke(clazz, false); + for (Field field : fields) + { + if (fieldName.equals(field.getName())) + { + return field; + } + } + } + catch (ReflectiveOperationException ex) + { + e.addSuppressed(ex); + } + throw e; + } } } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org For additional commands, e-mail: commits-h...@cassandra.apache.org