X-Git-Url: https://git.mdrn.pl/pylucene.git/blobdiff_plain/a2e61f0c04805cfcb8706176758d1283c7e3a55c..aaeed5504b982cf3545252ab528713250aa33eed:/lucene-java-3.5.0/lucene/src/java/org/apache/lucene/store/BufferedIndexInput.java?ds=sidebyside diff --git a/lucene-java-3.5.0/lucene/src/java/org/apache/lucene/store/BufferedIndexInput.java b/lucene-java-3.5.0/lucene/src/java/org/apache/lucene/store/BufferedIndexInput.java new file mode 100644 index 0000000..9125ba4 --- /dev/null +++ b/lucene-java-3.5.0/lucene/src/java/org/apache/lucene/store/BufferedIndexInput.java @@ -0,0 +1,310 @@ +package org.apache.lucene.store; + +/** + * 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; + +/** Base implementation class for buffered {@link IndexInput}. */ +public abstract class BufferedIndexInput extends IndexInput { + + /** Default buffer size */ + public static final int BUFFER_SIZE = 1024; + + private int bufferSize = BUFFER_SIZE; + + protected byte[] buffer; + + private long bufferStart = 0; // position in file of buffer + private int bufferLength = 0; // end of valid bytes + private int bufferPosition = 0; // next byte to read + + @Override + public byte readByte() throws IOException { + if (bufferPosition >= bufferLength) + refill(); + return buffer[bufferPosition++]; + } + + /** @deprecated please pass resourceDesc */ + @Deprecated + public BufferedIndexInput() { + this("anonymous BuffereIndexInput"); + } + + public BufferedIndexInput(String resourceDesc) { + this(resourceDesc, BUFFER_SIZE); + } + + /** Inits BufferedIndexInput with a specific bufferSize + * @deprecated please pass resourceDesc */ + @Deprecated + public BufferedIndexInput(int bufferSize) { + this("anonymous BuffereIndexInput", bufferSize); + } + + /** Inits BufferedIndexInput with a specific bufferSize */ + public BufferedIndexInput(String resourceDesc, int bufferSize) { + super(resourceDesc); + checkBufferSize(bufferSize); + this.bufferSize = bufferSize; + } + + /** Change the buffer size used by this IndexInput */ + public void setBufferSize(int newSize) { + assert buffer == null || bufferSize == buffer.length: "buffer=" + buffer + " bufferSize=" + bufferSize + " buffer.length=" + (buffer != null ? buffer.length : 0); + 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; + newBuffer(newBuffer); + } + } + } + + protected void newBuffer(byte[] newBuffer) { + // Subclasses can do something here + 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 + ")"); + } + + @Override + public void readBytes(byte[] b, int offset, int len) throws IOException { + readBytes(b, offset, len, true); + } + + @Override + public void readBytes(byte[] b, int offset, int len, boolean useBuffer) throws IOException { + + if(len <= (bufferLength-bufferPosition)){ + // the buffer contains enough data to satisfy 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 (useBuffer && len length()) + throw new IOException("read past EOF"); + readInternal(b, offset, len); + bufferStart = after; + bufferPosition = 0; + bufferLength = 0; // trigger refill() on read + } + } + } + + @Override + public int readInt() throws IOException { + if (4 <= (bufferLength-bufferPosition)) { + return ((buffer[bufferPosition++] & 0xFF) << 24) | ((buffer[bufferPosition++] & 0xFF) << 16) + | ((buffer[bufferPosition++] & 0xFF) << 8) | (buffer[bufferPosition++] & 0xFF); + } else { + return super.readInt(); + } + } + + @Override + public long readLong() throws IOException { + if (8 <= (bufferLength-bufferPosition)) { + final int i1 = ((buffer[bufferPosition++] & 0xff) << 24) | ((buffer[bufferPosition++] & 0xff) << 16) | + ((buffer[bufferPosition++] & 0xff) << 8) | (buffer[bufferPosition++] & 0xff); + final int i2 = ((buffer[bufferPosition++] & 0xff) << 24) | ((buffer[bufferPosition++] & 0xff) << 16) | + ((buffer[bufferPosition++] & 0xff) << 8) | (buffer[bufferPosition++] & 0xff); + return (((long)i1) << 32) | (i2 & 0xFFFFFFFFL); + } else { + return super.readLong(); + } + } + + @Override + public int readVInt() throws IOException { + if (5 <= (bufferLength-bufferPosition)) { + byte b = buffer[bufferPosition++]; + int i = b & 0x7F; + for (int shift = 7; (b & 0x80) != 0; shift += 7) { + b = buffer[bufferPosition++]; + i |= (b & 0x7F) << shift; + } + return i; + } else { + return super.readVInt(); + } + } + + @Override + public long readVLong() throws IOException { + if (9 <= bufferLength-bufferPosition) { + byte b = buffer[bufferPosition++]; + long i = b & 0x7F; + for (int shift = 7; (b & 0x80) != 0; shift += 7) { + b = buffer[bufferPosition++]; + i |= (b & 0x7FL) << shift; + } + return i; + } else { + return super.readVLong(); + } + } + + private void refill() throws IOException { + long start = bufferStart + bufferPosition; + long end = start + bufferSize; + if (end > length()) // don't read past EOF + end = length(); + int newLength = (int)(end - start); + if (newLength <= 0) + throw new IOException("read past EOF"); + + if (buffer == null) { + newBuffer(new byte[bufferSize]); // allocate buffer lazily + seekInternal(bufferStart); + } + readInternal(buffer, 0, newLength); + bufferLength = newLength; + 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; + + @Override + public long getFilePointer() { return bufferStart + bufferPosition; } + + @Override + 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; + + @Override + public Object clone() { + BufferedIndexInput clone = (BufferedIndexInput)super.clone(); + + clone.buffer = null; + clone.bufferLength = 0; + clone.bufferPosition = 0; + clone.bufferStart = getFilePointer(); + + return clone; + } + + /** + * Flushes the in-memory bufer to the given output, copying at most + * numBytes. + *

+ * NOTE: this method does not refill the buffer, however it does + * advance the buffer position. + * + * @return the number of bytes actually flushed from the in-memory buffer. + */ + protected int flushBuffer(IndexOutput out, long numBytes) throws IOException { + int toCopy = bufferLength - bufferPosition; + if (toCopy > numBytes) { + toCopy = (int) numBytes; + } + if (toCopy > 0) { + out.writeBytes(buffer, bufferPosition, toCopy); + bufferPosition += toCopy; + } + return toCopy; + } + + @Override + public void copyBytes(IndexOutput out, long numBytes) throws IOException { + assert numBytes >= 0: "numBytes=" + numBytes; + + while (numBytes > 0) { + if (bufferLength == bufferPosition) { + refill(); + } + numBytes -= flushBuffer(out, numBytes); + } + } + +}