HBASE-24163 MOB compactor implementations should use format specifiers when calling...
[hbase.git] / hbase-common / src / main / java / org / apache / hadoop / hbase / CellUtil.java
bloba51fa3de96efdac8a55ca35d964665ced106c56f
1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 package org.apache.hadoop.hbase;
21 import static org.apache.hadoop.hbase.KeyValue.COLUMN_FAMILY_DELIMITER;
22 import static org.apache.hadoop.hbase.KeyValue.COLUMN_FAMILY_DELIM_ARRAY;
23 import static org.apache.hadoop.hbase.KeyValue.getDelimiter;
25 import java.io.IOException;
26 import java.nio.ByteBuffer;
27 import java.util.Arrays;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Map.Entry;
31 import java.util.NavigableMap;
32 import java.util.function.Function;
33 import org.apache.hadoop.hbase.KeyValue.Type;
34 import org.apache.hadoop.hbase.util.ByteBufferUtils;
35 import org.apache.hadoop.hbase.util.Bytes;
36 import org.apache.yetus.audience.InterfaceAudience;
38 /**
39 * Utility methods helpful for slinging {@link Cell} instances. Some methods below are for internal
40 * use only and are marked InterfaceAudience.Private at the method level. Note that all such methods
41 * have been marked deprecated in HBase-2.0 which will be subsequently removed in HBase-3.0
43 @InterfaceAudience.Public
44 public final class CellUtil {
46 /**
47 * Private constructor to keep this class from being instantiated.
49 private CellUtil() {
52 /***************** get individual arrays for tests ************/
54 public static byte[] cloneRow(Cell cell) {
55 byte[] output = new byte[cell.getRowLength()];
56 copyRowTo(cell, output, 0);
57 return output;
60 public static byte[] cloneFamily(Cell cell) {
61 byte[] output = new byte[cell.getFamilyLength()];
62 copyFamilyTo(cell, output, 0);
63 return output;
66 public static byte[] cloneQualifier(Cell cell) {
67 byte[] output = new byte[cell.getQualifierLength()];
68 copyQualifierTo(cell, output, 0);
69 return output;
72 public static byte[] cloneValue(Cell cell) {
73 byte[] output = new byte[cell.getValueLength()];
74 copyValueTo(cell, output, 0);
75 return output;
78 /**
79 * Makes a column in family:qualifier form from separate byte arrays.
80 * <p>
81 * Not recommended for usage as this is old-style API.
82 * @param family
83 * @param qualifier
84 * @return family:qualifier
86 public static byte[] makeColumn(byte[] family, byte[] qualifier) {
87 return Bytes.add(family, COLUMN_FAMILY_DELIM_ARRAY, qualifier);
90 /**
91 * Splits a column in {@code family:qualifier} form into separate byte arrays. An empty qualifier
92 * (ie, {@code fam:}) is parsed as <code>{ fam, EMPTY_BYTE_ARRAY }</code> while no delimiter (ie,
93 * {@code fam}) is parsed as an array of one element, <code>{ fam }</code>.
94 * <p>
95 * Don't forget, HBase DOES support empty qualifiers. (see HBASE-9549)
96 * </p>
97 * <p>
98 * Not recommend to be used as this is old-style API.
99 * </p>
100 * @param c The column.
101 * @return The parsed column.
103 public static byte[][] parseColumn(byte[] c) {
104 final int index = getDelimiter(c, 0, c.length, COLUMN_FAMILY_DELIMITER);
105 if (index == -1) {
106 // If no delimiter, return array of size 1
107 return new byte[][] { c };
108 } else if (index == c.length - 1) {
109 // family with empty qualifier, return array size 2
110 byte[] family = new byte[c.length - 1];
111 System.arraycopy(c, 0, family, 0, family.length);
112 return new byte[][] { family, HConstants.EMPTY_BYTE_ARRAY };
114 // Family and column, return array size 2
115 final byte[][] result = new byte[2][];
116 result[0] = new byte[index];
117 System.arraycopy(c, 0, result[0], 0, index);
118 final int len = c.length - (index + 1);
119 result[1] = new byte[len];
120 System.arraycopy(c, index + 1 /* Skip delimiter */, result[1], 0, len);
121 return result;
124 /******************** copyTo **********************************/
127 * Copies the row to the given byte[]
128 * @param cell the cell whose row has to be copied
129 * @param destination the destination byte[] to which the row has to be copied
130 * @param destinationOffset the offset in the destination byte[]
131 * @return the offset of the byte[] after the copy has happened
133 public static int copyRowTo(Cell cell, byte[] destination, int destinationOffset) {
134 short rowLen = cell.getRowLength();
135 if (cell instanceof ByteBufferExtendedCell) {
136 ByteBufferUtils.copyFromBufferToArray(destination,
137 ((ByteBufferExtendedCell) cell).getRowByteBuffer(),
138 ((ByteBufferExtendedCell) cell).getRowPosition(), destinationOffset, rowLen);
139 } else {
140 System.arraycopy(cell.getRowArray(), cell.getRowOffset(), destination, destinationOffset,
141 rowLen);
143 return destinationOffset + rowLen;
147 * Copies the row to the given bytebuffer
148 * @param cell cell the cell whose row has to be copied
149 * @param destination the destination bytebuffer to which the row has to be copied
150 * @param destinationOffset the offset in the destination byte[]
151 * @return the offset of the bytebuffer after the copy has happened
153 public static int copyRowTo(Cell cell, ByteBuffer destination, int destinationOffset) {
154 short rowLen = cell.getRowLength();
155 if (cell instanceof ByteBufferExtendedCell) {
156 ByteBufferUtils.copyFromBufferToBuffer(((ByteBufferExtendedCell) cell).getRowByteBuffer(),
157 destination, ((ByteBufferExtendedCell) cell).getRowPosition(), destinationOffset, rowLen);
158 } else {
159 ByteBufferUtils.copyFromArrayToBuffer(destination, destinationOffset, cell.getRowArray(),
160 cell.getRowOffset(), rowLen);
162 return destinationOffset + rowLen;
166 * Copies the row to a new byte[]
167 * @param cell the cell from which row has to copied
168 * @return the byte[] containing the row
170 public static byte[] copyRow(Cell cell) {
171 if (cell instanceof ByteBufferExtendedCell) {
172 return ByteBufferUtils.copyOfRange(((ByteBufferExtendedCell) cell).getRowByteBuffer(),
173 ((ByteBufferExtendedCell) cell).getRowPosition(),
174 ((ByteBufferExtendedCell) cell).getRowPosition() + cell.getRowLength());
175 } else {
176 return Arrays.copyOfRange(cell.getRowArray(), cell.getRowOffset(),
177 cell.getRowOffset() + cell.getRowLength());
182 * Copies the family to the given byte[]
183 * @param cell the cell whose family has to be copied
184 * @param destination the destination byte[] to which the family has to be copied
185 * @param destinationOffset the offset in the destination byte[]
186 * @return the offset of the byte[] after the copy has happened
188 public static int copyFamilyTo(Cell cell, byte[] destination, int destinationOffset) {
189 byte fLen = cell.getFamilyLength();
190 if (cell instanceof ByteBufferExtendedCell) {
191 ByteBufferUtils.copyFromBufferToArray(destination,
192 ((ByteBufferExtendedCell) cell).getFamilyByteBuffer(),
193 ((ByteBufferExtendedCell) cell).getFamilyPosition(), destinationOffset, fLen);
194 } else {
195 System.arraycopy(cell.getFamilyArray(), cell.getFamilyOffset(), destination,
196 destinationOffset, fLen);
198 return destinationOffset + fLen;
202 * Copies the family to the given bytebuffer
203 * @param cell the cell whose family has to be copied
204 * @param destination the destination bytebuffer to which the family has to be copied
205 * @param destinationOffset the offset in the destination bytebuffer
206 * @return the offset of the bytebuffer after the copy has happened
208 public static int copyFamilyTo(Cell cell, ByteBuffer destination, int destinationOffset) {
209 byte fLen = cell.getFamilyLength();
210 if (cell instanceof ByteBufferExtendedCell) {
211 ByteBufferUtils.copyFromBufferToBuffer(((ByteBufferExtendedCell) cell).getFamilyByteBuffer(),
212 destination, ((ByteBufferExtendedCell) cell).getFamilyPosition(), destinationOffset, fLen);
213 } else {
214 ByteBufferUtils.copyFromArrayToBuffer(destination, destinationOffset, cell.getFamilyArray(),
215 cell.getFamilyOffset(), fLen);
217 return destinationOffset + fLen;
221 * Copies the qualifier to the given byte[]
222 * @param cell the cell whose qualifier has to be copied
223 * @param destination the destination byte[] to which the qualifier has to be copied
224 * @param destinationOffset the offset in the destination byte[]
225 * @return the offset of the byte[] after the copy has happened
227 public static int copyQualifierTo(Cell cell, byte[] destination, int destinationOffset) {
228 int qlen = cell.getQualifierLength();
229 if (cell instanceof ByteBufferExtendedCell) {
230 ByteBufferUtils.copyFromBufferToArray(destination,
231 ((ByteBufferExtendedCell) cell).getQualifierByteBuffer(),
232 ((ByteBufferExtendedCell) cell).getQualifierPosition(), destinationOffset, qlen);
233 } else {
234 System.arraycopy(cell.getQualifierArray(), cell.getQualifierOffset(), destination,
235 destinationOffset, qlen);
237 return destinationOffset + qlen;
241 * Copies the qualifier to the given bytebuffer
242 * @param cell the cell whose qualifier has to be copied
243 * @param destination the destination bytebuffer to which the qualifier has to be copied
244 * @param destinationOffset the offset in the destination bytebuffer
245 * @return the offset of the bytebuffer after the copy has happened
247 public static int copyQualifierTo(Cell cell, ByteBuffer destination, int destinationOffset) {
248 int qlen = cell.getQualifierLength();
249 if (cell instanceof ByteBufferExtendedCell) {
250 ByteBufferUtils.copyFromBufferToBuffer(
251 ((ByteBufferExtendedCell) cell).getQualifierByteBuffer(),
252 destination, ((ByteBufferExtendedCell) cell).getQualifierPosition(),
253 destinationOffset, qlen);
254 } else {
255 ByteBufferUtils.copyFromArrayToBuffer(destination, destinationOffset,
256 cell.getQualifierArray(), cell.getQualifierOffset(), qlen);
258 return destinationOffset + qlen;
262 * Copies the value to the given byte[]
263 * @param cell the cell whose value has to be copied
264 * @param destination the destination byte[] to which the value has to be copied
265 * @param destinationOffset the offset in the destination byte[]
266 * @return the offset of the byte[] after the copy has happened
268 public static int copyValueTo(Cell cell, byte[] destination, int destinationOffset) {
269 int vlen = cell.getValueLength();
270 if (cell instanceof ByteBufferExtendedCell) {
271 ByteBufferUtils.copyFromBufferToArray(destination,
272 ((ByteBufferExtendedCell) cell).getValueByteBuffer(),
273 ((ByteBufferExtendedCell) cell).getValuePosition(), destinationOffset, vlen);
274 } else {
275 System.arraycopy(cell.getValueArray(), cell.getValueOffset(), destination, destinationOffset,
276 vlen);
278 return destinationOffset + vlen;
282 * Copies the value to the given bytebuffer
283 * @param cell the cell whose value has to be copied
284 * @param destination the destination bytebuffer to which the value has to be copied
285 * @param destinationOffset the offset in the destination bytebuffer
286 * @return the offset of the bytebuffer after the copy has happened
288 public static int copyValueTo(Cell cell, ByteBuffer destination, int destinationOffset) {
289 int vlen = cell.getValueLength();
290 if (cell instanceof ByteBufferExtendedCell) {
291 ByteBufferUtils.copyFromBufferToBuffer(((ByteBufferExtendedCell) cell).getValueByteBuffer(),
292 destination, ((ByteBufferExtendedCell) cell).getValuePosition(), destinationOffset, vlen);
293 } else {
294 ByteBufferUtils.copyFromArrayToBuffer(destination, destinationOffset, cell.getValueArray(),
295 cell.getValueOffset(), vlen);
297 return destinationOffset + vlen;
301 * @param cellScannerables
302 * @return CellScanner interface over <code>cellIterables</code>
304 public static CellScanner createCellScanner(
305 final List<? extends CellScannable> cellScannerables) {
306 return new CellScanner() {
307 private final Iterator<? extends CellScannable> iterator = cellScannerables.iterator();
308 private CellScanner cellScanner = null;
310 @Override
311 public Cell current() {
312 return this.cellScanner != null? this.cellScanner.current(): null;
315 @Override
316 public boolean advance() throws IOException {
317 while (true) {
318 if (this.cellScanner == null) {
319 if (!this.iterator.hasNext()) return false;
320 this.cellScanner = this.iterator.next().cellScanner();
322 if (this.cellScanner.advance()) return true;
323 this.cellScanner = null;
330 * @param cellIterable
331 * @return CellScanner interface over <code>cellIterable</code>
333 public static CellScanner createCellScanner(final Iterable<Cell> cellIterable) {
334 if (cellIterable == null) return null;
335 return createCellScanner(cellIterable.iterator());
339 * @param cells
340 * @return CellScanner interface over <code>cellIterable</code> or null if <code>cells</code> is
341 * null
343 public static CellScanner createCellScanner(final Iterator<Cell> cells) {
344 if (cells == null) return null;
345 return new CellScanner() {
346 private final Iterator<Cell> iterator = cells;
347 private Cell current = null;
349 @Override
350 public Cell current() {
351 return this.current;
354 @Override
355 public boolean advance() {
356 boolean hasNext = this.iterator.hasNext();
357 this.current = hasNext? this.iterator.next(): null;
358 return hasNext;
364 * @param cellArray
365 * @return CellScanner interface over <code>cellArray</code>
367 public static CellScanner createCellScanner(final Cell[] cellArray) {
368 return new CellScanner() {
369 private final Cell [] cells = cellArray;
370 private int index = -1;
372 @Override
373 public Cell current() {
374 if (cells == null) return null;
375 return (index < 0)? null: this.cells[index];
378 @Override
379 public boolean advance() {
380 if (cells == null) return false;
381 return ++index < this.cells.length;
387 * Flatten the map of cells out under the CellScanner
388 * @param map Map of Cell Lists; for example, the map of families to Cells that is used
389 * inside Put, etc., keeping Cells organized by family.
390 * @return CellScanner interface over <code>cellIterable</code>
392 public static CellScanner createCellScanner(final NavigableMap<byte [], List<Cell>> map) {
393 return new CellScanner() {
394 private final Iterator<Entry<byte[], List<Cell>>> entries = map.entrySet().iterator();
395 private Iterator<Cell> currentIterator = null;
396 private Cell currentCell;
398 @Override
399 public Cell current() {
400 return this.currentCell;
403 @Override
404 public boolean advance() {
405 while(true) {
406 if (this.currentIterator == null) {
407 if (!this.entries.hasNext()) return false;
408 this.currentIterator = this.entries.next().getValue().iterator();
410 if (this.currentIterator.hasNext()) {
411 this.currentCell = this.currentIterator.next();
412 return true;
414 this.currentCell = null;
415 this.currentIterator = null;
421 public static boolean matchingRows(final Cell left, final byte[] buf) {
422 if (buf == null) {
423 return left.getRowLength() == 0;
425 return PrivateCellUtil.matchingRows(left, buf, 0, buf.length);
428 public static boolean matchingRow(final Cell left, final byte[] buf, final int offset,
429 final int length) {
430 return PrivateCellUtil.matchingRows(left, buf, offset, length);
433 public static boolean matchingFamily(final Cell left, final Cell right) {
434 byte lfamlength = left.getFamilyLength();
435 byte rfamlength = right.getFamilyLength();
436 if (left instanceof ByteBufferExtendedCell && right instanceof ByteBufferExtendedCell) {
437 return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getFamilyByteBuffer(),
438 ((ByteBufferExtendedCell) left).getFamilyPosition(), lfamlength,
439 ((ByteBufferExtendedCell) right).getFamilyByteBuffer(),
440 ((ByteBufferExtendedCell) right).getFamilyPosition(), rfamlength);
442 if (left instanceof ByteBufferExtendedCell) {
443 return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getFamilyByteBuffer(),
444 ((ByteBufferExtendedCell) left).getFamilyPosition(), lfamlength,
445 right.getFamilyArray(), right.getFamilyOffset(), rfamlength);
447 if (right instanceof ByteBufferExtendedCell) {
448 return ByteBufferUtils.equals(((ByteBufferExtendedCell) right).getFamilyByteBuffer(),
449 ((ByteBufferExtendedCell) right).getFamilyPosition(), rfamlength,
450 left.getFamilyArray(), left.getFamilyOffset(), lfamlength);
452 return Bytes.equals(left.getFamilyArray(), left.getFamilyOffset(), lfamlength,
453 right.getFamilyArray(), right.getFamilyOffset(), rfamlength);
456 public static boolean matchingFamily(final Cell left, final byte[] buf) {
457 if (buf == null) {
458 return left.getFamilyLength() == 0;
460 return PrivateCellUtil.matchingFamily(left, buf, 0, buf.length);
463 public static boolean matchingQualifier(final Cell left, final Cell right) {
464 int lqlength = left.getQualifierLength();
465 int rqlength = right.getQualifierLength();
466 if (left instanceof ByteBufferExtendedCell && right instanceof ByteBufferExtendedCell) {
467 return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getQualifierByteBuffer(),
468 ((ByteBufferExtendedCell) left).getQualifierPosition(), lqlength,
469 ((ByteBufferExtendedCell) right).getQualifierByteBuffer(),
470 ((ByteBufferExtendedCell) right).getQualifierPosition(), rqlength);
472 if (left instanceof ByteBufferExtendedCell) {
473 return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getQualifierByteBuffer(),
474 ((ByteBufferExtendedCell) left).getQualifierPosition(), lqlength,
475 right.getQualifierArray(), right.getQualifierOffset(), rqlength);
477 if (right instanceof ByteBufferExtendedCell) {
478 return ByteBufferUtils.equals(((ByteBufferExtendedCell) right).getQualifierByteBuffer(),
479 ((ByteBufferExtendedCell) right).getQualifierPosition(), rqlength,
480 left.getQualifierArray(), left.getQualifierOffset(), lqlength);
482 return Bytes.equals(left.getQualifierArray(), left.getQualifierOffset(),
483 lqlength, right.getQualifierArray(), right.getQualifierOffset(),
484 rqlength);
488 * Finds if the qualifier part of the cell and the KV serialized
489 * byte[] are equal
490 * @param left
491 * @param buf the serialized keyvalue format byte[]
492 * @return true if the qualifier matches, false otherwise
494 public static boolean matchingQualifier(final Cell left, final byte[] buf) {
495 if (buf == null) {
496 return left.getQualifierLength() == 0;
498 return PrivateCellUtil.matchingQualifier(left, buf, 0, buf.length);
501 public static boolean matchingColumn(final Cell left, final byte[] fam, final byte[] qual) {
502 return matchingFamily(left, fam) && matchingQualifier(left, qual);
506 * @return True if matching column family and the qualifier starts with <code>qual</code>
508 public static boolean matchingColumnFamilyAndQualifierPrefix(final Cell left, final byte[] fam,
509 final byte[] qual) {
510 return matchingFamily(left, fam) && PrivateCellUtil.qualifierStartsWith(left, qual);
513 public static boolean matchingColumn(final Cell left, final Cell right) {
514 if (!matchingFamily(left, right))
515 return false;
516 return matchingQualifier(left, right);
519 public static boolean matchingValue(final Cell left, final Cell right) {
520 return matchingValue(left, right, left.getValueLength(), right.getValueLength());
523 public static boolean matchingValue(final Cell left, final Cell right, int lvlength,
524 int rvlength) {
525 if (left instanceof ByteBufferExtendedCell && right instanceof ByteBufferExtendedCell) {
526 return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getValueByteBuffer(),
527 ((ByteBufferExtendedCell) left).getValuePosition(), lvlength,
528 ((ByteBufferExtendedCell) right).getValueByteBuffer(),
529 ((ByteBufferExtendedCell) right).getValuePosition(), rvlength);
531 if (left instanceof ByteBufferExtendedCell) {
532 return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getValueByteBuffer(),
533 ((ByteBufferExtendedCell) left).getValuePosition(), lvlength, right.getValueArray(),
534 right.getValueOffset(), rvlength);
536 if (right instanceof ByteBufferExtendedCell) {
537 return ByteBufferUtils.equals(((ByteBufferExtendedCell) right).getValueByteBuffer(),
538 ((ByteBufferExtendedCell) right).getValuePosition(), rvlength, left.getValueArray(),
539 left.getValueOffset(), lvlength);
541 return Bytes.equals(left.getValueArray(), left.getValueOffset(), lvlength,
542 right.getValueArray(), right.getValueOffset(), rvlength);
545 public static boolean matchingValue(final Cell left, final byte[] buf) {
546 if (left instanceof ByteBufferExtendedCell) {
547 return ByteBufferUtils.compareTo(((ByteBufferExtendedCell) left).getValueByteBuffer(),
548 ((ByteBufferExtendedCell) left).getValuePosition(), left.getValueLength(), buf, 0,
549 buf.length) == 0;
551 return Bytes.equals(left.getValueArray(), left.getValueOffset(), left.getValueLength(), buf, 0,
552 buf.length);
556 * @return True if a delete type, a {@link KeyValue.Type#Delete} or a
557 * {KeyValue.Type#DeleteFamily} or a
558 * {@link KeyValue.Type#DeleteColumn} KeyValue type.
560 @SuppressWarnings("deprecation")
561 public static boolean isDelete(final Cell cell) {
562 return PrivateCellUtil.isDelete(cell.getTypeByte());
566 * @return True if this cell is a Put.
568 @SuppressWarnings("deprecation")
569 public static boolean isPut(Cell cell) {
570 return cell.getTypeByte() == Type.Put.getCode();
574 * Sets the given timestamp to the cell.
576 * Note that this method is a LimitedPrivate API and may change between minor releases.
577 * @param cell
578 * @param ts
579 * @throws IOException when the passed cell is not of type {@link ExtendedCell}
581 @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.COPROC)
582 public static void setTimestamp(Cell cell, long ts) throws IOException {
583 PrivateCellUtil.setTimestamp(cell, ts);
587 * Sets the given timestamp to the cell.
589 * Note that this method is a LimitedPrivate API and may change between minor releases.
590 * @param cell
591 * @param ts buffer containing the timestamp value
592 * @param tsOffset offset to the new timestamp
593 * @throws IOException when the passed cell is not of type {@link ExtendedCell}
595 @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.COPROC)
596 public static void setTimestamp(Cell cell, byte[] ts, int tsOffset) throws IOException {
597 PrivateCellUtil.setTimestamp(cell, Bytes.toLong(ts, tsOffset));
601 * @return The Key portion of the passed <code>cell</code> as a String.
603 public static String getCellKeyAsString(Cell cell) {
604 return getCellKeyAsString(cell,
605 c -> Bytes.toStringBinary(c.getRowArray(), c.getRowOffset(), c.getRowLength()));
609 * @param cell the cell to convert
610 * @param rowConverter used to convert the row of the cell to a string
611 * @return The Key portion of the passed <code>cell</code> as a String.
613 public static String getCellKeyAsString(Cell cell, Function<Cell, String> rowConverter) {
614 StringBuilder sb = new StringBuilder(rowConverter.apply(cell));
615 sb.append('/');
616 sb.append(cell.getFamilyLength() == 0 ? "" :
617 Bytes.toStringBinary(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength()));
618 // KeyValue only added ':' if family is non-null. Do same.
619 if (cell.getFamilyLength() > 0) sb.append(':');
620 sb.append(cell.getQualifierLength() == 0 ? "" :
621 Bytes.toStringBinary(cell.getQualifierArray(), cell.getQualifierOffset(),
622 cell.getQualifierLength()));
623 sb.append('/');
624 sb.append(KeyValue.humanReadableTimestamp(cell.getTimestamp()));
625 sb.append('/');
626 sb.append(Type.codeToType(cell.getTypeByte()));
627 if (!(cell instanceof KeyValue.KeyOnlyKeyValue)) {
628 sb.append("/vlen=");
629 sb.append(cell.getValueLength());
631 sb.append("/seqid=");
632 sb.append(cell.getSequenceId());
633 return sb.toString();
636 /** Returns a string representation of the cell */
637 public static String toString(Cell cell, boolean verbose) {
638 if (cell == null) {
639 return "";
641 StringBuilder builder = new StringBuilder();
642 String keyStr = getCellKeyAsString(cell);
644 String tag = null;
645 String value = null;
646 if (verbose) {
647 // TODO: pretty print tags as well
648 if (cell.getTagsLength() > 0) {
649 tag = Bytes.toStringBinary(cell.getTagsArray(), cell.getTagsOffset(), cell.getTagsLength());
651 if (!(cell instanceof KeyValue.KeyOnlyKeyValue)) {
652 value = Bytes.toStringBinary(cell.getValueArray(), cell.getValueOffset(),
653 cell.getValueLength());
657 builder.append(keyStr);
658 if (tag != null && !tag.isEmpty()) {
659 builder.append("/").append(tag);
661 if (value != null) {
662 builder.append("/").append(value);
665 return builder.toString();
668 /**************** equals ****************************/
670 public static boolean equals(Cell a, Cell b) {
671 return matchingRows(a, b) && matchingFamily(a, b) && matchingQualifier(a, b)
672 && matchingTimestamp(a, b) && PrivateCellUtil.matchingType(a, b);
675 public static boolean matchingTimestamp(Cell a, Cell b) {
676 return CellComparator.getInstance().compareTimestamps(a.getTimestamp(), b.getTimestamp()) == 0;
680 * Compares the row of two keyvalues for equality
681 * @param left
682 * @param right
683 * @return True if rows match.
685 public static boolean matchingRows(final Cell left, final Cell right) {
686 short lrowlength = left.getRowLength();
687 short rrowlength = right.getRowLength();
688 if (lrowlength != rrowlength) return false;
689 if (left instanceof ByteBufferExtendedCell && right instanceof ByteBufferExtendedCell) {
690 return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getRowByteBuffer(),
691 ((ByteBufferExtendedCell) left).getRowPosition(), lrowlength,
692 ((ByteBufferExtendedCell) right).getRowByteBuffer(),
693 ((ByteBufferExtendedCell) right).getRowPosition(), rrowlength);
695 if (left instanceof ByteBufferExtendedCell) {
696 return ByteBufferUtils.equals(((ByteBufferExtendedCell) left).getRowByteBuffer(),
697 ((ByteBufferExtendedCell) left).getRowPosition(), lrowlength, right.getRowArray(),
698 right.getRowOffset(), rrowlength);
700 if (right instanceof ByteBufferExtendedCell) {
701 return ByteBufferUtils.equals(((ByteBufferExtendedCell) right).getRowByteBuffer(),
702 ((ByteBufferExtendedCell) right).getRowPosition(), rrowlength, left.getRowArray(),
703 left.getRowOffset(), lrowlength);
705 return Bytes.equals(left.getRowArray(), left.getRowOffset(), lrowlength, right.getRowArray(),
706 right.getRowOffset(), rrowlength);
710 * Compares the row and column of two keyvalues for equality
711 * @param left
712 * @param right
713 * @return True if same row and column.
715 public static boolean matchingRowColumn(final Cell left, final Cell right) {
716 if ((left.getRowLength() + left.getFamilyLength()
717 + left.getQualifierLength()) != (right.getRowLength() + right.getFamilyLength()
718 + right.getQualifierLength())) {
719 return false;
722 if (!matchingRows(left, right)) {
723 return false;
725 return matchingColumn(left, right);
728 public static boolean matchingRowColumnBytes(final Cell left, final Cell right) {
729 int lrowlength = left.getRowLength();
730 int rrowlength = right.getRowLength();
731 int lfamlength = left.getFamilyLength();
732 int rfamlength = right.getFamilyLength();
733 int lqlength = left.getQualifierLength();
734 int rqlength = right.getQualifierLength();
735 // match length
736 if ((lrowlength + lfamlength + lqlength) !=
737 (rrowlength + rfamlength + rqlength)) {
738 return false;
741 // match row
742 if (!Bytes.equals(left.getRowArray(), left.getRowOffset(), lrowlength, right.getRowArray(),
743 right.getRowOffset(), rrowlength)) {
744 return false;
746 //match family
747 if (!Bytes.equals(left.getFamilyArray(), left.getFamilyOffset(), lfamlength,
748 right.getFamilyArray(), right.getFamilyOffset(), rfamlength)) {
749 return false;
751 //match qualifier
752 return Bytes.equals(left.getQualifierArray(), left.getQualifierOffset(),
753 lqlength, right.getQualifierArray(), right.getQualifierOffset(),
754 rqlength);
758 * Compares the cell's qualifier with the given byte[]
759 * @param left the cell for which the qualifier has to be compared
760 * @param right the byte[] having the qualifier
761 * @param rOffset the offset of the qualifier
762 * @param rLength the length of the qualifier
763 * @return greater than 0 if left cell's qualifier is bigger than byte[], lesser than 0 if left
764 * cell's qualifier is lesser than byte[] and 0 otherwise
766 public final static int compareQualifiers(Cell left, byte[] right, int rOffset, int rLength) {
767 if (left instanceof ByteBufferExtendedCell) {
768 return ByteBufferUtils.compareTo(((ByteBufferExtendedCell) left).getQualifierByteBuffer(),
769 ((ByteBufferExtendedCell) left).getQualifierPosition(),
770 left.getQualifierLength(), right, rOffset, rLength);
772 return Bytes.compareTo(left.getQualifierArray(), left.getQualifierOffset(),
773 left.getQualifierLength(), right, rOffset, rLength);
777 * Compares the cell's family with the given byte[]
778 * @param left the cell for which the family has to be compared
779 * @param right the byte[] having the family
780 * @param roffset the offset of the family
781 * @param rlength the length of the family
782 * @return greater than 0 if left cell's family is bigger than byte[], lesser than 0 if left
783 * cell's family is lesser than byte[] and 0 otherwise
785 public final static int compareFamilies(Cell left, byte[] right, int roffset, int rlength) {
786 if (left instanceof ByteBufferExtendedCell) {
787 return ByteBufferUtils.compareTo(((ByteBufferExtendedCell) left).getFamilyByteBuffer(),
788 ((ByteBufferExtendedCell) left).getFamilyPosition(), left.getFamilyLength(), right, roffset,
789 rlength);
791 return Bytes.compareTo(left.getFamilyArray(), left.getFamilyOffset(), left.getFamilyLength(),
792 right, roffset, rlength);
796 * Compares the cell's column (family and qualifier) with the given byte[]
797 * @param left the cell for which the column has to be compared
798 * @param right the byte[] having the column
799 * @param rfoffset the offset of the family
800 * @param rflength the length of the family
801 * @param rqoffset the offset of the qualifier
802 * @param rqlength the length of the qualifier
803 * @return greater than 0 if left cell's column is bigger than byte[], lesser than 0 if left
804 * cell's column is lesser than byte[] and 0 otherwise
806 public final static int compareColumns(Cell left, byte[] right, int rfoffset, int rflength,
807 int rqoffset, int rqlength) {
808 int diff = compareFamilies(left, right, rfoffset, rflength);
809 if (diff != 0) return diff;
810 return compareQualifiers(left, right, rqoffset, rqlength);