HBASE-26921 Rewrite the counting cells part in TestMultiVersions (#4316)
[hbase.git] / hbase-common / src / main / java / org / apache / hadoop / hbase / PrivateCellUtil.java
blob810eb24504abfee90812c453f561a3e03dbf396a
1 /*
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 static org.apache.hadoop.hbase.HConstants.EMPTY_BYTE_ARRAY;
21 import static org.apache.hadoop.hbase.Tag.TAG_LENGTH_SIZE;
23 import java.io.DataOutput;
24 import java.io.DataOutputStream;
25 import java.io.IOException;
26 import java.io.OutputStream;
27 import java.math.BigDecimal;
28 import java.nio.ByteBuffer;
29 import java.util.ArrayList;
30 import java.util.Iterator;
31 import java.util.List;
32 import java.util.Optional;
33 import org.apache.hadoop.hbase.filter.ByteArrayComparable;
34 import org.apache.hadoop.hbase.io.TagCompressionContext;
35 import org.apache.hadoop.hbase.io.util.Dictionary;
36 import org.apache.hadoop.hbase.io.util.StreamUtils;
37 import org.apache.hadoop.hbase.util.ByteBufferUtils;
38 import org.apache.hadoop.hbase.util.ByteRange;
39 import org.apache.hadoop.hbase.util.Bytes;
40 import org.apache.hadoop.hbase.util.ClassSize;
41 import org.apache.yetus.audience.InterfaceAudience;
43 /**
44 * Utility methods helpful slinging {@link Cell} instances. It has more powerful and
45 * rich set of APIs than those in {@link CellUtil} for internal usage.
47 @InterfaceAudience.Private
48 public final class PrivateCellUtil {
50 /**
51 * Private constructor to keep this class from being instantiated.
53 private PrivateCellUtil() {
56 /******************* ByteRange *******************************/
58 public static ByteRange fillRowRange(Cell cell, ByteRange range) {
59 return range.set(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
62 public static ByteRange fillFamilyRange(Cell cell, ByteRange range) {
63 return range.set(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength());
66 public static ByteRange fillQualifierRange(Cell cell, ByteRange range) {
67 return range.set(cell.getQualifierArray(), cell.getQualifierOffset(),
68 cell.getQualifierLength());
71 public static ByteRange fillValueRange(Cell cell, ByteRange range) {
72 return range.set(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength());
75 public static ByteRange fillTagRange(Cell cell, ByteRange range) {
76 return range.set(cell.getTagsArray(), cell.getTagsOffset(), cell.getTagsLength());
79 /********************* misc *************************************/
81 public static byte getRowByte(Cell cell, int index) {
82 if (cell instanceof ByteBufferExtendedCell) {
83 return ((ByteBufferExtendedCell) cell).getRowByteBuffer()
84 .get(((ByteBufferExtendedCell) cell).getRowPosition() + index);
86 return cell.getRowArray()[cell.getRowOffset() + index];
89 public static byte getQualifierByte(Cell cell, int index) {
90 if (cell instanceof ByteBufferExtendedCell) {
91 return ((ByteBufferExtendedCell) cell).getQualifierByteBuffer()
92 .get(((ByteBufferExtendedCell) cell).getQualifierPosition() + index);
94 return cell.getQualifierArray()[cell.getQualifierOffset() + index];
97 public static ByteBuffer getValueBufferShallowCopy(Cell cell) {
98 ByteBuffer buffer =
99 ByteBuffer.wrap(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength());
100 return buffer;
104 * @return A new cell which is having the extra tags also added to it.
106 public static Cell createCell(Cell cell, List<Tag> tags) {
107 return createCell(cell, TagUtil.fromList(tags));
111 * @return A new cell which is having the extra tags also added to it.
113 public static Cell createCell(Cell cell, byte[] tags) {
114 if (cell instanceof ByteBufferExtendedCell) {
115 return new TagRewriteByteBufferExtendedCell((ByteBufferExtendedCell) cell, tags);
117 return new TagRewriteCell(cell, tags);
120 public static Cell createCell(Cell cell, byte[] value, byte[] tags) {
121 if (cell instanceof ByteBufferExtendedCell) {
122 return new ValueAndTagRewriteByteBufferExtendedCell((ByteBufferExtendedCell) cell,
123 value, tags);
125 return new ValueAndTagRewriteCell(cell, value, tags);
129 * This can be used when a Cell has to change with addition/removal of one or more tags. This is
130 * an efficient way to do so in which only the tags bytes part need to recreated and copied. All
131 * other parts, refer to the original Cell.
133 static class TagRewriteCell implements ExtendedCell {
134 protected Cell cell;
135 protected byte[] tags;
136 private static final int HEAP_SIZE_OVERHEAD = ClassSize.OBJECT + 2 * ClassSize.REFERENCE;
139 * @param cell The original Cell which it rewrites
140 * @param tags the tags bytes. The array suppose to contain the tags bytes alone.
142 public TagRewriteCell(Cell cell, byte[] tags) {
143 assert cell instanceof ExtendedCell;
144 assert tags != null;
145 this.cell = cell;
146 this.tags = tags;
147 // tag offset will be treated as 0 and length this.tags.length
148 if (this.cell instanceof TagRewriteCell) {
149 // Cleaning the ref so that the byte[] can be GCed
150 ((TagRewriteCell) this.cell).tags = null;
154 @Override
155 public byte[] getRowArray() {
156 return cell.getRowArray();
159 @Override
160 public int getRowOffset() {
161 return cell.getRowOffset();
164 @Override
165 public short getRowLength() {
166 return cell.getRowLength();
169 @Override
170 public byte[] getFamilyArray() {
171 return cell.getFamilyArray();
174 @Override
175 public int getFamilyOffset() {
176 return cell.getFamilyOffset();
179 @Override
180 public byte getFamilyLength() {
181 return cell.getFamilyLength();
184 @Override
185 public byte[] getQualifierArray() {
186 return cell.getQualifierArray();
189 @Override
190 public int getQualifierOffset() {
191 return cell.getQualifierOffset();
194 @Override
195 public int getQualifierLength() {
196 return cell.getQualifierLength();
199 @Override
200 public long getTimestamp() {
201 return cell.getTimestamp();
204 @Override
205 public byte getTypeByte() {
206 return cell.getTypeByte();
209 @Override
210 public long getSequenceId() {
211 return cell.getSequenceId();
214 @Override
215 public byte[] getValueArray() {
216 return cell.getValueArray();
219 @Override
220 public int getValueOffset() {
221 return cell.getValueOffset();
224 @Override
225 public int getValueLength() {
226 return cell.getValueLength();
229 @Override
230 public byte[] getTagsArray() {
231 return this.tags;
234 @Override
235 public int getTagsOffset() {
236 return 0;
239 @Override
240 public int getTagsLength() {
241 if (null == this.tags) {
242 // Nulled out tags array optimization in constructor
243 return 0;
245 return this.tags.length;
248 @Override
249 public long heapSize() {
250 long sum = HEAP_SIZE_OVERHEAD + cell.heapSize();
251 if (this.tags != null) {
252 sum += ClassSize.sizeOf(this.tags);
254 return sum;
257 @Override
258 public void setTimestamp(long ts) throws IOException {
259 // The incoming cell is supposed to be ExtendedCell type.
260 PrivateCellUtil.setTimestamp(cell, ts);
263 @Override
264 public void setTimestamp(byte[] ts) throws IOException {
265 // The incoming cell is supposed to be ExtendedCell type.
266 PrivateCellUtil.setTimestamp(cell, ts);
269 @Override
270 public void setSequenceId(long seqId) throws IOException {
271 // The incoming cell is supposed to be ExtendedCell type.
272 PrivateCellUtil.setSequenceId(cell, seqId);
275 @Override
276 public int write(OutputStream out, boolean withTags) throws IOException {
277 int len = ((ExtendedCell) this.cell).write(out, false);
278 if (withTags && this.tags != null) {
279 // Write the tagsLength 2 bytes
280 out.write((byte) (0xff & (this.tags.length >> 8)));
281 out.write((byte) (0xff & this.tags.length));
282 out.write(this.tags);
283 len += KeyValue.TAGS_LENGTH_SIZE + this.tags.length;
285 return len;
288 @Override
289 public int getSerializedSize(boolean withTags) {
290 int len = ((ExtendedCell) this.cell).getSerializedSize(false);
291 if (withTags && this.tags != null) {
292 len += KeyValue.TAGS_LENGTH_SIZE + this.tags.length;
294 return len;
297 @Override
298 public void write(ByteBuffer buf, int offset) {
299 offset = KeyValueUtil.appendTo(this.cell, buf, offset, false);
300 int tagsLen = this.tags == null ? 0 : this.tags.length;
301 if (tagsLen > 0) {
302 offset = ByteBufferUtils.putAsShort(buf, offset, tagsLen);
303 ByteBufferUtils.copyFromArrayToBuffer(buf, offset, this.tags, 0, tagsLen);
307 @Override
308 public ExtendedCell deepClone() {
309 Cell clonedBaseCell = ((ExtendedCell) this.cell).deepClone();
310 return new TagRewriteCell(clonedBaseCell, this.tags);
314 static class TagRewriteByteBufferExtendedCell extends ByteBufferExtendedCell {
316 protected ByteBufferExtendedCell cell;
317 protected byte[] tags;
318 private static final int HEAP_SIZE_OVERHEAD = ClassSize.OBJECT + 2 * ClassSize.REFERENCE;
321 * @param cell The original ByteBufferExtendedCell which it rewrites
322 * @param tags the tags bytes. The array suppose to contain the tags bytes alone.
324 public TagRewriteByteBufferExtendedCell(ByteBufferExtendedCell cell, byte[] tags) {
325 assert tags != null;
326 this.cell = cell;
327 this.tags = tags;
328 // tag offset will be treated as 0 and length this.tags.length
329 if (this.cell instanceof TagRewriteByteBufferExtendedCell) {
330 // Cleaning the ref so that the byte[] can be GCed
331 ((TagRewriteByteBufferExtendedCell) this.cell).tags = null;
335 @Override
336 public byte[] getRowArray() {
337 return this.cell.getRowArray();
340 @Override
341 public int getRowOffset() {
342 return this.cell.getRowOffset();
345 @Override
346 public short getRowLength() {
347 return this.cell.getRowLength();
350 @Override
351 public byte[] getFamilyArray() {
352 return this.cell.getFamilyArray();
355 @Override
356 public int getFamilyOffset() {
357 return this.cell.getFamilyOffset();
360 @Override
361 public byte getFamilyLength() {
362 return this.cell.getFamilyLength();
365 @Override
366 public byte[] getQualifierArray() {
367 return this.cell.getQualifierArray();
370 @Override
371 public int getQualifierOffset() {
372 return this.cell.getQualifierOffset();
375 @Override
376 public int getQualifierLength() {
377 return this.cell.getQualifierLength();
380 @Override
381 public long getTimestamp() {
382 return this.cell.getTimestamp();
385 @Override
386 public byte getTypeByte() {
387 return this.cell.getTypeByte();
390 @Override
391 public long getSequenceId() {
392 return this.cell.getSequenceId();
395 @Override
396 public byte[] getValueArray() {
397 return this.cell.getValueArray();
400 @Override
401 public int getValueOffset() {
402 return this.cell.getValueOffset();
405 @Override
406 public int getValueLength() {
407 return this.cell.getValueLength();
410 @Override
411 public byte[] getTagsArray() {
412 return this.tags;
415 @Override
416 public int getTagsOffset() {
417 return 0;
420 @Override
421 public int getTagsLength() {
422 if (null == this.tags) {
423 // Nulled out tags array optimization in constructor
424 return 0;
426 return this.tags.length;
429 @Override
430 public void setSequenceId(long seqId) throws IOException {
431 PrivateCellUtil.setSequenceId(this.cell, seqId);
434 @Override
435 public void setTimestamp(long ts) throws IOException {
436 PrivateCellUtil.setTimestamp(this.cell, ts);
439 @Override
440 public void setTimestamp(byte[] ts) throws IOException {
441 PrivateCellUtil.setTimestamp(this.cell, ts);
444 @Override
445 public long heapSize() {
446 long sum = HEAP_SIZE_OVERHEAD + cell.heapSize();
447 // this.tags is on heap byte[]
448 if (this.tags != null) {
449 sum += ClassSize.sizeOf(this.tags);
451 return sum;
454 @Override
455 public int write(OutputStream out, boolean withTags) throws IOException {
456 int len = ((ExtendedCell) this.cell).write(out, false);
457 if (withTags && this.tags != null) {
458 // Write the tagsLength 2 bytes
459 out.write((byte) (0xff & (this.tags.length >> 8)));
460 out.write((byte) (0xff & this.tags.length));
461 out.write(this.tags);
462 len += KeyValue.TAGS_LENGTH_SIZE + this.tags.length;
464 return len;
467 @Override
468 public int getSerializedSize(boolean withTags) {
469 int len = ((ExtendedCell) this.cell).getSerializedSize(false);
470 if (withTags && this.tags != null) {
471 len += KeyValue.TAGS_LENGTH_SIZE + this.tags.length;
473 return len;
476 @Override
477 public void write(ByteBuffer buf, int offset) {
478 offset = KeyValueUtil.appendTo(this.cell, buf, offset, false);
479 int tagsLen = this.tags == null ? 0 : this.tags.length;
480 if (tagsLen > 0) {
481 offset = ByteBufferUtils.putAsShort(buf, offset, tagsLen);
482 ByteBufferUtils.copyFromArrayToBuffer(buf, offset, this.tags, 0, tagsLen);
486 @Override
487 public ExtendedCell deepClone() {
488 Cell clonedBaseCell = ((ExtendedCell) this.cell).deepClone();
489 if (clonedBaseCell instanceof ByteBufferExtendedCell) {
490 return new TagRewriteByteBufferExtendedCell((ByteBufferExtendedCell) clonedBaseCell,
491 this.tags);
493 return new TagRewriteCell(clonedBaseCell, this.tags);
496 @Override
497 public ByteBuffer getRowByteBuffer() {
498 return this.cell.getRowByteBuffer();
501 @Override
502 public int getRowPosition() {
503 return this.cell.getRowPosition();
506 @Override
507 public ByteBuffer getFamilyByteBuffer() {
508 return this.cell.getFamilyByteBuffer();
511 @Override
512 public int getFamilyPosition() {
513 return this.cell.getFamilyPosition();
516 @Override
517 public ByteBuffer getQualifierByteBuffer() {
518 return this.cell.getQualifierByteBuffer();
521 @Override
522 public int getQualifierPosition() {
523 return this.cell.getQualifierPosition();
526 @Override
527 public ByteBuffer getValueByteBuffer() {
528 return this.cell.getValueByteBuffer();
531 @Override
532 public int getValuePosition() {
533 return this.cell.getValuePosition();
536 @Override
537 public ByteBuffer getTagsByteBuffer() {
538 return this.tags == null ? HConstants.EMPTY_BYTE_BUFFER : ByteBuffer.wrap(this.tags);
541 @Override
542 public int getTagsPosition() {
543 return 0;
547 static class ValueAndTagRewriteCell extends TagRewriteCell {
549 protected byte[] value;
551 public ValueAndTagRewriteCell(Cell cell, byte[] value, byte[] tags) {
552 super(cell, tags);
553 this.value = value;
556 @Override
557 public byte[] getValueArray() {
558 return this.value;
561 @Override
562 public int getValueOffset() {
563 return 0;
566 @Override
567 public int getValueLength() {
568 return this.value == null ? 0 : this.value.length;
571 @Override
572 public long heapSize() {
573 long sum = ClassSize.REFERENCE + super.heapSize();
574 if (this.value != null) {
575 sum += ClassSize.sizeOf(this.value);
577 return sum;
580 @Override
581 public int write(OutputStream out, boolean withTags) throws IOException {
582 return write(out, withTags, this.cell, this.value, this.tags);
586 * Made into a static method so as to reuse the logic within
587 * ValueAndTagRewriteByteBufferExtendedCell
589 static int write(OutputStream out, boolean withTags, Cell cell, byte[] value, byte[] tags)
590 throws IOException {
591 int valLen = value == null ? 0 : value.length;
592 ByteBufferUtils.putInt(out, KeyValueUtil.keyLength(cell));// Key length
593 ByteBufferUtils.putInt(out, valLen);// Value length
594 int len = 2 * Bytes.SIZEOF_INT;
595 len += writeFlatKey(cell, out);// Key
596 if (valLen > 0) {
597 out.write(value);// Value
599 len += valLen;
600 if (withTags && tags != null) {
601 // Write the tagsLength 2 bytes
602 out.write((byte) (0xff & (tags.length >> 8)));
603 out.write((byte) (0xff & tags.length));
604 out.write(tags);
605 len += KeyValue.TAGS_LENGTH_SIZE + tags.length;
607 return len;
610 @Override
611 public int getSerializedSize(boolean withTags) {
612 return super.getSerializedSize(withTags) - this.cell.getValueLength() + this.value.length;
615 @Override
616 public void write(ByteBuffer buf, int offset) {
617 write(buf, offset, this.cell, this.value, this.tags);
621 * Made into a static method so as to reuse the logic
622 * within ValueAndTagRewriteByteBufferExtendedCell
624 static void write(ByteBuffer buf, int offset, Cell cell, byte[] value, byte[] tags) {
625 offset = ByteBufferUtils.putInt(buf, offset, KeyValueUtil.keyLength(cell));// Key length
626 offset = ByteBufferUtils.putInt(buf, offset, value.length);// Value length
627 offset = KeyValueUtil.appendKeyTo(cell, buf, offset);
628 ByteBufferUtils.copyFromArrayToBuffer(buf, offset, value, 0, value.length);
629 offset += value.length;
630 int tagsLen = tags == null ? 0 : tags.length;
631 if (tagsLen > 0) {
632 offset = ByteBufferUtils.putAsShort(buf, offset, tagsLen);
633 ByteBufferUtils.copyFromArrayToBuffer(buf, offset, tags, 0, tagsLen);
637 @Override
638 public ExtendedCell deepClone() {
639 Cell clonedBaseCell = ((ExtendedCell) this.cell).deepClone();
640 return new ValueAndTagRewriteCell(clonedBaseCell, this.value, this.tags);
644 static class ValueAndTagRewriteByteBufferExtendedCell extends TagRewriteByteBufferExtendedCell {
646 protected byte[] value;
648 public ValueAndTagRewriteByteBufferExtendedCell(ByteBufferExtendedCell cell,
649 byte[] value, byte[] tags) {
650 super(cell, tags);
651 this.value = value;
654 @Override
655 public byte[] getValueArray() {
656 return this.value;
659 @Override
660 public int getValueOffset() {
661 return 0;
664 @Override
665 public int getValueLength() {
666 return this.value == null ? 0 : this.value.length;
669 @Override
670 public ByteBuffer getValueByteBuffer() {
671 return ByteBuffer.wrap(this.value);
674 @Override
675 public int getValuePosition() {
676 return 0;
679 @Override
680 public long heapSize() {
681 long sum = ClassSize.REFERENCE + super.heapSize();
682 if (this.value != null) {
683 sum += ClassSize.sizeOf(this.value);
685 return sum;
688 @Override
689 public int write(OutputStream out, boolean withTags) throws IOException {
690 return ValueAndTagRewriteCell.write(out, withTags, this.cell, this.value, this.tags);
693 @Override
694 public int getSerializedSize(boolean withTags) {
695 return super.getSerializedSize(withTags) - this.cell.getValueLength() + this.value.length;
698 @Override
699 public void write(ByteBuffer buf, int offset) {
700 ValueAndTagRewriteCell.write(buf, offset, this.cell, this.value, this.tags);
703 @Override
704 public ExtendedCell deepClone() {
705 Cell clonedBaseCell = this.cell.deepClone();
706 if (clonedBaseCell instanceof ByteBufferExtendedCell) {
707 return new ValueAndTagRewriteByteBufferExtendedCell(
708 (ByteBufferExtendedCell) clonedBaseCell, this.value, this.tags);
710 return new ValueAndTagRewriteCell(clonedBaseCell, this.value, this.tags);
714 public static boolean matchingRows(final Cell left, final byte[] buf, final int offset,
715 final int length) {
716 if (left instanceof ByteBufferExtendedCell) {
717 return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getRowByteBuffer(),
718 ((ByteBufferExtendedCell) left).getRowPosition(), left.getRowLength(),
719 buf, offset, length);
721 return Bytes.equals(left.getRowArray(), left.getRowOffset(), left.getRowLength(), buf, offset,
722 length);
725 public static boolean matchingFamily(final Cell left, final byte[] buf, final int offset,
726 final int length) {
727 if (left instanceof ByteBufferExtendedCell) {
728 return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getFamilyByteBuffer(),
729 ((ByteBufferExtendedCell) left).getFamilyPosition(), left.getFamilyLength(),
730 buf, offset, length);
732 return Bytes.equals(left.getFamilyArray(), left.getFamilyOffset(), left.getFamilyLength(), buf,
733 offset, length);
737 * Finds if the qualifier part of the cell and the KV serialized byte[] are equal
738 * @param left the cell with which we need to match the qualifier
739 * @param buf the serialized keyvalue format byte[]
740 * @param offset the offset of the qualifier in the byte[]
741 * @param length the length of the qualifier in the byte[]
742 * @return true if the qualifier matches, false otherwise
744 public static boolean matchingQualifier(final Cell left, final byte[] buf, final int offset,
745 final int length) {
746 if (buf == null) {
747 return left.getQualifierLength() == 0;
749 if (left instanceof ByteBufferExtendedCell) {
750 return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getQualifierByteBuffer(),
751 ((ByteBufferExtendedCell) left).getQualifierPosition(), left.getQualifierLength(),
752 buf, offset, length);
754 return Bytes.equals(left.getQualifierArray(), left.getQualifierOffset(),
755 left.getQualifierLength(), buf, offset, length);
759 * Finds if the start of the qualifier part of the Cell matches <code>buf</code>
760 * @param left the cell with which we need to match the qualifier
761 * @param startsWith the serialized keyvalue format byte[]
762 * @return true if the qualifier have same staring characters, false otherwise
764 public static boolean qualifierStartsWith(final Cell left, final byte[] startsWith) {
765 if (startsWith == null || startsWith.length == 0) {
766 throw new IllegalArgumentException("Cannot pass an empty startsWith");
768 if (left.getQualifierLength() < startsWith.length) {
769 return false;
771 if (left instanceof ByteBufferExtendedCell) {
772 return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getQualifierByteBuffer(),
773 ((ByteBufferExtendedCell) left).getQualifierPosition(), startsWith.length,
774 startsWith, 0, startsWith.length);
776 return Bytes.equals(left.getQualifierArray(), left.getQualifierOffset(),
777 startsWith.length, startsWith, 0, startsWith.length);
780 public static boolean matchingColumn(final Cell left, final byte[] fam, final int foffset,
781 final int flength, final byte[] qual, final int qoffset, final int qlength) {
782 if (!matchingFamily(left, fam, foffset, flength)) {
783 return false;
785 return matchingQualifier(left, qual, qoffset, qlength);
788 public static boolean matchingValue(final Cell left, final Cell right, int lvlength,
789 int rvlength) {
790 if (left instanceof ByteBufferExtendedCell && right instanceof ByteBufferExtendedCell) {
791 return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getValueByteBuffer(),
792 ((ByteBufferExtendedCell) left).getValuePosition(), lvlength,
793 ((ByteBufferExtendedCell) right).getValueByteBuffer(),
794 ((ByteBufferExtendedCell) right).getValuePosition(), rvlength);
796 if (left instanceof ByteBufferExtendedCell) {
797 return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getValueByteBuffer(),
798 ((ByteBufferExtendedCell) left).getValuePosition(), lvlength, right.getValueArray(),
799 right.getValueOffset(), rvlength);
801 if (right instanceof ByteBufferExtendedCell) {
802 return ByteBufferUtils.equals(((ByteBufferExtendedCell) right).getValueByteBuffer(),
803 ((ByteBufferExtendedCell) right).getValuePosition(), rvlength, left.getValueArray(),
804 left.getValueOffset(), lvlength);
806 return Bytes
807 .equals(left.getValueArray(), left.getValueOffset(), lvlength, right.getValueArray(),
808 right.getValueOffset(), rvlength);
811 public static boolean matchingType(Cell a, Cell b) {
812 return a.getTypeByte() == b.getTypeByte();
815 public static boolean matchingTags(final Cell left, final Cell right, int llength,
816 int rlength) {
817 if (left instanceof ByteBufferExtendedCell && right instanceof ByteBufferExtendedCell) {
818 ByteBufferExtendedCell leftBBCell = (ByteBufferExtendedCell) left;
819 ByteBufferExtendedCell rightBBCell = (ByteBufferExtendedCell) right;
820 return ByteBufferUtils.equals(
821 leftBBCell.getTagsByteBuffer(), leftBBCell.getTagsPosition(), llength,
822 rightBBCell.getTagsByteBuffer(),rightBBCell.getTagsPosition(), rlength);
824 if (left instanceof ByteBufferExtendedCell) {
825 ByteBufferExtendedCell leftBBCell = (ByteBufferExtendedCell) left;
826 return ByteBufferUtils.equals(
827 leftBBCell.getTagsByteBuffer(), leftBBCell.getTagsPosition(), llength,
828 right.getTagsArray(), right.getTagsOffset(), rlength);
830 if (right instanceof ByteBufferExtendedCell) {
831 ByteBufferExtendedCell rightBBCell = (ByteBufferExtendedCell) right;
832 return ByteBufferUtils.equals(
833 rightBBCell.getTagsByteBuffer(), rightBBCell.getTagsPosition(), rlength,
834 left.getTagsArray(), left.getTagsOffset(), llength);
836 return Bytes.equals(left.getTagsArray(), left.getTagsOffset(), llength,
837 right.getTagsArray(), right.getTagsOffset(), rlength);
841 * @return True if a delete type, a {@link KeyValue.Type#Delete} or a {KeyValue.Type#DeleteFamily}
842 * or a {@link KeyValue.Type#DeleteColumn} KeyValue type.
844 public static boolean isDelete(final byte type) {
845 return KeyValue.Type.Delete.getCode() <= type && type <= KeyValue.Type.DeleteFamily.getCode();
849 * @return True if this cell is a {@link KeyValue.Type#Delete} type.
851 public static boolean isDeleteType(Cell cell) {
852 return cell.getTypeByte() == KeyValue.Type.Delete.getCode();
855 public static boolean isDeleteFamily(final Cell cell) {
856 return cell.getTypeByte() == KeyValue.Type.DeleteFamily.getCode();
859 public static boolean isDeleteFamilyVersion(final Cell cell) {
860 return cell.getTypeByte() == KeyValue.Type.DeleteFamilyVersion.getCode();
863 public static boolean isDeleteColumns(final Cell cell) {
864 return cell.getTypeByte() == KeyValue.Type.DeleteColumn.getCode();
867 public static boolean isDeleteColumnVersion(final Cell cell) {
868 return cell.getTypeByte() == KeyValue.Type.Delete.getCode();
872 * @return True if this cell is a delete family or column type.
874 public static boolean isDeleteColumnOrFamily(Cell cell) {
875 int t = cell.getTypeByte();
876 return t == KeyValue.Type.DeleteColumn.getCode() || t == KeyValue.Type.DeleteFamily.getCode();
879 public static byte[] cloneTags(Cell cell) {
880 byte[] output = new byte[cell.getTagsLength()];
881 copyTagsTo(cell, output, 0);
882 return output;
886 * Copies the tags info into the tag portion of the cell
887 * @param cell
888 * @param destination
889 * @param destinationOffset
890 * @return position after tags
892 public static int copyTagsTo(Cell cell, byte[] destination, int destinationOffset) {
893 int tlen = cell.getTagsLength();
894 if (cell instanceof ByteBufferExtendedCell) {
895 ByteBufferUtils
896 .copyFromBufferToArray(destination, ((ByteBufferExtendedCell) cell).getTagsByteBuffer(),
897 ((ByteBufferExtendedCell) cell).getTagsPosition(), destinationOffset, tlen);
898 } else {
899 System
900 .arraycopy(cell.getTagsArray(), cell.getTagsOffset(), destination, destinationOffset, tlen);
902 return destinationOffset + tlen;
906 * Copies the tags info into the tag portion of the cell
907 * @param cell
908 * @param destination
909 * @param destinationOffset
910 * @return the position after tags
912 public static int copyTagsTo(Cell cell, ByteBuffer destination, int destinationOffset) {
913 int tlen = cell.getTagsLength();
914 if (cell instanceof ByteBufferExtendedCell) {
915 ByteBufferUtils.copyFromBufferToBuffer(((ByteBufferExtendedCell) cell).getTagsByteBuffer(),
916 destination, ((ByteBufferExtendedCell) cell).getTagsPosition(), destinationOffset, tlen);
917 } else {
918 ByteBufferUtils.copyFromArrayToBuffer(destination, destinationOffset, cell.getTagsArray(),
919 cell.getTagsOffset(), tlen);
921 return destinationOffset + tlen;
925 * @param cell The Cell
926 * @return Tags in the given Cell as a List
928 public static List<Tag> getTags(Cell cell) {
929 List<Tag> tags = new ArrayList<>();
930 Iterator<Tag> tagsItr = tagsIterator(cell);
931 while (tagsItr.hasNext()) {
932 tags.add(tagsItr.next());
934 return tags;
938 * Retrieve Cell's first tag, matching the passed in type
939 * @param cell The Cell
940 * @param type Type of the Tag to retrieve
941 * @return Optional, empty if there is no tag of the passed in tag type
943 public static Optional<Tag> getTag(Cell cell, byte type) {
944 boolean bufferBacked = cell instanceof ByteBufferExtendedCell;
945 int length = cell.getTagsLength();
946 int offset =
947 bufferBacked ? ((ByteBufferExtendedCell) cell).getTagsPosition() : cell.getTagsOffset();
948 int pos = offset;
949 while (pos < offset + length) {
950 int tagLen;
951 if (bufferBacked) {
952 ByteBuffer tagsBuffer = ((ByteBufferExtendedCell) cell).getTagsByteBuffer();
953 tagLen = ByteBufferUtils.readAsInt(tagsBuffer, pos, TAG_LENGTH_SIZE);
954 if (ByteBufferUtils.toByte(tagsBuffer, pos + TAG_LENGTH_SIZE) == type) {
955 return Optional.of(new ByteBufferTag(tagsBuffer, pos, tagLen + TAG_LENGTH_SIZE));
957 } else {
958 tagLen = Bytes.readAsInt(cell.getTagsArray(), pos, TAG_LENGTH_SIZE);
959 if (cell.getTagsArray()[pos + TAG_LENGTH_SIZE] == type) {
960 return Optional
961 .of(new ArrayBackedTag(cell.getTagsArray(), pos, tagLen + TAG_LENGTH_SIZE));
964 pos += TAG_LENGTH_SIZE + tagLen;
966 return Optional.empty();
970 * Util method to iterate through the tags in the given cell.
971 * @param cell The Cell over which tags iterator is needed.
972 * @return iterator for the tags
974 public static Iterator<Tag> tagsIterator(final Cell cell) {
975 final int tagsLength = cell.getTagsLength();
976 // Save an object allocation where we can
977 if (tagsLength == 0) {
978 return TagUtil.EMPTY_TAGS_ITR;
980 if (cell instanceof ByteBufferExtendedCell) {
981 return tagsIterator(((ByteBufferExtendedCell) cell).getTagsByteBuffer(),
982 ((ByteBufferExtendedCell) cell).getTagsPosition(), tagsLength);
985 return new Iterator<Tag>() {
986 private int offset = cell.getTagsOffset();
987 private int pos = offset;
988 private int endOffset = offset + cell.getTagsLength() - 1;
990 @Override
991 public boolean hasNext() {
992 return this.pos < endOffset;
995 @Override
996 public Tag next() {
997 if (hasNext()) {
998 byte[] tags = cell.getTagsArray();
999 int curTagLen = Bytes.readAsInt(tags, this.pos, Tag.TAG_LENGTH_SIZE);
1000 Tag tag = new ArrayBackedTag(tags, pos, curTagLen + TAG_LENGTH_SIZE);
1001 this.pos += Bytes.SIZEOF_SHORT + curTagLen;
1002 return tag;
1004 return null;
1007 @Override
1008 public void remove() {
1009 throw new UnsupportedOperationException();
1014 public static Iterator<Tag> tagsIterator(final ByteBuffer tags, final int offset,
1015 final int length) {
1016 return new Iterator<Tag>() {
1017 private int pos = offset;
1018 private int endOffset = offset + length - 1;
1020 @Override
1021 public boolean hasNext() {
1022 return this.pos < endOffset;
1025 @Override
1026 public Tag next() {
1027 if (hasNext()) {
1028 int curTagLen = ByteBufferUtils.readAsInt(tags, this.pos, Tag.TAG_LENGTH_SIZE);
1029 Tag tag = new ByteBufferTag(tags, pos, curTagLen + Tag.TAG_LENGTH_SIZE);
1030 this.pos += Bytes.SIZEOF_SHORT + curTagLen;
1031 return tag;
1033 return null;
1036 @Override
1037 public void remove() {
1038 throw new UnsupportedOperationException();
1044 * Returns true if the first range start1...end1 overlaps with the second range start2...end2,
1045 * assuming the byte arrays represent row keys
1047 public static boolean overlappingKeys(final byte[] start1, final byte[] end1, final byte[] start2,
1048 final byte[] end2) {
1049 return (end2.length == 0 || start1.length == 0 || Bytes.compareTo(start1, end2) < 0)
1050 && (end1.length == 0 || start2.length == 0 || Bytes.compareTo(start2, end1) < 0);
1054 * Write rowkey excluding the common part.
1055 * @param cell
1056 * @param rLen
1057 * @param commonPrefix
1058 * @param out
1059 * @throws IOException
1061 public static void writeRowKeyExcludingCommon(Cell cell, short rLen, int commonPrefix,
1062 DataOutputStream out) throws IOException {
1063 if (commonPrefix == 0) {
1064 out.writeShort(rLen);
1065 } else if (commonPrefix == 1) {
1066 out.writeByte((byte) rLen);
1067 commonPrefix--;
1068 } else {
1069 commonPrefix -= KeyValue.ROW_LENGTH_SIZE;
1071 if (rLen > commonPrefix) {
1072 writeRowSkippingBytes(out, cell, rLen, commonPrefix);
1077 * Writes the row from the given cell to the output stream excluding the common prefix
1078 * @param out The dataoutputstream to which the data has to be written
1079 * @param cell The cell whose contents has to be written
1080 * @param rlength the row length
1081 * @throws IOException
1083 public static void writeRowSkippingBytes(DataOutputStream out, Cell cell, short rlength,
1084 int commonPrefix) throws IOException {
1085 if (cell instanceof ByteBufferExtendedCell) {
1086 ByteBufferUtils
1087 .copyBufferToStream((DataOutput) out, ((ByteBufferExtendedCell) cell).getRowByteBuffer(),
1088 ((ByteBufferExtendedCell) cell).getRowPosition() + commonPrefix,
1089 rlength - commonPrefix);
1090 } else {
1091 out.write(cell.getRowArray(), cell.getRowOffset() + commonPrefix, rlength - commonPrefix);
1096 * Find length of common prefix in keys of the cells, considering key as byte[] if serialized in
1097 * {@link KeyValue}. The key format is &lt;2 bytes rk len&gt;&lt;rk&gt;&lt;1 byte cf
1098 * len&gt;&lt;cf&gt;&lt;qualifier&gt;&lt;8 bytes timestamp&gt;&lt;1 byte type&gt;
1099 * @param c1 the cell
1100 * @param c2 the cell
1101 * @param bypassFamilyCheck when true assume the family bytes same in both cells. Pass it as true
1102 * when dealing with Cells in same CF so as to avoid some checks
1103 * @param withTsType when true check timestamp and type bytes also.
1104 * @return length of common prefix
1106 public static int findCommonPrefixInFlatKey(Cell c1, Cell c2, boolean bypassFamilyCheck,
1107 boolean withTsType) {
1108 // Compare the 2 bytes in RK length part
1109 short rLen1 = c1.getRowLength();
1110 short rLen2 = c2.getRowLength();
1111 int commonPrefix = KeyValue.ROW_LENGTH_SIZE;
1112 if (rLen1 != rLen2) {
1113 // early out when the RK length itself is not matching
1114 return ByteBufferUtils
1115 .findCommonPrefix(Bytes.toBytes(rLen1), 0, KeyValue.ROW_LENGTH_SIZE, Bytes.toBytes(rLen2),
1116 0, KeyValue.ROW_LENGTH_SIZE);
1118 // Compare the RKs
1119 int rkCommonPrefix = 0;
1120 if (c1 instanceof ByteBufferExtendedCell && c2 instanceof ByteBufferExtendedCell) {
1121 rkCommonPrefix = ByteBufferUtils
1122 .findCommonPrefix(((ByteBufferExtendedCell) c1).getRowByteBuffer(),
1123 ((ByteBufferExtendedCell) c1).getRowPosition(), rLen1,
1124 ((ByteBufferExtendedCell) c2).getRowByteBuffer(),
1125 ((ByteBufferExtendedCell) c2).getRowPosition(), rLen2);
1126 } else {
1127 // There cannot be a case where one cell is BBCell and other is KeyValue. This flow comes
1128 // either
1129 // in flush or compactions. In flushes both cells are KV and in case of compaction it will be
1130 // either
1131 // KV or BBCell
1132 rkCommonPrefix = ByteBufferUtils
1133 .findCommonPrefix(c1.getRowArray(), c1.getRowOffset(), rLen1, c2.getRowArray(),
1134 c2.getRowOffset(), rLen2);
1136 commonPrefix += rkCommonPrefix;
1137 if (rkCommonPrefix != rLen1) {
1138 // Early out when RK is not fully matching.
1139 return commonPrefix;
1141 // Compare 1 byte CF length part
1142 byte fLen1 = c1.getFamilyLength();
1143 if (bypassFamilyCheck) {
1144 // This flag will be true when caller is sure that the family will be same for both the cells
1145 // Just make commonPrefix to increment by the family part
1146 commonPrefix += KeyValue.FAMILY_LENGTH_SIZE + fLen1;
1147 } else {
1148 byte fLen2 = c2.getFamilyLength();
1149 if (fLen1 != fLen2) {
1150 // early out when the CF length itself is not matching
1151 return commonPrefix;
1153 // CF lengths are same so there is one more byte common in key part
1154 commonPrefix += KeyValue.FAMILY_LENGTH_SIZE;
1155 // Compare the CF names
1156 int fCommonPrefix;
1157 if (c1 instanceof ByteBufferExtendedCell && c2 instanceof ByteBufferExtendedCell) {
1158 fCommonPrefix = ByteBufferUtils
1159 .findCommonPrefix(((ByteBufferExtendedCell) c1).getFamilyByteBuffer(),
1160 ((ByteBufferExtendedCell) c1).getFamilyPosition(), fLen1,
1161 ((ByteBufferExtendedCell) c2).getFamilyByteBuffer(),
1162 ((ByteBufferExtendedCell) c2).getFamilyPosition(), fLen2);
1163 } else {
1164 fCommonPrefix = ByteBufferUtils
1165 .findCommonPrefix(c1.getFamilyArray(), c1.getFamilyOffset(), fLen1, c2.getFamilyArray(),
1166 c2.getFamilyOffset(), fLen2);
1168 commonPrefix += fCommonPrefix;
1169 if (fCommonPrefix != fLen1) {
1170 return commonPrefix;
1173 // Compare the Qualifiers
1174 int qLen1 = c1.getQualifierLength();
1175 int qLen2 = c2.getQualifierLength();
1176 int qCommon;
1177 if (c1 instanceof ByteBufferExtendedCell && c2 instanceof ByteBufferExtendedCell) {
1178 qCommon = ByteBufferUtils
1179 .findCommonPrefix(((ByteBufferExtendedCell) c1).getQualifierByteBuffer(),
1180 ((ByteBufferExtendedCell) c1).getQualifierPosition(), qLen1,
1181 ((ByteBufferExtendedCell) c2).getQualifierByteBuffer(),
1182 ((ByteBufferExtendedCell) c2).getQualifierPosition(), qLen2);
1183 } else {
1184 qCommon = ByteBufferUtils
1185 .findCommonPrefix(c1.getQualifierArray(), c1.getQualifierOffset(), qLen1,
1186 c2.getQualifierArray(), c2.getQualifierOffset(), qLen2);
1188 commonPrefix += qCommon;
1189 if (!withTsType || Math.max(qLen1, qLen2) != qCommon) {
1190 return commonPrefix;
1192 // Compare the timestamp parts
1193 int tsCommonPrefix = ByteBufferUtils
1194 .findCommonPrefix(Bytes.toBytes(c1.getTimestamp()), 0, KeyValue.TIMESTAMP_SIZE,
1195 Bytes.toBytes(c2.getTimestamp()), 0, KeyValue.TIMESTAMP_SIZE);
1196 commonPrefix += tsCommonPrefix;
1197 if (tsCommonPrefix != KeyValue.TIMESTAMP_SIZE) {
1198 return commonPrefix;
1200 // Compare the type
1201 if (c1.getTypeByte() == c2.getTypeByte()) {
1202 commonPrefix += KeyValue.TYPE_SIZE;
1204 return commonPrefix;
1208 * Used to compare two cells based on the column hint provided. This is specifically used when we
1209 * need to optimize the seeks based on the next indexed key. This is an advanced usage API
1210 * specifically needed for some optimizations.
1211 * @param nextIndexedCell the next indexed cell
1212 * @param currentCell the cell to be compared
1213 * @param foff the family offset of the currentCell
1214 * @param flen the family length of the currentCell
1215 * @param colHint the column hint provided - could be null
1216 * @param coff the offset of the column hint if provided, if not offset of the currentCell's
1217 * qualifier
1218 * @param clen the length of the column hint if provided, if not length of the currentCell's
1219 * qualifier
1220 * @param ts the timestamp to be seeked
1221 * @param type the type to be seeked
1222 * @return an int based on the given column hint TODO : To be moved out of here because this is a
1223 * special API used in scan optimization.
1225 // compare a key against row/fam/qual/ts/type
1226 public static final int compareKeyBasedOnColHint(CellComparator comparator, Cell nextIndexedCell,
1227 Cell currentCell, int foff, int flen, byte[] colHint, int coff, int clen, long ts,
1228 byte type) {
1229 int compare = comparator.compareRows(nextIndexedCell, currentCell);
1230 if (compare != 0) {
1231 return compare;
1233 // If the column is not specified, the "minimum" key type appears the
1234 // latest in the sorted order, regardless of the timestamp. This is used
1235 // for specifying the last key/value in a given row, because there is no
1236 // "lexicographically last column" (it would be infinitely long). The
1237 // "maximum" key type does not need this behavior.
1238 if (nextIndexedCell.getFamilyLength() + nextIndexedCell.getQualifierLength() == 0
1239 && nextIndexedCell.getTypeByte() == KeyValue.Type.Minimum.getCode()) {
1240 // left is "bigger", i.e. it appears later in the sorted order
1241 return 1;
1243 if (flen + clen == 0 && type == KeyValue.Type.Minimum.getCode()) {
1244 return -1;
1247 compare = comparator.compareFamilies(nextIndexedCell, currentCell);
1248 if (compare != 0) {
1249 return compare;
1251 if (colHint == null) {
1252 compare = comparator.compareQualifiers(nextIndexedCell, currentCell);
1253 } else {
1254 compare = CellUtil.compareQualifiers(nextIndexedCell, colHint, coff, clen);
1256 if (compare != 0) {
1257 return compare;
1259 // Next compare timestamps.
1260 compare = comparator.compareTimestamps(nextIndexedCell.getTimestamp(), ts);
1261 if (compare != 0) {
1262 return compare;
1265 // Compare types. Let the delete types sort ahead of puts; i.e. types
1266 // of higher numbers sort before those of lesser numbers. Maximum (255)
1267 // appears ahead of everything, and minimum (0) appears after
1268 // everything.
1269 return (0xff & type) - (0xff & nextIndexedCell.getTypeByte());
1273 * Compares only the key portion of a cell. It does not include the sequence id/mvcc of the cell
1274 * @param left
1275 * @param right
1276 * @return an int greater than 0 if left &gt; than right lesser than 0 if left &lt; than right
1277 * equal to 0 if left is equal to right
1279 public static final int compareKeyIgnoresMvcc(CellComparator comparator, Cell left, Cell right) {
1280 return ((CellComparatorImpl) comparator).compare(left, right, true);
1284 * Compare cell's row against given comparator
1285 * @param cell the cell to use for comparison
1286 * @param comparator the {@link CellComparator} to use for comparison
1287 * @return result comparing cell's row
1289 public static int compareRow(Cell cell, ByteArrayComparable comparator) {
1290 if (cell instanceof ByteBufferExtendedCell) {
1291 return comparator.compareTo(((ByteBufferExtendedCell) cell).getRowByteBuffer(),
1292 ((ByteBufferExtendedCell) cell).getRowPosition(), cell.getRowLength());
1294 return comparator.compareTo(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
1298 * Compare cell's column family against given comparator
1299 * @param cell the cell to use for comparison
1300 * @param comparator the {@link CellComparator} to use for comparison
1301 * @return result comparing cell's column family
1303 public static int compareFamily(Cell cell, ByteArrayComparable comparator) {
1304 if (cell instanceof ByteBufferExtendedCell) {
1305 return comparator.compareTo(((ByteBufferExtendedCell) cell).getFamilyByteBuffer(),
1306 ((ByteBufferExtendedCell) cell).getFamilyPosition(), cell.getFamilyLength());
1308 return comparator.compareTo(cell.getFamilyArray(), cell.getFamilyOffset(),
1309 cell.getFamilyLength());
1313 * Compare cell's qualifier against given comparator
1314 * @param cell the cell to use for comparison
1315 * @param comparator the {@link CellComparator} to use for comparison
1316 * @return result comparing cell's qualifier
1318 public static int compareQualifier(Cell cell, ByteArrayComparable comparator) {
1319 if (cell instanceof ByteBufferExtendedCell) {
1320 return comparator.compareTo(((ByteBufferExtendedCell) cell).getQualifierByteBuffer(),
1321 ((ByteBufferExtendedCell) cell).getQualifierPosition(), cell.getQualifierLength());
1323 return comparator.compareTo(cell.getQualifierArray(), cell.getQualifierOffset(),
1324 cell.getQualifierLength());
1327 public static Cell.Type toType(byte type) {
1328 KeyValue.Type codeToType = KeyValue.Type.codeToType(type);
1329 switch (codeToType) {
1330 case Put: return Cell.Type.Put;
1331 case Delete: return Cell.Type.Delete;
1332 case DeleteColumn: return Cell.Type.DeleteColumn;
1333 case DeleteFamily: return Cell.Type.DeleteFamily;
1334 case DeleteFamilyVersion: return Cell.Type.DeleteFamilyVersion;
1335 default: throw new UnsupportedOperationException("Invalid type of cell "+type);
1339 public static KeyValue.Type toTypeByte(Cell.Type type) {
1340 switch (type) {
1341 case Put: return KeyValue.Type.Put;
1342 case Delete: return KeyValue.Type.Delete;
1343 case DeleteColumn: return KeyValue.Type.DeleteColumn;
1344 case DeleteFamilyVersion: return KeyValue.Type.DeleteFamilyVersion;
1345 case DeleteFamily: return KeyValue.Type.DeleteFamily;
1346 default: throw new UnsupportedOperationException("Unsupported data type:" + type);
1351 * Compare cell's value against given comparator
1352 * @param cell the cell to use for comparison
1353 * @param comparator the {@link CellComparator} to use for comparison
1354 * @return result comparing cell's value
1356 public static int compareValue(Cell cell, ByteArrayComparable comparator) {
1357 if (cell instanceof ByteBufferExtendedCell) {
1358 return comparator.compareTo(((ByteBufferExtendedCell) cell).getValueByteBuffer(),
1359 ((ByteBufferExtendedCell) cell).getValuePosition(), cell.getValueLength());
1361 return comparator.compareTo(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength());
1365 * These cells are used in reseeks/seeks to improve the read performance. They are not real cells
1366 * that are returned back to the clients
1368 private static abstract class EmptyCell implements ExtendedCell {
1370 @Override
1371 public void setSequenceId(long seqId) {
1372 // Fake cells don't need seqId, so leaving it as a noop.
1375 @Override
1376 public void setTimestamp(long ts) {
1377 // Fake cells can't be changed timestamp, so leaving it as a noop.
1380 @Override
1381 public void setTimestamp(byte[] ts) {
1382 // Fake cells can't be changed timestamp, so leaving it as a noop.
1385 @Override
1386 public byte[] getRowArray() {
1387 return EMPTY_BYTE_ARRAY;
1390 @Override
1391 public int getRowOffset() {
1392 return 0;
1395 @Override
1396 public short getRowLength() {
1397 return 0;
1400 @Override
1401 public byte[] getFamilyArray() {
1402 return EMPTY_BYTE_ARRAY;
1405 @Override
1406 public int getFamilyOffset() {
1407 return 0;
1410 @Override
1411 public byte getFamilyLength() {
1412 return 0;
1415 @Override
1416 public byte[] getQualifierArray() {
1417 return EMPTY_BYTE_ARRAY;
1420 @Override
1421 public int getQualifierOffset() {
1422 return 0;
1425 @Override
1426 public int getQualifierLength() {
1427 return 0;
1430 @Override
1431 public long getSequenceId() {
1432 return 0;
1435 @Override
1436 public byte[] getValueArray() {
1437 return EMPTY_BYTE_ARRAY;
1440 @Override
1441 public int getValueOffset() {
1442 return 0;
1445 @Override
1446 public int getValueLength() {
1447 return 0;
1450 @Override
1451 public byte[] getTagsArray() {
1452 return EMPTY_BYTE_ARRAY;
1455 @Override
1456 public int getTagsOffset() {
1457 return 0;
1460 @Override
1461 public int getTagsLength() {
1462 return 0;
1467 * These cells are used in reseeks/seeks to improve the read performance. They are not real cells
1468 * that are returned back to the clients
1470 private static abstract class EmptyByteBufferExtendedCell extends ByteBufferExtendedCell {
1472 @Override
1473 public void setSequenceId(long seqId) {
1474 // Fake cells don't need seqId, so leaving it as a noop.
1477 @Override
1478 public void setTimestamp(long ts) {
1479 // Fake cells can't be changed timestamp, so leaving it as a noop.
1482 @Override
1483 public void setTimestamp(byte[] ts) {
1484 // Fake cells can't be changed timestamp, so leaving it as a noop.
1487 @Override
1488 public byte[] getRowArray() {
1489 return CellUtil.cloneRow(this);
1492 @Override
1493 public int getRowOffset() {
1494 return 0;
1497 @Override
1498 public short getRowLength() {
1499 return 0;
1502 @Override
1503 public byte[] getFamilyArray() {
1504 return CellUtil.cloneFamily(this);
1507 @Override
1508 public int getFamilyOffset() {
1509 return 0;
1512 @Override
1513 public byte getFamilyLength() {
1514 return 0;
1517 @Override
1518 public byte[] getQualifierArray() {
1519 return CellUtil.cloneQualifier(this);
1522 @Override
1523 public int getQualifierOffset() {
1524 return 0;
1527 @Override
1528 public int getQualifierLength() {
1529 return 0;
1532 @Override
1533 public long getSequenceId() {
1534 return 0;
1537 @Override
1538 public byte[] getValueArray() {
1539 return CellUtil.cloneValue(this);
1542 @Override
1543 public int getValueOffset() {
1544 return 0;
1547 @Override
1548 public int getValueLength() {
1549 return 0;
1552 @Override
1553 public byte[] getTagsArray() {
1554 return PrivateCellUtil.cloneTags(this);
1557 @Override
1558 public int getTagsOffset() {
1559 return 0;
1562 @Override
1563 public int getTagsLength() {
1564 return 0;
1567 @Override
1568 public ByteBuffer getRowByteBuffer() {
1569 return HConstants.EMPTY_BYTE_BUFFER;
1572 @Override
1573 public int getRowPosition() {
1574 return 0;
1577 @Override
1578 public ByteBuffer getFamilyByteBuffer() {
1579 return HConstants.EMPTY_BYTE_BUFFER;
1582 @Override
1583 public int getFamilyPosition() {
1584 return 0;
1587 @Override
1588 public ByteBuffer getQualifierByteBuffer() {
1589 return HConstants.EMPTY_BYTE_BUFFER;
1592 @Override
1593 public int getQualifierPosition() {
1594 return 0;
1597 @Override
1598 public ByteBuffer getTagsByteBuffer() {
1599 return HConstants.EMPTY_BYTE_BUFFER;
1602 @Override
1603 public int getTagsPosition() {
1604 return 0;
1607 @Override
1608 public ByteBuffer getValueByteBuffer() {
1609 return HConstants.EMPTY_BYTE_BUFFER;
1612 @Override
1613 public int getValuePosition() {
1614 return 0;
1618 private static class FirstOnRowCell extends EmptyCell {
1619 private static final int FIXED_HEAPSIZE =
1620 ClassSize.OBJECT // object
1621 + ClassSize.REFERENCE // row array
1622 + Bytes.SIZEOF_INT // row offset
1623 + Bytes.SIZEOF_SHORT; // row length
1624 private final byte[] rowArray;
1625 private final int roffset;
1626 private final short rlength;
1628 public FirstOnRowCell(final byte[] row, int roffset, short rlength) {
1629 this.rowArray = row;
1630 this.roffset = roffset;
1631 this.rlength = rlength;
1634 @Override
1635 public long heapSize() {
1636 return ClassSize.align(FIXED_HEAPSIZE)
1637 // array overhead
1638 + (rlength == 0 ? ClassSize.sizeOfByteArray(rlength) : rlength);
1641 @Override
1642 public byte[] getRowArray() {
1643 return this.rowArray;
1646 @Override
1647 public int getRowOffset() {
1648 return this.roffset;
1651 @Override
1652 public short getRowLength() {
1653 return this.rlength;
1656 @Override
1657 public long getTimestamp() {
1658 return HConstants.LATEST_TIMESTAMP;
1661 @Override
1662 public byte getTypeByte() {
1663 return KeyValue.Type.Maximum.getCode();
1666 @Override
1667 public Type getType() {
1668 throw new UnsupportedOperationException();
1672 private static class FirstOnRowByteBufferExtendedCell extends EmptyByteBufferExtendedCell {
1673 private static final int FIXED_OVERHEAD =
1674 ClassSize.OBJECT // object
1675 + ClassSize.REFERENCE // row buffer
1676 + Bytes.SIZEOF_INT // row offset
1677 + Bytes.SIZEOF_SHORT; // row length
1678 private final ByteBuffer rowBuff;
1679 private final int roffset;
1680 private final short rlength;
1682 public FirstOnRowByteBufferExtendedCell(final ByteBuffer row, int roffset, short rlength) {
1683 this.rowBuff = row;
1684 this.roffset = roffset;
1685 this.rlength = rlength;
1688 @Override
1689 public long heapSize() {
1690 if (this.rowBuff.hasArray()) {
1691 return ClassSize.align(FIXED_OVERHEAD + rlength);
1693 return ClassSize.align(FIXED_OVERHEAD);
1696 @Override
1697 public ByteBuffer getRowByteBuffer() {
1698 return this.rowBuff;
1701 @Override
1702 public int getRowPosition() {
1703 return this.roffset;
1706 @Override
1707 public short getRowLength() {
1708 return this.rlength;
1711 @Override
1712 public long getTimestamp() {
1713 return HConstants.LATEST_TIMESTAMP;
1716 @Override
1717 public byte getTypeByte() {
1718 return KeyValue.Type.Maximum.getCode();
1721 @Override
1722 public Type getType() {
1723 throw new UnsupportedOperationException();
1727 private static class LastOnRowByteBufferExtendedCell extends EmptyByteBufferExtendedCell {
1728 private static final int FIXED_OVERHEAD =
1729 ClassSize.OBJECT // object
1730 + ClassSize.REFERENCE // rowBuff
1731 + Bytes.SIZEOF_INT // roffset
1732 + Bytes.SIZEOF_SHORT; // rlength
1733 private final ByteBuffer rowBuff;
1734 private final int roffset;
1735 private final short rlength;
1737 public LastOnRowByteBufferExtendedCell(final ByteBuffer row, int roffset, short rlength) {
1738 this.rowBuff = row;
1739 this.roffset = roffset;
1740 this.rlength = rlength;
1743 @Override
1744 public long heapSize() {
1745 if (this.rowBuff.hasArray()) {
1746 return ClassSize.align(FIXED_OVERHEAD + rlength);
1748 return ClassSize.align(FIXED_OVERHEAD);
1751 @Override
1752 public ByteBuffer getRowByteBuffer() {
1753 return this.rowBuff;
1756 @Override
1757 public int getRowPosition() {
1758 return this.roffset;
1761 @Override
1762 public short getRowLength() {
1763 return this.rlength;
1766 @Override
1767 public long getTimestamp() {
1768 return PrivateConstants.OLDEST_TIMESTAMP;
1771 @Override
1772 public byte getTypeByte() {
1773 return KeyValue.Type.Minimum.getCode();
1776 @Override
1777 public Type getType() {
1778 throw new UnsupportedOperationException();
1782 private static class FirstOnRowColByteBufferExtendedCell
1783 extends FirstOnRowByteBufferExtendedCell {
1784 private static final int FIXED_OVERHEAD =
1785 FirstOnRowByteBufferExtendedCell.FIXED_OVERHEAD
1786 + ClassSize.REFERENCE * 2 // family buffer and column buffer
1787 + Bytes.SIZEOF_INT * 3 // famOffset, colOffset, colLength
1788 + Bytes.SIZEOF_BYTE; // famLength
1789 private final ByteBuffer famBuff;
1790 private final int famOffset;
1791 private final byte famLength;
1792 private final ByteBuffer colBuff;
1793 private final int colOffset;
1794 private final int colLength;
1796 public FirstOnRowColByteBufferExtendedCell(final ByteBuffer row, int roffset, short rlength,
1797 final ByteBuffer famBuff, final int famOffset, final byte famLength, final ByteBuffer col,
1798 final int colOffset, final int colLength) {
1799 super(row, roffset, rlength);
1800 this.famBuff = famBuff;
1801 this.famOffset = famOffset;
1802 this.famLength = famLength;
1803 this.colBuff = col;
1804 this.colOffset = colOffset;
1805 this.colLength = colLength;
1808 @Override
1809 public long heapSize() {
1810 if (famBuff.hasArray() && colBuff.hasArray()) {
1811 return ClassSize.align(FIXED_OVERHEAD + famLength + colLength);
1812 } else if (famBuff.hasArray()) {
1813 return ClassSize.align(FIXED_OVERHEAD + famLength);
1814 } else if (colBuff.hasArray()) {
1815 return ClassSize.align(FIXED_OVERHEAD + colLength);
1816 } else {
1817 return ClassSize.align(FIXED_OVERHEAD);
1821 @Override
1822 public ByteBuffer getFamilyByteBuffer() {
1823 return this.famBuff;
1826 @Override
1827 public int getFamilyPosition() {
1828 return this.famOffset;
1831 @Override
1832 public byte getFamilyLength() {
1833 return famLength;
1836 @Override
1837 public ByteBuffer getQualifierByteBuffer() {
1838 return this.colBuff;
1841 @Override
1842 public int getQualifierPosition() {
1843 return this.colOffset;
1846 @Override
1847 public int getQualifierLength() {
1848 return this.colLength;
1852 private static class FirstOnRowColCell extends FirstOnRowCell {
1853 private static final long FIXED_HEAPSIZE =
1854 FirstOnRowCell.FIXED_HEAPSIZE
1855 + Bytes.SIZEOF_BYTE // flength
1856 + Bytes.SIZEOF_INT * 3 // foffset, qoffset, qlength
1857 + ClassSize.REFERENCE * 2; // fArray, qArray
1858 private final byte[] fArray;
1859 private final int foffset;
1860 private final byte flength;
1861 private final byte[] qArray;
1862 private final int qoffset;
1863 private final int qlength;
1865 public FirstOnRowColCell(byte[] rArray, int roffset, short rlength, byte[] fArray, int foffset,
1866 byte flength, byte[] qArray, int qoffset, int qlength) {
1867 super(rArray, roffset, rlength);
1868 this.fArray = fArray;
1869 this.foffset = foffset;
1870 this.flength = flength;
1871 this.qArray = qArray;
1872 this.qoffset = qoffset;
1873 this.qlength = qlength;
1876 @Override
1877 public long heapSize() {
1878 return ClassSize.align(FIXED_HEAPSIZE)
1879 // array overhead
1880 + (flength == 0 ? ClassSize.sizeOfByteArray(flength) : flength)
1881 + (qlength == 0 ? ClassSize.sizeOfByteArray(qlength) : qlength);
1884 @Override
1885 public byte[] getFamilyArray() {
1886 return this.fArray;
1889 @Override
1890 public int getFamilyOffset() {
1891 return this.foffset;
1894 @Override
1895 public byte getFamilyLength() {
1896 return this.flength;
1899 @Override
1900 public byte[] getQualifierArray() {
1901 return this.qArray;
1904 @Override
1905 public int getQualifierOffset() {
1906 return this.qoffset;
1909 @Override
1910 public int getQualifierLength() {
1911 return this.qlength;
1915 private static class FirstOnRowColTSCell extends FirstOnRowColCell {
1916 private static final long FIXED_HEAPSIZE =
1917 FirstOnRowColCell.FIXED_HEAPSIZE
1918 + Bytes.SIZEOF_LONG; // ts
1919 private long ts;
1921 public FirstOnRowColTSCell(byte[] rArray, int roffset, short rlength, byte[] fArray,
1922 int foffset, byte flength, byte[] qArray, int qoffset, int qlength, long ts) {
1923 super(rArray, roffset, rlength, fArray, foffset, flength, qArray, qoffset, qlength);
1924 this.ts = ts;
1927 @Override
1928 public long getTimestamp() {
1929 return this.ts;
1932 @Override
1933 public long heapSize() {
1934 return ClassSize.align(FIXED_HEAPSIZE);
1938 private static class FirstOnRowColTSByteBufferExtendedCell
1939 extends FirstOnRowColByteBufferExtendedCell {
1940 private static final int FIXED_OVERHEAD =
1941 FirstOnRowColByteBufferExtendedCell.FIXED_OVERHEAD
1942 + Bytes.SIZEOF_LONG; // ts
1943 private long ts;
1945 public FirstOnRowColTSByteBufferExtendedCell(ByteBuffer rBuffer, int roffset, short rlength,
1946 ByteBuffer fBuffer, int foffset, byte flength, ByteBuffer qBuffer, int qoffset, int qlength,
1947 long ts) {
1948 super(rBuffer, roffset, rlength, fBuffer, foffset, flength, qBuffer, qoffset, qlength);
1949 this.ts = ts;
1952 @Override
1953 public long getTimestamp() {
1954 return this.ts;
1957 @Override
1958 public long heapSize() {
1959 return ClassSize.align(FIXED_OVERHEAD + super.heapSize());
1963 private static class LastOnRowCell extends EmptyCell {
1964 private static final int FIXED_OVERHEAD =
1965 ClassSize.OBJECT // object
1966 + ClassSize.REFERENCE // row array
1967 + Bytes.SIZEOF_INT // row offset
1968 + Bytes.SIZEOF_SHORT; // row length
1969 private final byte[] rowArray;
1970 private final int roffset;
1971 private final short rlength;
1973 public LastOnRowCell(byte[] row, int roffset, short rlength) {
1974 this.rowArray = row;
1975 this.roffset = roffset;
1976 this.rlength = rlength;
1979 @Override
1980 public long heapSize() {
1981 return ClassSize.align(FIXED_OVERHEAD)
1982 // array overhead
1983 + (rlength == 0 ? ClassSize.sizeOfByteArray(rlength) : rlength);
1986 @Override
1987 public byte[] getRowArray() {
1988 return this.rowArray;
1991 @Override
1992 public int getRowOffset() {
1993 return this.roffset;
1996 @Override
1997 public short getRowLength() {
1998 return this.rlength;
2001 @Override
2002 public long getTimestamp() {
2003 return PrivateConstants.OLDEST_TIMESTAMP;
2006 @Override
2007 public byte getTypeByte() {
2008 return KeyValue.Type.Minimum.getCode();
2011 @Override
2012 public Type getType() {
2013 throw new UnsupportedOperationException();
2017 private static class LastOnRowColCell extends LastOnRowCell {
2018 private static final long FIXED_OVERHEAD = LastOnRowCell.FIXED_OVERHEAD
2019 + ClassSize.REFERENCE * 2 // fArray and qArray
2020 + Bytes.SIZEOF_INT * 3 // foffset, qoffset, qlength
2021 + Bytes.SIZEOF_BYTE; // flength
2022 private final byte[] fArray;
2023 private final int foffset;
2024 private final byte flength;
2025 private final byte[] qArray;
2026 private final int qoffset;
2027 private final int qlength;
2029 public LastOnRowColCell(byte[] rArray, int roffset, short rlength, byte[] fArray, int foffset,
2030 byte flength, byte[] qArray, int qoffset, int qlength) {
2031 super(rArray, roffset, rlength);
2032 this.fArray = fArray;
2033 this.foffset = foffset;
2034 this.flength = flength;
2035 this.qArray = qArray;
2036 this.qoffset = qoffset;
2037 this.qlength = qlength;
2040 @Override
2041 public long heapSize() {
2042 return ClassSize.align(FIXED_OVERHEAD)
2043 // array overhead
2044 + (flength == 0 ? ClassSize.sizeOfByteArray(flength) : flength)
2045 + (qlength == 0 ? ClassSize.sizeOfByteArray(qlength) : qlength);
2048 @Override
2049 public byte[] getFamilyArray() {
2050 return this.fArray;
2053 @Override
2054 public int getFamilyOffset() {
2055 return this.foffset;
2058 @Override
2059 public byte getFamilyLength() {
2060 return this.flength;
2063 @Override
2064 public byte[] getQualifierArray() {
2065 return this.qArray;
2068 @Override
2069 public int getQualifierOffset() {
2070 return this.qoffset;
2073 @Override
2074 public int getQualifierLength() {
2075 return this.qlength;
2079 private static class LastOnRowColByteBufferExtendedCell extends LastOnRowByteBufferExtendedCell {
2080 private static final int FIXED_OVERHEAD =
2081 LastOnRowByteBufferExtendedCell.FIXED_OVERHEAD
2082 + ClassSize.REFERENCE * 2 // fBuffer and qBuffer
2083 + Bytes.SIZEOF_INT * 3 // foffset, qoffset, qlength
2084 + Bytes.SIZEOF_BYTE; // flength
2085 private final ByteBuffer fBuffer;
2086 private final int foffset;
2087 private final byte flength;
2088 private final ByteBuffer qBuffer;
2089 private final int qoffset;
2090 private final int qlength;
2092 public LastOnRowColByteBufferExtendedCell(ByteBuffer rBuffer, int roffset, short rlength,
2093 ByteBuffer fBuffer, int foffset, byte flength, ByteBuffer qBuffer, int qoffset,
2094 int qlength) {
2095 super(rBuffer, roffset, rlength);
2096 this.fBuffer = fBuffer;
2097 this.foffset = foffset;
2098 this.flength = flength;
2099 this.qBuffer = qBuffer;
2100 this.qoffset = qoffset;
2101 this.qlength = qlength;
2104 @Override
2105 public long heapSize() {
2106 if (fBuffer.hasArray() && qBuffer.hasArray()) {
2107 return ClassSize.align(FIXED_OVERHEAD + flength + qlength);
2108 } else if (fBuffer.hasArray()) {
2109 return ClassSize.align(FIXED_OVERHEAD + flength);
2110 } else if (qBuffer.hasArray()) {
2111 return ClassSize.align(FIXED_OVERHEAD + qlength);
2112 } else {
2113 return ClassSize.align(FIXED_OVERHEAD);
2117 @Override
2118 public ByteBuffer getFamilyByteBuffer() {
2119 return this.fBuffer;
2122 @Override
2123 public int getFamilyPosition() {
2124 return this.foffset;
2127 @Override
2128 public byte getFamilyLength() {
2129 return this.flength;
2132 @Override
2133 public ByteBuffer getQualifierByteBuffer() {
2134 return this.qBuffer;
2137 @Override
2138 public int getQualifierPosition() {
2139 return this.qoffset;
2142 @Override
2143 public int getQualifierLength() {
2144 return this.qlength;
2148 private static class FirstOnRowDeleteFamilyCell extends EmptyCell {
2149 private static final int FIXED_OVERHEAD =
2150 ClassSize.OBJECT // object
2151 + ClassSize.REFERENCE * 2 // fBuffer and qBuffer
2152 + Bytes.SIZEOF_INT * 3 // foffset, qoffset, qlength
2153 + Bytes.SIZEOF_BYTE; // flength
2154 private final byte[] row;
2155 private final byte[] fam;
2157 public FirstOnRowDeleteFamilyCell(byte[] row, byte[] fam) {
2158 this.row = row;
2159 this.fam = fam;
2162 @Override
2163 public long heapSize() {
2164 return ClassSize.align(FIXED_OVERHEAD)
2165 // array overhead
2166 + (getRowLength() == 0 ? ClassSize.sizeOfByteArray(getRowLength()) : getRowLength())
2167 + (getFamilyLength() == 0 ?
2168 ClassSize.sizeOfByteArray(getFamilyLength()) : getFamilyLength());
2171 @Override
2172 public byte[] getRowArray() {
2173 return this.row;
2176 @Override
2177 public short getRowLength() {
2178 return (short) this.row.length;
2181 @Override
2182 public byte[] getFamilyArray() {
2183 return this.fam;
2186 @Override
2187 public byte getFamilyLength() {
2188 return (byte) this.fam.length;
2191 @Override
2192 public long getTimestamp() {
2193 return HConstants.LATEST_TIMESTAMP;
2196 @Override
2197 public byte getTypeByte() {
2198 return KeyValue.Type.DeleteFamily.getCode();
2201 @Override
2202 public Type getType() {
2203 return Type.DeleteFamily;
2208 * Writes the Cell's key part as it would have serialized in a KeyValue. The format is &lt;2 bytes
2209 * rk len&gt;&lt;rk&gt;&lt;1 byte cf len&gt;&lt;cf&gt;&lt;qualifier&gt;&lt;8 bytes
2210 * timestamp&gt;&lt;1 byte type&gt;
2211 * @param cell
2212 * @param out
2213 * @throws IOException
2215 public static void writeFlatKey(Cell cell, DataOutput out) throws IOException {
2216 short rowLen = cell.getRowLength();
2217 byte fLen = cell.getFamilyLength();
2218 int qLen = cell.getQualifierLength();
2219 // Using just one if/else loop instead of every time checking before writing every
2220 // component of cell
2221 if (cell instanceof ByteBufferExtendedCell) {
2222 out.writeShort(rowLen);
2223 ByteBufferUtils.copyBufferToStream(out, ((ByteBufferExtendedCell) cell).getRowByteBuffer(),
2224 ((ByteBufferExtendedCell) cell).getRowPosition(), rowLen);
2225 out.writeByte(fLen);
2226 ByteBufferUtils.copyBufferToStream(out, ((ByteBufferExtendedCell) cell).getFamilyByteBuffer(),
2227 ((ByteBufferExtendedCell) cell).getFamilyPosition(), fLen);
2228 ByteBufferUtils
2229 .copyBufferToStream(out, ((ByteBufferExtendedCell) cell).getQualifierByteBuffer(),
2230 ((ByteBufferExtendedCell) cell).getQualifierPosition(), qLen);
2231 } else {
2232 out.writeShort(rowLen);
2233 out.write(cell.getRowArray(), cell.getRowOffset(), rowLen);
2234 out.writeByte(fLen);
2235 out.write(cell.getFamilyArray(), cell.getFamilyOffset(), fLen);
2236 out.write(cell.getQualifierArray(), cell.getQualifierOffset(), qLen);
2238 out.writeLong(cell.getTimestamp());
2239 out.writeByte(cell.getTypeByte());
2243 * Deep clones the given cell if the cell supports deep cloning
2244 * @param cell the cell to be cloned
2245 * @return the cloned cell
2246 * @throws CloneNotSupportedException
2248 public static Cell deepClone(Cell cell) throws CloneNotSupportedException {
2249 if (cell instanceof ExtendedCell) {
2250 return ((ExtendedCell) cell).deepClone();
2252 throw new CloneNotSupportedException();
2256 * Writes the cell to the given OutputStream
2257 * @param cell the cell to be written
2258 * @param out the outputstream
2259 * @param withTags if tags are to be written or not
2260 * @return the total bytes written
2261 * @throws IOException
2263 public static int writeCell(Cell cell, OutputStream out, boolean withTags) throws IOException {
2264 if (cell instanceof ExtendedCell) {
2265 return ((ExtendedCell) cell).write(out, withTags);
2266 } else {
2267 ByteBufferUtils.putInt(out, estimatedSerializedSizeOfKey(cell));
2268 ByteBufferUtils.putInt(out, cell.getValueLength());
2269 writeFlatKey(cell, out);
2270 writeValue(out, cell, cell.getValueLength());
2271 int tagsLength = cell.getTagsLength();
2272 if (withTags) {
2273 byte[] len = new byte[Bytes.SIZEOF_SHORT];
2274 Bytes.putAsShort(len, 0, tagsLength);
2275 out.write(len);
2276 if (tagsLength > 0) {
2277 writeTags(out, cell, tagsLength);
2280 int lenWritten = (2 * Bytes.SIZEOF_INT) + estimatedSerializedSizeOfKey(cell)
2281 + cell.getValueLength();
2282 if (withTags) {
2283 lenWritten += Bytes.SIZEOF_SHORT + tagsLength;
2285 return lenWritten;
2290 * Writes a cell to the buffer at the given offset
2291 * @param cell the cell to be written
2292 * @param buf the buffer to which the cell has to be wrriten
2293 * @param offset the offset at which the cell should be written
2295 public static void writeCellToBuffer(Cell cell, ByteBuffer buf, int offset) {
2296 if (cell instanceof ExtendedCell) {
2297 ((ExtendedCell) cell).write(buf, offset);
2298 } else {
2299 // Using the KVUtil
2300 byte[] bytes = KeyValueUtil.copyToNewByteArray(cell);
2301 ByteBufferUtils.copyFromArrayToBuffer(buf, offset, bytes, 0, bytes.length);
2305 public static int writeFlatKey(Cell cell, OutputStream out) throws IOException {
2306 short rowLen = cell.getRowLength();
2307 byte fLen = cell.getFamilyLength();
2308 int qLen = cell.getQualifierLength();
2309 // Using just one if/else loop instead of every time checking before writing every
2310 // component of cell
2311 if (cell instanceof ByteBufferExtendedCell) {
2312 StreamUtils.writeShort(out, rowLen);
2313 ByteBufferUtils.copyBufferToStream(out, ((ByteBufferExtendedCell) cell).getRowByteBuffer(),
2314 ((ByteBufferExtendedCell) cell).getRowPosition(), rowLen);
2315 out.write(fLen);
2316 ByteBufferUtils.copyBufferToStream(out, ((ByteBufferExtendedCell) cell).getFamilyByteBuffer(),
2317 ((ByteBufferExtendedCell) cell).getFamilyPosition(), fLen);
2318 ByteBufferUtils
2319 .copyBufferToStream(out, ((ByteBufferExtendedCell) cell).getQualifierByteBuffer(),
2320 ((ByteBufferExtendedCell) cell).getQualifierPosition(), qLen);
2321 } else {
2322 StreamUtils.writeShort(out, rowLen);
2323 out.write(cell.getRowArray(), cell.getRowOffset(), rowLen);
2324 out.write(fLen);
2325 out.write(cell.getFamilyArray(), cell.getFamilyOffset(), fLen);
2326 out.write(cell.getQualifierArray(), cell.getQualifierOffset(), qLen);
2328 StreamUtils.writeLong(out, cell.getTimestamp());
2329 out.write(cell.getTypeByte());
2330 return Bytes.SIZEOF_SHORT + rowLen + Bytes.SIZEOF_BYTE + fLen + qLen + Bytes.SIZEOF_LONG
2331 + Bytes.SIZEOF_BYTE;
2335 * Sets the given seqId to the cell. Marked as audience Private as of 1.2.0. Setting a Cell
2336 * sequenceid is an internal implementation detail not for general public use.
2337 * @param cell
2338 * @param seqId
2339 * @throws IOException when the passed cell is not of type {@link ExtendedCell}
2341 public static void setSequenceId(Cell cell, long seqId) throws IOException {
2342 if (cell instanceof ExtendedCell) {
2343 ((ExtendedCell) cell).setSequenceId(seqId);
2344 } else {
2345 throw new IOException(new UnsupportedOperationException(
2346 "Cell is not of type " + ExtendedCell.class.getName()));
2351 * Sets the given timestamp to the cell.
2352 * @param cell
2353 * @param ts
2354 * @throws IOException when the passed cell is not of type {@link ExtendedCell}
2356 public static void setTimestamp(Cell cell, long ts) throws IOException {
2357 if (cell instanceof ExtendedCell) {
2358 ((ExtendedCell) cell).setTimestamp(ts);
2359 } else {
2360 throw new IOException(new UnsupportedOperationException(
2361 "Cell is not of type " + ExtendedCell.class.getName()));
2366 * Sets the given timestamp to the cell.
2367 * @param cell
2368 * @param ts buffer containing the timestamp value
2369 * @throws IOException when the passed cell is not of type {@link ExtendedCell}
2371 public static void setTimestamp(Cell cell, byte[] ts) throws IOException {
2372 if (cell instanceof ExtendedCell) {
2373 ((ExtendedCell) cell).setTimestamp(ts);
2374 } else {
2375 throw new IOException(new UnsupportedOperationException(
2376 "Cell is not of type " + ExtendedCell.class.getName()));
2381 * Sets the given timestamp to the cell iff current timestamp is
2382 * {@link HConstants#LATEST_TIMESTAMP}.
2383 * @param cell
2384 * @param ts
2385 * @return True if cell timestamp is modified.
2386 * @throws IOException when the passed cell is not of type {@link ExtendedCell}
2388 public static boolean updateLatestStamp(Cell cell, long ts) throws IOException {
2389 if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP) {
2390 setTimestamp(cell, ts);
2391 return true;
2393 return false;
2397 * Sets the given timestamp to the cell iff current timestamp is
2398 * {@link HConstants#LATEST_TIMESTAMP}.
2399 * @param cell
2400 * @param ts buffer containing the timestamp value
2401 * @return True if cell timestamp is modified.
2402 * @throws IOException when the passed cell is not of type {@link ExtendedCell}
2404 public static boolean updateLatestStamp(Cell cell, byte[] ts) throws IOException {
2405 if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP) {
2406 setTimestamp(cell, ts);
2407 return true;
2409 return false;
2413 * Writes the row from the given cell to the output stream
2414 * @param out The outputstream to which the data has to be written
2415 * @param cell The cell whose contents has to be written
2416 * @param rlength the row length
2417 * @throws IOException
2419 public static void writeRow(OutputStream out, Cell cell, short rlength) throws IOException {
2420 if (cell instanceof ByteBufferExtendedCell) {
2421 ByteBufferUtils.copyBufferToStream(out, ((ByteBufferExtendedCell) cell).getRowByteBuffer(),
2422 ((ByteBufferExtendedCell) cell).getRowPosition(), rlength);
2423 } else {
2424 out.write(cell.getRowArray(), cell.getRowOffset(), rlength);
2429 * Writes the family from the given cell to the output stream
2430 * @param out The outputstream to which the data has to be written
2431 * @param cell The cell whose contents has to be written
2432 * @param flength the family length
2433 * @throws IOException
2435 public static void writeFamily(OutputStream out, Cell cell, byte flength) throws IOException {
2436 if (cell instanceof ByteBufferExtendedCell) {
2437 ByteBufferUtils.copyBufferToStream(out, ((ByteBufferExtendedCell) cell).getFamilyByteBuffer(),
2438 ((ByteBufferExtendedCell) cell).getFamilyPosition(), flength);
2439 } else {
2440 out.write(cell.getFamilyArray(), cell.getFamilyOffset(), flength);
2445 * Writes the qualifier from the given cell to the output stream
2446 * @param out The outputstream to which the data has to be written
2447 * @param cell The cell whose contents has to be written
2448 * @param qlength the qualifier length
2449 * @throws IOException
2451 public static void writeQualifier(OutputStream out, Cell cell, int qlength) throws IOException {
2452 if (cell instanceof ByteBufferExtendedCell) {
2453 ByteBufferUtils
2454 .copyBufferToStream(out, ((ByteBufferExtendedCell) cell).getQualifierByteBuffer(),
2455 ((ByteBufferExtendedCell) cell).getQualifierPosition(), qlength);
2456 } else {
2457 out.write(cell.getQualifierArray(), cell.getQualifierOffset(), qlength);
2462 * Writes the qualifier from the given cell to the output stream excluding the common prefix
2463 * @param out The dataoutputstream to which the data has to be written
2464 * @param cell The cell whose contents has to be written
2465 * @param qlength the qualifier length
2466 * @throws IOException
2468 public static void writeQualifierSkippingBytes(DataOutputStream out, Cell cell, int qlength,
2469 int commonPrefix) throws IOException {
2470 if (cell instanceof ByteBufferExtendedCell) {
2471 ByteBufferUtils.copyBufferToStream((DataOutput) out,
2472 ((ByteBufferExtendedCell) cell).getQualifierByteBuffer(),
2473 ((ByteBufferExtendedCell) cell).getQualifierPosition() + commonPrefix,
2474 qlength - commonPrefix);
2475 } else {
2476 out.write(cell.getQualifierArray(), cell.getQualifierOffset() + commonPrefix,
2477 qlength - commonPrefix);
2482 * Writes the value from the given cell to the output stream
2483 * @param out The outputstream to which the data has to be written
2484 * @param cell The cell whose contents has to be written
2485 * @param vlength the value length
2486 * @throws IOException
2488 public static void writeValue(OutputStream out, Cell cell, int vlength) throws IOException {
2489 if (cell instanceof ByteBufferExtendedCell) {
2490 ByteBufferUtils.copyBufferToStream(out, ((ByteBufferExtendedCell) cell).getValueByteBuffer(),
2491 ((ByteBufferExtendedCell) cell).getValuePosition(), vlength);
2492 } else {
2493 out.write(cell.getValueArray(), cell.getValueOffset(), vlength);
2498 * Writes the tag from the given cell to the output stream
2499 * @param out The outputstream to which the data has to be written
2500 * @param cell The cell whose contents has to be written
2501 * @param tagsLength the tag length
2502 * @throws IOException
2504 public static void writeTags(OutputStream out, Cell cell, int tagsLength) throws IOException {
2505 if (cell instanceof ByteBufferExtendedCell) {
2506 ByteBufferUtils.copyBufferToStream(out, ((ByteBufferExtendedCell) cell).getTagsByteBuffer(),
2507 ((ByteBufferExtendedCell) cell).getTagsPosition(), tagsLength);
2508 } else {
2509 out.write(cell.getTagsArray(), cell.getTagsOffset(), tagsLength);
2514 * special case for Cell.equals
2516 public static boolean equalsIgnoreMvccVersion(Cell a, Cell b) {
2517 // row
2518 boolean res = CellUtil.matchingRows(a, b);
2519 if (!res) return res;
2521 // family
2522 res = CellUtil.matchingColumn(a, b);
2523 if (!res) return res;
2525 // timestamp: later sorts first
2526 if (!CellUtil.matchingTimestamp(a, b)) return false;
2528 // type
2529 int c = (0xff & b.getTypeByte()) - (0xff & a.getTypeByte());
2530 if (c != 0) return false;
2531 else return true;
2535 * Converts the rowkey bytes of the given cell into an int value
2536 * @param cell
2537 * @return rowkey as int
2539 public static int getRowAsInt(Cell cell) {
2540 if (cell instanceof ByteBufferExtendedCell) {
2541 return ByteBufferUtils.toInt(((ByteBufferExtendedCell) cell).getRowByteBuffer(),
2542 ((ByteBufferExtendedCell) cell).getRowPosition());
2544 return Bytes.toInt(cell.getRowArray(), cell.getRowOffset());
2548 * Converts the value bytes of the given cell into a long value
2549 * @param cell
2550 * @return value as long
2552 public static long getValueAsLong(Cell cell) {
2553 if (cell instanceof ByteBufferExtendedCell) {
2554 return ByteBufferUtils.toLong(((ByteBufferExtendedCell) cell).getValueByteBuffer(),
2555 ((ByteBufferExtendedCell) cell).getValuePosition());
2557 return Bytes.toLong(cell.getValueArray(), cell.getValueOffset());
2561 * Converts the value bytes of the given cell into a int value
2562 * @param cell
2563 * @return value as int
2565 public static int getValueAsInt(Cell cell) {
2566 if (cell instanceof ByteBufferExtendedCell) {
2567 return ByteBufferUtils.toInt(((ByteBufferExtendedCell) cell).getValueByteBuffer(),
2568 ((ByteBufferExtendedCell) cell).getValuePosition());
2570 return Bytes.toInt(cell.getValueArray(), cell.getValueOffset());
2574 * Converts the value bytes of the given cell into a double value
2575 * @param cell
2576 * @return value as double
2578 public static double getValueAsDouble(Cell cell) {
2579 if (cell instanceof ByteBufferExtendedCell) {
2580 return ByteBufferUtils.toDouble(((ByteBufferExtendedCell) cell).getValueByteBuffer(),
2581 ((ByteBufferExtendedCell) cell).getValuePosition());
2583 return Bytes.toDouble(cell.getValueArray(), cell.getValueOffset());
2587 * Converts the value bytes of the given cell into a BigDecimal
2588 * @param cell
2589 * @return value as BigDecimal
2591 public static BigDecimal getValueAsBigDecimal(Cell cell) {
2592 if (cell instanceof ByteBufferExtendedCell) {
2593 return ByteBufferUtils.toBigDecimal(((ByteBufferExtendedCell) cell).getValueByteBuffer(),
2594 ((ByteBufferExtendedCell) cell).getValuePosition(), cell.getValueLength());
2596 return Bytes.toBigDecimal(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength());
2600 * Compresses the tags to the given outputstream using the TagcompressionContext
2601 * @param out the outputstream to which the compression should happen
2602 * @param cell the cell which has tags
2603 * @param tagCompressionContext the TagCompressionContext
2604 * @throws IOException can throw IOException if the compression encounters issue
2606 public static void compressTags(OutputStream out, Cell cell,
2607 TagCompressionContext tagCompressionContext) throws IOException {
2608 if (cell instanceof ByteBufferExtendedCell) {
2609 tagCompressionContext.compressTags(out, ((ByteBufferExtendedCell) cell).getTagsByteBuffer(),
2610 ((ByteBufferExtendedCell) cell).getTagsPosition(), cell.getTagsLength());
2611 } else {
2612 tagCompressionContext.compressTags(out, cell.getTagsArray(), cell.getTagsOffset(),
2613 cell.getTagsLength());
2617 public static void compressRow(OutputStream out, Cell cell, Dictionary dict) throws IOException {
2618 if (cell instanceof ByteBufferExtendedCell) {
2619 Dictionary.write(out, ((ByteBufferExtendedCell) cell).getRowByteBuffer(),
2620 ((ByteBufferExtendedCell) cell).getRowPosition(), cell.getRowLength(), dict);
2621 } else {
2622 Dictionary.write(out, cell.getRowArray(), cell.getRowOffset(), cell.getRowLength(), dict);
2626 public static void compressFamily(OutputStream out, Cell cell, Dictionary dict)
2627 throws IOException {
2628 if (cell instanceof ByteBufferExtendedCell) {
2629 Dictionary.write(out, ((ByteBufferExtendedCell) cell).getFamilyByteBuffer(),
2630 ((ByteBufferExtendedCell) cell).getFamilyPosition(), cell.getFamilyLength(), dict);
2631 } else {
2632 Dictionary.write(out, cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength(),
2633 dict);
2637 public static void compressQualifier(OutputStream out, Cell cell, Dictionary dict)
2638 throws IOException {
2639 if (cell instanceof ByteBufferExtendedCell) {
2640 Dictionary.write(out, ((ByteBufferExtendedCell) cell).getQualifierByteBuffer(),
2641 ((ByteBufferExtendedCell) cell).getQualifierPosition(), cell.getQualifierLength(), dict);
2642 } else {
2643 Dictionary.write(out, cell.getQualifierArray(), cell.getQualifierOffset(),
2644 cell.getQualifierLength(), dict);
2649 * Used when a cell needs to be compared with a key byte[] such as cases of finding the index from
2650 * the index block, bloom keys from the bloom blocks This byte[] is expected to be serialized in
2651 * the KeyValue serialization format If the KeyValue (Cell's) serialization format changes this
2652 * method cannot be used.
2653 * @param comparator the {@link CellComparator} to use for comparison
2654 * @param left the cell to be compared
2655 * @param key the serialized key part of a KeyValue
2656 * @param offset the offset in the key byte[]
2657 * @param length the length of the key byte[]
2658 * @return an int greater than 0 if left is greater than right lesser than 0 if left is lesser
2659 * than right equal to 0 if left is equal to right
2661 public static final int compare(CellComparator comparator, Cell left, byte[] key, int offset,
2662 int length) {
2663 // row
2664 short rrowlength = Bytes.toShort(key, offset);
2665 int c = comparator.compareRows(left, key, offset + Bytes.SIZEOF_SHORT, rrowlength);
2666 if (c != 0) return c;
2668 // Compare the rest of the two KVs without making any assumptions about
2669 // the common prefix. This function will not compare rows anyway, so we
2670 // don't need to tell it that the common prefix includes the row.
2671 return compareWithoutRow(comparator, left, key, offset, length, rrowlength);
2675 * Compare columnFamily, qualifier, timestamp, and key type (everything except the row). This
2676 * method is used both in the normal comparator and the "same-prefix" comparator. Note that we are
2677 * assuming that row portions of both KVs have already been parsed and found identical, and we
2678 * don't validate that assumption here.
2679 * @param comparator the {@link CellComparator} to use for comparison
2680 * @param left the cell to be compared
2681 * @param right the serialized key part of a key-value
2682 * @param roffset the offset in the key byte[]
2683 * @param rlength the length of the key byte[]
2684 * @param rowlength the row length
2685 * @return greater than 0 if left cell is bigger, less than 0 if right cell is bigger, 0 if both
2686 * cells are equal
2688 static final int compareWithoutRow(CellComparator comparator, Cell left, byte[] right,
2689 int roffset, int rlength, short rowlength) {
2690 /***
2691 * KeyValue Format and commonLength:
2692 * |_keyLen_|_valLen_|_rowLen_|_rowKey_|_famiLen_|_fami_|_Quali_|....
2693 * ------------------|-------commonLength--------|--------------
2695 int commonLength = KeyValue.ROW_LENGTH_SIZE + KeyValue.FAMILY_LENGTH_SIZE + rowlength;
2697 // commonLength + TIMESTAMP_TYPE_SIZE
2698 int commonLengthWithTSAndType = KeyValue.TIMESTAMP_TYPE_SIZE + commonLength;
2699 // ColumnFamily + Qualifier length.
2700 int lcolumnlength = left.getFamilyLength() + left.getQualifierLength();
2701 int rcolumnlength = rlength - commonLengthWithTSAndType;
2703 byte ltype = left.getTypeByte();
2704 byte rtype = right[roffset + (rlength - 1)];
2706 // If the column is not specified, the "minimum" key type appears the
2707 // latest in the sorted order, regardless of the timestamp. This is used
2708 // for specifying the last key/value in a given row, because there is no
2709 // "lexicographically last column" (it would be infinitely long). The
2710 // "maximum" key type does not need this behavior.
2711 if (lcolumnlength == 0 && ltype == KeyValue.Type.Minimum.getCode()) {
2712 // left is "bigger", i.e. it appears later in the sorted order
2713 return 1;
2715 if (rcolumnlength == 0 && rtype == KeyValue.Type.Minimum.getCode()) {
2716 return -1;
2719 int rfamilyoffset = commonLength + roffset;
2721 // Column family length.
2722 int lfamilylength = left.getFamilyLength();
2723 int rfamilylength = right[rfamilyoffset - 1];
2724 // If left family size is not equal to right family size, we need not
2725 // compare the qualifiers.
2726 boolean sameFamilySize = (lfamilylength == rfamilylength);
2727 if (!sameFamilySize) {
2728 // comparing column family is enough.
2729 return CellUtil.compareFamilies(left, right, rfamilyoffset, rfamilylength);
2731 // Compare family & qualifier together.
2732 // Families are same. Compare on qualifiers.
2733 int comparison = CellUtil.compareColumns(left, right, rfamilyoffset, rfamilylength,
2734 rfamilyoffset + rfamilylength, (rcolumnlength - rfamilylength));
2735 if (comparison != 0) {
2736 return comparison;
2739 // //
2740 // Next compare timestamps.
2741 long rtimestamp = Bytes.toLong(right, roffset + (rlength - KeyValue.TIMESTAMP_TYPE_SIZE));
2742 int compare = comparator.compareTimestamps(left.getTimestamp(), rtimestamp);
2743 if (compare != 0) {
2744 return compare;
2747 // Compare types. Let the delete types sort ahead of puts; i.e. types
2748 // of higher numbers sort before those of lesser numbers. Maximum (255)
2749 // appears ahead of everything, and minimum (0) appears after
2750 // everything.
2751 return (0xff & rtype) - (0xff & ltype);
2755 * @return An new cell is located following input cell. If both of type and timestamp are minimum,
2756 * the input cell will be returned directly.
2758 public static Cell createNextOnRowCol(Cell cell) {
2759 long ts = cell.getTimestamp();
2760 byte type = cell.getTypeByte();
2761 if (type != KeyValue.Type.Minimum.getCode()) {
2762 type = KeyValue.Type.values()[KeyValue.Type.codeToType(type).ordinal() - 1].getCode();
2763 } else if (ts != PrivateConstants.OLDEST_TIMESTAMP) {
2764 ts = ts - 1;
2765 type = KeyValue.Type.Maximum.getCode();
2766 } else {
2767 return cell;
2769 return createNextOnRowCol(cell, ts, type);
2772 static Cell createNextOnRowCol(Cell cell, long ts, byte type) {
2773 if (cell instanceof ByteBufferExtendedCell) {
2774 return new LastOnRowColByteBufferExtendedCell(
2775 ((ByteBufferExtendedCell) cell).getRowByteBuffer(),
2776 ((ByteBufferExtendedCell) cell).getRowPosition(), cell.getRowLength(),
2777 ((ByteBufferExtendedCell) cell).getFamilyByteBuffer(),
2778 ((ByteBufferExtendedCell) cell).getFamilyPosition(), cell.getFamilyLength(),
2779 ((ByteBufferExtendedCell) cell).getQualifierByteBuffer(),
2780 ((ByteBufferExtendedCell) cell).getQualifierPosition(), cell.getQualifierLength()) {
2781 @Override
2782 public long getTimestamp() {
2783 return ts;
2786 @Override
2787 public byte getTypeByte() {
2788 return type;
2792 return new LastOnRowColCell(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength(),
2793 cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength(),
2794 cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength()) {
2795 @Override
2796 public long getTimestamp() {
2797 return ts;
2800 @Override
2801 public byte getTypeByte() {
2802 return type;
2808 * Estimate based on keyvalue's serialization format in the RPC layer. Note that there is an extra
2809 * SIZEOF_INT added to the size here that indicates the actual length of the cell for cases where
2810 * cell's are serialized in a contiguous format (For eg in RPCs).
2811 * @param cell
2812 * @return Estimate of the <code>cell</code> size in bytes plus an extra SIZEOF_INT indicating the
2813 * actual cell length.
2815 public static int estimatedSerializedSizeOf(final Cell cell) {
2816 return cell.getSerializedSize() + Bytes.SIZEOF_INT;
2820 * Calculates the serialized key size. We always serialize in the KeyValue's serialization format.
2821 * @param cell the cell for which the key size has to be calculated.
2822 * @return the key size
2824 public static int estimatedSerializedSizeOfKey(final Cell cell) {
2825 if (cell instanceof KeyValue) return ((KeyValue) cell).getKeyLength();
2826 return cell.getRowLength() + cell.getFamilyLength() + cell.getQualifierLength()
2827 + KeyValue.KEY_INFRASTRUCTURE_SIZE;
2831 * This method exists just to encapsulate how we serialize keys. To be replaced by a factory that
2832 * we query to figure what the Cell implementation is and then, what serialization engine to use
2833 * and further, how to serialize the key for inclusion in hfile index. TODO.
2834 * @param cell
2835 * @return The key portion of the Cell serialized in the old-school KeyValue way or null if passed
2836 * a null <code>cell</code>
2838 public static byte[] getCellKeySerializedAsKeyValueKey(final Cell cell) {
2839 if (cell == null) return null;
2840 byte[] b = new byte[KeyValueUtil.keyLength(cell)];
2841 KeyValueUtil.appendKeyTo(cell, b, 0);
2842 return b;
2846 * Create a Cell that is smaller than all other possible Cells for the given Cell's row.
2847 * @param cell
2848 * @return First possible Cell on passed Cell's row.
2850 public static Cell createFirstOnRow(final Cell cell) {
2851 if (cell instanceof ByteBufferExtendedCell) {
2852 return new FirstOnRowByteBufferExtendedCell(
2853 ((ByteBufferExtendedCell) cell).getRowByteBuffer(),
2854 ((ByteBufferExtendedCell) cell).getRowPosition(), cell.getRowLength());
2856 return new FirstOnRowCell(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
2859 public static Cell createFirstOnRow(final byte[] row, int roffset, short rlength) {
2860 return new FirstOnRowCell(row, roffset, rlength);
2863 public static Cell createFirstOnRow(final byte[] row, final byte[] family, final byte[] col) {
2864 return createFirstOnRow(row, 0, (short) row.length, family, 0, (byte) family.length, col, 0,
2865 col.length);
2868 public static Cell createFirstOnRow(final byte[] row, int roffset, short rlength,
2869 final byte[] family, int foffset, byte flength, final byte[] col, int coffset, int clength) {
2870 return new FirstOnRowColCell(row, roffset, rlength, family, foffset, flength, col, coffset,
2871 clength);
2874 public static Cell createFirstOnRow(final byte[] row) {
2875 return createFirstOnRow(row, 0, (short) row.length);
2878 public static Cell createFirstOnRowFamily(Cell cell, byte[] fArray, int foff, int flen) {
2879 if (cell instanceof ByteBufferExtendedCell) {
2880 return new FirstOnRowColByteBufferExtendedCell(
2881 ((ByteBufferExtendedCell) cell).getRowByteBuffer(),
2882 ((ByteBufferExtendedCell) cell).getRowPosition(), cell.getRowLength(),
2883 ByteBuffer.wrap(fArray), foff, (byte) flen, HConstants.EMPTY_BYTE_BUFFER, 0, 0);
2885 return new FirstOnRowColCell(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength(),
2886 fArray, foff, (byte) flen, HConstants.EMPTY_BYTE_ARRAY, 0, 0);
2889 public static Cell createFirstOnRowCol(final Cell cell) {
2890 if (cell instanceof ByteBufferExtendedCell) {
2891 return new FirstOnRowColByteBufferExtendedCell(
2892 ((ByteBufferExtendedCell) cell).getRowByteBuffer(),
2893 ((ByteBufferExtendedCell) cell).getRowPosition(), cell.getRowLength(),
2894 HConstants.EMPTY_BYTE_BUFFER, 0, (byte) 0,
2895 ((ByteBufferExtendedCell) cell).getQualifierByteBuffer(),
2896 ((ByteBufferExtendedCell) cell).getQualifierPosition(), cell.getQualifierLength());
2898 return new FirstOnRowColCell(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength(),
2899 HConstants.EMPTY_BYTE_ARRAY, 0, (byte) 0, cell.getQualifierArray(),
2900 cell.getQualifierOffset(), cell.getQualifierLength());
2903 public static Cell createFirstOnNextRow(final Cell cell) {
2904 byte[] nextRow = new byte[cell.getRowLength() + 1];
2905 CellUtil.copyRowTo(cell, nextRow, 0);
2906 nextRow[nextRow.length - 1] = 0;// maybe not necessary
2907 return new FirstOnRowCell(nextRow, 0, (short) nextRow.length);
2911 * Create a Cell that is smaller than all other possible Cells for the given Cell's rk:cf and
2912 * passed qualifier.
2913 * @param cell
2914 * @param qArray
2915 * @param qoffest
2916 * @param qlength
2917 * @return Last possible Cell on passed Cell's rk:cf and passed qualifier.
2919 public static Cell createFirstOnRowCol(final Cell cell, byte[] qArray, int qoffest, int qlength) {
2920 if (cell instanceof ByteBufferExtendedCell) {
2921 return new FirstOnRowColByteBufferExtendedCell(
2922 ((ByteBufferExtendedCell) cell).getRowByteBuffer(),
2923 ((ByteBufferExtendedCell) cell).getRowPosition(), cell.getRowLength(),
2924 ((ByteBufferExtendedCell) cell).getFamilyByteBuffer(),
2925 ((ByteBufferExtendedCell) cell).getFamilyPosition(), cell.getFamilyLength(),
2926 ByteBuffer.wrap(qArray), qoffest, qlength);
2928 return new FirstOnRowColCell(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength(),
2929 cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength(), qArray, qoffest,
2930 qlength);
2934 * Creates the first cell with the row/family/qualifier of this cell and the given timestamp. Uses
2935 * the "maximum" type that guarantees that the new cell is the lowest possible for this
2936 * combination of row, family, qualifier, and timestamp. This cell's own timestamp is ignored.
2937 * @param cell - cell
2938 * @param ts
2940 public static Cell createFirstOnRowColTS(Cell cell, long ts) {
2941 if (cell instanceof ByteBufferExtendedCell) {
2942 return new FirstOnRowColTSByteBufferExtendedCell(
2943 ((ByteBufferExtendedCell) cell).getRowByteBuffer(),
2944 ((ByteBufferExtendedCell) cell).getRowPosition(), cell.getRowLength(),
2945 ((ByteBufferExtendedCell) cell).getFamilyByteBuffer(),
2946 ((ByteBufferExtendedCell) cell).getFamilyPosition(), cell.getFamilyLength(),
2947 ((ByteBufferExtendedCell) cell).getQualifierByteBuffer(),
2948 ((ByteBufferExtendedCell) cell).getQualifierPosition(), cell.getQualifierLength(), ts);
2950 return new FirstOnRowColTSCell(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength(),
2951 cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength(),
2952 cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength(), ts);
2956 * Create a Cell that is larger than all other possible Cells for the given Cell's row.
2957 * @param cell
2958 * @return Last possible Cell on passed Cell's row.
2960 public static Cell createLastOnRow(final Cell cell) {
2961 if (cell instanceof ByteBufferExtendedCell) {
2962 return new LastOnRowByteBufferExtendedCell(((ByteBufferExtendedCell) cell).getRowByteBuffer(),
2963 ((ByteBufferExtendedCell) cell).getRowPosition(), cell.getRowLength());
2965 return new LastOnRowCell(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
2968 public static Cell createLastOnRow(final byte[] row) {
2969 return new LastOnRowCell(row, 0, (short) row.length);
2973 * Create a Cell that is larger than all other possible Cells for the given Cell's rk:cf:q. Used
2974 * in creating "fake keys" for the multi-column Bloom filter optimization to skip the row/column
2975 * we already know is not in the file.
2976 * @param cell
2977 * @return Last possible Cell on passed Cell's rk:cf:q.
2979 public static Cell createLastOnRowCol(final Cell cell) {
2980 if (cell instanceof ByteBufferExtendedCell) {
2981 return new LastOnRowColByteBufferExtendedCell(
2982 ((ByteBufferExtendedCell) cell).getRowByteBuffer(),
2983 ((ByteBufferExtendedCell) cell).getRowPosition(), cell.getRowLength(),
2984 ((ByteBufferExtendedCell) cell).getFamilyByteBuffer(),
2985 ((ByteBufferExtendedCell) cell).getFamilyPosition(), cell.getFamilyLength(),
2986 ((ByteBufferExtendedCell) cell).getQualifierByteBuffer(),
2987 ((ByteBufferExtendedCell) cell).getQualifierPosition(), cell.getQualifierLength());
2989 return new LastOnRowColCell(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength(),
2990 cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength(),
2991 cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength());
2995 * Create a Delete Family Cell for the specified row and family that would be smaller than all
2996 * other possible Delete Family KeyValues that have the same row and family. Used for seeking.
2997 * @param row - row key (arbitrary byte array)
2998 * @param fam - family name
2999 * @return First Delete Family possible key on passed <code>row</code>.
3001 public static Cell createFirstDeleteFamilyCellOnRow(final byte[] row, final byte[] fam) {
3002 return new FirstOnRowDeleteFamilyCell(row, fam);