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:08:51 UTC

svn commit: r1245710 - in /lucene/dev/trunk/lucene: ./ core/src/java/org/apache/lucene/search/ core/src/test/org/apache/lucene/search/

Author: mikemccand
Date: Fri Feb 17 19:08:51 2012
New Revision: 1245710

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

Modified:
    lucene/dev/trunk/lucene/CHANGES.txt
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/NRTManager.java
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/NRTManagerReopenThread.java
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/ReferenceManager.java
    lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/SearcherManager.java
    lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/search/TestNRTManager.java
    lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/search/TestSearcherManager.java

Modified: lucene/dev/trunk/lucene/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/CHANGES.txt?rev=1245710&r1=1245709&r2=1245710&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/CHANGES.txt (original)
+++ lucene/dev/trunk/lucene/CHANGES.txt Fri Feb 17 19:08:51 2012
@@ -815,6 +815,10 @@ API Changes
   create two NRTManagers (one always applying deletes and the other
   never applying deletes).  (MJB, Shai Erera, Mike McCandless)
 
+* 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/trunk/lucene/core/src/java/org/apache/lucene/search/NRTManager.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/NRTManager.java?rev=1245710&r1=1245709&r2=1245710&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/NRTManager.java (original)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/NRTManager.java Fri Feb 17 19:08:51 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.List;
 import java.util.concurrent.CopyOnWriteArrayList;
@@ -28,6 +27,7 @@ import java.util.concurrent.locks.Reentr
 
 import org.apache.lucene.analysis.Analyzer;
 import org.apache.lucene.index.CorruptIndexException;
+import org.apache.lucene.index.DirectoryReader;
 import org.apache.lucene.index.IndexReader; // javadocs
 import org.apache.lucene.index.IndexWriter;
 import org.apache.lucene.index.IndexableField;
@@ -71,14 +71,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;
 
   /**
@@ -101,24 +101,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, DirectoryReader.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. */
@@ -296,7 +297,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) {
@@ -309,7 +310,7 @@ public class NRTManager implements Close
           }
         }
       } finally {
-        reopenLock.unlock();
+        genLock.unlock();
       }
     } catch (InterruptedException ie) {
       throw new ThreadInterruptedException(ie);
@@ -318,7 +319,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;
@@ -332,51 +333,67 @@ 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();
+    assert r instanceof DirectoryReader: "searcher's IndexReader should be a DirectoryReader, but got " + r;
+    final DirectoryReader dirReader = (DirectoryReader) r;
+    IndexSearcher newSearcher = null;
+    if (!dirReader.isCurrent()) {
+      final IndexReader newReader = DirectoryReader.openIfChanged(dirReader);
+      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 DirectoryReader#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();
-      }
+      final IndexReader r = searcher.getIndexReader();
+      assert r instanceof DirectoryReader: "searcher's IndexReader should be a DirectoryReader, but got " + r;
+      return ((DirectoryReader) r).isCurrent();
     } finally {
-      reopenLock.unlock();
+      release(searcher);
     }
   }
 }

Modified: lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/NRTManagerReopenThread.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/NRTManagerReopenThread.java?rev=1245710&r1=1245709&r2=1245710&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/NRTManagerReopenThread.java (original)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/NRTManagerReopenThread.java Fri Feb 17 19:08:51 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/trunk/lucene/core/src/java/org/apache/lucene/search/ReferenceManager.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/ReferenceManager.java?rev=1245710&r1=1245709&r2=1245710&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/ReferenceManager.java (original)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/ReferenceManager.java Fri Feb 17 19:08:51 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/trunk/lucene/core/src/java/org/apache/lucene/search/SearcherManager.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/SearcherManager.java?rev=1245710&r1=1245709&r2=1245710&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/SearcherManager.java (original)
+++ lucene/dev/trunk/lucene/core/src/java/org/apache/lucene/search/SearcherManager.java Fri Feb 17 19:08:51 2012
@@ -86,9 +86,26 @@ public final class SearcherManager exten
       searcherFactory = new SearcherFactory();
     }
     this.searcherFactory = searcherFactory;
