2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package org
.apache
.hadoop
.hbase
;
20 import java
.io
.IOException
;
21 import java
.io
.OutputStream
;
22 import java
.nio
.ByteBuffer
;
23 import org
.apache
.hadoop
.hbase
.util
.ByteBufferUtils
;
24 import org
.apache
.hadoop
.hbase
.util
.Bytes
;
25 import org
.apache
.hadoop
.hbase
.util
.ClassSize
;
26 import org
.apache
.yetus
.audience
.InterfaceAudience
;
28 import org
.apache
.hbase
.thirdparty
.com
.google
.common
.annotations
.VisibleForTesting
;
31 * This Cell is an implementation of {@link ByteBufferExtendedCell} where the data resides in
32 * off heap/ on heap ByteBuffer
34 @InterfaceAudience.Private
35 public class ByteBufferKeyValue
extends ByteBufferExtendedCell
{
37 protected final ByteBuffer buf
;
38 protected final int offset
;
39 protected final int length
;
40 private long seqId
= 0;
42 public static final int FIXED_OVERHEAD
= ClassSize
.OBJECT
+ ClassSize
.REFERENCE
43 + (2 * Bytes
.SIZEOF_INT
) + Bytes
.SIZEOF_LONG
;
45 public ByteBufferKeyValue(ByteBuffer buf
, int offset
, int length
, long seqId
) {
52 public ByteBufferKeyValue(ByteBuffer buf
, int offset
, int length
) {
59 public ByteBuffer
getBuffer() {
64 public int getOffset() {
69 public byte[] getRowArray() {
70 return CellUtil
.cloneRow(this);
74 public int getRowOffset() {
79 public short getRowLength() {
80 return ByteBufferUtils
.toShort(this.buf
, this.offset
+ KeyValue
.ROW_OFFSET
);
84 public byte[] getFamilyArray() {
85 return CellUtil
.cloneFamily(this);
89 public int getFamilyOffset() {
94 public byte getFamilyLength() {
95 return getFamilyLength(getFamilyLengthPosition());
98 int getFamilyLengthPosition() {
99 return getFamilyLengthPosition(getRowLength());
102 int getFamilyLengthPosition(int rowLength
) {
103 return this.offset
+ KeyValue
.ROW_KEY_OFFSET
+ rowLength
;
106 byte getFamilyLength(int famLenPos
) {
107 return ByteBufferUtils
.toByte(this.buf
, famLenPos
);
111 public byte[] getQualifierArray() {
112 return CellUtil
.cloneQualifier(this);
116 public int getQualifierOffset() {
121 public int getQualifierLength() {
122 return getQualifierLength(getKeyLength(), getRowLength(), getFamilyLength());
125 int getQualifierLength(int keyLength
, int rlength
, int flength
) {
126 return keyLength
- (int) KeyValue
.getKeyDataStructureSize(rlength
, flength
, 0);
130 public long getTimestamp() {
131 return getTimestamp(getKeyLength());
134 long getTimestamp(int keyLength
) {
135 int offset
= getTimestampOffset(keyLength
);
136 return ByteBufferUtils
.toLong(this.buf
, offset
);
140 return ByteBufferUtils
.toInt(this.buf
, this.offset
);
143 private int getTimestampOffset(int keyLen
) {
144 return this.offset
+ KeyValue
.ROW_OFFSET
+ keyLen
- KeyValue
.TIMESTAMP_TYPE_SIZE
;
148 public byte getTypeByte() {
149 return getTypeByte(getKeyLength());
152 byte getTypeByte(int keyLen
) {
153 return ByteBufferUtils
.toByte(this.buf
, this.offset
+ keyLen
- 1 + KeyValue
.ROW_OFFSET
);
157 public long getSequenceId() {
162 public void setSequenceId(long seqId
) {
167 public byte[] getValueArray() {
168 return CellUtil
.cloneValue(this);
172 public int getValueOffset() {
177 public int getValueLength() {
178 return ByteBufferUtils
.toInt(this.buf
, this.offset
+ Bytes
.SIZEOF_INT
);
182 public byte[] getTagsArray() {
183 return PrivateCellUtil
.cloneTags(this);
187 public int getTagsOffset() {
192 public int getTagsLength() {
193 int tagsLen
= this.length
- (getKeyLength() + getValueLength()
194 + KeyValue
.KEYVALUE_INFRASTRUCTURE_SIZE
);
196 // There are some Tag bytes in the byte[]. So reduce 2 bytes which is
197 // added to denote the tags
199 tagsLen
-= KeyValue
.TAGS_LENGTH_SIZE
;
205 public ByteBuffer
getRowByteBuffer() {
210 public int getRowPosition() {
211 return this.offset
+ KeyValue
.ROW_KEY_OFFSET
;
215 public ByteBuffer
getFamilyByteBuffer() {
220 public int getFamilyPosition() {
221 return getFamilyPosition(getFamilyLengthPosition());
224 public int getFamilyPosition(int familyLengthPosition
) {
225 return familyLengthPosition
+ Bytes
.SIZEOF_BYTE
;
229 public ByteBuffer
getQualifierByteBuffer() {
234 public int getQualifierPosition() {
235 return getQualifierPosition(getFamilyPosition(), getFamilyLength());
238 int getQualifierPosition(int familyPosition
, int familyLength
) {
239 return familyPosition
+ familyLength
;
243 public ByteBuffer
getValueByteBuffer() {
248 public int getValuePosition() {
249 return this.offset
+ KeyValue
.ROW_OFFSET
+ getKeyLength();
253 public ByteBuffer
getTagsByteBuffer() {
258 public int getTagsPosition() {
259 int tagsLen
= getTagsLength();
261 return this.offset
+ this.length
;
263 return this.offset
+ this.length
- tagsLen
;
267 public long heapSize() {
268 if (this.buf
.hasArray()) {
269 return ClassSize
.align(FIXED_OVERHEAD
+ length
);
271 return ClassSize
.align(FIXED_OVERHEAD
) + this.getSerializedSize();
275 public int write(OutputStream out
, boolean withTags
) throws IOException
{
276 int length
= getSerializedSize(withTags
);
277 ByteBufferUtils
.copyBufferToStream(out
, this.buf
, this.offset
, length
);
282 public int getSerializedSize(boolean withTags
) {
286 return getKeyLength() + this.getValueLength() + KeyValue
.KEYVALUE_INFRASTRUCTURE_SIZE
;
290 public int getSerializedSize() {
295 public void write(ByteBuffer buf
, int offset
) {
296 ByteBufferUtils
.copyFromBufferToBuffer(this.buf
, buf
, this.offset
, offset
, this.length
);
300 public String
toString() {
301 return CellUtil
.toString(this, true);
305 public void setTimestamp(long ts
) throws IOException
{
306 ByteBufferUtils
.copyFromArrayToBuffer(this.buf
, this.getTimestampOffset(), Bytes
.toBytes(ts
), 0,
310 private int getTimestampOffset() {
311 return this.offset
+ KeyValue
.KEYVALUE_INFRASTRUCTURE_SIZE
312 + getKeyLength() - KeyValue
.TIMESTAMP_TYPE_SIZE
;
316 public void setTimestamp(byte[] ts
) throws IOException
{
317 ByteBufferUtils
.copyFromArrayToBuffer(this.buf
, this.getTimestampOffset(), ts
, 0,
322 public ExtendedCell
deepClone() {
323 byte[] copy
= new byte[this.length
];
324 ByteBufferUtils
.copyFromBufferToArray(copy
, this.buf
, this.offset
, 0, this.length
);
325 KeyValue kv
= new KeyValue(copy
, 0, copy
.length
);
326 kv
.setSequenceId(this.getSequenceId());
331 * Needed doing 'contains' on List. Only compares the key portion, not the value.
334 public boolean equals(Object other
) {
335 if (!(other
instanceof Cell
)) {
338 return CellUtil
.equals(this, (Cell
) other
);
342 * In line with {@link #equals(Object)}, only uses the key portion, not the value.
345 public int hashCode() {
346 return calculateHashForKey(this);
349 private int calculateHashForKey(ByteBufferExtendedCell cell
) {
350 int rowHash
= ByteBufferUtils
.hashCode(cell
.getRowByteBuffer(), cell
.getRowPosition(),
351 cell
.getRowLength());
352 int familyHash
= ByteBufferUtils
.hashCode(cell
.getFamilyByteBuffer(), cell
.getFamilyPosition(),
353 cell
.getFamilyLength());
354 int qualifierHash
= ByteBufferUtils
.hashCode(cell
.getQualifierByteBuffer(),
355 cell
.getQualifierPosition(), cell
.getQualifierLength());
357 int hash
= 31 * rowHash
+ familyHash
;
358 hash
= 31 * hash
+ qualifierHash
;
359 hash
= 31 * hash
+ (int) cell
.getTimestamp();
360 hash
= 31 * hash
+ cell
.getTypeByte();