| /* |
| * 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); |
| } |
| } |