mirror of https://github.com/apache/lucene.git
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:
parent
7efc00511e
commit
11f6b9185e
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue