You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by mi...@apache.org on 2012/02/17 20:30:07 UTC

svn commit: r1245720 - in /lucene/dev/branches/branch_3x: ./ lucene/ lucene/core/src/java/org/apache/lucene/search/ lucene/core/src/test/org/apache/lucene/search/

Author: mikemccand
Date: Fri Feb 17 19:30:06 2012
New Revision: 1245720

URL: http://svn.apache.org/viewvc?rev=1245720&view=rev
Log:
LUCENE-3776: now you acquire/release directly from NRTManager (fixes trap)

Modified:
    lucene/dev/branches/branch_3x/   (props changed)
    lucene/dev/branches/branch_3x/lucene/   (props changed)
    lucene/dev/branches/branch_3x/lucene/CHANGES.txt
    lucene/dev/branches/branch_3x/lucene/core/src/java/org/apache/lucene/search/NRTManager.java
    lucene/dev/branches/branch_3x/lucene/core/src/java/org/apache/lucene/search/NRTManagerReopenThread.java
    lucene/dev/branches/branch_3x/lucene/core/src/java/org/apache/lucene/search/ReferenceManager.java
    lucene/dev/branches/branch_3x/lucene/core/src/java/org/apache/lucene/search/SearcherManager.java
    lucene/dev/branches/branch_3x/lucene/core/src/test/org/apache/lucene/search/TestNRTManager.java
    lucene/dev/branches/branch_3x/lucene/core/src/test/org/apache/lucene/search/TestSearcherManager.java

Modified: lucene/dev/branches/branch_3x/lucene/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/CHANGES.txt?rev=1245720&r1=1245719&r2=1245720&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/CHANGES.txt (original)
+++ lucene/dev/branches/branch_3x/lucene/CHANGES.txt Fri Feb 17 19:30:06 2012
@@ -120,6 +120,9 @@ API Changes
   method maybeReopen has been deprecated in favor of maybeRefresh().
   (Shai Erera, Mike McCandless, Simon Willnauer)
 
+* LUCENE-3776: You now acquire/release the IndexSearcher directly from
+  NRTManager.  (Mike McCandless)
+  
 New Features
 
 * LUCENE-3593: Added a FieldValueFilter that accepts all documents that either

Modified: lucene/dev/branches/branch_3x/lucene/core/src/java/org/apache/lucene/search/NRTManager.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/core/src/java/org/apache/lucene/search/NRTManager.java?rev=1245720&r1=1245719&r2=1245720&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/core/src/java/org/apache/lucene/search/NRTManager.java (original)
+++ lucene/dev/branches/branch_3x/lucene/core/src/java/org/apache/lucene/search/NRTManager.java Fri Feb 17 19:30:06 2012
@@ -17,7 +17,6 @@ package org.apache.lucene.search;
  * limitations under the License.
  */
 
-import java.io.Closeable;
 import java.io.IOException;
 import java.util.Collection;
 import java.util.List;
@@ -52,13 +51,11 @@ import org.apache.lucene.util.ThreadInte
  * not.  In this case you should use a single {@link
  * NRTManager.TrackingIndexWriter} instance for both.
  *
- * <p>Then, use {@link #getSearcherManager} to obtain the
- * {@link SearcherManager} that you then use to
- * acquire/release searchers.  Don't call maybeReopen on
- * that SearcherManager!  Only call NRTManager's {@link
- * #maybeReopen}.
+ * <p>Then, use {@link #acquire} to obtain the
+ * {@link IndexSearcher}, and {@link #release} (ideally,
+ * from within a <code>finally</code> clause) to release it.
  *
- * <p>NOTE: to use this class, you must call {@link #maybeReopen()}
+ * <p>NOTE: to use this class, you must call {@link #maybeRefresh()}
  * periodically.  The {@link NRTManagerReopenThread} is a
  * simple class to do this on a periodic basis, and reopens
  * more quickly if a request is waiting.  If you implement
@@ -72,14 +69,14 @@ import org.apache.lucene.util.ThreadInte
  * @lucene.experimental
  */
 
-public class NRTManager implements Closeable {
+public class NRTManager extends ReferenceManager<IndexSearcher> {
   private static final long MAX_SEARCHER_GEN = Long.MAX_VALUE;
   private final TrackingIndexWriter writer;
   private final List<WaitingListener> waitingListeners = new CopyOnWriteArrayList<WaitingListener>();
-  private final ReentrantLock reopenLock = new ReentrantLock();
-  private final Condition newGeneration = reopenLock.newCondition();
+  private final ReentrantLock genLock = new ReentrantLock();;
+  private final Condition newGeneration = genLock.newCondition();
+  private final SearcherFactory searcherFactory;
 
-  private final SearcherManager mgr;
   private volatile long searchingGen;
 
   /**
@@ -102,24 +99,25 @@ public class NRTManager implements Close
    * apply deletes.  This is useful for cases where certain
    * uses can tolerate seeing some deleted docs, since
    * reopen time is faster if deletes need not be applied. */
-  public NRTManager(TrackingIndexWriter writer, SearcherFactory searcherFactory, boolean applyDeletes) throws IOException {
+  public NRTManager(TrackingIndexWriter writer, SearcherFactory searcherFactory, boolean applyAllDeletes) throws IOException {
     this.writer = writer;
-    mgr = new SearcherManager(writer.getIndexWriter(), applyDeletes, searcherFactory);
+    if (searcherFactory == null) {
+      searcherFactory = new SearcherFactory();
+    }
+    this.searcherFactory = searcherFactory;
+    current = SearcherManager.getSearcher(searcherFactory, IndexReader.open(writer.getIndexWriter(), applyAllDeletes));
   }
 
-  /**
-   * Returns the {@link SearcherManager} you should use to
-   * acquire/release searchers.
-   *
-   * <p><b>NOTE</b>: Never call maybeReopen on the returned
-   * SearcherManager; only call this NRTManager's {@link
-   * #maybeReopen}.  Otherwise threads waiting for a
-   * generation may never return.
-   */
-  public SearcherManager getSearcherManager() {
-    return mgr;
+  @Override
+  protected void decRef(IndexSearcher reference) throws IOException {
+    reference.getIndexReader().decRef();
   }
   
+  @Override
+  protected boolean tryIncRef(IndexSearcher reference) {
+    return reference.getIndexReader().tryIncRef();
+  }
+
   /** NRTManager invokes this interface to notify it when a
    *  caller is waiting for a specific generation searcher
    *  to be visible. */
@@ -265,7 +263,7 @@ public class NRTManager implements Close
    * If the current searcher is older than the
    * target generation, this method will block
    * until the searcher is reopened, by another via
-   * {@link #maybeReopen} or until the {@link NRTManager} is closed.
+   * {@link #maybeRefresh} or until the {@link NRTManager} is closed.
    * 
    * @param targetGen the generation to wait for
    */
@@ -278,7 +276,7 @@ public class NRTManager implements Close
    * the searcher.  If the current searcher is older than
    * the target generation, this method will block until the
    * searcher has been reopened by another thread via
-   * {@link #maybeReopen}, the given waiting time has elapsed, or until
+   * {@link #maybeRefresh}, the given waiting time has elapsed, or until
    * the NRTManager is closed.
    * <p>
    * NOTE: if the waiting time elapses before the requested target generation is
@@ -297,7 +295,7 @@ public class NRTManager implements Close
       if (targetGen > curGen) {
         throw new IllegalArgumentException("targetGen=" + targetGen + " was never returned by this NRTManager instance (current gen=" + curGen + ")");
       }
-      reopenLock.lockInterruptibly();
+      genLock.lockInterruptibly();
       try {
         if (targetGen > searchingGen) {
           for (WaitingListener listener : waitingListeners) {
@@ -310,7 +308,7 @@ public class NRTManager implements Close
           }
         }
       } finally {
-        reopenLock.unlock();
+        genLock.unlock();
       }
     } catch (InterruptedException ie) {
       throw new ThreadInterruptedException(ie);
@@ -319,7 +317,7 @@ public class NRTManager implements Close
   
   private boolean waitOnGenCondition(long time, TimeUnit unit)
       throws InterruptedException {
-    assert reopenLock.isHeldByCurrentThread();
+    assert genLock.isHeldByCurrentThread();
     if (time < 0) {
       newGeneration.await();
       return true;
@@ -333,51 +331,63 @@ public class NRTManager implements Close
     return searchingGen;
   }
 
-  public void maybeReopen() throws IOException {
-    if (reopenLock.tryLock()) {
-      try {
-        // Mark gen as of when reopen started:
-        final long newSearcherGen = writer.getAndIncrementGeneration();
-        if (searchingGen == MAX_SEARCHER_GEN) {
-          newGeneration.signalAll(); // wake up threads if we have a new generation
-          return;
-        }
-        boolean setSearchGen;
-        if (!mgr.isSearcherCurrent()) {
-          setSearchGen = mgr.maybeRefresh();
-        } else {
-          setSearchGen = true;
-        }
-        if (setSearchGen) {
-          searchingGen = newSearcherGen;// update searcher gen
-          newGeneration.signalAll(); // wake up threads if we have a new generation
-        }
-      } finally {
-        reopenLock.unlock();
+  private long lastRefreshGen;
+
+  @Override
+  protected IndexSearcher refreshIfNeeded(IndexSearcher referenceToRefresh) throws IOException {
+    // Record gen as of when reopen started:
+    lastRefreshGen = writer.getAndIncrementGeneration();
+    final IndexReader r = referenceToRefresh.getIndexReader();
+    IndexSearcher newSearcher = null;
+    if (!r.isCurrent()) {
+      final IndexReader newReader = IndexReader.openIfChanged(r);
+      if (newReader != null) {
+        newSearcher = SearcherManager.getSearcher(searcherFactory, newReader);
+      }
+    }
+
+    return newSearcher;
+  }
+
+  @Override
+  protected void afterRefresh() {
+    genLock.lock();
+    try {
+      if (searchingGen != MAX_SEARCHER_GEN) {
+        // update searchingGen:
+        assert lastRefreshGen >= searchingGen;
+        searchingGen = lastRefreshGen;
       }
+      // wake up threads if we have a new generation:
+      newGeneration.signalAll();
+    } finally {
+      genLock.unlock();
+    }
+  }
+
+  @Override
+  protected synchronized void afterClose() throws IOException {
+    genLock.lock();
+    try {
+      // max it out to make sure nobody can wait on another gen
+      searchingGen = MAX_SEARCHER_GEN; 
+      newGeneration.signalAll();
+    } finally {
+      genLock.unlock();
     }
   }
 
   /**
-   * Close this NRTManager to future searching. Any searches still in process in
-   * other threads won't be affected, and they should still call
-   * {@link SearcherManager#release} after they are done.
-   * 
-   * <p>
-   * <b>NOTE</b>: caller must separately close the writer.
+   * Returns <code>true</code> if no changes have occured since this searcher
+   * ie. reader was opened, otherwise <code>false</code>.
+   * @see IndexReader#isCurrent() 
    */
-  public void close() throws IOException {
-    reopenLock.lock();
+  public boolean isSearcherCurrent() throws IOException {
+    final IndexSearcher searcher = acquire();
     try {
-      try {
-        // max it out to make sure nobody can wait on another gen
-        searchingGen = MAX_SEARCHER_GEN; 
-        mgr.close();
-      } finally { // make sure we signal even if close throws an exception
-        newGeneration.signalAll();
-      }
+      return searcher.getIndexReader().isCurrent();
     } finally {
-      reopenLock.unlock();
+      release(searcher);
     }
   }
 }

Modified: lucene/dev/branches/branch_3x/lucene/core/src/java/org/apache/lucene/search/NRTManagerReopenThread.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/core/src/java/org/apache/lucene/search/NRTManagerReopenThread.java?rev=1245720&r1=1245719&r2=1245720&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/core/src/java/org/apache/lucene/search/NRTManagerReopenThread.java (original)
+++ lucene/dev/branches/branch_3x/lucene/core/src/java/org/apache/lucene/search/NRTManagerReopenThread.java Fri Feb 17 19:30:06 2012
@@ -181,7 +181,7 @@ public class NRTManagerReopenThread exte
         lastReopenStartNS = System.nanoTime();
         try {
           //final long t0 = System.nanoTime();
-          manager.maybeReopen();
+          manager.maybeRefresh();
           //System.out.println("reopen took " + ((System.nanoTime()-t0)/1000000.0) + " msec");
         } catch (IOException ioe) {
           //System.out.println(Thread.currentThread().getName() + ": IOE");

Modified: lucene/dev/branches/branch_3x/lucene/core/src/java/org/apache/lucene/search/ReferenceManager.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/core/src/java/org/apache/lucene/search/ReferenceManager.java?rev=1245720&r1=1245719&r2=1245720&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/core/src/java/org/apache/lucene/search/ReferenceManager.java (original)
+++ lucene/dev/branches/branch_3x/lucene/core/src/java/org/apache/lucene/search/ReferenceManager.java Fri Feb 17 19:30:06 2012
@@ -56,7 +56,7 @@ public abstract class ReferenceManager<G
     current = newReference;
     release(oldReference);
   }
-  
+
   /** Decrement reference counting on the given reference. */
   protected abstract void decRef(G reference) throws IOException;
   
@@ -100,9 +100,14 @@ public abstract class ReferenceManager<G
       // closeable javadoc says:
       // if this is already closed then invoking this method has no effect.
       swapReference(null);
+      afterClose();
     }
   }
 
+  /** Called after close(), so subclass can free any resources. */
+  protected void afterClose() throws IOException {
+  }
+
   /**
    * You must call this, periodically, if you want that {@link #acquire()} will
    * return refreshed instances.
@@ -116,13 +121,16 @@ public abstract class ReferenceManager<G
    * refresh to complete.
    * 
    * <p>
-   * This method returns true if the reference was in fact refreshed, or if the
-   * current reference has no pending changes.
+   * If this method returns true it means the calling thread either refreshed
+   * or that there were no changes to refresh.  If it returns false it means another
+   * thread is currently refreshing.
    */
   public final boolean maybeRefresh() throws IOException {
     ensureOpen();
+
     // Ensure only 1 thread does reopen at once; other threads just return immediately:
-    if (reopenLock.tryAcquire()) {
+    final boolean doTryRefresh = reopenLock.tryAcquire();
+    if (doTryRefresh) {
       try {
         final G reference = acquire();
         try {
@@ -142,15 +150,20 @@ public abstract class ReferenceManager<G
         } finally {
           release(reference);
         }
-        return true;
+        afterRefresh();
       } finally {
         reopenLock.release();
       }
-    } else {
-      return false;
     }
+
+    return doTryRefresh;
   }
 
+  /** Called after swapReference has installed a new
+   *  instance. */
+  protected void afterRefresh() throws IOException {
+  }
+  
   /**
    * Release the refernce previously obtained via {@link #acquire()}.
    * <p>
@@ -160,5 +173,4 @@ public abstract class ReferenceManager<G
     assert reference != null;
     decRef(reference);
   }
-  
 }

Modified: lucene/dev/branches/branch_3x/lucene/core/src/java/org/apache/lucene/search/SearcherManager.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/core/src/java/org/apache/lucene/search/SearcherManager.java?rev=1245720&r1=1245719&r2=1245720&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/core/src/java/org/apache/lucene/search/SearcherManager.java (original)
+++ lucene/dev/branches/branch_3x/lucene/core/src/java/org/apache/lucene/search/SearcherManager.java Fri Feb 17 19:30:06 2012
@@ -79,9 +79,26 @@ public final class SearcherManager exten
       searcherFactory = new SearcherFactory();
     }
     this.searcherFactory = searcherFactory;
-    current = searcherFactory.newSearcher(IndexReader.open(writer, applyAllDeletes));
+    current = getSearcher(searcherFactory, IndexReader.open(writer, applyAllDeletes));
   }
   
+  /**
+   * Creates and returns a new SearcherManager from the given {@link Directory}. 
+   * @param dir the directory to open the DirectoryReader on.
+   * @param searcherFactory An optional {@link SearcherFactory}. Pass
+   *        <code>null</code> if you don't require the searcher to be warmed
+   *        before going live or other custom behavior.
+   *        
+   * @throws IOException
+   */
+  public SearcherManager(Directory dir, SearcherFactory searcherFactory) throws IOException {
+    if (searcherFactory == null) {
+      searcherFactory = new SearcherFactory();
+    }
+    this.searcherFactory = searcherFactory;
+    current = getSearcher(searcherFactory, IndexReader.open(dir));
+  }
+
   @Override
   protected void decRef(IndexSearcher reference) throws IOException {
     reference.getIndexReader().decRef();
@@ -93,7 +110,7 @@ public final class SearcherManager exten
     if (newReader == null) {
       return null;
     } else {
-      return searcherFactory.newSearcher(newReader);
+      return getSearcher(searcherFactory, newReader);
     }
   }
   
@@ -102,25 +119,9 @@ public final class SearcherManager exten
     return reference.getIndexReader().tryIncRef();
   }
 
-  /**
-   * Creates and returns a new SearcherManager from the given {@link Directory}. 
-   * @param dir the directory to open the IndexReader on.
-   * @param searcherFactory An optional {@link SearcherFactory}. Pass
-   *        <code>null</code> if you don't require the searcher to be warmed
-   *        before going live or other custom behavior.
-   *        
-   * @throws IOException
-   */
-  public SearcherManager(Directory dir, SearcherFactory searcherFactory) throws IOException {
-    if (searcherFactory == null) {
-      searcherFactory = new SearcherFactory();
-    }
-    this.searcherFactory = searcherFactory;
-    current = searcherFactory.newSearcher(IndexReader.open(dir));
-  }
-
   /** @deprecated see {@link #maybeRefresh()}. */
-  public final boolean maybeReopen() throws IOException {
+  @Deprecated
+  public boolean maybeReopen() throws IOException {
     return maybeRefresh();
   }
   
@@ -137,5 +138,22 @@ public final class SearcherManager exten
       release(searcher);
     }
   }
-  
+
+  // NOTE: decRefs incoming reader on throwing an exception
+  static IndexSearcher getSearcher(SearcherFactory searcherFactory, IndexReader reader) throws IOException {
+    boolean success = false;
+    final IndexSearcher searcher;
+    try {
+      searcher = searcherFactory.newSearcher(reader);
+      if (searcher.getIndexReader() != reader) {
+        throw new IllegalStateException("SearcherFactory must wrap exactly the provided reader (got " + searcher.getIndexReader() + " but expected " + reader + ")");
+      }
+      success = true;
+    } finally {
+      if (!success) {
+        reader.decRef();
+      }
+    }
+    return searcher;
+  }
 }

Modified: lucene/dev/branches/branch_3x/lucene/core/src/test/org/apache/lucene/search/TestNRTManager.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/core/src/test/org/apache/lucene/search/TestNRTManager.java?rev=1245720&r1=1245719&r2=1245720&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/core/src/test/org/apache/lucene/search/TestNRTManager.java (original)
+++ lucene/dev/branches/branch_3x/lucene/core/src/test/org/apache/lucene/search/TestNRTManager.java Fri Feb 17 19:30:06 2012
@@ -32,6 +32,7 @@ import org.apache.lucene.index.CorruptIn
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.IndexWriter;
 import org.apache.lucene.index.IndexWriterConfig;
+import org.apache.lucene.index.RandomIndexWriter;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.index.ThreadedIndexingAndSearchingTestCase;
 import org.apache.lucene.store.Directory;
@@ -55,7 +56,7 @@ public class TestNRTManager extends Thre
       System.out.println("TEST: finalSearcher maxGen=" + maxGen);
     }
     nrtDeletes.waitForGeneration(maxGen);
-    return nrtDeletes.getSearcherManager().acquire();
+    return nrtDeletes.acquire();
   }
 
   @Override
@@ -82,14 +83,14 @@ public class TestNRTManager extends Thre
         System.out.println(Thread.currentThread().getName() + ": nrt: verify " + id);
       }
       nrtDeletes.waitForGeneration(gen);
-      final IndexSearcher s = nrtDeletes.getSearcherManager().acquire();
+      final IndexSearcher s = nrtDeletes.acquire();
       if (VERBOSE) {
         System.out.println(Thread.currentThread().getName() + ": nrt: got searcher=" + s);
       }
       try {
         assertEquals(docs.size(), s.search(new TermQuery(id), 10).totalHits);
       } finally {
-        nrtDeletes.getSearcherManager().release(s);
+        nrtDeletes.release(s);
       }
     }
     
@@ -105,14 +106,14 @@ public class TestNRTManager extends Thre
         System.out.println(Thread.currentThread().getName() + ": nrt: verify " + id);
       }
       nrtNoDeletes.waitForGeneration(gen);
-      final IndexSearcher s = nrtNoDeletes.getSearcherManager().acquire();
+      final IndexSearcher s = nrtNoDeletes.acquire();
       if (VERBOSE) {
         System.out.println(Thread.currentThread().getName() + ": nrt: got searcher=" + s);
       }
       try {
         assertEquals(docs.size(), s.search(new TermQuery(id), 10).totalHits);
       } finally {
-        nrtNoDeletes.getSearcherManager().release(s);
+        nrtNoDeletes.release(s);
       }
     }
     lastGens.set(gen);
@@ -128,14 +129,14 @@ public class TestNRTManager extends Thre
         System.out.println(Thread.currentThread().getName() + ": nrt: verify " + id);
       }
       nrtNoDeletes.waitForGeneration(gen);
-      final IndexSearcher s = nrtNoDeletes.getSearcherManager().acquire();
+      final IndexSearcher s = nrtNoDeletes.acquire();
       if (VERBOSE) {
         System.out.println(Thread.currentThread().getName() + ": nrt: got searcher=" + s);
       }
       try {
         assertEquals(1, s.search(new TermQuery(id), 10).totalHits);
       } finally {
-        nrtNoDeletes.getSearcherManager().release(s);
+        nrtNoDeletes.release(s);
       }
     }
     lastGens.set(gen);
@@ -150,14 +151,14 @@ public class TestNRTManager extends Thre
         System.out.println(Thread.currentThread().getName() + ": nrt: verify " + id);
       }
       nrtDeletes.waitForGeneration(gen);
-      final IndexSearcher s = nrtDeletes.getSearcherManager().acquire();
+      final IndexSearcher s = nrtDeletes.acquire();
       if (VERBOSE) {
         System.out.println(Thread.currentThread().getName() + ": nrt: got searcher=" + s);
       }
       try {
         assertEquals(1, s.search(new TermQuery(id), 10).totalHits);
       } finally {
-        nrtDeletes.getSearcherManager().release(s);
+        nrtDeletes.release(s);
       }
     }
     lastGens.set(gen);
@@ -172,14 +173,14 @@ public class TestNRTManager extends Thre
         System.out.println(Thread.currentThread().getName() + ": nrt: verify del " + id);
       }
       nrtDeletes.waitForGeneration(gen);
-      final IndexSearcher s = nrtDeletes.getSearcherManager().acquire();
+      final IndexSearcher s = nrtDeletes.acquire();
       if (VERBOSE) {
         System.out.println(Thread.currentThread().getName() + ": nrt: got searcher=" + s);
       }
       try {
         assertEquals(0, s.search(new TermQuery(id), 10).totalHits);
       } finally {
-        nrtDeletes.getSearcherManager().release(s);
+        nrtDeletes.release(s);
       }
     }
     lastGens.set(gen);
