Skip to content

Commit

Permalink
BUG 35590953 - [35544351->23.03.2] Memory leak: After restarting View…
Browse files Browse the repository at this point in the history
… service, serviceMap size increases (merge ce/main -> ce/23.03 @ 101670)

[git-p4: depot-paths = "//dev/coherence-ce/release/coherence-ce-v23.03/": change = 101671]
  • Loading branch information
rlubke committed Jul 11, 2023
1 parent 8635467 commit be73089
Showing 1 changed file with 74 additions and 29 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/*
* Copyright (c) 2000, 2020, Oracle and/or its affiliates.
* Copyright (c) 2000, 2023, Oracle and/or its affiliates.
*
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
* https://oss.oracle.com/licenses/upl.
*/
package com.tangosol.coherence.config.scheme;

Expand All @@ -21,10 +21,12 @@

import com.tangosol.net.cache.ContinuousQueryCache;

import com.tangosol.net.internal.ScopedServiceReferenceStore;
import com.tangosol.net.internal.ViewCacheService;

import com.tangosol.util.RegistrationBehavior;
import com.tangosol.util.ResourceRegistry;
import com.tangosol.util.Base;

import java.lang.reflect.Method;

/**
* A Scheme that realizes both services and caches for Coherence 12.2.1.4 feature
Expand All @@ -41,10 +43,41 @@
// caches are primed eagerly with data to have similar behavior semantics as
// replicated caches. Unlike regular services this service does not have its
// own type and is *not* instantiated or maintained by the cluster 'consciously'
// (we use the cluster's resource registry to store these services).
// (we use the cluster's ScopedServiceReferenceStore to store these services).
@SuppressWarnings("rawtypes")
public class ViewScheme
extends AbstractCompositeScheme<ContinuousQueryCache>
{

// Internal Notes:
// Static initialization to obtain and store a reference
// to SafeCluster.getScopedServiceStore(). This store will be used to
// store ViewCacheService instances.
//
// Originally, these instances were stored in the Cluster's resource
// registry, however, the registry contents won't survive a cluster
// stop/start (like a member eviction/restart).
// The ScopedServiceReferenceStore will survive in this scenario
// allowing the same ViewCacheService instance to be used and thus
// avoiding a potential memory leak.
static
{
Class<?> clzSafeCluster;
try
{
clzSafeCluster = Class.forName("com.tangosol.coherence.component.util.SafeCluster",
false,
ViewScheme.class.getClassLoader());
SAFE_CLUSTER_GET_SCOPED_SERVICE_STORE =
clzSafeCluster.getDeclaredMethod("getScopedServiceStore");

}
catch (Exception e)
{
throw Base.ensureRuntimeException(e, "ViewScheme initialization failed");
}
}

// ----- constructors ---------------------------------------------------

/**
Expand All @@ -57,7 +90,6 @@ public ViewScheme()
setFrontScheme(NO_SCHEME);

DistributedScheme schemeBack = new DistributedScheme();
schemeBack.setServiceName(getServiceType());
setBackScheme(schemeBack);
}

Expand All @@ -69,25 +101,9 @@ public Service realizeService(ParameterResolver resolver, ClassLoader loader, Cl
validate();

// see if we've already created the appropriate CacheService
ResourceRegistry registry = cluster.getResourceRegistry();

ConcurrentHashMap<String, Service> mapServices =
registry.getResource(ConcurrentHashMap.class, ViewCacheService.KEY_CLUSTER_REGISTRY);

if (mapServices == null)
{
registry.registerResource(
ConcurrentHashMap.class,
ViewCacheService.KEY_CLUSTER_REGISTRY,
ConcurrentHashMap::new,
RegistrationBehavior.IGNORE,
null);

mapServices = registry.getResource(ConcurrentHashMap.class, ViewCacheService.KEY_CLUSTER_REGISTRY);
}

String sServiceName = getScopedServiceName();
Service service = mapServices.get(sServiceName);
ScopedServiceReferenceStore store = getServiceStore(cluster);
String sServiceName = getScopedServiceName();
Service service = store.getService(sServiceName);
if (service != null)
{
return service;
Expand All @@ -110,10 +126,7 @@ public Service realizeService(ParameterResolver resolver, ClassLoader loader, Cl
service = new ViewCacheService(serviceBack);
service.setDependencies(deps);

if (mapServices.putIfAbsent(sServiceName, service) != null)
{
service = mapServices.get(sServiceName); // highly unlikely path
}
store.putService(service, sServiceName, getServiceType());

return service;
}
Expand All @@ -133,10 +146,42 @@ public String getServiceType()
return ViewCacheService.TYPE_VIEW;
}

// ----- helper methods -------------------------------------------------

/**
* Obtain the {@link ScopedServiceReferenceStore} from the provided
* {@link Cluster}.
*
* @param cluster the {@link Cluster}
*
* @return the {@link ScopedServiceReferenceStore} from the provided
* {@link Cluster}.
*
* @since 12.2.1.4.19
*/
protected ScopedServiceReferenceStore getServiceStore(Cluster cluster)
{
try
{
return (ScopedServiceReferenceStore) SAFE_CLUSTER_GET_SCOPED_SERVICE_STORE.invoke(cluster);
}
catch (Exception e)
{
throw Base.ensureRuntimeException(e, "Failed to invoke SafeCluster.getScopedReferenceStore()");
}
}

// ----- constants ------------------------------------------------------

/**
* A CachingScheme that represents NO_VALUE.
*/
private static final CachingScheme NO_SCHEME = new ClassScheme();

/**
* Method reference to obtain SafeCluster ScopedServiceReferenceStore.
*
* @since 12.2.1.4.19
*/
private static final Method SAFE_CLUSTER_GET_SCOPED_SERVICE_STORE;
}

0 comments on commit be73089

Please sign in to comment.