Property changes on: . ___________________________________________________________________ Modified: svn:mergeinfo Merged /lucene/dev/trunk:r1178612 Property changes on: solr ___________________________________________________________________ Modified: svn:mergeinfo Merged /lucene/dev/trunk/solr:r1178612 Index: solr/core/src/java/org/apache/solr/core/SolrCore.java =================================================================== --- solr/core/src/java/org/apache/solr/core/SolrCore.java (revision 1178612) +++ solr/core/src/java/org/apache/solr/core/SolrCore.java (working copy) @@ -1077,10 +1077,11 @@ 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); Property changes on: lucene ___________________________________________________________________ Modified: svn:mergeinfo Merged /lucene/dev/trunk/lucene:r1178612 Index: lucene/contrib/misc/src/test/org/apache/lucene/index/TestMultiPassIndexSplitter.java =================================================================== --- lucene/contrib/misc/src/test/org/apache/lucene/index/TestMultiPassIndexSplitter.java (revision 1178612) +++ lucene/contrib/misc/src/test/org/apache/lucene/index/TestMultiPassIndexSplitter.java (working copy) @@ -44,9 +44,6 @@ input = IndexReader.open(dir, false); // delete the last doc input.deleteDocument(input.maxDoc() - 1); - IndexReader inputOld = input; - input = input.reopen(true); - inputOld.close(); } @Override Index: lucene/contrib/misc/src/test/org/apache/lucene/store/TestNRTCachingDirectory.java =================================================================== --- lucene/contrib/misc/src/test/org/apache/lucene/store/TestNRTCachingDirectory.java (revision 1178612) +++ lucene/contrib/misc/src/test/org/apache/lucene/store/TestNRTCachingDirectory.java (working copy) @@ -65,8 +65,8 @@ 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; } Index: lucene/contrib/misc/src/java/org/apache/lucene/search/SearcherManager.java =================================================================== --- lucene/contrib/misc/src/java/org/apache/lucene/search/SearcherManager.java (revision 1178612) +++ lucene/contrib/misc/src/java/org/apache/lucene/search/SearcherManager.java (working copy) @@ -111,7 +111,7 @@ } /** 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 @@ // 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 { Index: lucene/contrib/misc/src/java/org/apache/lucene/index/NRTManager.java =================================================================== --- lucene/contrib/misc/src/java/org/apache/lucene/index/NRTManager.java (revision 1178612) +++ lucene/contrib/misc/src/java/org/apache/lucene/index/NRTManager.java (working copy) @@ -309,7 +309,14 @@ // 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); Property changes on: lucene/backwards/src/test ___________________________________________________________________ Modified: svn:mergeinfo Merged /lucene/dev/trunk/lucene/backwards/src/test:r1178612 Index: lucene/CHANGES.txt =================================================================== --- lucene/CHANGES.txt (revision 1178612) +++ lucene/CHANGES.txt (working copy) @@ -19,6 +19,11 @@ 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 Index: lucene/src/test/org/apache/lucene/search/TestCachingWrapperFilter.java =================================================================== --- lucene/src/test/org/apache/lucene/search/TestCachingWrapperFilter.java (revision 1178612) +++ lucene/src/test/org/apache/lucene/search/TestCachingWrapperFilter.java (working copy) @@ -298,10 +298,12 @@ 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; } } Index: lucene/src/test/org/apache/lucene/search/TestCachingSpanFilter.java =================================================================== --- lucene/src/test/org/apache/lucene/search/TestCachingSpanFilter.java (revision 1178612) +++ lucene/src/test/org/apache/lucene/search/TestCachingSpanFilter.java (working copy) @@ -149,10 +149,12 @@ 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; } } Index: lucene/src/test/org/apache/lucene/index/TestIndexReaderClone.java =================================================================== --- lucene/src/test/org/apache/lucene/index/TestIndexReaderClone.java (revision 1178612) +++ lucene/src/test/org/apache/lucene/index/TestIndexReaderClone.java (working copy) @@ -115,7 +115,8 @@ 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 @@ 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 @@ 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); Index: lucene/src/test/org/apache/lucene/index/TestIndexWriterCommit.java =================================================================== --- lucene/src/test/org/apache/lucene/index/TestIndexWriterCommit.java (revision 1178612) +++ lucene/src/test/org/apache/lucene/index/TestIndexWriterCommit.java (working copy) @@ -344,7 +344,8 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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(); Index: lucene/src/test/org/apache/lucene/index/TestIndexReader.java =================================================================== --- lucene/src/test/org/apache/lucene/index/TestIndexReader.java (revision 1178612) +++ lucene/src/test/org/apache/lucene/index/TestIndexReader.java (working copy) @@ -92,7 +92,8 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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(); Index: lucene/src/test/org/apache/lucene/index/TestIndexWriter.java =================================================================== --- lucene/src/test/org/apache/lucene/index/TestIndexWriter.java (revision 1178612) +++ lucene/src/test/org/apache/lucene/index/TestIndexWriter.java (working copy) @@ -1568,7 +1568,8 @@ if (iter == 1) { w.commit(); } - IndexReader r2 = r.reopen(); + IndexReader r2 = IndexReader.openIfChanged(r); + assertNotNull(r2); assertTrue(r != r2); files = Arrays.asList(dir.listAll()); Index: lucene/src/test/org/apache/lucene/index/TestNeverDelete.java =================================================================== --- lucene/src/test/org/apache/lucene/index/TestNeverDelete.java (revision 1178612) +++ lucene/src/test/org/apache/lucene/index/TestNeverDelete.java (working copy) @@ -91,8 +91,8 @@ 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; } Index: lucene/src/test/org/apache/lucene/index/TestStressNRT.java =================================================================== --- lucene/src/test/org/apache/lucene/index/TestStressNRT.java (revision 1178612) +++ lucene/src/test/org/apache/lucene/index/TestStressNRT.java (working copy) @@ -144,7 +144,7 @@ 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 @@ 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(); Index: lucene/src/test/org/apache/lucene/index/TestNRTThreads.java =================================================================== --- lucene/src/test/org/apache/lucene/index/TestNRTThreads.java (revision 1178612) +++ lucene/src/test/org/apache/lucene/index/TestNRTThreads.java (working copy) @@ -41,8 +41,8 @@ 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; } Index: lucene/src/test/org/apache/lucene/index/TestIndexWriterReader.java =================================================================== --- lucene/src/test/org/apache/lucene/index/TestIndexWriterReader.java (revision 1178612) +++ lucene/src/test/org/apache/lucene/index/TestIndexWriterReader.java (working copy) @@ -667,8 +667,8 @@ } ((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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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; } Index: lucene/src/test/org/apache/lucene/index/TestRollingUpdates.java =================================================================== --- lucene/src/test/org/apache/lucene/index/TestRollingUpdates.java (revision 1178612) +++ lucene/src/test/org/apache/lucene/index/TestRollingUpdates.java (working copy) @@ -126,8 +126,8 @@ 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; } Index: lucene/src/test/org/apache/lucene/index/TestIndexReaderReopen.java =================================================================== --- lucene/src/test/org/apache/lucene/index/TestIndexReaderReopen.java (revision 1178612) +++ lucene/src/test/org/apache/lucene/index/TestIndexReaderReopen.java (working copy) @@ -183,8 +183,8 @@ 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 @@ 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 @@ } 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ // 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 @@ Collection 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 @@ 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 @@ 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(); Index: lucene/src/java/org/apache/lucene/search/IndexSearcher.java =================================================================== --- lucene/src/java/org/apache/lucene/search/IndexSearcher.java (revision 1178612) +++ lucene/src/java/org/apache/lucene/search/IndexSearcher.java (working copy) @@ -51,7 +51,7 @@ * 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)}). Index: lucene/src/java/org/apache/lucene/index/ParallelReader.java =================================================================== --- lucene/src/java/org/apache/lucene/index/ParallelReader.java (revision 1178612) +++ lucene/src/java/org/apache/lucene/index/ParallelReader.java (working copy) @@ -154,12 +154,12 @@ *
* 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. *