@@ -263,7 +264,7 @@ public class TestNRTManager extends Thre
       nrt = nrtNoDeletes;
     }
 
-    return nrt.getSearcherManager().acquire();
+    return nrt.acquire();
   }
 
   @Override
@@ -272,7 +273,7 @@ public class TestNRTManager extends Thre
     // against the same NRT mgr you acquired from... but
     // both impls just decRef the underlying reader so we
     // can get away w/ cheating:
-    nrtNoDeletes.getSearcherManager().release(s);
+    nrtNoDeletes.release(s);
   }
 
   @Override
@@ -302,15 +303,15 @@ public class TestNRTManager extends Thre
     Document doc = new Document();
     doc.add(newField("test","test", Store.YES, Index.ANALYZED));
     long gen = writer.addDocument(doc);
-    manager.maybeReopen();
+    manager.maybeRefresh();
     assertFalse(gen < manager.getCurrentSearchingGen());
     Thread t = new Thread() {
       public void run() {
         try {
           signal.await();
-          manager.maybeReopen();
+          manager.maybeRefresh();
           writer.deleteDocuments(new TermQuery(new Term("foo", "barista")));
-          manager.maybeReopen(); // kick off another reopen so we inc. the internal gen
+          manager.maybeRefresh(); // kick off another reopen so we inc. the internal gen
         } catch (Exception e) {
           e.printStackTrace();
         } finally {
@@ -322,13 +323,13 @@ public class TestNRTManager extends Thre
     _writer.waitAfterUpdate = true; // wait in addDocument to let some reopens go through
     final long lastGen = writer.updateDocument(new Term("foo", "bar"), doc); // once this returns the doc is already reflected in the last reopen
 
-    assertFalse(manager.getSearcherManager().isSearcherCurrent()); // false since there is a delete in the queue
+    assertFalse(manager.isSearcherCurrent()); // false since there is a delete in the queue
     
-    IndexSearcher acquire = manager.getSearcherManager().acquire();
+    IndexSearcher searcher = manager.acquire();
     try {
-      assertEquals(2, acquire.getIndexReader().numDocs());
+      assertEquals(2, searcher.getIndexReader().numDocs());
     } finally {
-      manager.getSearcherManager().release(acquire);
+      manager.release(searcher);
     }
     NRTManagerReopenThread thread = new NRTManagerReopenThread(manager, 0.01, 0.01);
     thread.start(); // start reopening
@@ -344,7 +345,7 @@ public class TestNRTManager extends Thre
       }
     };
     waiter.start();
-    manager.maybeReopen();
+    manager.maybeRefresh();
     waiter.join(1000);
     if (!finished.get()) {
       waiter.interrupt();
@@ -384,4 +385,28 @@ public class TestNRTManager extends Thre
       }
     }
   }
