LUCENE-2260: Fix AttributeSource to not hold a strong reference to the Attribute/AttributeImpl classes which prevents unloading of custom attributes loaded by other classloaders. The same fix applies to VirtualMethod (3.1 only).

git-svn-id: https://svn.apache.org/repos/asf/lucene/java/trunk@909360 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Uwe Schindler 2010-02-12 11:20:35 +00:00
parent 7efc00511e
commit 11f6b9185e
3 changed files with 29 additions and 15 deletions

View File

@ -118,6 +118,11 @@ Bug fixes
termIndexInterval (default 128) * ~2.1 billion = ~274 billion.
(Tom Burton-West via Mike McCandless)
* LUCENE-2260: Fixed AttributeSource to not hold a strong
reference to the Attribute/AttributeImpl classes which prevents
unloading of custom attributes loaded by other classloaders
(e.g. in Solr plugins). (Uwe Schindler)
New features
* LUCENE-2128: Parallelized fetching document frequencies during weight

View File

@ -17,11 +17,12 @@ package org.apache.lucene.util;
* limitations under the License.
*/
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.NoSuchElementException;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.IdentityHashMap;
import java.util.WeakHashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;
@ -54,8 +55,8 @@ public class AttributeSource {
public static final AttributeFactory DEFAULT_ATTRIBUTE_FACTORY = new DefaultAttributeFactory();
private static final class DefaultAttributeFactory extends AttributeFactory {
private static final IdentityHashMap<Class<? extends Attribute>, Class<? extends AttributeImpl>> attClassImplMap =
new IdentityHashMap<Class<? extends Attribute>, Class<? extends AttributeImpl>>();
private static final WeakHashMap<Class<? extends Attribute>, WeakReference<Class<? extends AttributeImpl>>> attClassImplMap =
new WeakHashMap<Class<? extends Attribute>, WeakReference<Class<? extends AttributeImpl>>>();
private DefaultAttributeFactory() {}
@ -72,12 +73,15 @@ public class AttributeSource {
private static Class<? extends AttributeImpl> getClassForInterface(Class<? extends Attribute> attClass) {
synchronized(attClassImplMap) {
Class<? extends AttributeImpl> clazz = attClassImplMap.get(attClass);
final WeakReference<Class<? extends AttributeImpl>> ref = attClassImplMap.get(attClass);
Class<? extends AttributeImpl> clazz = (ref == null) ? null : ref.get();
if (clazz == null) {
try {
attClassImplMap.put(attClass,
clazz = Class.forName(attClass.getName() + "Impl", true, attClass.getClassLoader())
.asSubclass(AttributeImpl.class)
new WeakReference<Class<? extends AttributeImpl>>(
clazz = Class.forName(attClass.getName() + "Impl", true, attClass.getClassLoader())
.asSubclass(AttributeImpl.class)
)
);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("Could not find implementing class for " + attClass.getName());
@ -173,8 +177,8 @@ public class AttributeSource {
}
/** a cache that stores all interfaces for known implementation classes for performance (slow reflection) */
private static final IdentityHashMap<Class<? extends AttributeImpl>,LinkedList<Class<? extends Attribute>>> knownImplClasses =
new IdentityHashMap<Class<? extends AttributeImpl>,LinkedList<Class<? extends Attribute>>>();
private static final WeakHashMap<Class<? extends AttributeImpl>,LinkedList<WeakReference<Class<? extends Attribute>>>> knownImplClasses =
new WeakHashMap<Class<? extends AttributeImpl>,LinkedList<WeakReference<Class<? extends Attribute>>>>();
/** <b>Expert:</b> Adds a custom AttributeImpl instance with one or more Attribute interfaces.
* <p><font color="red"><b>Please note:</b> It is not guaranteed, that <code>att</code> is added to
@ -187,18 +191,20 @@ public class AttributeSource {
public void addAttributeImpl(final AttributeImpl att) {
final Class<? extends AttributeImpl> clazz = att.getClass();
if (attributeImpls.containsKey(clazz)) return;
LinkedList<Class<? extends Attribute>> foundInterfaces;
LinkedList<WeakReference<Class<? extends Attribute>>> foundInterfaces;
synchronized(knownImplClasses) {
foundInterfaces = knownImplClasses.get(clazz);
if (foundInterfaces == null) {
knownImplClasses.put(clazz, foundInterfaces = new LinkedList<Class<? extends Attribute>>());
// we have a strong reference to the class instance holding all interfaces in the list (parameter "att"),
// so all WeakReferences are never evicted by GC
knownImplClasses.put(clazz, foundInterfaces = new LinkedList<WeakReference<Class<? extends Attribute>>>());
// find all interfaces that this attribute instance implements
// and that extend the Attribute interface
Class<?> actClazz = clazz;
do {
for (Class<?> curInterface : actClazz.getInterfaces()) {
if (curInterface != Attribute.class && Attribute.class.isAssignableFrom(curInterface)) {
foundInterfaces.add(curInterface.asSubclass(Attribute.class));
foundInterfaces.add(new WeakReference<Class<? extends Attribute>>(curInterface.asSubclass(Attribute.class)));
}
}
actClazz = actClazz.getSuperclass();
@ -207,7 +213,10 @@ public class AttributeSource {
}
// add all interfaces of this AttributeImpl to the maps
for (Class<? extends Attribute> curInterface : foundInterfaces) {
for (WeakReference<Class<? extends Attribute>> curInterfaceRef : foundInterfaces) {
final Class<? extends Attribute> curInterface = curInterfaceRef.get();
assert (curInterface != null) :
"We have a strong reference on the class holding the interfaces, so they should never get evicted";
// Attribute is a superclass of this interface
if (!attributes.containsKey(curInterface)) {
// invalidate state to force recomputation in captureState()

View File

@ -20,7 +20,7 @@ package org.apache.lucene.util;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.WeakHashMap;
import java.util.Set;
/**
@ -64,8 +64,8 @@ public final class VirtualMethod<C> {
private final Class<C> baseClass;
private final String method;
private final Class<?>[] parameters;
private final IdentityHashMap<Class<? extends C>, Integer> cache =
new IdentityHashMap<Class<? extends C>, Integer>();
private final WeakHashMap<Class<? extends C>, Integer> cache =
new WeakHashMap<Class<? extends C>, Integer>();
/**
* Creates a new instance for the given {@code baseClass} and method declaration.