You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-commits@lucene.apache.org by us...@apache.org on 2010/02/12 12:21:59 UTC

svn commit: r909361 - in /lucene/java/branches/lucene_2_9: CHANGES.txt src/java/org/apache/lucene/util/AttributeSource.java

Author: uschindler
Date: Fri Feb 12 11:21:58 2010
New Revision: 909361

URL: http://svn.apache.org/viewvc?rev=909361&view=rev
Log:
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.

Modified:
    lucene/java/branches/lucene_2_9/CHANGES.txt
    lucene/java/branches/lucene_2_9/src/java/org/apache/lucene/util/AttributeSource.java

Modified: lucene/java/branches/lucene_2_9/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/java/branches/lucene_2_9/CHANGES.txt?rev=909361&r1=909360&r2=909361&view=diff
==============================================================================
--- lucene/java/branches/lucene_2_9/CHANGES.txt (original)
+++ lucene/java/branches/lucene_2_9/CHANGES.txt Fri Feb 12 11:21:58 2010
@@ -35,6 +35,11 @@
    implementation class when interface was loaded by a different
    class loader.  (Uwe Schindler, reported on java-user by Ahmed El-dawy)
 
+ * 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)
+
 API Changes
 
  * LUCENE-2190: Added setNextReader method to CustomScoreQuery, which

Modified: lucene/java/branches/lucene_2_9/src/java/org/apache/lucene/util/AttributeSource.java
URL: http://svn.apache.org/viewvc/lucene/java/branches/lucene_2_9/src/java/org/apache/lucene/util/AttributeSource.java?rev=909361&r1=909360&r2=909361&view=diff
==============================================================================
--- lucene/java/branches/lucene_2_9/src/java/org/apache/lucene/util/AttributeSource.java (original)
+++ lucene/java/branches/lucene_2_9/src/java/org/apache/lucene/util/AttributeSource.java Fri Feb 12 11:21:58 2010
@@ -17,11 +17,12 @@
  * 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;
@@ -55,7 +56,7 @@
     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();
+      private static final WeakHashMap/*<Class<? extends Attribute>, WeakReference<Class<? extends AttributeImpl>>>*/ attClassImplMap = new WeakHashMap();
       
       private DefaultAttributeFactory() {}
     
@@ -71,12 +72,13 @@
       
       private static Class getClassForInterface(Class attClass) {
         synchronized(attClassImplMap) {
-          Class clazz = (Class) attClassImplMap.get(attClass);
+          final WeakReference ref = (WeakReference) attClassImplMap.get(attClass);
+          Class clazz = (ref == null) ? null : ((Class) ref.get());
           if (clazz == null) {
             try {
-              attClassImplMap.put(attClass,
+              attClassImplMap.put(attClass, new WeakReference(
                 clazz = Class.forName(attClass.getName() + "Impl", true, attClass.getClassLoader())
-              );
+              ));
             } catch (ClassNotFoundException e) {
               throw new IllegalArgumentException("Could not find implementing class for " + attClass.getName());
             }
@@ -173,7 +175,8 @@
   }
   
   /** 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();
+  private static final WeakHashMap/*<Class<? extends AttributeImpl>,LinkedList<WeakReference<Class<? extends Attribute>>>>*/
+    knownImplClasses = new WeakHashMap();
   
   /** Adds a custom AttributeImpl instance with one or more Attribute interfaces. */
   public void addAttributeImpl(final AttributeImpl att) {
@@ -183,6 +186,8 @@
     synchronized(knownImplClasses) {
       foundInterfaces = (LinkedList) knownImplClasses.get(clazz);
       if (foundInterfaces == null) {
+        // 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());
         // find all interfaces that this attribute instance implements
         // and that extend the Attribute interface
@@ -192,7 +197,7 @@
           for (int i = 0; i < interfaces.length; i++) {
             final Class curInterface = interfaces[i];
             if (curInterface != Attribute.class && Attribute.class.isAssignableFrom(curInterface)) {
-              foundInterfaces.add(curInterface);
+              foundInterfaces.add(new WeakReference(curInterface));
             }
           }
           actClazz = actClazz.getSuperclass();
@@ -202,7 +207,10 @@
     
     // add all interfaces of this AttributeImpl to the maps
     for (Iterator it = foundInterfaces.iterator(); it.hasNext(); ) {
-      final Class curInterface = (Class) it.next();
+      final WeakReference curInterfaceRef = (WeakReference) it.next();
+      final Class curInterface = (Class) 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()