001/** 002 * Copyright The Apache Software Foundation 003 * 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020package org.apache.hadoop.hbase; 021 022import java.nio.ByteBuffer; 023 024import org.apache.hadoop.hbase.util.Bytes; 025import org.apache.yetus.audience.InterfaceAudience; 026import org.apache.yetus.audience.InterfaceStability; 027 028/** 029 * This is a {@link Tag} implementation in which value is backed by an on heap byte array. 030 */ 031@InterfaceAudience.Private 032@InterfaceStability.Evolving 033public class ArrayBackedTag implements Tag { 034 private final byte type;// TODO extra type state needed? 035 private final byte[] bytes; 036 private int offset = 0; 037 private int length = 0; 038 039 /** 040 * The special tag will write the length of each tag and that will be 041 * followed by the type and then the actual tag. 042 * So every time the length part is parsed we need to add + 1 byte to it to 043 * get the type and then get the actual tag. 044 */ 045 public ArrayBackedTag(byte tagType, String tag) { 046 this(tagType, Bytes.toBytes(tag)); 047 } 048 049 /** 050 * Format for a tag : 051 * {@code <length of tag - 2 bytes><type code - 1 byte><tag>} tag length is serialized 052 * using 2 bytes only but as this will be unsigned, we can have max tag length of 053 * (Short.MAX_SIZE * 2) +1. It includes 1 byte type length and actual tag bytes length. 054 */ 055 public ArrayBackedTag(byte tagType, byte[] tag) { 056 int tagLength = tag.length + TYPE_LENGTH_SIZE; 057 if (tagLength > MAX_TAG_LENGTH) { 058 throw new IllegalArgumentException( 059 "Invalid tag data being passed. Its length can not exceed " + MAX_TAG_LENGTH); 060 } 061 length = TAG_LENGTH_SIZE + tagLength; 062 bytes = new byte[length]; 063 int pos = Bytes.putAsShort(bytes, 0, tagLength); 064 pos = Bytes.putByte(bytes, pos, tagType); 065 Bytes.putBytes(bytes, pos, tag, 0, tag.length); 066 this.type = tagType; 067 } 068 069 /** 070 * Creates a Tag from the specified byte array and offset. Presumes 071 * <code>bytes</code> content starting at <code>offset</code> is formatted as 072 * a Tag blob. 073 * The bytes to include the tag type, tag length and actual tag bytes. 074 * @param offset offset to start of Tag 075 */ 076 public ArrayBackedTag(byte[] bytes, int offset) { 077 this(bytes, offset, getLength(bytes, offset)); 078 } 079 080 private static int getLength(byte[] bytes, int offset) { 081 return TAG_LENGTH_SIZE + Bytes.readAsInt(bytes, offset, TAG_LENGTH_SIZE); 082 } 083 084 /** 085 * Creates a Tag from the specified byte array, starting at offset, and for length 086 * <code>length</code>. Presumes <code>bytes</code> content starting at <code>offset</code> is 087 * formatted as a Tag blob. 088 */ 089 public ArrayBackedTag(byte[] bytes, int offset, int length) { 090 if (length > MAX_TAG_LENGTH) { 091 throw new IllegalArgumentException( 092 "Invalid tag data being passed. Its length can not exceed " + MAX_TAG_LENGTH); 093 } 094 this.bytes = bytes; 095 this.offset = offset; 096 this.length = length; 097 this.type = bytes[offset + TAG_LENGTH_SIZE]; 098 } 099 100 /** 101 * @return The byte array backing this Tag. 102 */ 103 @Override 104 public byte[] getValueArray() { 105 return this.bytes; 106 } 107 108 /** 109 * @return the tag type 110 */ 111 @Override 112 public byte getType() { 113 return this.type; 114 } 115 116 /** 117 * @return Length of actual tag bytes within the backed buffer 118 */ 119 @Override 120 public int getValueLength() { 121 return this.length - INFRASTRUCTURE_SIZE; 122 } 123 124 /** 125 * @return Offset of actual tag bytes within the backed buffer 126 */ 127 @Override 128 public int getValueOffset() { 129 return this.offset + INFRASTRUCTURE_SIZE; 130 } 131 132 @Override 133 public boolean hasArray() { 134 return true; 135 } 136 137 @Override 138 public ByteBuffer getValueByteBuffer() { 139 return ByteBuffer.wrap(bytes); 140 } 141 142 @Override 143 public String toString() { 144 return "[Tag type : " + this.type + ", value : " 145 + Bytes.toStringBinary(bytes, getValueOffset(), getValueLength()) + "]"; 146 } 147}