View Javadoc

1   /*
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with 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  package org.apache.hadoop.hbase.io.hfile;
20  
21  import java.io.IOException;
22  import java.nio.ByteBuffer;
23  import java.util.concurrent.atomic.AtomicInteger;
24  
25  import org.apache.hadoop.conf.Configurable;
26  import org.apache.hadoop.conf.Configuration;
27  import org.apache.hadoop.fs.Path;
28  import org.apache.hadoop.hbase.KeyValue;
29  import org.apache.hadoop.hbase.KeyValue.KVComparator;
30  import org.apache.hadoop.hbase.classification.InterfaceAudience;
31  import org.apache.hadoop.hbase.fs.HFileSystem;
32  import org.apache.hadoop.hbase.io.compress.Compression;
33  import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding;
34  import org.apache.hadoop.hbase.io.hfile.HFile.FileInfo;
35  
36  /**
37   * Common functionality needed by all versions of {@link HFile} readers.
38   */
39  @InterfaceAudience.Private
40  public abstract class AbstractHFileReader
41      implements HFile.Reader, Configurable {
42    /** Stream to read from. Does checksum verifications in file system */
43  
44    /** The file system stream of the underlying {@link HFile} that
45     * does not do checksum verification in the file system */
46  
47    /** Data block index reader keeping the root data index in memory */
48    protected HFileBlockIndex.BlockIndexReader dataBlockIndexReader;
49  
50    /** Meta block index reader -- always single level */
51    protected HFileBlockIndex.BlockIndexReader metaBlockIndexReader;
52  
53    protected final FixedFileTrailer trailer;
54  
55    /** Filled when we read in the trailer. */
56    protected final Compression.Algorithm compressAlgo;
57  
58    private boolean isPrimaryReplicaReader;
59  
60    /**
61     * What kind of data block encoding should be used while reading, writing,
62     * and handling cache.
63     */
64    protected HFileDataBlockEncoder dataBlockEncoder =
65        NoOpDataBlockEncoder.INSTANCE;
66  
67    /** Last key in the file. Filled in when we read in the file info */
68    protected byte [] lastKey = null;
69  
70    /** Average key length read from file info */
71    protected int avgKeyLen = -1;
72  
73    /** Average value length read from file info */
74    protected int avgValueLen = -1;
75  
76    /** Key comparator */
77    protected KVComparator comparator = new KVComparator();
78  
79    /** Size of this file. */
80    protected final long fileSize;
81  
82    /** Block cache configuration. */
83    protected final CacheConfig cacheConf;
84  
85    /** Path of file */
86    protected final Path path;
87  
88    /** File name to be used for block names */
89    protected final String name;
90  
91    protected FileInfo fileInfo;
92  
93    /** The filesystem used for accesing data */
94    protected HFileSystem hfs;
95  
96    protected Configuration conf;
97  
98    @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
99    protected AbstractHFileReader(Path path, FixedFileTrailer trailer,
100       final long fileSize, final CacheConfig cacheConf, final HFileSystem hfs,
101       final Configuration conf) {
102     this.trailer = trailer;
103     this.compressAlgo = trailer.getCompressionCodec();
104     this.cacheConf = cacheConf;
105     this.fileSize = fileSize;
106     this.path = path;
107     this.name = path.getName();
108     this.hfs = hfs; // URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD
109     this.conf = conf;
110   }
111 
112   @SuppressWarnings("serial")
113   public static class BlockIndexNotLoadedException
114       extends IllegalStateException {
115     public BlockIndexNotLoadedException() {
116       // Add a message in case anyone relies on it as opposed to class name.
117       super("Block index not loaded");
118     }
119   }
120 
121   protected String toStringFirstKey() {
122     return KeyValue.keyToString(getFirstKey());
123   }
124 
125   protected String toStringLastKey() {
126     return KeyValue.keyToString(getLastKey());
127   }
128 
129   public abstract boolean isFileInfoLoaded();
130 
131   @Override
132   public String toString() {
133     return "reader=" + path.toString() +
134         (!isFileInfoLoaded()? "":
135           ", compression=" + compressAlgo.getName() +
136           ", cacheConf=" + cacheConf +
137           ", firstKey=" + toStringFirstKey() +
138           ", lastKey=" + toStringLastKey()) +
139           ", avgKeyLen=" + avgKeyLen +
140           ", avgValueLen=" + avgValueLen +
141           ", entries=" + trailer.getEntryCount() +
142           ", length=" + fileSize;
143   }
144 
145   @Override
146   public long length() {
147     return fileSize;
148   }
149 
150   /**
151    * Create a Scanner on this file. No seeks or reads are done on creation. Call
152    * {@link HFileScanner#seekTo(byte[])} to position an start the read. There is
153    * nothing to clean up in a Scanner. Letting go of your references to the
154    * scanner is sufficient. NOTE: Do not use this overload of getScanner for
155    * compactions.
156    *
157    * @param cacheBlocks True if we should cache blocks read in by this scanner.
158    * @param pread Use positional read rather than seek+read if true (pread is
159    *          better for random reads, seek+read is better scanning).
160    * @return Scanner on this file.
161    */
162   @Override
163   public HFileScanner getScanner(boolean cacheBlocks, final boolean pread) {
164     return getScanner(cacheBlocks, pread, false);
165   }
166 
167   /**
168    * @return the first key in the file. May be null if file has no entries. Note
169    *         that this is not the first row key, but rather the byte form of the
170    *         first KeyValue.
171    */
172   @Override
173   public byte [] getFirstKey() {
174     if (dataBlockIndexReader == null) {
175       throw new BlockIndexNotLoadedException();
176     }
177     return dataBlockIndexReader.isEmpty() ? null
178         : dataBlockIndexReader.getRootBlockKey(0);
179   }
180 
181   /**
182    * TODO left from {@link HFile} version 1: move this to StoreFile after Ryan's
183    * patch goes in to eliminate {@link KeyValue} here.
184    *
185    * @return the first row key, or null if the file is empty.
186    */
187   @Override
188   public byte[] getFirstRowKey() {
189     byte[] firstKey = getFirstKey();
190     if (firstKey == null)
191       return null;
192     return KeyValue.createKeyValueFromKey(firstKey).getRow();
193   }
194 
195   /**
196    * TODO left from {@link HFile} version 1: move this to StoreFile after
197    * Ryan's patch goes in to eliminate {@link KeyValue} here.
198    *
199    * @return the last row key, or null if the file is empty.
200    */
201   @Override
202   public byte[] getLastRowKey() {
203     byte[] lastKey = getLastKey();
204     if (lastKey == null)
205       return null;
206     return KeyValue.createKeyValueFromKey(lastKey).getRow();
207   }
208 
209   /** @return number of KV entries in this HFile */
210   @Override
211   public long getEntries() {
212     return trailer.getEntryCount();
213   }
214 
215   /** @return comparator */
216   @Override
217   public KVComparator getComparator() {
218     return comparator;
219   }
220 
221   /** @return compression algorithm */
222   @Override
223   public Compression.Algorithm getCompressionAlgorithm() {
224     return compressAlgo;
225   }
226 
227   /**
228    * @return the total heap size of data and meta block indexes in bytes. Does
229    *         not take into account non-root blocks of a multilevel data index.
230    */
231   @Override
232   public long indexSize() {
233     return (dataBlockIndexReader != null ? dataBlockIndexReader.heapSize() : 0)
234         + ((metaBlockIndexReader != null) ? metaBlockIndexReader.heapSize()
235             : 0);
236   }
237 
238   @Override
239   public String getName() {
240     return name;
241   }
242 
243   @Override
244   public HFileBlockIndex.BlockIndexReader getDataBlockIndexReader() {
245     return dataBlockIndexReader;
246   }
247 
248   @Override
249   public FixedFileTrailer getTrailer() {
250     return trailer;
251   }
252 
253   @Override
254   public boolean isPrimaryReplicaReader() {
255     return isPrimaryReplicaReader;
256   }
257 
258   @Override
259   public void setPrimaryReplicaReader(boolean isPrimaryReplicaReader) {
260     this.isPrimaryReplicaReader = isPrimaryReplicaReader;
261   }
262 
263   @Override
264   public FileInfo loadFileInfo() throws IOException {
265     return fileInfo;
266   }
267 
268   /**
269    * An exception thrown when an operation requiring a scanner to be seeked
270    * is invoked on a scanner that is not seeked.
271    */
272   @SuppressWarnings("serial")
273   public static class NotSeekedException extends IllegalStateException {
274     public NotSeekedException() {
275       super("Not seeked to a key/value");
276     }
277   }
278 
279   protected static abstract class Scanner implements HFileScanner {
280     protected ByteBuffer blockBuffer;
281 
282     protected boolean cacheBlocks;
283     protected final boolean pread;
284     protected final boolean isCompaction;
285 
286     protected int currKeyLen;
287     protected int currValueLen;
288     protected int currMemstoreTSLen;
289     protected long currMemstoreTS;
290 
291     protected AtomicInteger blockFetches = new AtomicInteger();
292 
293     protected final HFile.Reader reader;
294 
295     public Scanner(final HFile.Reader reader, final boolean cacheBlocks,
296         final boolean pread, final boolean isCompaction) {
297       this.reader = reader;
298       this.cacheBlocks = cacheBlocks;
299       this.pread = pread;
300       this.isCompaction = isCompaction;
301     }
302 
303     @Override
304     public boolean isSeeked(){
305       return blockBuffer != null;
306     }
307 
308     @Override
309     public String toString() {
310       return "HFileScanner for reader " + String.valueOf(getReader());
311     }
312 
313     protected void assertSeeked() {
314       if (!isSeeked())
315         throw new NotSeekedException();
316     }
317 
318     @Override
319     public int seekTo(byte[] key) throws IOException {
320       return seekTo(key, 0, key.length);
321     }
322     
323     @Override
324     public boolean seekBefore(byte[] key) throws IOException {
325       return seekBefore(key, 0, key.length);
326     }
327     
328     @Override
329     public int reseekTo(byte[] key) throws IOException {
330       return reseekTo(key, 0, key.length);
331     }
332 
333     @Override
334     public HFile.Reader getReader() {
335       return reader;
336     }
337 
338     @Override
339     public void close() {
340       if (!pread) {
341         // For seek + pread stream socket should be closed when the scanner is closed. HBASE-9393
342         reader.unbufferStream();
343       }
344     }
345   }
346 
347   /** For testing */
348   abstract HFileBlock.FSReader getUncachedBlockReader();
349 
350   @Override
351   public Path getPath() {
352     return path;
353   }
354 
355   @Override
356   public DataBlockEncoding getDataBlockEncoding() {
357     return dataBlockEncoder.getDataBlockEncoding();
358   }
359 
360   public abstract int getMajorVersion();
361 
362   @Override
363   public Configuration getConf() {
364     return conf;
365   }
366 
367   @Override
368   public void setConf(Configuration conf) {
369     this.conf = conf;
370   }
371 }