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 2011/10/05 17:17:29 UTC

svn commit: r1179256 - in /lucene/dev/branches/branch_3x: lucene/ lucene/contrib/misc/src/java/org/apache/lucene/index/ lucene/contrib/misc/src/java/org/apache/lucene/search/ lucene/contrib/misc/src/test/org/apache/lucene/index/ lucene/contrib/misc/src...

Author: mikemccand
Date: Wed Oct  5 15:17:28 2011
New Revision: 1179256

URL: http://svn.apache.org/viewvc?rev=1179256&view=rev
Log:
LUCENE-3464: rename IR.reopen -> IR.openIfChanged, and return null (not old reader) if there are no changes

Modified:
    lucene/dev/branches/branch_3x/lucene/CHANGES.txt
    lucene/dev/branches/branch_3x/lucene/contrib/misc/src/java/org/apache/lucene/index/NRTManager.java
    lucene/dev/branches/branch_3x/lucene/contrib/misc/src/java/org/apache/lucene/search/SearcherManager.java
    lucene/dev/branches/branch_3x/lucene/contrib/misc/src/test/org/apache/lucene/index/TestMultiPassIndexSplitter.java
    lucene/dev/branches/branch_3x/lucene/contrib/misc/src/test/org/apache/lucene/store/TestNRTCachingDirectory.java
    lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/index/DirectoryReader.java
    lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/index/IndexReader.java
    lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/index/MultiReader.java
    lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/index/ParallelReader.java
    lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/index/SegmentReader.java
    lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/search/IndexSearcher.java
    lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexReader.java
    lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexReaderClone.java
    lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexReaderReopen.java
    lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexWriter.java
    lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexWriterCommit.java
    lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexWriterReader.java
    lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestNRTThreads.java
    lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestNeverDelete.java
    lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestRollingUpdates.java
    lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestStressNRT.java
    lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/search/TestCachingSpanFilter.java
    lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/search/TestCachingWrapperFilter.java
    lucene/dev/branches/branch_3x/solr/core/src/java/org/apache/solr/core/SolrCore.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=1179256&r1=1179255&r2=1179256&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/CHANGES.txt (original)
+++ lucene/dev/branches/branch_3x/lucene/CHANGES.txt Wed Oct  5 15:17:28 2011
@@ -19,6 +19,11 @@ Changes in backwards compatibility polic
   As this is expert API, most code will not be affected.
   (Uwe Schindler, Doron Cohen, Mike McCandless)
 
+* LUCENE-3464: IndexReader.reopen has been renamed to
+  IndexReader.openIfChanged (a static method), and now returns null
+  (instead of the old reader) if there are no changes in the index, to
+  prevent the common pitfall of accidentally closing the old reader.
+
 Bug fixes
 
 * SOLR-2762: (backport form 4.x line): FSTLookup could return duplicate 

Modified: lucene/dev/branches/branch_3x/lucene/contrib/misc/src/java/org/apache/lucene/index/NRTManager.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/contrib/misc/src/java/org/apache/lucene/index/NRTManager.java?rev=1179256&r1=1179255&r2=1179256&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/contrib/misc/src/java/org/apache/lucene/index/NRTManager.java (original)
+++ lucene/dev/branches/branch_3x/lucene/contrib/misc/src/java/org/apache/lucene/index/NRTManager.java Wed Oct  5 15:17:28 2011
@@ -309,7 +309,14 @@ public class NRTManager implements Close
 
     // Start from whichever searcher is most current:
     final IndexSearcher startSearcher = noDeletesSearchingGen.get() > searchingGen.get() ? noDeletesCurrentSearcher : currentSearcher;
