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.hadoop.hbase.Cell;
023import org.apache.hadoop.hbase.io.encoding.DataBlockEncoder;
024import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding;
025import org.apache.hadoop.hbase.io.encoding.HFileBlockDecodingContext;
026import org.apache.hadoop.hbase.io.encoding.HFileBlockDefaultDecodingContext;
027import org.apache.hadoop.hbase.io.encoding.HFileBlockDefaultEncodingContext;
028import org.apache.hadoop.hbase.io.encoding.HFileBlockEncodingContext;
029import org.apache.hadoop.hbase.util.Bytes;
030import org.apache.yetus.audience.InterfaceAudience;
031
032/**
033 * Do different kinds of data block encoding according to column family
034 * 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(
049      HFileInfo fileInfo) throws IOException {
050    DataBlockEncoding encoding = DataBlockEncoding.NONE;
051    byte[] dataBlockEncodingType = fileInfo.get(DATA_BLOCK_ENCODING);
052    if (dataBlockEncodingType != null) {
053      String dataBlockEncodingStr = Bytes.toString(dataBlockEncodingType);
054      try {
055        encoding = DataBlockEncoding.valueOf(dataBlockEncodingStr);
056      } catch (IllegalArgumentException ex) {
057        throw new IOException("Invalid data block encoding type in file info: "
058          + dataBlockEncodingStr, ex);
059      }
060    }
061
062    if (encoding == DataBlockEncoding.NONE) {
063      return NoOpDataBlockEncoder.INSTANCE;
064    }
065    return new HFileDataBlockEncoderImpl(encoding);
066  }
067
068  @Override
069  public void saveMetadata(HFile.Writer writer) throws IOException {
070    writer.appendFileInfo(DATA_BLOCK_ENCODING, encoding.getNameInBytes());
071  }
072
073  @Override
074  public DataBlockEncoding getDataBlockEncoding() {
075    return encoding;
076  }
077
078  public boolean useEncodedScanner(boolean isCompaction) {
079    if (isCompaction && encoding == DataBlockEncoding.NONE) {
080      return false;
081    }
082    return encoding != DataBlockEncoding.NONE;
083  }
084
085  @Override
086  public DataBlockEncoding getEffectiveEncodingInCache(boolean isCompaction) {
087    if (!useEncodedScanner(isCompaction)) {
088      return DataBlockEncoding.NONE;
089    }
090    return encoding;
091  }
092
093  @Override
094  public void encode(Cell cell, HFileBlockEncodingContext encodingCtx, DataOutputStream out)
095      throws IOException {
096    this.encoding.getEncoder().encode(cell, encodingCtx, out);
097  }
098
099  @Override
100  public boolean useEncodedScanner() {
101    return encoding != DataBlockEncoding.NONE;
102  }
103
104
105  @Override
106  public String toString() {
107    return getClass().getSimpleName() + "(encoding=" + encoding + ")";
108  }
109
110  @Override
111  public HFileBlockEncodingContext newDataBlockEncodingContext(
112      byte[] dummyHeader, HFileContext fileContext) {
113    DataBlockEncoder encoder = encoding.getEncoder();
114    if (encoder != null) {
115      return encoder.newDataBlockEncodingContext(encoding, dummyHeader, fileContext);
116    }
117    return new HFileBlockDefaultEncodingContext(null, dummyHeader, fileContext);
118  }
119
120  @Override
121  public HFileBlockDecodingContext newDataBlockDecodingContext(HFileContext fileContext) {
122    DataBlockEncoder encoder = encoding.getEncoder();
123    if (encoder != null) {
124      return encoder.newDataBlockDecodingContext(fileContext);
125    }
126    return new HFileBlockDefaultDecodingContext(fileContext);
127  }
128
129  @Override
130  public void startBlockEncoding(HFileBlockEncodingContext encodingCtx, DataOutputStream out)
131      throws IOException {
132    if (this.encoding != null && this.encoding != DataBlockEncoding.NONE) {
133      this.encoding.getEncoder().startBlockEncoding(encodingCtx, out);
134    }
135  }
136
137  @Override
138  public void endBlockEncoding(HFileBlockEncodingContext encodingCtx, DataOutputStream out,
139      byte[] uncompressedBytesWithHeader, BlockType blockType) throws IOException {
140    this.encoding.getEncoder().endBlockEncoding(encodingCtx, out, uncompressedBytesWithHeader);
141  }
142}