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 + ")";
}
}