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.io.IOException; 021import java.util.ArrayList; 022import java.util.Iterator; 023import java.util.List; 024import org.apache.hadoop.hbase.io.util.StreamUtils; 025import org.apache.hadoop.hbase.util.ByteBufferUtils; 026import org.apache.hadoop.hbase.util.Bytes; 027import org.apache.hadoop.hbase.util.Pair; 028import org.apache.yetus.audience.InterfaceAudience; 029 030@InterfaceAudience.Private 031public final class TagUtil { 032 033 private TagUtil() { 034 } 035 036 /** 037 * Creates list of tags from given byte array, expected that it is in the expected tag format. 038 * @param b The byte array 039 * @param offset The offset in array where tag bytes begin 040 * @param length Total length of all tags bytes 041 * @return List of tags 042 */ 043 public static List<Tag> asList(byte[] b, int offset, int length) { 044 List<Tag> tags = new ArrayList<>(); 045 int pos = offset; 046 while (pos < offset + length) { 047 int tagLen = Bytes.readAsInt(b, pos, Tag.TAG_LENGTH_SIZE); 048 tags.add(new ArrayBackedTag(b, pos, tagLen + Tag.TAG_LENGTH_SIZE)); 049 pos += Tag.TAG_LENGTH_SIZE + tagLen; 050 } 051 return tags; 052 } 053 054 /** 055 * Reads an int value stored as a VInt at tag's given offset. 056 * @param tag The Tag 057 * @param offset The offset where VInt bytes begin 058 * @return A pair of the int value and number of bytes taken to store VInt 059 * @throws IOException When varint is malformed and not able to be read correctly 060 */ 061 public static Pair<Integer, Integer> readVIntValuePart(Tag tag, int offset) throws IOException { 062 if (tag.hasArray()) { 063 return StreamUtils.readRawVarint32(tag.getValueArray(), offset); 064 } 065 return StreamUtils.readRawVarint32(tag.getValueByteBuffer(), offset); 066 } 067 068 /** Returns A List<Tag> of any Tags found in <code>cell</code> else null. */ 069 public static List<Tag> carryForwardTags(final ExtendedCell cell) { 070 return carryForwardTags(null, cell); 071 } 072 073 /** Add to <code>tagsOrNull</code> any Tags <code>cell</code> is carrying or null if none. */ 074 public static List<Tag> carryForwardTags(final List<Tag> tagsOrNull, final ExtendedCell cell) { 075 Iterator<Tag> itr = PrivateCellUtil.tagsIterator(cell); 076 if (itr == EMPTY_TAGS_ITR) { 077 // If no Tags, return early. 078 return tagsOrNull; 079 } 080 List<Tag> tags = tagsOrNull; 081 if (tags == null) { 082 tags = new ArrayList<>(); 083 } 084 while (itr.hasNext()) { 085 tags.add(itr.next()); 086 } 087 return tags; 088 } 089 090 public static byte[] concatTags(byte[] tags, ExtendedCell cell) { 091 int cellTagsLen = cell.getTagsLength(); 092 if (cellTagsLen == 0) { 093 // If no Tags, return early. 094 return tags; 095 } 096 byte[] b = new byte[tags.length + cellTagsLen]; 097 int pos = Bytes.putBytes(b, 0, tags, 0, tags.length); 098 if (cell instanceof ByteBufferExtendedCell) { 099 ByteBufferUtils.copyFromBufferToArray(b, ((ByteBufferExtendedCell) cell).getTagsByteBuffer(), 100 ((ByteBufferExtendedCell) cell).getTagsPosition(), pos, cellTagsLen); 101 } else { 102 Bytes.putBytes(b, pos, cell.getTagsArray(), cell.getTagsOffset(), cellTagsLen); 103 } 104 return b; 105 } 106 107 /** Returns Carry forward the TTL tag. */ 108 public static List<Tag> carryForwardTTLTag(final List<Tag> tagsOrNull, final long ttl) { 109 if (ttl == Long.MAX_VALUE) { 110 return tagsOrNull; 111 } 112 List<Tag> tags = tagsOrNull; 113 // If we are making the array in here, given we are the last thing checked, we'll be only thing 114 // in the array so set its size to '1' (I saw this being done in earlier version of 115 // tag-handling). 116 if (tags == null) { 117 tags = new ArrayList<>(1); 118 } else { 119 // Remove existing TTL tags if any 120 Iterator<Tag> tagsItr = tags.iterator(); 121 while (tagsItr.hasNext()) { 122 Tag tag = tagsItr.next(); 123 if (tag.getType() == TagType.TTL_TAG_TYPE) { 124 tagsItr.remove(); 125 break; 126 } 127 } 128 } 129 tags.add(new ArrayBackedTag(TagType.TTL_TAG_TYPE, Bytes.toBytes(ttl))); 130 return tags; 131 } 132 133 /** 134 * Write a list of tags into a byte array Note : these are all purely internal APIs. It helps in 135 * cases where we have set of tags and we would want to create a cell out of it. Say in Mobs we 136 * create a reference tags to indicate the presence of mob data. Also note that these are not 137 * exposed to CPs also 138 * @param tags The list of tags 139 * @return the serialized tag data as bytes 140 */ 141 public static byte[] fromList(List<Tag> tags) { 142 if (tags == null || tags.isEmpty()) { 143 return HConstants.EMPTY_BYTE_ARRAY; 144 } 145 int length = 0; 146 for (Tag tag : tags) { 147 length += tag.getValueLength() + Tag.INFRASTRUCTURE_SIZE; 148 } 149 byte[] b = new byte[length]; 150 int pos = 0; 151 int tlen; 152 for (Tag tag : tags) { 153 tlen = tag.getValueLength(); 154 pos = Bytes.putAsShort(b, pos, tlen + Tag.TYPE_LENGTH_SIZE); 155 pos = Bytes.putByte(b, pos, tag.getType()); 156 if (tag.hasArray()) { 157 pos = Bytes.putBytes(b, pos, tag.getValueArray(), tag.getValueOffset(), tlen); 158 } else { 159 ByteBufferUtils.copyFromBufferToArray(b, tag.getValueByteBuffer(), tag.getValueOffset(), 160 pos, tlen); 161 pos += tlen; 162 } 163 } 164 return b; 165 } 166 167 /** Iterator returned when no Tags. Used by CellUtil too. */ 168 static final Iterator<Tag> EMPTY_TAGS_ITR = new Iterator<Tag>() { 169 @Override 170 public boolean hasNext() { 171 return false; 172 } 173 174 @Override 175 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "IT_NO_SUCH_ELEMENT", 176 justification = "Intentional") 177 public Tag next() { 178 return null; 179 } 180 181 @Override 182 public void remove() { 183 throw new UnsupportedOperationException(); 184 } 185 }; 186}