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

Reply via email to