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