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.io.OutputStream; 022import java.nio.ByteBuffer; 023import org.apache.hadoop.hbase.util.ByteBufferUtils; 024import org.apache.hadoop.hbase.util.Bytes; 025import org.apache.hadoop.hbase.util.ClassSize; 026import org.apache.yetus.audience.InterfaceAudience; 027 028/** 029 * This Cell is an implementation of {@link ByteBufferExtendedCell} where the data resides in off 030 * heap/ on heap ByteBuffer 031 */ 032@InterfaceAudience.Private 033public class ByteBufferKeyValue extends ByteBufferExtendedCell { 034 035 protected final ByteBuffer buf; 036 protected final int offset; 037 protected final int length; 038 private long seqId = 0; 039 040 public static final int FIXED_OVERHEAD = 041 ClassSize.OBJECT + ClassSize.REFERENCE + (2 * Bytes.SIZEOF_INT) + Bytes.SIZEOF_LONG; 042 043 public ByteBufferKeyValue(ByteBuffer buf, int offset, int length, long seqId) { 044 this.buf = buf; 045 this.offset = offset; 046 this.length = length; 047 this.seqId = seqId; 048 } 049 050 public ByteBufferKeyValue(ByteBuffer buf, int offset, int length) { 051 this.buf = buf; 052 this.offset = offset; 053 this.length = length; 054 } 055 056 public ByteBuffer getBuffer() { 057 return this.buf; 058 } 059 060 public int getOffset() { 061 return this.offset; 062 } 063 064 @Override 065 public byte[] getRowArray() { 066 return CellUtil.cloneRow(this); 067 } 068 069 @Override 070 public int getRowOffset() { 071 return 0; 072 } 073 074 @Override 075 public short getRowLength() { 076 return ByteBufferUtils.toShort(this.buf, this.offset + KeyValue.ROW_OFFSET); 077 } 078 079 @Override 080 public byte[] getFamilyArray() { 081 return CellUtil.cloneFamily(this); 082 } 083 084 @Override 085 public int getFamilyOffset() { 086 return 0; 087 } 088 089 @Override 090 public byte getFamilyLength() { 091 return getFamilyLength(getFamilyLengthPosition()); 092 } 093 094 int getFamilyLengthPosition() { 095 return getFamilyLengthPosition(getRowLength()); 096 } 097 098 int getFamilyLengthPosition(int rowLength) { 099 return this.offset + KeyValue.ROW_KEY_OFFSET + rowLength; 100 } 101 102 byte getFamilyLength(int famLenPos) { 103 return ByteBufferUtils.toByte(this.buf, famLenPos); 104 } 105 106 @Override 107 public byte[] getQualifierArray() { 108 return CellUtil.cloneQualifier(this); 109 } 110 111 @Override 112 public int getQualifierOffset() { 113 return 0; 114 } 115 116 @Override 117 public int getQualifierLength() { 118 return getQualifierLength(getKeyLength(), getRowLength(), getFamilyLength()); 119 } 120 121 int getQualifierLength(int keyLength, int rlength, int flength) { 122 return keyLength - (int) KeyValue.getKeyDataStructureSize(rlength, flength, 0); 123 } 124 125 @Override 126 public long getTimestamp() { 127 return getTimestamp(getKeyLength()); 128 } 129 130 long getTimestamp(int keyLength) { 131 int offset = getTimestampOffset(keyLength); 132 return ByteBufferUtils.toLong(this.buf, offset); 133 } 134 135 int getKeyLength() { 136 return ByteBufferUtils.toInt(this.buf, this.offset); 137 } 138 139 private int getTimestampOffset(int keyLen) { 140 return this.offset + KeyValue.ROW_OFFSET + keyLen - KeyValue.TIMESTAMP_TYPE_SIZE; 141 } 142 143 @Override 144 public byte getTypeByte() { 145 return getTypeByte(getKeyLength()); 146 } 147 148 byte getTypeByte(int keyLen) { 149 return ByteBufferUtils.toByte(this.buf, this.offset + keyLen - 1 + KeyValue.ROW_OFFSET); 150 } 151 152 @Override 153 public long getSequenceId() { 154 return this.seqId; 155 } 156 157 @Override 158 public void setSequenceId(long seqId) { 159 this.seqId = seqId; 160 } 161 162 @Override 163 public byte[] getValueArray() { 164 return CellUtil.cloneValue(this); 165 } 166 167 @Override 168 public int getValueOffset() { 169 return 0; 170 } 171 172 @Override 173 public int getValueLength() { 174 return ByteBufferUtils.toInt(this.buf, this.offset + Bytes.SIZEOF_INT); 175 } 176 177 @Override 178 public byte[] getTagsArray() { 179 return CellUtil.cloneTags(this); 180 } 181 182 @Override 183 public int getTagsOffset() { 184 return 0; 185 } 186 187 @Override 188 public int getTagsLength() { 189 int tagsLen = 190 this.length - (getKeyLength() + getValueLength() + KeyValue.KEYVALUE_INFRASTRUCTURE_SIZE); 191 if (tagsLen > 0) { 192 // There are some Tag bytes in the byte[]. So reduce 2 bytes which is 193 // added to denote the tags 194 // length 195 tagsLen -= KeyValue.TAGS_LENGTH_SIZE; 196 } 197 return tagsLen; 198 } 199 200 @Override 201 public ByteBuffer getRowByteBuffer() { 202 return this.buf; 203 } 204 205 @Override 206 public int getRowPosition() { 207 return this.offset + KeyValue.ROW_KEY_OFFSET; 208 } 209 210 @Override 211 public ByteBuffer getFamilyByteBuffer() { 212 return this.buf; 213 } 214 215 @Override 216 public int getFamilyPosition() { 217 return getFamilyPosition(getFamilyLengthPosition()); 218 } 219 220 public int getFamilyPosition(int familyLengthPosition) { 221 return familyLengthPosition + Bytes.SIZEOF_BYTE; 222 } 223 224 @Override 225 public ByteBuffer getQualifierByteBuffer() { 226 return this.buf; 227 } 228 229 @Override 230 public int getQualifierPosition() { 231 return getQualifierPosition(getFamilyPosition(), getFamilyLength()); 232 } 233 234 int getQualifierPosition(int familyPosition, int familyLength) { 235 return familyPosition + familyLength; 236 } 237 238 @Override 239 public ByteBuffer getValueByteBuffer() { 240 return this.buf; 241 } 242 243 @Override 244 public int getValuePosition() { 245 return this.offset + KeyValue.ROW_OFFSET + getKeyLength(); 246 } 247 248 @Override 249 public ByteBuffer getTagsByteBuffer() { 250 return this.buf; 251 } 252 253 @Override 254 public int getTagsPosition() { 255 int tagsLen = getTagsLength(); 256 if (tagsLen == 0) { 257 return this.offset + this.length; 258 } 259 return this.offset + this.length - tagsLen; 260 } 261 262 @Override 263 public long heapSize() { 264 if (this.buf.hasArray()) { 265 return ClassSize.align(FIXED_OVERHEAD + length); 266 } 267 return (long) ClassSize.align(FIXED_OVERHEAD) + this.getSerializedSize(); 268 } 269 270 @Override 271 public int write(OutputStream out, boolean withTags) throws IOException { 272 int length = getSerializedSize(withTags); 273 ByteBufferUtils.copyBufferToStream(out, this.buf, this.offset, length); 274 return length; 275 } 276 277 @Override 278 public int getSerializedSize(boolean withTags) { 279 if (withTags) { 280 return this.length; 281 } 282 return getKeyLength() + this.getValueLength() + KeyValue.KEYVALUE_INFRASTRUCTURE_SIZE; 283 } 284 285 @Override 286 public int getSerializedSize() { 287 return this.length; 288 } 289 290 @Override 291 public void write(ByteBuffer buf, int offset) { 292 ByteBufferUtils.copyFromBufferToBuffer(this.buf, buf, this.offset, offset, this.length); 293 } 294 295 @Override 296 public String toString() { 297 return CellUtil.toString(this, false); 298 } 299 300 @Override 301 public void setTimestamp(long ts) throws IOException { 302 ByteBufferUtils.copyFromArrayToBuffer(this.buf, this.getTimestampOffset(), Bytes.toBytes(ts), 0, 303 Bytes.SIZEOF_LONG); 304 } 305 306 private int getTimestampOffset() { 307 return this.offset + KeyValue.KEYVALUE_INFRASTRUCTURE_SIZE + getKeyLength() 308 - KeyValue.TIMESTAMP_TYPE_SIZE; 309 } 310 311 @Override 312 public void setTimestamp(byte[] ts) throws IOException { 313 ByteBufferUtils.copyFromArrayToBuffer(this.buf, this.getTimestampOffset(), ts, 0, 314 Bytes.SIZEOF_LONG); 315 } 316 317 @Override 318 public ExtendedCell deepClone() { 319 byte[] copy = new byte[this.length]; 320 ByteBufferUtils.copyFromBufferToArray(copy, this.buf, this.offset, 0, this.length); 321 KeyValue kv = new KeyValue(copy, 0, copy.length); 322 kv.setSequenceId(this.getSequenceId()); 323 return kv; 324 } 325 326 /** 327 * Needed doing 'contains' on List. Only compares the key portion, not the value. 328 */ 329 @Override 330 public boolean equals(Object other) { 331 if (!(other instanceof Cell)) { 332 return false; 333 } 334 return CellUtil.equals(this, (Cell) other); 335 } 336 337 /** 338 * In line with {@link #equals(Object)}, only uses the key portion, not the value. 339 */ 340 @Override 341 public int hashCode() { 342 return calculateHashForKey(this); 343 } 344 345 private int calculateHashForKey(ByteBufferExtendedCell cell) { 346 int rowHash = 347 ByteBufferUtils.hashCode(cell.getRowByteBuffer(), cell.getRowPosition(), cell.getRowLength()); 348 int familyHash = ByteBufferUtils.hashCode(cell.getFamilyByteBuffer(), cell.getFamilyPosition(), 349 cell.getFamilyLength()); 350 int qualifierHash = ByteBufferUtils.hashCode(cell.getQualifierByteBuffer(), 351 cell.getQualifierPosition(), cell.getQualifierLength()); 352 353 int hash = 31 * rowHash + familyHash; 354 hash = 31 * hash + qualifierHash; 355 hash = 31 * hash + (int) cell.getTimestamp(); 356 hash = 31 * hash + cell.getTypeByte(); 357 return hash; 358 } 359}