View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with this
4    * work for additional information regarding copyright ownership. The ASF
5    * licenses this file to you under the Apache License, Version 2.0 (the
6    * "License"); you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    * http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14   * License for the specific language governing permissions and limitations under
15   * the License.
16   */
17  
18  package org.apache.hadoop.hbase.io.hfile;
19  
20  import java.io.IOException;
21  import java.io.InputStream;
22  
23  import org.apache.hadoop.classification.InterfaceAudience;
24  import org.apache.hadoop.fs.FSDataInputStream;
25  
26  /**
27   * BoundedRangeFIleInputStream abstracts a contiguous region of a Hadoop
28   * FSDataInputStream as a regular input stream. One can create multiple
29   * BoundedRangeFileInputStream on top of the same FSDataInputStream and they
30   * would not interfere with each other.
31   * Copied from hadoop-335 tfile.
32   */
33  @InterfaceAudience.Private
34  class BoundedRangeFileInputStream  extends InputStream {
35  
36    private FSDataInputStream in;
37    private long pos;
38    private long end;
39    private long mark;
40    private final byte[] oneByte = new byte[1];
41    private final boolean pread;
42  
43    /**
44     * Constructor
45     *
46     * @param in
47     *          The FSDataInputStream we connect to.
48     * @param offset
49     *          Beginning offset of the region.
50     * @param length
51     *          Length of the region.
52     * @param pread If true, use Filesystem positional read rather than seek+read.
53     *
54     *          The actual length of the region may be smaller if (off_begin +
55     *          length) goes beyond the end of FS input stream.
56     */
57    public BoundedRangeFileInputStream(FSDataInputStream in, long offset,
58        long length, final boolean pread) {
59      if (offset < 0 || length < 0) {
60        throw new IndexOutOfBoundsException("Invalid offset/length: " + offset
61            + "/" + length);
62      }
63  
64      this.in = in;
65      this.pos = offset;
66      this.end = offset + length;
67      this.mark = -1;
68      this.pread = pread;
69    }
70  
71    @Override
72    public int available() throws IOException {
73      int avail = in.available();
74      if (pos + avail > end) {
75        avail = (int) (end - pos);
76      }
77  
78      return avail;
79    }
80  
81    @Override
82    public int read() throws IOException {
83      int ret = read(oneByte);
84      if (ret == 1) return oneByte[0] & 0xff;
85      return -1;
86    }
87  
88    @Override
89    public int read(byte[] b) throws IOException {
90      return read(b, 0, b.length);
91    }
92  
93    @Override
94    public int read(byte[] b, int off, int len) throws IOException {
95      if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
96        throw new IndexOutOfBoundsException();
97      }
98  
99      int n = (int) Math.min(Integer.MAX_VALUE, Math.min(len, (end - pos)));
100     if (n == 0) return -1;
101     int ret = 0;
102     if (this.pread) {
103       ret = in.read(pos, b, off, n);
104     } else {
105       synchronized (in) {
106         in.seek(pos);
107         ret = in.read(b, off, n);
108       }
109     }
110     if (ret < 0) {
111       end = pos;
112       return -1;
113     }
114     pos += ret;
115     return ret;
116   }
117 
118   @Override
119   /*
120    * We may skip beyond the end of the file.
121    */
122   public long skip(long n) throws IOException {
123     long len = Math.min(n, end - pos);
124     pos += len;
125     return len;
126   }
127 
128   @Override
129   public void mark(int readlimit) {
130     mark = pos;
131   }
132 
133   @Override
134   public void reset() throws IOException {
135     if (mark < 0) throw new IOException("Resetting to invalid mark");
136     pos = mark;
137   }
138 
139   @Override
140   public boolean markSupported() {
141     return true;
142   }
143 
144   @Override
145   public void close() {
146     // Invalidate the state of the stream.
147     in = null;
148     pos = end;
149     mark = -1;
150   }
151 }