001: package org.apache.lucene.store;
002:
003: import java.io.IOException;
004:
005: /**
006: * A simple base class that performs index input memory based buffering. Allows the buffer size to be
007: * configurable.
008: *
009: * @author kimchy
010: */
011: // NEED TO BE MONITORED AGAINST LUCENE (EXATCLY THE SAME)
012: public abstract class ConfigurableBufferedIndexInput extends IndexInput {
013:
014: /** Default buffer size */
015: public static final int BUFFER_SIZE = 1024;
016:
017: protected int bufferSize = BUFFER_SIZE;
018:
019: protected byte[] buffer;
020:
021: protected long bufferStart = 0; // position in file of buffer
022: protected int bufferLength = 0; // end of valid bytes
023: protected int bufferPosition = 0; // next byte to read
024:
025: public byte readByte() throws IOException {
026: if (bufferPosition >= bufferLength)
027: refill();
028: return buffer[bufferPosition++];
029: }
030:
031: public ConfigurableBufferedIndexInput() {
032: }
033:
034: /** Inits BufferedIndexInput with a specific bufferSize */
035: public ConfigurableBufferedIndexInput(int bufferSize) {
036: checkBufferSize(bufferSize);
037: this .bufferSize = bufferSize;
038: }
039:
040: /** Change the buffer size used by this IndexInput */
041: public void setBufferSize(int newSize) {
042: assert buffer == null || bufferSize == buffer.length;
043: if (newSize != bufferSize) {
044: checkBufferSize(newSize);
045: bufferSize = newSize;
046: if (buffer != null) {
047: // Resize the existing buffer and carefully save as
048: // many bytes as possible starting from the current
049: // bufferPosition
050: byte[] newBuffer = new byte[newSize];
051: final int leftInBuffer = bufferLength - bufferPosition;
052: final int numToCopy;
053: if (leftInBuffer > newSize)
054: numToCopy = newSize;
055: else
056: numToCopy = leftInBuffer;
057: System.arraycopy(buffer, bufferPosition, newBuffer, 0,
058: numToCopy);
059: bufferStart += bufferPosition;
060: bufferPosition = 0;
061: bufferLength = numToCopy;
062: buffer = newBuffer;
063: }
064: }
065: }
066:
067: /** Returns buffer size. @see #setBufferSize */
068: public int getBufferSize() {
069: return bufferSize;
070: }
071:
072: private void checkBufferSize(int bufferSize) {
073: if (bufferSize <= 0)
074: throw new IllegalArgumentException(
075: "bufferSize must be greater than 0 (got "
076: + bufferSize + ")");
077: }
078:
079: public void readBytes(byte[] b, int offset, int len)
080: throws IOException {
081: if (len <= (bufferLength - bufferPosition)) {
082: // the buffer contains enough data to satistfy this request
083: if (len > 0) // to allow b to be null if len is 0...
084: System
085: .arraycopy(buffer, bufferPosition, b, offset,
086: len);
087: bufferPosition += len;
088: } else {
089: // the buffer does not have enough data. First serve all we've got.
090: int available = bufferLength - bufferPosition;
091: if (available > 0) {
092: System.arraycopy(buffer, bufferPosition, b, offset,
093: available);
094: offset += available;
095: len -= available;
096: bufferPosition += available;
097: }
098: // and now, read the remaining 'len' bytes:
099: if (len < bufferSize) {
100: // If the amount left to read is small enough, do it in the usual
101: // buffered way: fill the buffer and copy from it:
102: refill();
103: if (bufferLength < len) {
104: // Throw an exception when refill() could not read len bytes:
105: System
106: .arraycopy(buffer, 0, b, offset,
107: bufferLength);
108: throw new IOException("read past EOF");
109: } else {
110: System.arraycopy(buffer, 0, b, offset, len);
111: bufferPosition = len;
112: }
113: } else {
114: // The amount left to read is larger than the buffer - there's no
115: // performance reason not to read it all at once. Note that unlike
116: // the previous code of this function, there is no need to do a seek
117: // here, because there's no need to reread what we had in the buffer.
118: long after = bufferStart + bufferPosition + len;
119: if (after > length())
120: throw new IOException("read past EOF");
121: readInternal(b, offset, len);
122: bufferStart = after;
123: bufferPosition = 0;
124: bufferLength = 0; // trigger refill() on read
125: }
126: }
127: }
128:
129: protected void refill() throws IOException {
130: long start = bufferStart + bufferPosition;
131: long end = start + bufferSize;
132: if (end > length()) // don't read past EOF
133: end = length();
134: bufferLength = (int) (end - start);
135: if (bufferLength <= 0)
136: throw new IOException("read past EOF");
137:
138: if (buffer == null) {
139: buffer = new byte[bufferSize]; // allocate buffer lazily
140: seekInternal(bufferStart);
141: }
142: readInternal(buffer, 0, bufferLength);
143:
144: bufferStart = start;
145: bufferPosition = 0;
146: }
147:
148: /** Expert: implements buffer refill. Reads bytes from the current position
149: * in the input.
150: * @param b the array to read bytes into
151: * @param offset the offset in the array to start storing bytes
152: * @param length the number of bytes to read
153: */
154: protected abstract void readInternal(byte[] b, int offset,
155: int length) throws IOException;
156:
157: public long getFilePointer() {
158: return bufferStart + bufferPosition;
159: }
160:
161: public void seek(long pos) throws IOException {
162: if (pos >= bufferStart && pos < (bufferStart + bufferLength))
163: bufferPosition = (int) (pos - bufferStart); // seek within buffer
164: else {
165: bufferStart = pos;
166: bufferPosition = 0;
167: bufferLength = 0; // trigger refill() on read()
168: seekInternal(pos);
169: }
170: }
171:
172: /** Expert: implements seek. Sets current position in this file, where the
173: * next {@link #readInternal(byte[],int,int)} will occur.
174: * @see #readInternal(byte[],int,int)
175: */
176: protected abstract void seekInternal(long pos) throws IOException;
177:
178: public Object clone() {
179: ConfigurableBufferedIndexInput clone = (ConfigurableBufferedIndexInput) super
180: .clone();
181:
182: clone.buffer = null;
183: clone.bufferLength = 0;
184: clone.bufferPosition = 0;
185: clone.bufferStart = getFilePointer();
186:
187: return clone;
188: }
189:
190: }
|