Skip to content

Commit c681880

Browse files
committed
HHH-19230 Avoid class loader leak in enhancement and improve bytebuddy type caching efficiency
1 parent 78b40cf commit c681880

File tree

6 files changed

+107
-162
lines changed

6 files changed

+107
-162
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
6+
*/
7+
package org.hibernate.bytecode.enhance.internal.bytebuddy;
8+
9+
import net.bytebuddy.pool.TypePool;
10+
11+
import java.util.AbstractMap;
12+
import java.util.Map;
13+
14+
/**
15+
* A simple cache provider that allows overriding the resolution for the class that is currently being enhanced.
16+
*/
17+
final class EnhancerCacheProvider extends TypePool.CacheProvider.Simple {
18+
19+
private final ThreadLocal<Map.Entry<String, TypePool.Resolution>> enhancedTypeResolution = new ThreadLocal<>();
20+
21+
@Override
22+
public TypePool.Resolution find(final String name) {
23+
final Map.Entry<String, TypePool.Resolution> entry = enhancedTypeResolution.get();
24+
if ( entry != null && entry.getKey().equals( name ) ) {
25+
return entry.getValue();
26+
}
27+
return super.find( name );
28+
}
29+
30+
@Override
31+
public void clear() {
32+
super.clear();
33+
enhancedTypeResolution.remove();
34+
}
35+
36+
public void registerEnhancedType(final String className, TypePool.Resolution resolution) {
37+
enhancedTypeResolution.set( new AbstractMap.SimpleEntry<>( className, resolution ) );
38+
}
39+
40+
public void deregisterEnhancedType(final String name) {
41+
enhancedTypeResolution.remove();
42+
}
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
6+
*/
7+
package org.hibernate.bytecode.enhance.internal.bytebuddy;
8+
9+
import net.bytebuddy.dynamic.ClassFileLocator;
10+
11+
import java.io.IOException;
12+
import java.util.AbstractMap;
13+
import java.util.Map;
14+
15+
/**
16+
* A delegating ClassFileLocator that allows overriding the resolution for the class that is currently being enhanced.
17+
*/
18+
final class EnhancerClassFileLocator implements ClassFileLocator {
19+
20+
private final ThreadLocal<Map.Entry<String, ClassFileLocator.Resolution>> enhancedTypeResolution = new ThreadLocal<>();
21+
private final ClassFileLocator delegate;
22+
23+
public EnhancerClassFileLocator(ClassFileLocator delegate) {
24+
this.delegate = delegate;
25+
}
26+
27+
@Override
28+
public Resolution locate(final String name) throws IOException {
29+
final Map.Entry<String, ClassFileLocator.Resolution> entry = enhancedTypeResolution.get();
30+
if ( entry != null && entry.getKey().equals( name ) ) {
31+
return entry.getValue();
32+
}
33+
return delegate.locate( name );
34+
}
35+
36+
@Override
37+
public void close() throws IOException {
38+
try {
39+
delegate.close();
40+
}
41+
finally {
42+
enhancedTypeResolution.remove();
43+
}
44+
}
45+
46+
public void registerEnhancedType(final String className, ClassFileLocator.Resolution resolution) {
47+
enhancedTypeResolution.set( new AbstractMap.SimpleEntry<>( className, resolution ) );
48+
}
49+
50+
public void deregisterEnhancedType(final String name) {
51+
enhancedTypeResolution.remove();
52+
}
53+
54+
}

hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/ModelTypePool.java

+10-28
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
package org.hibernate.bytecode.enhance.internal.bytebuddy;
88

99
import java.util.Objects;
10-
import java.util.concurrent.ConcurrentHashMap;
1110

1211
import net.bytebuddy.dynamic.ClassFileLocator;
1312
import net.bytebuddy.pool.TypePool;
@@ -18,11 +17,10 @@
1817
*/
1918
public class ModelTypePool extends TypePool.Default implements EnhancerClassLocator {
2019

21-
private final ConcurrentHashMap<String, Resolution> resolutions = new ConcurrentHashMap<>();
22-
private final OverridingClassFileLocator locator;
23-
private final SafeCacheProvider poolCache;
20+
private final EnhancerClassFileLocator locator;
21+
private final EnhancerCacheProvider poolCache;
2422

25-
private ModelTypePool(SafeCacheProvider cacheProvider, OverridingClassFileLocator classFileLocator, CoreTypePool parent) {
23+
private ModelTypePool(EnhancerCacheProvider cacheProvider, EnhancerClassFileLocator classFileLocator, CoreTypePool parent) {
2624
super( cacheProvider, classFileLocator, ReaderMode.FAST, parent );
2725
this.poolCache = cacheProvider;
2826
this.locator = classFileLocator;
@@ -64,7 +62,7 @@ public static EnhancerClassLocator buildModelTypePool(ClassFileLocator classFile
6462
* @return
6563
*/
6664
public static EnhancerClassLocator buildModelTypePool(ClassFileLocator classFileLocator, CoreTypePool coreTypePool) {
67-
return buildModelTypePool( classFileLocator, coreTypePool, new SafeCacheProvider() );
65+
return buildModelTypePool( classFileLocator, coreTypePool, new EnhancerCacheProvider() );
6866
}
6967

7068
/**
@@ -74,39 +72,23 @@ public static EnhancerClassLocator buildModelTypePool(ClassFileLocator classFile
7472
* @param cacheProvider
7573
* @return
7674
*/
77-
public static EnhancerClassLocator buildModelTypePool(ClassFileLocator classFileLocator, CoreTypePool coreTypePool, SafeCacheProvider cacheProvider) {
75+
static EnhancerClassLocator buildModelTypePool(ClassFileLocator classFileLocator, CoreTypePool coreTypePool, EnhancerCacheProvider cacheProvider) {
7876
Objects.requireNonNull( classFileLocator );
7977
Objects.requireNonNull( coreTypePool );
8078
Objects.requireNonNull( cacheProvider );
81-
return new ModelTypePool( cacheProvider, new OverridingClassFileLocator( classFileLocator ), coreTypePool );
82-
}
83-
84-
@Override
85-
protected Resolution doDescribe(final String name) {
86-
final Resolution resolution = resolutions.get( name );
87-
if ( resolution != null ) {
88-
return resolution;
89-
}
90-
else {
91-
return resolutions.computeIfAbsent( name, super::doDescribe );
92-
}
79+
return new ModelTypePool( cacheProvider, new EnhancerClassFileLocator( classFileLocator ), coreTypePool );
9380
}
9481

9582
@Override
9683
public void registerClassNameAndBytes(final String className, final byte[] bytes) {
97-
//Very important: ensure the registered override is actually effective in case this class
98-
//was already resolved in the recent past; this could have happened for example as a side effect
99-
//of symbol resolution during enhancement of a different class, or very simply when attempting
100-
//to re-enhanced the same class - which happens frequently in WildFly because of the class transformers
101-
//being triggered concurrently by multiple parallel deployments.
102-
resolutions.remove( className );
103-
poolCache.remove( className );
104-
locator.put( className, new ClassFileLocator.Resolution.Explicit( Objects.requireNonNull( bytes ) ) );
84+
locator.registerEnhancedType( className, new ClassFileLocator.Resolution.Explicit( Objects.requireNonNull( bytes ) ) );
85+
poolCache.registerEnhancedType( className, doDescribe( className ) );
10586
}
10687

10788
@Override
10889
public void deregisterClassNameAndBytes(final String className) {
109-
locator.remove( className );
90+
poolCache.deregisterEnhancedType( className );
91+
locator.deregisterEnhancedType( className );
11092
}
11193

11294
@Override

hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/OverridingClassFileLocator.java

-82
This file was deleted.

hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/SafeCacheProvider.java

-49
This file was deleted.

hibernate-core/src/main/java/org/hibernate/jpa/internal/enhance/EnhancingClassTransformerImpl.java

-3
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,6 @@ public byte[] transform(
6262
catch (final Exception e) {
6363
throw new TransformerException( "Error performing enhancement of " + className, e );
6464
}
65-
finally {
66-
bytecodeProvider.resetCaches();
67-
}
6865
}
6966

7067
@Override

0 commit comments

Comments
 (0)