blob: 18cd6a8e4f988da2c78fede383b0e40e801fcf94 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hbase;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.ClassSize;
import org.apache.yetus.audience.InterfaceAudience;
@InterfaceAudience.Private
public class IndividualBytesFieldCell implements ExtendedCell, Cloneable {
// do alignment(padding gap)
private static final long FIXED_OVERHEAD = ClassSize.align(ClassSize.OBJECT // object header
// timestamp and type
+ KeyValue.TIMESTAMP_TYPE_SIZE
// sequence id
+ Bytes.SIZEOF_LONG
// references to all byte arrays: row, family, qualifier, value, tags
+ 5 * ClassSize.REFERENCE);
// The following fields are backed by individual byte arrays
private final byte[] row;
private final int rOffset;
private final int rLength;
private final byte[] family;
private final int fOffset;
private final int fLength;
private final byte[] qualifier;
private final int qOffset;
private final int qLength;
private final byte[] value;
private final int vOffset;
private final int vLength;
private final byte[] tags; // A byte array, rather than an array of org.apache.hadoop.hbase.Tag
private final int tagsOffset;
private final int tagsLength;
// Other fields
private long timestamp;
private final byte type; // A byte, rather than org.apache.hadoop.hbase.KeyValue.Type
private long seqId;
public IndividualBytesFieldCell(byte[] row, byte[] family, byte[] qualifier, long timestamp,
KeyValue.Type type, long seqId, byte[] value, byte[] tags) {
this(row, 0, ArrayUtils.getLength(row), family, 0, ArrayUtils.getLength(family), qualifier, 0,
ArrayUtils.getLength(qualifier), timestamp, type, seqId, value, 0,
ArrayUtils.getLength(value), tags, 0, ArrayUtils.getLength(tags));
}
public IndividualBytesFieldCell(byte[] row, int rOffset, int rLength, byte[] family, int fOffset,
int fLength, byte[] qualifier, int qOffset, int qLength, long timestamp, KeyValue.Type type,
long seqId, byte[] value, int vOffset, int vLength, byte[] tags, int tagsOffset,
int tagsLength) {
// Check row, family, qualifier and value
KeyValue.checkParameters(row, rLength, // row and row length
family, fLength, // family and family length
qLength, // qualifier length
vLength); // value length
// Check timestamp
if (timestamp < 0) {
throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + timestamp);
}
// Check tags
RawCell.checkForTagsLength(tagsLength);
checkArrayBounds(row, rOffset, rLength);
checkArrayBounds(family, fOffset, fLength);
checkArrayBounds(qualifier, qOffset, qLength);
checkArrayBounds(value, vOffset, vLength);
checkArrayBounds(tags, tagsOffset, tagsLength);
// No local copy is made, but reference to the input directly
this.row = row;
this.rOffset = rOffset;
this.rLength = rLength;
this.family = family;
this.fOffset = fOffset;
this.fLength = fLength;
this.qualifier = qualifier;
this.qOffset = qOffset;
this.qLength = qLength;
this.value = value;
this.vOffset = vOffset;
this.vLength = vLength;
this.tags = tags;
this.tagsOffset = tagsOffset;
this.tagsLength = tagsLength;
// Set others
this.timestamp = timestamp;
this.type = type.getCode();
this.seqId = seqId;
}
private void checkArrayBounds(byte[] bytes, int offset, int length) {
if (offset < 0 || length < 0) {
throw new IllegalArgumentException(
"Negative number! offset=" + offset + "and length=" + length);
}
if (bytes == null && (offset != 0 || length != 0)) {
throw new IllegalArgumentException(
"Null bytes array but offset=" + offset + "and length=" + length);
}
if (bytes != null && bytes.length < offset + length) {
throw new IllegalArgumentException("Out of bounds! bytes.length=" + bytes.length + ", offset="
+ offset + ", length=" + length);
}
}
private long heapOverhead() {
return FIXED_OVERHEAD + ClassSize.ARRAY // row , can not be null
+ ((family == null) ? 0 : ClassSize.ARRAY) // family , can be null
+ ((qualifier == null) ? 0 : ClassSize.ARRAY) // qualifier, can be null
+ ((value == null) ? 0 : ClassSize.ARRAY) // value , can be null
+ ((tags == null) ? 0 : ClassSize.ARRAY); // tags , can be null
}
/**
* Implement Cell interface
*/
// 1) Row
@Override
public byte[] getRowArray() {
// If row is null, the constructor will reject it, by {@link KeyValue#checkParameters()},
// so it is safe to return row without checking.
return row;
}
@Override
public int getRowOffset() {
return rOffset;
}
@Override
public short getRowLength() {
// If row is null or rLength is invalid, the constructor will reject it, by
// {@link KeyValue#checkParameters()}, so it is safe to call rLength and make the type
// conversion.
return (short) (rLength);
}
// 2) Family
@Override
public byte[] getFamilyArray() {
// Family could be null
return (family == null) ? HConstants.EMPTY_BYTE_ARRAY : family;
}
@Override
public int getFamilyOffset() {
return fOffset;
}
@Override
public byte getFamilyLength() {
// If fLength is invalid, the constructor will reject it, by {@link KeyValue#checkParameters()},
// so it is safe to make the type conversion.
return (byte) (fLength);
}
// 3) Qualifier
@Override
public byte[] getQualifierArray() {
// Qualifier could be null
return (qualifier == null) ? HConstants.EMPTY_BYTE_ARRAY : qualifier;
}
@Override
public int getQualifierOffset() {
return qOffset;
}
@Override
public int getQualifierLength() {
return qLength;
}
// 4) Timestamp
@Override
public long getTimestamp() {
return timestamp;
}
// 5) Type
@Override
public byte getTypeByte() {
return type;
}
// 6) Sequence id
@Override
public long getSequenceId() {
return seqId;
}
// 7) Value
@Override
public byte[] getValueArray() {
// Value could be null
return (value == null) ? HConstants.EMPTY_BYTE_ARRAY : value;
}
@Override
public int getValueOffset() {
return vOffset;
}
@Override
public int getValueLength() {
return vLength;
}
// 8) Tags
@Override
public byte[] getTagsArray() {
// Tags can could null
return (tags == null) ? HConstants.EMPTY_BYTE_ARRAY : tags;
}
@Override
public int getTagsOffset() {
return tagsOffset;
}
@Override
public int getTagsLength() {
return tagsLength;
}
/**
* Implement HeapSize interface
*/
@Override
public long heapSize() {
// Size of array headers are already included into overhead, so do not need to include it for
// each byte array
return heapOverhead() // overhead, with array headers included
+ ClassSize.align(getRowLength()) // row
+ ClassSize.align(getFamilyLength()) // family
+ ClassSize.align(getQualifierLength()) // qualifier
+ ClassSize.align(getValueLength()) // value
+ ClassSize.align(getTagsLength()); // tags
}
/**
* Implement Cloneable interface
*/
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone(); // only a shadow copy
}
@Override
public void setSequenceId(long seqId) {
if (seqId < 0) {
throw new IllegalArgumentException("Sequence Id cannot be negative. ts=" + seqId);
}
this.seqId = seqId;
}
@Override
public void setTimestamp(long ts) {
if (ts < 0) {
throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + ts);
}
this.timestamp = ts;
}
@Override
public void setTimestamp(byte[] ts) {
setTimestamp(Bytes.toLong(ts, 0));
}
@Override
public String toString() {
return CellUtil.toString(this, false);
}
}