diff --git a/lucene/src/java/org/apache/lucene/index/SegmentCoreReaders.java b/lucene/src/java/org/apache/lucene/index/SegmentCoreReaders.java new file mode 100644 index 00000000000..af64cae7fb6 --- /dev/null +++ b/lucene/src/java/org/apache/lucene/index/SegmentCoreReaders.java @@ -0,0 +1,191 @@ +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 java.io.IOException; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.lucene.index.codecs.FieldsProducer; +import org.apache.lucene.store.Directory; + +/** Holds core readers that are shared (unchanged) when + * SegmentReader is cloned or reopened */ +final class SegmentCoreReaders { + + // Counts how many other reader share the core objects + // (freqStream, proxStream, tis, etc.) of this reader; + // when coreRef drops to 0, these core objects may be + // closed. A given instance of SegmentReader may be + // closed, even those it shares core objects with other + // SegmentReaders: + private final AtomicInteger ref = new AtomicInteger(1); + + final String segment; + final FieldInfos fieldInfos; + + final FieldsProducer fields; + + final Directory dir; + final Directory cfsDir; + final int readBufferSize; + final int termsIndexDivisor; + + private final SegmentReader owner; + + FieldsReader fieldsReaderOrig; + TermVectorsReader termVectorsReaderOrig; + CompoundFileReader cfsReader; + CompoundFileReader storeCFSReader; + + SegmentCoreReaders(SegmentReader owner, Directory dir, SegmentInfo si, int readBufferSize, int termsIndexDivisor) throws IOException { + + if (termsIndexDivisor == 0) { + throw new IllegalArgumentException("indexDivisor must be < 0 (don't load terms index) or greater than 0 (got 0)"); + } + + segment = si.name; + final SegmentCodecs segmentCodecs = si.getSegmentCodecs(); + this.readBufferSize = readBufferSize; + this.dir = dir; + + boolean success = false; + + try { + Directory dir0 = dir; + if (si.getUseCompoundFile()) { + cfsReader = new CompoundFileReader(dir, IndexFileNames.segmentFileName(segment, "", IndexFileNames.COMPOUND_FILE_EXTENSION), readBufferSize); + dir0 = cfsReader; + } + cfsDir = dir0; + si.loadFieldInfos(cfsDir, false); // prevent opening the CFS to load fieldInfos + fieldInfos = si.getFieldInfos(); + + this.termsIndexDivisor = termsIndexDivisor; + + // Ask codec for its Fields + fields = segmentCodecs.codec().fieldsProducer(new SegmentReadState(cfsDir, si, fieldInfos, readBufferSize, termsIndexDivisor)); + assert fields != null; + + success = true; + } finally { + if (!success) { + decRef(); + } + } + + // Must assign this at the end -- if we hit an + // exception above core, we don't want to attempt to + // purge the FieldCache (will hit NPE because core is + // not assigned yet). + this.owner = owner; + } + + synchronized TermVectorsReader getTermVectorsReaderOrig() { + return termVectorsReaderOrig; + } + + synchronized FieldsReader getFieldsReaderOrig() { + return fieldsReaderOrig; + } + + synchronized void incRef() { + ref.incrementAndGet(); + } + + synchronized Directory getCFSReader() { + return cfsReader; + } + + synchronized void decRef() throws IOException { + + if (ref.decrementAndGet() == 0) { + + if (fields != null) { + fields.close(); + } + + if (termVectorsReaderOrig != null) { + termVectorsReaderOrig.close(); + } + + if (fieldsReaderOrig != null) { + fieldsReaderOrig.close(); + } + + if (cfsReader != null) { + cfsReader.close(); + } + + if (storeCFSReader != null) { + storeCFSReader.close(); + } + + // Now, notify any ReaderFinished listeners: + if (owner != null) { + owner.notifyReaderFinishedListeners(); + } + } + } + + synchronized void openDocStores(SegmentInfo si) throws IOException { + + assert si.name.equals(segment); + + if (fieldsReaderOrig == null) { + final Directory storeDir; + if (si.getDocStoreOffset() != -1) { + if (si.getDocStoreIsCompoundFile()) { + assert storeCFSReader == null; + storeCFSReader = new CompoundFileReader(dir, + IndexFileNames.segmentFileName(si.getDocStoreSegment(), "", IndexFileNames.COMPOUND_FILE_STORE_EXTENSION), + readBufferSize); + storeDir = storeCFSReader; + assert storeDir != null; + } else { + storeDir = dir; + assert storeDir != null; + } + } else if (si.getUseCompoundFile()) { + // In some cases, we were originally opened when CFS + // was not used, but then we are asked to open doc + // stores after the segment has switched to CFS + if (cfsReader == null) { + cfsReader = new CompoundFileReader(dir, IndexFileNames.segmentFileName(segment, "", IndexFileNames.COMPOUND_FILE_EXTENSION), readBufferSize); + } + storeDir = cfsReader; + assert storeDir != null; + } else { + storeDir = dir; + assert storeDir != null; + } + + final String storesSegment = si.getDocStoreSegment(); + fieldsReaderOrig = new FieldsReader(storeDir, storesSegment, fieldInfos, readBufferSize, + si.getDocStoreOffset(), si.docCount); + + // Verify two sources of "maxDoc" agree: + if (si.getDocStoreOffset() == -1 && fieldsReaderOrig.size() != si.docCount) { + throw new CorruptIndexException("doc counts differ for segment " + segment + ": fieldsReader shows " + fieldsReaderOrig.size() + " but segmentInfo shows " + si.docCount); + } + + if (si.getHasVectors()) { // open term vector files only as needed + termVectorsReaderOrig = new TermVectorsReader(storeDir, storesSegment, fieldInfos, readBufferSize, si.getDocStoreOffset(), si.docCount); + } + } + } +} diff --git a/lucene/src/java/org/apache/lucene/index/SegmentReader.java b/lucene/src/java/org/apache/lucene/index/SegmentReader.java index 1bfe13b8a88..47d4cc62c66 100644 --- a/lucene/src/java/org/apache/lucene/index/SegmentReader.java +++ b/lucene/src/java/org/apache/lucene/index/SegmentReader.java @@ -29,7 +29,6 @@ import java.util.concurrent.atomic.AtomicInteger; import org.apache.lucene.document.Document; import org.apache.lucene.document.FieldSelector; -import org.apache.lucene.index.codecs.FieldsProducer; import org.apache.lucene.store.BufferedIndexInput; import org.apache.lucene.store.Directory; import org.apache.lucene.store.IndexInput; @@ -70,174 +69,7 @@ public class SegmentReader extends IndexReader implements Cloneable { IndexInput singleNormStream; AtomicInteger singleNormRef; - CoreReaders core; - - // Holds core readers that are shared (unchanged) when - // SegmentReader is cloned or reopened - static final class CoreReaders { - - // Counts how many other reader share the core objects - // (freqStream, proxStream, tis, etc.) of this reader; - // when coreRef drops to 0, these core objects may be - // closed. A given instance of SegmentReader may be - // closed, even those it shares core objects with other - // SegmentReaders: - private final AtomicInteger ref = new AtomicInteger(1); - - final String segment; - final FieldInfos fieldInfos; - - final FieldsProducer fields; - - final Directory dir; - final Directory cfsDir; - final int readBufferSize; - final int termsIndexDivisor; - - private final SegmentReader origInstance; - - FieldsReader fieldsReaderOrig; - TermVectorsReader termVectorsReaderOrig; - CompoundFileReader cfsReader; - CompoundFileReader storeCFSReader; - - CoreReaders(SegmentReader origInstance, Directory dir, SegmentInfo si, int readBufferSize, int termsIndexDivisor) throws IOException { - - if (termsIndexDivisor == 0) { - throw new IllegalArgumentException("indexDivisor must be < 0 (don't load terms index) or greater than 0 (got 0)"); - } - - segment = si.name; - final SegmentCodecs segmentCodecs = si.getSegmentCodecs(); - this.readBufferSize = readBufferSize; - this.dir = dir; - - boolean success = false; - - try { - Directory dir0 = dir; - if (si.getUseCompoundFile()) { - cfsReader = new CompoundFileReader(dir, IndexFileNames.segmentFileName(segment, "", IndexFileNames.COMPOUND_FILE_EXTENSION), readBufferSize); - dir0 = cfsReader; - } - cfsDir = dir0; - si.loadFieldInfos(cfsDir, false); // prevent opening the CFS to load fieldInfos - fieldInfos = si.getFieldInfos(); - - this.termsIndexDivisor = termsIndexDivisor; - - // Ask codec for its Fields - fields = segmentCodecs.codec().fieldsProducer(new SegmentReadState(cfsDir, si, fieldInfos, readBufferSize, termsIndexDivisor)); - assert fields != null; - - success = true; - } finally { - if (!success) { - decRef(); - } - } - - // Must assign this at the end -- if we hit an - // exception above core, we don't want to attempt to - // purge the FieldCache (will hit NPE because core is - // not assigned yet). - this.origInstance = origInstance; - } - - synchronized TermVectorsReader getTermVectorsReaderOrig() { - return termVectorsReaderOrig; - } - - synchronized FieldsReader getFieldsReaderOrig() { - return fieldsReaderOrig; - } - - synchronized void incRef() { - ref.incrementAndGet(); - } - - synchronized Directory getCFSReader() { - return cfsReader; - } - - synchronized void decRef() throws IOException { - - if (ref.decrementAndGet() == 0) { - - if (fields != null) { - fields.close(); - } - - if (termVectorsReaderOrig != null) { - termVectorsReaderOrig.close(); - } - - if (fieldsReaderOrig != null) { - fieldsReaderOrig.close(); - } - - if (cfsReader != null) { - cfsReader.close(); - } - - if (storeCFSReader != null) { - storeCFSReader.close(); - } - - // Now, notify any ReaderFinished listeners: - if (origInstance != null) { - origInstance.notifyReaderFinishedListeners(); - } - } - } - - synchronized void openDocStores(SegmentInfo si) throws IOException { - - assert si.name.equals(segment); - - if (fieldsReaderOrig == null) { - final Directory storeDir; - if (si.getDocStoreOffset() != -1) { - if (si.getDocStoreIsCompoundFile()) { - assert storeCFSReader == null; - storeCFSReader = new CompoundFileReader(dir, - IndexFileNames.segmentFileName(si.getDocStoreSegment(), "", IndexFileNames.COMPOUND_FILE_STORE_EXTENSION), - readBufferSize); - storeDir = storeCFSReader; - assert storeDir != null; - } else { - storeDir = dir; - assert storeDir != null; - } - } else if (si.getUseCompoundFile()) { - // In some cases, we were originally opened when CFS - // was not used, but then we are asked to open doc - // stores after the segment has switched to CFS - if (cfsReader == null) { - cfsReader = new CompoundFileReader(dir, IndexFileNames.segmentFileName(segment, "", IndexFileNames.COMPOUND_FILE_EXTENSION), readBufferSize); - } - storeDir = cfsReader; - assert storeDir != null; - } else { - storeDir = dir; - assert storeDir != null; - } - - final String storesSegment = si.getDocStoreSegment(); - fieldsReaderOrig = new FieldsReader(storeDir, storesSegment, fieldInfos, readBufferSize, - si.getDocStoreOffset(), si.docCount); - - // Verify two sources of "maxDoc" agree: - if (si.getDocStoreOffset() == -1 && fieldsReaderOrig.size() != si.docCount) { - throw new CorruptIndexException("doc counts differ for segment " + segment + ": fieldsReader shows " + fieldsReaderOrig.size() + " but segmentInfo shows " + si.docCount); - } - - if (si.getHasVectors()) { // open term vector files only as needed - termVectorsReaderOrig = new TermVectorsReader(storeDir, storesSegment, fieldInfos, readBufferSize, si.getDocStoreOffset(), si.docCount); - } - } - } - } + SegmentCoreReaders core; /** * Sets the initial value @@ -248,8 +80,6 @@ public class SegmentReader extends IndexReader implements Cloneable { return (FieldsReader) core.getFieldsReaderOrig().clone(); } } - - Map norms = new HashMap(); @@ -281,7 +111,7 @@ public class SegmentReader extends IndexReader implements Cloneable { boolean success = false; try { - instance.core = new CoreReaders(instance, dir, si, readBufferSize, termInfosIndexDivisor); + instance.core = new SegmentCoreReaders(instance, dir, si, readBufferSize, termInfosIndexDivisor); if (doOpenStores) { instance.core.openDocStores(si); }