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
;
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
{
47 * Private constructor to keep this class from being instantiated.
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);
60 public static byte[] cloneFamily(Cell cell
) {
61 byte[] output
= new byte[cell
.getFamilyLength()];
62 copyFamilyTo(cell
, output
, 0);
66 public static byte[] cloneQualifier(Cell cell
) {
67 byte[] output
= new byte[cell
.getQualifierLength()];
68 copyQualifierTo(cell
, output
, 0);
72 public static byte[] cloneValue(Cell cell
) {
73 byte[] output
= new byte[cell
.getValueLength()];
74 copyValueTo(cell
, output
, 0);
79 * Makes a column in family:qualifier form from separate byte arrays.
81 * Not recommended for usage as this is old-style API.
84 * @return family:qualifier
86 public static byte[] makeColumn(byte[] family
, byte[] qualifier
) {
87 return Bytes
.add(family
, COLUMN_FAMILY_DELIM_ARRAY
, qualifier
);
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>.
95 * Don't forget, HBase DOES support empty qualifiers. (see HBASE-9549)
98 * Not recommend to be used as this is old-style API.
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
);
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
);
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
);
140 System
.arraycopy(cell
.getRowArray(), cell
.getRowOffset(), destination
, destinationOffset
,
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
);
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());
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
);
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
);
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
);
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
);
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
);
275 System
.arraycopy(cell
.getValueArray(), cell
.getValueOffset(), destination
, destinationOffset
,
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
);
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;
311 public Cell
current() {
312 return this.cellScanner
!= null?
this.cellScanner
.current(): null;
316 public boolean advance() throws IOException
{
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());
340 * @return CellScanner interface over <code>cellIterable</code> or null if <code>cells</code> is
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;
350 public Cell
current() {
355 public boolean advance() {
356 boolean hasNext
= this.iterator
.hasNext();
357 this.current
= hasNext?
this.iterator
.next(): null;
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;
373 public Cell
current() {
374 if (cells
== null) return null;
375 return (index
< 0)?
null: this.cells
[index
];
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
;
399 public Cell
current() {
400 return this.currentCell
;
404 public boolean advance() {
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();
414 this.currentCell
= null;
415 this.currentIterator
= null;
421 public static boolean matchingRows(final Cell left
, final byte[] buf
) {
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
,
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
) {
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(),
488 * Finds if the qualifier part of the cell and the KV serialized
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
) {
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
,
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
))
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
,
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,
551 return Bytes
.equals(left
.getValueArray(), left
.getValueOffset(), left
.getValueLength(), buf
, 0,
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.
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.
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
));
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()));
624 sb
.append(KeyValue
.humanReadableTimestamp(cell
.getTimestamp()));
626 sb
.append(Type
.codeToType(cell
.getTypeByte()));
627 if (!(cell
instanceof KeyValue
.KeyOnlyKeyValue
)) {
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
) {
641 StringBuilder builder
= new StringBuilder();
642 String keyStr
= getCellKeyAsString(cell
);
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
);
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
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
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())) {
722 if (!matchingRows(left
, right
)) {
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();
736 if ((lrowlength
+ lfamlength
+ lqlength
) !=
737 (rrowlength
+ rfamlength
+ rqlength
)) {
742 if (!Bytes
.equals(left
.getRowArray(), left
.getRowOffset(), lrowlength
, right
.getRowArray(),
743 right
.getRowOffset(), rrowlength
)) {
747 if (!Bytes
.equals(left
.getFamilyArray(), left
.getFamilyOffset(), lfamlength
,
748 right
.getFamilyArray(), right
.getFamilyOffset(), rfamlength
)) {
752 return Bytes
.equals(left
.getQualifierArray(), left
.getQualifierOffset(),
753 lqlength
, right
.getQualifierArray(), right
.getQualifierOffset(),
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
,
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
);