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