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.
|
termIndexInterval (default 128) * ~2.1 billion = ~274 billion.
|
||||||
(Tom Burton-West via Mike McCandless)
|
(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
|
New features
|
||||||
|
|
||||||
* LUCENE-2128: Parallelized fetching document frequencies during weight
|
* LUCENE-2128: Parallelized fetching document frequencies during weight
|
||||||
|
|
|
@ -17,11 +17,12 @@ package org.apache.lucene.util;
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.IdentityHashMap;
|
import java.util.WeakHashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
@ -54,8 +55,8 @@ public class AttributeSource {
|
||||||
public static final AttributeFactory DEFAULT_ATTRIBUTE_FACTORY = new DefaultAttributeFactory();
|
public static final AttributeFactory DEFAULT_ATTRIBUTE_FACTORY = new DefaultAttributeFactory();
|
||||||
|
|
||||||
private static final class DefaultAttributeFactory extends AttributeFactory {
|
private static final class DefaultAttributeFactory extends AttributeFactory {
|
||||||
private static final IdentityHashMap<Class<? extends Attribute>, Class<? extends AttributeImpl>> attClassImplMap =
|
private static final WeakHashMap<Class<? extends Attribute>, WeakReference<Class<? extends AttributeImpl>>> attClassImplMap =
|
||||||
new IdentityHashMap<Class<? extends Attribute>, Class<? extends AttributeImpl>>();
|
new WeakHashMap<Class<? extends Attribute>, WeakReference<Class<? extends AttributeImpl>>>();
|
||||||
|
|
||||||
private DefaultAttributeFactory() {}
|
private DefaultAttributeFactory() {}
|
||||||
|
|
||||||
|
@ -72,12 +73,15 @@ public class AttributeSource {
|
||||||
|
|
||||||
private static Class<? extends AttributeImpl> getClassForInterface(Class<? extends Attribute> attClass) {
|
private static Class<? extends AttributeImpl> getClassForInterface(Class<? extends Attribute> attClass) {
|
||||||
synchronized(attClassImplMap) {
|
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) {
|
if (clazz == null) {
|
||||||
try {
|
try {
|
||||||
attClassImplMap.put(attClass,
|
attClassImplMap.put(attClass,
|
||||||
clazz = Class.forName(attClass.getName() + "Impl", true, attClass.getClassLoader())
|
new WeakReference<Class<? extends AttributeImpl>>(
|
||||||
.asSubclass(AttributeImpl.class)
|
clazz = Class.forName(attClass.getName() + "Impl", true, attClass.getClassLoader())
|
||||||
|
.asSubclass(AttributeImpl.class)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
} catch (ClassNotFoundException e) {
|
} catch (ClassNotFoundException e) {
|
||||||
throw new IllegalArgumentException("Could not find implementing class for " + attClass.getName());
|
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) */
|
/** 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 =
|
private static final WeakHashMap<Class<? extends AttributeImpl>,LinkedList<WeakReference<Class<? extends Attribute>>>> knownImplClasses =
|
||||||
new IdentityHashMap<Class<? extends AttributeImpl>,LinkedList<Class<? extends Attribute>>>();
|
new WeakHashMap<Class<? extends AttributeImpl>,LinkedList<WeakReference<Class<? extends Attribute>>>>();
|
||||||
|
|
||||||
/** <b>Expert:</b> Adds a custom AttributeImpl instance with one or more Attribute interfaces.
|
/** <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
|
* <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) {
|
public void addAttributeImpl(final AttributeImpl att) {
|
||||||
final Class<? extends AttributeImpl> clazz = att.getClass();
|
final Class<? extends AttributeImpl> clazz = att.getClass();
|
||||||
if (attributeImpls.containsKey(clazz)) return;
|
if (attributeImpls.containsKey(clazz)) return;
|
||||||
LinkedList<Class<? extends Attribute>> foundInterfaces;
|
LinkedList<WeakReference<Class<? extends Attribute>>> foundInterfaces;
|
||||||
synchronized(knownImplClasses) {
|
synchronized(knownImplClasses) {
|
||||||
foundInterfaces = knownImplClasses.get(clazz);
|
foundInterfaces = knownImplClasses.get(clazz);
|
||||||
if (foundInterfaces == null) {
|
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
|
// find all interfaces that this attribute instance implements
|
||||||
// and that extend the Attribute interface
|
// and that extend the Attribute interface
|
||||||
Class<?> actClazz = clazz;
|
Class<?> actClazz = clazz;
|
||||||
do {
|
do {
|
||||||
for (Class<?> curInterface : actClazz.getInterfaces()) {
|
for (Class<?> curInterface : actClazz.getInterfaces()) {
|
||||||
if (curInterface != Attribute.class && Attribute.class.isAssignableFrom(curInterface)) {
|
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();
|
actClazz = actClazz.getSuperclass();
|
||||||
|
@ -207,7 +213,10 @@ public class AttributeSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
// add all interfaces of this AttributeImpl to the maps
|
// 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
|
// Attribute is a superclass of this interface
|
||||||
if (!attributes.containsKey(curInterface)) {
|
if (!attributes.containsKey(curInterface)) {
|
||||||
// invalidate state to force recomputation in captureState()
|
// invalidate state to force recomputation in captureState()
|
||||||
|
|
|
@ -20,7 +20,7 @@ package org.apache.lucene.util;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.IdentityHashMap;
|
import java.util.WeakHashMap;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -64,8 +64,8 @@ public final class VirtualMethod<C> {
|
||||||
private final Class<C> baseClass;
|
private final Class<C> baseClass;
|
||||||
private final String method;
|
private final String method;
|
||||||
private final Class<?>[] parameters;
|
private final Class<?>[] parameters;
|
||||||
private final IdentityHashMap<Class<? extends C>, Integer> cache =
|
private final WeakHashMap<Class<? extends C>, Integer> cache =
|
||||||
new IdentityHashMap<Class<? extends C>, Integer>();
|
new WeakHashMap<Class<? extends C>, Integer>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance for the given {@code baseClass} and method declaration.
|
* Creates a new instance for the given {@code baseClass} and method declaration.
|
||||||
|
|
Loading…
Reference in New Issue