001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.io.hfile;
019
020import java.io.DataOutputStream;
021import java.io.IOException;
022import org.apache.hadoop.conf.Configuration;
023import org.apache.hadoop.hbase.Cell;
024import org.apache.hadoop.hbase.io.encoding.DataBlockEncoder;
025import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding;
026import org.apache.hadoop.hbase.io.encoding.HFileBlockDecodingContext;
027import org.apache.hadoop.hbase.io.encoding.HFileBlockDefaultDecodingContext;
028import org.apache.hadoop.hbase.io.encoding.HFileBlockDefaultEncodingContext;
029import org.apache.hadoop.hbase.io.encoding.HFileBlockEncodingContext;
030import org.apache.hadoop.hbase.util.Bytes;
031import org.apache.yetus.audience.InterfaceAudience;
032
033/**
034 * Do different kinds of data block encoding according to column family options.
035 */
036@InterfaceAudience.Private
037public class HFileDataBlockEncoderImpl implements HFileDataBlockEncoder {
038  private final DataBlockEncoding encoding;
039
040  /**
041   * Do data block encoding with specified options.
042   * @param encoding What kind of data block encoding will be used.
043   */
044  public HFileDataBlockEncoderImpl(DataBlockEncoding encoding) {
045    this.encoding = encoding != null ? encoding : DataBlockEncoding.NONE;
046  }
047
048  public static HFileDataBlockEncoder createFromFileInfo(HFileInfo fileInfo) throws IOException {
049    DataBlockEncoding encoding = DataBlockEncoding.NONE;
050    byte[] dataBlockEncodingType = fileInfo.get(DATA_BLOCK_ENCODING);
051    if (dataBlockEncodingType != null) {
052      String dataBlockEncodingStr = Bytes.toString(dataBlockEncodingType);
053      try {
054        encoding = DataBlockEncoding.valueOf(dataBlockEncodingStr);
055      } catch (IllegalArgumentException ex) {
056        throw new IOException(
057          "Invalid data block encoding type in file info: " + dataBlockEncodingStr, ex);
058      }
059    }
060
061    if (encoding == DataBlockEncoding.NONE) {
062      return NoOpDataBlockEncoder.INSTANCE;
063    }
064    return new HFileDataBlockEncoderImpl(encoding);
065  }
066
067  @Override
068  public void saveMetadata(HFile.Writer writer) throws IOException {
069    writer.appendFileInfo(DATA_BLOCK_ENCODING, encoding.getNameInBytes());
070  }
071
072  @Override
073  public DataBlockEncoding getDataBlockEncoding() {
074    return encoding;
075  }
076
077  public boolean useEncodedScanner(boolean isCompaction) {
078    if (isCompaction && encoding == DataBlockEncoding.NONE) {
079      return false;
080    }
081    return encoding != DataBlockEncoding.NONE;
082  }
083
084  @Override
085  public DataBlockEncoding getEffectiveEncodingInCache(boolean isCompaction) {
086    if (!useEncodedScanner(isCompaction)) {
087      return DataBlockEncoding.NONE;
088    }
089    return encoding;
090  }
091
092  @Override
093  public void encode(Cell cell, HFileBlockEncodingContext encodingCtx, DataOutputStream out)
094    throws IOException {
095    this.encoding.getEncoder().encode(cell, encodingCtx, out);
096  }
097
098  @Override
099  public boolean useEncodedScanner() {
100    return encoding != DataBlockEncoding.NONE;
101  }
102
103  @Override
104  public String toString() {
105    return getClass().getSimpleName() + "(encoding=" + encoding + ")";
106  }
107
108  @Override
109  public HFileBlockEncodingContext newDataBlockEncodingContext(Configuration conf,
110    byte[] dummyHeader, HFileContext fileContext) {
111    DataBlockEncoder encoder = encoding.getEncoder();
112    if (encoder != null) {
113      return encoder.newDataBlockEncodingContext(conf, encoding, dummyHeader, fileContext);
114    }
115    return new HFileBlockDefaultEncodingContext(conf, null, dummyHeader, fileContext);
116  }
117
118  @Override
119  public HFileBlockDecodingContext newDataBlockDecodingContext(Configuration conf,
120    HFileContext fileContext) {
121    DataBlockEncoder encoder = encoding.getEncoder();
122    if (encoder != null) {
123      return encoder.newDataBlockDecodingContext(conf, fileContext);
124    }
125    return new HFileBlockDefaultDecodingContext(conf, fileContext);
126  }
127
128  @Override
129  public void startBlockEncoding(HFileBlockEncodingContext encodingCtx, DataOutputStream out)
130    throws IOException {
131    if (this.encoding != null && this.encoding != DataBlockEncoding.NONE) {
132      this.encoding.getEncoder().startBlockEncoding(encodingCtx, out);
133    }
134  }
135
136  @Override
137  public void endBlockEncoding(HFileBlockEncodingContext encodingCtx, DataOutputStream out,
138    byte[] uncompressedBytesWithHeader, BlockType blockType) throws IOException {
139    this.encoding.getEncoder().endBlockEncoding(encodingCtx, out, uncompressedBytesWithHeader);
140  }
141}