diff --git a/src/java/org/apache/lucene/index/DirectoryIndexReader.java b/src/java/org/apache/lucene/index/DirectoryIndexReader.java index 8add9c5f787..8185e4c838a 100644 --- a/src/java/org/apache/lucene/index/DirectoryIndexReader.java +++ b/src/java/org/apache/lucene/index/DirectoryIndexReader.java @@ -80,7 +80,7 @@ abstract class DirectoryIndexReader extends IndexReader implements Cloneable { boolean hasSegmentInfos() { return segmentInfos != null; } - + protected DirectoryIndexReader() {} DirectoryIndexReader(Directory directory, SegmentInfos segmentInfos, @@ -167,11 +167,16 @@ abstract class DirectoryIndexReader extends IndexReader implements Cloneable { public final synchronized IndexReader clone(boolean openReadOnly) throws CorruptIndexException, IOException { - final SegmentInfos infos = (SegmentInfos) segmentInfos.clone(); - DirectoryIndexReader newReader = doReopen(infos, true, openReadOnly); + final SegmentInfos clonedInfos; + if (segmentInfos != null) { + clonedInfos = (SegmentInfos) segmentInfos.clone(); + } else { + clonedInfos = null; + } + DirectoryIndexReader newReader = doReopen(clonedInfos, true, openReadOnly); if (this != newReader) { - newReader.init(directory, infos, closeDirectory, openReadOnly); + newReader.init(directory, clonedInfos, closeDirectory, openReadOnly); newReader.deletionPolicy = deletionPolicy; } diff --git a/src/java/org/apache/lucene/index/IndexReader.java b/src/java/org/apache/lucene/index/IndexReader.java index 134098ef734..43f93d6b2e5 100644 --- a/src/java/org/apache/lucene/index/IndexReader.java +++ b/src/java/org/apache/lucene/index/IndexReader.java @@ -1184,13 +1184,21 @@ public abstract class IndexReader implements Cloneable { return DirectoryIndexReader.listCommits(dir); } - /** Returns the sequential sub readers that this reader is - * logically composed of. IndexSearcher uses this API to - * drive searching by one sub reader at a time. If this - * reader is not composed of sequential child readers, it - * should return null. If this method returns an empty - * array, that means this reader is a null reader (for - * example a MultiReader that has no sub readers).*/ + /** Expert: returns the sequential sub readers that this + * reader is logically composed of. For example, + * IndexSearcher uses this API to drive searching by one + * sub reader at a time. If this reader is not composed + * of sequential child readers, it should return null. + * If this method returns an empty array, that means this + * reader is a null reader (for example a MultiReader + * that has no sub readers). + *

+ * NOTE: for a MultiSegmentReader, which is obtained by + * {@link #open} when the index has more than one + * segment, you should not use the sub-readers returned + * by this method to make any changes (setNorm, + * deleteDocument, etc.). Doing so will likely lead to + * index corruption. Use the parent reader instead. */ public IndexReader[] getSequentialSubReaders() { return null; } diff --git a/src/java/org/apache/lucene/index/SegmentReader.java b/src/java/org/apache/lucene/index/SegmentReader.java index 3cb24f8ced7..d37db837126 100644 --- a/src/java/org/apache/lucene/index/SegmentReader.java +++ b/src/java/org/apache/lucene/index/SegmentReader.java @@ -625,8 +625,15 @@ class SegmentReader extends DirectoryIndexReader { protected synchronized DirectoryIndexReader doReopen(SegmentInfos infos, boolean doClone, boolean openReadOnly) throws CorruptIndexException, IOException { DirectoryIndexReader newReader; - - if (infos.size() == 1) { + + if (infos == null) { + if (doClone) { + // OK: directly clone myself + newReader = reopenSegment(si, doClone, openReadOnly); + } else { + throw new UnsupportedOperationException("cannot reopen a standalone SegmentReader"); + } + } else if (infos.size() == 1) { SegmentInfo si = infos.info(0); if (segment.equals(si.name) && si.getUseCompoundFile() == SegmentReader.this.si.getUseCompoundFile()) { newReader = reopenSegment(si, doClone, openReadOnly); diff --git a/src/test/org/apache/lucene/index/TestIndexReaderClone.java b/src/test/org/apache/lucene/index/TestIndexReaderClone.java index eef9292a649..7a824d2c185 100644 --- a/src/test/org/apache/lucene/index/TestIndexReaderClone.java +++ b/src/test/org/apache/lucene/index/TestIndexReaderClone.java @@ -403,4 +403,24 @@ public class TestIndexReaderClone extends LuceneTestCase { private void assertDelDocsRefCountEquals(int refCount, SegmentReader reader) { assertEquals(refCount, reader.deletedDocsRef.refCount()); } + + public void testCloneSubreaders() throws Exception { + final Directory dir1 = new MockRAMDirectory(); + + TestIndexReaderReopen.createIndex(dir1, true); + IndexReader reader = IndexReader.open(dir1); + reader.deleteDocument(1); // acquire write lock + IndexReader[] subs = reader.getSequentialSubReaders(); + assert subs.length > 1; + + IndexReader[] clones = new IndexReader[subs.length]; + for (int x=0; x < subs.length; x++) { + clones[x] = (IndexReader) subs[x].clone(); + } + reader.close(); + for (int x=0; x < subs.length; x++) { + clones[x].close(); + } + dir1.close(); + } }