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; 019 020import java.nio.ByteBuffer; 021import org.apache.hadoop.hbase.util.Bytes; 022import org.apache.yetus.audience.InterfaceAudience; 023import org.apache.yetus.audience.InterfaceStability; 024 025/** 026 * This is a {@link Tag} implementation in which value is backed by an on heap byte array. 027 */ 028@InterfaceAudience.Private 029@InterfaceStability.Evolving 030public class ArrayBackedTag implements Tag { 031 private final byte type;// TODO extra type state needed? 032 private final byte[] bytes; 033 private int offset = 0; 034 private int length = 0; 035 036 /** 037 * The special tag will write the length of each tag and that will be followed by the type and 038 * then the actual tag. So every time the length part is parsed we need to add + 1 byte to it to 039 * get the type and then get the actual tag. 040 */ 041 public ArrayBackedTag(byte tagType, String tag) { 042 this(tagType, Bytes.toBytes(tag)); 043 } 044 045 /** 046 * Format for a tag : {@code <length of tag - 2 bytes><type code - 1 byte><tag>} tag length is 047 * serialized using 2 bytes only but as this will be unsigned, we can have max tag length of 048 * (Short.MAX_SIZE * 2) +1. It includes 1 byte type length and actual tag bytes length. 049 */ 050 public ArrayBackedTag(byte tagType, byte[] tag) { 051 int tagLength = tag.length + TYPE_LENGTH_SIZE; 052 if (tagLength > MAX_TAG_LENGTH) { 053 throw new IllegalArgumentException( 054 "Invalid tag data being passed. Its length can not exceed " + MAX_TAG_LENGTH); 055 } 056 length = TAG_LENGTH_SIZE + tagLength; 057 bytes = new byte[length]; 058 int pos = Bytes.putAsShort(bytes, 0, tagLength); 059 pos = Bytes.putByte(bytes, pos, tagType); 060 Bytes.putBytes(bytes, pos, tag, 0, tag.length); 061 this.type = tagType; 062 } 063 064 /** 065 * Creates a Tag from the specified byte array and offset. Presumes <code>bytes</code> content 066 * starting at <code>offset</code> is formatted as a Tag blob. The bytes to include the tag type, 067 * tag length and actual tag bytes. 068 * @param offset offset to start of Tag 069 */ 070 public ArrayBackedTag(byte[] bytes, int offset) { 071 this(bytes, offset, getLength(bytes, offset)); 072 } 073 074 private static int getLength(byte[] bytes, int offset) { 075 return TAG_LENGTH_SIZE + Bytes.readAsInt(bytes, offset, TAG_LENGTH_SIZE); 076 } 077 078 /** 079 * Creates a Tag from the specified byte array, starting at offset, and for length 080 * <code>length</code>. Presumes <code>bytes</code> content starting at <code>offset</code> is 081 * formatted as a Tag blob. 082 */ 083 public ArrayBackedTag(byte[] bytes, int offset, int length) { 084 if (length > MAX_TAG_LENGTH) { 085 throw new IllegalArgumentException( 086 "Invalid tag data being passed. Its length can not exceed " + MAX_TAG_LENGTH); 087 } 088 this.bytes = bytes; 089 this.offset = offset; 090 this.length = length; 091 this.type = bytes[offset + TAG_LENGTH_SIZE]; 092 } 093 094 /** Returns The byte array backing this Tag. */ 095 @Override 096 public byte[] getValueArray() { 097 return this.bytes; 098 } 099 100 /** Returns the tag type */ 101 @Override 102 public byte getType() { 103 return this.type; 104 } 105 106 /** Returns Length of actual tag bytes within the backed buffer */ 107 @Override 108 public int getValueLength() { 109 return this.length - INFRASTRUCTURE_SIZE; 110 } 111 112 /** Returns Offset of actual tag bytes within the backed buffer */ 113 @Override 114 public int getValueOffset() { 115 return this.offset + INFRASTRUCTURE_SIZE; 116 } 117 118 @Override 119 public boolean hasArray() { 120 return true; 121 } 122 123 @Override 124 public ByteBuffer getValueByteBuffer() { 125 return ByteBuffer.wrap(bytes); 126 } 127 128 @Override 129 public String toString() { 130 return "[Tag type : " + this.type + ", value : " 131 + Bytes.toStringBinary(bytes, getValueOffset(), getValueLength()) + "]"; 132 } 133}