blob: 10f4a375f2ca12ce8849b98f40066343ac7f8780 [file] [log] [blame]
/*
* 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.
*/
package org.apache.lucene.store;
import java.io.Closeable;
import java.io.IOException;
/**
* Abstract base class for input from a file in a {@link Directory}. A random-access input stream.
* Used for all Lucene index input operations.
*
* <p>{@code IndexInput} may only be used from one thread, because it is not thread safe (it keeps
* internal state like file position). To allow multithreaded use, every {@code IndexInput} instance
* must be cloned before it is used in another thread. Subclasses must therefore implement {@link
* #clone()}, returning a new {@code IndexInput} which operates on the same underlying resource, but
* positioned independently.
*
* <p><b>Warning:</b> Lucene never closes cloned {@code IndexInput}s, it will only call {@link
* #close()} on the original object.
*
* <p>If you access the cloned IndexInput after closing the original object, any <code>readXXX
* </code> methods will throw {@link AlreadyClosedException}.
*
* @see Directory
*/
public abstract class IndexInput extends DataInput implements Cloneable, Closeable {
private final String resourceDescription;
/**
* resourceDescription should be a non-null, opaque string describing this resource; it's returned
* from {@link #toString}.
*/
protected IndexInput(String resourceDescription) {
if (resourceDescription == null) {
throw new IllegalArgumentException("resourceDescription must not be null");
}
this.resourceDescription = resourceDescription;
}
/** Closes the stream to further operations. */
@Override
public abstract void close() throws IOException;
/**
* Returns the current position in this file, where the next read will occur.
*
* @see #seek(long)
*/
public abstract long getFilePointer();
/**
* Sets current position in this file, where the next read will occur. If this is beyond the end
* of the file then this will throw {@code EOFException} and then the stream is in an undetermined
* state.
*
* @see #getFilePointer()
*/
public abstract void seek(long pos) throws IOException;
/**
* {@inheritDoc}
*
* <p>Behavior is functionally equivalent to seeking to <code>getFilePointer() + numBytes</code>.
*
* @see #getFilePointer()
* @see #seek(long)
*/
@Override
public void skipBytes(long numBytes) throws IOException {
if (numBytes < 0) {
throw new IllegalArgumentException("numBytes must be >= 0, got " + numBytes);
}
final long skipTo = getFilePointer() + numBytes;
seek(skipTo);
}
/** The number of bytes in the file. */
public abstract long length();
@Override
public String toString() {
return resourceDescription;
}
/**
* {@inheritDoc}
*
* <p><b>Warning:</b> Lucene never closes cloned {@code IndexInput}s, it will only call {@link
* #close()} on the original object.
*
* <p>If you access the cloned IndexInput after closing the original object, any <code>readXXX
* </code> methods will throw {@link AlreadyClosedException}.
*
* <p>This method is NOT thread safe, so if the current {@code IndexInput} is being used by one
* thread while {@code clone} is called by another, disaster could strike.
*/
@Override
public IndexInput clone() {
return (IndexInput) super.clone();
}
/**
* Creates a slice of this index input, with the given description, offset, and length. The slice
* is sought to the beginning.
*/
public abstract IndexInput slice(String sliceDescription, long offset, long length)
throws IOException;
/**
* Subclasses call this to get the String for resourceDescription of a slice of this {@code
* IndexInput}.
*/
protected String getFullSliceDescription(String sliceDescription) {
if (sliceDescription == null) {
// Clones pass null sliceDescription:
return toString();
} else {
return toString() + " [slice=" + sliceDescription + "]";
}
}
/**
* Creates a random-access slice of this index input, with the given offset and length.
*
* <p>The default implementation calls {@link #slice}, and it doesn't support random access, it
* implements absolute reads as seek+read.
*/
public RandomAccessInput randomAccessSlice(long offset, long length) throws IOException {
final IndexInput slice = slice("randomaccess", offset, length);
if (slice instanceof RandomAccessInput) {
// slice() already supports random access
return (RandomAccessInput) slice;
} else {
// return default impl
return new RandomAccessInput() {
@Override
public byte readByte(long pos) throws IOException {
slice.seek(pos);
return slice.readByte();
}
@Override
public short readShort(long pos) throws IOException {
slice.seek(pos);
return slice.readShort();
}
@Override
public int readInt(long pos) throws IOException {
slice.seek(pos);
return slice.readInt();
}
@Override
public long readLong(long pos) throws IOException {
slice.seek(pos);
return slice.readLong();
}
@Override
public String toString() {
return "RandomAccessInput(" + IndexInput.this.toString() + ")";
}
};
}
}
}