Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

30315 memory leak weak hashmap keys #30325

Draft
wants to merge 7 commits into
base: integration
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ IBM-Process-Types: server, \
com.ibm.websphere.appserver.artifact-1.0
-bundles=com.ibm.ws.anno
-jars=com.ibm.websphere.appserver.spi.anno; location:=dev/spi/ibm/
-files=dev/spi/ibm/javadoc/com.ibm.websphere.appserver.spi.anno_1.1-javadoc.zip
-files=dev/spi/ibm/javadoc/com.ibm.websphere.appserver.spi.anno_1.2-javadoc.zip
kind=ga
edition=core
WLP-Activation-Type: parallel
2 changes: 1 addition & 1 deletion dev/com.ibm.websphere.appserver.spi.anno/bnd.bnd
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
# IBM Corporation - initial API and implementation
#*******************************************************************************
-include= ~../cnf/resources/bnd/bundle.props
bVersion: 1.1
bVersion: 1.2

Bundle-Name: WebSphere Annotations SPI
Bundle-Description: WebSphere Annotations SPI, version ${bVersion}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@
<artifactId>com.ibm.websphere.appserver.spi.anno</artifactId>
<version>${bFullVersion}</version>
<name>WebSphere Annotations SPI</name>
<description>WebSphere Annotations SPI, version 1.1</description>
<description>WebSphere Annotations SPI, version 1.2</description>
</project>
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2011, 2019 IBM Corporation and others.
* Copyright (c) 2011, 2024 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
Expand All @@ -16,6 +16,7 @@
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
Expand All @@ -25,7 +26,6 @@
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;

import java.util.logging.Logger;

