/** * Copyright The Apache Software Foundation * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.hadoop.hbase; import java.nio.ByteBuffer; import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.hbase.classification.InterfaceStability; import org.apache.hadoop.hbase.util.Bytes; /** * This is a {@link Tag} implementation in which value is backed by an on heap byte array. */ @InterfaceAudience.Private @InterfaceStability.Evolving public class ArrayBackedTag implements Tag { private final byte type;// TODO extra type state needed? private final byte[] bytes; private int offset = 0; private int length = 0; /** * The special tag will write the length of each tag and that will be * followed by the type and then the actual tag. * So every time the length part is parsed we need to add + 1 byte to it to * get the type and then get the actual tag. */ public ArrayBackedTag(byte tagType, String tag) { this(tagType, Bytes.toBytes(tag)); } /** * Format for a tag : * {@code <length of tag - 2 bytes><type code - 1 byte><tag>} tag length is serialized * using 2 bytes only but as this will be unsigned, we can have max tag length of * (Short.MAX_SIZE * 2) +1. It includes 1 byte type length and actual tag bytes length. */ public ArrayBackedTag(byte tagType, byte[] tag) { int tagLength = tag.length + TYPE_LENGTH_SIZE; if (tagLength > MAX_TAG_LENGTH) { throw new IllegalArgumentException( "Invalid tag data being passed. Its length can not exceed " + MAX_TAG_LENGTH); } length = TAG_LENGTH_SIZE + tagLength; bytes = new byte[length]; int pos = Bytes.putAsShort(bytes, 0, tagLength); pos = Bytes.putByte(bytes, pos, tagType); Bytes.putBytes(bytes, pos, tag, 0, tag.length); this.type = tagType; } /** * Creates a Tag from the specified byte array and offset. Presumes * <code>bytes</code> content starting at <code>offset</code> is formatted as * a Tag blob. * The bytes to include the tag type, tag length and actual tag bytes. * @param offset offset to start of Tag */ public ArrayBackedTag(byte[] bytes, int offset) { this(bytes, offset, getLength(bytes, offset)); } private static int getLength(byte[] bytes, int offset) { return TAG_LENGTH_SIZE + Bytes.readAsInt(bytes, offset, TAG_LENGTH_SIZE); } /** * Creates a Tag from the specified byte array, starting at offset, and for length * <code>length</code>. Presumes <code>bytes</code> content starting at <code>offset</code> is * formatted as a Tag blob. */ public ArrayBackedTag(byte[] bytes, int offset, int length) { if (length > MAX_TAG_LENGTH) { throw new IllegalArgumentException( "Invalid tag data being passed. Its length can not exceed " + MAX_TAG_LENGTH); } this.bytes = bytes; this.offset = offset; this.length = length; this.type = bytes[offset + TAG_LENGTH_SIZE]; } /** * @return The byte array backing this Tag. */ public byte[] getValueArray() { return this.bytes; } /** * @return the tag type */ public byte getType() { return this.type; } /** * @return Length of actual tag bytes within the backed buffer */ public int getValueLength() { return this.length - INFRASTRUCTURE_SIZE; } /** * @return Offset of actual tag bytes within the backed buffer */ public int getValueOffset() { return this.offset + INFRASTRUCTURE_SIZE; } @Override public boolean hasArray() { return true; } @Override public ByteBuffer getValueByteBuffer() { return ByteBuffer.wrap(bytes); } @Override public String toString() { return "[Tag type : " + this.type + ", value : " + Bytes.toStringBinary(bytes, getValueOffset(), getValueLength()) + "]"; } }