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 c8a223d Add support for JMX
c8a223d is described below
commit c8a223dc28f036307ae0a50755b2623a9017f200
Author: Doug Rohrer <[email protected]>
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: [email protected]
For additional commands, e-mail: [email protected]