LUCENE-1551: add expert IndexReader.reopen(IndexCommit)

git-svn-id: https://svn.apache.org/repos/asf/lucene/java/trunk@752538 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Michael McCandless 2009-03-11 17:32:37 +00:00
parent cce1e98416
commit 75d6fab25b
4 changed files with 122 additions and 22 deletions

View File

@ -173,6 +173,11 @@ New features
15. LUCENE-1398: Add ReverseStringFilter to contrib/analyzers, a filter 15. LUCENE-1398: Add ReverseStringFilter to contrib/analyzers, a filter
to reverse the characters in each token. (Koji Sekiguchi via yonik) to reverse the characters in each token. (Koji Sekiguchi via yonik)
16. LUCENE-1551: Add expert IndexReader.reopen(IndexCommit) to allow
efficiently opening a new reader on a specific commit, sharing
resources with the original reader. (Torin Danil via Mike
McCandless)
Optimizations Optimizations
1. LUCENE-1427: Fixed QueryWrapperFilter to not waste time computing 1. LUCENE-1427: Fixed QueryWrapperFilter to not waste time computing

View File

@ -149,11 +149,15 @@ abstract class DirectoryIndexReader extends IndexReader implements Cloneable {
public final synchronized IndexReader reopen() throws CorruptIndexException, IOException { public final synchronized IndexReader reopen() throws CorruptIndexException, IOException {
// Preserve current readOnly // Preserve current readOnly
return doReopen(readOnly); return doReopen(readOnly, null);
} }
public final synchronized IndexReader reopen(boolean openReadOnly) throws CorruptIndexException, IOException { public final synchronized IndexReader reopen(boolean openReadOnly) throws CorruptIndexException, IOException {
return doReopen(openReadOnly); return doReopen(openReadOnly, null);
}
public final synchronized IndexReader reopen(final IndexCommit commit) throws CorruptIndexException, IOException {
return doReopen(true, commit);
} }
public final synchronized Object clone() { public final synchronized Object clone() {
@ -194,29 +198,44 @@ abstract class DirectoryIndexReader extends IndexReader implements Cloneable {
// If there are no changes to the index, simply return // If there are no changes to the index, simply return
// ourself. If there are changes, load the latest // ourself. If there are changes, load the latest
// SegmentInfos and reopen based on that // SegmentInfos and reopen based on that
protected final synchronized IndexReader doReopen(final boolean openReadOnly) throws CorruptIndexException, IOException { protected final synchronized IndexReader doReopen(final boolean openReadOnly, IndexCommit commit) throws CorruptIndexException, IOException {
ensureOpen(); ensureOpen();
if (hasChanges) { assert commit == null || openReadOnly;
// We have changes, which means we are not readOnly:
assert readOnly == false;
// and we hold the write lock:
assert writeLock != null;
// so no other writer holds the write lock, which
// means no changes could have been done to the index:
assert isCurrent();
if (openReadOnly) { if (commit == null) {
return (IndexReader) clone(openReadOnly); if (hasChanges) {
} else { // We have changes, which means we are not readOnly:
return this; assert readOnly == false;
// and we hold the write lock:
assert writeLock != null;
// so no other writer holds the write lock, which
// means no changes could have been done to the index:
assert isCurrent();
if (openReadOnly) {
return (IndexReader) clone(openReadOnly);
} else {
return this;
}
} else if (isCurrent()) {
if (openReadOnly != readOnly) {
// Just fallback to clone
return (IndexReader) clone(openReadOnly);
} else {
return this;
}
} }
} else if (isCurrent()) { } else {
if (openReadOnly != readOnly) { if (directory != commit.getDirectory())
// Just fallback to clone throw new IOException("the specified commit does not match the specified Directory");
return (IndexReader) clone(openReadOnly); if (segmentInfos != null && commit.getSegmentsFileName().equals(segmentInfos.getCurrentSegmentFileName())) {
} else { if (readOnly != openReadOnly) {
return this; // Just fallback to clone
return (IndexReader) clone(openReadOnly);
} else {
return this;
}
} }
} }
@ -247,7 +266,11 @@ abstract class DirectoryIndexReader extends IndexReader implements Cloneable {
closeDirectory = false; closeDirectory = false;
try { try {
reader = (DirectoryIndexReader) finder.run(); if (commit == null) {
reader = (DirectoryIndexReader) finder.run();
} else {
reader = (DirectoryIndexReader) finder.doBody(commit.getSegmentsFileName());
}
} finally { } finally {
if (myCloseDirectory) { if (myCloseDirectory) {
assert directory instanceof FSDirectory; assert directory instanceof FSDirectory;

View File

@ -369,6 +369,16 @@ public abstract class IndexReader implements Cloneable {
throw new UnsupportedOperationException("This reader does not support reopen()."); throw new UnsupportedOperationException("This reader does not support reopen().");
} }
/** 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).");
}
/** /**
* Efficiently clones the IndexReader (sharing most * Efficiently clones the IndexReader (sharing most
* internal state). * internal state).

View File

@ -1052,6 +1052,7 @@ public class TestIndexReaderReopen extends LuceneTestCase {
} }
} }
/*
private void assertReaderOpen(IndexReader reader) { private void assertReaderOpen(IndexReader reader) {
reader.ensureOpen(); reader.ensureOpen();
@ -1062,6 +1063,7 @@ public class TestIndexReaderReopen extends LuceneTestCase {
} }
} }
} }
*/
private void assertRefCountEquals(int refCount, IndexReader reader) { private void assertRefCountEquals(int refCount, IndexReader reader) {
assertEquals("Reader has wrong refCount value.", refCount, reader.getRefCount()); assertEquals("Reader has wrong refCount value.", refCount, reader.getRefCount());
@ -1225,4 +1227,64 @@ public class TestIndexReaderReopen extends LuceneTestCase {
r2.close(); r2.close();
dir.close(); dir.close();
} }
private static class KeepAllCommits implements IndexDeletionPolicy {
public void onInit(List commits) {
}
public void onCommit(List commits) {
}
}
public void testReopenOnCommit() throws Throwable {
Directory dir = new MockRAMDirectory();
IndexWriter writer = new IndexWriter(dir, new WhitespaceAnalyzer(), new KeepAllCommits(), IndexWriter.MaxFieldLength.UNLIMITED);
for(int i=0;i<4;i++) {
Document doc = new Document();
doc.add(new Field("id", ""+i, Field.Store.NO, Field.Index.NOT_ANALYZED));
writer.addDocument(doc);
writer.commit(""+i);
}
for(int i=0;i<4;i++) {
writer.deleteDocuments(new Term("id", ""+i));
writer.commit(""+(4+i));
}
writer.close();
IndexReader r = IndexReader.open(dir);
assertEquals(0, r.numDocs());
assertEquals(4, r.maxDoc());
Iterator it = IndexReader.listCommits(dir).iterator();
while(it.hasNext()) {
IndexCommit commit = (IndexCommit) it.next();
IndexReader r2 = r.reopen(commit);
assertTrue(r2 != r);
// Reader should be readOnly
try {
r2.deleteDocument(0);
fail("no exception hit");
} catch (UnsupportedOperationException uoe) {
// expected
}
final String s = commit.getUserData();
final int v;
if (s == null) {
// First commit created by IW
v = -1;
} else {
v = Integer.parseInt(s);
}
if (v < 4) {
assertEquals(1+v, r2.numDocs());
} else {
assertEquals(7-v, r2.numDocs());
}
r.close();
r = r2;
}
r.close();
dir.close();
}
} }