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 */ 018 019package org.apache.hadoop.hbase; 020 021import static org.apache.hadoop.hbase.KeyValue.COLUMN_FAMILY_DELIMITER; 022import static org.apache.hadoop.hbase.KeyValue.COLUMN_FAMILY_DELIM_ARRAY; 023import static org.apache.hadoop.hbase.KeyValue.getDelimiter; 024import static org.apache.hadoop.hbase.Tag.TAG_LENGTH_SIZE; 025 026import java.io.DataOutput; 027import java.io.DataOutputStream; 028import java.io.IOException; 029import java.nio.ByteBuffer; 030import java.util.ArrayList; 031import java.util.Arrays; 032import java.util.Iterator; 033import java.util.List; 034import java.util.Map.Entry; 035import java.util.NavigableMap; 036import java.util.Optional; 037 038import org.apache.hadoop.hbase.KeyValue.Type; 039import org.apache.hadoop.hbase.io.HeapSize; 040import org.apache.hadoop.hbase.util.ByteBufferUtils; 041import org.apache.hadoop.hbase.util.ByteRange; 042import org.apache.hadoop.hbase.util.Bytes; 043import org.apache.yetus.audience.InterfaceAudience; 044import org.apache.yetus.audience.InterfaceAudience.Private; 045 046import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting; 047 048/** 049 * Utility methods helpful for slinging {@link Cell} instances. Some methods below are for internal 050 * use only and are marked InterfaceAudience.Private at the method level. Note that all such methods 051 * have been marked deprecated in HBase-2.0 which will be subsequently removed in HBase-3.0 052 */ 053@InterfaceAudience.Public 054public final class CellUtil { 055 056 /** 057 * Private constructor to keep this class from being instantiated. 058 */ 059 private CellUtil() { 060 } 061 062 /******************* ByteRange *******************************/ 063 064 /** 065 * @deprecated As of HBase-2.0. Will be removed in HBase-3.0. 066 */ 067 @Deprecated 068 public static ByteRange fillRowRange(Cell cell, ByteRange range) { 069 return range.set(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength()); 070 } 071 072 /** 073 * @deprecated As of HBase-2.0. Will be removed in HBase-3.0. 074 */ 075 @Deprecated 076 public static ByteRange fillFamilyRange(Cell cell, ByteRange range) { 077 return range.set(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength()); 078 } 079 080 /** 081 * @deprecated As of HBase-2.0. Will be removed in HBase-3.0. 082 */ 083 @Deprecated 084 public static ByteRange fillQualifierRange(Cell cell, ByteRange range) { 085 return range.set(cell.getQualifierArray(), cell.getQualifierOffset(), 086 cell.getQualifierLength()); 087 } 088 089 /** 090 * @deprecated As of HBase-2.0. Will be removed in HBase-3.0. 091 */ 092 @Deprecated 093 public static ByteRange fillValueRange(Cell cell, ByteRange range) { 094 return range.set(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength()); 095 } 096 097 /** 098 * @deprecated As of HBase-2.0. Will be removed in HBase-3.0. 099 */ 100 @Deprecated 101 public static ByteRange fillTagRange(Cell cell, ByteRange range) { 102 return range.set(cell.getTagsArray(), cell.getTagsOffset(), cell.getTagsLength()); 103 } 104 105 /***************** get individual arrays for tests ************/ 106 107 public static byte[] cloneRow(Cell cell) { 108 byte[] output = new byte[cell.getRowLength()]; 109 copyRowTo(cell, output, 0); 110 return output; 111 } 112 113 public static byte[] cloneFamily(Cell cell) { 114 byte[] output = new byte[cell.getFamilyLength()]; 115 copyFamilyTo(cell, output, 0); 116 return output; 117 } 118 119 public static byte[] cloneQualifier(Cell cell) { 120 byte[] output = new byte[cell.getQualifierLength()]; 121 copyQualifierTo(cell, output, 0); 122 return output; 123 } 124 125 public static byte[] cloneValue(Cell cell) { 126 byte[] output = new byte[cell.getValueLength()]; 127 copyValueTo(cell, output, 0); 128 return output; 129 } 130 131 /** 132 * @deprecated As of HBase-2.0. Will be removed in HBase-3.0. 133 * Use {@link RawCell#cloneTags()} 134 */ 135 @Deprecated 136 public static byte[] cloneTags(Cell cell) { 137 byte[] output = new byte[cell.getTagsLength()]; 138 PrivateCellUtil.copyTagsTo(cell, output, 0); 139 return output; 140 } 141 142 /** 143 * Returns tag value in a new byte array. If server-side, use {@link Tag#getValueArray()} with 144 * appropriate {@link Tag#getValueOffset()} and {@link Tag#getValueLength()} instead to save on 145 * allocations. 146 * @param cell 147 * @return tag value in a new byte array. 148 * @deprecated As of HBase-2.0. Will be removed in HBase-3.0 149 */ 150 @Deprecated 151 public static byte[] getTagArray(Cell cell) { 152 byte[] output = new byte[cell.getTagsLength()]; 153 PrivateCellUtil.copyTagsTo(cell, output, 0); 154 return output; 155 } 156 157 /** 158 * Makes a column in family:qualifier form from separate byte arrays. 159 * <p> 160 * Not recommended for usage as this is old-style API. 161 * @param family 162 * @param qualifier 163 * @return family:qualifier 164 */ 165 public static byte[] makeColumn(byte[] family, byte[] qualifier) { 166 return Bytes.add(family, COLUMN_FAMILY_DELIM_ARRAY, qualifier); 167 } 168 169 /** 170 * Splits a column in {@code family:qualifier} form into separate byte arrays. An empty qualifier 171 * (ie, {@code fam:}) is parsed as <code>{ fam, EMPTY_BYTE_ARRAY }</code> while no delimiter (ie, 172 * {@code fam}) is parsed as an array of one element, <code>{ fam }</code>. 173 * <p> 174 * Don't forget, HBase DOES support empty qualifiers. (see HBASE-9549) 175 * </p> 176 * <p> 177 * Not recommend to be used as this is old-style API. 178 * </p> 179 * @param c The column. 180 * @return The parsed column. 181 */ 182 public static byte[][] parseColumn(byte[] c) { 183 final int index = getDelimiter(c, 0, c.length, COLUMN_FAMILY_DELIMITER); 184 if (index == -1) { 185 // If no delimiter, return array of size 1 186 return new byte[][] { c }; 187 } else if (index == c.length - 1) { 188 // family with empty qualifier, return array size 2 189 byte[] family = new byte[c.length - 1]; 190 System.arraycopy(c, 0, family, 0, family.length); 191 return new byte[][] { family, HConstants.EMPTY_BYTE_ARRAY }; 192 } 193 // Family and column, return array size 2 194 final byte[][] result = new byte[2][]; 195 result[0] = new byte[index]; 196 System.arraycopy(c, 0, result[0], 0, index); 197 final int len = c.length - (index + 1); 198 result[1] = new byte[len]; 199 System.arraycopy(c, index + 1 /* Skip delimiter */, result[1], 0, len); 200 return result; 201 } 202 203 /******************** copyTo **********************************/ 204 205 /** 206 * Copies the row to the given byte[] 207 * @param cell the cell whose row has to be copied 208 * @param destination the destination byte[] to which the row has to be copied 209 * @param destinationOffset the offset in the destination byte[] 210 * @return the offset of the byte[] after the copy has happened 211 */ 212 public static int copyRowTo(Cell cell, byte[] destination, int destinationOffset) { 213 short rowLen = cell.getRowLength(); 214 if (cell instanceof ByteBufferExtendedCell) { 215 ByteBufferUtils.copyFromBufferToArray(destination, 216 ((ByteBufferExtendedCell) cell).getRowByteBuffer(), 217 ((ByteBufferExtendedCell) cell).getRowPosition(), destinationOffset, rowLen); 218 } else { 219 System.arraycopy(cell.getRowArray(), cell.getRowOffset(), destination, destinationOffset, 220 rowLen); 221 } 222 return destinationOffset + rowLen; 223 } 224 225 /** 226 * Copies the row to the given bytebuffer 227 * @param cell cell the cell whose row has to be copied 228 * @param destination the destination bytebuffer to which the row has to be copied 229 * @param destinationOffset the offset in the destination byte[] 230 * @return the offset of the bytebuffer after the copy has happened 231 */ 232 public static int copyRowTo(Cell cell, ByteBuffer destination, int destinationOffset) { 233 short rowLen = cell.getRowLength(); 234 if (cell instanceof ByteBufferExtendedCell) { 235 ByteBufferUtils.copyFromBufferToBuffer(((ByteBufferExtendedCell) cell).getRowByteBuffer(), 236 destination, ((ByteBufferExtendedCell) cell).getRowPosition(), destinationOffset, rowLen); 237 } else { 238 ByteBufferUtils.copyFromArrayToBuffer(destination, destinationOffset, cell.getRowArray(), 239 cell.getRowOffset(), rowLen); 240 } 241 return destinationOffset + rowLen; 242 } 243 244 /** 245 * Copies the row to a new byte[] 246 * @param cell the cell from which row has to copied 247 * @return the byte[] containing the row 248 */ 249 public static byte[] copyRow(Cell cell) { 250 if (cell instanceof ByteBufferExtendedCell) { 251 return ByteBufferUtils.copyOfRange(((ByteBufferExtendedCell) cell).getRowByteBuffer(), 252 ((ByteBufferExtendedCell) cell).getRowPosition(), 253 ((ByteBufferExtendedCell) cell).getRowPosition() + cell.getRowLength()); 254 } else { 255 return Arrays.copyOfRange(cell.getRowArray(), cell.getRowOffset(), 256 cell.getRowOffset() + cell.getRowLength()); 257 } 258 } 259 260 /** 261 * Copies the family to the given byte[] 262 * @param cell the cell whose family has to be copied 263 * @param destination the destination byte[] to which the family has to be copied 264 * @param destinationOffset the offset in the destination byte[] 265 * @return the offset of the byte[] after the copy has happened 266 */ 267 public static int copyFamilyTo(Cell cell, byte[] destination, int destinationOffset) { 268 byte fLen = cell.getFamilyLength(); 269 if (cell instanceof ByteBufferExtendedCell) { 270 ByteBufferUtils.copyFromBufferToArray(destination, 271 ((ByteBufferExtendedCell) cell).getFamilyByteBuffer(), 272 ((ByteBufferExtendedCell) cell).getFamilyPosition(), destinationOffset, fLen); 273 } else { 274 System.arraycopy(cell.getFamilyArray(), cell.getFamilyOffset(), destination, 275 destinationOffset, fLen); 276 } 277 return destinationOffset + fLen; 278 } 279 280 /** 281 * Copies the family to the given bytebuffer 282 * @param cell the cell whose family has to be copied 283 * @param destination the destination bytebuffer to which the family has to be copied 284 * @param destinationOffset the offset in the destination bytebuffer 285 * @return the offset of the bytebuffer after the copy has happened 286 */ 287 public static int copyFamilyTo(Cell cell, ByteBuffer destination, int destinationOffset) { 288 byte fLen = cell.getFamilyLength(); 289 if (cell instanceof ByteBufferExtendedCell) { 290 ByteBufferUtils.copyFromBufferToBuffer(((ByteBufferExtendedCell) cell).getFamilyByteBuffer(), 291 destination, ((ByteBufferExtendedCell) cell).getFamilyPosition(), destinationOffset, fLen); 292 } else { 293 ByteBufferUtils.copyFromArrayToBuffer(destination, destinationOffset, cell.getFamilyArray(), 294 cell.getFamilyOffset(), fLen); 295 } 296 return destinationOffset + fLen; 297 } 298 299 /** 300 * Copies the qualifier to the given byte[] 301 * @param cell the cell whose qualifier has to be copied 302 * @param destination the destination byte[] to which the qualifier has to be copied 303 * @param destinationOffset the offset in the destination byte[] 304 * @return the offset of the byte[] after the copy has happened 305 */ 306 public static int copyQualifierTo(Cell cell, byte[] destination, int destinationOffset) { 307 int qlen = cell.getQualifierLength(); 308 if (cell instanceof ByteBufferExtendedCell) { 309 ByteBufferUtils.copyFromBufferToArray(destination, 310 ((ByteBufferExtendedCell) cell).getQualifierByteBuffer(), 311 ((ByteBufferExtendedCell) cell).getQualifierPosition(), destinationOffset, qlen); 312 } else { 313 System.arraycopy(cell.getQualifierArray(), cell.getQualifierOffset(), destination, 314 destinationOffset, qlen); 315 } 316 return destinationOffset + qlen; 317 } 318 319 /** 320 * Copies the qualifier to the given bytebuffer 321 * @param cell the cell whose qualifier has to be copied 322 * @param destination the destination bytebuffer to which the qualifier has to be copied 323 * @param destinationOffset the offset in the destination bytebuffer 324 * @return the offset of the bytebuffer after the copy has happened 325 */ 326 public static int copyQualifierTo(Cell cell, ByteBuffer destination, int destinationOffset) { 327 int qlen = cell.getQualifierLength(); 328 if (cell instanceof ByteBufferExtendedCell) { 329 ByteBufferUtils.copyFromBufferToBuffer( 330 ((ByteBufferExtendedCell) cell).getQualifierByteBuffer(), 331 destination, ((ByteBufferExtendedCell) cell).getQualifierPosition(), 332 destinationOffset, qlen); 333 } else { 334 ByteBufferUtils.copyFromArrayToBuffer(destination, destinationOffset, 335 cell.getQualifierArray(), cell.getQualifierOffset(), qlen); 336 } 337 return destinationOffset + qlen; 338 } 339 340 /** 341 * Copies the value to the given byte[] 342 * @param cell the cell whose value has to be copied 343 * @param destination the destination byte[] to which the value has to be copied 344 * @param destinationOffset the offset in the destination byte[] 345 * @return the offset of the byte[] after the copy has happened 346 */ 347 public static int copyValueTo(Cell cell, byte[] destination, int destinationOffset) { 348 int vlen = cell.getValueLength(); 349 if (cell instanceof ByteBufferExtendedCell) { 350 ByteBufferUtils.copyFromBufferToArray(destination, 351 ((ByteBufferExtendedCell) cell).getValueByteBuffer(), 352 ((ByteBufferExtendedCell) cell).getValuePosition(), destinationOffset, vlen); 353 } else { 354 System.arraycopy(cell.getValueArray(), cell.getValueOffset(), destination, destinationOffset, 355 vlen); 356 } 357 return destinationOffset + vlen; 358 } 359 360 /** 361 * Copies the value to the given bytebuffer 362 * @param cell the cell whose value has to be copied 363 * @param destination the destination bytebuffer to which the value has to be copied 364 * @param destinationOffset the offset in the destination bytebuffer 365 * @return the offset of the bytebuffer after the copy has happened 366 */ 367 public static int copyValueTo(Cell cell, ByteBuffer destination, int destinationOffset) { 368 int vlen = cell.getValueLength(); 369 if (cell instanceof ByteBufferExtendedCell) { 370 ByteBufferUtils.copyFromBufferToBuffer(((ByteBufferExtendedCell) cell).getValueByteBuffer(), 371 destination, ((ByteBufferExtendedCell) cell).getValuePosition(), destinationOffset, vlen); 372 } else { 373 ByteBufferUtils.copyFromArrayToBuffer(destination, destinationOffset, cell.getValueArray(), 374 cell.getValueOffset(), vlen); 375 } 376 return destinationOffset + vlen; 377 } 378 379 /** 380 * Copies the tags info into the tag portion of the cell 381 * @param cell 382 * @param destination 383 * @param destinationOffset 384 * @return position after tags 385 * @deprecated As of HBase-2.0. Will be removed in HBase-3.0. 386 */ 387 @Deprecated 388 public static int copyTagTo(Cell cell, byte[] destination, int destinationOffset) { 389 int tlen = cell.getTagsLength(); 390 if (cell instanceof ByteBufferExtendedCell) { 391 ByteBufferUtils 392 .copyFromBufferToArray(destination, ((ByteBufferExtendedCell) cell).getTagsByteBuffer(), 393 ((ByteBufferExtendedCell) cell).getTagsPosition(), destinationOffset, tlen); 394 } else { 395 System 396 .arraycopy(cell.getTagsArray(), cell.getTagsOffset(), destination, destinationOffset, tlen); 397 } 398 return destinationOffset + tlen; 399 } 400 401 /** 402 * Copies the tags info into the tag portion of the cell 403 * @param cell 404 * @param destination 405 * @param destinationOffset 406 * @return position after tags 407 * @deprecated As of HBase-2.0. Will be removed in 3.0. 408 */ 409 @Deprecated 410 public static int copyTagTo(Cell cell, ByteBuffer destination, int destinationOffset) { 411 int tlen = cell.getTagsLength(); 412 if (cell instanceof ByteBufferExtendedCell) { 413 ByteBufferUtils.copyFromBufferToBuffer(((ByteBufferExtendedCell) cell).getTagsByteBuffer(), 414 destination, ((ByteBufferExtendedCell) cell).getTagsPosition(), destinationOffset, tlen); 415 } else { 416 ByteBufferUtils.copyFromArrayToBuffer(destination, destinationOffset, cell.getTagsArray(), 417 cell.getTagsOffset(), tlen); 418 } 419 return destinationOffset + tlen; 420 } 421 422 /********************* misc *************************************/ 423 424 @Private 425 /** 426 * @deprecated As of HBase-2.0. Will be removed in HBase-3.0. 427 */ 428 @Deprecated 429 public static byte getRowByte(Cell cell, int index) { 430 if (cell instanceof ByteBufferExtendedCell) { 431 return ((ByteBufferExtendedCell) cell).getRowByteBuffer() 432 .get(((ByteBufferExtendedCell) cell).getRowPosition() + index); 433 } 434 return cell.getRowArray()[cell.getRowOffset() + index]; 435 } 436 437 /** 438 * @deprecated As of HBase-2.0. Will be removed in 3.0. 439 */ 440 @Deprecated 441 public static ByteBuffer getValueBufferShallowCopy(Cell cell) { 442 ByteBuffer buffer = 443 ByteBuffer.wrap(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength()); 444 return buffer; 445 } 446 447 /** 448 * @param cell 449 * @return cell's qualifier wrapped into a ByteBuffer. 450 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. 451 */ 452 @Deprecated 453 public static ByteBuffer getQualifierBufferShallowCopy(Cell cell) { 454 // No usage of this in code. 455 ByteBuffer buffer = ByteBuffer.wrap(cell.getQualifierArray(), cell.getQualifierOffset(), 456 cell.getQualifierLength()); 457 return buffer; 458 } 459 460 /** 461 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. Use {@link CellBuilder} 462 * instead 463 */ 464 @Deprecated 465 public static Cell createCell(final byte[] row, final byte[] family, final byte[] qualifier, 466 final long timestamp, final byte type, final byte[] value) { 467 return ExtendedCellBuilderFactory.create(CellBuilderType.DEEP_COPY) 468 .setRow(row) 469 .setFamily(family) 470 .setQualifier(qualifier) 471 .setTimestamp(timestamp) 472 .setType(type) 473 .setValue(value) 474 .build(); 475 } 476 477 /** 478 * Creates a cell with deep copy of all passed bytes. 479 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. Use {@link CellBuilder} 480 * instead 481 */ 482 @Deprecated 483 public static Cell createCell(final byte[] rowArray, final int rowOffset, final int rowLength, 484 final byte[] familyArray, final int familyOffset, final int familyLength, 485 final byte[] qualifierArray, final int qualifierOffset, final int qualifierLength) { 486 // See createCell(final byte [] row, final byte [] value) for why we default Maximum type. 487 return ExtendedCellBuilderFactory.create(CellBuilderType.DEEP_COPY) 488 .setRow(rowArray, rowOffset, rowLength) 489 .setFamily(familyArray, familyOffset, familyLength) 490 .setQualifier(qualifierArray, qualifierOffset, qualifierLength) 491 .setTimestamp(HConstants.LATEST_TIMESTAMP) 492 .setType(KeyValue.Type.Maximum.getCode()) 493 .setValue(HConstants.EMPTY_BYTE_ARRAY, 0, HConstants.EMPTY_BYTE_ARRAY.length) 494 .build(); 495 } 496 497 /** 498 * Marked as audience Private as of 1.2.0. 499 * Creating a Cell with a memstoreTS/mvcc is an internal 500 * implementation detail not for public use. 501 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. Use 502 * {@link ExtendedCellBuilder} instead 503 */ 504 @InterfaceAudience.Private 505 @Deprecated 506 public static Cell createCell(final byte[] row, final byte[] family, final byte[] qualifier, 507 final long timestamp, final byte type, final byte[] value, final long memstoreTS) { 508 return createCell(row, family, qualifier, timestamp, type, value, null, memstoreTS); 509 } 510 511 /** 512 * Marked as audience Private as of 1.2.0. 513 * Creating a Cell with tags and a memstoreTS/mvcc is an 514 * internal implementation detail not for public use. 515 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. Use 516 * {@link ExtendedCellBuilder} instead 517 */ 518 @InterfaceAudience.Private 519 @Deprecated 520 public static Cell createCell(final byte[] row, final byte[] family, final byte[] qualifier, 521 final long timestamp, final byte type, final byte[] value, byte[] tags, 522 final long memstoreTS) { 523 return ExtendedCellBuilderFactory.create(CellBuilderType.DEEP_COPY) 524 .setRow(row) 525 .setFamily(family) 526 .setQualifier(qualifier) 527 .setTimestamp(timestamp) 528 .setType(type) 529 .setValue(value) 530 .setTags(tags) 531 .setSequenceId(memstoreTS) 532 .build(); 533 } 534 535 /** 536 * Marked as audience Private as of 1.2.0. 537 * Creating a Cell with tags is an internal implementation detail not for public use. 538 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. Use 539 * {@link ExtendedCellBuilder} instead 540 */ 541 @InterfaceAudience.Private 542 @Deprecated 543 public static Cell createCell(final byte[] row, final byte[] family, final byte[] qualifier, 544 final long timestamp, Type type, final byte[] value, byte[] tags) { 545 return createCell(row, family, qualifier, timestamp, type.getCode(), value, tags, 0); 546 } 547 548 /** 549 * Create a Cell with specific row. Other fields defaulted. 550 * @param row 551 * @return Cell with passed row but all other fields are arbitrary 552 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. Use {@link CellBuilder} 553 * instead 554 */ 555 @Deprecated 556 public static Cell createCell(final byte[] row) { 557 return createCell(row, HConstants.EMPTY_BYTE_ARRAY); 558 } 559 560 /** 561 * Create a Cell with specific row and value. Other fields are defaulted. 562 * @param row 563 * @param value 564 * @return Cell with passed row and value but all other fields are arbitrary 565 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. Use {@link CellBuilder} 566 * instead 567 */ 568 @Deprecated 569 public static Cell createCell(final byte[] row, final byte[] value) { 570 // An empty family + empty qualifier + Type.Minimum is used as flag to indicate last on row. 571 // See the CellComparator and KeyValue comparator. Search for compareWithoutRow. 572 // Lets not make a last-on-row key as default but at same time, if you are making a key 573 // without specifying type, etc., flag it as weird by setting type to be Maximum. 574 return createCell(row, HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY, 575 HConstants.LATEST_TIMESTAMP, KeyValue.Type.Maximum.getCode(), value); 576 } 577 578 /** 579 * Create a Cell with specific row. Other fields defaulted. 580 * @param row 581 * @param family 582 * @param qualifier 583 * @return Cell with passed row but all other fields are arbitrary 584 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. Use {@link CellBuilder} 585 * instead 586 */ 587 @Deprecated 588 public static Cell createCell(final byte[] row, final byte[] family, final byte[] qualifier) { 589 // See above in createCell(final byte [] row, final byte [] value) why we set type to Maximum. 590 return createCell(row, family, qualifier, HConstants.LATEST_TIMESTAMP, 591 KeyValue.Type.Maximum.getCode(), HConstants.EMPTY_BYTE_ARRAY); 592 } 593 594 /** 595 * Note : Now only CPs can create cell with tags using the CP environment 596 * @return A new cell which is having the extra tags also added to it. 597 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. 598 * 599 */ 600 @Deprecated 601 public static Cell createCell(Cell cell, List<Tag> tags) { 602 return PrivateCellUtil.createCell(cell, tags); 603 } 604 605 /** 606 * Now only CPs can create cell with tags using the CP environment 607 * @return A new cell which is having the extra tags also added to it. 608 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. 609 */ 610 @Deprecated 611 public static Cell createCell(Cell cell, byte[] tags) { 612 return PrivateCellUtil.createCell(cell, tags); 613 } 614 615 /** 616 * Now only CPs can create cell with tags using the CP environment 617 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. 618 */ 619 @Deprecated 620 public static Cell createCell(Cell cell, byte[] value, byte[] tags) { 621 return PrivateCellUtil.createCell(cell, value, tags); 622 } 623 624 /** 625 * @param cellScannerables 626 * @return CellScanner interface over <code>cellIterables</code> 627 */ 628 public static CellScanner 629 createCellScanner(final List<? extends CellScannable> cellScannerables) { 630 return new CellScanner() { 631 private final Iterator<? extends CellScannable> iterator = cellScannerables.iterator(); 632 private CellScanner cellScanner = null; 633 634 @Override 635 public Cell current() { 636 return this.cellScanner != null ? this.cellScanner.current() : null; 637 } 638 639 @Override 640 public boolean advance() throws IOException { 641 while (true) { 642 if (this.cellScanner == null) { 643 if (!this.iterator.hasNext()) return false; 644 this.cellScanner = this.iterator.next().cellScanner(); 645 } 646 if (this.cellScanner.advance()) return true; 647 this.cellScanner = null; 648 } 649 } 650 }; 651 } 652 653 /** 654 * @param cellIterable 655 * @return CellScanner interface over <code>cellIterable</code> 656 */ 657 public static CellScanner createCellScanner(final Iterable<Cell> cellIterable) { 658 if (cellIterable == null) return null; 659 return createCellScanner(cellIterable.iterator()); 660 } 661 662 /** 663 * @param cells 664 * @return CellScanner interface over <code>cellIterable</code> or null if <code>cells</code> is 665 * null 666 */ 667 public static CellScanner createCellScanner(final Iterator<Cell> cells) { 668 if (cells == null) return null; 669 return new CellScanner() { 670 private final Iterator<Cell> iterator = cells; 671 private Cell current = null; 672 673 @Override 674 public Cell current() { 675 return this.current; 676 } 677 678 @Override 679 public boolean advance() { 680 boolean hasNext = this.iterator.hasNext(); 681 this.current = hasNext ? this.iterator.next() : null; 682 return hasNext; 683 } 684 }; 685 } 686 687 /** 688 * @param cellArray 689 * @return CellScanner interface over <code>cellArray</code> 690 */ 691 public static CellScanner createCellScanner(final Cell[] cellArray) { 692 return new CellScanner() { 693 private final Cell[] cells = cellArray; 694 private int index = -1; 695 696 @Override 697 public Cell current() { 698 if (cells == null) return null; 699 return (index < 0) ? null : this.cells[index]; 700 } 701 702 @Override 703 public boolean advance() { 704 if (cells == null) return false; 705 return ++index < this.cells.length; 706 } 707 }; 708 } 709 710 /** 711 * Flatten the map of cells out under the CellScanner 712 * @param map Map of Cell Lists; for example, the map of families to Cells that is used inside 713 * Put, etc., keeping Cells organized by family. 714 * @return CellScanner interface over <code>cellIterable</code> 715 */ 716 public static CellScanner createCellScanner(final NavigableMap<byte[], List<Cell>> map) { 717 return new CellScanner() { 718 private final Iterator<Entry<byte[], List<Cell>>> entries = map.entrySet().iterator(); 719 private Iterator<Cell> currentIterator = null; 720 private Cell currentCell; 721 722 @Override 723 public Cell current() { 724 return this.currentCell; 725 } 726 727 @Override 728 public boolean advance() { 729 while (true) { 730 if (this.currentIterator == null) { 731 if (!this.entries.hasNext()) return false; 732 this.currentIterator = this.entries.next().getValue().iterator(); 733 } 734 if (this.currentIterator.hasNext()) { 735 this.currentCell = this.currentIterator.next(); 736 return true; 737 } 738 this.currentCell = null; 739 this.currentIterator = null; 740 } 741 } 742 }; 743 } 744 745 /** 746 * @param left 747 * @param right 748 * @return True if the rows in <code>left</code> and <code>right</code> Cells match 749 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. Instead use 750 * {@link #matchingRows(Cell, Cell)} 751 */ 752 @Deprecated 753 public static boolean matchingRow(final Cell left, final Cell right) { 754 return matchingRows(left, right); 755 } 756 757 /** 758 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. Instead use 759 * {@link #matchingRows(Cell, byte[]))} 760 */ 761 @Deprecated 762 public static boolean matchingRow(final Cell left, final byte[] buf) { 763 return matchingRows(left, buf); 764 } 765 766 public static boolean matchingRows(final Cell left, final byte[] buf) { 767 if (buf == null) { 768 return left.getRowLength() == 0; 769 } 770 return PrivateCellUtil.matchingRows(left, buf, 0, buf.length); 771 } 772 773 /** 774 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. Instead use 775 * {@link #matchingRows(Cell, Cell)} 776 * @return true if the row is matching 777 */ 778 @Deprecated 779 public static boolean matchingRow(final Cell left, final byte[] buf, final int offset, 780 final int length) { 781 if (left instanceof ByteBufferExtendedCell) { 782 return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getRowByteBuffer(), 783 ((ByteBufferExtendedCell) left).getRowPosition(), left.getRowLength(), buf, offset, length); 784 } 785 return Bytes.equals(left.getRowArray(), left.getRowOffset(), left.getRowLength(), buf, offset, 786 length); 787 } 788 789 public static boolean matchingFamily(final Cell left, final Cell right) { 790 byte lfamlength = left.getFamilyLength(); 791 byte rfamlength = right.getFamilyLength(); 792 if (left instanceof ByteBufferExtendedCell && right instanceof ByteBufferExtendedCell) { 793 return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getFamilyByteBuffer(), 794 ((ByteBufferExtendedCell) left).getFamilyPosition(), lfamlength, 795 ((ByteBufferExtendedCell) right).getFamilyByteBuffer(), 796 ((ByteBufferExtendedCell) right).getFamilyPosition(), rfamlength); 797 } 798 if (left instanceof ByteBufferExtendedCell) { 799 return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getFamilyByteBuffer(), 800 ((ByteBufferExtendedCell) left).getFamilyPosition(), lfamlength, right.getFamilyArray(), 801 right.getFamilyOffset(), rfamlength); 802 } 803 if (right instanceof ByteBufferExtendedCell) { 804 return ByteBufferUtils.equals(((ByteBufferExtendedCell) right).getFamilyByteBuffer(), 805 ((ByteBufferExtendedCell) right).getFamilyPosition(), rfamlength, left.getFamilyArray(), 806 left.getFamilyOffset(), lfamlength); 807 } 808 return Bytes.equals(left.getFamilyArray(), left.getFamilyOffset(), lfamlength, 809 right.getFamilyArray(), right.getFamilyOffset(), rfamlength); 810 } 811 812 public static boolean matchingFamily(final Cell left, final byte[] buf) { 813 if (buf == null) { 814 return left.getFamilyLength() == 0; 815 } 816 return PrivateCellUtil.matchingFamily(left, buf, 0, buf.length); 817 } 818 819 /** 820 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. 821 */ 822 @Deprecated 823 public static boolean matchingFamily(final Cell left, final byte[] buf, final int offset, 824 final int length) { 825 if (left instanceof ByteBufferExtendedCell) { 826 return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getFamilyByteBuffer(), 827 ((ByteBufferExtendedCell) left).getFamilyPosition(), left.getFamilyLength(), buf, offset, 828 length); 829 } 830 return Bytes 831 .equals(left.getFamilyArray(), left.getFamilyOffset(), left.getFamilyLength(), buf, offset, 832 length); 833 } 834 835 public static boolean matchingQualifier(final Cell left, final Cell right) { 836 int lqlength = left.getQualifierLength(); 837 int rqlength = right.getQualifierLength(); 838 if (left instanceof ByteBufferExtendedCell && right instanceof ByteBufferExtendedCell) { 839 return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getQualifierByteBuffer(), 840 ((ByteBufferExtendedCell) left).getQualifierPosition(), lqlength, 841 ((ByteBufferExtendedCell) right).getQualifierByteBuffer(), 842 ((ByteBufferExtendedCell) right).getQualifierPosition(), rqlength); 843 } 844 if (left instanceof ByteBufferExtendedCell) { 845 return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getQualifierByteBuffer(), 846 ((ByteBufferExtendedCell) left).getQualifierPosition(), lqlength, right.getQualifierArray(), 847 right.getQualifierOffset(), rqlength); 848 } 849 if (right instanceof ByteBufferExtendedCell) { 850 return ByteBufferUtils.equals(((ByteBufferExtendedCell) right).getQualifierByteBuffer(), 851 ((ByteBufferExtendedCell) right).getQualifierPosition(), rqlength, left.getQualifierArray(), 852 left.getQualifierOffset(), lqlength); 853 } 854 return Bytes.equals(left.getQualifierArray(), left.getQualifierOffset(), lqlength, 855 right.getQualifierArray(), right.getQualifierOffset(), rqlength); 856 } 857 858 /** 859 * Finds if the qualifier part of the cell and the KV serialized byte[] are equal 860 * @param left 861 * @param buf the serialized keyvalue format byte[] 862 * @return true if the qualifier matches, false otherwise 863 */ 864 public static boolean matchingQualifier(final Cell left, final byte[] buf) { 865 if (buf == null) { 866 return left.getQualifierLength() == 0; 867 } 868 return PrivateCellUtil.matchingQualifier(left, buf, 0, buf.length); 869 } 870 871 /** 872 * Finds if the qualifier part of the cell and the KV serialized byte[] are equal 873 * @param left 874 * @param buf the serialized keyvalue format byte[] 875 * @param offset the offset of the qualifier in the byte[] 876 * @param length the length of the qualifier in the byte[] 877 * @return true if the qualifier matches, false otherwise 878 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. 879 */ 880 @Deprecated 881 public static boolean matchingQualifier(final Cell left, final byte[] buf, final int offset, 882 final int length) { 883 if (buf == null) { 884 return left.getQualifierLength() == 0; 885 } 886 if (left instanceof ByteBufferExtendedCell) { 887 return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getQualifierByteBuffer(), 888 ((ByteBufferExtendedCell) left).getQualifierPosition(), left.getQualifierLength(), buf, 889 offset, length); 890 } 891 return Bytes 892 .equals(left.getQualifierArray(), left.getQualifierOffset(), left.getQualifierLength(), buf, 893 offset, length); 894 } 895 896 public static boolean matchingColumn(final Cell left, final byte[] fam, final byte[] qual) { 897 if (!matchingFamily(left, fam)) return false; 898 return matchingQualifier(left, qual); 899 } 900 901 /** 902 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. 903 */ 904 @Deprecated 905 public static boolean matchingColumn(final Cell left, final byte[] fam, final int foffset, 906 final int flength, final byte[] qual, final int qoffset, final int qlength) { 907 if (!PrivateCellUtil.matchingFamily(left, fam, foffset, flength)) return false; 908 return PrivateCellUtil.matchingQualifier(left, qual, qoffset, qlength); 909 } 910 911 public static boolean matchingColumn(final Cell left, final Cell right) { 912 if (!matchingFamily(left, right)) return false; 913 return matchingQualifier(left, right); 914 } 915 916 public static boolean matchingValue(final Cell left, final Cell right) { 917 return PrivateCellUtil.matchingValue(left, right, left.getValueLength(), 918 right.getValueLength()); 919 } 920 921 public static boolean matchingValue(final Cell left, final byte[] buf) { 922 if (left instanceof ByteBufferExtendedCell) { 923 return ByteBufferUtils.compareTo(((ByteBufferExtendedCell) left).getValueByteBuffer(), 924 ((ByteBufferExtendedCell) left).getValuePosition(), left.getValueLength(), buf, 0, 925 buf.length) == 0; 926 } 927 return Bytes.equals(left.getValueArray(), left.getValueOffset(), left.getValueLength(), buf, 0, 928 buf.length); 929 } 930 931 /** 932 * @return True if a delete type, a {@link KeyValue.Type#Delete} or a {KeyValue.Type#DeleteFamily} 933 * or a {@link KeyValue.Type#DeleteColumn} KeyValue type. 934 */ 935 @SuppressWarnings("deprecation") 936 public static boolean isDelete(final Cell cell) { 937 return PrivateCellUtil.isDelete(cell.getTypeByte()); 938 } 939 940 /** 941 * @return True if a delete type, a {@link KeyValue.Type#Delete} or a {KeyValue.Type#DeleteFamily} 942 * or a {@link KeyValue.Type#DeleteColumn} KeyValue type. 943 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. 944 */ 945 @Deprecated 946 public static boolean isDelete(final byte type) { 947 return Type.Delete.getCode() <= type && type <= Type.DeleteFamily.getCode(); 948 } 949 950 /** 951 * @return True if this cell is a {@link KeyValue.Type#Delete} type. 952 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. 953 */ 954 @Deprecated 955 public static boolean isDeleteType(Cell cell) { 956 return cell.getTypeByte() == Type.Delete.getCode(); 957 } 958 959 /** 960 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. 961 */ 962 @Deprecated 963 public static boolean isDeleteFamily(final Cell cell) { 964 return cell.getTypeByte() == Type.DeleteFamily.getCode(); 965 } 966 967 /** 968 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. 969 */ 970 @Deprecated 971 public static boolean isDeleteFamilyVersion(final Cell cell) { 972 return cell.getTypeByte() == Type.DeleteFamilyVersion.getCode(); 973 } 974 975 /** 976 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. 977 */ 978 @Deprecated 979 public static boolean isDeleteColumns(final Cell cell) { 980 return cell.getTypeByte() == Type.DeleteColumn.getCode(); 981 } 982 983 /** 984 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. 985 */ 986 @Deprecated 987 public static boolean isDeleteColumnVersion(final Cell cell) { 988 return cell.getTypeByte() == Type.Delete.getCode(); 989 } 990 991 /** 992 * @return True if this cell is a delete family or column type. 993 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. 994 */ 995 @Deprecated 996 public static boolean isDeleteColumnOrFamily(Cell cell) { 997 int t = cell.getTypeByte(); 998 return t == Type.DeleteColumn.getCode() || t == Type.DeleteFamily.getCode(); 999 } 1000 1001 /** 1002 * @return True if this cell is a Put. 1003 */ 1004 @SuppressWarnings("deprecation") 1005 public static boolean isPut(Cell cell) { 1006 return cell.getTypeByte() == Type.Put.getCode(); 1007 } 1008 1009 /** 1010 * Estimate based on keyvalue's serialization format in the RPC layer. Note that there is an extra 1011 * SIZEOF_INT added to the size here that indicates the actual length of the cell for cases where 1012 * cell's are serialized in a contiguous format (For eg in RPCs). 1013 * @param cell 1014 * @return Estimate of the <code>cell</code> size in bytes plus an extra SIZEOF_INT indicating the 1015 * actual cell length. 1016 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. 1017 */ 1018 @Deprecated 1019 public static int estimatedSerializedSizeOf(final Cell cell) { 1020 if (cell instanceof ExtendedCell) { 1021 return ((ExtendedCell) cell).getSerializedSize(true) + Bytes.SIZEOF_INT; 1022 } 1023 1024 return getSumOfCellElementLengths(cell) + 1025 // Use the KeyValue's infrastructure size presuming that another implementation would have 1026 // same basic cost. 1027 KeyValue.ROW_LENGTH_SIZE + KeyValue.FAMILY_LENGTH_SIZE + 1028 // Serialization is probably preceded by a length (it is in the KeyValueCodec at least). 1029 Bytes.SIZEOF_INT; 1030 } 1031 1032 /** 1033 * @param cell 1034 * @return Sum of the lengths of all the elements in a Cell; does not count in any infrastructure 1035 */ 1036 private static int getSumOfCellElementLengths(final Cell cell) { 1037 return getSumOfCellKeyElementLengths(cell) + cell.getValueLength() + cell.getTagsLength(); 1038 } 1039 1040 /** 1041 * @param cell 1042 * @return Sum of all elements that make up a key; does not include infrastructure, tags or 1043 * values. 1044 */ 1045 private static int getSumOfCellKeyElementLengths(final Cell cell) { 1046 return cell.getRowLength() + cell.getFamilyLength() + cell.getQualifierLength() 1047 + KeyValue.TIMESTAMP_TYPE_SIZE; 1048 } 1049 1050 /** 1051 * Calculates the serialized key size. We always serialize in the KeyValue's serialization format. 1052 * @param cell the cell for which the key size has to be calculated. 1053 * @return the key size 1054 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. 1055 */ 1056 @Deprecated 1057 public static int estimatedSerializedSizeOfKey(final Cell cell) { 1058 if (cell instanceof KeyValue) return ((KeyValue) cell).getKeyLength(); 1059 return cell.getRowLength() + cell.getFamilyLength() + cell.getQualifierLength() 1060 + KeyValue.KEY_INFRASTRUCTURE_SIZE; 1061 } 1062 1063 /** 1064 * This is an estimate of the heap space occupied by a cell. When the cell is of type 1065 * {@link HeapSize} we call {@link HeapSize#heapSize()} so cell can give a correct value. In other 1066 * cases we just consider the bytes occupied by the cell components ie. row, CF, qualifier, 1067 * timestamp, type, value and tags. 1068 * @param cell 1069 * @return estimate of the heap space 1070 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. 1071 * Use {@link RawCell#getTags()} 1072 */ 1073 @Deprecated 1074 public static long estimatedHeapSizeOf(final Cell cell) { 1075 return cell.heapSize(); 1076 } 1077 1078 /********************* tags *************************************/ 1079 /** 1080 * Util method to iterate through the tags 1081 * @param tags 1082 * @param offset 1083 * @param length 1084 * @return iterator for the tags 1085 * @deprecated As of 2.0.0 and will be removed in 3.0.0 Instead use 1086 * {@link PrivateCellUtil#tagsIterator(Cell)} 1087 */ 1088 @Deprecated 1089 public static Iterator<Tag> tagsIterator(final byte[] tags, final int offset, final int length) { 1090 return new Iterator<Tag>() { 1091 private int pos = offset; 1092 private int endOffset = offset + length - 1; 1093 1094 @Override 1095 public boolean hasNext() { 1096 return this.pos < endOffset; 1097 } 1098 1099 @Override 1100 public Tag next() { 1101 if (hasNext()) { 1102 int curTagLen = Bytes.readAsInt(tags, this.pos, Tag.TAG_LENGTH_SIZE); 1103 Tag tag = new ArrayBackedTag(tags, pos, curTagLen + TAG_LENGTH_SIZE); 1104 this.pos += Bytes.SIZEOF_SHORT + curTagLen; 1105 return tag; 1106 } 1107 return null; 1108 } 1109 1110 @Override 1111 public void remove() { 1112 throw new UnsupportedOperationException(); 1113 } 1114 }; 1115 } 1116 1117 /** 1118 * @param cell The Cell 1119 * @return Tags in the given Cell as a List 1120 * @deprecated As of 2.0.0 and will be removed in 3.0.0 1121 */ 1122 @Deprecated 1123 public static List<Tag> getTags(Cell cell) { 1124 List<Tag> tags = new ArrayList<>(); 1125 Iterator<Tag> tagsItr = PrivateCellUtil.tagsIterator(cell); 1126 while (tagsItr.hasNext()) { 1127 tags.add(tagsItr.next()); 1128 } 1129 return tags; 1130 } 1131 1132 /** 1133 * Retrieve Cell's first tag, matching the passed in type 1134 * @param cell The Cell 1135 * @param type Type of the Tag to retrieve 1136 * @return null if there is no tag of the passed in tag type 1137 * @deprecated As of 2.0.0 and will be removed in HBase-3.0.0 1138 * Use {@link RawCell#getTag(byte)} 1139 */ 1140 @Deprecated 1141 public static Tag getTag(Cell cell, byte type) { 1142 Optional<Tag> tag = PrivateCellUtil.getTag(cell, type); 1143 if (tag.isPresent()) { 1144 return tag.get(); 1145 } else { 1146 return null; 1147 } 1148 } 1149 1150 /** 1151 * Returns true if the first range start1...end1 overlaps with the second range start2...end2, 1152 * assuming the byte arrays represent row keys 1153 * @deprecated As of 2.0.0 and will be removed in 3.0.0 1154 */ 1155 @Deprecated 1156 public static boolean overlappingKeys(final byte[] start1, final byte[] end1, final byte[] start2, 1157 final byte[] end2) { 1158 return (end2.length == 0 || start1.length == 0 || Bytes.compareTo(start1, end2) < 0) 1159 && (end1.length == 0 || start2.length == 0 || Bytes.compareTo(start2, end1) < 0); 1160 } 1161 1162 /** 1163 * Sets the given seqId to the cell. Marked as audience Private as of 1.2.0. Setting a Cell 1164 * sequenceid is an internal implementation detail not for general public use. 1165 * @param cell 1166 * @param seqId 1167 * @throws IOException when the passed cell is not of type {@link ExtendedCell} 1168 * @deprecated As of HBase-2.0. Will be removed in HBase-3.0 1169 */ 1170 @Deprecated 1171 public static void setSequenceId(Cell cell, long seqId) throws IOException { 1172 PrivateCellUtil.setSequenceId(cell, seqId); 1173 } 1174 1175 /** 1176 * Sets the given timestamp to the cell. 1177 * @param cell 1178 * @param ts 1179 * @throws IOException when the passed cell is not of type {@link ExtendedCell} 1180 * @deprecated As of HBase-2.0. Will be a LimitedPrivate API in HBase-3.0. 1181 */ 1182 @Deprecated 1183 public static void setTimestamp(Cell cell, long ts) throws IOException { 1184 PrivateCellUtil.setTimestamp(cell, ts); 1185 } 1186 1187 /** 1188 * Sets the given timestamp to the cell. 1189 * @param cell 1190 * @param ts buffer containing the timestamp value 1191 * @param tsOffset offset to the new timestamp 1192 * @throws IOException when the passed cell is not of type {@link ExtendedCell} 1193 * @deprecated As of HBase-2.0. Will be a LimitedPrivate API in HBase-3.0. 1194 */ 1195 @Deprecated 1196 public static void setTimestamp(Cell cell, byte[] ts, int tsOffset) throws IOException { 1197 PrivateCellUtil.setTimestamp(cell, Bytes.toLong(ts, tsOffset)); 1198 } 1199 1200 /** 1201 * Sets the given timestamp to the cell iff current timestamp is 1202 * {@link HConstants#LATEST_TIMESTAMP}. 1203 * @param cell 1204 * @param ts 1205 * @return True if cell timestamp is modified. 1206 * @throws IOException when the passed cell is not of type {@link ExtendedCell} 1207 * @deprecated As of HBase-2.0. Will be removed in HBase-3.0 1208 */ 1209 @Deprecated 1210 public static boolean updateLatestStamp(Cell cell, long ts) throws IOException { 1211 return PrivateCellUtil.updateLatestStamp(cell, ts); 1212 } 1213 1214 /** 1215 * Sets the given timestamp to the cell iff current timestamp is 1216 * {@link HConstants#LATEST_TIMESTAMP}. 1217 * @param cell 1218 * @param ts buffer containing the timestamp value 1219 * @param tsOffset offset to the new timestamp 1220 * @return True if cell timestamp is modified. 1221 * @throws IOException when the passed cell is not of type {@link ExtendedCell} 1222 * @deprecated As of HBase-2.0. Will be removed in HBase-3.0 1223 */ 1224 @Deprecated 1225 public static boolean updateLatestStamp(Cell cell, byte[] ts, int tsOffset) throws IOException { 1226 return PrivateCellUtil.updateLatestStamp(cell, Bytes.toLong(ts, tsOffset)); 1227 } 1228 1229 /** 1230 * Writes the Cell's key part as it would have serialized in a KeyValue. The format is <2 bytes 1231 * rk len><rk><1 byte cf len><cf><qualifier><8 bytes 1232 * timestamp><1 byte type> 1233 * @param cell 1234 * @param out 1235 * @deprecated As of HBase-2.0. Will be removed in HBase-3.0 1236 * @throws IOException 1237 */ 1238 @Deprecated 1239 public static void writeFlatKey(Cell cell, DataOutputStream out) throws IOException { 1240 short rowLen = cell.getRowLength(); 1241 byte fLen = cell.getFamilyLength(); 1242 int qLen = cell.getQualifierLength(); 1243 // Using just one if/else loop instead of every time checking before writing every 1244 // component of cell 1245 if (cell instanceof ByteBufferExtendedCell) { 1246 out.writeShort(rowLen); 1247 ByteBufferUtils 1248 .copyBufferToStream((DataOutput) out, ((ByteBufferExtendedCell) cell).getRowByteBuffer(), 1249 ((ByteBufferExtendedCell) cell).getRowPosition(), rowLen); 1250 out.writeByte(fLen); 1251 ByteBufferUtils 1252 .copyBufferToStream((DataOutput) out, ((ByteBufferExtendedCell) cell).getFamilyByteBuffer(), 1253 ((ByteBufferExtendedCell) cell).getFamilyPosition(), fLen); 1254 ByteBufferUtils.copyBufferToStream((DataOutput) out, 1255 ((ByteBufferExtendedCell) cell).getQualifierByteBuffer(), 1256 ((ByteBufferExtendedCell) cell).getQualifierPosition(), qLen); 1257 } else { 1258 out.writeShort(rowLen); 1259 out.write(cell.getRowArray(), cell.getRowOffset(), rowLen); 1260 out.writeByte(fLen); 1261 out.write(cell.getFamilyArray(), cell.getFamilyOffset(), fLen); 1262 out.write(cell.getQualifierArray(), cell.getQualifierOffset(), qLen); 1263 } 1264 out.writeLong(cell.getTimestamp()); 1265 out.writeByte(cell.getTypeByte()); 1266 } 1267 1268 /** 1269 * Writes the row from the given cell to the output stream excluding the common prefix 1270 * @param out The dataoutputstream to which the data has to be written 1271 * @param cell The cell whose contents has to be written 1272 * @param rlength the row length 1273 * @throws IOException 1274 * @deprecated As of 2.0. Will be removed in hbase-3.0 1275 */ 1276 @Deprecated 1277 public static void writeRowSkippingBytes(DataOutputStream out, Cell cell, short rlength, 1278 int commonPrefix) throws IOException { 1279 if (cell instanceof ByteBufferExtendedCell) { 1280 ByteBufferUtils 1281 .copyBufferToStream((DataOutput) out, ((ByteBufferExtendedCell) cell).getRowByteBuffer(), 1282 ((ByteBufferExtendedCell) cell).getRowPosition() + commonPrefix, rlength - commonPrefix); 1283 } else { 1284 out.write(cell.getRowArray(), cell.getRowOffset() + commonPrefix, rlength - commonPrefix); 1285 } 1286 } 1287 1288 /** 1289 * @param cell 1290 * @return The Key portion of the passed <code>cell</code> as a String. 1291 */ 1292 public static String getCellKeyAsString(Cell cell) { 1293 StringBuilder sb = new StringBuilder( 1294 Bytes.toStringBinary(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())); 1295 sb.append('/'); 1296 sb.append(cell.getFamilyLength() == 0 ? "" 1297 : Bytes.toStringBinary(cell.getFamilyArray(), cell.getFamilyOffset(), 1298 cell.getFamilyLength())); 1299 // KeyValue only added ':' if family is non-null. Do same. 1300 if (cell.getFamilyLength() > 0) sb.append(':'); 1301 sb.append(cell.getQualifierLength() == 0 ? "" 1302 : Bytes.toStringBinary(cell.getQualifierArray(), cell.getQualifierOffset(), 1303 cell.getQualifierLength())); 1304 sb.append('/'); 1305 sb.append(KeyValue.humanReadableTimestamp(cell.getTimestamp())); 1306 sb.append('/'); 1307 sb.append(Type.codeToType(cell.getTypeByte())); 1308 if (!(cell instanceof KeyValue.KeyOnlyKeyValue)) { 1309 sb.append("/vlen="); 1310 sb.append(cell.getValueLength()); 1311 } 1312 sb.append("/seqid="); 1313 sb.append(cell.getSequenceId()); 1314 return sb.toString(); 1315 } 1316 1317 /** 1318 * This method exists just to encapsulate how we serialize keys. To be replaced by a factory that 1319 * we query to figure what the Cell implementation is and then, what serialization engine to use 1320 * and further, how to serialize the key for inclusion in hfile index. TODO. 1321 * @param cell 1322 * @return The key portion of the Cell serialized in the old-school KeyValue way or null if passed 1323 * a null <code>cell</code> 1324 * @deprecated As of HBase-2.0. Will be removed in HBase-3.0 1325 */ 1326 @Deprecated 1327 public static byte[] getCellKeySerializedAsKeyValueKey(final Cell cell) { 1328 if (cell == null) return null; 1329 byte[] b = new byte[KeyValueUtil.keyLength(cell)]; 1330 KeyValueUtil.appendKeyTo(cell, b, 0); 1331 return b; 1332 } 1333 1334 /** 1335 * Write rowkey excluding the common part. 1336 * @param cell 1337 * @param rLen 1338 * @param commonPrefix 1339 * @param out 1340 * @throws IOException 1341 * @deprecated As of HBase-2.0. Will be removed in HBase-3.0 1342 */ 1343 @Deprecated 1344 public static void writeRowKeyExcludingCommon(Cell cell, short rLen, int commonPrefix, 1345 DataOutputStream out) throws IOException { 1346 if (commonPrefix == 0) { 1347 out.writeShort(rLen); 1348 } else if (commonPrefix == 1) { 1349 out.writeByte((byte) rLen); 1350 commonPrefix--; 1351 } else { 1352 commonPrefix -= KeyValue.ROW_LENGTH_SIZE; 1353 } 1354 if (rLen > commonPrefix) { 1355 PrivateCellUtil.writeRowSkippingBytes(out, cell, rLen, commonPrefix); 1356 } 1357 } 1358 1359 /** 1360 * Find length of common prefix in keys of the cells, considering key as byte[] if serialized in 1361 * {@link KeyValue}. The key format is <2 bytes rk len><rk><1 byte cf 1362 * len><cf><qualifier><8 bytes timestamp><1 byte type> 1363 * @param c1 the cell 1364 * @param c2 the cell 1365 * @param bypassFamilyCheck when true assume the family bytes same in both cells. Pass it as true 1366 * when dealing with Cells in same CF so as to avoid some checks 1367 * @param withTsType when true check timestamp and type bytes also. 1368 * @return length of common prefix 1369 * @deprecated As of HBase-2.0. Will be removed in HBase-3.0 1370 */ 1371 @Deprecated 1372 public static int findCommonPrefixInFlatKey(Cell c1, Cell c2, boolean bypassFamilyCheck, 1373 boolean withTsType) { 1374 // Compare the 2 bytes in RK length part 1375 short rLen1 = c1.getRowLength(); 1376 short rLen2 = c2.getRowLength(); 1377 int commonPrefix = KeyValue.ROW_LENGTH_SIZE; 1378 if (rLen1 != rLen2) { 1379 // early out when the RK length itself is not matching 1380 return ByteBufferUtils 1381 .findCommonPrefix(Bytes.toBytes(rLen1), 0, KeyValue.ROW_LENGTH_SIZE, Bytes.toBytes(rLen2), 1382 0, KeyValue.ROW_LENGTH_SIZE); 1383 } 1384 // Compare the RKs 1385 int rkCommonPrefix = 0; 1386 if (c1 instanceof ByteBufferExtendedCell && c2 instanceof ByteBufferExtendedCell) { 1387 rkCommonPrefix = ByteBufferUtils 1388 .findCommonPrefix(((ByteBufferExtendedCell) c1).getRowByteBuffer(), 1389 ((ByteBufferExtendedCell) c1).getRowPosition(), rLen1, 1390 ((ByteBufferExtendedCell) c2).getRowByteBuffer(), 1391 ((ByteBufferExtendedCell) c2).getRowPosition(), rLen2); 1392 } else { 1393 // There cannot be a case where one cell is BBCell and other is KeyValue. This flow comes 1394 // either 1395 // in flush or compactions. In flushes both cells are KV and in case of compaction it will be 1396 // either 1397 // KV or BBCell 1398 rkCommonPrefix = ByteBufferUtils 1399 .findCommonPrefix(c1.getRowArray(), c1.getRowOffset(), rLen1, c2.getRowArray(), 1400 c2.getRowOffset(), rLen2); 1401 } 1402 commonPrefix += rkCommonPrefix; 1403 if (rkCommonPrefix != rLen1) { 1404 // Early out when RK is not fully matching. 1405 return commonPrefix; 1406 } 1407 // Compare 1 byte CF length part 1408 byte fLen1 = c1.getFamilyLength(); 1409 if (bypassFamilyCheck) { 1410 // This flag will be true when caller is sure that the family will be same for both the cells 1411 // Just make commonPrefix to increment by the family part 1412 commonPrefix += KeyValue.FAMILY_LENGTH_SIZE + fLen1; 1413 } else { 1414 byte fLen2 = c2.getFamilyLength(); 1415 if (fLen1 != fLen2) { 1416 // early out when the CF length itself is not matching 1417 return commonPrefix; 1418 } 1419 // CF lengths are same so there is one more byte common in key part 1420 commonPrefix += KeyValue.FAMILY_LENGTH_SIZE; 1421 // Compare the CF names 1422 int fCommonPrefix; 1423 if (c1 instanceof ByteBufferExtendedCell && c2 instanceof ByteBufferExtendedCell) { 1424 fCommonPrefix = ByteBufferUtils 1425 .findCommonPrefix(((ByteBufferExtendedCell) c1).getFamilyByteBuffer(), 1426 ((ByteBufferExtendedCell) c1).getFamilyPosition(), fLen1, 1427 ((ByteBufferExtendedCell) c2).getFamilyByteBuffer(), 1428 ((ByteBufferExtendedCell) c2).getFamilyPosition(), fLen2); 1429 } else { 1430 fCommonPrefix = ByteBufferUtils 1431 .findCommonPrefix(c1.getFamilyArray(), c1.getFamilyOffset(), fLen1, c2.getFamilyArray(), 1432 c2.getFamilyOffset(), fLen2); 1433 } 1434 commonPrefix += fCommonPrefix; 1435 if (fCommonPrefix != fLen1) { 1436 return commonPrefix; 1437 } 1438 } 1439 // Compare the Qualifiers 1440 int qLen1 = c1.getQualifierLength(); 1441 int qLen2 = c2.getQualifierLength(); 1442 int qCommon; 1443 if (c1 instanceof ByteBufferExtendedCell && c2 instanceof ByteBufferExtendedCell) { 1444 qCommon = ByteBufferUtils 1445 .findCommonPrefix(((ByteBufferExtendedCell) c1).getQualifierByteBuffer(), 1446 ((ByteBufferExtendedCell) c1).getQualifierPosition(), qLen1, 1447 ((ByteBufferExtendedCell) c2).getQualifierByteBuffer(), 1448 ((ByteBufferExtendedCell) c2).getQualifierPosition(), qLen2); 1449 } else { 1450 qCommon = ByteBufferUtils 1451 .findCommonPrefix(c1.getQualifierArray(), c1.getQualifierOffset(), qLen1, 1452 c2.getQualifierArray(), c2.getQualifierOffset(), qLen2); 1453 } 1454 commonPrefix += qCommon; 1455 if (!withTsType || Math.max(qLen1, qLen2) != qCommon) { 1456 return commonPrefix; 1457 } 1458 // Compare the timestamp parts 1459 int tsCommonPrefix = ByteBufferUtils 1460 .findCommonPrefix(Bytes.toBytes(c1.getTimestamp()), 0, KeyValue.TIMESTAMP_SIZE, 1461 Bytes.toBytes(c2.getTimestamp()), 0, KeyValue.TIMESTAMP_SIZE); 1462 commonPrefix += tsCommonPrefix; 1463 if (tsCommonPrefix != KeyValue.TIMESTAMP_SIZE) { 1464 return commonPrefix; 1465 } 1466 // Compare the type 1467 if (c1.getTypeByte() == c2.getTypeByte()) { 1468 commonPrefix += KeyValue.TYPE_SIZE; 1469 } 1470 return commonPrefix; 1471 } 1472 1473 /** Returns a string representation of the cell */ 1474 public static String toString(Cell cell, boolean verbose) { 1475 if (cell == null) { 1476 return ""; 1477 } 1478 StringBuilder builder = new StringBuilder(); 1479 String keyStr = getCellKeyAsString(cell); 1480 1481 String tag = null; 1482 String value = null; 1483 if (verbose) { 1484 // TODO: pretty print tags as well 1485 if (cell.getTagsLength() > 0) { 1486 tag = Bytes.toStringBinary(cell.getTagsArray(), cell.getTagsOffset(), cell.getTagsLength()); 1487 } 1488 if (!(cell instanceof KeyValue.KeyOnlyKeyValue)) { 1489 value = Bytes.toStringBinary(cell.getValueArray(), cell.getValueOffset(), 1490 cell.getValueLength()); 1491 } 1492 } 1493 1494 builder.append(keyStr); 1495 if (tag != null && !tag.isEmpty()) { 1496 builder.append("/").append(tag); 1497 } 1498 if (value != null) { 1499 builder.append("/").append(value); 1500 } 1501 1502 return builder.toString(); 1503 } 1504 1505 /***************** special cases ****************************/ 1506 1507 /** 1508 * special case for Cell.equals 1509 * @deprecated As of HBase-2.0. Will be removed in HBase-3.0 1510 */ 1511 @Deprecated 1512 public static boolean equalsIgnoreMvccVersion(Cell a, Cell b) { 1513 // row 1514 boolean res = matchingRows(a, b); 1515 if (!res) return res; 1516 1517 // family 1518 res = matchingColumn(a, b); 1519 if (!res) return res; 1520 1521 // timestamp: later sorts first 1522 if (!matchingTimestamp(a, b)) return false; 1523 1524 // type 1525 int c = (0xff & b.getTypeByte()) - (0xff & a.getTypeByte()); 1526 if (c != 0) return false; 1527 else return true; 1528 } 1529 1530 /**************** equals ****************************/ 1531 1532 public static boolean equals(Cell a, Cell b) { 1533 return matchingRows(a, b) && matchingFamily(a, b) && matchingQualifier(a, b) 1534 && matchingTimestamp(a, b) && PrivateCellUtil.matchingType(a, b); 1535 } 1536 1537 public static boolean matchingTimestamp(Cell a, Cell b) { 1538 return CellComparator.getInstance().compareTimestamps(a.getTimestamp(), b.getTimestamp()) == 0; 1539 } 1540 1541 /** 1542 * @deprecated As of HBase-2.0. Will be removed in HBase-3.0 1543 */ 1544 @Deprecated 1545 public static boolean matchingType(Cell a, Cell b) { 1546 return a.getTypeByte() == b.getTypeByte(); 1547 } 1548 1549 /** 1550 * Compares the row of two keyvalues for equality 1551 * @param left 1552 * @param right 1553 * @return True if rows match. 1554 */ 1555 public static boolean matchingRows(final Cell left, final Cell right) { 1556 short lrowlength = left.getRowLength(); 1557 short rrowlength = right.getRowLength(); 1558 if (lrowlength != rrowlength) return false; 1559 if (left instanceof ByteBufferExtendedCell && right instanceof ByteBufferExtendedCell) { 1560 return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getRowByteBuffer(), 1561 ((ByteBufferExtendedCell) left).getRowPosition(), lrowlength, 1562 ((ByteBufferExtendedCell) right).getRowByteBuffer(), 1563 ((ByteBufferExtendedCell) right).getRowPosition(), rrowlength); 1564 } 1565 if (left instanceof ByteBufferExtendedCell) { 1566 return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getRowByteBuffer(), 1567 ((ByteBufferExtendedCell) left).getRowPosition(), lrowlength, right.getRowArray(), 1568 right.getRowOffset(), rrowlength); 1569 } 1570 if (right instanceof ByteBufferExtendedCell) { 1571 return ByteBufferUtils.equals(((ByteBufferExtendedCell) right).getRowByteBuffer(), 1572 ((ByteBufferExtendedCell) right).getRowPosition(), rrowlength, left.getRowArray(), 1573 left.getRowOffset(), lrowlength); 1574 } 1575 return Bytes.equals(left.getRowArray(), left.getRowOffset(), lrowlength, right.getRowArray(), 1576 right.getRowOffset(), rrowlength); 1577 } 1578 1579 /** 1580 * Compares the row and column of two keyvalues for equality 1581 * @param left 1582 * @param right 1583 * @return True if same row and column. 1584 */ 1585 public static boolean matchingRowColumn(final Cell left, final Cell right) { 1586 if ((left.getRowLength() + left.getFamilyLength() 1587 + left.getQualifierLength()) != (right.getRowLength() + right.getFamilyLength() 1588 + right.getQualifierLength())) { 1589 return false; 1590 } 1591 1592 if (!matchingRows(left, right)) { 1593 return false; 1594 } 1595 return matchingColumn(left, right); 1596 } 1597 1598 public static boolean matchingRowColumnBytes(final Cell left, final Cell right) { 1599 int lrowlength = left.getRowLength(); 1600 int rrowlength = right.getRowLength(); 1601 int lfamlength = left.getFamilyLength(); 1602 int rfamlength = right.getFamilyLength(); 1603 int lqlength = left.getQualifierLength(); 1604 int rqlength = right.getQualifierLength(); 1605 // match length 1606 if ((lrowlength + lfamlength + lqlength) != 1607 (rrowlength + rfamlength + rqlength)) { 1608 return false; 1609 } 1610 1611 // match row 1612 if (!Bytes.equals(left.getRowArray(), left.getRowOffset(), lrowlength, right.getRowArray(), 1613 right.getRowOffset(), rrowlength)) { 1614 return false; 1615 } 1616 //match family 1617 if (!Bytes.equals(left.getFamilyArray(), left.getFamilyOffset(), lfamlength, 1618 right.getFamilyArray(), right.getFamilyOffset(), rfamlength)) { 1619 return false; 1620 } 1621 //match qualifier 1622 return Bytes.equals(left.getQualifierArray(), left.getQualifierOffset(), 1623 lqlength, right.getQualifierArray(), right.getQualifierOffset(), 1624 rqlength); 1625 } 1626 1627 /** 1628 * Compares the cell's qualifier with the given byte[] 1629 * @param left the cell for which the qualifier has to be compared 1630 * @param right the byte[] having the qualifier 1631 * @param rOffset the offset of the qualifier 1632 * @param rLength the length of the qualifier 1633 * @return greater than 0 if left cell's qualifier is bigger than byte[], lesser than 0 if left 1634 * cell's qualifier is lesser than byte[] and 0 otherwise 1635 */ 1636 public final static int compareQualifiers(Cell left, byte[] right, int rOffset, int rLength) { 1637 if (left instanceof ByteBufferExtendedCell) { 1638 return ByteBufferUtils.compareTo(((ByteBufferExtendedCell) left).getQualifierByteBuffer(), 1639 ((ByteBufferExtendedCell) left).getQualifierPosition(), 1640 left.getQualifierLength(), right, rOffset, rLength); 1641 } 1642 return Bytes.compareTo(left.getQualifierArray(), left.getQualifierOffset(), 1643 left.getQualifierLength(), right, rOffset, rLength); 1644 } 1645 1646 /** 1647 * Used when a cell needs to be compared with a key byte[] such as cases of finding the index from 1648 * the index block, bloom keys from the bloom blocks This byte[] is expected to be serialized in 1649 * the KeyValue serialization format If the KeyValue (Cell's) serialization format changes this 1650 * method cannot be used. 1651 * @param comparator the cell comparator 1652 * @param left the cell to be compared 1653 * @param key the serialized key part of a KeyValue 1654 * @param offset the offset in the key byte[] 1655 * @param length the length of the key byte[] 1656 * @return an int greater than 0 if left is greater than right lesser than 0 if left is lesser 1657 * than right equal to 0 if left is equal to right 1658 * @deprecated As of HBase-2.0. Will be removed in HBase-3.0 1659 */ 1660 @VisibleForTesting 1661 @Deprecated 1662 public static final int compare(CellComparator comparator, Cell left, byte[] key, int offset, 1663 int length) { 1664 // row 1665 short rrowlength = Bytes.toShort(key, offset); 1666 int c = comparator.compareRows(left, key, offset + Bytes.SIZEOF_SHORT, rrowlength); 1667 if (c != 0) return c; 1668 1669 // Compare the rest of the two KVs without making any assumptions about 1670 // the common prefix. This function will not compare rows anyway, so we 1671 // don't need to tell it that the common prefix includes the row. 1672 return PrivateCellUtil.compareWithoutRow(comparator, left, key, offset, length, rrowlength); 1673 } 1674 1675 /** 1676 * Compares the cell's family with the given byte[] 1677 * @param left the cell for which the family has to be compared 1678 * @param right the byte[] having the family 1679 * @param roffset the offset of the family 1680 * @param rlength the length of the family 1681 * @return greater than 0 if left cell's family is bigger than byte[], lesser than 0 if left 1682 * cell's family is lesser than byte[] and 0 otherwise 1683 */ 1684 public final static int compareFamilies(Cell left, byte[] right, int roffset, int rlength) { 1685 if (left instanceof ByteBufferExtendedCell) { 1686 return ByteBufferUtils.compareTo(((ByteBufferExtendedCell) left).getFamilyByteBuffer(), 1687 ((ByteBufferExtendedCell) left).getFamilyPosition(), left.getFamilyLength(), right, roffset, 1688 rlength); 1689 } 1690 return Bytes.compareTo(left.getFamilyArray(), left.getFamilyOffset(), left.getFamilyLength(), 1691 right, roffset, rlength); 1692 } 1693 1694 /** 1695 * Compares the cell's column (family and qualifier) with the given byte[] 1696 * @param left the cell for which the column has to be compared 1697 * @param right the byte[] having the column 1698 * @param rfoffset the offset of the family 1699 * @param rflength the length of the family 1700 * @param rqoffset the offset of the qualifier 1701 * @param rqlength the length of the qualifier 1702 * @return greater than 0 if left cell's column is bigger than byte[], lesser than 0 if left 1703 * cell's column is lesser than byte[] and 0 otherwise 1704 */ 1705 public final static int compareColumns(Cell left, byte[] right, int rfoffset, int rflength, 1706 int rqoffset, int rqlength) { 1707 int diff = compareFamilies(left, right, rfoffset, rflength); 1708 if (diff != 0) return diff; 1709 return compareQualifiers(left, right, rqoffset, rqlength); 1710 } 1711}