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.store.Directory; import org.apache.lucene.store.FSDirectory; import org.apache.lucene.store.IndexInput; import org.apache.lucene.util.IOUtils; import org.apache.solr.schema.IndexSchema; import com.alimama.mdrill.buffer.BlockBufferInput; import com.alimama.mdrill.hdfsDirectory.FileSystemDirectory; /** Holds core readers that are shared (unchanged) when * SegmentReader is cloned or reopened */ public class SegmentCoreReaders { public void invertInit(IndexSchema schema, String field, int index){ throw new UnsupportedOperationException(); } // 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 IndexInput freqStream; final IndexInput proxStream; final TermInfosReader tisNoIndex; final Directory dir; final Directory cfsDir; final int readBufferSize; final int termsIndexDivisor; private final SegmentReader owner; TermInfosReader tis; FieldsReader fieldsReaderOrig; TermVectorsReader termVectorsReaderOrig; CompoundFileReader cfsReader; CompoundFileReader storeCFSReader; SegmentCoreReaders(SegmentReader owner, Directory dir, SegmentInfo si, int readBufferSize, int termsIndexDivisor) throws IOException { segment = si.name; 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),IndexFileNames.segmentFileName(segment, IndexFileNames.COMPOUND_FILE_EXTENSION_POS), readBufferSize); dir0 = cfsReader; } cfsDir = dir0; fieldInfos = new FieldInfos(cfsDir, IndexFileNames.segmentFileName(segment, IndexFileNames.FIELD_INFOS_EXTENSION)); this.termsIndexDivisor = termsIndexDivisor; TermInfosReader reader = new TermInfosReader(cfsDir, segment, fieldInfos, readBufferSize, termsIndexDivisor); if (termsIndexDivisor == -1) { tisNoIndex = reader; } else { tis = reader; tisNoIndex = null; } // make sure that all index files have been read or are kept open // so that if an index update removes them we'll still have them String filename=IndexFileNames.segmentFileName(segment, IndexFileNames.FREQ_EXTENSION); if(cfsDir instanceof FSDirectory) { FSDirectory dddir=(FSDirectory)cfsDir; freqStream = new BlockBufferInput.KeyInput(cfsDir.openInput(filename, readBufferSize), cfsDir,filename,cfsDir.getP()); if (fieldInfos.hasProx()) { String fname=IndexFileNames.segmentFileName(segment, IndexFileNames.PROX_EXTENSION); proxStream = BlockBufferInput.MaybeInstance(cfsDir.openInput(fname, readBufferSize), cfsDir,fname,cfsDir.getP()); } else { proxStream = null; } }else if(cfsDir instanceof FileSystemDirectory) { FileSystemDirectory dddir=(FileSystemDirectory)cfsDir; freqStream = new BlockBufferInput.KeyInput(cfsDir.openInput(filename, readBufferSize), cfsDir,filename,cfsDir.getP()); if (fieldInfos.hasProx()) { String fname=IndexFileNames.segmentFileName(segment, IndexFileNames.PROX_EXTENSION); proxStream = BlockBufferInput.MaybeInstance(cfsDir.openInput(fname, readBufferSize),cfsDir,fname,cfsDir.getP()); } else { proxStream = null; } } else{ freqStream=cfsDir.openInput(filename, readBufferSize); if (fieldInfos.hasProx()) { proxStream = cfsDir.openInput(IndexFileNames.segmentFileName(segment, IndexFileNames.PROX_EXTENSION), readBufferSize); } else { proxStream = 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; } public synchronized TermInfosReader getTermsReader() { if (tis != null) { return tis; } else { return tisNoIndex; } } synchronized boolean termsIndexIsLoaded() { return tis != null; } // NOTE: only called from IndexWriter when a near // real-time reader is opened, or applyDeletes is run, // sharing a segment that's still being merged. This // method is not fully thread safe, and relies on the // synchronization in IndexWriter synchronized void loadTermsIndex(SegmentInfo si, int termsIndexDivisor) throws IOException { if (tis == null) { Directory dir0; if (si.getUseCompoundFile()) { // In some cases, we were originally opened when CFS // was not used, but then we are asked to open the // terms reader with index, the segment has switched // to CFS if (cfsReader == null) { cfsReader = new CompoundFileReader(dir, IndexFileNames.segmentFileName(segment, IndexFileNames.COMPOUND_FILE_EXTENSION), IndexFileNames.segmentFileName(segment, IndexFileNames.COMPOUND_FILE_EXTENSION_POS), readBufferSize); } dir0 = cfsReader; } else { dir0 = dir; } tis = new TermInfosReader(dir0, segment, fieldInfos, readBufferSize, termsIndexDivisor); } } synchronized void decRef() throws IOException { if (ref.decrementAndGet() == 0) { IOUtils.close(tis, tisNoIndex, freqStream, proxStream, termVectorsReaderOrig, fieldsReaderOrig, cfsReader, storeCFSReader); tis = null; // 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),IndexFileNames.segmentFileName(si.getDocStoreSegment(), IndexFileNames.COMPOUND_FILE_STORE_EXTENSION_POS), 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), IndexFileNames.segmentFileName(segment, IndexFileNames.COMPOUND_FILE_EXTENSION_POS), readBufferSize); } storeDir = cfsReader; assert storeDir != null; } else { storeDir = dir; assert storeDir != null; } final String storesSegment; if (si.getDocStoreOffset() != -1) { storesSegment = si.getDocStoreSegment(); } else { storesSegment = segment; } 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); } } } @Override public String toString() { return "SegmentCoreReader(owner=" + owner + ")"; } }