Index: solr/src/java/org/apache/solr/search/function/ValueSource.java =================================================================== --- solr/src/java/org/apache/solr/search/function/ValueSource.java (revision 985484) +++ solr/src/java/org/apache/solr/search/function/ValueSource.java (working copy) @@ -24,12 +24,13 @@ import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Searcher; import org.apache.lucene.search.SortField; +import org.apache.lucene.util.Bits; +import org.apache.lucene.index.MultiFields; import java.io.IOException; import java.io.Serializable; import java.util.IdentityHashMap; import java.util.Map; -import java.util.HashMap; import java.util.Collections; /** @@ -177,6 +178,7 @@ protected final int maxDoc; protected final DocValues values; protected boolean checkDeletes; + private final Bits delDocs; protected ValueSourceScorer(IndexReader reader, DocValues values) { super(null); @@ -184,6 +186,7 @@ this.maxDoc = reader.maxDoc(); this.values = values; setCheckDeletes(true); + this.delDocs = MultiFields.getDeletedDocs(reader); } public IndexReader getReader() { @@ -195,7 +198,7 @@ } public boolean matches(int doc) { - return (!checkDeletes || !reader.isDeleted(doc)) && matchesValue(doc); + return (!checkDeletes || !delDocs.get(doc)) && matchesValue(doc); } public boolean matchesValue(int doc) { Index: solr/src/java/org/apache/solr/search/function/FunctionQuery.java =================================================================== --- solr/src/java/org/apache/solr/search/function/FunctionQuery.java (revision 985484) +++ solr/src/java/org/apache/solr/search/function/FunctionQuery.java (working copy) @@ -19,11 +19,12 @@ import org.apache.lucene.index.IndexReader; import org.apache.lucene.search.*; +import org.apache.lucene.index.MultiFields; +import org.apache.lucene.util.Bits; import org.apache.solr.search.SolrIndexReader; import java.io.IOException; import java.util.Set; -import java.util.IdentityHashMap; import java.util.Map; @@ -112,6 +113,7 @@ int doc=-1; final DocValues vals; final boolean hasDeletions; + final Bits delDocs; public AllScorer(Similarity similarity, IndexReader reader, FunctionWeight w) throws IOException { super(similarity); @@ -120,6 +122,8 @@ this.reader = reader; this.maxDoc = reader.maxDoc(); this.hasDeletions = reader.hasDeletions(); + this.delDocs = MultiFields.getDeletedDocs(reader); + assert !hasDeletions || delDocs != null; vals = func.getValues(weight.context, reader); } @@ -139,7 +143,7 @@ if (doc>=maxDoc) { return doc=NO_MORE_DOCS; } - if (hasDeletions && reader.isDeleted(doc)) continue; + if (hasDeletions && delDocs.get(doc)) continue; return doc; } } @@ -161,7 +165,7 @@ if (doc>=maxDoc) { return false; } - if (hasDeletions && reader.isDeleted(doc)) continue; + if (hasDeletions && delDocs.get(doc)) continue; // todo: maybe allow score() to throw a specific exception // and continue on to the next document if it is thrown... // that may be useful, but exceptions aren't really good Index: solr/src/java/org/apache/solr/search/SolrIndexReader.java =================================================================== --- solr/src/java/org/apache/solr/search/SolrIndexReader.java (revision 985484) +++ solr/src/java/org/apache/solr/search/SolrIndexReader.java (working copy) @@ -225,7 +225,7 @@ } @Override - public Bits getDeletedDocs() throws IOException { + public Bits getDeletedDocs() { return in.getDeletedDocs(); } @@ -267,11 +267,6 @@ } @Override - public boolean isDeleted(int n) { - return in.isDeleted(n); - } - - @Override public boolean hasDeletions() { return in.hasDeletions(); } Index: lucene/CHANGES.txt =================================================================== --- lucene/CHANGES.txt (revision 985485) +++ lucene/CHANGES.txt (working copy) @@ -105,6 +105,9 @@ calling setCalibrateSizeByDeletes(false) on the merge policy. (Mike McCandless) +* LUCENE-2600: Remove IndexReader.isDeleted in favor of + IndexReader.getDeletedDocs(). (Mike McCandless) + API Changes * LUCENE-2302, LUCENE-1458, LUCENE-2111, LUCENE-2514: Terms are no longer Index: lucene/src/test/org/apache/lucene/index/TestIndexReaderClone.java =================================================================== --- lucene/src/test/org/apache/lucene/index/TestIndexReaderClone.java (revision 985485) +++ lucene/src/test/org/apache/lucene/index/TestIndexReaderClone.java (working copy) @@ -26,8 +26,8 @@ import org.apache.lucene.document.Field; import org.apache.lucene.store.Directory; import org.apache.lucene.store.LockObtainFailedException; -import org.apache.lucene.store.MockRAMDirectory; import org.apache.lucene.util.LuceneTestCase; +import org.apache.lucene.util.Bits; /** * Tests cloning multiple types of readers, modifying the deletedDocs and norms @@ -243,10 +243,13 @@ } public static boolean isReadOnly(IndexReader r) { - if (r instanceof ReadOnlySegmentReader - || r instanceof ReadOnlyDirectoryReader) - return true; - return false; + if (r instanceof SegmentReader) { + return ((SegmentReader) r).readOnly; + } else if (r instanceof DirectoryReader) { + return ((DirectoryReader) r).readOnly; + } else { + return false; + } } public void testParallelReader() throws Exception { @@ -286,8 +289,9 @@ assertTrue(Similarity.getDefault().decodeNormValue(r1.norms("field1")[4]) == norm1); assertTrue(Similarity.getDefault().decodeNormValue(pr1Clone.norms("field1")[4]) != norm1); - assertTrue(!r1.isDeleted(10)); - assertTrue(pr1Clone.isDeleted(10)); + final Bits delDocs = MultiFields.getDeletedDocs(r1); + assertTrue(delDocs == null || !delDocs.get(10)); + assertTrue(MultiFields.getDeletedDocs(pr1Clone).get(10)); // try to update the original reader, which should throw an exception try { @@ -376,9 +380,10 @@ assertTrue(origSegmentReader.deletedDocs != clonedSegmentReader.deletedDocs); assertDocDeleted(origSegmentReader, clonedSegmentReader, 1); - assertTrue(!origSegmentReader.isDeleted(2)); // doc 2 should not be deleted + final Bits delDocs = origSegmentReader.getDeletedDocs(); + assertTrue(delDocs == null || !delDocs.get(2)); // doc 2 should not be deleted // in original segmentreader - assertTrue(clonedSegmentReader.isDeleted(2)); // doc 2 should be deleted in + assertTrue(clonedSegmentReader.getDeletedDocs().get(2)); // doc 2 should be deleted in // cloned segmentreader // deleting a doc from the original segmentreader should throw an exception @@ -420,7 +425,7 @@ clonedReader.close(); IndexReader r = IndexReader.open(dir1, false); - assertTrue(r.isDeleted(1)); + assertTrue(MultiFields.getDeletedDocs(r).get(1)); r.close(); dir1.close(); } @@ -448,7 +453,7 @@ private void assertDocDeleted(SegmentReader reader, SegmentReader reader2, int doc) { - assertEquals(reader.isDeleted(doc), reader2.isDeleted(doc)); + assertEquals(reader.getDeletedDocs().get(doc), reader2.getDeletedDocs().get(doc)); } private void assertDelDocsRefCountEquals(int refCount, SegmentReader reader) { Index: lucene/src/test/org/apache/lucene/index/TestIndexReader.java =================================================================== --- lucene/src/test/org/apache/lucene/index/TestIndexReader.java (revision 985485) +++ lucene/src/test/org/apache/lucene/index/TestIndexReader.java (working copy) @@ -1149,6 +1149,36 @@ dir.close(); } + public void testMultiReaderDeletes() throws Exception { + Directory dir = new MockRAMDirectory(); + RandomIndexWriter w = new RandomIndexWriter(random, dir); + Document doc = new Document(); + doc.add(new Field("f", "doctor", Field.Store.NO, Field.Index.NOT_ANALYZED)); + w.addDocument(doc); + doc = new Document(); + w.commit(); + doc.add(new Field("f", "who", Field.Store.NO, Field.Index.NOT_ANALYZED)); + w.addDocument(doc); + IndexReader r = w.getReader(); + IndexReader wr = SlowMultiReaderWrapper.wrap(r); + w.close(); + + assertNull(wr.getDeletedDocs()); + r.close(); + + r = IndexReader.open(dir, false); + wr = SlowMultiReaderWrapper.wrap(r); + + assertNull(wr.getDeletedDocs()); + assertEquals(1, r.deleteDocuments(new Term("f", "doctor"))); + assertNotNull(wr.getDeletedDocs()); + assertTrue(wr.getDeletedDocs().get(0)); + assertEquals(1, r.deleteDocuments(new Term("f", "who"))); + assertTrue(wr.getDeletedDocs().get(1)); + r.close(); + dir.close(); + } + private void deleteReaderReaderConflict(boolean optimize) throws IOException { Directory dir = getDirectory(); @@ -1250,7 +1280,6 @@ dir.close(); } - private void addDocumentWithFields(IndexWriter writer) throws IOException { Document doc = new Document(); @@ -1333,13 +1362,17 @@ } // check deletions + final Bits delDocs1 = MultiFields.getDeletedDocs(index1); + final Bits delDocs2 = MultiFields.getDeletedDocs(index2); for (int i = 0; i < index1.maxDoc(); i++) { - assertEquals("Doc " + i + " only deleted in one index.", index1.isDeleted(i), index2.isDeleted(i)); + assertEquals("Doc " + i + " only deleted in one index.", + delDocs1 == null || delDocs1.get(i), + delDocs2 == null || delDocs2.get(i)); } // check stored fields for (int i = 0; i < index1.maxDoc(); i++) { - if (!index1.isDeleted(i)) { + if (delDocs1 == null || !delDocs1.get(i)) { Document doc1 = index1.document(i); Document doc2 = index2.document(i); List fieldable1 = doc1.getFields(); @@ -1670,7 +1703,7 @@ // Reopen to readonly w/ no chnages IndexReader r3 = r.reopen(true); - assertTrue(r3 instanceof ReadOnlyDirectoryReader); + assertTrue(((DirectoryReader) r3).readOnly); r3.close(); // Add new segment @@ -1680,13 +1713,13 @@ // Reopen reader1 --> reader2 IndexReader r2 = r.reopen(true); r.close(); - assertTrue(r2 instanceof ReadOnlyDirectoryReader); + assertTrue(((DirectoryReader) r2).readOnly); IndexReader[] subs = r2.getSequentialSubReaders(); final int[] ints2 = FieldCache.DEFAULT.getInts(subs[0], "number"); r2.close(); - assertTrue(subs[0] instanceof ReadOnlySegmentReader); - assertTrue(subs[1] instanceof ReadOnlySegmentReader); + assertTrue(((SegmentReader) subs[0]).readOnly); + assertTrue(((SegmentReader) subs[1]).readOnly); assertTrue(ints == ints2); dir.close(); Index: lucene/src/test/org/apache/lucene/index/TestIndexWriter.java =================================================================== --- lucene/src/test/org/apache/lucene/index/TestIndexWriter.java (revision 985485) +++ lucene/src/test/org/apache/lucene/index/TestIndexWriter.java (working copy) @@ -76,6 +76,7 @@ import org.apache.lucene.util._TestUtil; import org.apache.lucene.util.ThreadInterruptedException; import org.apache.lucene.util.BytesRef; +import org.apache.lucene.util.Bits; public class TestIndexWriter extends LuceneTestCase { Random random; @@ -1897,8 +1898,10 @@ assertEquals(expected, reader.docFreq(new Term("contents", "here"))); assertEquals(expected, reader.maxDoc()); int numDel = 0; + final Bits delDocs = MultiFields.getDeletedDocs(reader); + assertNotNull(delDocs); for(int j=0;j fields = d.getFields(); if (d.getField("content3") == null) { Index: lucene/src/java/org/apache/lucene/index/ParallelReader.java =================================================================== --- lucene/src/java/org/apache/lucene/index/ParallelReader.java (revision 985485) +++ lucene/src/java/org/apache/lucene/index/ParallelReader.java (working copy) @@ -195,7 +195,7 @@ } @Override - public Bits getDeletedDocs() throws IOException { + public Bits getDeletedDocs() { return MultiFields.getDeletedDocs(readers.get(0)); } @@ -320,15 +320,6 @@ return hasDeletions; } - // check first reader - @Override - public boolean isDeleted(int n) { - // Don't call ensureOpen() here (it could affect performance) - if (readers.size() > 0) - return readers.get(0).isDeleted(n); - return false; - } - // delete in all readers @Override protected void doDelete(int n) throws CorruptIndexException, IOException { Index: lucene/src/java/org/apache/lucene/index/SegmentReader.java =================================================================== --- lucene/src/java/org/apache/lucene/index/SegmentReader.java (revision 985485) +++ lucene/src/java/org/apache/lucene/index/SegmentReader.java (working copy) @@ -56,7 +56,7 @@ CloseableThreadLocal fieldsReaderLocal = new FieldsReaderLocal(); CloseableThreadLocal termVectorsLocal = new CloseableThreadLocal(); - BitVector deletedDocs = null; + volatile BitVector deletedDocs; AtomicInteger deletedDocsRef = null; private boolean deletedDocsDirty = false; private boolean normsDirty = false; @@ -525,7 +525,7 @@ codecs = CodecProvider.getDefault(); } - SegmentReader instance = readOnly ? new ReadOnlySegmentReader() : new SegmentReader(); + SegmentReader instance = new SegmentReader(); instance.readOnly = readOnly; instance.si = si; instance.readBufferSize = readBufferSize; @@ -559,7 +559,7 @@ } @Override - public synchronized Bits getDeletedDocs() { + public Bits getDeletedDocs() { return deletedDocs; } @@ -663,7 +663,7 @@ assert !doClone || (normsUpToDate && deletionsUpToDate); // clone reader - SegmentReader clone = openReadOnly ? new ReadOnlySegmentReader() : new SegmentReader(); + SegmentReader clone = new SegmentReader(); boolean success = false; try { @@ -883,11 +883,6 @@ } @Override - public synchronized boolean isDeleted(int n) { - return (deletedDocs != null && deletedDocs.get(n)); - } - - @Override public Fields fields() throws IOException { return core.fields; } Index: lucene/src/java/org/apache/lucene/index/CheckIndex.java =================================================================== --- lucene/src/java/org/apache/lucene/index/CheckIndex.java (revision 985485) +++ lucene/src/java/org/apache/lucene/index/CheckIndex.java (working copy) @@ -733,8 +733,9 @@ } // Scan stored fields for all documents + final Bits delDocs = reader.getDeletedDocs(); for (int j = 0; j < info.docCount; ++j) { - if (!reader.isDeleted(j)) { + if (delDocs == null || !delDocs.get(j)) { status.docCount++; Document doc = reader.document(j); status.totFields += doc.getFields().size(); @@ -770,8 +771,9 @@ infoStream.print(" test: term vectors........"); } + final Bits delDocs = reader.getDeletedDocs(); for (int j = 0; j < info.docCount; ++j) { - if (!reader.isDeleted(j)) { + if (delDocs == null || !delDocs.get(j)) { status.docCount++; TermFreqVector[] tfv = reader.getTermFreqVectors(j); if (tfv != null) { Index: lucene/src/java/org/apache/lucene/index/ReadOnlyDirectoryReader.java =================================================================== --- lucene/src/java/org/apache/lucene/index/ReadOnlyDirectoryReader.java (revision 985484) +++ lucene/src/java/org/apache/lucene/index/ReadOnlyDirectoryReader.java (working copy) @@ -1,44 +0,0 @@ -package org.apache.lucene.index; - -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.apache.lucene.store.Directory; -import org.apache.lucene.index.codecs.CodecProvider; - -import java.io.IOException; -import java.util.Map; - -class ReadOnlyDirectoryReader extends DirectoryReader { - ReadOnlyDirectoryReader(Directory directory, SegmentInfos sis, IndexDeletionPolicy deletionPolicy, int termInfosIndexDivisor, CodecProvider codecs) throws IOException { - super(directory, sis, deletionPolicy, true, termInfosIndexDivisor, codecs); - } - - ReadOnlyDirectoryReader(Directory directory, SegmentInfos infos, SegmentReader[] oldReaders, int[] oldStarts, Map oldNormsCache, boolean doClone, - int termInfosIndexDivisor, CodecProvider codecs) throws IOException { - super(directory, infos, oldReaders, oldStarts, oldNormsCache, true, doClone, termInfosIndexDivisor, codecs); - } - - ReadOnlyDirectoryReader(IndexWriter writer, SegmentInfos infos, int termInfosIndexDivisor, CodecProvider codecs) throws IOException { - super(writer, infos, termInfosIndexDivisor, codecs); - } - - @Override - protected void acquireWriteLock() { - ReadOnlySegmentReader.noWrite(); - } -} Index: lucene/src/java/org/apache/lucene/index/MultiReader.java =================================================================== --- lucene/src/java/org/apache/lucene/index/MultiReader.java (revision 985485) +++ lucene/src/java/org/apache/lucene/index/MultiReader.java (working copy) @@ -153,7 +153,7 @@ } @Override - public Bits getDeletedDocs() throws IOException { + public Bits getDeletedDocs() { throw new UnsupportedOperationException("please use MultiFields.getDeletedDocs, or wrap your IndexReader with SlowMultiReaderWrapper, if you really need a top level Bits deletedDocs"); } @@ -279,13 +279,6 @@ } @Override - public boolean isDeleted(int n) { - // Don't call ensureOpen() here (it could affect performance) - int i = readerIndex(n); // find segment num - return subReaders[i].isDeleted(n - starts[i]); // dispatch to segment reader - } - - @Override public boolean hasDeletions() { // Don't call ensureOpen() here (it could affect performance) return hasDeletions; Index: lucene/src/java/org/apache/lucene/index/ReadOnlySegmentReader.java =================================================================== --- lucene/src/java/org/apache/lucene/index/ReadOnlySegmentReader.java (revision 985484) +++ lucene/src/java/org/apache/lucene/index/ReadOnlySegmentReader.java (working copy) @@ -1,36 +0,0 @@ -package org.apache.lucene.index; - -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -class ReadOnlySegmentReader extends SegmentReader { - - static void noWrite() { - throw new UnsupportedOperationException("This IndexReader cannot make any changes to the index (it was opened with readOnly = true)"); - } - - @Override - protected void acquireWriteLock() { - noWrite(); - } - - // Not synchronized - @Override - public boolean isDeleted(int n) { - return deletedDocs != null && deletedDocs.get(n); - } -} Index: lucene/src/java/org/apache/lucene/index/DirectoryReader.java =================================================================== --- lucene/src/java/org/apache/lucene/index/DirectoryReader.java (revision 985485) +++ lucene/src/java/org/apache/lucene/index/DirectoryReader.java (working copy) @@ -93,10 +93,7 @@ protected Object doBody(String segmentFileName) throws CorruptIndexException, IOException { SegmentInfos infos = new SegmentInfos(); infos.read(directory, segmentFileName, codecs2); - if (readOnly) - return new ReadOnlyDirectoryReader(directory, infos, deletionPolicy, termInfosIndexDivisor, codecs2); - else - return new DirectoryReader(directory, infos, deletionPolicy, false, termInfosIndexDivisor, codecs2); + return new DirectoryReader(directory, infos, deletionPolicy, readOnly, termInfosIndexDivisor, codecs2); } }.run(commit); } @@ -503,11 +500,7 @@ private synchronized DirectoryReader doReopen(SegmentInfos infos, boolean doClone, boolean openReadOnly) throws CorruptIndexException, IOException { DirectoryReader reader; - if (openReadOnly) { - reader = new ReadOnlyDirectoryReader(directory, infos, subReaders, starts, normsCache, doClone, termInfosIndexDivisor, null); - } else { - reader = new DirectoryReader(directory, infos, subReaders, starts, normsCache, false, doClone, termInfosIndexDivisor, null); - } + reader = new DirectoryReader(directory, infos, subReaders, starts, normsCache, openReadOnly, doClone, termInfosIndexDivisor, null); return reader; } @@ -588,13 +581,6 @@ } @Override - public boolean isDeleted(int n) { - // Don't call ensureOpen() here (it could affect performance) - final int i = readerIndex(n); // find segment num - return subReaders[i].isDeleted(n - starts[i]); // dispatch to segment reader - } - - @Override public boolean hasDeletions() { // Don't call ensureOpen() here (it could affect performance) return hasDeletions; @@ -735,7 +721,7 @@ // NOTE: we should not reach this code w/ the core // IndexReader classes; however, an external subclass // of IndexReader could reach this. - ReadOnlySegmentReader.noWrite(); + throw new UnsupportedOperationException("This IndexReader cannot make any changes to the index (it was opened with readOnly = true)"); } if (segmentInfos != null) { Index: lucene/src/java/org/apache/lucene/index/FilterIndexReader.java =================================================================== --- lucene/src/java/org/apache/lucene/index/FilterIndexReader.java (revision 985485) +++ lucene/src/java/org/apache/lucene/index/FilterIndexReader.java (working copy) @@ -273,7 +273,7 @@ } @Override - public Bits getDeletedDocs() throws IOException { + public Bits getDeletedDocs() { return MultiFields.getDeletedDocs(in); } @@ -324,12 +324,6 @@ } @Override - public boolean isDeleted(int n) { - // Don't call ensureOpen() here (it could affect performance) - return in.isDeleted(n); - } - - @Override public boolean hasDeletions() { // Don't call ensureOpen() here (it could affect performance) return in.hasDeletions(); Index: lucene/src/java/org/apache/lucene/index/SegmentMerger.java =================================================================== --- lucene/src/java/org/apache/lucene/index/SegmentMerger.java (revision 985485) +++ lucene/src/java/org/apache/lucene/index/SegmentMerger.java (working copy) @@ -367,10 +367,11 @@ throws IOException, MergeAbortedException, CorruptIndexException { int docCount = 0; final int maxDoc = reader.maxDoc(); + final Bits delDocs = MultiFields.getDeletedDocs(reader); if (matchingFieldsReader != null) { // We can bulk-copy because the fieldInfos are "congruent" for (int j = 0; j < maxDoc;) { - if (reader.isDeleted(j)) { + if (delDocs.get(j)) { // skip deleted docs ++j; continue; @@ -382,7 +383,7 @@ j++; numDocs++; if (j >= maxDoc) break; - if (reader.isDeleted(j)) { + if (delDocs.get(j)) { j++; break; } @@ -395,7 +396,7 @@ } } else { for (int j = 0; j < maxDoc; j++) { - if (reader.isDeleted(j)) { + if (delDocs.get(j)) { // skip deleted docs continue; } @@ -485,10 +486,11 @@ final IndexReader reader) throws IOException, MergeAbortedException { final int maxDoc = reader.maxDoc(); + final Bits delDocs = MultiFields.getDeletedDocs(reader); if (matchingVectorsReader != null) { // We can bulk-copy because the fieldInfos are "congruent" for (int docNum = 0; docNum < maxDoc;) { - if (reader.isDeleted(docNum)) { + if (delDocs.get(docNum)) { // skip deleted docs ++docNum; continue; @@ -500,7 +502,7 @@ docNum++; numDocs++; if (docNum >= maxDoc) break; - if (reader.isDeleted(docNum)) { + if (delDocs.get(docNum)) { docNum++; break; } @@ -512,7 +514,7 @@ } } else { for (int docNum = 0; docNum < maxDoc; docNum++) { - if (reader.isDeleted(docNum)) { + if (delDocs.get(docNum)) { // skip deleted docs continue; } @@ -621,12 +623,13 @@ inputDocBase += reader.maxDoc(); if (mergeState.delCounts[i] != 0) { int delCount = 0; - Bits deletedDocs = reader.getDeletedDocs(); + final Bits delDocs = MultiFields.getDeletedDocs(reader); + assert delDocs != null; final int maxDoc = reader.maxDoc(); final int[] docMap = mergeState.docMaps[i] = new int[maxDoc]; int newDocID = 0; for(int j=0;j public abstract Document document(int n, FieldSelector fieldSelector) throws CorruptIndexException, IOException; - /** Returns true if document n has been deleted */ - public abstract boolean isDeleted(int n); - /** Returns true if any documents have been deleted */ public abstract boolean hasDeletions(); @@ -1120,7 +1117,7 @@ * docs. * * @lucene.experimental */ - public abstract Bits getDeletedDocs() throws IOException; + public abstract Bits getDeletedDocs(); /** * Expert: return the IndexCommit that this reader has @@ -1304,16 +1301,4 @@ Fields retrieveFields() { return fields; } - - private Bits storedDelDocs; - - /** @lucene.internal */ - void storeDelDocs(Bits delDocs) { - this.storedDelDocs = delDocs; - } - - /** @lucene.internal */ - Bits retrieveDelDocs() { - return storedDelDocs; - } } Index: lucene/src/java/org/apache/lucene/index/IndexWriter.java =================================================================== --- lucene/src/java/org/apache/lucene/index/IndexWriter.java (revision 985485) +++ lucene/src/java/org/apache/lucene/index/IndexWriter.java (working copy) @@ -32,6 +32,7 @@ import org.apache.lucene.index.codecs.CodecProvider; import org.apache.lucene.util.ThreadInterruptedException; import org.apache.lucene.util.Version; +import org.apache.lucene.util.Bits; import java.io.IOException; import java.io.Closeable; @@ -418,7 +419,7 @@ // just like we do when loading segments_N synchronized(this) { applyDeletes(); - final IndexReader r = new ReadOnlyDirectoryReader(this, segmentInfos, termInfosIndexDivisor, codecs); + final IndexReader r = new DirectoryReader(this, segmentInfos, termInfosIndexDivisor, codecs); if (infoStream != null) { message("return reader version=" + r.getVersion() + " reader=" + r); } @@ -3464,7 +3465,9 @@ SegmentInfo info = sourceSegments.info(i); int docCount = info.docCount; SegmentReader previousReader = merge.readersClone[i]; + final Bits prevDelDocs = previousReader.getDeletedDocs(); SegmentReader currentReader = merge.readers[i]; + final Bits currentDelDocs = currentReader.getDeletedDocs(); if (previousReader.hasDeletions()) { // There were deletes on this segment when the merge @@ -3479,10 +3482,10 @@ // committed since we started the merge, so we // must merge them: for(int j=0;j readers = new ArrayList(); + final List starts = new ArrayList(); - final List bits = new ArrayList(); - final List starts = new ArrayList(); - + try { final int maxDoc = new ReaderUtil.Gather(r) { - @Override - protected void add(int base, IndexReader r) throws IOException { - // record all delDocs, even if they are null - bits.add(r.getDeletedDocs()); - starts.add(base); - } - }.run(); + @Override + protected void add(int base, IndexReader r) throws IOException { + // record all delDocs, even if they are null + readers.add(r); + starts.add(base); + } + }.run(); starts.add(maxDoc); + } catch (IOException ioe) { + // should not happen + throw new RuntimeException(ioe); + } - assert bits.size() > 0; - if (bits.size() == 1) { - // Only one actual sub reader -- optimize this case - result = bits.get(0); - } else { - result = new MultiBits(bits, starts); + assert readers.size() > 0; + if (readers.size() == 1) { + // Only one actual sub reader -- optimize this case + result = readers.get(0).getDeletedDocs(); + } else { + int[] startsArray = new int[starts.size()]; + for(int i=0;i subs = new ArrayList(); ReaderUtil.gatherSubReaders(subs, reader); if (subs == null) { @@ -61,7 +61,7 @@ } } - private SlowMultiReaderWrapper(IndexReader other) { + private SlowMultiReaderWrapper(IndexReader other) throws IOException { super(other); } @@ -71,7 +71,7 @@ } @Override - public Bits getDeletedDocs() throws IOException { + public Bits getDeletedDocs() { return MultiFields.getDeletedDocs(in); } Index: lucene/contrib/instantiated/src/test/org/apache/lucene/store/instantiated/TestIndicesEquals.java =================================================================== --- lucene/contrib/instantiated/src/test/org/apache/lucene/store/instantiated/TestIndicesEquals.java (revision 985485) +++ lucene/contrib/instantiated/src/test/org/apache/lucene/store/instantiated/TestIndicesEquals.java (working copy) @@ -31,7 +31,6 @@ import org.apache.lucene.document.Field; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexWriter; -import org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.index.Payload; import org.apache.lucene.index.Term; import org.apache.lucene.index.DocsEnum; @@ -46,6 +45,7 @@ import org.apache.lucene.util.AttributeImpl; import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.util.BytesRef; +import org.apache.lucene.util.Bits; /** * Asserts equality of content and behaviour of two index readers. @@ -303,8 +303,14 @@ assertEquals(air.numDocs(), tir.numDocs()); assertEquals(air.numDeletedDocs(), tir.numDeletedDocs()); - for (int d =0; d