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.encoding;
019
020import java.io.IOException;
021import java.io.OutputStream;
022import org.apache.hadoop.hbase.util.Bytes;
023import org.apache.yetus.audience.InterfaceAudience;
024
025/**
026 * Provide access to all index block encoding algorithms. All of the algorithms are required to have
027 * unique id which should <b>NEVER</b> be changed. If you want to add a new algorithm/version,
028 * assign it a new id. Announce the new id in the HBase mailing list to prevent collisions.
029 */
030@InterfaceAudience.Public
031public enum IndexBlockEncoding {
032
033  /** Disable index block encoding. */
034  NONE(0, null),
035  // id 1 is reserved for the PREFIX_TREE algorithm to be added later
036  PREFIX_TREE(1, null);
037
038  private final short id;
039  private final byte[] idInBytes;
040  private final String encoderCls;
041
042  public static final int ID_SIZE = Bytes.SIZEOF_SHORT;
043
044  /** Maps data block encoding ids to enum instances. */
045  private static IndexBlockEncoding[] idArray = new IndexBlockEncoding[Byte.MAX_VALUE + 1];
046
047  static {
048    for (IndexBlockEncoding algo : values()) {
049      if (idArray[algo.id] != null) {
050        throw new RuntimeException(
051          String.format("Two data block encoder algorithms '%s' and '%s' have " + "the same id %d",
052            idArray[algo.id].toString(), algo.toString(), (int) algo.id));
053      }
054      idArray[algo.id] = algo;
055    }
056  }
057
058  private IndexBlockEncoding(int id, String encoderClsName) {
059    if (id < 0 || id > Byte.MAX_VALUE) {
060      throw new AssertionError("Data block encoding algorithm id is out of range: " + id);
061    }
062    this.id = (short) id;
063    this.idInBytes = Bytes.toBytes(this.id);
064    if (idInBytes.length != ID_SIZE) {
065      // White this may seem redundant, if we accidentally serialize
066      // the id as e.g. an int instead of a short, all encoders will break.
067      throw new RuntimeException("Unexpected length of encoder ID byte " + "representation: "
068        + Bytes.toStringBinary(idInBytes));
069    }
070    this.encoderCls = encoderClsName;
071  }
072
073  /** Returns name converted to bytes. */
074  public byte[] getNameInBytes() {
075    return Bytes.toBytes(toString());
076  }
077
078  /** Returns The id of a data block encoder. */
079  public short getId() {
080    return id;
081  }
082
083  /**
084   * Writes id in bytes.
085   * @param stream where the id should be written.
086   */
087  public void writeIdInBytes(OutputStream stream) throws IOException {
088    stream.write(idInBytes);
089  }
090
091  /**
092   * Writes id bytes to the given array starting from offset.
093   * @param dest   output array
094   * @param offset starting offset of the output array
095   */
096  public void writeIdInBytes(byte[] dest, int offset) throws IOException {
097    System.arraycopy(idInBytes, 0, dest, offset, ID_SIZE);
098  }
099
100  /**
101   * Find and return the name of data block encoder for the given id.
102   * @param encoderId id of data block encoder
103   * @return name, same as used in options in column family
104   */
105  public static String getNameFromId(short encoderId) {
106    return getEncodingById(encoderId).toString();
107  }
108
109  public static IndexBlockEncoding getEncodingById(short indexBlockEncodingId) {
110    IndexBlockEncoding algorithm = null;
111    if (indexBlockEncodingId >= 0 && indexBlockEncodingId <= Byte.MAX_VALUE) {
112      algorithm = idArray[indexBlockEncodingId];
113    }
114    if (algorithm == null) {
115      throw new IllegalArgumentException(String
116        .format("There is no index block encoder for given id '%d'", (int) indexBlockEncodingId));
117    }
118    return algorithm;
119  }
120
121}