+
+  public void testEvilSearcherFactory() throws Exception {
+    final Directory dir = newDirectory();
+    final RandomIndexWriter w = new RandomIndexWriter(random, dir);
+    w.commit();
+
+    final IndexReader other = IndexReader.open(dir);
+
+    final SearcherFactory theEvilOne = new SearcherFactory() {
+      @Override
+      public IndexSearcher newSearcher(IndexReader ignored) throws IOException {
+        return new IndexSearcher(other);
+      }
+      };
+
+    try {
+      new NRTManager(new NRTManager.TrackingIndexWriter(w.w), theEvilOne);
+    } catch (IllegalStateException ise) {
+      // expected
+    }
+    w.close();
+    other.close();
+    dir.close();
+  }
 }

Modified: lucene/dev/branches/branch_3x/lucene/core/src/test/org/apache/lucene/search/TestSearcherManager.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/core/src/test/org/apache/lucene/search/TestSearcherManager.java?rev=1245720&r1=1245719&r2=1245720&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/core/src/test/org/apache/lucene/search/TestSearcherManager.java (original)
+++ lucene/dev/branches/branch_3x/lucene/core/src/test/org/apache/lucene/search/TestSearcherManager.java Fri Feb 17 19:30:06 2012
@@ -32,6 +32,7 @@ import org.apache.lucene.index.Concurren
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.IndexWriter;
 import org.apache.lucene.index.IndexWriterConfig;
+import org.apache.lucene.index.RandomIndexWriter;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.index.ThreadedIndexingAndSearchingTestCase;
 import org.apache.lucene.store.AlreadyClosedException;
@@ -312,5 +313,33 @@ public class TestSearcherManager extends
     }
     dir.close();
   }
-  
+
+  public void testEvilSearcherFactory() throws Exception {
+    final Directory dir = newDirectory();
+    final RandomIndexWriter w = new RandomIndexWriter(random, dir);
+    w.commit();
+
+    final IndexReader other = IndexReader.open(dir);
+
+    final SearcherFactory theEvilOne = new SearcherFactory() {
+      @Override
+      public IndexSearcher newSearcher(IndexReader ignored) throws IOException {
+        return new IndexSearcher(other);
+      }
+      };
+
+    try {
+      new SearcherManager(dir, theEvilOne);
+    } catch (IllegalStateException ise) {
+      // expected
+    }
+    try {
+      new SearcherManager(w.w, random.nextBoolean(), theEvilOne);
+    } catch (IllegalStateException ise) {
+      // expected
+    }
+    w.close();
+    other.close();
+    dir.close();
+  }
 }