* 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}). *

* If subreaders are shared, then the reference count of those * readers is increased to ensure that the subreaders remain open @@ -169,7 +169,7 @@ * @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 @@ 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 @@ return pr; } else { // No subreader was refreshed - return this; + return null; } } Index: lucene/src/java/org/apache/lucene/index/SegmentReader.java =================================================================== --- lucene/src/java/org/apache/lucene/index/SegmentReader.java (revision 1178612) +++ lucene/src/java/org/apache/lucene/index/SegmentReader.java (working copy) @@ -202,13 +202,13 @@ } @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 @@ // 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 Index: lucene/src/java/org/apache/lucene/index/MultiReader.java =================================================================== --- lucene/src/java/org/apache/lucene/index/MultiReader.java (revision 1178612) +++ lucene/src/java/org/apache/lucene/index/MultiReader.java (working copy) @@ -91,14 +91,14 @@ /** * Tries to reopen the subreaders. *
- * 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. *

* 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}). *

* If subreaders are shared, then the reference count of those * readers is increased to ensure that the subreaders remain open @@ -108,8 +108,8 @@ * @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 @@ @Override public synchronized Object clone() { try { - return doReopen(true); + return doOpenIfChanged(true); } catch (Exception ex) { throw new RuntimeException(ex); } @@ -133,33 +133,35 @@ /** * 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 @@ } } - 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 @@ mr.decrefOnClose = newDecrefOnClose; return mr; } else { - return this; + return null; } } Index: lucene/src/java/org/apache/lucene/index/DirectoryReader.java =================================================================== --- lucene/src/java/org/apache/lucene/index/DirectoryReader.java (revision 1178612) +++ lucene/src/java/org/apache/lucene/index/DirectoryReader.java (working copy) @@ -183,7 +183,7 @@ 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 oldNormsCache, boolean readOnly, boolean doClone, int termInfosIndexDivisor, Collection readerFinishedListeners) throws IOException { @@ -234,19 +234,22 @@ // 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; + readerShared[i] = false; + newReaders[i] = newReader; } else { newReader = newReaders[i].reopenSegment(infos.info(i), doClone, readOnly); - assert newReader.readerFinishedListeners == readerFinishedListeners; + 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; + } } - 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; - } success = true; } finally { if (!success) { @@ -359,8 +362,8 @@ @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 @@ } @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 @@ 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 @@ // 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 @@ 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 @@ 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); Index: lucene/src/java/org/apache/lucene/index/IndexReader.java =================================================================== --- lucene/src/java/org/apache/lucene/index/IndexReader.java (revision 1178612) +++ lucene/src/java/org/apache/lucene/index/IndexReader.java (working copy) @@ -23,6 +23,7 @@ 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 @@ * @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 @@ } /** + * 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. + * + *

This method is typically far less costly than opening a + * fully new IndexReader as it shares + * resources (for example sub-readers) with the provided + * IndexReader, when possible. + * + *

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 + * SearcherManager in + * contrib/misc to simplify managing this. + * + *

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. + * + *

NOTE: 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 readOnly; 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 + * readOnly=true 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). + * + *

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}. + * + *

It's near 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.

+ * + *

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.

+ * + *

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.

+ * + *

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.

+ * + *

NOTE: 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}.

+ * + * @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. *

@@ -504,28 +677,50 @@ * * @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 @@ * @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 @@ * changes to the index on close, but the old reader still * reflects all changes made up until it was cloned. *

- * 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 @@ * implemented in the IndexReader base class. * *

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 @@ * *

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 @@ * index since this reader was opened. * *

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).

* *

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 @@ * merging, this method will still return false.

* *

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.

* * @throws CorruptIndexException if the index is corrupt @@ -1424,4 +1642,52 @@ public int getTermInfosIndexDivisor() { throw new UnsupportedOperationException("This reader does not support this method."); } + + // Back compat for reopen() + @Deprecated + private static final VirtualMethod reopenMethod1 = + new VirtualMethod(IndexReader.class, "reopen"); + @Deprecated + private static final VirtualMethod doOpenIfChangedMethod1 = + new VirtualMethod(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 reopenMethod2 = + new VirtualMethod(IndexReader.class, "reopen", boolean.class); + @Deprecated + private static final VirtualMethod doOpenIfChangedMethod2 = + new VirtualMethod(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 reopenMethod3 = + new VirtualMethod(IndexReader.class, "reopen", IndexCommit.class); + @Deprecated + private static final VirtualMethod doOpenIfChangedMethod3 = + new VirtualMethod(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 reopenMethod4 = + new VirtualMethod(IndexReader.class, "reopen", IndexWriter.class, boolean.class); + @Deprecated + private static final VirtualMethod doOpenIfChangedMethod4 = + new VirtualMethod(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 }