Index: CHANGES.txt =================================================================== --- CHANGES.txt (revision 825137) +++ CHANGES.txt (working copy) @@ -87,6 +87,10 @@ BooleanScorer for scoring), whereby some matching documents fail to be collected. (Fulin Tang via Mike McCandless) +* LUCENE-1976: Fix IndexReader.isCurrent() to return the right thing + when the reader is a near real-time reader. (Jake Mannix via Mike + McCandless) + New features * LUCENE-1933: Provide a convenience AttributeFactory that creates a Index: src/test/org/apache/lucene/index/TestIndexWriterReader.java =================================================================== --- src/test/org/apache/lucene/index/TestIndexWriterReader.java (revision 825137) +++ src/test/org/apache/lucene/index/TestIndexWriterReader.java (working copy) @@ -85,6 +85,7 @@ // get a reader IndexReader r1 = writer.getReader(); + assertTrue(r1.isCurrent()); String id10 = r1.document(10).getField("id").stringValue(); @@ -92,8 +93,10 @@ newDoc.removeField("id"); newDoc.add(new Field("id", Integer.toString(8000), Store.YES, Index.NOT_ANALYZED)); writer.updateDocument(new Term("id", id10), newDoc); + assertFalse(r1.isCurrent()); IndexReader r2 = writer.getReader(); + assertTrue(r2.isCurrent()); assertEquals(0, count(new Term("id", id10), r2)); assertEquals(1, count(new Term("id", Integer.toString(8000)), r2)); @@ -102,6 +105,7 @@ writer.close(); IndexReader r3 = IndexReader.open(dir1, true); + assertTrue(r3.isCurrent()); assertEquals(0, count(new Term("id", id10), r3)); assertEquals(1, count(new Term("id", Integer.toString(8000)), r3)); r3.close(); @@ -133,9 +137,18 @@ createIndexNoClose(!optimize, "index2", writer2); writer2.close(); + IndexReader r0 = writer.getReader(); + assertTrue(r0.isCurrent()); writer.addIndexesNoOptimize(new Directory[] { dir2 }); + assertFalse(r0.isCurrent()); + r0.close(); IndexReader r1 = writer.getReader(); + assertTrue(r1.isCurrent()); + + writer.commit(); + assertTrue(r1.isCurrent()); + assertEquals(200, r1.maxDoc()); int index2df = r1.docFreq(new Term("indexname", "index2")); Index: src/java/org/apache/lucene/index/DirectoryReader.java =================================================================== --- src/java/org/apache/lucene/index/DirectoryReader.java (revision 825137) +++ src/java/org/apache/lucene/index/DirectoryReader.java (working copy) @@ -50,6 +50,7 @@ private final HashSet synced = new HashSet(); private Lock writeLock; private SegmentInfos segmentInfos; + private SegmentInfos segmentInfosStart; private boolean stale; private final int termInfosIndexDivisor; @@ -124,6 +125,7 @@ this.directory = writer.getDirectory(); this.readOnly = true; this.segmentInfos = infos; + segmentInfosStart = (SegmentInfos) infos.clone(); this.termInfosIndexDivisor = termInfosIndexDivisor; if (!readOnly) { // We assume that this segments_N was previously @@ -769,19 +771,14 @@ return segmentInfos.getUserData(); } - /** - * Check whether this IndexReader is still using the current (i.e., most recently committed) version of the index. If - * a writer has committed any changes to the index since this reader was opened, this will return false, - * in which case you must open a new IndexReader in order - * to see the changes. Use {@link IndexWriter#commit} to - * commit changes to the index. - * - * @throws CorruptIndexException if the index is corrupt - * @throws IOException if there is a low-level IO error - */ public boolean isCurrent() throws CorruptIndexException, IOException { ensureOpen(); - return SegmentInfos.readCurrentVersion(directory) == segmentInfos.getVersion(); + if (writer == null) { + // we loaded SegmentInfos from the directory + return SegmentInfos.readCurrentVersion(directory) == segmentInfos.getVersion(); + } else { + return writer.nrtIsCurrent(segmentInfosStart); + } } protected synchronized void doClose() throws IOException { Index: src/java/org/apache/lucene/index/IndexReader.java =================================================================== --- src/java/org/apache/lucene/index/IndexReader.java (revision 825137) +++ src/java/org/apache/lucene/index/IndexReader.java (working copy) @@ -468,7 +468,27 @@ } /** - * Version number when this IndexReader was opened. Not implemented in the IndexReader base class. + * Version number when this IndexReader was opened. Not + * 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 + * 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 + * {@link IndexWriter#commit} is called.

+ * + *

If instead this reader is a near real-time reader + * (ie, obtained by a call to {@link + * IndexWriter#getReader}, or by calling {@link #reopen} + * 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 + * writer, the version will not changed until a commit is + * completed. Thus, you should not rely on this method to + * determine when a near real-time reader should be + * opened. Use {@link #isCurrent} instead.

+ * * @throws UnsupportedOperationException unless overridden in subclass */ public long getVersion() { @@ -518,21 +538,32 @@ throw new UnsupportedOperationException("This reader does not support this method."); } + /** - * Check whether this IndexReader is still using the - * current (i.e., most recently committed) version of the - * index. If a writer has committed any changes to the - * index since this reader was opened, this will return - * false, in which case you must open a new - * IndexReader in order to see the changes. Changes must - * be committed using {@link IndexWriter#commit} to be - * visible to readers. - * - *

- * Not implemented in the IndexReader base class. - *

+ * Check whether any new changes have occurred to the + * 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 + * 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} + * 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. + * Note that even if the writer has only performed + * 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 + * changes.

+ * * @throws CorruptIndexException if the index is corrupt - * @throws IOException if there is a low-level IO error + * @throws IOException if there is a low-level IO error * @throws UnsupportedOperationException unless overridden in subclass */ public boolean isCurrent() throws CorruptIndexException, IOException { Index: src/java/org/apache/lucene/index/DocumentsWriter.java =================================================================== --- src/java/org/apache/lucene/index/DocumentsWriter.java (revision 825137) +++ src/java/org/apache/lucene/index/DocumentsWriter.java (working copy) @@ -543,6 +543,13 @@ return true; } + synchronized boolean anyChanges() { + return numDocsInRAM != 0 || + deletesInRAM.numTerms != 0 || + deletesInRAM.docIDs.size() != 0 || + deletesInRAM.queries.size() != 0; + } + synchronized private void initFlushState(boolean onlyDocStore) { initSegmentName(onlyDocStore); flushState = new SegmentWriteState(this, directory, segment, docStoreSegment, numDocsInRAM, numDocsInStore, writer.getTermIndexInterval()); Index: src/java/org/apache/lucene/index/IndexWriter.java =================================================================== --- src/java/org/apache/lucene/index/IndexWriter.java (revision 825137) +++ src/java/org/apache/lucene/index/IndexWriter.java (working copy) @@ -4961,4 +4961,14 @@ boolean testPoint(String name) { return true; } + + synchronized boolean nrtIsCurrent(SegmentInfos infos) { + if (!infos.equals(segmentInfos)) { + // if any structural changes (new segments), we are + // stale + return false; + } else { + return !docWriter.anyChanges(); + } + } }