import com.ibm.websphere.ras.Tr;
Expand All @@ -34,6 +34,7 @@
import com.ibm.ws.annocache.service.internal.AnnotationCacheServiceImpl_Logging;
import com.ibm.wsspi.anno.classsource.ClassSource_ScanCounts;
import com.ibm.wsspi.anno.classsource.ClassSource_ScanCounts.ResultField;
import com.ibm.wsspi.anno.service.AppKey;
import com.ibm.wsspi.anno.classsource.ClassSource_Streamer;
import com.ibm.wsspi.annocache.classsource.ClassSource;
import com.ibm.wsspi.annocache.classsource.ClassSource_Aggregate;
Expand Down Expand Up @@ -81,11 +82,11 @@ public String toString() {
//

// Top O' the world

public ClassSourceImpl_Aggregate(
ClassSourceImpl_Factory factory,
Util_InternMap internMap,
String applicationName, String moduleName, String moduleCategoryName,
String applicationName, AppKey appKey, String moduleName, String moduleCategoryName,
ClassSource_Options options) {

String methodName = "<init>";
Expand All @@ -99,6 +100,7 @@ public ClassSourceImpl_Aggregate(
this.applicationName = applicationName;
this.moduleName = moduleName;
this.moduleCategoryName = moduleCategoryName;
this.applicationKey = new WeakReference<AppKey>(appKey);

//

Expand Down Expand Up @@ -180,6 +182,7 @@ protected String internClassName(String className, boolean doForce) {
protected final String applicationName;
protected final String moduleName;
protected final String moduleCategoryName;
protected final WeakReference<AppKey> applicationKey;

/**
* <p>Answer the name of the application of this class source.</p>
Expand All @@ -191,6 +194,17 @@ protected String internClassName(String className, boolean doForce) {
public String getApplicationName() {
return applicationName;
}

/**
* <p>Answer the name of the application of this class source.</p>
*
* @return The name of the application of this class source.
*/
@Override
@Trivial
public AppKey getApplicationKey() {
return applicationKey.get();
}

/**
* <p>Answer the name of the module of this class source.</p>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017, 2020 IBM Corporation and others.
* Copyright (c) 2017, 2024 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
Expand All @@ -13,6 +13,8 @@

package com.ibm.ws.annocache.classsource.internal;

import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

Expand All @@ -39,14 +41,14 @@
import com.ibm.wsspi.anno.classsource.ClassSource_MappedDirectory;
import com.ibm.wsspi.anno.classsource.ClassSource_MappedJar;
import com.ibm.wsspi.anno.classsource.ClassSource_MappedSimple.SimpleClassProvider;
import com.ibm.wsspi.anno.service.AppKey;
import com.ibm.wsspi.annocache.classsource.ClassSource_Aggregate;
import com.ibm.wsspi.annocache.classsource.ClassSource_Aggregate.ScanPolicy;
import com.ibm.wsspi.annocache.classsource.ClassSource_ClassLoader;
import com.ibm.wsspi.annocache.classsource.ClassSource_Exception;
import com.ibm.wsspi.annocache.classsource.ClassSource_Factory;
import com.ibm.wsspi.annocache.classsource.ClassSource_MappedSimple;
import com.ibm.wsspi.annocache.classsource.ClassSource_Options;
import com.ibm.wsspi.annocache.service.AnnotationCacheService_Service;
import com.ibm.wsspi.annocache.util.Util_Factory;
import com.ibm.wsspi.annocache.util.Util_InternMap;
import com.ibm.wsspi.annocache.util.Util_RelativePath;
Expand Down Expand Up @@ -166,13 +168,13 @@ public String getCanonicalName(String classSourceName) {
@Override
@Trivial
public ClassSourceImpl_Aggregate createAggregateClassSource(
String appName, String modName, String modCategoryName,
String appName, AppKey appKey, String modName, String modCategoryName,
ClassSource_Options options) throws ClassSource_Exception {

Util_InternMap classInternMap =
getUtilFactory().createInternMap(Util_InternMap.ValueType.VT_CLASS_NAME, "classes and packages");

return createAggregateClassSource(classInternMap, appName, modName, modCategoryName, options);
return createAggregateClassSource(classInternMap, appName, appKey, modName, modCategoryName, options);
// throws ClassSource_Exception
}

Expand Down Expand Up @@ -283,10 +285,10 @@ public ClassSourceImpl_ClassLoader createClassLoaderClassSource(
@Override
public ClassSourceImpl_Aggregate createAggregateClassSource(
Util_InternMap internMap,
String appName, String modName, String modCategoryName,
String appName, AppKey appKey, String modName, String modCategoryName,
ClassSource_Options options) throws ClassSource_Exception {

return new ClassSourceImpl_Aggregate(this, internMap, appName, modName, modCategoryName, options);
return new ClassSourceImpl_Aggregate(this, internMap, appName, appKey, modName, modCategoryName, options);
}

@Override
Expand Down Expand Up @@ -524,4 +526,27 @@ public ClassSource_Specification_Container_EJB newEJBContainerSpecification() {
public ClassSource_Specification_Container_WAR newWARContainerSpecification() {
return null;
}

//Leaky keys will only be used if someone calls the old deprecated interface that does not take an AppKey as an argument.
//No IBM code does so. And if an external SPI user does so, I think it is better to avoid the risk that their code depended
//on the WeakHashMap we uses these app keys for never being cleaned out. Then avoid a memory leak that is relatively minor.
@Deprecated
private static final Map<String, AppKey> MEMORY_LEAKY_KEYS = new HashMap<String,AppKey>();

@Override
@Deprecated
public ClassSource_Aggregate createAggregateClassSource(String appName, String modName, String modNameCategory, ClassSource_Options options) throws ClassSource_Exception {
MEMORY_LEAKY_KEYS.computeIfAbsent(appName, AppKey::new);
return createAggregateClassSource(appName, MEMORY_LEAKY_KEYS.get(appName), modName,
modNameCategory, options);
}

@Override
@Deprecated
public ClassSource_Aggregate createAggregateClassSource(Util_InternMap internMap, String appName, String modName, String modNameCategory,
ClassSource_Options options) throws ClassSource_Exception {
MEMORY_LEAKY_KEYS.computeIfAbsent(appName, AppKey::new);
return createAggregateClassSource(internMap, appName, MEMORY_LEAKY_KEYS.get(appName), modName,
modNameCategory, options);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017, 2019 IBM Corporation and others.
* Copyright (c) 2017, 2024 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
Expand All @@ -12,23 +12,24 @@
*******************************************************************************/
package com.ibm.ws.annocache.classsource.specification.internal;

import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.ibm.websphere.ras.annotation.Trivial;

import com.ibm.wsspi.annocache.classsource.ClassSource_Exception;
import com.ibm.wsspi.annocache.classsource.ClassSource_Options;
import com.ibm.wsspi.annocache.classsource.ClassSource_Aggregate;
import com.ibm.wsspi.annocache.classsource.ClassSource_Aggregate.ScanPolicy;

import com.ibm.ws.annocache.classsource.internal.ClassSourceImpl_Aggregate;
import com.ibm.ws.annocache.classsource.internal.ClassSourceImpl_ClassLoader;
import com.ibm.ws.annocache.classsource.internal.ClassSourceImpl_Factory;
import com.ibm.ws.annocache.classsource.internal.ClassSourceImpl_MappedDirectory;
import com.ibm.ws.annocache.classsource.internal.ClassSourceImpl_MappedJar;
import com.ibm.ws.annocache.classsource.specification.ClassSource_Specification;
import com.ibm.ws.annocache.service.internal.AnnotationCacheServiceImpl_Logging;
import com.ibm.wsspi.anno.service.AppKey;
import com.ibm.wsspi.annocache.classsource.ClassSource_Aggregate;
import com.ibm.wsspi.annocache.classsource.ClassSource_Aggregate.ScanPolicy;
import com.ibm.wsspi.annocache.classsource.ClassSource_Exception;
import com.ibm.wsspi.annocache.classsource.ClassSource_Options;


public abstract class ClassSourceImpl_Specification implements ClassSource_Specification {
Expand Down Expand Up @@ -128,13 +129,17 @@ public ClassSourceImpl_Aggregate createRootClassSource(ClassSource_Options class
}

//


//This is only called from a unit test where a memory leak is no issue but an early GC could cause a test fail
private static final Map<String, AppKey> UNIT_TEST_MEMORY_LEAKY_KEYS = new HashMap<String,AppKey>();

@Override
public ClassSourceImpl_Aggregate createEmptyRootClassSource(ClassSource_Options classSourceOptions)
throws ClassSource_Exception {

return getFactory().createAggregateClassSource(
getAppName(), getModName(), getModCategoryName(),
UNIT_TEST_MEMORY_LEAKY_KEYS.computeIfAbsent(appName, AppKey::new);
return getFactory().createAggregateClassSource(
getAppName(), UNIT_TEST_MEMORY_LEAKY_KEYS.get(appName), getModName(), getModCategoryName(),
classSourceOptions );
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017, 2019 IBM Corporation and others.
* Copyright (c) 2017, 2024 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
Expand All @@ -16,8 +16,10 @@
import java.util.WeakHashMap;

import com.ibm.websphere.ras.annotation.Trivial;
import com.ibm.wsspi.anno.service.AppKey;
import com.ibm.wsspi.annocache.classsource.ClassSource_Factory;
import com.ibm.wsspi.annocache.targets.cache.TargetCache_ExternalConstants;
import com.ibm.wsspi.annocache.targets.cache.TargetCache_Options;

/**
* Root of annotation caching data.
Expand Down Expand Up @@ -74,7 +76,7 @@ public TargetCacheImpl_DataApps(
new File( factory.getCacheOptions().getDir() ) );

this.appsLock = new AppsLock();
this.apps = new WeakHashMap<String, TargetCacheImpl_DataApp>();
this.apps = new WeakHashMap<AppKey, TargetCacheImpl_DataApp>();

this.queriesLock = new QueriesLock();
this.queries = new WeakHashMap<String, TargetCacheImpl_DataQueries>();
Expand Down Expand Up @@ -152,7 +154,7 @@ private class AppsLock {
// EMPTY
}
private final AppsLock appsLock;
private final WeakHashMap<String, TargetCacheImpl_DataApp> apps;
private final WeakHashMap<AppKey, TargetCacheImpl_DataApp> apps;

/**
* Obtain cache data for an application.
Expand All @@ -166,17 +168,17 @@ private class AppsLock {
*
* @return Cache data for the application.
*/
public TargetCacheImpl_DataApp getAppForcing(String appName) {
public TargetCacheImpl_DataApp getAppForcing(String appName, AppKey appKey) {
// Unnamed applications always create new data.
if ( appName == ClassSource_Factory.UNNAMED_APP ) {
return createAppData(appName);
}

synchronized( appsLock ) {
TargetCacheImpl_DataApp app = apps.get(appName);
TargetCacheImpl_DataApp app = apps.get(appKey);
if ( app == null ) {
app = createAppData(appName);
apps.put(appName, app);
apps.put(appKey, app);
}
return app;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2011, 2020 IBM Corporation and others.
* Copyright (c) 2011, 2024 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
Expand All @@ -12,6 +12,7 @@
*******************************************************************************/
package com.ibm.ws.annocache.targets.internal;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
Expand Down Expand Up @@ -39,6 +40,7 @@
import com.ibm.ws.annocache.util.internal.UtilImpl_NonInternSet;
import com.ibm.ws.annocache.util.internal.UtilImpl_Utils;
import com.ibm.wsspi.anno.classsource.ClassSource_Aggregate.ScanPolicy;
import com.ibm.wsspi.anno.service.AppKey;
import com.ibm.wsspi.anno.util.Util_InternMap.ValueType;
import com.ibm.wsspi.annocache.classsource.ClassSource_Aggregate;
import com.ibm.wsspi.annocache.targets.AnnotationTargets_Exception;
Expand Down Expand Up @@ -437,7 +439,7 @@ public void scan(

// The query logger has its own reference to module data.

TargetCacheImpl_DataApp appData = getAnnoCache().getAppForcing( getAppName() );
TargetCacheImpl_DataApp appData = getAnnoCache().getAppForcing( getAppName(), getAppKey() );

putQueriesData(appData);

Expand All @@ -462,6 +464,7 @@ protected void putSpecificResults(TargetsScannerBaseImpl scanner) {
protected ClassSource_Aggregate rootClassSource;

protected String appName;
protected WeakReference<AppKey> appKey;
protected String modName;
protected String modCatName;
protected String modFullName;
Expand All @@ -474,6 +477,7 @@ protected void setRootClassSource(ClassSource_Aggregate rootClassSource) {

protected void setNames(ClassSource_Aggregate useRootClassSource) {
this.appName = useRootClassSource.getApplicationName();
this.appKey = new WeakReference<AppKey>(useRootClassSource.getApplicationKey());
this.modName = useRootClassSource.getModuleName();
this.modCatName = useRootClassSource.getModuleCategoryName();

Expand All @@ -496,6 +500,11 @@ public String getAppName() {
return appName;
}

@Trivial
public AppKey getAppKey() {
return appKey.get();
}

@Trivial
public String getModName() {
return modName;
Expand Down Expand Up @@ -720,7 +729,7 @@ protected synchronized void ensureInternalResults() {
"App [ {0} ] Mod [ {1} ]", new Object[] { useAppName, useModFullName });
}

TargetCacheImpl_DataApp appData = getAnnoCache().getAppForcing(useAppName);
TargetCacheImpl_DataApp appData = getAnnoCache().getAppForcing(useAppName, getAppKey());
TargetCacheImpl_DataMod modData = appData.getModForcing(useModFullName, getIsLightweight() );

TargetsScannerOverallImpl useOverallScanner =
Expand Down
Loading