001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase; 019 020import static org.apache.hadoop.hbase.HConstants.EMPTY_BYTE_ARRAY; 021import static org.apache.hadoop.hbase.Tag.TAG_LENGTH_SIZE; 022 023import java.io.DataOutput; 024import java.io.DataOutputStream; 025import java.io.IOException; 026import java.io.OutputStream; 027import java.math.BigDecimal; 028import java.nio.ByteBuffer; 029import java.util.ArrayList; 030import java.util.Iterator; 031import java.util.List; 032import java.util.Map.Entry; 033import java.util.NavigableMap; 034import java.util.Optional; 035import org.apache.hadoop.hbase.filter.ByteArrayComparable; 036import org.apache.hadoop.hbase.io.TagCompressionContext; 037import org.apache.hadoop.hbase.io.util.Dictionary; 038import org.apache.hadoop.hbase.io.util.StreamUtils; 039import org.apache.hadoop.hbase.util.ByteBufferUtils; 040import org.apache.hadoop.hbase.util.ByteRange; 041import org.apache.hadoop.hbase.util.Bytes; 042import org.apache.hadoop.hbase.util.ClassSize; 043import org.apache.yetus.audience.InterfaceAudience; 044 045import org.apache.hbase.thirdparty.com.google.common.base.Preconditions; 046 047/** 048 * Utility methods helpful slinging {@link Cell} instances. It has more powerful and rich set of 049 * APIs than those in {@link CellUtil} for internal usage. 050 */ 051@InterfaceAudience.Private 052public final class PrivateCellUtil { 053 054 /** 055 * Private constructor to keep this class from being instantiated. 056 */ 057 private PrivateCellUtil() { 058 } 059 060 /******************* ByteRange *******************************/ 061 062 public static ByteRange fillRowRange(Cell cell, ByteRange range) { 063 return range.set(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength()); 064 } 065 066 public static ByteRange fillFamilyRange(Cell cell, ByteRange range) { 067 return range.set(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength()); 068 } 069 070 public static ByteRange fillQualifierRange(Cell cell, ByteRange range) { 071 return range.set(cell.getQualifierArray(), cell.getQualifierOffset(), 072 cell.getQualifierLength()); 073 } 074 075 public static ByteRange fillValueRange(Cell cell, ByteRange range) { 076 return range.set(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength()); 077 } 078 079 public static ByteRange fillTagRange(ExtendedCell cell, ByteRange range) { 080 return range.set(cell.getTagsArray(), cell.getTagsOffset(), cell.getTagsLength()); 081 } 082 083 /********************* misc *************************************/ 084 085 public static byte getRowByte(Cell cell, int index) { 086 if (cell instanceof ByteBufferExtendedCell) { 087 return ((ByteBufferExtendedCell) cell).getRowByteBuffer() 088 .get(((ByteBufferExtendedCell) cell).getRowPosition() + index); 089 } 090 return cell.getRowArray()[cell.getRowOffset() + index]; 091 } 092 093 public static byte getQualifierByte(Cell cell, int index) { 094 if (cell instanceof ByteBufferExtendedCell) { 095 return ((ByteBufferExtendedCell) cell).getQualifierByteBuffer() 096 .get(((ByteBufferExtendedCell) cell).getQualifierPosition() + index); 097 } 098 return cell.getQualifierArray()[cell.getQualifierOffset() + index]; 099 } 100 101 public static ByteBuffer getValueBufferShallowCopy(Cell cell) { 102 ByteBuffer buffer = 103 ByteBuffer.wrap(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength()); 104 return buffer; 105 } 106 107 /** Returns A new cell which is having the extra tags also added to it. */ 108 public static ExtendedCell createCell(ExtendedCell cell, List<Tag> tags) { 109 return createCell(cell, TagUtil.fromList(tags)); 110 } 111 112 /** Returns A new cell which is having the extra tags also added to it. */ 113 public static ExtendedCell createCell(ExtendedCell cell, byte[] tags) { 114 if (cell instanceof ByteBufferExtendedCell) { 115 return new TagRewriteByteBufferExtendedCell((ByteBufferExtendedCell) cell, tags); 116 } 117 return new TagRewriteCell(cell, tags); 118 } 119 120 public static ExtendedCell createCell(ExtendedCell cell, byte[] value, byte[] tags) { 121 if (cell instanceof ByteBufferExtendedCell) { 122 return new ValueAndTagRewriteByteBufferExtendedCell((ByteBufferExtendedCell) cell, value, 123 tags); 124 } 125 return new ValueAndTagRewriteCell(cell, value, tags); 126 } 127 128 /** 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. 132 */ 133 static class TagRewriteCell implements ExtendedCell { 134 protected ExtendedCell cell; 135 protected byte[] tags; 136 private static final int HEAP_SIZE_OVERHEAD = ClassSize.OBJECT + 2 * ClassSize.REFERENCE; 137 138 /** 139 * Construct a TagRewriteCell 140 * @param cell The original Cell which it rewrites 141 * @param tags the tags bytes. The array suppose to contain the tags bytes alone. 142 */ 143 public TagRewriteCell(ExtendedCell cell, byte[] tags) { 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; 151 } 152 } 153 154 @Override 155 public byte[] getRowArray() { 156 return cell.getRowArray(); 157 } 158 159 @Override 160 public int getRowOffset() { 161 return cell.getRowOffset(); 162 } 163 164 @Override 165 public short getRowLength() { 166 return cell.getRowLength(); 167 } 168 169 @Override 170 public byte[] getFamilyArray() { 171 return cell.getFamilyArray(); 172 } 173 174 @Override 175 public int getFamilyOffset() { 176 return cell.getFamilyOffset(); 177 } 178 179 @Override 180 public byte getFamilyLength() { 181 return cell.getFamilyLength(); 182 } 183 184 @Override 185 public byte[] getQualifierArray() { 186 return cell.getQualifierArray(); 187 } 188 189 @Override 190 public int getQualifierOffset() { 191 return cell.getQualifierOffset(); 192 } 193 194 @Override 195 public int getQualifierLength() { 196 return cell.getQualifierLength(); 197 } 198 199 @Override 200 public long getTimestamp() { 201 return cell.getTimestamp(); 202 } 203 204 @Override 205 public byte getTypeByte() { 206 return cell.getTypeByte(); 207 } 208 209 @Override 210 public long getSequenceId() { 211 return cell.getSequenceId(); 212 } 213 214 @Override 215 public byte[] getValueArray() { 216 return cell.getValueArray(); 217 } 218 219 @Override 220 public int getValueOffset() { 221 return cell.getValueOffset(); 222 } 223 224 @Override 225 public int getValueLength() { 226 return cell.getValueLength(); 227 } 228 229 @Override 230 public byte[] getTagsArray() { 231 return this.tags; 232 } 233 234 @Override 235 public int getTagsOffset() { 236 return 0; 237 } 238 239 @Override 240 public int getTagsLength() { 241 if (null == this.tags) { 242 // Nulled out tags array optimization in constructor 243 return 0; 244 } 245 return this.tags.length; 246 } 247 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); 253 } 254 return sum; 255 } 256 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); 261 } 262 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); 267 } 268 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); 273 } 274 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; 284 } 285 return len; 286 } 287 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; 293 } 294 return len; 295 } 296 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); 304 } 305 } 306 307 @Override 308 public ExtendedCell deepClone() { 309 ExtendedCell clonedBaseCell = this.cell.deepClone(); 310 return new TagRewriteCell(clonedBaseCell, this.tags); 311 } 312 } 313 314 static class TagRewriteByteBufferExtendedCell extends ByteBufferExtendedCell { 315 316 protected ByteBufferExtendedCell cell; 317 protected byte[] tags; 318 private static final int HEAP_SIZE_OVERHEAD = ClassSize.OBJECT + 2 * ClassSize.REFERENCE; 319 320 /** 321 * @param cell The original ByteBufferExtendedCell which it rewrites 322 * @param tags the tags bytes. The array suppose to contain the tags bytes alone. 323 */ 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; 332 } 333 } 334 335 @Override 336 public byte[] getRowArray() { 337 return this.cell.getRowArray(); 338 } 339 340 @Override 341 public int getRowOffset() { 342 return this.cell.getRowOffset(); 343 } 344 345 @Override 346 public short getRowLength() { 347 return this.cell.getRowLength(); 348 } 349 350 @Override 351 public byte[] getFamilyArray() { 352 return this.cell.getFamilyArray(); 353 } 354 355 @Override 356 public int getFamilyOffset() { 357 return this.cell.getFamilyOffset(); 358 } 359 360 @Override 361 public byte getFamilyLength() { 362 return this.cell.getFamilyLength(); 363 } 364 365 @Override 366 public byte[] getQualifierArray() { 367 return this.cell.getQualifierArray(); 368 } 369 370 @Override 371 public int getQualifierOffset() { 372 return this.cell.getQualifierOffset(); 373 } 374 375 @Override 376 public int getQualifierLength() { 377 return this.cell.getQualifierLength(); 378 } 379 380 @Override 381 public long getTimestamp() { 382 return this.cell.getTimestamp(); 383 } 384 385 @Override 386 public byte getTypeByte() { 387 return this.cell.getTypeByte(); 388 } 389 390 @Override 391 public long getSequenceId() { 392 return this.cell.getSequenceId(); 393 } 394 395 @Override 396 public byte[] getValueArray() { 397 return this.cell.getValueArray(); 398 } 399 400 @Override 401 public int getValueOffset() { 402 return this.cell.getValueOffset(); 403 } 404 405 @Override 406 public int getValueLength() { 407 return this.cell.getValueLength(); 408 } 409 410 @Override 411 public byte[] getTagsArray() { 412 return this.tags; 413 } 414 415 @Override 416 public int getTagsOffset() { 417 return 0; 418 } 419 420 @Override 421 public int getTagsLength() { 422 if (null == this.tags) { 423 // Nulled out tags array optimization in constructor 424 return 0; 425 } 426 return this.tags.length; 427 } 428 429 @Override 430 public void setSequenceId(long seqId) throws IOException { 431 PrivateCellUtil.setSequenceId(this.cell, seqId); 432 } 433 434 @Override 435 public void setTimestamp(long ts) throws IOException { 436 PrivateCellUtil.setTimestamp(this.cell, ts); 437 } 438 439 @Override 440 public void setTimestamp(byte[] ts) throws IOException { 441 PrivateCellUtil.setTimestamp(this.cell, ts); 442 } 443 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); 450 } 451 return sum; 452 } 453 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; 463 } 464 return len; 465 } 466 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; 472 } 473 return len; 474 } 475 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); 483 } 484 } 485 486 @Override 487 public ExtendedCell deepClone() { 488 ExtendedCell clonedBaseCell = this.cell.deepClone(); 489 if (clonedBaseCell instanceof ByteBufferExtendedCell) { 490 return new TagRewriteByteBufferExtendedCell((ByteBufferExtendedCell) clonedBaseCell, 491 this.tags); 492 } 493 return new TagRewriteCell(clonedBaseCell, this.tags); 494 } 495 496 @Override 497 public ByteBuffer getRowByteBuffer() { 498 return this.cell.getRowByteBuffer(); 499 } 500 501 @Override 502 public int getRowPosition() { 503 return this.cell.getRowPosition(); 504 } 505 506 @Override 507 public ByteBuffer getFamilyByteBuffer() { 508 return this.cell.getFamilyByteBuffer(); 509 } 510 511 @Override 512 public int getFamilyPosition() { 513 return this.cell.getFamilyPosition(); 514 } 515 516 @Override 517 public ByteBuffer getQualifierByteBuffer() { 518 return this.cell.getQualifierByteBuffer(); 519 } 520 521 @Override 522 public int getQualifierPosition() { 523 return this.cell.getQualifierPosition(); 524 } 525 526 @Override 527 public ByteBuffer getValueByteBuffer() { 528 return this.cell.getValueByteBuffer(); 529 } 530 531 @Override 532 public int getValuePosition() { 533 return this.cell.getValuePosition(); 534 } 535 536 @Override 537 public ByteBuffer getTagsByteBuffer() { 538 return this.tags == null ? HConstants.EMPTY_BYTE_BUFFER : ByteBuffer.wrap(this.tags); 539 } 540 541 @Override 542 public int getTagsPosition() { 543 return 0; 544 } 545 } 546 547 static class ValueAndTagRewriteCell extends TagRewriteCell { 548 549 protected byte[] value; 550 551 public ValueAndTagRewriteCell(ExtendedCell cell, byte[] value, byte[] tags) { 552 super(cell, tags); 553 this.value = value; 554 } 555 556 @Override 557 public byte[] getValueArray() { 558 return this.value; 559 } 560 561 @Override 562 public int getValueOffset() { 563 return 0; 564 } 565 566 @Override 567 public int getValueLength() { 568 return this.value == null ? 0 : this.value.length; 569 } 570 571 @Override 572 public long heapSize() { 573 long sum = ClassSize.REFERENCE + super.heapSize(); 574 if (this.value != null) { 575 sum += ClassSize.sizeOf(this.value); 576 } 577 return sum; 578 } 579 580 @Override 581 public int write(OutputStream out, boolean withTags) throws IOException { 582 return write(out, withTags, this.cell, this.value, this.tags); 583 } 584 585 /** 586 * Made into a static method so as to reuse the logic within 587 * ValueAndTagRewriteByteBufferExtendedCell 588 */ 589 static int write(OutputStream out, boolean withTags, ExtendedCell cell, byte[] value, 590 byte[] tags) 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 598 } 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; 606 } 607 return len; 608 } 609 610 @Override 611 public int getSerializedSize(boolean withTags) { 612 return super.getSerializedSize(withTags) - this.cell.getValueLength() + this.value.length; 613 } 614 615 @Override 616 public void write(ByteBuffer buf, int offset) { 617 write(buf, offset, this.cell, this.value, this.tags); 618 } 619 620 /** 621 * Made into a static method so as to reuse the logic within 622 * ValueAndTagRewriteByteBufferExtendedCell 623 */ 624 static void write(ByteBuffer buf, int offset, ExtendedCell 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); 634 } 635 } 636 637 @Override 638 public ExtendedCell deepClone() { 639 ExtendedCell clonedBaseCell = this.cell.deepClone(); 640 return new ValueAndTagRewriteCell(clonedBaseCell, this.value, this.tags); 641 } 642 } 643 644 static class ValueAndTagRewriteByteBufferExtendedCell extends TagRewriteByteBufferExtendedCell { 645 646 protected byte[] value; 647 648 public ValueAndTagRewriteByteBufferExtendedCell(ByteBufferExtendedCell cell, byte[] value, 649 byte[] tags) { 650 super(cell, tags); 651 this.value = value; 652 } 653 654 @Override 655 public byte[] getValueArray() { 656 return this.value; 657 } 658 659 @Override 660 public int getValueOffset() { 661 return 0; 662 } 663 664 @Override 665 public int getValueLength() { 666 return this.value == null ? 0 : this.value.length; 667 } 668 669 @Override 670 public ByteBuffer getValueByteBuffer() { 671 return ByteBuffer.wrap(this.value); 672 } 673 674 @Override 675 public int getValuePosition() { 676 return 0; 677 } 678 679 @Override 680 public long heapSize() { 681 long sum = ClassSize.REFERENCE + super.heapSize(); 682 if (this.value != null) { 683 sum += ClassSize.sizeOf(this.value); 684 } 685 return sum; 686 } 687 688 @Override 689 public int write(OutputStream out, boolean withTags) throws IOException { 690 return ValueAndTagRewriteCell.write(out, withTags, this.cell, this.value, this.tags); 691 } 692 693 @Override 694 public int getSerializedSize(boolean withTags) { 695 return super.getSerializedSize(withTags) - this.cell.getValueLength() + this.value.length; 696 } 697 698 @Override 699 public void write(ByteBuffer buf, int offset) { 700 ValueAndTagRewriteCell.write(buf, offset, this.cell, this.value, this.tags); 701 } 702 703 @Override 704 public ExtendedCell deepClone() { 705 ExtendedCell clonedBaseCell = this.cell.deepClone(); 706 if (clonedBaseCell instanceof ByteBufferExtendedCell) { 707 return new ValueAndTagRewriteByteBufferExtendedCell((ByteBufferExtendedCell) clonedBaseCell, 708 this.value, this.tags); 709 } 710 return new ValueAndTagRewriteCell(clonedBaseCell, this.value, this.tags); 711 } 712 } 713 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(), buf, offset, length); 719 } 720 return Bytes.equals(left.getRowArray(), left.getRowOffset(), left.getRowLength(), buf, offset, 721 length); 722 } 723 724 public static boolean matchingFamily(final Cell left, final byte[] buf, final int offset, 725 final int length) { 726 if (left instanceof ByteBufferExtendedCell) { 727 return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getFamilyByteBuffer(), 728 ((ByteBufferExtendedCell) left).getFamilyPosition(), left.getFamilyLength(), buf, offset, 729 length); 730 } 731 return Bytes.equals(left.getFamilyArray(), left.getFamilyOffset(), left.getFamilyLength(), buf, 732 offset, length); 733 } 734 735 /** 736 * Finds if the qualifier part of the cell and the KV serialized byte[] are equal 737 * @param left the cell with which we need to match the qualifier 738 * @param buf the serialized keyvalue format byte[] 739 * @param offset the offset of the qualifier in the byte[] 740 * @param length the length of the qualifier in the byte[] 741 * @return true if the qualifier matches, false otherwise 742 */ 743 public static boolean matchingQualifier(final Cell left, final byte[] buf, final int offset, 744 final int length) { 745 if (buf == null) { 746 return left.getQualifierLength() == 0; 747 } 748 if (left instanceof ByteBufferExtendedCell) { 749 return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getQualifierByteBuffer(), 750 ((ByteBufferExtendedCell) left).getQualifierPosition(), left.getQualifierLength(), buf, 751 offset, length); 752 } 753 return Bytes.equals(left.getQualifierArray(), left.getQualifierOffset(), 754 left.getQualifierLength(), buf, offset, length); 755 } 756 757 /** 758 * Finds if the start of the qualifier part of the Cell matches <code>buf</code> 759 * @param left the cell with which we need to match the qualifier 760 * @param startsWith the serialized keyvalue format byte[] 761 * @return true if the qualifier have same staring characters, false otherwise 762 */ 763 public static boolean qualifierStartsWith(final Cell left, final byte[] startsWith) { 764 if (startsWith == null || startsWith.length == 0) { 765 throw new IllegalArgumentException("Cannot pass an empty startsWith"); 766 } 767 if (left.getQualifierLength() < startsWith.length) { 768 return false; 769 } 770 if (left instanceof ByteBufferExtendedCell) { 771 return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getQualifierByteBuffer(), 772 ((ByteBufferExtendedCell) left).getQualifierPosition(), startsWith.length, startsWith, 0, 773 startsWith.length); 774 } 775 return Bytes.equals(left.getQualifierArray(), left.getQualifierOffset(), startsWith.length, 776 startsWith, 0, startsWith.length); 777 } 778 779 public static boolean matchingColumn(final Cell left, final byte[] fam, final int foffset, 780 final int flength, final byte[] qual, final int qoffset, final int qlength) { 781 if (!matchingFamily(left, fam, foffset, flength)) { 782 return false; 783 } 784 return matchingQualifier(left, qual, qoffset, qlength); 785 } 786 787 public static boolean matchingValue(final Cell left, final Cell right, int lvlength, 788 int rvlength) { 789 if (left instanceof ByteBufferExtendedCell && right instanceof ByteBufferExtendedCell) { 790 return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getValueByteBuffer(), 791 ((ByteBufferExtendedCell) left).getValuePosition(), lvlength, 792 ((ByteBufferExtendedCell) right).getValueByteBuffer(), 793 ((ByteBufferExtendedCell) right).getValuePosition(), rvlength); 794 } 795 if (left instanceof ByteBufferExtendedCell) { 796 return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getValueByteBuffer(), 797 ((ByteBufferExtendedCell) left).getValuePosition(), lvlength, right.getValueArray(), 798 right.getValueOffset(), rvlength); 799 } 800 if (right instanceof ByteBufferExtendedCell) { 801 return ByteBufferUtils.equals(((ByteBufferExtendedCell) right).getValueByteBuffer(), 802 ((ByteBufferExtendedCell) right).getValuePosition(), rvlength, left.getValueArray(), 803 left.getValueOffset(), lvlength); 804 } 805 return Bytes.equals(left.getValueArray(), left.getValueOffset(), lvlength, 806 right.getValueArray(), right.getValueOffset(), rvlength); 807 } 808 809 public static boolean matchingType(ExtendedCell a, ExtendedCell b) { 810 return a.getTypeByte() == b.getTypeByte(); 811 } 812 813 public static boolean matchingTags(final ExtendedCell left, final ExtendedCell right) { 814 return matchingTags(left, right, left.getTagsLength(), right.getTagsLength()); 815 } 816 817 public static boolean matchingTags(final ExtendedCell left, final ExtendedCell right, int llength, 818 int rlength) { 819 if (left instanceof ByteBufferExtendedCell && right instanceof ByteBufferExtendedCell) { 820 ByteBufferExtendedCell leftBBCell = (ByteBufferExtendedCell) left; 821 ByteBufferExtendedCell rightBBCell = (ByteBufferExtendedCell) right; 822 return ByteBufferUtils.equals(leftBBCell.getTagsByteBuffer(), leftBBCell.getTagsPosition(), 823 llength, rightBBCell.getTagsByteBuffer(), rightBBCell.getTagsPosition(), rlength); 824 } 825 if (left instanceof ByteBufferExtendedCell) { 826 ByteBufferExtendedCell leftBBCell = (ByteBufferExtendedCell) left; 827 return ByteBufferUtils.equals(leftBBCell.getTagsByteBuffer(), leftBBCell.getTagsPosition(), 828 llength, right.getTagsArray(), right.getTagsOffset(), rlength); 829 } 830 if (right instanceof ByteBufferExtendedCell) { 831 ByteBufferExtendedCell rightBBCell = (ByteBufferExtendedCell) right; 832 return ByteBufferUtils.equals(rightBBCell.getTagsByteBuffer(), rightBBCell.getTagsPosition(), 833 rlength, left.getTagsArray(), left.getTagsOffset(), llength); 834 } 835 return Bytes.equals(left.getTagsArray(), left.getTagsOffset(), llength, right.getTagsArray(), 836 right.getTagsOffset(), rlength); 837 } 838 839 /** 840 * Return true if a delete type, a {@link KeyValue.Type#Delete} or a {KeyValue.Type#DeleteFamily} 841 * or a {@link KeyValue.Type#DeleteColumn} KeyValue type. 842 */ 843 public static boolean isDelete(final byte type) { 844 return KeyValue.Type.Delete.getCode() <= type && type <= KeyValue.Type.DeleteFamily.getCode(); 845 } 846 847 /** Returns True if this cell is a {@link KeyValue.Type#Delete} type. */ 848 public static boolean isDeleteType(ExtendedCell cell) { 849 return cell.getTypeByte() == KeyValue.Type.Delete.getCode(); 850 } 851 852 public static boolean isDeleteFamily(final ExtendedCell cell) { 853 return cell.getTypeByte() == KeyValue.Type.DeleteFamily.getCode(); 854 } 855 856 public static boolean isDeleteFamilyVersion(final ExtendedCell cell) { 857 return cell.getTypeByte() == KeyValue.Type.DeleteFamilyVersion.getCode(); 858 } 859 860 public static boolean isDeleteColumns(final ExtendedCell cell) { 861 return cell.getTypeByte() == KeyValue.Type.DeleteColumn.getCode(); 862 } 863 864 public static boolean isDeleteColumnVersion(final ExtendedCell cell) { 865 return cell.getTypeByte() == KeyValue.Type.Delete.getCode(); 866 } 867 868 /** Returns True if this cell is a delete family or column type. */ 869 public static boolean isDeleteColumnOrFamily(ExtendedCell cell) { 870 int t = cell.getTypeByte(); 871 return t == KeyValue.Type.DeleteColumn.getCode() || t == KeyValue.Type.DeleteFamily.getCode(); 872 } 873 874 public static byte[] cloneTags(ExtendedCell cell) { 875 byte[] output = new byte[cell.getTagsLength()]; 876 copyTagsTo(cell, output, 0); 877 return output; 878 } 879 880 /** Copies the tags info into the tag portion of the cell */ 881 public static int copyTagsTo(ExtendedCell cell, byte[] destination, int destinationOffset) { 882 int tlen = cell.getTagsLength(); 883 if (cell instanceof ByteBufferExtendedCell) { 884 ByteBufferUtils.copyFromBufferToArray(destination, 885 ((ByteBufferExtendedCell) cell).getTagsByteBuffer(), 886 ((ByteBufferExtendedCell) cell).getTagsPosition(), destinationOffset, tlen); 887 } else { 888 System.arraycopy(cell.getTagsArray(), cell.getTagsOffset(), destination, destinationOffset, 889 tlen); 890 } 891 return destinationOffset + tlen; 892 } 893 894 /** Copies the tags info into the tag portion of the cell */ 895 public static int copyTagsTo(ExtendedCell cell, ByteBuffer destination, int destinationOffset) { 896 int tlen = cell.getTagsLength(); 897 if (cell instanceof ByteBufferExtendedCell) { 898 ByteBufferUtils.copyFromBufferToBuffer(((ByteBufferExtendedCell) cell).getTagsByteBuffer(), 899 destination, ((ByteBufferExtendedCell) cell).getTagsPosition(), destinationOffset, tlen); 900 } else { 901 ByteBufferUtils.copyFromArrayToBuffer(destination, destinationOffset, cell.getTagsArray(), 902 cell.getTagsOffset(), tlen); 903 } 904 return destinationOffset + tlen; 905 } 906 907 /** 908 * Return tags in the given Cell as a List 909 * @param cell The Cell 910 * @return Tags in the given Cell as a List 911 */ 912 public static List<Tag> getTags(ExtendedCell cell) { 913 List<Tag> tags = new ArrayList<>(); 914 Iterator<Tag> tagsItr = tagsIterator(cell); 915 while (tagsItr.hasNext()) { 916 tags.add(tagsItr.next()); 917 } 918 return tags; 919 } 920 921 /** 922 * Retrieve Cell's first tag, matching the passed in type 923 * @param cell The Cell 924 * @param type Type of the Tag to retrieve 925 * @return Optional, empty if there is no tag of the passed in tag type 926 */ 927 public static Optional<Tag> getTag(ExtendedCell cell, byte type) { 928 boolean bufferBacked = cell instanceof ByteBufferExtendedCell; 929 int length = cell.getTagsLength(); 930 int offset = 931 bufferBacked ? ((ByteBufferExtendedCell) cell).getTagsPosition() : cell.getTagsOffset(); 932 int pos = offset; 933 while (pos < offset + length) { 934 int tagLen; 935 if (bufferBacked) { 936 ByteBuffer tagsBuffer = ((ByteBufferExtendedCell) cell).getTagsByteBuffer(); 937 tagLen = ByteBufferUtils.readAsInt(tagsBuffer, pos, TAG_LENGTH_SIZE); 938 if (ByteBufferUtils.toByte(tagsBuffer, pos + TAG_LENGTH_SIZE) == type) { 939 return Optional.of(new ByteBufferTag(tagsBuffer, pos, tagLen + TAG_LENGTH_SIZE)); 940 } 941 } else { 942 tagLen = Bytes.readAsInt(cell.getTagsArray(), pos, TAG_LENGTH_SIZE); 943 if (cell.getTagsArray()[pos + TAG_LENGTH_SIZE] == type) { 944 return Optional 945 .of(new ArrayBackedTag(cell.getTagsArray(), pos, tagLen + TAG_LENGTH_SIZE)); 946 } 947 } 948 pos += TAG_LENGTH_SIZE + tagLen; 949 } 950 return Optional.empty(); 951 } 952 953 /** 954 * Utility method to iterate through the tags in the given cell. 955 * @param cell The Cell over which tags iterator is needed. 956 * @return iterator for the tags 957 */ 958 public static Iterator<Tag> tagsIterator(final ExtendedCell cell) { 959 final int tagsLength = cell.getTagsLength(); 960 // Save an object allocation where we can 961 if (tagsLength == 0) { 962 return TagUtil.EMPTY_TAGS_ITR; 963 } 964 if (cell instanceof ByteBufferExtendedCell) { 965 return tagsIterator(((ByteBufferExtendedCell) cell).getTagsByteBuffer(), 966 ((ByteBufferExtendedCell) cell).getTagsPosition(), tagsLength); 967 } 968 969 return new Iterator<Tag>() { 970 private int offset = cell.getTagsOffset(); 971 private int pos = offset; 972 private int endOffset = offset + cell.getTagsLength() - 1; 973 974 @Override 975 public boolean hasNext() { 976 return this.pos < endOffset; 977 } 978 979 @Override 980 public Tag next() { 981 if (hasNext()) { 982 byte[] tags = cell.getTagsArray(); 983 int curTagLen = Bytes.readAsInt(tags, this.pos, Tag.TAG_LENGTH_SIZE); 984 Tag tag = new ArrayBackedTag(tags, pos, curTagLen + TAG_LENGTH_SIZE); 985 this.pos += Bytes.SIZEOF_SHORT + curTagLen; 986 return tag; 987 } 988 return null; 989 } 990 991 @Override 992 public void remove() { 993 throw new UnsupportedOperationException(); 994 } 995 }; 996 } 997 998 public static Iterator<Tag> tagsIterator(final ByteBuffer tags, final int offset, 999 final int length) { 1000 return new Iterator<Tag>() { 1001 private int pos = offset; 1002 private int endOffset = offset + length - 1; 1003 1004 @Override 1005 public boolean hasNext() { 1006 return this.pos < endOffset; 1007 } 1008 1009 @Override 1010 public Tag next() { 1011 if (hasNext()) { 1012 int curTagLen = ByteBufferUtils.readAsInt(tags, this.pos, Tag.TAG_LENGTH_SIZE); 1013 Tag tag = new ByteBufferTag(tags, pos, curTagLen + Tag.TAG_LENGTH_SIZE); 1014 this.pos += Bytes.SIZEOF_SHORT + curTagLen; 1015 return tag; 1016 } 1017 return null; 1018 } 1019 1020 @Override 1021 public void remove() { 1022 throw new UnsupportedOperationException(); 1023 } 1024 }; 1025 } 1026 1027 /** 1028 * Returns true if the first range start1...end1 overlaps with the second range start2...end2, 1029 * assuming the byte arrays represent row keys 1030 */ 1031 public static boolean overlappingKeys(final byte[] start1, final byte[] end1, final byte[] start2, 1032 final byte[] end2) { 1033 return (end2.length == 0 || start1.length == 0 || Bytes.compareTo(start1, end2) < 0) 1034 && (end1.length == 0 || start2.length == 0 || Bytes.compareTo(start2, end1) < 0); 1035 } 1036 1037 /** Write rowkey excluding the common part. */ 1038 public static void writeRowKeyExcludingCommon(Cell cell, short rLen, int commonPrefix, 1039 DataOutputStream out) throws IOException { 1040 if (commonPrefix == 0) { 1041 out.writeShort(rLen); 1042 } else if (commonPrefix == 1) { 1043 out.writeByte((byte) rLen); 1044 commonPrefix--; 1045 } else { 1046 commonPrefix -= KeyValue.ROW_LENGTH_SIZE; 1047 } 1048 if (rLen > commonPrefix) { 1049 writeRowSkippingBytes(out, cell, rLen, commonPrefix); 1050 } 1051 } 1052 1053 /** 1054 * Writes the row from the given cell to the output stream excluding the common prefix 1055 * @param out The dataoutputstream to which the data has to be written 1056 * @param cell The cell whose contents has to be written 1057 * @param rlength the row length 1058 */ 1059 public static void writeRowSkippingBytes(DataOutputStream out, Cell cell, short rlength, 1060 int commonPrefix) throws IOException { 1061 if (cell instanceof ByteBufferExtendedCell) { 1062 ByteBufferUtils.copyBufferToStream((DataOutput) out, 1063 ((ByteBufferExtendedCell) cell).getRowByteBuffer(), 1064 ((ByteBufferExtendedCell) cell).getRowPosition() + commonPrefix, rlength - commonPrefix); 1065 } else { 1066 out.write(cell.getRowArray(), cell.getRowOffset() + commonPrefix, rlength - commonPrefix); 1067 } 1068 } 1069 1070 /** 1071 * Find length of common prefix in keys of the cells, considering key as byte[] if serialized in 1072 * {@link KeyValue}. The key format is <2 bytes rk len><rk><1 byte cf 1073 * len><cf><qualifier><8 bytes timestamp><1 byte type> 1074 * @param c1 the cell 1075 * @param c2 the cell 1076 * @param bypassFamilyCheck when true assume the family bytes same in both cells. Pass it as true 1077 * when dealing with Cells in same CF so as to avoid some checks 1078 * @param withTsType when true check timestamp and type bytes also. 1079 * @return length of common prefix 1080 */ 1081 public static int findCommonPrefixInFlatKey(ExtendedCell c1, ExtendedCell c2, 1082 boolean bypassFamilyCheck, boolean withTsType) { 1083 // Compare the 2 bytes in RK length part 1084 short rLen1 = c1.getRowLength(); 1085 short rLen2 = c2.getRowLength(); 1086 int commonPrefix = KeyValue.ROW_LENGTH_SIZE; 1087 if (rLen1 != rLen2) { 1088 // early out when the RK length itself is not matching 1089 return ByteBufferUtils.findCommonPrefix(Bytes.toBytes(rLen1), 0, KeyValue.ROW_LENGTH_SIZE, 1090 Bytes.toBytes(rLen2), 0, KeyValue.ROW_LENGTH_SIZE); 1091 } 1092 // Compare the RKs 1093 int rkCommonPrefix = 0; 1094 if (c1 instanceof ByteBufferExtendedCell && c2 instanceof ByteBufferExtendedCell) { 1095 rkCommonPrefix = 1096 ByteBufferUtils.findCommonPrefix(((ByteBufferExtendedCell) c1).getRowByteBuffer(), 1097 ((ByteBufferExtendedCell) c1).getRowPosition(), rLen1, 1098 ((ByteBufferExtendedCell) c2).getRowByteBuffer(), 1099 ((ByteBufferExtendedCell) c2).getRowPosition(), rLen2); 1100 } else { 1101 // There cannot be a case where one cell is BBCell and other is KeyValue. This flow comes 1102 // either 1103 // in flush or compactions. In flushes both cells are KV and in case of compaction it will be 1104 // either 1105 // KV or BBCell 1106 rkCommonPrefix = ByteBufferUtils.findCommonPrefix(c1.getRowArray(), c1.getRowOffset(), rLen1, 1107 c2.getRowArray(), c2.getRowOffset(), rLen2); 1108 } 1109 commonPrefix += rkCommonPrefix; 1110 if (rkCommonPrefix != rLen1) { 1111 // Early out when RK is not fully matching. 1112 return commonPrefix; 1113 } 1114 // Compare 1 byte CF length part 1115 byte fLen1 = c1.getFamilyLength(); 1116 if (bypassFamilyCheck) { 1117 // This flag will be true when caller is sure that the family will be same for both the cells 1118 // Just make commonPrefix to increment by the family part 1119 commonPrefix += KeyValue.FAMILY_LENGTH_SIZE + fLen1; 1120 } else { 1121 byte fLen2 = c2.getFamilyLength(); 1122 if (fLen1 != fLen2) { 1123 // early out when the CF length itself is not matching 1124 return commonPrefix; 1125 } 1126 // CF lengths are same so there is one more byte common in key part 1127 commonPrefix += KeyValue.FAMILY_LENGTH_SIZE; 1128 // Compare the CF names 1129 int fCommonPrefix; 1130 if (c1 instanceof ByteBufferExtendedCell && c2 instanceof ByteBufferExtendedCell) { 1131 fCommonPrefix = 1132 ByteBufferUtils.findCommonPrefix(((ByteBufferExtendedCell) c1).getFamilyByteBuffer(), 1133 ((ByteBufferExtendedCell) c1).getFamilyPosition(), fLen1, 1134 ((ByteBufferExtendedCell) c2).getFamilyByteBuffer(), 1135 ((ByteBufferExtendedCell) c2).getFamilyPosition(), fLen2); 1136 } else { 1137 fCommonPrefix = ByteBufferUtils.findCommonPrefix(c1.getFamilyArray(), c1.getFamilyOffset(), 1138 fLen1, c2.getFamilyArray(), c2.getFamilyOffset(), fLen2); 1139 } 1140 commonPrefix += fCommonPrefix; 1141 if (fCommonPrefix != fLen1) { 1142 return commonPrefix; 1143 } 1144 } 1145 // Compare the Qualifiers 1146 int qLen1 = c1.getQualifierLength(); 1147 int qLen2 = c2.getQualifierLength(); 1148 int qCommon; 1149 if (c1 instanceof ByteBufferExtendedCell && c2 instanceof ByteBufferExtendedCell) { 1150 qCommon = 1151 ByteBufferUtils.findCommonPrefix(((ByteBufferExtendedCell) c1).getQualifierByteBuffer(), 1152 ((ByteBufferExtendedCell) c1).getQualifierPosition(), qLen1, 1153 ((ByteBufferExtendedCell) c2).getQualifierByteBuffer(), 1154 ((ByteBufferExtendedCell) c2).getQualifierPosition(), qLen2); 1155 } else { 1156 qCommon = ByteBufferUtils.findCommonPrefix(c1.getQualifierArray(), c1.getQualifierOffset(), 1157 qLen1, c2.getQualifierArray(), c2.getQualifierOffset(), qLen2); 1158 } 1159 commonPrefix += qCommon; 1160 if (!withTsType || Math.max(qLen1, qLen2) != qCommon) { 1161 return commonPrefix; 1162 } 1163 // Compare the timestamp parts 1164 int tsCommonPrefix = ByteBufferUtils.findCommonPrefix(Bytes.toBytes(c1.getTimestamp()), 0, 1165 KeyValue.TIMESTAMP_SIZE, Bytes.toBytes(c2.getTimestamp()), 0, KeyValue.TIMESTAMP_SIZE); 1166 commonPrefix += tsCommonPrefix; 1167 if (tsCommonPrefix != KeyValue.TIMESTAMP_SIZE) { 1168 return commonPrefix; 1169 } 1170 // Compare the type 1171 if (c1.getTypeByte() == c2.getTypeByte()) { 1172 commonPrefix += KeyValue.TYPE_SIZE; 1173 } 1174 return commonPrefix; 1175 } 1176 1177 /** 1178 * Used to compare two cells based on the column hint provided. This is specifically used when we 1179 * need to optimize the seeks based on the next indexed key. This is an advanced usage API 1180 * specifically needed for some optimizations. 1181 * @param nextIndexedCell the next indexed cell 1182 * @param currentCell the cell to be compared 1183 * @param foff the family offset of the currentCell 1184 * @param flen the family length of the currentCell 1185 * @param colHint the column hint provided - could be null 1186 * @param coff the offset of the column hint if provided, if not offset of the 1187 * currentCell's qualifier 1188 * @param clen the length of the column hint if provided, if not length of the 1189 * currentCell's qualifier 1190 * @param ts the timestamp to be seeked 1191 * @param type the type to be seeked 1192 * @return an int based on the given column hint TODO : To be moved out of here because this is a 1193 * special API used in scan optimization. 1194 */ 1195 // compare a key against row/fam/qual/ts/type 1196 public static final int compareKeyBasedOnColHint(CellComparator comparator, 1197 ExtendedCell nextIndexedCell, ExtendedCell currentCell, int foff, int flen, byte[] colHint, 1198 int coff, int clen, long ts, byte type) { 1199 int compare = comparator.compareRows(nextIndexedCell, currentCell); 1200 if (compare != 0) { 1201 return compare; 1202 } 1203 // If the column is not specified, the "minimum" key type appears the 1204 // latest in the sorted order, regardless of the timestamp. This is used 1205 // for specifying the last key/value in a given row, because there is no 1206 // "lexicographically last column" (it would be infinitely long). The 1207 // "maximum" key type does not need this behavior. 1208 if ( 1209 nextIndexedCell.getFamilyLength() + nextIndexedCell.getQualifierLength() == 0 1210 && nextIndexedCell.getTypeByte() == KeyValue.Type.Minimum.getCode() 1211 ) { 1212 // left is "bigger", i.e. it appears later in the sorted order 1213 return 1; 1214 } 1215 if (flen + clen == 0 && type == KeyValue.Type.Minimum.getCode()) { 1216 return -1; 1217 } 1218 1219 compare = comparator.compareFamilies(nextIndexedCell, currentCell); 1220 if (compare != 0) { 1221 return compare; 1222 } 1223 if (colHint == null) { 1224 compare = comparator.compareQualifiers(nextIndexedCell, currentCell); 1225 } else { 1226 compare = CellUtil.compareQualifiers(nextIndexedCell, colHint, coff, clen); 1227 } 1228 if (compare != 0) { 1229 return compare; 1230 } 1231 // Next compare timestamps. 1232 compare = comparator.compareTimestamps(nextIndexedCell.getTimestamp(), ts); 1233 if (compare != 0) { 1234 return compare; 1235 } 1236 1237 // Compare types. Let the delete types sort ahead of puts; i.e. types 1238 // of higher numbers sort before those of lesser numbers. Maximum (255) 1239 // appears ahead of everything, and minimum (0) appears after 1240 // everything. 1241 return (0xff & type) - (0xff & nextIndexedCell.getTypeByte()); 1242 } 1243 1244 /** 1245 * Compares only the key portion of a cell. It does not include the sequence id/mvcc of the cell 1246 * @return an int greater than 0 if left > than right lesser than 0 if left < than right 1247 * equal to 0 if left is equal to right 1248 */ 1249 public static final int compareKeyIgnoresMvcc(CellComparator comparator, Cell left, Cell right) { 1250 return ((CellComparatorImpl) comparator).compare(left, right, true); 1251 } 1252 1253 /** 1254 * Compare cell's row against given comparator 1255 * @param cell the cell to use for comparison 1256 * @param comparator the {@link CellComparator} to use for comparison 1257 * @return result comparing cell's row 1258 */ 1259 public static int compareRow(Cell cell, ByteArrayComparable comparator) { 1260 if (cell instanceof ByteBufferExtendedCell) { 1261 return comparator.compareTo(((ByteBufferExtendedCell) cell).getRowByteBuffer(), 1262 ((ByteBufferExtendedCell) cell).getRowPosition(), cell.getRowLength()); 1263 } 1264 return comparator.compareTo(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength()); 1265 } 1266 1267 /** 1268 * Compare cell's column family against given comparator 1269 * @param cell the cell to use for comparison 1270 * @param comparator the {@link CellComparator} to use for comparison 1271 * @return result comparing cell's column family 1272 */ 1273 public static int compareFamily(Cell cell, ByteArrayComparable comparator) { 1274 if (cell instanceof ByteBufferExtendedCell) { 1275 return comparator.compareTo(((ByteBufferExtendedCell) cell).getFamilyByteBuffer(), 1276 ((ByteBufferExtendedCell) cell).getFamilyPosition(), cell.getFamilyLength()); 1277 } 1278 return comparator.compareTo(cell.getFamilyArray(), cell.getFamilyOffset(), 1279 cell.getFamilyLength()); 1280 } 1281 1282 /** 1283 * Compare cell's qualifier against given comparator 1284 * @param cell the cell to use for comparison 1285 * @param comparator the {@link CellComparator} to use for comparison 1286 * @return result comparing cell's qualifier 1287 */ 1288 public static int compareQualifier(Cell cell, ByteArrayComparable comparator) { 1289 if (cell instanceof ByteBufferExtendedCell) { 1290 return comparator.compareTo(((ByteBufferExtendedCell) cell).getQualifierByteBuffer(), 1291 ((ByteBufferExtendedCell) cell).getQualifierPosition(), cell.getQualifierLength()); 1292 } 1293 return comparator.compareTo(cell.getQualifierArray(), cell.getQualifierOffset(), 1294 cell.getQualifierLength()); 1295 } 1296 1297 public static Cell.Type toType(byte type) { 1298 KeyValue.Type codeToType = KeyValue.Type.codeToType(type); 1299 switch (codeToType) { 1300 case Put: 1301 return Cell.Type.Put; 1302 case Delete: 1303 return Cell.Type.Delete; 1304 case DeleteColumn: 1305 return Cell.Type.DeleteColumn; 1306 case DeleteFamily: 1307 return Cell.Type.DeleteFamily; 1308 case DeleteFamilyVersion: 1309 return Cell.Type.DeleteFamilyVersion; 1310 default: 1311 throw new UnsupportedOperationException("Invalid type of cell " + type); 1312 } 1313 } 1314 1315 public static KeyValue.Type toTypeByte(Cell.Type type) { 1316 switch (type) { 1317 case Put: 1318 return KeyValue.Type.Put; 1319 case Delete: 1320 return KeyValue.Type.Delete; 1321 case DeleteColumn: 1322 return KeyValue.Type.DeleteColumn; 1323 case DeleteFamilyVersion: 1324 return KeyValue.Type.DeleteFamilyVersion; 1325 case DeleteFamily: 1326 return KeyValue.Type.DeleteFamily; 1327 default: 1328 throw new UnsupportedOperationException("Unsupported data type:" + type); 1329 } 1330 } 1331 1332 /** 1333 * Compare cell's value against given comparator 1334 * @param cell the cell to use for comparison 1335 * @param comparator the {@link CellComparator} to use for comparison 1336 * @return result comparing cell's value 1337 */ 1338 public static int compareValue(Cell cell, ByteArrayComparable comparator) { 1339 if (cell instanceof ByteBufferExtendedCell) { 1340 return comparator.compareTo(((ByteBufferExtendedCell) cell).getValueByteBuffer(), 1341 ((ByteBufferExtendedCell) cell).getValuePosition(), cell.getValueLength()); 1342 } 1343 return comparator.compareTo(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength()); 1344 } 1345 1346 /** 1347 * These cells are used in reseeks/seeks to improve the read performance. They are not real cells 1348 * that are returned back to the clients 1349 */ 1350 private static abstract class EmptyCell implements ExtendedCell { 1351 1352 @Override 1353 public void setSequenceId(long seqId) { 1354 // Fake cells don't need seqId, so leaving it as a noop. 1355 } 1356 1357 @Override 1358 public void setTimestamp(long ts) { 1359 // Fake cells can't be changed timestamp, so leaving it as a noop. 1360 } 1361 1362 @Override 1363 public void setTimestamp(byte[] ts) { 1364 // Fake cells can't be changed timestamp, so leaving it as a noop. 1365 } 1366 1367 @Override 1368 public byte[] getRowArray() { 1369 return EMPTY_BYTE_ARRAY; 1370 } 1371 1372 @Override 1373 public int getRowOffset() { 1374 return 0; 1375 } 1376 1377 @Override 1378 public short getRowLength() { 1379 return 0; 1380 } 1381 1382 @Override 1383 public byte[] getFamilyArray() { 1384 return EMPTY_BYTE_ARRAY; 1385 } 1386 1387 @Override 1388 public int getFamilyOffset() { 1389 return 0; 1390 } 1391 1392 @Override 1393 public byte getFamilyLength() { 1394 return 0; 1395 } 1396 1397 @Override 1398 public byte[] getQualifierArray() { 1399 return EMPTY_BYTE_ARRAY; 1400 } 1401 1402 @Override 1403 public int getQualifierOffset() { 1404 return 0; 1405 } 1406 1407 @Override 1408 public int getQualifierLength() { 1409 return 0; 1410 } 1411 1412 @Override 1413 public long getSequenceId() { 1414 return 0; 1415 } 1416 1417 @Override 1418 public byte[] getValueArray() { 1419 return EMPTY_BYTE_ARRAY; 1420 } 1421 1422 @Override 1423 public int getValueOffset() { 1424 return 0; 1425 } 1426 1427 @Override 1428 public int getValueLength() { 1429 return 0; 1430 } 1431 1432 @Override 1433 public byte[] getTagsArray() { 1434 return EMPTY_BYTE_ARRAY; 1435 } 1436 1437 @Override 1438 public int getTagsOffset() { 1439 return 0; 1440 } 1441 1442 @Override 1443 public int getTagsLength() { 1444 return 0; 1445 } 1446 } 1447 1448 /** 1449 * These cells are used in reseeks/seeks to improve the read performance. They are not real cells 1450 * that are returned back to the clients 1451 */ 1452 private static abstract class EmptyByteBufferExtendedCell extends ByteBufferExtendedCell { 1453 1454 @Override 1455 public void setSequenceId(long seqId) { 1456 // Fake cells don't need seqId, so leaving it as a noop. 1457 } 1458 1459 @Override 1460 public void setTimestamp(long ts) { 1461 // Fake cells can't be changed timestamp, so leaving it as a noop. 1462 } 1463 1464 @Override 1465 public void setTimestamp(byte[] ts) { 1466 // Fake cells can't be changed timestamp, so leaving it as a noop. 1467 } 1468 1469 @Override 1470 public byte[] getRowArray() { 1471 return CellUtil.cloneRow(this); 1472 } 1473 1474 @Override 1475 public int getRowOffset() { 1476 return 0; 1477 } 1478 1479 @Override 1480 public short getRowLength() { 1481 return 0; 1482 } 1483 1484 @Override 1485 public byte[] getFamilyArray() { 1486 return CellUtil.cloneFamily(this); 1487 } 1488 1489 @Override 1490 public int getFamilyOffset() { 1491 return 0; 1492 } 1493 1494 @Override 1495 public byte getFamilyLength() { 1496 return 0; 1497 } 1498 1499 @Override 1500 public byte[] getQualifierArray() { 1501 return CellUtil.cloneQualifier(this); 1502 } 1503 1504 @Override 1505 public int getQualifierOffset() { 1506 return 0; 1507 } 1508 1509 @Override 1510 public int getQualifierLength() { 1511 return 0; 1512 } 1513 1514 @Override 1515 public long getSequenceId() { 1516 return 0; 1517 } 1518 1519 @Override 1520 public byte[] getValueArray() { 1521 return CellUtil.cloneValue(this); 1522 } 1523 1524 @Override 1525 public int getValueOffset() { 1526 return 0; 1527 } 1528 1529 @Override 1530 public int getValueLength() { 1531 return 0; 1532 } 1533 1534 @Override 1535 public byte[] getTagsArray() { 1536 return PrivateCellUtil.cloneTags(this); 1537 } 1538 1539 @Override 1540 public int getTagsOffset() { 1541 return 0; 1542 } 1543 1544 @Override 1545 public int getTagsLength() { 1546 return 0; 1547 } 1548 1549 @Override 1550 public ByteBuffer getRowByteBuffer() { 1551 return HConstants.EMPTY_BYTE_BUFFER; 1552 } 1553 1554 @Override 1555 public int getRowPosition() { 1556 return 0; 1557 } 1558 1559 @Override 1560 public ByteBuffer getFamilyByteBuffer() { 1561 return HConstants.EMPTY_BYTE_BUFFER; 1562 } 1563 1564 @Override 1565 public int getFamilyPosition() { 1566 return 0; 1567 } 1568 1569 @Override 1570 public ByteBuffer getQualifierByteBuffer() { 1571 return HConstants.EMPTY_BYTE_BUFFER; 1572 } 1573 1574 @Override 1575 public int getQualifierPosition() { 1576 return 0; 1577 } 1578 1579 @Override 1580 public ByteBuffer getTagsByteBuffer() { 1581 return HConstants.EMPTY_BYTE_BUFFER; 1582 } 1583 1584 @Override 1585 public int getTagsPosition() { 1586 return 0; 1587 } 1588 1589 @Override 1590 public ByteBuffer getValueByteBuffer() { 1591 return HConstants.EMPTY_BYTE_BUFFER; 1592 } 1593 1594 @Override 1595 public int getValuePosition() { 1596 return 0; 1597 } 1598 } 1599 1600 private static class FirstOnRowCell extends EmptyCell { 1601 // @formatter:off 1602 private static final int FIXED_HEAPSIZE = 1603 ClassSize.OBJECT // object 1604 + ClassSize.REFERENCE // row array 1605 + Bytes.SIZEOF_INT // row offset 1606 + Bytes.SIZEOF_SHORT; // row length 1607 // @formatter:on 1608 private final byte[] rowArray; 1609 private final int roffset; 1610 private final short rlength; 1611 1612 public FirstOnRowCell(final byte[] row, int roffset, short rlength) { 1613 this.rowArray = row; 1614 this.roffset = roffset; 1615 this.rlength = rlength; 1616 } 1617 1618 @Override 1619 public long heapSize() { 1620 return ClassSize.align(FIXED_HEAPSIZE) 1621 // array overhead 1622 + (rlength == 0 ? ClassSize.sizeOfByteArray(rlength) : rlength); 1623 } 1624 1625 @Override 1626 public byte[] getRowArray() { 1627 return this.rowArray; 1628 } 1629 1630 @Override 1631 public int getRowOffset() { 1632 return this.roffset; 1633 } 1634 1635 @Override 1636 public short getRowLength() { 1637 return this.rlength; 1638 } 1639 1640 @Override 1641 public long getTimestamp() { 1642 return HConstants.LATEST_TIMESTAMP; 1643 } 1644 1645 @Override 1646 public byte getTypeByte() { 1647 return KeyValue.Type.Maximum.getCode(); 1648 } 1649 1650 @Override 1651 public Cell.Type getType() { 1652 throw new UnsupportedOperationException(); 1653 } 1654 } 1655 1656 private static class FirstOnRowByteBufferExtendedCell extends EmptyByteBufferExtendedCell { 1657 // @formatter:off 1658 private static final int FIXED_OVERHEAD = 1659 ClassSize.OBJECT // object 1660 + ClassSize.REFERENCE // row buffer 1661 + Bytes.SIZEOF_INT // row offset 1662 + Bytes.SIZEOF_SHORT; // row length 1663 // @formatter:on 1664 private final ByteBuffer rowBuff; 1665 private final int roffset; 1666 private final short rlength; 1667 1668 public FirstOnRowByteBufferExtendedCell(final ByteBuffer row, int roffset, short rlength) { 1669 this.rowBuff = row; 1670 this.roffset = roffset; 1671 this.rlength = rlength; 1672 } 1673 1674 @Override 1675 public long heapSize() { 1676 if (this.rowBuff.hasArray()) { 1677 return ClassSize.align(FIXED_OVERHEAD + rlength); 1678 } 1679 return ClassSize.align(FIXED_OVERHEAD); 1680 } 1681 1682 @Override 1683 public ByteBuffer getRowByteBuffer() { 1684 return this.rowBuff; 1685 } 1686 1687 @Override 1688 public int getRowPosition() { 1689 return this.roffset; 1690 } 1691 1692 @Override 1693 public short getRowLength() { 1694 return this.rlength; 1695 } 1696 1697 @Override 1698 public long getTimestamp() { 1699 return HConstants.LATEST_TIMESTAMP; 1700 } 1701 1702 @Override 1703 public byte getTypeByte() { 1704 return KeyValue.Type.Maximum.getCode(); 1705 } 1706 1707 @Override 1708 public Type getType() { 1709 throw new UnsupportedOperationException(); 1710 } 1711 } 1712 1713 private static class LastOnRowByteBufferExtendedCell extends EmptyByteBufferExtendedCell { 1714 // @formatter:off 1715 private static final int FIXED_OVERHEAD = ClassSize.OBJECT // object 1716 + ClassSize.REFERENCE // rowBuff 1717 + Bytes.SIZEOF_INT // roffset 1718 + Bytes.SIZEOF_SHORT; // rlength 1719 // @formatter:on 1720 private final ByteBuffer rowBuff; 1721 private final int roffset; 1722 private final short rlength; 1723 1724 public LastOnRowByteBufferExtendedCell(final ByteBuffer row, int roffset, short rlength) { 1725 this.rowBuff = row; 1726 this.roffset = roffset; 1727 this.rlength = rlength; 1728 } 1729 1730 @Override 1731 public long heapSize() { 1732 if (this.rowBuff.hasArray()) { 1733 return ClassSize.align(FIXED_OVERHEAD + rlength); 1734 } 1735 return ClassSize.align(FIXED_OVERHEAD); 1736 } 1737 1738 @Override 1739 public ByteBuffer getRowByteBuffer() { 1740 return this.rowBuff; 1741 } 1742 1743 @Override 1744 public int getRowPosition() { 1745 return this.roffset; 1746 } 1747 1748 @Override 1749 public short getRowLength() { 1750 return this.rlength; 1751 } 1752 1753 @Override 1754 public long getTimestamp() { 1755 return PrivateConstants.OLDEST_TIMESTAMP; 1756 } 1757 1758 @Override 1759 public byte getTypeByte() { 1760 return KeyValue.Type.Minimum.getCode(); 1761 } 1762 1763 @Override 1764 public Type getType() { 1765 throw new UnsupportedOperationException(); 1766 } 1767 } 1768 1769 private static class FirstOnRowColByteBufferExtendedCell 1770 extends FirstOnRowByteBufferExtendedCell { 1771 // @formatter:off 1772 private static final int FIXED_OVERHEAD = FirstOnRowByteBufferExtendedCell.FIXED_OVERHEAD 1773 + ClassSize.REFERENCE * 2 // family buffer and column buffer 1774 + Bytes.SIZEOF_INT * 3 // famOffset, colOffset, colLength 1775 + Bytes.SIZEOF_BYTE; // famLength 1776 // @formatter:on 1777 private final ByteBuffer famBuff; 1778 private final int famOffset; 1779 private final byte famLength; 1780 private final ByteBuffer colBuff; 1781 private final int colOffset; 1782 private final int colLength; 1783 1784 public FirstOnRowColByteBufferExtendedCell(final ByteBuffer row, int roffset, short rlength, 1785 final ByteBuffer famBuff, final int famOffset, final byte famLength, final ByteBuffer col, 1786 final int colOffset, final int colLength) { 1787 super(row, roffset, rlength); 1788 this.famBuff = famBuff; 1789 this.famOffset = famOffset; 1790 this.famLength = famLength; 1791 this.colBuff = col; 1792 this.colOffset = colOffset; 1793 this.colLength = colLength; 1794 } 1795 1796 @Override 1797 public long heapSize() { 1798 if (famBuff.hasArray() && colBuff.hasArray()) { 1799 return ClassSize.align(FIXED_OVERHEAD + famLength + colLength); 1800 } else if (famBuff.hasArray()) { 1801 return ClassSize.align(FIXED_OVERHEAD + famLength); 1802 } else if (colBuff.hasArray()) { 1803 return ClassSize.align(FIXED_OVERHEAD + colLength); 1804 } else { 1805 return ClassSize.align(FIXED_OVERHEAD); 1806 } 1807 } 1808 1809 @Override 1810 public ByteBuffer getFamilyByteBuffer() { 1811 return this.famBuff; 1812 } 1813 1814 @Override 1815 public int getFamilyPosition() { 1816 return this.famOffset; 1817 } 1818 1819 @Override 1820 public byte getFamilyLength() { 1821 return famLength; 1822 } 1823 1824 @Override 1825 public ByteBuffer getQualifierByteBuffer() { 1826 return this.colBuff; 1827 } 1828 1829 @Override 1830 public int getQualifierPosition() { 1831 return this.colOffset; 1832 } 1833 1834 @Override 1835 public int getQualifierLength() { 1836 return this.colLength; 1837 } 1838 } 1839 1840 private static class FirstOnRowColCell extends FirstOnRowCell { 1841 // @formatter:off 1842 private static final long FIXED_HEAPSIZE = (long) FirstOnRowCell.FIXED_HEAPSIZE 1843 + Bytes.SIZEOF_BYTE // flength 1844 + Bytes.SIZEOF_INT * 3 // foffset, qoffset, qlength 1845 + ClassSize.REFERENCE * 2; // fArray, qArray 1846 // @formatter:on 1847 private final byte[] fArray; 1848 private final int foffset; 1849 private final byte flength; 1850 private final byte[] qArray; 1851 private final int qoffset; 1852 private final int qlength; 1853 1854 public FirstOnRowColCell(byte[] rArray, int roffset, short rlength, byte[] fArray, int foffset, 1855 byte flength, byte[] qArray, int qoffset, int qlength) { 1856 super(rArray, roffset, rlength); 1857 this.fArray = fArray; 1858 this.foffset = foffset; 1859 this.flength = flength; 1860 this.qArray = qArray; 1861 this.qoffset = qoffset; 1862 this.qlength = qlength; 1863 } 1864 1865 @Override 1866 public long heapSize() { 1867 return ClassSize.align(FIXED_HEAPSIZE) 1868 // array overhead 1869 + (flength == 0 ? ClassSize.sizeOfByteArray(flength) : flength) 1870 + (qlength == 0 ? ClassSize.sizeOfByteArray(qlength) : qlength); 1871 } 1872 1873 @Override 1874 public byte[] getFamilyArray() { 1875 return this.fArray; 1876 } 1877 1878 @Override 1879 public int getFamilyOffset() { 1880 return this.foffset; 1881 } 1882 1883 @Override 1884 public byte getFamilyLength() { 1885 return this.flength; 1886 } 1887 1888 @Override 1889 public byte[] getQualifierArray() { 1890 return this.qArray; 1891 } 1892 1893 @Override 1894 public int getQualifierOffset() { 1895 return this.qoffset; 1896 } 1897 1898 @Override 1899 public int getQualifierLength() { 1900 return this.qlength; 1901 } 1902 } 1903 1904 private static class FirstOnRowColTSCell extends FirstOnRowColCell { 1905 // @formatter:off 1906 private static final long FIXED_HEAPSIZE = FirstOnRowColCell.FIXED_HEAPSIZE 1907 + Bytes.SIZEOF_LONG; // ts 1908 private long ts; 1909 // @formatter:on 1910 1911 public FirstOnRowColTSCell(byte[] rArray, int roffset, short rlength, byte[] fArray, 1912 int foffset, byte flength, byte[] qArray, int qoffset, int qlength, long ts) { 1913 super(rArray, roffset, rlength, fArray, foffset, flength, qArray, qoffset, qlength); 1914 this.ts = ts; 1915 } 1916 1917 @Override 1918 public long getTimestamp() { 1919 return this.ts; 1920 } 1921 1922 @Override 1923 public long heapSize() { 1924 return ClassSize.align(FIXED_HEAPSIZE); 1925 } 1926 } 1927 1928 private static class FirstOnRowColTSByteBufferExtendedCell 1929 extends FirstOnRowColByteBufferExtendedCell { 1930 // @formatter:off 1931 private static final int FIXED_OVERHEAD = FirstOnRowColByteBufferExtendedCell.FIXED_OVERHEAD 1932 + Bytes.SIZEOF_LONG; // ts 1933 private long ts; 1934 // @formatter:on 1935 1936 public FirstOnRowColTSByteBufferExtendedCell(ByteBuffer rBuffer, int roffset, short rlength, 1937 ByteBuffer fBuffer, int foffset, byte flength, ByteBuffer qBuffer, int qoffset, int qlength, 1938 long ts) { 1939 super(rBuffer, roffset, rlength, fBuffer, foffset, flength, qBuffer, qoffset, qlength); 1940 this.ts = ts; 1941 } 1942 1943 @Override 1944 public long getTimestamp() { 1945 return this.ts; 1946 } 1947 1948 @Override 1949 public long heapSize() { 1950 return ClassSize.align(FIXED_OVERHEAD + super.heapSize()); 1951 } 1952 } 1953 1954 private static class LastOnRowCell extends EmptyCell { 1955 // @formatter:off 1956 private static final int FIXED_OVERHEAD = ClassSize.OBJECT // object 1957 + ClassSize.REFERENCE // row array 1958 + Bytes.SIZEOF_INT // row offset 1959 + Bytes.SIZEOF_SHORT; // row length 1960 // @formatter:on 1961 private final byte[] rowArray; 1962 private final int roffset; 1963 private final short rlength; 1964 1965 public LastOnRowCell(byte[] row, int roffset, short rlength) { 1966 this.rowArray = row; 1967 this.roffset = roffset; 1968 this.rlength = rlength; 1969 } 1970 1971 @Override 1972 public long heapSize() { 1973 return ClassSize.align(FIXED_OVERHEAD) 1974 // array overhead 1975 + (rlength == 0 ? ClassSize.sizeOfByteArray(rlength) : rlength); 1976 } 1977 1978 @Override 1979 public byte[] getRowArray() { 1980 return this.rowArray; 1981 } 1982 1983 @Override 1984 public int getRowOffset() { 1985 return this.roffset; 1986 } 1987 1988 @Override 1989 public short getRowLength() { 1990 return this.rlength; 1991 } 1992 1993 @Override 1994 public long getTimestamp() { 1995 return PrivateConstants.OLDEST_TIMESTAMP; 1996 } 1997 1998 @Override 1999 public byte getTypeByte() { 2000 return KeyValue.Type.Minimum.getCode(); 2001 } 2002 2003 @Override 2004 public Type getType() { 2005 throw new UnsupportedOperationException(); 2006 } 2007 } 2008 2009 private static class LastOnRowColCell extends LastOnRowCell { 2010 // @formatter:off 2011 private static final long FIXED_OVERHEAD = (long) LastOnRowCell.FIXED_OVERHEAD 2012 + ClassSize.REFERENCE * 2 // fArray and qArray 2013 + Bytes.SIZEOF_INT * 3 // foffset, qoffset, qlength 2014 + Bytes.SIZEOF_BYTE; // flength 2015 // @formatter:on 2016 private final byte[] fArray; 2017 private final int foffset; 2018 private final byte flength; 2019 private final byte[] qArray; 2020 private final int qoffset; 2021 private final int qlength; 2022 2023 public LastOnRowColCell(byte[] rArray, int roffset, short rlength, byte[] fArray, int foffset, 2024 byte flength, byte[] qArray, int qoffset, int qlength) { 2025 super(rArray, roffset, rlength); 2026 this.fArray = fArray; 2027 this.foffset = foffset; 2028 this.flength = flength; 2029 this.qArray = qArray; 2030 this.qoffset = qoffset; 2031 this.qlength = qlength; 2032 } 2033 2034 @Override 2035 public long heapSize() { 2036 return ClassSize.align(FIXED_OVERHEAD) 2037 // array overhead 2038 + (flength == 0 ? ClassSize.sizeOfByteArray(flength) : flength) 2039 + (qlength == 0 ? ClassSize.sizeOfByteArray(qlength) : qlength); 2040 } 2041 2042 @Override 2043 public byte[] getFamilyArray() { 2044 return this.fArray; 2045 } 2046 2047 @Override 2048 public int getFamilyOffset() { 2049 return this.foffset; 2050 } 2051 2052 @Override 2053 public byte getFamilyLength() { 2054 return this.flength; 2055 } 2056 2057 @Override 2058 public byte[] getQualifierArray() { 2059 return this.qArray; 2060 } 2061 2062 @Override 2063 public int getQualifierOffset() { 2064 return this.qoffset; 2065 } 2066 2067 @Override 2068 public int getQualifierLength() { 2069 return this.qlength; 2070 } 2071 } 2072 2073 private static class LastOnRowColByteBufferExtendedCell extends LastOnRowByteBufferExtendedCell { 2074 // @formatter:off 2075 private static final int FIXED_OVERHEAD = LastOnRowByteBufferExtendedCell.FIXED_OVERHEAD 2076 + ClassSize.REFERENCE * 2 // fBuffer and qBuffer 2077 + Bytes.SIZEOF_INT * 3 // foffset, qoffset, qlength 2078 + Bytes.SIZEOF_BYTE; // flength 2079 // @formatter:on 2080 private final ByteBuffer fBuffer; 2081 private final int foffset; 2082 private final byte flength; 2083 private final ByteBuffer qBuffer; 2084 private final int qoffset; 2085 private final int qlength; 2086 2087 public LastOnRowColByteBufferExtendedCell(ByteBuffer rBuffer, int roffset, short rlength, 2088 ByteBuffer fBuffer, int foffset, byte flength, ByteBuffer qBuffer, int qoffset, int qlength) { 2089 super(rBuffer, roffset, rlength); 2090 this.fBuffer = fBuffer; 2091 this.foffset = foffset; 2092 this.flength = flength; 2093 this.qBuffer = qBuffer; 2094 this.qoffset = qoffset; 2095 this.qlength = qlength; 2096 } 2097 2098 @Override 2099 public long heapSize() { 2100 if (fBuffer.hasArray() && qBuffer.hasArray()) { 2101 return ClassSize.align(FIXED_OVERHEAD + flength + qlength); 2102 } else if (fBuffer.hasArray()) { 2103 return ClassSize.align(FIXED_OVERHEAD + flength); 2104 } else if (qBuffer.hasArray()) { 2105 return ClassSize.align(FIXED_OVERHEAD + qlength); 2106 } else { 2107 return ClassSize.align(FIXED_OVERHEAD); 2108 } 2109 } 2110 2111 @Override 2112 public ByteBuffer getFamilyByteBuffer() { 2113 return this.fBuffer; 2114 } 2115 2116 @Override 2117 public int getFamilyPosition() { 2118 return this.foffset; 2119 } 2120 2121 @Override 2122 public byte getFamilyLength() { 2123 return this.flength; 2124 } 2125 2126 @Override 2127 public ByteBuffer getQualifierByteBuffer() { 2128 return this.qBuffer; 2129 } 2130 2131 @Override 2132 public int getQualifierPosition() { 2133 return this.qoffset; 2134 } 2135 2136 @Override 2137 public int getQualifierLength() { 2138 return this.qlength; 2139 } 2140 } 2141 2142 private static class FirstOnRowDeleteFamilyCell extends EmptyCell { 2143 // @formatter:off 2144 private static final int FIXED_OVERHEAD = ClassSize.OBJECT // object 2145 + ClassSize.REFERENCE * 2 // fBuffer and qBuffer 2146 + Bytes.SIZEOF_INT * 3 // foffset, qoffset, qlength 2147 + Bytes.SIZEOF_BYTE; // flength 2148 // @formatter:on 2149 private final byte[] row; 2150 private final byte[] fam; 2151 2152 public FirstOnRowDeleteFamilyCell(byte[] row, byte[] fam) { 2153 this.row = row; 2154 this.fam = fam; 2155 } 2156 2157 @Override 2158 public long heapSize() { 2159 return ClassSize.align(FIXED_OVERHEAD) 2160 // array overhead 2161 + (getRowLength() == 0 ? ClassSize.sizeOfByteArray(getRowLength()) : getRowLength()) 2162 + (getFamilyLength() == 0 2163 ? ClassSize.sizeOfByteArray(getFamilyLength()) 2164 : getFamilyLength()); 2165 } 2166 2167 @Override 2168 public byte[] getRowArray() { 2169 return this.row; 2170 } 2171 2172 @Override 2173 public short getRowLength() { 2174 return (short) this.row.length; 2175 } 2176 2177 @Override 2178 public byte[] getFamilyArray() { 2179 return this.fam; 2180 } 2181 2182 @Override 2183 public byte getFamilyLength() { 2184 return (byte) this.fam.length; 2185 } 2186 2187 @Override 2188 public long getTimestamp() { 2189 return HConstants.LATEST_TIMESTAMP; 2190 } 2191 2192 @Override 2193 public byte getTypeByte() { 2194 return KeyValue.Type.DeleteFamily.getCode(); 2195 } 2196 2197 @Override 2198 public Type getType() { 2199 return Type.DeleteFamily; 2200 } 2201 } 2202 2203 /** 2204 * Writes the Cell's key part as it would have serialized in a KeyValue. The format is <2 bytes 2205 * rk len><rk><1 byte cf len><cf><qualifier><8 bytes 2206 * timestamp><1 byte type> 2207 */ 2208 public static void writeFlatKey(ExtendedCell cell, DataOutput out) throws IOException { 2209 short rowLen = cell.getRowLength(); 2210 byte fLen = cell.getFamilyLength(); 2211 int qLen = cell.getQualifierLength(); 2212 // Using just one if/else loop instead of every time checking before writing every 2213 // component of cell 2214 if (cell instanceof ByteBufferExtendedCell) { 2215 out.writeShort(rowLen); 2216 ByteBufferUtils.copyBufferToStream(out, ((ByteBufferExtendedCell) cell).getRowByteBuffer(), 2217 ((ByteBufferExtendedCell) cell).getRowPosition(), rowLen); 2218 out.writeByte(fLen); 2219 ByteBufferUtils.copyBufferToStream(out, ((ByteBufferExtendedCell) cell).getFamilyByteBuffer(), 2220 ((ByteBufferExtendedCell) cell).getFamilyPosition(), fLen); 2221 ByteBufferUtils.copyBufferToStream(out, 2222 ((ByteBufferExtendedCell) cell).getQualifierByteBuffer(), 2223 ((ByteBufferExtendedCell) cell).getQualifierPosition(), qLen); 2224 } else { 2225 out.writeShort(rowLen); 2226 out.write(cell.getRowArray(), cell.getRowOffset(), rowLen); 2227 out.writeByte(fLen); 2228 out.write(cell.getFamilyArray(), cell.getFamilyOffset(), fLen); 2229 out.write(cell.getQualifierArray(), cell.getQualifierOffset(), qLen); 2230 } 2231 out.writeLong(cell.getTimestamp()); 2232 out.writeByte(cell.getTypeByte()); 2233 } 2234 2235 public static int writeFlatKey(ExtendedCell cell, OutputStream out) throws IOException { 2236 short rowLen = cell.getRowLength(); 2237 byte fLen = cell.getFamilyLength(); 2238 int qLen = cell.getQualifierLength(); 2239 // Using just one if/else loop instead of every time checking before writing every 2240 // component of cell 2241 if (cell instanceof ByteBufferExtendedCell) { 2242 StreamUtils.writeShort(out, rowLen); 2243 ByteBufferUtils.copyBufferToStream(out, ((ByteBufferExtendedCell) cell).getRowByteBuffer(), 2244 ((ByteBufferExtendedCell) cell).getRowPosition(), rowLen); 2245 out.write(fLen); 2246 ByteBufferUtils.copyBufferToStream(out, ((ByteBufferExtendedCell) cell).getFamilyByteBuffer(), 2247 ((ByteBufferExtendedCell) cell).getFamilyPosition(), fLen); 2248 ByteBufferUtils.copyBufferToStream(out, 2249 ((ByteBufferExtendedCell) cell).getQualifierByteBuffer(), 2250 ((ByteBufferExtendedCell) cell).getQualifierPosition(), qLen); 2251 } else { 2252 StreamUtils.writeShort(out, rowLen); 2253 out.write(cell.getRowArray(), cell.getRowOffset(), rowLen); 2254 out.write(fLen); 2255 out.write(cell.getFamilyArray(), cell.getFamilyOffset(), fLen); 2256 out.write(cell.getQualifierArray(), cell.getQualifierOffset(), qLen); 2257 } 2258 StreamUtils.writeLong(out, cell.getTimestamp()); 2259 out.write(cell.getTypeByte()); 2260 return Bytes.SIZEOF_SHORT + rowLen + Bytes.SIZEOF_BYTE + fLen + qLen + Bytes.SIZEOF_LONG 2261 + Bytes.SIZEOF_BYTE; 2262 } 2263 2264 /** 2265 * Sets the given seqId to the cell. Marked as audience Private as of 1.2.0. Setting a Cell 2266 * sequenceid is an internal implementation detail not for general public use. 2267 * @throws IOException when the passed cell is not of type {@link ExtendedCell} 2268 */ 2269 public static void setSequenceId(Cell cell, long seqId) throws IOException { 2270 if (cell instanceof ExtendedCell) { 2271 ((ExtendedCell) cell).setSequenceId(seqId); 2272 } else { 2273 throw new IOException( 2274 new UnsupportedOperationException("Cell is not of type " + ExtendedCell.class.getName())); 2275 } 2276 } 2277 2278 /** 2279 * Sets the given timestamp to the cell. 2280 * @throws IOException when the passed cell is not of type {@link ExtendedCell} 2281 */ 2282 public static void setTimestamp(Cell cell, long ts) throws IOException { 2283 if (cell instanceof ExtendedCell) { 2284 ((ExtendedCell) cell).setTimestamp(ts); 2285 } else { 2286 throw new IOException( 2287 new UnsupportedOperationException("Cell is not of type " + ExtendedCell.class.getName())); 2288 } 2289 } 2290 2291 /** 2292 * Sets the given timestamp to the cell. 2293 * @throws IOException when the passed cell is not of type {@link ExtendedCell} 2294 */ 2295 public static void setTimestamp(Cell cell, byte[] ts) throws IOException { 2296 if (cell instanceof ExtendedCell) { 2297 ((ExtendedCell) cell).setTimestamp(ts); 2298 } else { 2299 throw new IOException( 2300 new UnsupportedOperationException("Cell is not of type " + ExtendedCell.class.getName())); 2301 } 2302 } 2303 2304 /** 2305 * Sets the given timestamp to the cell iff current timestamp is 2306 * {@link HConstants#LATEST_TIMESTAMP}. 2307 * @return True if cell timestamp is modified. 2308 * @throws IOException when the passed cell is not of type {@link ExtendedCell} 2309 */ 2310 public static boolean updateLatestStamp(ExtendedCell cell, long ts) throws IOException { 2311 if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP) { 2312 cell.setTimestamp(ts); 2313 return true; 2314 } 2315 return false; 2316 } 2317 2318 /** 2319 * Sets the given timestamp to the cell iff current timestamp is 2320 * {@link HConstants#LATEST_TIMESTAMP}. 2321 * @return True if cell timestamp is modified. 2322 * @throws IOException when the passed cell is not of type {@link ExtendedCell} 2323 */ 2324 public static boolean updateLatestStamp(Cell cell, byte[] ts) throws IOException { 2325 if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP) { 2326 setTimestamp(cell, ts); 2327 return true; 2328 } 2329 return false; 2330 } 2331 2332 /** 2333 * Writes the row from the given cell to the output stream 2334 * @param out The outputstream to which the data has to be written 2335 * @param cell The cell whose contents has to be written 2336 * @param rlength the row length 2337 */ 2338 public static void writeRow(OutputStream out, Cell cell, short rlength) throws IOException { 2339 if (cell instanceof ByteBufferExtendedCell) { 2340 ByteBufferUtils.copyBufferToStream(out, ((ByteBufferExtendedCell) cell).getRowByteBuffer(), 2341 ((ByteBufferExtendedCell) cell).getRowPosition(), rlength); 2342 } else { 2343 out.write(cell.getRowArray(), cell.getRowOffset(), rlength); 2344 } 2345 } 2346 2347 /** 2348 * Writes the family from the given cell to the output stream 2349 * @param out The outputstream to which the data has to be written 2350 * @param cell The cell whose contents has to be written 2351 * @param flength the family length 2352 */ 2353 public static void writeFamily(OutputStream out, Cell cell, byte flength) throws IOException { 2354 if (cell instanceof ByteBufferExtendedCell) { 2355 ByteBufferUtils.copyBufferToStream(out, ((ByteBufferExtendedCell) cell).getFamilyByteBuffer(), 2356 ((ByteBufferExtendedCell) cell).getFamilyPosition(), flength); 2357 } else { 2358 out.write(cell.getFamilyArray(), cell.getFamilyOffset(), flength); 2359 } 2360 } 2361 2362 /** 2363 * Writes the qualifier from the given cell to the output stream 2364 * @param out The outputstream to which the data has to be written 2365 * @param cell The cell whose contents has to be written 2366 * @param qlength the qualifier length 2367 */ 2368 public static void writeQualifier(OutputStream out, Cell cell, int qlength) throws IOException { 2369 if (cell instanceof ByteBufferExtendedCell) { 2370 ByteBufferUtils.copyBufferToStream(out, 2371 ((ByteBufferExtendedCell) cell).getQualifierByteBuffer(), 2372 ((ByteBufferExtendedCell) cell).getQualifierPosition(), qlength); 2373 } else { 2374 out.write(cell.getQualifierArray(), cell.getQualifierOffset(), qlength); 2375 } 2376 } 2377 2378 /** 2379 * Writes the qualifier from the given cell to the output stream excluding the common prefix 2380 * @param out The dataoutputstream to which the data has to be written 2381 * @param cell The cell whose contents has to be written 2382 * @param qlength the qualifier length 2383 */ 2384 public static void writeQualifierSkippingBytes(DataOutputStream out, Cell cell, int qlength, 2385 int commonPrefix) throws IOException { 2386 if (cell instanceof ByteBufferExtendedCell) { 2387 ByteBufferUtils.copyBufferToStream((DataOutput) out, 2388 ((ByteBufferExtendedCell) cell).getQualifierByteBuffer(), 2389 ((ByteBufferExtendedCell) cell).getQualifierPosition() + commonPrefix, 2390 qlength - commonPrefix); 2391 } else { 2392 out.write(cell.getQualifierArray(), cell.getQualifierOffset() + commonPrefix, 2393 qlength - commonPrefix); 2394 } 2395 } 2396 2397 /** 2398 * Writes the value from the given cell to the output stream 2399 * @param out The outputstream to which the data has to be written 2400 * @param cell The cell whose contents has to be written 2401 * @param vlength the value length 2402 */ 2403 public static void writeValue(OutputStream out, ExtendedCell cell, int vlength) 2404 throws IOException { 2405 if (cell instanceof ByteBufferExtendedCell) { 2406 ByteBufferUtils.copyBufferToStream(out, ((ByteBufferExtendedCell) cell).getValueByteBuffer(), 2407 ((ByteBufferExtendedCell) cell).getValuePosition(), vlength); 2408 } else { 2409 out.write(cell.getValueArray(), cell.getValueOffset(), vlength); 2410 } 2411 } 2412 2413 /** 2414 * Writes the tag from the given cell to the output stream 2415 * @param out The outputstream to which the data has to be written 2416 * @param cell The cell whose contents has to be written 2417 * @param tagsLength the tag length 2418 */ 2419 public static void writeTags(OutputStream out, ExtendedCell cell, int tagsLength) 2420 throws IOException { 2421 if (cell instanceof ByteBufferExtendedCell) { 2422 ByteBufferUtils.copyBufferToStream(out, ((ByteBufferExtendedCell) cell).getTagsByteBuffer(), 2423 ((ByteBufferExtendedCell) cell).getTagsPosition(), tagsLength); 2424 } else { 2425 out.write(cell.getTagsArray(), cell.getTagsOffset(), tagsLength); 2426 } 2427 } 2428 2429 /** 2430 * special case for Cell.equals 2431 */ 2432 public static boolean equalsIgnoreMvccVersion(ExtendedCell a, ExtendedCell b) { 2433 // row 2434 boolean res = CellUtil.matchingRows(a, b); 2435 if (!res) { 2436 return res; 2437 } 2438 2439 // family 2440 res = CellUtil.matchingColumn(a, b); 2441 if (!res) { 2442 return res; 2443 } 2444 2445 // timestamp: later sorts first 2446 if (!CellUtil.matchingTimestamp(a, b)) { 2447 return false; 2448 } 2449 2450 // type 2451 int c = (0xff & b.getTypeByte()) - (0xff & a.getTypeByte()); 2452 if (c != 0) { 2453 return false; 2454 } else { 2455 return true; 2456 } 2457 } 2458 2459 /** 2460 * Converts the rowkey bytes of the given cell into an int value 2461 * @return rowkey as int 2462 */ 2463 public static int getRowAsInt(Cell cell) { 2464 if (cell instanceof ByteBufferExtendedCell) { 2465 return ByteBufferUtils.toInt(((ByteBufferExtendedCell) cell).getRowByteBuffer(), 2466 ((ByteBufferExtendedCell) cell).getRowPosition()); 2467 } 2468 return Bytes.toInt(cell.getRowArray(), cell.getRowOffset()); 2469 } 2470 2471 /** 2472 * Converts the value bytes of the given cell into a long value 2473 * @return value as long 2474 */ 2475 public static long getValueAsLong(Cell cell) { 2476 if (cell instanceof ByteBufferExtendedCell) { 2477 return ByteBufferUtils.toLong(((ByteBufferExtendedCell) cell).getValueByteBuffer(), 2478 ((ByteBufferExtendedCell) cell).getValuePosition()); 2479 } 2480 return Bytes.toLong(cell.getValueArray(), cell.getValueOffset()); 2481 } 2482 2483 /** 2484 * Converts the value bytes of the given cell into a int value 2485 * @return value as int 2486 */ 2487 public static int getValueAsInt(Cell cell) { 2488 if (cell instanceof ByteBufferExtendedCell) { 2489 return ByteBufferUtils.toInt(((ByteBufferExtendedCell) cell).getValueByteBuffer(), 2490 ((ByteBufferExtendedCell) cell).getValuePosition()); 2491 } 2492 return Bytes.toInt(cell.getValueArray(), cell.getValueOffset()); 2493 } 2494 2495 /** 2496 * Converts the value bytes of the given cell into a double value 2497 * @return value as double 2498 */ 2499 public static double getValueAsDouble(Cell cell) { 2500 if (cell instanceof ByteBufferExtendedCell) { 2501 return ByteBufferUtils.toDouble(((ByteBufferExtendedCell) cell).getValueByteBuffer(), 2502 ((ByteBufferExtendedCell) cell).getValuePosition()); 2503 } 2504 return Bytes.toDouble(cell.getValueArray(), cell.getValueOffset()); 2505 } 2506 2507 /** 2508 * Converts the value bytes of the given cell into a BigDecimal 2509 * @return value as BigDecimal 2510 */ 2511 public static BigDecimal getValueAsBigDecimal(Cell cell) { 2512 if (cell instanceof ByteBufferExtendedCell) { 2513 return ByteBufferUtils.toBigDecimal(((ByteBufferExtendedCell) cell).getValueByteBuffer(), 2514 ((ByteBufferExtendedCell) cell).getValuePosition(), cell.getValueLength()); 2515 } 2516 return Bytes.toBigDecimal(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength()); 2517 } 2518 2519 /** 2520 * Compresses the tags to the given outputstream using the TagcompressionContext 2521 * @param out the outputstream to which the compression should happen 2522 * @param cell the cell which has tags 2523 * @param tagCompressionContext the TagCompressionContext 2524 * @throws IOException can throw IOException if the compression encounters issue 2525 */ 2526 public static void compressTags(OutputStream out, ExtendedCell cell, 2527 TagCompressionContext tagCompressionContext) throws IOException { 2528 if (cell instanceof ByteBufferExtendedCell) { 2529 tagCompressionContext.compressTags(out, ((ByteBufferExtendedCell) cell).getTagsByteBuffer(), 2530 ((ByteBufferExtendedCell) cell).getTagsPosition(), cell.getTagsLength()); 2531 } else { 2532 tagCompressionContext.compressTags(out, cell.getTagsArray(), cell.getTagsOffset(), 2533 cell.getTagsLength()); 2534 } 2535 } 2536 2537 public static void compressRow(OutputStream out, Cell cell, Dictionary dict) throws IOException { 2538 if (cell instanceof ByteBufferExtendedCell) { 2539 Dictionary.write(out, ((ByteBufferExtendedCell) cell).getRowByteBuffer(), 2540 ((ByteBufferExtendedCell) cell).getRowPosition(), cell.getRowLength(), dict); 2541 } else { 2542 Dictionary.write(out, cell.getRowArray(), cell.getRowOffset(), cell.getRowLength(), dict); 2543 } 2544 } 2545 2546 public static void compressFamily(OutputStream out, Cell cell, Dictionary dict) 2547 throws IOException { 2548 if (cell instanceof ByteBufferExtendedCell) { 2549 Dictionary.write(out, ((ByteBufferExtendedCell) cell).getFamilyByteBuffer(), 2550 ((ByteBufferExtendedCell) cell).getFamilyPosition(), cell.getFamilyLength(), dict); 2551 } else { 2552 Dictionary.write(out, cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength(), 2553 dict); 2554 } 2555 } 2556 2557 public static void compressQualifier(OutputStream out, Cell cell, Dictionary dict) 2558 throws IOException { 2559 if (cell instanceof ByteBufferExtendedCell) { 2560 Dictionary.write(out, ((ByteBufferExtendedCell) cell).getQualifierByteBuffer(), 2561 ((ByteBufferExtendedCell) cell).getQualifierPosition(), cell.getQualifierLength(), dict); 2562 } else { 2563 Dictionary.write(out, cell.getQualifierArray(), cell.getQualifierOffset(), 2564 cell.getQualifierLength(), dict); 2565 } 2566 } 2567 2568 /** 2569 * Used when a cell needs to be compared with a key byte[] such as cases of finding the index from 2570 * the index block, bloom keys from the bloom blocks This byte[] is expected to be serialized in 2571 * the KeyValue serialization format If the KeyValue (Cell's) serialization format changes this 2572 * method cannot be used. 2573 * @param comparator the {@link CellComparator} to use for comparison 2574 * @param left the cell to be compared 2575 * @param key the serialized key part of a KeyValue 2576 * @param offset the offset in the key byte[] 2577 * @param length the length of the key byte[] 2578 * @return an int greater than 0 if left is greater than right lesser than 0 if left is lesser 2579 * than right equal to 0 if left is equal to right 2580 */ 2581 public static final int compare(CellComparator comparator, ExtendedCell left, byte[] key, 2582 int offset, int length) { 2583 // row 2584 short rrowlength = Bytes.toShort(key, offset); 2585 int c = comparator.compareRows(left, key, offset + Bytes.SIZEOF_SHORT, rrowlength); 2586 if (c != 0) return c; 2587 2588 // Compare the rest of the two KVs without making any assumptions about 2589 // the common prefix. This function will not compare rows anyway, so we 2590 // don't need to tell it that the common prefix includes the row. 2591 return compareWithoutRow(comparator, left, key, offset, length, rrowlength); 2592 } 2593 2594 /** 2595 * Compare columnFamily, qualifier, timestamp, and key type (everything except the row). This 2596 * method is used both in the normal comparator and the "same-prefix" comparator. Note that we are 2597 * assuming that row portions of both KVs have already been parsed and found identical, and we 2598 * don't validate that assumption here. 2599 * @param comparator the {@link CellComparator} to use for comparison 2600 * @param left the cell to be compared 2601 * @param right the serialized key part of a key-value 2602 * @param roffset the offset in the key byte[] 2603 * @param rlength the length of the key byte[] 2604 * @param rowlength the row length 2605 * @return greater than 0 if left cell is bigger, less than 0 if right cell is bigger, 0 if both 2606 * cells are equal 2607 */ 2608 static final int compareWithoutRow(CellComparator comparator, ExtendedCell left, byte[] right, 2609 int roffset, int rlength, short rowlength) { 2610 /*** 2611 * KeyValue Format and commonLength: 2612 * |_keyLen_|_valLen_|_rowLen_|_rowKey_|_famiLen_|_fami_|_Quali_|.... 2613 * ------------------|-------commonLength--------|-------------- 2614 */ 2615 int commonLength = KeyValue.ROW_LENGTH_SIZE + KeyValue.FAMILY_LENGTH_SIZE + rowlength; 2616 2617 // commonLength + TIMESTAMP_TYPE_SIZE 2618 int commonLengthWithTSAndType = KeyValue.TIMESTAMP_TYPE_SIZE + commonLength; 2619 // ColumnFamily + Qualifier length. 2620 int lcolumnlength = left.getFamilyLength() + left.getQualifierLength(); 2621 int rcolumnlength = rlength - commonLengthWithTSAndType; 2622 2623 byte ltype = left.getTypeByte(); 2624 byte rtype = right[roffset + (rlength - 1)]; 2625 2626 // If the column is not specified, the "minimum" key type appears the 2627 // latest in the sorted order, regardless of the timestamp. This is used 2628 // for specifying the last key/value in a given row, because there is no 2629 // "lexicographically last column" (it would be infinitely long). The 2630 // "maximum" key type does not need this behavior. 2631 if (lcolumnlength == 0 && ltype == KeyValue.Type.Minimum.getCode()) { 2632 // left is "bigger", i.e. it appears later in the sorted order 2633 return 1; 2634 } 2635 if (rcolumnlength == 0 && rtype == KeyValue.Type.Minimum.getCode()) { 2636 return -1; 2637 } 2638 2639 int rfamilyoffset = commonLength + roffset; 2640 2641 // Column family length. 2642 int lfamilylength = left.getFamilyLength(); 2643 int rfamilylength = right[rfamilyoffset - 1]; 2644 // If left family size is not equal to right family size, we need not 2645 // compare the qualifiers. 2646 boolean sameFamilySize = (lfamilylength == rfamilylength); 2647 if (!sameFamilySize) { 2648 // comparing column family is enough. 2649 return CellUtil.compareFamilies(left, right, rfamilyoffset, rfamilylength); 2650 } 2651 // Compare family & qualifier together. 2652 // Families are same. Compare on qualifiers. 2653 int comparison = CellUtil.compareColumns(left, right, rfamilyoffset, rfamilylength, 2654 rfamilyoffset + rfamilylength, (rcolumnlength - rfamilylength)); 2655 if (comparison != 0) { 2656 return comparison; 2657 } 2658 2659 // // 2660 // Next compare timestamps. 2661 long rtimestamp = Bytes.toLong(right, roffset + (rlength - KeyValue.TIMESTAMP_TYPE_SIZE)); 2662 int compare = comparator.compareTimestamps(left.getTimestamp(), rtimestamp); 2663 if (compare != 0) { 2664 return compare; 2665 } 2666 2667 // Compare types. Let the delete types sort ahead of puts; i.e. types 2668 // of higher numbers sort before those of lesser numbers. Maximum (255) 2669 // appears ahead of everything, and minimum (0) appears after 2670 // everything. 2671 return (0xff & rtype) - (0xff & ltype); 2672 } 2673 2674 /** 2675 * Return a new cell is located following input cell. If both of type and timestamp are minimum, 2676 * the input cell will be returned directly. 2677 */ 2678 public static ExtendedCell createNextOnRowCol(ExtendedCell cell) { 2679 long ts = cell.getTimestamp(); 2680 byte type = cell.getTypeByte(); 2681 if (type != KeyValue.Type.Minimum.getCode()) { 2682 type = KeyValue.Type.values()[KeyValue.Type.codeToType(type).ordinal() - 1].getCode(); 2683 } else if (ts != PrivateConstants.OLDEST_TIMESTAMP) { 2684 ts = ts - 1; 2685 type = KeyValue.Type.Maximum.getCode(); 2686 } else { 2687 return cell; 2688 } 2689 return createNextOnRowCol(cell, ts, type); 2690 } 2691 2692 static ExtendedCell createNextOnRowCol(ExtendedCell cell, long ts, byte type) { 2693 if (cell instanceof ByteBufferExtendedCell) { 2694 return new LastOnRowColByteBufferExtendedCell( 2695 ((ByteBufferExtendedCell) cell).getRowByteBuffer(), 2696 ((ByteBufferExtendedCell) cell).getRowPosition(), cell.getRowLength(), 2697 ((ByteBufferExtendedCell) cell).getFamilyByteBuffer(), 2698 ((ByteBufferExtendedCell) cell).getFamilyPosition(), cell.getFamilyLength(), 2699 ((ByteBufferExtendedCell) cell).getQualifierByteBuffer(), 2700 ((ByteBufferExtendedCell) cell).getQualifierPosition(), cell.getQualifierLength()) { 2701 @Override 2702 public long getTimestamp() { 2703 return ts; 2704 } 2705 2706 @Override 2707 public byte getTypeByte() { 2708 return type; 2709 } 2710 }; 2711 } 2712 return new LastOnRowColCell(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength(), 2713 cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength(), 2714 cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength()) { 2715 @Override 2716 public long getTimestamp() { 2717 return ts; 2718 } 2719 2720 @Override 2721 public byte getTypeByte() { 2722 return type; 2723 } 2724 }; 2725 } 2726 2727 /** 2728 * Estimate based on keyvalue's serialization format in the RPC layer. Note that there is an extra 2729 * SIZEOF_INT added to the size here that indicates the actual length of the cell for cases where 2730 * cell's are serialized in a contiguous format (For eg in RPCs). 2731 * @return Estimate of the <code>cell</code> size in bytes plus an extra SIZEOF_INT indicating the 2732 * actual cell length. 2733 */ 2734 public static int estimatedSerializedSizeOf(final Cell cell) { 2735 return cell.getSerializedSize() + Bytes.SIZEOF_INT; 2736 } 2737 2738 /** 2739 * Calculates the serialized key size. We always serialize in the KeyValue's serialization format. 2740 * @param cell the cell for which the key size has to be calculated. 2741 * @return the key size 2742 */ 2743 public static int estimatedSerializedSizeOfKey(final Cell cell) { 2744 if (cell instanceof KeyValue) return ((KeyValue) cell).getKeyLength(); 2745 return cell.getRowLength() + cell.getFamilyLength() + cell.getQualifierLength() 2746 + KeyValue.KEY_INFRASTRUCTURE_SIZE; 2747 } 2748 2749 /** 2750 * This method exists just to encapsulate how we serialize keys. To be replaced by a factory that 2751 * we query to figure what the Cell implementation is and then, what serialization engine to use 2752 * and further, how to serialize the key for inclusion in hfile index. TODO. 2753 * @return The key portion of the Cell serialized in the old-school KeyValue way or null if passed 2754 * a null <code>cell</code> 2755 */ 2756 public static byte[] getCellKeySerializedAsKeyValueKey(final ExtendedCell cell) { 2757 if (cell == null) return null; 2758 byte[] b = new byte[KeyValueUtil.keyLength(cell)]; 2759 KeyValueUtil.appendKeyTo(cell, b, 0); 2760 return b; 2761 } 2762 2763 /** 2764 * Create a Cell that is smaller than all other possible Cells for the given Cell's row. 2765 * @return First possible Cell on passed Cell's row. 2766 */ 2767 public static ExtendedCell createFirstOnRow(final Cell cell) { 2768 if (cell instanceof ByteBufferExtendedCell) { 2769 return new FirstOnRowByteBufferExtendedCell( 2770 ((ByteBufferExtendedCell) cell).getRowByteBuffer(), 2771 ((ByteBufferExtendedCell) cell).getRowPosition(), cell.getRowLength()); 2772 } 2773 return new FirstOnRowCell(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength()); 2774 } 2775 2776 public static ExtendedCell createFirstOnRow(final byte[] row, int roffset, short rlength) { 2777 return new FirstOnRowCell(row, roffset, rlength); 2778 } 2779 2780 public static ExtendedCell createFirstOnRow(final byte[] row, final byte[] family, 2781 final byte[] col) { 2782 return createFirstOnRow(row, 0, (short) row.length, family, 0, (byte) family.length, col, 0, 2783 col.length); 2784 } 2785 2786 public static ExtendedCell createFirstOnRow(final byte[] row, int roffset, short rlength, 2787 final byte[] family, int foffset, byte flength, final byte[] col, int coffset, int clength) { 2788 return new FirstOnRowColCell(row, roffset, rlength, family, foffset, flength, col, coffset, 2789 clength); 2790 } 2791 2792 public static ExtendedCell createFirstOnRow(final byte[] row) { 2793 return createFirstOnRow(row, 0, (short) row.length); 2794 } 2795 2796 public static ExtendedCell createFirstOnRowFamily(Cell cell, byte[] fArray, int foff, int flen) { 2797 if (cell instanceof ByteBufferExtendedCell) { 2798 return new FirstOnRowColByteBufferExtendedCell( 2799 ((ByteBufferExtendedCell) cell).getRowByteBuffer(), 2800 ((ByteBufferExtendedCell) cell).getRowPosition(), cell.getRowLength(), 2801 ByteBuffer.wrap(fArray), foff, (byte) flen, HConstants.EMPTY_BYTE_BUFFER, 0, 0); 2802 } 2803 return new FirstOnRowColCell(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength(), 2804 fArray, foff, (byte) flen, HConstants.EMPTY_BYTE_ARRAY, 0, 0); 2805 } 2806 2807 public static ExtendedCell createFirstOnRowCol(final Cell cell) { 2808 if (cell instanceof ByteBufferExtendedCell) { 2809 return new FirstOnRowColByteBufferExtendedCell( 2810 ((ByteBufferExtendedCell) cell).getRowByteBuffer(), 2811 ((ByteBufferExtendedCell) cell).getRowPosition(), cell.getRowLength(), 2812 HConstants.EMPTY_BYTE_BUFFER, 0, (byte) 0, 2813 ((ByteBufferExtendedCell) cell).getQualifierByteBuffer(), 2814 ((ByteBufferExtendedCell) cell).getQualifierPosition(), cell.getQualifierLength()); 2815 } 2816 return new FirstOnRowColCell(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength(), 2817 HConstants.EMPTY_BYTE_ARRAY, 0, (byte) 0, cell.getQualifierArray(), cell.getQualifierOffset(), 2818 cell.getQualifierLength()); 2819 } 2820 2821 public static ExtendedCell createFirstOnNextRow(final Cell cell) { 2822 byte[] nextRow = new byte[cell.getRowLength() + 1]; 2823 CellUtil.copyRowTo(cell, nextRow, 0); 2824 nextRow[nextRow.length - 1] = 0;// maybe not necessary 2825 return new FirstOnRowCell(nextRow, 0, (short) nextRow.length); 2826 } 2827 2828 /** 2829 * Create a Cell that is smaller than all other possible Cells for the given Cell's rk:cf and 2830 * passed qualifier. 2831 * @return Last possible Cell on passed Cell's rk:cf and passed qualifier. 2832 */ 2833 public static ExtendedCell createFirstOnRowCol(final Cell cell, byte[] qArray, int qoffest, 2834 int qlength) { 2835 if (cell instanceof ByteBufferExtendedCell) { 2836 return new FirstOnRowColByteBufferExtendedCell( 2837 ((ByteBufferExtendedCell) cell).getRowByteBuffer(), 2838 ((ByteBufferExtendedCell) cell).getRowPosition(), cell.getRowLength(), 2839 ((ByteBufferExtendedCell) cell).getFamilyByteBuffer(), 2840 ((ByteBufferExtendedCell) cell).getFamilyPosition(), cell.getFamilyLength(), 2841 ByteBuffer.wrap(qArray), qoffest, qlength); 2842 } 2843 return new FirstOnRowColCell(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength(), 2844 cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength(), qArray, qoffest, 2845 qlength); 2846 } 2847 2848 /** 2849 * Creates the first cell with the row/family/qualifier of this cell and the given timestamp. Uses 2850 * the "maximum" type that guarantees that the new cell is the lowest possible for this 2851 * combination of row, family, qualifier, and timestamp. This cell's own timestamp is ignored. 2852 * @param cell - cell 2853 */ 2854 public static ExtendedCell createFirstOnRowColTS(Cell cell, long ts) { 2855 if (cell instanceof ByteBufferExtendedCell) { 2856 return new FirstOnRowColTSByteBufferExtendedCell( 2857 ((ByteBufferExtendedCell) cell).getRowByteBuffer(), 2858 ((ByteBufferExtendedCell) cell).getRowPosition(), cell.getRowLength(), 2859 ((ByteBufferExtendedCell) cell).getFamilyByteBuffer(), 2860 ((ByteBufferExtendedCell) cell).getFamilyPosition(), cell.getFamilyLength(), 2861 ((ByteBufferExtendedCell) cell).getQualifierByteBuffer(), 2862 ((ByteBufferExtendedCell) cell).getQualifierPosition(), cell.getQualifierLength(), ts); 2863 } 2864 return new FirstOnRowColTSCell(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength(), 2865 cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength(), 2866 cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength(), ts); 2867 } 2868 2869 /** 2870 * Create a Cell that is larger than all other possible Cells for the given Cell's row. 2871 * @return Last possible Cell on passed Cell's row. 2872 */ 2873 public static ExtendedCell createLastOnRow(final Cell cell) { 2874 if (cell instanceof ByteBufferExtendedCell) { 2875 return new LastOnRowByteBufferExtendedCell(((ByteBufferExtendedCell) cell).getRowByteBuffer(), 2876 ((ByteBufferExtendedCell) cell).getRowPosition(), cell.getRowLength()); 2877 } 2878 return new LastOnRowCell(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength()); 2879 } 2880 2881 public static ExtendedCell createLastOnRow(final byte[] row) { 2882 return new LastOnRowCell(row, 0, (short) row.length); 2883 } 2884 2885 /** 2886 * Create a Cell that is larger than all other possible Cells for the given Cell's rk:cf:q. Used 2887 * in creating "fake keys" for the multi-column Bloom filter optimization to skip the row/column 2888 * we already know is not in the file. 2889 * @return Last possible Cell on passed Cell's rk:cf:q. 2890 */ 2891 public static ExtendedCell createLastOnRowCol(final Cell cell) { 2892 if (cell instanceof ByteBufferExtendedCell) { 2893 return new LastOnRowColByteBufferExtendedCell( 2894 ((ByteBufferExtendedCell) cell).getRowByteBuffer(), 2895 ((ByteBufferExtendedCell) cell).getRowPosition(), cell.getRowLength(), 2896 ((ByteBufferExtendedCell) cell).getFamilyByteBuffer(), 2897 ((ByteBufferExtendedCell) cell).getFamilyPosition(), cell.getFamilyLength(), 2898 ((ByteBufferExtendedCell) cell).getQualifierByteBuffer(), 2899 ((ByteBufferExtendedCell) cell).getQualifierPosition(), cell.getQualifierLength()); 2900 } 2901 return new LastOnRowColCell(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength(), 2902 cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength(), 2903 cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength()); 2904 } 2905 2906 /** 2907 * Create a Delete Family Cell for the specified row and family that would be smaller than all 2908 * other possible Delete Family KeyValues that have the same row and family. Used for seeking. 2909 * @param row - row key (arbitrary byte array) 2910 * @param fam - family name 2911 * @return First Delete Family possible key on passed <code>row</code>. 2912 */ 2913 public static ExtendedCell createFirstDeleteFamilyCellOnRow(final byte[] row, final byte[] fam) { 2914 return new FirstOnRowDeleteFamilyCell(row, fam); 2915 } 2916 2917 /** 2918 * In fact, in HBase, all {@link Cell}s are {@link ExtendedCell}s. We do not expect users to 2919 * implement their own {@link Cell} types, except some special projects like Phoenix, where they 2920 * just use {@link org.apache.hadoop.hbase.KeyValue} and {@link ExtendedCell} directly. 2921 * @return the original {@code cell} which has already been cast to an {@link ExtendedCell}. 2922 * @throws IllegalArgumentException if the given {@code cell} is not an {@link ExtendedCell}. 2923 */ 2924 public static ExtendedCell ensureExtendedCell(Cell cell) { 2925 if (cell == null) { 2926 return null; 2927 } 2928 Preconditions.checkArgument(cell instanceof ExtendedCell, "Unsupported cell type: %s", 2929 cell.getClass().getName()); 2930 return (ExtendedCell) cell; 2931 } 2932 2933 public static boolean equals(ExtendedCell a, ExtendedCell b) { 2934 return CellUtil.matchingRows(a, b) && CellUtil.matchingFamily(a, b) 2935 && CellUtil.matchingQualifier(a, b) && CellUtil.matchingTimestamp(a, b) 2936 && PrivateCellUtil.matchingType(a, b); 2937 } 2938 2939 /** Returns ExtendedCellScanner interface over <code>cellIterables</code> */ 2940 public static ExtendedCellScanner 2941 createExtendedCellScanner(final List<? extends ExtendedCellScannable> cellScannerables) { 2942 return new ExtendedCellScanner() { 2943 private final Iterator<? extends ExtendedCellScannable> iterator = 2944 cellScannerables.iterator(); 2945 private ExtendedCellScanner cellScanner = null; 2946 2947 @Override 2948 public ExtendedCell current() { 2949 return this.cellScanner != null ? this.cellScanner.current() : null; 2950 } 2951 2952 @Override 2953 public boolean advance() throws IOException { 2954 while (true) { 2955 if (this.cellScanner == null) { 2956 if (!this.iterator.hasNext()) { 2957 return false; 2958 } 2959 this.cellScanner = this.iterator.next().cellScanner(); 2960 } 2961 if (this.cellScanner.advance()) { 2962 return true; 2963 } 2964 this.cellScanner = null; 2965 } 2966 } 2967 }; 2968 } 2969 2970 /** 2971 * Flatten the map of cells out under the ExtendedCellScanner 2972 * @param map Map of Cell Lists; for example, the map of families to ExtendedCells that is used 2973 * inside Put, etc., keeping Cells organized by family. 2974 * @return ExtendedCellScanner interface over <code>cellIterable</code> 2975 */ 2976 public static ExtendedCellScanner 2977 createExtendedCellScanner(final NavigableMap<byte[], List<ExtendedCell>> map) { 2978 return new ExtendedCellScanner() { 2979 private final Iterator<Entry<byte[], List<ExtendedCell>>> entries = map.entrySet().iterator(); 2980 private Iterator<ExtendedCell> currentIterator = null; 2981 private ExtendedCell currentCell; 2982 2983 @Override 2984 public ExtendedCell current() { 2985 return this.currentCell; 2986 } 2987 2988 @Override 2989 public boolean advance() { 2990 while (true) { 2991 if (this.currentIterator == null) { 2992 if (!this.entries.hasNext()) { 2993 return false; 2994 } 2995 this.currentIterator = this.entries.next().getValue().iterator(); 2996 } 2997 if (this.currentIterator.hasNext()) { 2998 this.currentCell = this.currentIterator.next(); 2999 return true; 3000 } 3001 this.currentCell = null; 3002 this.currentIterator = null; 3003 } 3004 } 3005 }; 3006 } 3007 3008 /** Returns CellScanner interface over <code>cellArray</code> */ 3009 public static ExtendedCellScanner createExtendedCellScanner(final ExtendedCell[] cellArray) { 3010 return new ExtendedCellScanner() { 3011 private final ExtendedCell[] cells = cellArray; 3012 private int index = -1; 3013 3014 @Override 3015 public ExtendedCell current() { 3016 if (cells == null) { 3017 return null; 3018 } 3019 return (index < 0) ? null : this.cells[index]; 3020 } 3021 3022 @Override 3023 public boolean advance() { 3024 if (cells == null) { 3025 return false; 3026 } 3027 return ++index < this.cells.length; 3028 } 3029 }; 3030 } 3031 3032 /** Returns ExtendedCellScanner interface over <code>cellIterable</code> */ 3033 public static ExtendedCellScanner 3034 createExtendedCellScanner(final Iterable<ExtendedCell> cellIterable) { 3035 if (cellIterable == null) { 3036 return null; 3037 } 3038 return createExtendedCellScanner(cellIterable.iterator()); 3039 } 3040 3041 /** 3042 * Returns ExtendedCellScanner interface over <code>cellIterable</code> or null if 3043 * <code>cells</code> is null 3044 */ 3045 public static ExtendedCellScanner createExtendedCellScanner(final Iterator<ExtendedCell> cells) { 3046 if (cells == null) { 3047 return null; 3048 } 3049 return new ExtendedCellScanner() { 3050 private final Iterator<ExtendedCell> iterator = cells; 3051 private ExtendedCell current = null; 3052 3053 @Override 3054 public ExtendedCell current() { 3055 return this.current; 3056 } 3057 3058 @Override 3059 public boolean advance() { 3060 boolean hasNext = this.iterator.hasNext(); 3061 this.current = hasNext ? this.iterator.next() : null; 3062 return hasNext; 3063 } 3064 }; 3065 } 3066 3067 private static final Cell.Type[] CELL_TYPE_CODE_ARRAY = new Cell.Type[256]; 3068 3069 static { 3070 for (Cell.Type t : Cell.Type.values()) { 3071 CELL_TYPE_CODE_ARRAY[t.getCode() & 0xff] = t; 3072 } 3073 } 3074 3075 public static Cell.Type code2Type(byte code) { 3076 Cell.Type t = CELL_TYPE_CODE_ARRAY[code & 0xff]; 3077 if (t != null) { 3078 return t; 3079 } 3080 throw new UnsupportedOperationException("Invalid type of cell " + code); 3081 } 3082 3083 public static byte getTypeByte(Cell c) { 3084 if (c instanceof ExtendedCell) { 3085 return ((ExtendedCell) c).getTypeByte(); 3086 } else { 3087 return c.getType().getCode(); 3088 } 3089 } 3090 3091 public static long getSequenceId(Cell c) { 3092 if (c instanceof ExtendedCell) { 3093 return ((ExtendedCell) c).getSequenceId(); 3094 } else { 3095 return HConstants.NO_SEQNUM; 3096 } 3097 } 3098}