This is an automated email from the ASF dual-hosted git repository.
apkhmv pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new 958e3c7f33 IGNITE-18604 Fix memory leak (#1749)
958e3c7f33 is described below
commit 958e3c7f33eddbcd59c3a8904b82a5e860fbd37f
Author: Mikhail <[email protected]>
AuthorDate: Mon Mar 6 21:14:05 2023 +0300
IGNITE-18604 Fix memory leak (#1749)
---------
Co-authored-by: Mikhail Pochatkin <[email protected]>
Co-authored-by: Vadim Pakhnushev <[email protected]>
---
.../apache/ignite/internal/rest/RestFactory.java | 11 +++++++++++
.../apache/ignite/internal/rest/RestComponent.java | 11 ++++++-----
.../internal/rest/RestFactoriesDestroyer.java} | 21 +++++++++++++++++++--
.../rest/authentication/AuthProviderFactory.java | 7 ++++++-
.../rest/cluster/ClusterManagementRestFactory.java | 10 ++++++++--
.../rest/configuration/PresentationsFactory.java | 10 ++++++++--
.../rest/deployment/CodeDeploymentRestFactory.java | 7 ++++++-
.../internal/rest/metrics/MetricRestFactory.java | 7 ++++++-
.../rest/node/NodeManagementRestFactory.java | 10 ++++++++--
.../org/apache/ignite/internal/app/IgniteImpl.java | 14 ++++++++------
10 files changed, 86 insertions(+), 22 deletions(-)
diff --git
a/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/RestFactory.java
b/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/RestFactory.java
index 88567cc8b6..6926a2e093 100644
---
a/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/RestFactory.java
+++
b/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/RestFactory.java
@@ -17,8 +17,19 @@
package org.apache.ignite.internal.rest;
+import io.micronaut.runtime.Micronaut;
+
/**
* Factory that produces all beans that is necessary for the controller class.
*/
public interface RestFactory {
+ /**
+ * Destroy method. All resources of the factory implementation must be
cleaned and all fields must be set to {@code null}.
+ * The reason of these requirements is Micronaut design.
+ * {@link Micronaut#start()} store shutdown hook and capture a pointer
+ * to the embedded application {@link
io.micronaut.http.server.netty.NettyEmbeddedServer} and as a result
+ * {@link io.micronaut.context.ApplicationContext} will never be
collected by the GC.
+ * All rest factories stored in the application context should be
cleaned to prevent memory leak.
+ */
+ void cleanResources();
}
diff --git
a/modules/rest/src/main/java/org/apache/ignite/internal/rest/RestComponent.java
b/modules/rest/src/main/java/org/apache/ignite/internal/rest/RestComponent.java
index 9d0e57b1e0..7aa8b5bde0 100644
---
a/modules/rest/src/main/java/org/apache/ignite/internal/rest/RestComponent.java
+++
b/modules/rest/src/main/java/org/apache/ignite/internal/rest/RestComponent.java
@@ -31,6 +31,7 @@ import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.function.Supplier;
import org.apache.ignite.internal.logger.IgniteLogger;
import org.apache.ignite.internal.logger.Loggers;
import org.apache.ignite.internal.manager.IgniteComponent;
@@ -61,7 +62,7 @@ public class RestComponent implements IgniteComponent {
private static final IgniteLogger LOG =
Loggers.forClass(RestComponent.class);
/** Factories that produce beans needed for REST controllers. */
- private final List<RestFactory> restFactories;
+ private final List<Supplier<RestFactory>> restFactories;
private final RestConfiguration restConfiguration;
@@ -77,7 +78,7 @@ public class RestComponent implements IgniteComponent {
/**
* Creates a new instance of REST module.
*/
- public RestComponent(List<RestFactory> restFactories, RestConfiguration
restConfiguration) {
+ public RestComponent(List<Supplier<RestFactory>> restFactories,
RestConfiguration restConfiguration) {
this.restFactories = restFactories;
this.restConfiguration = restConfiguration;
}
@@ -180,17 +181,17 @@ public class RestComponent implements IgniteComponent {
return micronaut
.properties(properties)
.banner(false)
- .mapError(ServerStartupException.class,
this::mapServerStartupException)
+ .mapError(ServerStartupException.class,
RestComponent::mapServerStartupException)
.mapError(ApplicationStartupException.class, ex -> -1);
}
private void setFactories(Micronaut micronaut) {
for (var factory : restFactories) {
- micronaut.singletons(factory);
+ micronaut.singletons(factory.get());
}
}
- private int mapServerStartupException(ServerStartupException exception) {
+ private static int mapServerStartupException(ServerStartupException
exception) {
if (exception.getCause() instanceof BindException) {
return -1; // -1 forces the micronaut to throw an
ApplicationStartupException
} else {
diff --git
a/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/RestFactory.java
b/modules/rest/src/main/java/org/apache/ignite/internal/rest/RestFactoriesDestroyer.java
similarity index 52%
copy from
modules/rest-api/src/main/java/org/apache/ignite/internal/rest/RestFactory.java
copy to
modules/rest/src/main/java/org/apache/ignite/internal/rest/RestFactoriesDestroyer.java
index 88567cc8b6..58051f6ccb 100644
---
a/modules/rest-api/src/main/java/org/apache/ignite/internal/rest/RestFactory.java
+++
b/modules/rest/src/main/java/org/apache/ignite/internal/rest/RestFactoriesDestroyer.java
@@ -17,8 +17,25 @@
package org.apache.ignite.internal.rest;
+import io.micronaut.context.event.BeanDestroyedEvent;
+import io.micronaut.context.event.BeanDestroyedEventListener;
+import jakarta.inject.Singleton;
+import org.apache.ignite.internal.logger.IgniteLogger;
+import org.apache.ignite.internal.logger.Loggers;
+
/**
- * Factory that produces all beans that is necessary for the controller class.
+ * Destroyer of any rest factory {@link RestFactory}.
*/
-public interface RestFactory {
+@Singleton
+public class RestFactoriesDestroyer implements
BeanDestroyedEventListener<RestFactory> {
+ private static final IgniteLogger LOG =
Loggers.forClass(RestFactoriesDestroyer.class);
+
+ @Override
+ public void onDestroyed(BeanDestroyedEvent<RestFactory> event) {
+ RestFactory bean = event.getBean();
+ if (bean != null) {
+ LOG.debug("Destroy rest factory " + bean);
+ bean.cleanResources();
+ }
+ }
}
diff --git
a/modules/rest/src/main/java/org/apache/ignite/internal/rest/authentication/AuthProviderFactory.java
b/modules/rest/src/main/java/org/apache/ignite/internal/rest/authentication/AuthProviderFactory.java
index 905e611bba..c01664a147 100644
---
a/modules/rest/src/main/java/org/apache/ignite/internal/rest/authentication/AuthProviderFactory.java
+++
b/modules/rest/src/main/java/org/apache/ignite/internal/rest/authentication/AuthProviderFactory.java
@@ -30,7 +30,7 @@ import org.apache.ignite.internal.rest.RestFactory;
@Factory
public class AuthProviderFactory implements RestFactory {
- private final DelegatingAuthenticationProvider authenticationProvider;
+ private DelegatingAuthenticationProvider authenticationProvider;
public AuthProviderFactory(AuthenticationConfiguration configuration) {
this.authenticationProvider = new DelegatingAuthenticationProvider();
@@ -47,4 +47,9 @@ public class AuthProviderFactory implements RestFactory {
public DelegatingAuthenticationProvider authenticationProvider() {
return authenticationProvider;
}
+
+ @Override
+ public void cleanResources() {
+ authenticationProvider = null;
+ }
}
diff --git
a/modules/rest/src/main/java/org/apache/ignite/internal/rest/cluster/ClusterManagementRestFactory.java
b/modules/rest/src/main/java/org/apache/ignite/internal/rest/cluster/ClusterManagementRestFactory.java
index 8a47cedd72..b724d2269a 100644
---
a/modules/rest/src/main/java/org/apache/ignite/internal/rest/cluster/ClusterManagementRestFactory.java
+++
b/modules/rest/src/main/java/org/apache/ignite/internal/rest/cluster/ClusterManagementRestFactory.java
@@ -31,9 +31,9 @@ import org.apache.ignite.network.TopologyService;
*/
@Factory
public class ClusterManagementRestFactory implements RestFactory {
- private final ClusterService clusterService;
+ private ClusterService clusterService;
- private final ClusterManagementGroupManager cmgManager;
+ private ClusterManagementGroupManager cmgManager;
/** Constructor. */
public ClusterManagementRestFactory(ClusterService clusterService,
ClusterManagementGroupManager cmgManager) {
@@ -58,4 +58,10 @@ public class ClusterManagementRestFactory implements
RestFactory {
public TopologyService topologyService() {
return clusterService.topologyService();
}
+
+ @Override
+ public void cleanResources() {
+ clusterService = null;
+ cmgManager = null;
+ }
}
diff --git
a/modules/rest/src/main/java/org/apache/ignite/internal/rest/configuration/PresentationsFactory.java
b/modules/rest/src/main/java/org/apache/ignite/internal/rest/configuration/PresentationsFactory.java
index c422ff55a4..371d436911 100644
---
a/modules/rest/src/main/java/org/apache/ignite/internal/rest/configuration/PresentationsFactory.java
+++
b/modules/rest/src/main/java/org/apache/ignite/internal/rest/configuration/PresentationsFactory.java
@@ -30,8 +30,8 @@ import
org.apache.ignite.internal.rest.configuration.hocon.HoconPresentation;
*/
@Factory
public class PresentationsFactory implements RestFactory {
- private final ConfigurationPresentation<String> nodeCfgPresentation;
- private final ConfigurationPresentation<String> clusterCfgPresentation;
+ private ConfigurationPresentation<String> nodeCfgPresentation;
+ private ConfigurationPresentation<String> clusterCfgPresentation;
public PresentationsFactory(ConfigurationManager nodeCfgMgr,
ConfigurationManager clusterCfgMgr) {
this.nodeCfgPresentation = new
HoconPresentation(nodeCfgMgr.configurationRegistry());
@@ -51,4 +51,10 @@ public class PresentationsFactory implements RestFactory {
public ConfigurationPresentation<String> nodeCfgPresentation() {
return nodeCfgPresentation;
}
+
+ @Override
+ public void cleanResources() {
+ nodeCfgPresentation = null;
+ clusterCfgPresentation = null;
+ }
}
diff --git
a/modules/rest/src/main/java/org/apache/ignite/internal/rest/deployment/CodeDeploymentRestFactory.java
b/modules/rest/src/main/java/org/apache/ignite/internal/rest/deployment/CodeDeploymentRestFactory.java
index a75c167f2c..d4411a0618 100644
---
a/modules/rest/src/main/java/org/apache/ignite/internal/rest/deployment/CodeDeploymentRestFactory.java
+++
b/modules/rest/src/main/java/org/apache/ignite/internal/rest/deployment/CodeDeploymentRestFactory.java
@@ -28,7 +28,7 @@ import org.apache.ignite.internal.rest.RestFactory;
*/
@Factory
public class CodeDeploymentRestFactory implements RestFactory {
- private final IgniteDeployment igniteDeployment;
+ private IgniteDeployment igniteDeployment;
public CodeDeploymentRestFactory(IgniteDeployment igniteDeployment) {
this.igniteDeployment = igniteDeployment;
@@ -39,4 +39,9 @@ public class CodeDeploymentRestFactory implements RestFactory
{
public IgniteDeployment deployment() {
return igniteDeployment;
}
+
+ @Override
+ public void cleanResources() {
+ igniteDeployment = null;
+ }
}
diff --git
a/modules/rest/src/main/java/org/apache/ignite/internal/rest/metrics/MetricRestFactory.java
b/modules/rest/src/main/java/org/apache/ignite/internal/rest/metrics/MetricRestFactory.java
index 38bf0b44f4..e93d616240 100644
---
a/modules/rest/src/main/java/org/apache/ignite/internal/rest/metrics/MetricRestFactory.java
+++
b/modules/rest/src/main/java/org/apache/ignite/internal/rest/metrics/MetricRestFactory.java
@@ -28,7 +28,7 @@ import org.apache.ignite.internal.rest.RestFactory;
*/
@Factory
public class MetricRestFactory implements RestFactory {
- private final MetricManager metricManager;
+ private MetricManager metricManager;
public MetricRestFactory(MetricManager metricManager) {
this.metricManager = metricManager;
@@ -39,4 +39,9 @@ public class MetricRestFactory implements RestFactory {
public MetricManager metricManager() {
return metricManager;
}
+
+ @Override
+ public void cleanResources() {
+ metricManager = null;
+ }
}
diff --git
a/modules/rest/src/main/java/org/apache/ignite/internal/rest/node/NodeManagementRestFactory.java
b/modules/rest/src/main/java/org/apache/ignite/internal/rest/node/NodeManagementRestFactory.java
index 21997ff5d5..344103a7a5 100644
---
a/modules/rest/src/main/java/org/apache/ignite/internal/rest/node/NodeManagementRestFactory.java
+++
b/modules/rest/src/main/java/org/apache/ignite/internal/rest/node/NodeManagementRestFactory.java
@@ -27,9 +27,9 @@ import org.apache.ignite.internal.rest.RestFactory;
*/
@Factory
public class NodeManagementRestFactory implements RestFactory {
- private final StateProvider stateProvider;
+ private StateProvider stateProvider;
- private final NameProvider nameProvider;
+ private NameProvider nameProvider;
public NodeManagementRestFactory(StateProvider stateProvider, NameProvider
nameProvider) {
this.stateProvider = stateProvider;
@@ -47,4 +47,10 @@ public class NodeManagementRestFactory implements
RestFactory {
public NameProvider nameProvider() {
return nameProvider;
}
+
+ @Override
+ public void cleanResources() {
+ stateProvider = null;
+ nameProvider = null;
+ }
}
diff --git
a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java
b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java
index ff05278575..f579c56f2f 100644
---
a/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java
+++
b/modules/runner/src/main/java/org/apache/ignite/internal/app/IgniteImpl.java
@@ -38,6 +38,7 @@ import java.util.concurrent.TimeUnit;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
+import java.util.function.Supplier;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgnitionManager;
import org.apache.ignite.client.handler.ClientHandlerModule;
@@ -525,12 +526,13 @@ public class IgniteImpl implements Ignite {
AuthenticationConfiguration authConfiguration =
clusterCfgMgr.configurationRegistry()
.getConfiguration(SecurityConfiguration.KEY)
.authentication();
- RestFactory presentationsFactory = new
PresentationsFactory(nodeCfgMgr, clusterCfgMgr);
- RestFactory clusterManagementRestFactory = new
ClusterManagementRestFactory(clusterSvc, cmgMgr);
- RestFactory nodeManagementRestFactory = new
NodeManagementRestFactory(lifecycleManager, () -> name);
- RestFactory nodeMetricRestFactory = new
MetricRestFactory(metricManager);
- AuthProviderFactory authProviderFactory = new
AuthProviderFactory(authConfiguration);
- RestFactory deploymentCodeRestFactory = new
CodeDeploymentRestFactory(deploymentManager);
+
+ Supplier<RestFactory> presentationsFactory = () -> new
PresentationsFactory(nodeCfgMgr, clusterCfgMgr);
+ Supplier<RestFactory> clusterManagementRestFactory = () -> new
ClusterManagementRestFactory(clusterSvc, cmgMgr);
+ Supplier<RestFactory> nodeManagementRestFactory = () -> new
NodeManagementRestFactory(lifecycleManager, () -> name);
+ Supplier<RestFactory> nodeMetricRestFactory = () -> new
MetricRestFactory(metricManager);
+ Supplier<RestFactory> authProviderFactory = () -> new
AuthProviderFactory(authConfiguration);
+ Supplier<RestFactory> deploymentCodeRestFactory = () -> new
CodeDeploymentRestFactory(deploymentManager);
RestConfiguration restConfiguration =
nodeCfgMgr.configurationRegistry().getConfiguration(RestConfiguration.KEY);
return new RestComponent(
List.of(presentationsFactory,