Save This Page
Home » lucene-2.4.1-src » org.apache » lucene » store » [javadoc | source]
    1   package org.apache.lucene.store;
    2   
    3   /**
    4    * Licensed to the Apache Software Foundation (ASF) under one or more
    5    * contributor license agreements.  See the NOTICE file distributed with
    6    * this work for additional information regarding copyright ownership.
    7    * The ASF licenses this file to You under the Apache License, Version 2.0
    8    * (the "License"); you may not use this file except in compliance with
    9    * the License.  You may obtain a copy of the License at
   10    *
   11    *     http://www.apache.org/licenses/LICENSE-2.0
   12    *
   13    * Unless required by applicable law or agreed to in writing, software
   14    * distributed under the License is distributed on an "AS IS" BASIS,
   15    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   16    * See the License for the specific language governing permissions and
   17    * limitations under the License.
   18    */
   19   
   20   import java.io.IOException;
   21   
   22   /** Base implementation class for buffered {@link IndexInput}. */
   23   public abstract class BufferedIndexInput extends IndexInput {
   24   
   25     /** Default buffer size */
   26     public static final int BUFFER_SIZE = 1024;
   27   
   28     private int bufferSize = BUFFER_SIZE;
   29   
   30     protected byte[] buffer;
   31   
   32     private long bufferStart = 0;			  // position in file of buffer
   33     private int bufferLength = 0;			  // end of valid bytes
   34     private int bufferPosition = 0;		  // next byte to read
   35   
   36     public byte readByte() throws IOException {
   37       if (bufferPosition >= bufferLength)
   38         refill();
   39       return buffer[bufferPosition++];
   40     }
   41   
   42     public BufferedIndexInput() {}
   43   
   44     /** Inits BufferedIndexInput with a specific bufferSize */
   45     public BufferedIndexInput(int bufferSize) {
   46       checkBufferSize(bufferSize);
   47       this.bufferSize = bufferSize;
   48     }
   49   
   50     /** Change the buffer size used by this IndexInput */
   51     public void setBufferSize(int newSize) {
   52       assert buffer == null || bufferSize == buffer.length: "buffer=" + buffer + " bufferSize=" + bufferSize + " buffer.length=" + (buffer != null ? buffer.length : 0);
   53       if (newSize != bufferSize) {
   54         checkBufferSize(newSize);
   55         bufferSize = newSize;
   56         if (buffer != null) {
   57           // Resize the existing buffer and carefully save as
   58           // many bytes as possible starting from the current
   59           // bufferPosition
   60           byte[] newBuffer = new byte[newSize];
   61           final int leftInBuffer = bufferLength-bufferPosition;
   62           final int numToCopy;
   63           if (leftInBuffer > newSize)
   64             numToCopy = newSize;
   65           else
   66             numToCopy = leftInBuffer;
   67           System.arraycopy(buffer, bufferPosition, newBuffer, 0, numToCopy);
   68           bufferStart += bufferPosition;
   69           bufferPosition = 0;
   70           bufferLength = numToCopy;
   71           newBuffer(newBuffer);
   72         }
   73       }
   74     }
   75   
   76     protected void newBuffer(byte[] newBuffer) {
   77       // Subclasses can do something here
   78       buffer = newBuffer;
   79     }
   80   
   81     /** Returns buffer size.  @see #setBufferSize */
   82     public int getBufferSize() {
   83       return bufferSize;
   84     }
   85   
   86     private void checkBufferSize(int bufferSize) {
   87       if (bufferSize <= 0)
   88         throw new IllegalArgumentException("bufferSize must be greater than 0 (got " + bufferSize + ")");
   89     }
   90   
   91     public void readBytes(byte[] b, int offset, int len) throws IOException {
   92       readBytes(b, offset, len, true);
   93     }
   94   
   95     public void readBytes(byte[] b, int offset, int len, boolean useBuffer) throws IOException {
   96   
   97       if(len <= (bufferLength-bufferPosition)){
   98         // the buffer contains enough data to satisfy this request
   99         if(len>0) // to allow b to be null if len is 0...
  100           System.arraycopy(buffer, bufferPosition, b, offset, len);
  101         bufferPosition+=len;
  102       } else {
  103         // the buffer does not have enough data. First serve all we've got.
  104         int available = bufferLength - bufferPosition;
  105         if(available > 0){
  106           System.arraycopy(buffer, bufferPosition, b, offset, available);
  107           offset += available;
  108           len -= available;
  109           bufferPosition += available;
  110         }
  111         // and now, read the remaining 'len' bytes:
  112         if (useBuffer && len<bufferSize){
  113           // If the amount left to read is small enough, and
  114           // we are allowed to use our buffer, do it in the usual
  115           // buffered way: fill the buffer and copy from it:
  116           refill();
  117           if(bufferLength<len){
  118             // Throw an exception when refill() could not read len bytes:
  119             System.arraycopy(buffer, 0, b, offset, bufferLength);
  120             throw new IOException("read past EOF");
  121           } else {
  122             System.arraycopy(buffer, 0, b, offset, len);
  123             bufferPosition=len;
  124           }
  125         } else {
  126           // The amount left to read is larger than the buffer
  127           // or we've been asked to not use our buffer -
  128           // there's no performance reason not to read it all
  129           // at once. Note that unlike the previous code of
  130           // this function, there is no need to do a seek
  131           // here, because there's no need to reread what we
  132           // had in the buffer.
  133           long after = bufferStart+bufferPosition+len;
  134           if(after > length())
  135             throw new IOException("read past EOF");
  136           readInternal(b, offset, len);
  137           bufferStart = after;
  138           bufferPosition = 0;
  139           bufferLength = 0;                    // trigger refill() on read
  140         }
  141       }
  142     }
  143   
  144     private void refill() throws IOException {
  145       long start = bufferStart + bufferPosition;
  146       long end = start + bufferSize;
  147       if (end > length())				  // don't read past EOF
  148         end = length();
  149       int newLength = (int)(end - start);
  150       if (newLength <= 0)
  151         throw new IOException("read past EOF");
  152   
  153       if (buffer == null) {
  154         newBuffer(new byte[bufferSize]);  // allocate buffer lazily
  155         seekInternal(bufferStart);
  156       }
  157       readInternal(buffer, 0, newLength);
  158       bufferLength = newLength;
  159       bufferStart = start;
  160       bufferPosition = 0;
  161     }
  162   
  163     /** Expert: implements buffer refill.  Reads bytes from the current position
  164      * in the input.
  165      * @param b the array to read bytes into
  166      * @param offset the offset in the array to start storing bytes
  167      * @param length the number of bytes to read
  168      */
  169     protected abstract void readInternal(byte[] b, int offset, int length)
  170             throws IOException;
  171   
  172     public long getFilePointer() { return bufferStart + bufferPosition; }
  173   
  174     public void seek(long pos) throws IOException {
  175       if (pos >= bufferStart && pos < (bufferStart + bufferLength))
  176         bufferPosition = (int)(pos - bufferStart);  // seek within buffer
  177       else {
  178         bufferStart = pos;
  179         bufferPosition = 0;
  180         bufferLength = 0;				  // trigger refill() on read()
  181         seekInternal(pos);
  182       }
  183     }
  184   
  185     /** Expert: implements seek.  Sets current position in this file, where the
  186      * next {@link #readInternal(byte[],int,int)} will occur.
  187      * @see #readInternal(byte[],int,int)
  188      */
  189     protected abstract void seekInternal(long pos) throws IOException;
  190   
  191     public Object clone() {
  192       BufferedIndexInput clone = (BufferedIndexInput)super.clone();
  193   
  194       clone.buffer = null;
  195       clone.bufferLength = 0;
  196       clone.bufferPosition = 0;
  197       clone.bufferStart = getFilePointer();
  198   
  199       return clone;
  200     }
  201   
  202   }

Save This Page
Home » lucene-2.4.1-src » org.apache » lucene » store » [javadoc | source]