blob: ac054f7d8f47f18bd6f883ef8e7ed23b1c49f0ac [file] [log] [blame]
package org.apache.lucene.index;
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2001 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" and
* "Apache Lucene" must not be used to endorse or promote products
* derived from this software without prior written permission. For
* written permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* "Apache Lucene", nor may "Apache" appear in their name, without
* prior written permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
import java.io.IOException;
import java.util.Hashtable;
import java.util.Enumeration;
import java.util.Vector;
import org.apache.lucene.util.BitVector;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.Lock;
import org.apache.lucene.store.InputStream;
import org.apache.lucene.document.Document;
final class SegmentReader extends IndexReader {
Directory directory;
private boolean closeDirectory = false;
private String segment;
FieldInfos fieldInfos;
private FieldsReader fieldsReader;
TermInfosReader tis;
BitVector deletedDocs = null;
private boolean deletedDocsDirty = false;
private InputStream freqStream;
private InputStream proxStream;
private static class Norm {
public Norm(InputStream in) { this.in = in; }
public InputStream in;
public byte[] bytes;
}
private Hashtable norms = new Hashtable();
SegmentReader(SegmentInfo si, boolean closeDir)
throws IOException {
this(si);
closeDirectory = closeDir;
}
SegmentReader(SegmentInfo si)
throws IOException {
directory = si.dir;
segment = si.name;
fieldInfos = new FieldInfos(directory, segment + ".fnm");
fieldsReader = new FieldsReader(directory, segment, fieldInfos);
tis = new TermInfosReader(directory, segment, fieldInfos);
if (hasDeletions(si))
deletedDocs = new BitVector(directory, segment + ".del");
// 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
freqStream = directory.openFile(segment + ".frq");
proxStream = directory.openFile(segment + ".prx");
openNorms();
}
public final synchronized void close() throws IOException {
if (deletedDocsDirty) {
synchronized (directory) { // in- & inter-process sync
new Lock.With(directory.makeLock("commit.lock")) {
public Object doBody() throws IOException {
deletedDocs.write(directory, segment + ".tmp");
directory.renameFile(segment + ".tmp", segment + ".del");
return null;
}
}.run();
}
deletedDocsDirty = false;
}
fieldsReader.close();
tis.close();
if (freqStream != null)
freqStream.close();
if (proxStream != null)
proxStream.close();
closeNorms();
if (closeDirectory)
directory.close();
}
final static boolean hasDeletions(SegmentInfo si) throws IOException {
return si.dir.fileExists(si.name + ".del");
}
public final synchronized void delete(int docNum) throws IOException {
if (deletedDocs == null)
deletedDocs = new BitVector(maxDoc());
deletedDocsDirty = true;
deletedDocs.set(docNum);
}
final Vector files() throws IOException {
Vector files = new Vector(16);
files.addElement(segment + ".fnm");
files.addElement(segment + ".fdx");
files.addElement(segment + ".fdt");
files.addElement(segment + ".tii");
files.addElement(segment + ".tis");
files.addElement(segment + ".frq");
files.addElement(segment + ".prx");
if (directory.fileExists(segment + ".del"))
files.addElement(segment + ".del");
for (int i = 0; i < fieldInfos.size(); i++) {
FieldInfo fi = fieldInfos.fieldInfo(i);
if (fi.isIndexed)
files.addElement(segment + ".f" + i);
}
return files;
}
public final TermEnum terms() throws IOException {
return tis.terms();
}
public final TermEnum terms(Term t) throws IOException {
return tis.terms(t);
}
public final synchronized Document document(int n) throws IOException {
if (isDeleted(n))
throw new IllegalArgumentException
("attempt to access a deleted document");
return fieldsReader.doc(n);
}
public final synchronized boolean isDeleted(int n) {
return (deletedDocs != null && deletedDocs.get(n));
}
public final TermDocs termDocs(Term t) throws IOException {
TermInfo ti = tis.get(t);
if (ti != null)
return new SegmentTermDocs(this, ti);
else
return null;
}
final InputStream getFreqStream () {
return (InputStream)freqStream.clone();
}
public final TermPositions termPositions(Term t) throws IOException {
TermInfo ti = tis.get(t);
if (ti != null)
return new SegmentTermPositions(this, ti);
else
return null;
}
final InputStream getProxStream () {
return (InputStream)proxStream.clone();
}
public final int docFreq(Term t) throws IOException {
TermInfo ti = tis.get(t);
if (ti != null)
return ti.docFreq;
else
return 0;
}
public final int numDocs() {
int n = maxDoc();
if (deletedDocs != null)
n -= deletedDocs.count();
return n;
}
public final int maxDoc() {
return fieldsReader.size();
}
public final byte[] norms(String field) throws IOException {
Norm norm = (Norm)norms.get(field);
if (norm == null)
return null;
if (norm.bytes == null) {
byte[] bytes = new byte[maxDoc()];
norms(field, bytes, 0);
norm.bytes = bytes;
}
return norm.bytes;
}
final void norms(String field, byte[] bytes, int offset) throws IOException {
InputStream normStream = normStream(field);
if (normStream == null)
return; // use zeros in array
try {
normStream.readBytes(bytes, offset, maxDoc());
} finally {
normStream.close();
}
}
final InputStream normStream(String field) throws IOException {
Norm norm = (Norm)norms.get(field);
if (norm == null)
return null;
InputStream result = (InputStream)norm.in.clone();
result.seek(0);
return result;
}
private final void openNorms() throws IOException {
for (int i = 0; i < fieldInfos.size(); i++) {
FieldInfo fi = fieldInfos.fieldInfo(i);
if (fi.isIndexed)
norms.put(fi.name,
new Norm(directory.openFile(segment + ".f" + fi.number)));
}
}
private final void closeNorms() throws IOException {
synchronized (norms) {
Enumeration enum = norms.elements();
while (enum.hasMoreElements()) {
Norm norm = (Norm)enum.nextElement();
norm.in.close();
}
}
}
}