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