LUCENE-1976: make IndexReader.isCurrent work correctly for NRT readers

git-svn-id: https://svn.apache.org/repos/asf/lucene/java/trunk@826029 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Michael McCandless 2009-10-16 18:45:38 +00:00
parent a0776e5cd0
commit 052e1f5630
6 changed files with 109 additions and 27 deletions

View File

@ -90,6 +90,10 @@ Bug fixes
* LUCENE-1124: Make sure FuzzyQuery always matches the precise term.
(stefatwork@gmail.com 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

View File

@ -50,6 +50,7 @@ class DirectoryReader extends IndexReader implements Cloneable {
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 @@ class DirectoryReader extends IndexReader implements Cloneable {
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 @@ class DirectoryReader extends IndexReader implements Cloneable {
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 <code>false</code>,
* 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 || writer.isClosed()) {
// we loaded SegmentInfos from the directory
return SegmentInfos.readCurrentVersion(directory) == segmentInfos.getVersion();
} else {
return writer.nrtIsCurrent(segmentInfosStart);
}
}
protected synchronized void doClose() throws IOException {

View File

@ -535,6 +535,13 @@ final class DocumentsWriter {
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());

View File

@ -468,7 +468,27 @@ public abstract class IndexReader implements Cloneable {
}
/**
* 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.
*
* <p>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.</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}
* 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.</p>
*
* @throws UnsupportedOperationException unless overridden in subclass
*/
public long getVersion() {
@ -487,21 +507,32 @@ public abstract class IndexReader implements Cloneable {
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
* <code>false</code>, 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.
*
* <p>
* Not implemented in the IndexReader base class.
* </p>
* Check whether any new changes have occurred to the
* 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
* 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}
* 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.</p>
*
* <p>In any event, if this returns false, you should call
* {@link #reopen} to get a new reader that sees the
* changes.</p>
*
* @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 {

View File

@ -4844,4 +4844,18 @@ public class IndexWriter {
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();
}
}
synchronized boolean isClosed() {
return closed;
}
}

View File

@ -76,7 +76,7 @@ public class TestIndexWriterReader extends LuceneTestCase {
Directory dir1 = new MockRAMDirectory();
IndexWriter writer = new IndexWriter(dir1, new WhitespaceAnalyzer(),
IndexWriter.MaxFieldLength.LIMITED);
IndexWriter.MaxFieldLength.LIMITED);
// create the index
createIndexNoClose(!optimize, "index1", writer);
@ -85,6 +85,7 @@ public class TestIndexWriterReader extends LuceneTestCase {
// get a reader
IndexReader r1 = writer.getReader();
assertTrue(r1.isCurrent());
String id10 = r1.document(10).getField("id").stringValue();
@ -92,18 +93,37 @@ public class TestIndexWriterReader extends LuceneTestCase {
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));
r1.close();
r2.close();
writer.close();
assertTrue(r2.isCurrent());
IndexReader r3 = IndexReader.open(dir1, true);
assertTrue(r3.isCurrent());
assertTrue(r2.isCurrent());
assertEquals(0, count(new Term("id", id10), r3));
assertEquals(1, count(new Term("id", Integer.toString(8000)), r3));
writer = new IndexWriter(dir1, new WhitespaceAnalyzer(),
IndexWriter.MaxFieldLength.LIMITED);
Document doc = new Document();
doc.add(new Field("field", "a b c", Field.Store.NO, Field.Index.ANALYZED));
writer.addDocument(doc);
assertTrue(r2.isCurrent());
assertTrue(r3.isCurrent());
writer.close();
assertFalse(r2.isCurrent());
assertTrue(!r3.isCurrent());
r2.close();
r3.close();
dir1.close();
@ -133,9 +153,18 @@ public class TestIndexWriterReader extends LuceneTestCase {
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"));