-    final IndexReader nextReader = startSearcher.getIndexReader().reopen(writer, applyDeletes);
+    IndexReader nextReader = IndexReader.openIfChanged(startSearcher.getIndexReader(), writer, applyDeletes);
+    if (nextReader == null) {
+      // NOTE: doesn't happen currently in Lucene (reopen on
+      // NRT reader always returns new reader), but could in
+      // the future:
+      nextReader = startSearcher.getIndexReader();
+      nextReader.incRef();
+    }
 
     if (nextReader != startSearcher.getIndexReader()) {
       final IndexSearcher nextSearcher = new IndexSearcher(nextReader, es);

Modified: lucene/dev/branches/branch_3x/lucene/contrib/misc/src/java/org/apache/lucene/search/SearcherManager.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/contrib/misc/src/java/org/apache/lucene/search/SearcherManager.java?rev=1179256&r1=1179255&r2=1179256&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/contrib/misc/src/java/org/apache/lucene/search/SearcherManager.java (original)
+++ lucene/dev/branches/branch_3x/lucene/contrib/misc/src/java/org/apache/lucene/search/SearcherManager.java Wed Oct  5 15:17:28 2011
@@ -111,7 +111,7 @@ public class SearcherManager implements 
   }
 
   /** You must call this, periodically, to perform a
-   *  reopen.  This calls {@link IndexReader#reopen} on the
+   *  reopen.  This calls {@link IndexReader#openIfChanged} on the
    *  underlying reader, and if that returns a new reader,
    *  it's warmed (if you provided a {@link SearcherWarmer}
    *  and then swapped into production.
@@ -139,8 +139,8 @@ public class SearcherManager implements 
     // threads just return immediately:
     if (reopening.tryAcquire()) {
       try {
-        IndexReader newReader = currentSearcher.getIndexReader().reopen();
-        if (newReader != currentSearcher.getIndexReader()) {
+        IndexReader newReader = IndexReader.openIfChanged(currentSearcher.getIndexReader());
+        if (newReader != null) {
           IndexSearcher newSearcher = new IndexSearcher(newReader, es);
           boolean success = false;
           try {

Modified: lucene/dev/branches/branch_3x/lucene/contrib/misc/src/test/org/apache/lucene/index/TestMultiPassIndexSplitter.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/contrib/misc/src/test/org/apache/lucene/index/TestMultiPassIndexSplitter.java?rev=1179256&r1=1179255&r2=1179256&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/contrib/misc/src/test/org/apache/lucene/index/TestMultiPassIndexSplitter.java (original)
+++ lucene/dev/branches/branch_3x/lucene/contrib/misc/src/test/org/apache/lucene/index/TestMultiPassIndexSplitter.java Wed Oct  5 15:17:28 2011
@@ -44,9 +44,6 @@ public class TestMultiPassIndexSplitter 
     input = IndexReader.open(dir, false);
     // delete the last doc
     input.deleteDocument(input.maxDoc() - 1);
-    IndexReader inputOld = input;
-    input = input.reopen(true);
-    inputOld.close();
   }
   
   @Override

Modified: lucene/dev/branches/branch_3x/lucene/contrib/misc/src/test/org/apache/lucene/store/TestNRTCachingDirectory.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/contrib/misc/src/test/org/apache/lucene/store/TestNRTCachingDirectory.java?rev=1179256&r1=1179255&r2=1179256&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/contrib/misc/src/test/org/apache/lucene/store/TestNRTCachingDirectory.java (original)
+++ lucene/dev/branches/branch_3x/lucene/contrib/misc/src/test/org/apache/lucene/store/TestNRTCachingDirectory.java Wed Oct  5 15:17:28 2011
@@ -65,8 +65,8 @@ public class TestNRTCachingDirectory ext
         if (r == null) {
           r = IndexReader.open(w.w, false);
         } else {
-          final IndexReader r2 = r.reopen();
-          if (r2 != r) {
+          final IndexReader r2 = IndexReader.openIfChanged(r);
+          if (r2 != null) {
             r.close();
             r = r2;
           }

Modified: lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/index/DirectoryReader.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/index/DirectoryReader.java?rev=1179256&r1=1179255&r2=1179256&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/index/DirectoryReader.java (original)
+++ lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/index/DirectoryReader.java Wed Oct  5 15:17:28 2011
@@ -183,7 +183,7 @@ class DirectoryReader extends IndexReade
     initialize(readers.toArray(new SegmentReader[readers.size()]));
   }
 
-  /** This constructor is only used for {@link #reopen()} */
+  /** This constructor is only used for {@link #doOpenIfChanged()} */
   DirectoryReader(Directory directory, SegmentInfos infos, SegmentReader[] oldReaders, int[] oldStarts,
                   Map<String,byte[]> oldNormsCache, boolean readOnly, boolean doClone, int termInfosIndexDivisor,
                   Collection<ReaderFinishedListener> readerFinishedListeners) throws IOException {
@@ -234,18 +234,21 @@ class DirectoryReader extends IndexReade
           // this is a new reader; in case we hit an exception we can close it safely
           newReader = SegmentReader.get(readOnly, infos.info(i), termInfosIndexDivisor);
           newReader.readerFinishedListeners = readerFinishedListeners;
-        } else {
-          newReader = newReaders[i].reopenSegment(infos.info(i), doClone, readOnly);
-          assert newReader.readerFinishedListeners == readerFinishedListeners;
-        }
-        if (newReader == newReaders[i]) {
-          // this reader will be shared between the old and the new one,
-          // so we must incRef it
-          readerShared[i] = true;
-          newReader.incRef();
-        } else {
           readerShared[i] = false;
           newReaders[i] = newReader;
+        } else {
+          newReader = newReaders[i].reopenSegment(infos.info(i), doClone, readOnly);
+          if (newReader == null) {
+            // this reader will be shared between the old and the new one,
+            // so we must incRef it
+            readerShared[i] = true;
+            newReaders[i].incRef();
+          } else {
+            assert newReader.readerFinishedListeners == readerFinishedListeners;
+            readerShared[i] = false;
+            // Steal ref returned to us by reopenSegment:
+            newReaders[i] = newReader;
+          }
         }
         success = true;
       } finally {
@@ -359,8 +362,8 @@ class DirectoryReader extends IndexReade
 
   @Override
   public final synchronized IndexReader clone(boolean openReadOnly) throws CorruptIndexException, IOException {
-    // doReopen calls ensureOpen
-    DirectoryReader newReader = doReopen((SegmentInfos) segmentInfos.clone(), true, openReadOnly);
+    // doOpenIfChanged calls ensureOpen
+    DirectoryReader newReader = doOpenIfChanged((SegmentInfos) segmentInfos.clone(), true, openReadOnly);
 
     if (this != newReader) {
       newReader.deletionPolicy = deletionPolicy;
@@ -383,22 +386,24 @@ class DirectoryReader extends IndexReade
   }
 
   @Override
-  public final IndexReader reopen() throws CorruptIndexException, IOException {
+  protected final IndexReader doOpenIfChanged() throws CorruptIndexException, IOException {
     // Preserve current readOnly
-    return doReopen(readOnly, null);
+    return doOpenIfChanged(readOnly, null);
   }
 
   @Override
-  public final IndexReader reopen(boolean openReadOnly) throws CorruptIndexException, IOException {
-    return doReopen(openReadOnly, null);
+  protected final IndexReader doOpenIfChanged(boolean openReadOnly) throws CorruptIndexException, IOException {
+    return doOpenIfChanged(openReadOnly, null);
   }
 
   @Override
-  public final IndexReader reopen(final IndexCommit commit) throws CorruptIndexException, IOException {
-    return doReopen(true, commit);
+  protected final IndexReader doOpenIfChanged(final IndexCommit commit) throws CorruptIndexException, IOException {
+    return doOpenIfChanged(true, commit);
   }
 
-  private final IndexReader doReopenFromWriter(boolean openReadOnly, IndexCommit commit) throws CorruptIndexException, IOException {
+  // NOTE: always returns a non-null result (ie new reader)
+  // but that could change someday
+  private final IndexReader doOpenFromWriter(boolean openReadOnly, IndexCommit commit) throws CorruptIndexException, IOException {
     assert readOnly;
 
     if (!openReadOnly) {
@@ -417,7 +422,7 @@ class DirectoryReader extends IndexReade
     return reader;
   }
 
-  private IndexReader doReopen(final boolean openReadOnly, IndexCommit commit) throws CorruptIndexException, IOException {
+  private IndexReader doOpenIfChanged(final boolean openReadOnly, IndexCommit commit) throws CorruptIndexException, IOException {
     ensureOpen();
 
     assert commit == null || openReadOnly;
@@ -425,13 +430,13 @@ class DirectoryReader extends IndexReade
     // If we were obtained by writer.getReader(), re-ask the
     // writer to get a new reader.
     if (writer != null) {
-      return doReopenFromWriter(openReadOnly, commit);
+      return doOpenFromWriter(openReadOnly, commit);
     } else {
-      return doReopenNoWriter(openReadOnly, commit);
+      return doOpenNoWriter(openReadOnly, commit);
     }
   }
 
-  private synchronized IndexReader doReopenNoWriter(final boolean openReadOnly, IndexCommit commit) throws CorruptIndexException, IOException {
+  private synchronized IndexReader doOpenNoWriter(final boolean openReadOnly, IndexCommit commit) throws CorruptIndexException, IOException {
 
     if (commit == null) {
       if (hasChanges) {
@@ -446,25 +451,26 @@ class DirectoryReader extends IndexReade
         if (openReadOnly) {
           return clone(openReadOnly);
         } else {
-          return this;
+          return null;
         }
       } else if (isCurrent()) {
         if (openReadOnly != readOnly) {
           // Just fallback to clone
           return clone(openReadOnly);
         } else {
-          return this;
+          return null;
         }
       }
     } else {
-      if (directory != commit.getDirectory())
+      if (directory != commit.getDirectory()) {
         throw new IOException("the specified commit does not match the specified Directory");
+      }
       if (segmentInfos != null && commit.getSegmentsFileName().equals(segmentInfos.getCurrentSegmentFileName())) {
         if (readOnly != openReadOnly) {
           // Just fallback to clone
           return clone(openReadOnly);
         } else {
-          return this;
+          return null;
         }
       }
     }
@@ -474,12 +480,12 @@ class DirectoryReader extends IndexReade
       protected Object doBody(String segmentFileName) throws CorruptIndexException, IOException {
         SegmentInfos infos = new SegmentInfos();
         infos.read(directory, segmentFileName);
-        return doReopen(infos, false, openReadOnly);
+        return doOpenIfChanged(infos, false, openReadOnly);
       }
     }.run(commit);
   }
 
-  private synchronized DirectoryReader doReopen(SegmentInfos infos, boolean doClone, boolean openReadOnly) throws CorruptIndexException, IOException {
+  private synchronized DirectoryReader doOpenIfChanged(SegmentInfos infos, boolean doClone, boolean openReadOnly) throws CorruptIndexException, IOException {
     DirectoryReader reader;
     if (openReadOnly) {
       reader = new ReadOnlyDirectoryReader(directory, infos, subReaders, starts, normsCache, doClone, termInfosIndexDivisor, readerFinishedListeners);

Modified: lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/index/IndexReader.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/index/IndexReader.java?rev=1179256&r1=1179255&r2=1179256&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/index/IndexReader.java (original)
+++ lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/index/IndexReader.java Wed Oct  5 15:17:28 2011
@@ -23,6 +23,7 @@ import org.apache.lucene.search.FieldCac
 import org.apache.lucene.search.Similarity;
 import org.apache.lucene.store.*;
 import org.apache.lucene.util.ArrayUtil;
+import org.apache.lucene.util.VirtualMethod;
 
 import java.io.File;
 import java.io.FileOutputStream;
@@ -335,7 +336,7 @@ public abstract class IndexReader implem
    * @throws CorruptIndexException
    * @throws IOException if there is a low-level IO error
    *
-   * @see #reopen(IndexWriter,boolean)
+   * @see #openIfChanged(IndexReader,IndexWriter,boolean)
    *
    * @lucene.experimental
    */
@@ -461,6 +462,178 @@ public abstract class IndexReader implem
   }
 
   /**
+   * If the index has changed since the provided reader was
+   * opened, open and return a new reader; else, return
+   * null.  The new reader, if not null, will be the same
+   * type of reader as the previous one, ie an NRT reader
+   * will open a new NRT reader, a MultiReader will open a
+   * new MultiReader,  etc.
+   *
+   * <p>This method is typically far less costly than opening a
+   * fully new <code>IndexReader</code> as it shares
+   * resources (for example sub-readers) with the provided
+   * <code>IndexReader</code>, when possible.
+   *
+   * <p>The provided reader is not closed (you are responsible
+   * for doing so); if a new reader is returned you also
+   * must eventually close it.  Be sure to never close a
+   * reader while other threads are still using it; see
+   * <code>SearcherManager</code> in
+   * <code>contrib/misc</code> to simplify managing this.
+   *
+   * <p>If a new reader is returned, it's safe to make changes
+   * (deletions, norms) with it.  All shared mutable state
+   * with the old reader uses "copy on write" semantics to
+   * ensure the changes are not seen by other readers.
+   *
+   * <p><b>NOTE</b>: If the provided reader is a near real-time
+   * reader, this method will return another near-real-time
+   * reader.
+   * 
+   * @throws CorruptIndexException if the index is corrupt
+   * @throws IOException if there is a low-level IO error
+   * @return null if there are no changes; else, a new
+   * IndexReader instance which you must eventually close
+   */  
+  public static IndexReader openIfChanged(IndexReader oldReader) throws IOException {
+    if (oldReader.hasNewReopenAPI1) {
+      final IndexReader newReader = oldReader.doOpenIfChanged();
+      assert newReader != oldReader;
+      return newReader;
+    } else {
+      final IndexReader newReader = oldReader.reopen();
+      if (newReader == oldReader) {
+        return null;
+      } else {
+        return newReader;
+      }
+    }
+  }
+
+  /**
+   * If the index has changed since the provided reader was
+   * opened, open and return a new reader, with the
+   * specified <code>readOnly</code>; else, return
+   * null.
+   *
+   * @see #openIfChanged(IndexReader)
+   */
+  public static IndexReader openIfChanged(IndexReader oldReader, boolean readOnly) throws IOException {
+    if (oldReader.hasNewReopenAPI2) {
+      final IndexReader newReader = oldReader.doOpenIfChanged(readOnly);
+      assert newReader != oldReader;
+      return newReader;
+    } else {
+      final IndexReader newReader = oldReader.reopen(readOnly);
+      if (newReader == oldReader) {
+        return null;
+      } else {
+        return newReader;
+      }
+    }
+  }
+
+  /**
+   * If the IndexCommit differs from what the
+   * provided reader is searching, or the provided reader is
+   * not already read-only, open and return a new
+   * <code>readOnly=true</code> reader; else, return null.
+   *
+   * @see #openIfChanged(IndexReader)
+   */
+  // TODO: should you be able to specify readOnly?
+  public static IndexReader openIfChanged(IndexReader oldReader, IndexCommit commit) throws IOException {
+    if (oldReader.hasNewReopenAPI3) {
+      final IndexReader newReader = oldReader.doOpenIfChanged(commit);
+      assert newReader != oldReader;
+      return newReader;
+    } else {
+      final IndexReader newReader = oldReader.reopen(commit);
+      if (newReader == oldReader) {
+        return null;
+      } else {
+        return newReader;
+      }
+    }
+  }
+
+  /**
+   * Expert: If there changes (committed or not) in the
+   * {@link IndexWriter} versus what the provided reader is
+   * searching, then open and return a new read-only
+   * IndexReader searching both committed and uncommitted
+   * changes from the writer; else, return null (though, the
+   * current implementation never returns null).
+   *
+   * <p>This provides "near real-time" searching, in that
+   * changes made during an {@link IndexWriter} session can be
+   * quickly made available for searching without closing
+   * the writer nor calling {@link #commit}.
+   *
+   * <p>It's <i>near</i> real-time because there is no hard
+   * guarantee on how quickly you can get a new reader after
+   * making changes with IndexWriter.  You'll have to
+   * experiment in your situation to determine if it's
+   * fast enough.  As this is a new and experimental
+   * feature, please report back on your findings so we can
+   * learn, improve and iterate.</p>
+   *
+   * <p>The very first time this method is called, this
+   * writer instance will make every effort to pool the
+   * readers that it opens for doing merges, applying
+   * deletes, etc.  This means additional resources (RAM,
+   * file descriptors, CPU time) will be consumed.</p>
+   *
+   * <p>For lower latency on reopening a reader, you should
+   * call {@link IndexWriterConfig#setMergedSegmentWarmer} to
+   * pre-warm a newly merged segment before it's committed
+   * to the index.  This is important for minimizing
+   * index-to-search delay after a large merge.  </p>
+   *
+   * <p>If an addIndexes* call is running in another thread,
+   * then this reader will only search those segments from
+   * the foreign index that have been successfully copied
+   * over, so far.</p>
+   *
+   * <p><b>NOTE</b>: Once the writer is closed, any
+   * outstanding readers may continue to be used.  However,
+   * if you attempt to reopen any of those readers, you'll
+   * hit an {@link AlreadyClosedException}.</p>
+   *
+   * @return IndexReader that covers entire index plus all
+   * changes made so far by this IndexWriter instance, or
+   * null if there are no new changes
+   *
+   * @param writer The IndexWriter to open from
+   *
+   * @param applyAllDeletes If true, all buffered deletes will
+   * be applied (made visible) in the returned reader.  If
+   * false, the deletes are not applied but remain buffered
+   * (in IndexWriter) so that they will be applied in the
+   * future.  Applying deletes can be costly, so if your app
+   * can tolerate deleted documents being returned you might
+   * gain some performance by passing false.
+   *
+   * @throws IOException
+   *
+   * @lucene.experimental
+   */
+  public static IndexReader openIfChanged(IndexReader oldReader, IndexWriter writer, boolean applyAllDeletes) throws IOException {
+    if (oldReader.hasNewReopenAPI4) {
+      final IndexReader newReader = oldReader.doOpenIfChanged(writer, applyAllDeletes);
+      assert newReader != oldReader;
+      return newReader;
+    } else {
+      final IndexReader newReader = oldReader.reopen(writer, applyAllDeletes);
+      if (newReader == oldReader) {
+        return null;
+      } else {
+        return newReader;
+      }
+    }
+  }
+
+  /**
    * Refreshes an IndexReader if the index has changed since this instance 
    * was (re)opened. 
    * <p>
@@ -504,28 +677,50 @@ public abstract class IndexReader implem
    * 
    * @throws CorruptIndexException if the index is corrupt
    * @throws IOException if there is a low-level IO error
-   */  
-  public synchronized IndexReader reopen() throws CorruptIndexException, IOException {
-    throw new UnsupportedOperationException("This reader does not support reopen().");
+   * @deprecated Use IndexReader#openIfChanged(IndexReader) instead
+   */
+  @Deprecated
+  public IndexReader reopen() throws CorruptIndexException, IOException {
+    final IndexReader newReader = IndexReader.openIfChanged(this);
+    if (newReader == null) {
+      return this;
+    } else {
+      return newReader;
+    }
   }
-  
 
   /** Just like {@link #reopen()}, except you can change the
    *  readOnly of the original reader.  If the index is
    *  unchanged but readOnly is different then a new reader
-   *  will be returned. */
-  public synchronized IndexReader reopen(boolean openReadOnly) throws CorruptIndexException, IOException {
-    throw new UnsupportedOperationException("This reader does not support reopen().");
+   *  will be returned.
+   * @deprecated Use
+   * IndexReader#openIfChanged(IndexReader,boolean) instead */
+  @Deprecated
+  public IndexReader reopen(boolean openReadOnly) throws CorruptIndexException, IOException {
+    final IndexReader newReader = IndexReader.openIfChanged(this, openReadOnly);
+    if (newReader == null) {
+      return this;
+    } else {
+      return newReader;
+    }
   }
-  
+
   /** Expert: reopen this reader on a specific commit point.
    *  This always returns a readOnly reader.  If the
    *  specified commit point matches what this reader is
    *  already on, and this reader is already readOnly, then
    *  this same instance is returned; if it is not already
-   *  readOnly, a readOnly clone is returned. */
-  public synchronized IndexReader reopen(final IndexCommit commit) throws CorruptIndexException, IOException {
-    throw new UnsupportedOperationException("This reader does not support reopen(IndexCommit).");
+   *  readOnly, a readOnly clone is returned.
+   * @deprecated Use IndexReader#openIfChanged(IndexReader,IndexCommit) instead
+   */
+  @Deprecated
+  public IndexReader reopen(IndexCommit commit) throws CorruptIndexException, IOException {
+    final IndexReader newReader = IndexReader.openIfChanged(this, commit);
+    if (newReader == null) {
+      return this;
+    } else {
+      return newReader;
+    }
   }
 
   /**
@@ -595,8 +790,31 @@ public abstract class IndexReader implem
    * @throws IOException
    *
    * @lucene.experimental
+   * @deprecated Use IndexReader#openIfChanged(IndexReader,IndexReader,boolean) instead
    */
+  @Deprecated
   public IndexReader reopen(IndexWriter writer, boolean applyAllDeletes) throws CorruptIndexException, IOException {
+    final IndexReader newReader = IndexReader.openIfChanged(this, writer, applyAllDeletes);
+    if (newReader == null) {
+      return this;
+    } else {
+      return newReader;
+    }
+  }
+
+  protected IndexReader doOpenIfChanged() throws CorruptIndexException, IOException {
+    throw new UnsupportedOperationException("This reader does not support reopen().");
+  }
+  
+  protected IndexReader doOpenIfChanged(boolean openReadOnly) throws CorruptIndexException, IOException {
+    throw new UnsupportedOperationException("This reader does not support reopen().");
+  }
+
+  protected IndexReader doOpenIfChanged(final IndexCommit commit) throws CorruptIndexException, IOException {
+    throw new UnsupportedOperationException("This reader does not support reopen(IndexCommit).");
+  }
+
+  protected IndexReader doOpenIfChanged(IndexWriter writer, boolean applyAllDeletes) throws CorruptIndexException, IOException {
     return writer.getReader(applyAllDeletes);
   }
 
@@ -611,7 +829,7 @@ public abstract class IndexReader implem
    * changes to the index on close, but the old reader still
    * reflects all changes made up until it was cloned.
    * <p>
-   * Like {@link #reopen()}, it's safe to make changes to
+   * Like {@link #openIfChanged(IndexReader)}, it's safe to make changes to
    * either the original or the cloned reader: all shared
    * mutable state obeys "copy on write" semantics to ensure
    * the changes are not seen by other readers.
@@ -697,7 +915,7 @@ public abstract class IndexReader implem
    * implemented in the IndexReader base class.
    *
    * <p>If this reader is based on a Directory (ie, was
-   * created by calling {@link #open}, or {@link #reopen} on
+   * created by calling {@link #open}, or {@link #openIfChanged} on
    * a reader based on a Directory), then this method
    * returns the version recorded in the commit that the
    * reader opened.  This version is advanced every time
@@ -705,7 +923,7 @@ public abstract class IndexReader implem
    *
    * <p>If instead this reader is a near real-time reader
    * (ie, obtained by a call to {@link
-   * IndexWriter#getReader}, or by calling {@link #reopen}
+   * IndexWriter#getReader}, or by calling {@link #openIfChanged}
    * on a near real-time reader), then this method returns
    * the version of the last commit done by the writer.
    * Note that even as further changes are made with the
@@ -738,14 +956,14 @@ public abstract class IndexReader implem
    * index since this reader was opened.
    *
    * <p>If this reader is based on a Directory (ie, was
-   * created by calling {@link #open}, or {@link #reopen} on
+   * created by calling {@link #open}, or {@link #openIfChanged} on
    * a reader based on a Directory), then this method checks
    * if any further commits (see {@link IndexWriter#commit}
    * have occurred in that directory).</p>
    *
    * <p>If instead this reader is a near real-time reader
    * (ie, obtained by a call to {@link
-   * IndexWriter#getReader}, or by calling {@link #reopen}
+   * IndexWriter#getReader}, or by calling {@link #openIfChanged}
    * on a near real-time reader), then this method checks if
    * either a new commmit has occurred, or any new
    * uncommitted changes have taken place via the writer.
@@ -753,7 +971,7 @@ public abstract class IndexReader implem
    * merging, this method will still return false.</p>
    *
    * <p>In any event, if this returns false, you should call
-   * {@link #reopen} to get a new reader that sees the
+   * {@link #openIfChanged} to get a new reader that sees the
    * changes.</p>
    *
    * @throws CorruptIndexException if the index is corrupt
@@ -1416,6 +1634,54 @@ public abstract class IndexReader implem
     throw new UnsupportedOperationException("this reader does not implement getUniqueTermCount()");
   }
 
+  // Back compat for reopen()
+  @Deprecated
+  private static final VirtualMethod<IndexReader> reopenMethod1 =
+    new VirtualMethod<IndexReader>(IndexReader.class, "reopen");
+  @Deprecated
+  private static final VirtualMethod<IndexReader> doOpenIfChangedMethod1 =
+    new VirtualMethod<IndexReader>(IndexReader.class, "doOpenIfChanged");
+  @Deprecated
+  private final boolean hasNewReopenAPI1 =
+    VirtualMethod.compareImplementationDistance(getClass(),
+        doOpenIfChangedMethod1, reopenMethod1) >= 0; // its ok for both to be overridden
+
+  // Back compat for reopen(boolean openReadOnly)
+  @Deprecated
+  private static final VirtualMethod<IndexReader> reopenMethod2 =
+    new VirtualMethod<IndexReader>(IndexReader.class, "reopen", boolean.class);
+  @Deprecated
+  private static final VirtualMethod<IndexReader> doOpenIfChangedMethod2 =
+    new VirtualMethod<IndexReader>(IndexReader.class, "doOpenIfChanged", boolean.class);
+  @Deprecated
+  private final boolean hasNewReopenAPI2 =
+    VirtualMethod.compareImplementationDistance(getClass(),
+        doOpenIfChangedMethod2, reopenMethod2) >= 0; // its ok for both to be overridden
+
+  // Back compat for reopen(IndexCommit commit)
+  @Deprecated
+  private static final VirtualMethod<IndexReader> reopenMethod3 =
+    new VirtualMethod<IndexReader>(IndexReader.class, "reopen", IndexCommit.class);
+  @Deprecated
+  private static final VirtualMethod<IndexReader> doOpenIfChangedMethod3 =
+    new VirtualMethod<IndexReader>(IndexReader.class, "doOpenIfChanged", IndexCommit.class);
+  @Deprecated
+  private final boolean hasNewReopenAPI3 =
+    VirtualMethod.compareImplementationDistance(getClass(),
+        doOpenIfChangedMethod3, reopenMethod3) >= 0; // its ok for both to be overridden
+
+  // Back compat for reopen(IndexWriter writer, boolean applyDeletes)
+  @Deprecated
+  private static final VirtualMethod<IndexReader> reopenMethod4 =
+    new VirtualMethod<IndexReader>(IndexReader.class, "reopen", IndexWriter.class, boolean.class);
+  @Deprecated
+  private static final VirtualMethod<IndexReader> doOpenIfChangedMethod4 =
+    new VirtualMethod<IndexReader>(IndexReader.class, "doOpenIfChanged", IndexWriter.class, boolean.class);
+  @Deprecated
+  private final boolean hasNewReopenAPI4 =
+    VirtualMethod.compareImplementationDistance(getClass(),
+        doOpenIfChangedMethod4, reopenMethod4) >= 0; // its ok for both to be overridden
+
   /** For IndexReader implementations that use
    *  TermInfosReader to read terms, this returns the
    *  current indexDivisor as specified when the reader was

Modified: lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/index/MultiReader.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/index/MultiReader.java?rev=1179256&r1=1179255&r2=1179256&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/index/MultiReader.java (original)
+++ lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/index/MultiReader.java Wed Oct  5 15:17:28 2011
@@ -91,14 +91,14 @@ public class MultiReader extends IndexRe
   /**
    * Tries to reopen the subreaders.
    * <br>
-   * If one or more subreaders could be re-opened (i. e. subReader.reopen() 
-   * returned a new instance != subReader), then a new MultiReader instance 
+   * If one or more subreaders could be re-opened (i. e. IndexReader.openIfChanged(subReader) 
+   * returned a new instance), then a new MultiReader instance 
    * is returned, otherwise this instance is returned.
    * <p>
    * A re-opened instance might share one or more subreaders with the old 
    * instance. Index modification operations result in undefined behavior
    * when performed before the old instance is closed.
-   * (see {@link IndexReader#reopen()}).
+   * (see {@link IndexReader#openIfChanged}).
    * <p>
    * If subreaders are shared, then the reference count of those
    * readers is increased to ensure that the subreaders remain open
@@ -108,8 +108,8 @@ public class MultiReader extends IndexRe
    * @throws IOException if there is a low-level IO error 
    */
   @Override
-  public synchronized IndexReader reopen() throws CorruptIndexException, IOException {
-    return doReopen(false);
+  protected synchronized IndexReader doOpenIfChanged() throws CorruptIndexException, IOException {
+    return doOpenIfChanged(false);
   }
   
   /**
@@ -124,7 +124,7 @@ public class MultiReader extends IndexRe
   @Override
   public synchronized Object clone() {
     try {
-      return doReopen(true);
+      return doOpenIfChanged(true);
     } catch (Exception ex) {
       throw new RuntimeException(ex);
     }
@@ -133,33 +133,35 @@ public class MultiReader extends IndexRe
   /**
    * If clone is true then we clone each of the subreaders
    * @param doClone
-   * @return New IndexReader, or same one (this) if
-   *   reopen/clone is not necessary
+   * @return New IndexReader, or null if open/clone is not necessary
    * @throws CorruptIndexException
    * @throws IOException
    */
-  protected IndexReader doReopen(boolean doClone) throws CorruptIndexException, IOException {
+  protected IndexReader doOpenIfChanged(boolean doClone) throws CorruptIndexException, IOException {
     ensureOpen();
     
-    boolean reopened = false;
+    boolean changed = false;
     IndexReader[] newSubReaders = new IndexReader[subReaders.length];
     
     boolean success = false;
     try {
       for (int i = 0; i < subReaders.length; i++) {
-        if (doClone)
+        if (doClone) {
           newSubReaders[i] = (IndexReader) subReaders[i].clone();
-        else
-          newSubReaders[i] = subReaders[i].reopen();
-        // if at least one of the subreaders was updated we remember that
-        // and return a new MultiReader
-        if (newSubReaders[i] != subReaders[i]) {
-          reopened = true;
+          changed = true;
+        } else {
+          final IndexReader newSubReader = IndexReader.openIfChanged(subReaders[i]);
+          if (newSubReader != null) {
+            newSubReaders[i] = newSubReader;
+            changed = true;
+          } else {
+            newSubReaders[i] = subReaders[i];
+          }
         }
       }
       success = true;
     } finally {
-      if (!success && reopened) {
+      if (!success && changed) {
         for (int i = 0; i < newSubReaders.length; i++) {
           if (newSubReaders[i] != subReaders[i]) {
             try {
@@ -172,7 +174,7 @@ public class MultiReader extends IndexRe
       }
     }
 
-    if (reopened) {
+    if (changed) {
       boolean[] newDecrefOnClose = new boolean[subReaders.length];
       for (int i = 0; i < subReaders.length; i++) {
         if (newSubReaders[i] == subReaders[i]) {
@@ -184,7 +186,7 @@ public class MultiReader extends IndexRe
       mr.decrefOnClose = newDecrefOnClose;
       return mr;
     } else {
-      return this;
+      return null;
     }
   }
 

Modified: lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/index/ParallelReader.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/index/ParallelReader.java?rev=1179256&r1=1179255&r2=1179256&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/index/ParallelReader.java (original)
+++ lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/index/ParallelReader.java Wed Oct  5 15:17:28 2011
@@ -154,12 +154,12 @@ public class ParallelReader extends Inde
    * <br>
    * If one or more subreaders could be re-opened (i. e. subReader.reopen() 
    * returned a new instance != subReader), then a new ParallelReader instance 
-   * is returned, otherwise this instance is returned.
+   * is returned, otherwise null is returned.
    * <p>
    * A re-opened instance might share one or more subreaders with the old 
    * instance. Index modification operations result in undefined behavior
    * when performed before the old instance is closed.
-   * (see {@link IndexReader#reopen()}).
+   * (see {@link IndexReader#openIfChanged}).
    * <p>
    * If subreaders are shared, then the reference count of those
    * readers is increased to ensure that the subreaders remain open
@@ -169,7 +169,7 @@ public class ParallelReader extends Inde
    * @throws IOException if there is a low-level IO error 
    */
   @Override
-  public synchronized IndexReader reopen() throws CorruptIndexException, IOException {
+  protected synchronized IndexReader doOpenIfChanged() throws CorruptIndexException, IOException {
     // doReopen calls ensureOpen
     return doReopen(false);
   }
@@ -187,15 +187,16 @@ public class ParallelReader extends Inde
         IndexReader newReader = null;
         if (doClone) {
           newReader = (IndexReader) oldReader.clone();
+          reopened = true;
         } else {
-          newReader = oldReader.reopen();
+          newReader = IndexReader.openIfChanged(oldReader);
+          if (newReader != null) {
+            reopened = true;
+          } else {
+            newReader = oldReader;
+          }
         }
         newReaders.add(newReader);
-        // if at least one of the subreaders was updated we remember that
-        // and return a new ParallelReader
-        if (newReader != oldReader) {
-          reopened = true;
-        }
       }
       success = true;
     } finally {
@@ -234,7 +235,7 @@ public class ParallelReader extends Inde
       return pr;
     } else {
       // No subreader was refreshed
-      return this;
+      return null;
     }
   }
 

Modified: lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/index/SegmentReader.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/index/SegmentReader.java?rev=1179256&r1=1179255&r2=1179256&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/index/SegmentReader.java (original)
+++ lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/index/SegmentReader.java Wed Oct  5 15:17:28 2011
@@ -202,13 +202,13 @@ public class SegmentReader extends Index
   }
 
   @Override
-  public synchronized IndexReader reopen()
+  protected synchronized IndexReader doOpenIfChanged()
     throws CorruptIndexException, IOException {
     return reopenSegment(si, false, readOnly);
   }
 
   @Override
-  public synchronized IndexReader reopen(boolean openReadOnly)
+  protected synchronized IndexReader doOpenIfChanged(boolean openReadOnly)
     throws CorruptIndexException, IOException {
     return reopenSegment(si, false, openReadOnly);
   }
@@ -231,7 +231,7 @@ public class SegmentReader extends Index
     // if we're cloning we need to run through the reopenSegment logic
     // also if both old and new readers aren't readonly, we clone to avoid sharing modifications
     if (normsUpToDate && deletionsUpToDate && !doClone && openReadOnly && readOnly) {
-      return this;
+      return null;
     }    
 
     // When cloning, the incoming SegmentInfos should not

Modified: lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/search/IndexSearcher.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/search/IndexSearcher.java?rev=1179256&r1=1179255&r2=1179256&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/search/IndexSearcher.java (original)
+++ lucene/dev/branches/branch_3x/lucene/src/java/org/apache/lucene/search/IndexSearcher.java Wed Oct  5 15:17:28 2011
@@ -51,7 +51,7 @@ import org.apache.lucene.util.ThreadInte
  * multiple searches instead of creating a new one
  * per-search.  If your index has changed and you wish to
  * see the changes reflected in searching, you should
- * use {@link IndexReader#reopen} to obtain a new reader and
+ * use {@link IndexReader#openIfChanged} to obtain a new reader and
  * then create a new IndexSearcher from that.  Also, for
  * low-latency turnaround it's best to use a near-real-time
  * reader ({@link IndexReader#open(IndexWriter,boolean)}).

Modified: lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexReader.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexReader.java?rev=1179256&r1=1179255&r2=1179256&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexReader.java (original)
+++ lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexReader.java Wed Oct  5 15:17:28 2011
@@ -92,7 +92,8 @@ public class TestIndexReader extends Luc
         addDocumentWithFields(writer);
       writer.close();
 
-      IndexReader r3 = r2.reopen();
+      IndexReader r3 = IndexReader.openIfChanged(r2);
+      assertNotNull(r3);
       assertFalse(c.equals(r3.getIndexCommit()));
       assertFalse(r2.getIndexCommit().isOptimized());
       r3.close();
@@ -103,7 +104,8 @@ public class TestIndexReader extends Luc
       writer.optimize();
       writer.close();
 
-      r3 = r2.reopen();
+      r3 = IndexReader.openIfChanged(r2);
+      assertNotNull(r3);
       assertTrue(r3.getIndexCommit().isOptimized());
       r2.close();
       r3.close();
@@ -937,7 +939,8 @@ public class TestIndexReader extends Luc
         addDocumentWithFields(writer);
       writer.close();
 
-      IndexReader r2 = r.reopen();
+      IndexReader r2 = IndexReader.openIfChanged(r);
+      assertNotNull(r2);
       assertFalse(c.equals(r2.getIndexCommit()));
       assertFalse(r2.getIndexCommit().isOptimized());
       r2.close();
@@ -948,7 +951,9 @@ public class TestIndexReader extends Luc
       writer.optimize();
       writer.close();
 
-      r2 = r.reopen();
+      r2 = IndexReader.openIfChanged(r);
+      assertNotNull(r2);
+      assertNull(IndexReader.openIfChanged(r2));
       assertTrue(r2.getIndexCommit().isOptimized());
 
       r.close();
@@ -983,7 +988,8 @@ public class TestIndexReader extends Luc
       writer.close();
 
       // Make sure reopen is still readonly:
-      IndexReader r2 = r.reopen();
+      IndexReader r2 = IndexReader.openIfChanged(r);
+      assertNotNull(r2);
       r.close();
 
       assertFalse(r == r2);
@@ -1002,7 +1008,8 @@ public class TestIndexReader extends Luc
       writer.close();
 
       // Make sure reopen to a single segment is still readonly:
-      IndexReader r3 = r2.reopen();
+      IndexReader r3 = IndexReader.openIfChanged(r2);
+      assertNotNull(r3);
       assertFalse(r3 == r2);
       r2.close();
       
@@ -1148,7 +1155,8 @@ public class TestIndexReader extends Luc
     writer.commit();
 
     // Reopen reader1 --> reader2
-    IndexReader r2 = r.reopen();
+    IndexReader r2 = IndexReader.openIfChanged(r);
+    assertNotNull(r2);
     r.close();
     IndexReader sub0 = r2.getSequentialSubReaders()[0];
     final int[] ints2 = FieldCache.DEFAULT.getInts(sub0, "number");
@@ -1175,7 +1183,8 @@ public class TestIndexReader extends Luc
     assertEquals(36, r1.getUniqueTermCount());
     writer.addDocument(doc);
     writer.commit();
-    IndexReader r2 = r.reopen();
+    IndexReader r2 = IndexReader.openIfChanged(r);
+    assertNotNull(r2);
     r.close();
     try {
       r2.getUniqueTermCount();
@@ -1222,7 +1231,9 @@ public class TestIndexReader extends Luc
     writer.close();
 
     // LUCENE-1718: ensure re-open carries over no terms index:
-    IndexReader r2 = r.reopen();
+    IndexReader r2 = IndexReader.openIfChanged(r);
+    assertNotNull(r2);
+    assertNull(IndexReader.openIfChanged(r2));
     r.close();
     IndexReader[] subReaders = r2.getSequentialSubReaders();
     assertEquals(2, subReaders.length);
@@ -1246,8 +1257,8 @@ public class TestIndexReader extends Luc
     writer.addDocument(doc);
     writer.prepareCommit();
     assertTrue(r.isCurrent());
-    IndexReader r2 = r.reopen();
-    assertTrue(r == r2);
+    IndexReader r2 = IndexReader.openIfChanged(r);
+    assertNull(r2);
     writer.commit();
     assertFalse(r.isCurrent());
     writer.close();

Modified: lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexReaderClone.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexReaderClone.java?rev=1179256&r1=1179255&r2=1179256&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexReaderClone.java (original)
+++ lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexReaderClone.java Wed Oct  5 15:17:28 2011
@@ -115,7 +115,8 @@ public class TestIndexReaderClone extend
 
     TestIndexReaderReopen.modifyIndex(5, dir1);
     
-    IndexReader reader2 = reader1.reopen();
+    IndexReader reader2 = IndexReader.openIfChanged(reader1);
+    assertNotNull(reader2);
     assertTrue(reader1 != reader2);
 
     assertTrue(deleteWorked(1, reader2));
@@ -156,7 +157,8 @@ public class TestIndexReaderClone extend
     assertTrue(deleteWorked(1, reader));
     assertEquals(docCount-1, reader.numDocs());
 
-    IndexReader readOnlyReader = reader.reopen(true);
+    IndexReader readOnlyReader = IndexReader.openIfChanged(reader, true);
+    assertNotNull(readOnlyReader);
     if (!isReadOnly(readOnlyReader)) {
       fail("reader isn't read only");
     }
@@ -387,7 +389,10 @@ public class TestIndexReaderClone extend
     assertDelDocsRefCountEquals(1, clonedSegmentReader);
 
     // test a reopened reader
-    IndexReader reopenedReader = clonedReader.reopen();
+    IndexReader reopenedReader = IndexReader.openIfChanged(clonedReader);
+    if (reopenedReader == null) {
+      reopenedReader = clonedReader;
+    }
     IndexReader cloneReader2 = (IndexReader) reopenedReader.clone();
     SegmentReader cloneSegmentReader2 = SegmentReader.getOnlySegmentReader(cloneReader2);
     assertDelDocsRefCountEquals(2, cloneSegmentReader2);

Modified: lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexReaderReopen.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexReaderReopen.java?rev=1179256&r1=1179255&r2=1179256&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexReaderReopen.java (original)
+++ lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexReaderReopen.java Wed Oct  5 15:17:28 2011
@@ -183,8 +183,8 @@ public class TestIndexReaderReopen exten
         iwriter.commit();
         if (withReopen) {
           // reopen
-          IndexReader r2 = reader.reopen();
-          if (reader != r2) {
+          IndexReader r2 = IndexReader.openIfChanged(reader);
+          if (r2 != null) {
             reader.close();
             reader = r2;
           }
@@ -463,12 +463,15 @@ public class TestIndexReaderReopen exten
       modifyIndex(0, dir2);
       assertRefCountEquals(1 + mode, reader1);
       
-      IndexReader multiReader2 = multiReader1.reopen();
+      IndexReader multiReader2 = IndexReader.openIfChanged(multiReader1);
+      assertNotNull(multiReader2);
       // index1 hasn't changed, so multiReader2 should share reader1 now with multiReader1
       assertRefCountEquals(2 + mode, reader1);
       
       modifyIndex(0, dir1);
-      IndexReader reader2 = reader1.reopen();
+      IndexReader reader2 = IndexReader.openIfChanged(reader1);
+      assertNotNull(reader2);
+      assertNull(IndexReader.openIfChanged(reader2));
       assertRefCountEquals(2 + mode, reader1);
 
       if (mode == 1) {
@@ -476,7 +479,8 @@ public class TestIndexReaderReopen exten
       }
       
       modifyIndex(1, dir1);
-      IndexReader reader3 = reader2.reopen();
+      IndexReader reader3 = IndexReader.openIfChanged(reader2);
+      assertNotNull(reader3);
       assertRefCountEquals(2 + mode, reader1);
       assertRefCountEquals(1, reader2);
       
@@ -536,13 +540,16 @@ public class TestIndexReaderReopen exten
       modifyIndex(1, dir2);
       assertRefCountEquals(1 + mode, reader1);
       
-      IndexReader parallelReader2 = parallelReader1.reopen();
+      IndexReader parallelReader2 = IndexReader.openIfChanged(parallelReader1);
+      assertNotNull(parallelReader2);
+      assertNull(IndexReader.openIfChanged(parallelReader2));
       // index1 hasn't changed, so parallelReader2 should share reader1 now with multiReader1
       assertRefCountEquals(2 + mode, reader1);
       
       modifyIndex(0, dir1);
       modifyIndex(0, dir2);
-      IndexReader reader2 = reader1.reopen();
+      IndexReader reader2 = IndexReader.openIfChanged(reader1);
+      assertNotNull(reader2);
       assertRefCountEquals(2 + mode, reader1);
 
       if (mode == 1) {
@@ -550,7 +557,8 @@ public class TestIndexReaderReopen exten
       }
       
       modifyIndex(4, dir1);
-      IndexReader reader3 = reader2.reopen();
+      IndexReader reader3 = IndexReader.openIfChanged(reader2);
+      assertNotNull(reader3);
       assertRefCountEquals(2 + mode, reader1);
       assertRefCountEquals(1, reader2);
       
@@ -604,24 +612,28 @@ public class TestIndexReaderReopen exten
     modifier.deleteDocument(0);
     modifier.close();
     
-    IndexReader reader2 = reader1.reopen();
+    IndexReader reader2 = IndexReader.openIfChanged(reader1);
+    assertNotNull(reader2);
     modifier = IndexReader.open(dir1, false);
     modifier.setNorm(1, "field1", 50);
     modifier.setNorm(1, "field2", 50);
     modifier.close();
     
-    IndexReader reader3 = reader2.reopen();
+    IndexReader reader3 = IndexReader.openIfChanged(reader2);
+    assertNotNull(reader3);
     SegmentReader segmentReader3 = SegmentReader.getOnlySegmentReader(reader3);
     modifier = IndexReader.open(dir1, false);
     modifier.deleteDocument(2);
     modifier.close();
 
-    IndexReader reader4 = reader3.reopen();
+    IndexReader reader4 = IndexReader.openIfChanged(reader3);
+    assertNotNull(reader4);
     modifier = IndexReader.open(dir1, false);
     modifier.deleteDocument(3);
     modifier.close();
 
-    IndexReader reader5 = reader3.reopen();
+    IndexReader reader5 = IndexReader.openIfChanged(reader3);
+    assertNotNull(reader5);
     
     // Now reader2-reader5 references reader1. reader1 and reader2
     // share the same norms. reader3, reader4, reader5 also share norms.
@@ -731,11 +743,11 @@ public class TestIndexReaderReopen exten
     
     for (int i = 0; i < n; i++) {
       if (i % 2 == 0) {
-        IndexReader refreshed = reader.reopen();
-        if (refreshed != reader) {
+        IndexReader refreshed = IndexReader.openIfChanged(reader);
+        if (refreshed != null) {
           readersToClose.add(reader);
+          reader = refreshed;
         }
-        reader = refreshed;
       }
       final IndexReader r = reader;
       
@@ -759,7 +771,10 @@ public class TestIndexReaderReopen exten
                 break;
               } else {
                 // not synchronized
-                IndexReader refreshed = r.reopen();
+                IndexReader refreshed = IndexReader.openIfChanged(r);
+                if (refreshed == null) {
+                  refreshed = r;
+                }
                 
                 IndexSearcher searcher = newSearcher(refreshed);
                 ScoreDoc[] hits = searcher.search(
@@ -900,7 +915,10 @@ public class TestIndexReaderReopen exten
       
       IndexReader refreshed = null;
       try {
-        refreshed = reader.reopen();
+        refreshed = IndexReader.openIfChanged(reader);
+        if (refreshed == null) {
+          refreshed = reader;
+        }
       } finally {
         if (refreshed == null && r != null) {
           // Hit exception -- close opened reader
@@ -1080,7 +1098,8 @@ public class TestIndexReaderReopen exten
     r2.deleteDocument(0);
     r2.close();
 
-    IndexReader r3 = r1.reopen();
+    IndexReader r3 = IndexReader.openIfChanged(r1);
+    assertNotNull(r3);
     assertTrue(r1 != r3);
     r1.close();
     try {
@@ -1104,7 +1123,9 @@ public class TestIndexReaderReopen exten
 
     modifyIndex(5, dir); // Add another doc (3 segments)
 
-    IndexReader r2 = r1.reopen(); // MSR
+    IndexReader r2 = IndexReader.openIfChanged(r1); // MSR
+    assertNotNull(r2);
+    assertNull(IndexReader.openIfChanged(r2));
     assertTrue(r1 != r2);
 
     SegmentReader sr1 = (SegmentReader) r1.getSequentialSubReaders()[0]; // Get SRs for the first segment from original
@@ -1136,7 +1157,8 @@ public class TestIndexReaderReopen exten
     // Add doc:
     modifyIndex(5, dir);
 
-    IndexReader r2 = r1.reopen();
+    IndexReader r2 = IndexReader.openIfChanged(r1);
+    assertNotNull(r2);
     assertTrue(r1 != r2);
 
     IndexReader[] rs2 = r2.getSequentialSubReaders();
@@ -1192,7 +1214,8 @@ public class TestIndexReaderReopen exten
 
     Collection<IndexCommit> commits = IndexReader.listCommits(dir);
     for (final IndexCommit commit : commits) {
-      IndexReader r2 = r.reopen(commit);
+      IndexReader r2 = IndexReader.openIfChanged(r, commit);
+      assertNotNull(r2);
       assertTrue(r2 != r);
 
       // Reader should be readOnly
@@ -1247,7 +1270,8 @@ public class TestIndexReaderReopen exten
     assertEquals(17, ints[0]);
 
     // Reopen to readonly w/ no chnages
-    IndexReader r3 = r.reopen(true);
+    IndexReader r3 = IndexReader.openIfChanged(r, true);
+    assertNotNull(r3);
     assertTrue(r3 instanceof ReadOnlyDirectoryReader);
     r3.close();
 
@@ -1256,7 +1280,8 @@ public class TestIndexReaderReopen exten
     writer.commit();
 
     // Reopen reader1 --> reader2
-    IndexReader r2 = r.reopen(true);
+    IndexReader r2 = IndexReader.openIfChanged(r, true);
+    assertNotNull(r2);
     r.close();
     assertTrue(r2 instanceof ReadOnlyDirectoryReader);
     IndexReader[] subs = r2.getSequentialSubReaders();

Modified: lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexWriter.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexWriter.java?rev=1179256&r1=1179255&r2=1179256&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexWriter.java (original)
+++ lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexWriter.java Wed Oct  5 15:17:28 2011
@@ -1568,7 +1568,8 @@ public class TestIndexWriter extends Luc
       if (iter == 1) {
         w.commit();
       }
-      IndexReader r2 = r.reopen();
+      IndexReader r2 = IndexReader.openIfChanged(r);
+      assertNotNull(r2);
       assertTrue(r != r2);
       files = Arrays.asList(dir.listAll());
 

Modified: lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexWriterCommit.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexWriterCommit.java?rev=1179256&r1=1179255&r2=1179256&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexWriterCommit.java (original)
+++ lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexWriterCommit.java Wed Oct  5 15:17:28 2011
@@ -344,7 +344,8 @@ public class TestIndexWriterCommit exten
                   f.setValue(s);
                   w.addDocument(doc);
                   w.commit();
-                  IndexReader r2 = r.reopen();
+                  IndexReader r2 = IndexReader.openIfChanged(r);
+                  assertNotNull(r2);
                   assertTrue(r2 != r);
                   r.close();
                   r = r2;
@@ -386,7 +387,8 @@ public class TestIndexWriterCommit exten
     IndexReader reader = IndexReader.open(dir, true);
     assertEquals(0, reader.numDocs());
     writer.commit();
-    IndexReader reader2 = reader.reopen();
+    IndexReader reader2 = IndexReader.openIfChanged(reader);
+    assertNotNull(reader2);
     assertEquals(0, reader.numDocs());
     assertEquals(23, reader2.numDocs());
     reader.close();
@@ -526,7 +528,8 @@ public class TestIndexWriterCommit exten
 
     writer.commit();
 
-    IndexReader reader3 = reader.reopen();
+    IndexReader reader3 = IndexReader.openIfChanged(reader);
+    assertNotNull(reader3);
     assertEquals(0, reader.numDocs());
     assertEquals(0, reader2.numDocs());
     assertEquals(23, reader3.numDocs());
@@ -582,10 +585,10 @@ public class TestIndexWriterCommit exten
 
     writer.rollback();
 
-    IndexReader reader3 = reader.reopen();
+    IndexReader reader3 = IndexReader.openIfChanged(reader);
+    assertNull(reader3);
     assertEquals(0, reader.numDocs());
     assertEquals(0, reader2.numDocs());
-    assertEquals(0, reader3.numDocs());
     reader.close();
     reader2.close();
 
@@ -593,8 +596,6 @@ public class TestIndexWriterCommit exten
     for (int i = 0; i < 17; i++)
       TestIndexWriter.addDoc(writer);
 
-    assertEquals(0, reader3.numDocs());
-    reader3.close();
     reader = IndexReader.open(dir, true);
     assertEquals(0, reader.numDocs());
     reader.close();

Modified: lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexWriterReader.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexWriterReader.java?rev=1179256&r1=1179255&r2=1179256&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexWriterReader.java (original)
+++ lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestIndexWriterReader.java Wed Oct  5 15:17:28 2011
@@ -667,8 +667,8 @@ public class TestIndexWriterReader exten
     }
     ((ConcurrentMergeScheduler) writer.getConfig().getMergeScheduler()).sync();
 
-    IndexReader r2 = r1.reopen();
-    if (r2 != r1) {
+    IndexReader r2 = IndexReader.openIfChanged(r1);
+    if (r2 != null) {
       r1.close();
       r1 = r2;
     }
@@ -699,7 +699,7 @@ public class TestIndexWriterReader exten
     assertEquals(100, searcher.search(q, 10).totalHits);
     searcher.close();
     try {
-      r.reopen();
+      IndexReader.openIfChanged(r);
       fail("failed to hit AlreadyClosedException");
     } catch (AlreadyClosedException ace) {
       // expected
@@ -758,8 +758,8 @@ public class TestIndexWriterReader exten
 
     int lastCount = 0;
     while(System.currentTimeMillis() < endTime) {
-      IndexReader r2 = r.reopen();
-      if (r2 != r) {
+      IndexReader r2 = IndexReader.openIfChanged(r);
+      if (r2 != null) {
         r.close();
         r = r2;
       }
@@ -775,7 +775,7 @@ public class TestIndexWriterReader exten
       threads[i].join();
     }
     // final check
-    IndexReader r2 = r.reopen();
+    IndexReader r2 = IndexReader.openIfChanged(r);
     if (r2 != r) {
       r.close();
       r = r2;
@@ -850,7 +850,7 @@ public class TestIndexWriterReader exten
 
     int sum = 0;
     while(System.currentTimeMillis() < endTime) {
-      IndexReader r2 = r.reopen();
+      IndexReader r2 = IndexReader.openIfChanged(r);
       if (r2 != r) {
         r.close();
         r = r2;
@@ -865,8 +865,8 @@ public class TestIndexWriterReader exten
       threads[i].join();
     }
     // at least search once
-    IndexReader r2 = r.reopen();
-    if (r2 != r) {
+    IndexReader r2 = IndexReader.openIfChanged(r);
+    if (r2 != null) {
       r.close();
       r = r2;
     }

Modified: lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestNRTThreads.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestNRTThreads.java?rev=1179256&r1=1179255&r2=1179256&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestNRTThreads.java (original)
+++ lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestNRTThreads.java Wed Oct  5 15:17:28 2011
@@ -41,8 +41,8 @@ public class TestNRTThreads extends Thre
         if (VERBOSE) {
           System.out.println("TEST: now reopen r=" + r);
         }
-        final IndexReader r2 = r.reopen();
-        if (r != r2) {
+        final IndexReader r2 = IndexReader.openIfChanged(r);
+        if (r2 != null) {
           r.close();
           r = r2;
         }

Modified: lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestNeverDelete.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestNeverDelete.java?rev=1179256&r1=1179255&r2=1179256&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestNeverDelete.java (original)
+++ lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestNeverDelete.java Wed Oct  5 15:17:28 2011
@@ -91,8 +91,8 @@ public class TestNeverDelete extends Luc
       for(String fileName : allFiles) {
         assertTrue("file " + fileName + " does not exist", d.fileExists(fileName));
       }
-      IndexReader r2 = r.reopen();
-      if (r2 != r) {
+      IndexReader r2 = IndexReader.openIfChanged(r);
+      if (r2 != null) {
         r.close();
         r = r2;
       }

Modified: lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestRollingUpdates.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestRollingUpdates.java?rev=1179256&r1=1179255&r2=1179256&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestRollingUpdates.java (original)
+++ lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestRollingUpdates.java Wed Oct  5 15:17:28 2011
@@ -126,8 +126,8 @@ public class TestRollingUpdates extends 
             if (open == null) {
               open = IndexReader.open(writer, true);
             }
-            IndexReader reader = open.reopen();
-            if (reader != open) {
+            IndexReader reader = IndexReader.openIfChanged(open);
+            if (reader != null) {
               open.close();
               open = reader;
             }

Modified: lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestStressNRT.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestStressNRT.java?rev=1179256&r1=1179255&r2=1179256&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestStressNRT.java (original)
+++ lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/index/TestStressNRT.java Wed Oct  5 15:17:28 2011
@@ -144,7 +144,7 @@ public class TestStressNRT extends Lucen
                       if (VERBOSE) {
                         System.out.println("TEST: " + Thread.currentThread().getName() + ": reopen reader=" + oldReader + " version=" + version);
                       }
-                      newReader = oldReader.reopen(writer.w, true);
+                      newReader = IndexReader.openIfChanged(oldReader, writer.w, true);
                     }
                   } else {
                     // assertU(commit());
@@ -155,13 +155,14 @@ public class TestStressNRT extends Lucen
                     if (VERBOSE) {
                       System.out.println("TEST: " + Thread.currentThread().getName() + ": now reopen after commit");
                     }
-                    newReader = oldReader.reopen();
+                    newReader = IndexReader.openIfChanged(oldReader);
                   }
 
                   // Code below assumes newReader comes w/
                   // extra ref:
-                  if (newReader == oldReader) {
-                    newReader.incRef();
+                  if (newReader == null) {
+                    oldReader.incRef();
+                    newReader = oldReader;
                   }
 
                   oldReader.decRef();

Modified: lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/search/TestCachingSpanFilter.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/search/TestCachingSpanFilter.java?rev=1179256&r1=1179255&r2=1179256&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/search/TestCachingSpanFilter.java (original)
+++ lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/search/TestCachingSpanFilter.java Wed Oct  5 15:17:28 2011
@@ -149,10 +149,12 @@ public class TestCachingSpanFilter exten
 
   private static IndexReader refreshReader(IndexReader reader) throws IOException {
     IndexReader oldReader = reader;
-    reader = reader.reopen();
-    if (reader != oldReader) {
+    reader = IndexReader.openIfChanged(reader);
+    if (reader != null) {
       oldReader.close();
+      return reader;
+    } else {
+      return oldReader;
     }
-    return reader;
   }
 }

Modified: lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/search/TestCachingWrapperFilter.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/search/TestCachingWrapperFilter.java?rev=1179256&r1=1179255&r2=1179256&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/search/TestCachingWrapperFilter.java (original)
+++ lucene/dev/branches/branch_3x/lucene/src/test/org/apache/lucene/search/TestCachingWrapperFilter.java Wed Oct  5 15:17:28 2011
@@ -298,10 +298,12 @@ public class TestCachingWrapperFilter ex
 
   private static IndexReader refreshReader(IndexReader reader) throws IOException {
     IndexReader oldReader = reader;
-    reader = reader.reopen();
-    if (reader != oldReader) {
+    reader = IndexReader.openIfChanged(reader);
+    if (reader != null) {
       oldReader.close();
+      return reader;
+    } else {
+      return oldReader;
     }
-    return reader;
   }
 }

Modified: lucene/dev/branches/branch_3x/solr/core/src/java/org/apache/solr/core/SolrCore.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/solr/core/src/java/org/apache/solr/core/SolrCore.java?rev=1179256&r1=1179255&r2=1179256&view=diff
==============================================================================
--- lucene/dev/branches/branch_3x/solr/core/src/java/org/apache/solr/core/SolrCore.java (original)
+++ lucene/dev/branches/branch_3x/solr/core/src/java/org/apache/solr/core/SolrCore.java Wed Oct  5 15:17:28 2011
@@ -1077,10 +1077,11 @@ public final class SolrCore implements S
       if (newestSearcher != null && solrConfig.reopenReaders
           && indexDirFile.equals(newIndexDirFile)) {
         IndexReader currentReader = newestSearcher.get().getReader();
-        IndexReader newReader = currentReader.reopen();
+        IndexReader newReader = IndexReader.openIfChanged(currentReader);
 
-        if (newReader == currentReader) {
+        if (newReader == null) {
           currentReader.incRef();
+          newReader = currentReader;
         }
 
         tmp = new SolrIndexSearcher(this, schema, "main", newReader, true, true);