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