This is an automated email from the ASF dual-hosted git repository. jackietien pushed a commit to branch rc/2.0.8 in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit 6951a0c3c127f163c6a2b4fd926eb54efbad21a2 Author: CritasWang <[email protected]> AuthorDate: Thu Feb 12 18:24:27 2026 +0800 Fix external service ClassLoader context handling and dependency scope (#17202) --- distribution/pom.xml | 1 - external-service-impl/rest/pom.xml | 1 - iotdb-core/datanode/pom.xml | 4 --- .../view/visitor/TransformToExpressionVisitor.java | 21 ++++++------- .../ExternalServiceManagementService.java | 35 ++++++++++++++++------ .../iotdb/commons/externalservice/ServiceInfo.java | 9 ++++++ 6 files changed, 44 insertions(+), 27 deletions(-) diff --git a/distribution/pom.xml b/distribution/pom.xml index 65a3572fd3a..f4773f6afad 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -86,7 +86,6 @@ <descriptor>src/assembly/confignode.xml</descriptor> <descriptor>src/assembly/cli.xml</descriptor> <descriptor>src/assembly/library-udf.xml</descriptor> - <descriptor>src/assembly/external-service-impl.xml</descriptor> </descriptors> <finalName>apache-iotdb-${project.version}</finalName> </configuration> diff --git a/external-service-impl/rest/pom.xml b/external-service-impl/rest/pom.xml index edb8aa3fc33..a5a1d76a1b2 100644 --- a/external-service-impl/rest/pom.xml +++ b/external-service-impl/rest/pom.xml @@ -153,7 +153,6 @@ <dependency> <groupId>jakarta.ws.rs</groupId> <artifactId>jakarta.ws.rs-api</artifactId> - <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.iotdb</groupId> diff --git a/iotdb-core/datanode/pom.xml b/iotdb-core/datanode/pom.xml index 2ccae580549..8b530204896 100644 --- a/iotdb-core/datanode/pom.xml +++ b/iotdb-core/datanode/pom.xml @@ -223,10 +223,6 @@ <groupId>jakarta.validation</groupId> <artifactId>jakarta.validation-api</artifactId> </dependency> - <dependency> - <groupId>jakarta.ws.rs</groupId> - <artifactId>jakarta.ws.rs-api</artifactId> - </dependency> <dependency> <groupId>org.reflections</groupId> <artifactId>reflections</artifactId> diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/view/visitor/TransformToExpressionVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/view/visitor/TransformToExpressionVisitor.java index 8bedc236c27..0b3bce049c2 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/view/visitor/TransformToExpressionVisitor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/view/visitor/TransformToExpressionVisitor.java @@ -76,8 +76,6 @@ import org.apache.iotdb.db.queryengine.plan.expression.leaf.TimestampOperand; import org.apache.tsfile.utils.Pair; -import javax.ws.rs.NotSupportedException; - import java.util.ArrayList; import java.util.List; @@ -90,15 +88,14 @@ public class TransformToExpressionVisitor extends ViewExpressionVisitor<Expressi @Override public Expression visitExpression(ViewExpression expression, Void context) { - throw new RuntimeException( - new NotSupportedException( - "visitExpression in TransformToExpressionVisitor is not supported.")); + throw new UnsupportedOperationException( + "visitExpression in TransformToExpressionVisitor is not supported."); } // region leaf operand @Override public Expression visitLeafOperand(LeafViewOperand leafViewOperand, Void context) { - throw new RuntimeException(new NotSupportedException("Can not construct abstract class.")); + throw new UnsupportedOperationException("Can not construct abstract class."); } @Override @@ -131,7 +128,7 @@ public class TransformToExpressionVisitor extends ViewExpressionVisitor<Expressi // region Unary Expressions @Override public Expression visitUnaryExpression(UnaryViewExpression unaryViewExpression, Void context) { - throw new RuntimeException(new NotSupportedException("Can not construct abstract class.")); + throw new UnsupportedOperationException("Can not construct abstract class."); } @Override @@ -184,7 +181,7 @@ public class TransformToExpressionVisitor extends ViewExpressionVisitor<Expressi @Override // region Binary Expressions public Expression visitBinaryExpression(BinaryViewExpression binaryViewExpression, Void context) { - throw new RuntimeException(new NotSupportedException("Can not construct abstract class.")); + throw new UnsupportedOperationException("Can not construct abstract class."); } private Pair<Expression, Expression> getExpressionsForBinaryExpression( @@ -197,7 +194,7 @@ public class TransformToExpressionVisitor extends ViewExpressionVisitor<Expressi // region Binary : Arithmetic Binary Expression public Expression visitArithmeticBinaryExpression( ArithmeticBinaryViewExpression arithmeticBinaryExpression, Void context) { - throw new RuntimeException(new NotSupportedException("Can not construct abstract class.")); + throw new UnsupportedOperationException("Can not construct abstract class."); } public Expression visitAdditionExpression( @@ -236,7 +233,7 @@ public class TransformToExpressionVisitor extends ViewExpressionVisitor<Expressi // region Binary: Compare Binary Expression public Expression visitCompareBinaryExpression( CompareBinaryViewExpression compareBinaryExpression, Void context) { - throw new RuntimeException(new NotSupportedException("Can not construct abstract class.")); + throw new UnsupportedOperationException("Can not construct abstract class."); } public Expression visitEqualToExpression(EqualToViewExpression equalToExpression, Void context) { @@ -281,7 +278,7 @@ public class TransformToExpressionVisitor extends ViewExpressionVisitor<Expressi // region Binary : Logic Binary Expression public Expression visitLogicBinaryExpression( LogicBinaryViewExpression logicBinaryExpression, Void context) { - throw new RuntimeException(new NotSupportedException("Can not construct abstract class.")); + throw new UnsupportedOperationException("Can not construct abstract class."); } public Expression visitLogicAndExpression( @@ -302,7 +299,7 @@ public class TransformToExpressionVisitor extends ViewExpressionVisitor<Expressi // region Ternary Expressions public Expression visitTernaryExpression( TernaryViewExpression ternaryViewExpression, Void context) { - throw new RuntimeException(new NotSupportedException("Can not construct abstract class.")); + throw new UnsupportedOperationException("Can not construct abstract class."); } public Expression visitBetweenExpression( diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/externalservice/ExternalServiceManagementService.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/externalservice/ExternalServiceManagementService.java index 98f231db5b8..1d108bc941a 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/externalservice/ExternalServiceManagementService.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/externalservice/ExternalServiceManagementService.java @@ -159,9 +159,9 @@ public class ExternalServiceManagementService { if (serviceInfo.getServiceInstance() == null) { // lazy create Instance serviceInfo.setServiceInstance( - createExternalServiceInstance(serviceName, serviceInfo.getClassName())); + createExternalServiceInstance(serviceName, serviceInfo.getClassName(), serviceInfo)); } - serviceInfo.getServiceInstance().start(); + runWithServiceClassLoader(serviceInfo, () -> serviceInfo.getServiceInstance().start()); } // 3. persist on CN if service is user-defined, rollback if failed @@ -170,7 +170,7 @@ public class ExternalServiceManagementService { ConfigNodeClientManager.getInstance().borrowClient(ConfigNodeInfo.CONFIG_REGION_ID)) { TSStatus status = client.startExternalService(QueryId.getDataNodeId(), serviceName); if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { - serviceInfo.getServiceInstance().stop(); + runWithServiceClassLoader(serviceInfo, () -> serviceInfo.getServiceInstance().stop()); throw new IoTDBRuntimeException(status.message, status.code); } } @@ -183,12 +183,14 @@ public class ExternalServiceManagementService { } } - private IExternalService createExternalServiceInstance(String serviceName, String className) { + private IExternalService createExternalServiceInstance( + String serviceName, String className, ServiceInfo serviceInfo) { // close ClassLoader automatically to release the file handle try { // Remind: this classLoader should be closed when service is dropped after user-defined // service supported ExternalServiceClassLoader classLoader = new ExternalServiceClassLoader(libRoot); + serviceInfo.setServiceClassLoader(classLoader); return (IExternalService) Class.forName(className, true, classLoader).getDeclaredConstructor().newInstance(); } catch (Throwable t) { @@ -203,6 +205,21 @@ public class ExternalServiceManagementService { } } + private static void runWithServiceClassLoader(ServiceInfo serviceInfo, Runnable action) { + ClassLoader serviceClassLoader = serviceInfo.getServiceClassLoader(); + if (serviceClassLoader == null) { + action.run(); + return; + } + ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(serviceClassLoader); + action.run(); + } finally { + Thread.currentThread().setContextClassLoader(originalClassLoader); + } + } + public void stopService(String serviceName) throws ClientManagerException, TException { try { lock.writeLock().lock(); @@ -231,7 +248,7 @@ public class ExternalServiceManagementService { ConfigNodeClientManager.getInstance().borrowClient(ConfigNodeInfo.CONFIG_REGION_ID); ) { TSStatus status = client.stopExternalService(QueryId.getDataNodeId(), serviceName); if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { - serviceInfo.getServiceInstance().start(); + runWithServiceClassLoader(serviceInfo, () -> serviceInfo.getServiceInstance().start()); throw new IoTDBRuntimeException(status.message, status.code); } } @@ -249,7 +266,7 @@ public class ExternalServiceManagementService { serviceInfo.getServiceInstance() != null, INSTANCE_NULL_ERROR_MSG, serviceInfo.getServiceName()); - serviceInfo.getServiceInstance().stop(); + runWithServiceClassLoader(serviceInfo, () -> serviceInfo.getServiceInstance().stop()); } public void dropService(String serviceName, boolean forcedly) @@ -325,11 +342,11 @@ public class ExternalServiceManagementService { if (serviceInfo.getState() == RUNNING) { IExternalService serviceInstance = createExternalServiceInstance( - serviceInfo.getServiceName(), serviceInfo.getClassName()); + serviceInfo.getServiceName(), serviceInfo.getClassName(), serviceInfo); checkState( serviceInstance != null, INSTANCE_NULL_ERROR_MSG, serviceInfo.getServiceName()); serviceInfo.setServiceInstance(serviceInstance); - serviceInstance.start(); + runWithServiceClassLoader(serviceInfo, serviceInstance::start); } }); } @@ -346,7 +363,7 @@ public class ExternalServiceManagementService { // service in restoreRunningServiceInstance method if (serviceInstance != null) { // only stop the instance successfully started - serviceInstance.stop(); + runWithServiceClassLoader(serviceInfo, serviceInstance::stop); } } }); diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/externalservice/ServiceInfo.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/externalservice/ServiceInfo.java index f9ef9a73c02..7a933812fb4 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/externalservice/ServiceInfo.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/externalservice/ServiceInfo.java @@ -36,6 +36,7 @@ public class ServiceInfo { private State state; private transient IExternalService serviceInstance; + private transient ClassLoader serviceClassLoader; public ServiceInfo(String serviceName, String className, ServiceType serviceType) { this.serviceName = serviceName; @@ -79,6 +80,14 @@ public class ServiceInfo { this.serviceInstance = serviceInstance; } + public ClassLoader getServiceClassLoader() { + return serviceClassLoader; + } + + public void setServiceClassLoader(ClassLoader serviceClassLoader) { + this.serviceClassLoader = serviceClassLoader; + } + public void serialize(OutputStream stream) throws IOException { ReadWriteIOUtils.write(serviceName, stream); ReadWriteIOUtils.write(className, stream);
