org.apache.lucene.store.ConfigurableBufferedIndexInput Maven / Gradle / Ivy
package org.apache.lucene.store;
import java.io.IOException;
/**
* A simple base class that performs index input memory based buffering. Allows the buffer size to be
* configurable.
*
* @author kimchy
*/
// NEED TO BE MONITORED AGAINST LUCENE (EXATCLY THE SAME)
public abstract class ConfigurableBufferedIndexInput extends IndexInput {
/** Default buffer size */
public static final int BUFFER_SIZE = 1024;
protected int bufferSize = BUFFER_SIZE;
protected byte[] buffer;
protected long bufferStart = 0; // position in file of buffer
protected int bufferLength = 0; // end of valid bytes
protected int bufferPosition = 0; // next byte to read
public byte readByte() throws IOException {
if (bufferPosition >= bufferLength)
refill();
return buffer[bufferPosition++];
}
public ConfigurableBufferedIndexInput() {}
/** Inits BufferedIndexInput with a specific bufferSize */
public ConfigurableBufferedIndexInput(int bufferSize) {
checkBufferSize(bufferSize);
this.bufferSize = bufferSize;
}
/** Change the buffer size used by this IndexInput */
public void setBufferSize(int newSize) {
assert buffer == null || bufferSize == buffer.length;
if (newSize != bufferSize) {
checkBufferSize(newSize);
bufferSize = newSize;
if (buffer != null) {
// Resize the existing buffer and carefully save as
// many bytes as possible starting from the current
// bufferPosition
byte[] newBuffer = new byte[newSize];
final int leftInBuffer = bufferLength-bufferPosition;
final int numToCopy;
if (leftInBuffer > newSize)
numToCopy = newSize;
else
numToCopy = leftInBuffer;
System.arraycopy(buffer, bufferPosition, newBuffer, 0, numToCopy);
bufferStart += bufferPosition;
bufferPosition = 0;
bufferLength = numToCopy;
buffer = newBuffer;
}
}
}
/** Returns buffer size. @see #setBufferSize */
public int getBufferSize() {
return bufferSize;
}
private void checkBufferSize(int bufferSize) {
if (bufferSize <= 0)
throw new IllegalArgumentException("bufferSize must be greater than 0 (got " + bufferSize + ")");
}
public void readBytes(byte[] b, int offset, int len) throws IOException {
if(len <= (bufferLength-bufferPosition)){
// the buffer contains enough data to satistfy this request
if(len>0) // to allow b to be null if len is 0...
System.arraycopy(buffer, bufferPosition, b, offset, len);
bufferPosition+=len;
} else {
// the buffer does not have enough data. First serve all we've got.
int available = bufferLength - bufferPosition;
if(available > 0){
System.arraycopy(buffer, bufferPosition, b, offset, available);
offset += available;
len -= available;
bufferPosition += available;
}
// and now, read the remaining 'len' bytes:
if(len length())
throw new IOException("read past EOF");
readInternal(b, offset, len);
bufferStart = after;
bufferPosition = 0;
bufferLength = 0; // trigger refill() on read
}
}
}
protected void refill() throws IOException {
long start = bufferStart + bufferPosition;
long end = start + bufferSize;
if (end > length()) // don't read past EOF
end = length();
bufferLength = (int)(end - start);
if (bufferLength <= 0)
throw new IOException("read past EOF");
if (buffer == null) {
buffer = new byte[bufferSize]; // allocate buffer lazily
seekInternal(bufferStart);
}
readInternal(buffer, 0, bufferLength);
bufferStart = start;
bufferPosition = 0;
}
/** Expert: implements buffer refill. Reads bytes from the current position
* in the input.
* @param b the array to read bytes into
* @param offset the offset in the array to start storing bytes
* @param length the number of bytes to read
*/
protected abstract void readInternal(byte[] b, int offset, int length)
throws IOException;
public long getFilePointer() { return bufferStart + bufferPosition; }
public void seek(long pos) throws IOException {
if (pos >= bufferStart && pos < (bufferStart + bufferLength))
bufferPosition = (int)(pos - bufferStart); // seek within buffer
else {
bufferStart = pos;
bufferPosition = 0;
bufferLength = 0; // trigger refill() on read()
seekInternal(pos);
}
}
/** Expert: implements seek. Sets current position in this file, where the
* next {@link #readInternal(byte[],int,int)} will occur.
* @see #readInternal(byte[],int,int)
*/
protected abstract void seekInternal(long pos) throws IOException;
public Object clone() {
ConfigurableBufferedIndexInput clone = (ConfigurableBufferedIndexInput)super.clone();
clone.buffer = null;
clone.bufferLength = 0;
clone.bufferPosition = 0;
clone.bufferStart = getFilePointer();
return clone;
}
}