-    current = searcherFactory.newSearcher(DirectoryReader.open(writer, applyAllDeletes));
+    current = getSearcher(searcherFactory, DirectoryReader.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, DirectoryReader.open(dir));
+  }
+
   @Override
   protected void decRef(IndexSearcher reference) throws IOException {
     reference.getIndexReader().decRef();
@@ -97,12 +114,12 @@ public final class SearcherManager exten
   @Override
   protected IndexSearcher refreshIfNeeded(IndexSearcher referenceToRefresh) throws IOException {
     final IndexReader r = referenceToRefresh.getIndexReader();
-    final IndexReader newReader = (r instanceof DirectoryReader) ?
-      DirectoryReader.openIfChanged((DirectoryReader) r) : null;
+    assert r instanceof DirectoryReader: "searcher's IndexReader should be a DirectoryReader, but got " + r;
+    final IndexReader newReader = DirectoryReader.openIfChanged((DirectoryReader) r);
     if (newReader == null) {
       return null;
     } else {
-      return searcherFactory.newSearcher(newReader);
+      return getSearcher(searcherFactory, newReader);
     }
   }
   
@@ -112,23 +129,6 @@ public final class SearcherManager exten
   }
 
   /**
-   * 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 = searcherFactory.newSearcher(DirectoryReader.open(dir));
-  }
-
-  /**
    * Returns <code>true</code> if no changes have occured since this searcher
    * ie. reader was opened, otherwise <code>false</code>.
    * @see DirectoryReader#isCurrent() 
@@ -137,12 +137,28 @@ public final class SearcherManager exten
     final IndexSearcher searcher = acquire();
     try {
       final IndexReader r = searcher.getIndexReader();
-      return r instanceof DirectoryReader ?
-        ((DirectoryReader ) r).isCurrent() :
-        true;
+      assert r instanceof DirectoryReader: "searcher's IndexReader should be a DirectoryReader, but got " + r;
+      return ((DirectoryReader) r).isCurrent();
     } finally {
       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/trunk/lucene/core/src/test/org/apache/lucene/search/TestNRTManager.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/search/TestNRTManager.java?rev=1245710&r1=1245709&r2=1245710&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/search/TestNRTManager.java (original)
+++ lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/search/TestNRTManager.java Fri Feb 17 19:08:51 2012
@@ -28,10 +28,12 @@ import org.apache.lucene.analysis.MockAn
 import org.apache.lucene.document.Document;
 import org.apache.lucene.document.TextField;
 import org.apache.lucene.index.CorruptIndexException;
+import org.apache.lucene.index.DirectoryReader;
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.IndexWriter;
 import org.apache.lucene.index.IndexWriterConfig;
 import org.apache.lucene.index.IndexableField;
+import org.apache.lucene.index.RandomIndexWriter;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.index.ThreadedIndexingAndSearchingTestCase;
 import org.apache.lucene.store.Directory;
@@ -57,7 +59,7 @@ public class TestNRTManager extends Thre
       System.out.println("TEST: finalSearcher maxGen=" + maxGen);
     }
     nrtDeletes.waitForGeneration(maxGen);
-    return nrtDeletes.getSearcherManager().acquire();
+    return nrtDeletes.acquire();
   }
 
   @Override
@@ -84,14 +86,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);
       }
     }
     
@@ -107,14 +109,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);
@@ -130,14 +132,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);
@@ -152,14 +154,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);
@@ -174,14 +176,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);
@@ -265,7 +267,7 @@ public class TestNRTManager extends Thre
       nrt = nrtNoDeletes;
     }
 
-    return nrt.getSearcherManager().acquire();
+    return nrt.acquire();
   }
 
   @Override
@@ -274,7 +276,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
@@ -304,15 +306,15 @@ public class TestNRTManager extends Thre
     Document doc = new Document();
     doc.add(newField("test","test", TextField.TYPE_STORED));
     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 {
@@ -324,13 +326,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
@@ -346,7 +348,7 @@ public class TestNRTManager extends Thre
       }
     };
     waiter.start();
-    manager.maybeReopen();
+    manager.maybeRefresh();
     waiter.join(1000);
     if (!finished.get()) {
       waiter.interrupt();
@@ -386,4 +388,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 = DirectoryReader.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/trunk/lucene/core/src/test/org/apache/lucene/search/TestSearcherManager.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/search/TestSearcherManager.java?rev=1245710&r1=1245709&r2=1245710&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/search/TestSearcherManager.java (original)
+++ lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/search/TestSearcherManager.java Fri Feb 17 19:08:51 2012
@@ -29,9 +29,11 @@ import java.util.concurrent.atomic.Atomi
 import org.apache.lucene.analysis.MockAnalyzer;
 import org.apache.lucene.document.Document;
 import org.apache.lucene.index.ConcurrentMergeScheduler;
+import org.apache.lucene.index.DirectoryReader;
 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;
@@ -316,5 +318,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 = DirectoryReader.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();
+  }
 }