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
15   * under the License.
16   */
17  package org.apache.hadoop.hbase.io.hfile;
18  
19  import java.io.IOException;
20  import java.nio.ByteBuffer;
21  
22  import org.apache.hadoop.classification.InterfaceAudience;
23  import org.apache.hadoop.hbase.io.encoding.DataBlockEncoder;
24  import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding;
25  import org.apache.hadoop.hbase.io.encoding.HFileBlockDecodingContext;
26  import org.apache.hadoop.hbase.io.encoding.HFileBlockDefaultDecodingContext;
27  import org.apache.hadoop.hbase.io.encoding.HFileBlockDefaultEncodingContext;
28  import org.apache.hadoop.hbase.io.encoding.HFileBlockEncodingContext;
29  import org.apache.hadoop.hbase.io.hfile.HFile.FileInfo;
30  import org.apache.hadoop.hbase.util.Bytes;
31  
32  /**
33   * Do different kinds of data block encoding according to column family
34   * options.
35   */
36  @InterfaceAudience.Private
37  public class HFileDataBlockEncoderImpl implements HFileDataBlockEncoder {
38    private final DataBlockEncoding encoding;
39  
40    /**
41     * Do data block encoding with specified options.
42     * @param encoding What kind of data block encoding will be used.
43     */
44    public HFileDataBlockEncoderImpl(DataBlockEncoding encoding) {
45      this.encoding = encoding != null ? encoding : DataBlockEncoding.NONE;
46    }
47  
48    public static HFileDataBlockEncoder createFromFileInfo(
49        FileInfo fileInfo) throws IOException {
50      DataBlockEncoding encoding = DataBlockEncoding.NONE;
51      byte[] dataBlockEncodingType = fileInfo.get(DATA_BLOCK_ENCODING);
52      if (dataBlockEncodingType != null) {
53        String dataBlockEncodingStr = Bytes.toString(dataBlockEncodingType);
54        try {
55          encoding = DataBlockEncoding.valueOf(dataBlockEncodingStr);
56        } catch (IllegalArgumentException ex) {
57          throw new IOException("Invalid data block encoding type in file info: "
58            + dataBlockEncodingStr, ex);
59        }
60      }
61  
62      if (encoding == DataBlockEncoding.NONE) {
63        return NoOpDataBlockEncoder.INSTANCE;
64      }
65      return new HFileDataBlockEncoderImpl(encoding);
66    }
67  
68    @Override
69    public void saveMetadata(HFile.Writer writer) throws IOException {
70      writer.appendFileInfo(DATA_BLOCK_ENCODING, encoding.getNameInBytes());
71    }
72  
73    @Override
74    public DataBlockEncoding getDataBlockEncoding() {
75      return encoding;
76    }
77  
78    /**
79     * Precondition: a non-encoded buffer. Postcondition: on-disk encoding.
80     *
81     * The encoded results can be stored in {@link HFileBlockEncodingContext}.
82     *
83     * @throws IOException
84     */
85    @Override
86    public void beforeWriteToDisk(ByteBuffer in,
87        HFileBlockEncodingContext encodeCtx,
88        BlockType blockType) throws IOException {
89      if (encoding == DataBlockEncoding.NONE) {
90        // there is no need to encode the block before writing it to disk
91        ((HFileBlockDefaultEncodingContext) encodeCtx).compressAfterEncodingWithBlockType(
92            in.array(), blockType);
93        return;
94      }
95      encodeBufferToHFileBlockBuffer(in, encoding, encodeCtx);
96    }
97  
98    @Override
99    public boolean useEncodedScanner() {
100     return encoding != DataBlockEncoding.NONE;
101   }
102 
103   /**
104    * Encode a block of key value pairs.
105    *
106    * @param in input data to encode
107    * @param algo encoding algorithm
108    * @param encodeCtx where will the output data be stored
109    */
110   private void encodeBufferToHFileBlockBuffer(ByteBuffer in, DataBlockEncoding algo,
111       HFileBlockEncodingContext encodeCtx) {
112     DataBlockEncoder encoder = algo.getEncoder();
113     try {
114       encoder.encodeKeyValues(in, encodeCtx);
115     } catch (IOException e) {
116       throw new RuntimeException(String.format(
117           "Bug in data block encoder "
118               + "'%s', it probably requested too much data, " +
119               "exception message: %s.",
120               algo.toString(), e.getMessage()), e);
121     }
122   }
123 
124   @Override
125   public String toString() {
126     return getClass().getSimpleName() + "(encoding=" + encoding + ")";
127   }
128 
129   @Override
130   public HFileBlockEncodingContext newDataBlockEncodingContext(
131       byte[] dummyHeader, HFileContext fileContext) {
132     DataBlockEncoder encoder = encoding.getEncoder();
133     if (encoder != null) {
134       return encoder.newDataBlockEncodingContext(encoding, dummyHeader, fileContext);
135     }
136     return new HFileBlockDefaultEncodingContext(null, dummyHeader, fileContext);
137   }
138 
139   @Override
140   public HFileBlockDecodingContext newDataBlockDecodingContext(HFileContext fileContext) {
141     DataBlockEncoder encoder = encoding.getEncoder();
142     if (encoder != null) {
143       return encoder.newDataBlockDecodingContext(fileContext);
144     }
145     return new HFileBlockDefaultDecodingContext(fileContext);
146   }
147 }