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 org.apache.commons.lang3.ArrayUtils; 021import org.apache.hadoop.hbase.util.Bytes; 022import org.apache.hadoop.hbase.util.ClassSize; 023import org.apache.yetus.audience.InterfaceAudience; 024 025@InterfaceAudience.Private 026public class IndividualBytesFieldCell implements ExtendedCell, Cloneable { 027 // do alignment(padding gap) 028 private static final long FIXED_OVERHEAD = ClassSize.align(ClassSize.OBJECT // object header 029 // timestamp and type 030 + KeyValue.TIMESTAMP_TYPE_SIZE 031 // sequence id 032 + Bytes.SIZEOF_LONG 033 // references to all byte arrays: row, family, qualifier, value, tags 034 + 5 * ClassSize.REFERENCE); 035 036 // The following fields are backed by individual byte arrays 037 private final byte[] row; 038 private final int rOffset; 039 private final int rLength; 040 private final byte[] family; 041 private final int fOffset; 042 private final int fLength; 043 private final byte[] qualifier; 044 private final int qOffset; 045 private final int qLength; 046 private final byte[] value; 047 private final int vOffset; 048 private final int vLength; 049 private final byte[] tags; // A byte array, rather than an array of org.apache.hadoop.hbase.Tag 050 private final int tagsOffset; 051 private final int tagsLength; 052 053 // Other fields 054 private long timestamp; 055 private final byte type; // A byte, rather than org.apache.hadoop.hbase.KeyValue.Type 056 private long seqId; 057 058 public IndividualBytesFieldCell(byte[] row, byte[] family, byte[] qualifier, long timestamp, 059 KeyValue.Type type, long seqId, byte[] value, byte[] tags) { 060 this(row, 0, ArrayUtils.getLength(row), family, 0, ArrayUtils.getLength(family), qualifier, 0, 061 ArrayUtils.getLength(qualifier), timestamp, type, seqId, value, 0, 062 ArrayUtils.getLength(value), tags, 0, ArrayUtils.getLength(tags)); 063 } 064 065 public IndividualBytesFieldCell(byte[] row, int rOffset, int rLength, byte[] family, int fOffset, 066 int fLength, byte[] qualifier, int qOffset, int qLength, long timestamp, KeyValue.Type type, 067 long seqId, byte[] value, int vOffset, int vLength, byte[] tags, int tagsOffset, 068 int tagsLength) { 069 // Check row, family, qualifier and value 070 KeyValue.checkParameters(row, rLength, // row and row length 071 family, fLength, // family and family length 072 qLength, // qualifier length 073 vLength); // value length 074 075 // Check timestamp 076 if (timestamp < 0) { 077 throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + timestamp); 078 } 079 080 // Check tags 081 RawCell.checkForTagsLength(tagsLength); 082 checkArrayBounds(row, rOffset, rLength); 083 checkArrayBounds(family, fOffset, fLength); 084 checkArrayBounds(qualifier, qOffset, qLength); 085 checkArrayBounds(value, vOffset, vLength); 086 checkArrayBounds(tags, tagsOffset, tagsLength); 087 // No local copy is made, but reference to the input directly 088 this.row = row; 089 this.rOffset = rOffset; 090 this.rLength = rLength; 091 this.family = family; 092 this.fOffset = fOffset; 093 this.fLength = fLength; 094 this.qualifier = qualifier; 095 this.qOffset = qOffset; 096 this.qLength = qLength; 097 this.value = value; 098 this.vOffset = vOffset; 099 this.vLength = vLength; 100 this.tags = tags; 101 this.tagsOffset = tagsOffset; 102 this.tagsLength = tagsLength; 103 104 // Set others 105 this.timestamp = timestamp; 106 this.type = type.getCode(); 107 this.seqId = seqId; 108 } 109 110 private void checkArrayBounds(byte[] bytes, int offset, int length) { 111 if (offset < 0 || length < 0) { 112 throw new IllegalArgumentException( 113 "Negative number! offset=" + offset + "and length=" + length); 114 } 115 if (bytes == null && (offset != 0 || length != 0)) { 116 throw new IllegalArgumentException( 117 "Null bytes array but offset=" + offset + "and length=" + length); 118 } 119 if (bytes != null && bytes.length < offset + length) { 120 throw new IllegalArgumentException("Out of bounds! bytes.length=" + bytes.length + ", offset=" 121 + offset + ", length=" + length); 122 } 123 } 124 125 private long heapOverhead() { 126 return FIXED_OVERHEAD + ClassSize.ARRAY // row , can not be null 127 + ((family == null) ? 0 : ClassSize.ARRAY) // family , can be null 128 + ((qualifier == null) ? 0 : ClassSize.ARRAY) // qualifier, can be null 129 + ((value == null) ? 0 : ClassSize.ARRAY) // value , can be null 130 + ((tags == null) ? 0 : ClassSize.ARRAY); // tags , can be null 131 } 132 133 /** 134 * Implement Cell interface 135 */ 136 // 1) Row 137 @Override 138 public byte[] getRowArray() { 139 // If row is null, the constructor will reject it, by {@link KeyValue#checkParameters()}, 140 // so it is safe to return row without checking. 141 return row; 142 } 143 144 @Override 145 public int getRowOffset() { 146 return rOffset; 147 } 148 149 @Override 150 public short getRowLength() { 151 // If row is null or rLength is invalid, the constructor will reject it, by 152 // {@link KeyValue#checkParameters()}, so it is safe to call rLength and make the type 153 // conversion. 154 return (short) rLength; 155 } 156 157 // 2) Family 158 @Override 159 public byte[] getFamilyArray() { 160 // Family could be null 161 return (family == null) ? HConstants.EMPTY_BYTE_ARRAY : family; 162 } 163 164 @Override 165 public int getFamilyOffset() { 166 return fOffset; 167 } 168 169 @Override 170 public byte getFamilyLength() { 171 // If fLength is invalid, the constructor will reject it, by {@link KeyValue#checkParameters()}, 172 // so it is safe to make the type conversion. 173 return (byte) fLength; 174 } 175 176 // 3) Qualifier 177 @Override 178 public byte[] getQualifierArray() { 179 // Qualifier could be null 180 return (qualifier == null) ? HConstants.EMPTY_BYTE_ARRAY : qualifier; 181 } 182 183 @Override 184 public int getQualifierOffset() { 185 return qOffset; 186 } 187 188 @Override 189 public int getQualifierLength() { 190 return qLength; 191 } 192 193 // 4) Timestamp 194 @Override 195 public long getTimestamp() { 196 return timestamp; 197 } 198 199 // 5) Type 200 @Override 201 public byte getTypeByte() { 202 return type; 203 } 204 205 // 6) Sequence id 206 @Override 207 public long getSequenceId() { 208 return seqId; 209 } 210 211 // 7) Value 212 @Override 213 public byte[] getValueArray() { 214 // Value could be null 215 return (value == null) ? HConstants.EMPTY_BYTE_ARRAY : value; 216 } 217 218 @Override 219 public int getValueOffset() { 220 return vOffset; 221 } 222 223 @Override 224 public int getValueLength() { 225 return vLength; 226 } 227 228 // 8) Tags 229 @Override 230 public byte[] getTagsArray() { 231 // Tags can could null 232 return (tags == null) ? HConstants.EMPTY_BYTE_ARRAY : tags; 233 } 234 235 @Override 236 public int getTagsOffset() { 237 return tagsOffset; 238 } 239 240 @Override 241 public int getTagsLength() { 242 return tagsLength; 243 } 244 245 /** 246 * Implement HeapSize interface 247 */ 248 @Override 249 public long heapSize() { 250 // Size of array headers are already included into overhead, so do not need to include it for 251 // each byte array 252 return heapOverhead() // overhead, with array headers included 253 + ClassSize.align(getRowLength()) // row 254 + ClassSize.align(getFamilyLength()) // family 255 + ClassSize.align(getQualifierLength()) // qualifier 256 + ClassSize.align(getValueLength()) // value 257 + ClassSize.align(getTagsLength()); // tags 258 } 259 260 /** 261 * Implement Cloneable interface 262 */ 263 @Override 264 public Object clone() throws CloneNotSupportedException { 265 return super.clone(); // only a shadow copy 266 } 267 268 @Override 269 public void setSequenceId(long seqId) { 270 if (seqId < 0) { 271 throw new IllegalArgumentException("Sequence Id cannot be negative. ts=" + seqId); 272 } 273 this.seqId = seqId; 274 } 275 276 @Override 277 public void setTimestamp(long ts) { 278 if (ts < 0) { 279 throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + ts); 280 } 281 this.timestamp = ts; 282 } 283 284 @Override 285 public void setTimestamp(byte[] ts) { 286 setTimestamp(Bytes.toLong(ts, 0)); 287 } 288 289 @Override 290 public String toString() { 291 return CellUtil.toString(this, false); 292 } 293}