2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package org
.apache
.hadoop
.hbase
;
20 import java
.nio
.ByteBuffer
;
21 import java
.util
.Comparator
;
22 import org
.apache
.hadoop
.hbase
.KeyValue
.Type
;
23 import org
.apache
.hadoop
.hbase
.util
.ByteBufferUtils
;
24 import org
.apache
.hadoop
.hbase
.util
.Bytes
;
25 import org
.apache
.yetus
.audience
.InterfaceAudience
;
26 import org
.apache
.yetus
.audience
.InterfaceStability
;
27 import org
.slf4j
.Logger
;
28 import org
.slf4j
.LoggerFactory
;
29 import org
.apache
.hbase
.thirdparty
.com
.google
.common
.primitives
.Longs
;
32 * Compare two HBase cells. Do not use this method comparing <code>-ROOT-</code> or
33 * <code>hbase:meta</code> cells. Cells from these tables need a specialized comparator, one that
34 * takes account of the special formatting of the row where we have commas to delimit table from
35 * regionname, from row. See KeyValue for how it has a special comparator to do hbase:meta cells
36 * and yet another for -ROOT-.
37 * <p>While using this comparator for {{@link #compareRows(Cell, Cell)} et al, the hbase:meta cells
38 * format should be taken into consideration, for which the instance of this comparator
39 * should be used. In all other cases the static APIs in this comparator would be enough
40 * <p>HOT methods. We spend a good portion of CPU comparing. Anything that makes the compare
41 * faster will likely manifest at the macro level. See also
42 * {@link BBKVComparator}. Use it when mostly {@link ByteBufferKeyValue}s.
45 @edu.umd
.cs
.findbugs
.annotations
.SuppressWarnings(
47 justification
="Findbugs doesn't like the way we are negating the result of a compare in below")
48 @InterfaceAudience.Private
49 @InterfaceStability.Evolving
50 public class CellComparatorImpl
implements CellComparator
{
51 static final Logger LOG
= LoggerFactory
.getLogger(CellComparatorImpl
.class);
54 * Comparator for plain key/values; i.e. non-catalog table key/values. Works on Key portion
57 public static final CellComparatorImpl COMPARATOR
= new CellComparatorImpl();
60 * A {@link CellComparatorImpl} for <code>hbase:meta</code> catalog table
63 public static final CellComparatorImpl META_COMPARATOR
= new MetaCellComparator();
66 public final int compare(final Cell a
, final Cell b
) {
67 return compare(a
, b
, false);
71 public int compare(final Cell a
, final Cell b
, boolean ignoreSequenceid
) {
74 // "Peel off" the most common path.
75 if (a
instanceof ByteBufferKeyValue
&& b
instanceof ByteBufferKeyValue
) {
76 diff
= BBKVComparator
.compare((ByteBufferKeyValue
)a
, (ByteBufferKeyValue
)b
, ignoreSequenceid
);
81 diff
= compareRows(a
, b
);
86 diff
= compareWithoutRow(a
, b
);
92 // Negate following comparisons so later edits show up first mvccVersion: later sorts first
93 return ignoreSequenceid? diff
: Long
.compare(b
.getSequenceId(), a
.getSequenceId());
97 * Compares the family and qualifier part of the cell
98 * @return 0 if both cells are equal, 1 if left cell is bigger than right, -1 otherwise
100 public final int compareColumns(final Cell left
, final Cell right
) {
101 int diff
= compareFamilies(left
, right
);
105 return compareQualifiers(left
, right
);
109 * Compare the families of left and right cell
110 * @return 0 if both cells are equal, 1 if left cell is bigger than right, -1 otherwise
113 public final int compareFamilies(Cell left
, Cell right
) {
114 if (left
instanceof ByteBufferExtendedCell
&& right
instanceof ByteBufferExtendedCell
) {
115 return ByteBufferUtils
.compareTo(((ByteBufferExtendedCell
) left
).getFamilyByteBuffer(),
116 ((ByteBufferExtendedCell
) left
).getFamilyPosition(), left
.getFamilyLength(),
117 ((ByteBufferExtendedCell
) right
).getFamilyByteBuffer(),
118 ((ByteBufferExtendedCell
) right
).getFamilyPosition(), right
.getFamilyLength());
120 if (left
instanceof ByteBufferExtendedCell
) {
121 return ByteBufferUtils
.compareTo(((ByteBufferExtendedCell
) left
).getFamilyByteBuffer(),
122 ((ByteBufferExtendedCell
) left
).getFamilyPosition(), left
.getFamilyLength(),
123 right
.getFamilyArray(), right
.getFamilyOffset(), right
.getFamilyLength());
125 if (right
instanceof ByteBufferExtendedCell
) {
126 // Notice how we flip the order of the compare here. We used to negate the return value but
127 // see what FindBugs says
128 // http://findbugs.sourceforge.net/bugDescriptions.html#RV_NEGATING_RESULT_OF_COMPARETO
129 // It suggest flipping the order to get same effect and 'safer'.
130 return ByteBufferUtils
.compareTo(
131 left
.getFamilyArray(), left
.getFamilyOffset(), left
.getFamilyLength(),
132 ((ByteBufferExtendedCell
)right
).getFamilyByteBuffer(),
133 ((ByteBufferExtendedCell
)right
).getFamilyPosition(), right
.getFamilyLength());
135 return Bytes
.compareTo(left
.getFamilyArray(), left
.getFamilyOffset(), left
.getFamilyLength(),
136 right
.getFamilyArray(), right
.getFamilyOffset(), right
.getFamilyLength());
140 * Compare the qualifiers part of the left and right cells.
141 * @return 0 if both cells are equal, 1 if left cell is bigger than right, -1 otherwise
144 public final int compareQualifiers(Cell left
, Cell right
) {
145 if (left
instanceof ByteBufferExtendedCell
&& right
instanceof ByteBufferExtendedCell
) {
146 return ByteBufferUtils
147 .compareTo(((ByteBufferExtendedCell
) left
).getQualifierByteBuffer(),
148 ((ByteBufferExtendedCell
) left
).getQualifierPosition(),
149 left
.getQualifierLength(), ((ByteBufferExtendedCell
) right
).getQualifierByteBuffer(),
150 ((ByteBufferExtendedCell
) right
).getQualifierPosition(),
151 right
.getQualifierLength());
153 if (left
instanceof ByteBufferExtendedCell
) {
154 return ByteBufferUtils
.compareTo(((ByteBufferExtendedCell
) left
).getQualifierByteBuffer(),
155 ((ByteBufferExtendedCell
) left
).getQualifierPosition(), left
.getQualifierLength(),
156 right
.getQualifierArray(), right
.getQualifierOffset(), right
.getQualifierLength());
158 if (right
instanceof ByteBufferExtendedCell
) {
159 // Notice how we flip the order of the compare here. We used to negate the return value but
160 // see what FindBugs says
161 // http://findbugs.sourceforge.net/bugDescriptions.html#RV_NEGATING_RESULT_OF_COMPARETO
162 // It suggest flipping the order to get same effect and 'safer'.
163 return ByteBufferUtils
.compareTo(left
.getQualifierArray(),
164 left
.getQualifierOffset(), left
.getQualifierLength(),
165 ((ByteBufferExtendedCell
)right
).getQualifierByteBuffer(),
166 ((ByteBufferExtendedCell
)right
).getQualifierPosition(), right
.getQualifierLength());
168 return Bytes
.compareTo(left
.getQualifierArray(), left
.getQualifierOffset(),
169 left
.getQualifierLength(), right
.getQualifierArray(), right
.getQualifierOffset(),
170 right
.getQualifierLength());
174 * Compares the rows of the left and right cell.
175 * For the hbase:meta case this method is overridden such that it can handle hbase:meta cells.
176 * The caller should ensure using the appropriate comparator for hbase:meta.
177 * @return 0 if both cells are equal, 1 if left cell is bigger than right, -1 otherwise
180 public int compareRows(final Cell left
, final Cell right
) {
181 return compareRows(left
, left
.getRowLength(), right
, right
.getRowLength());
184 static int compareRows(final Cell left
, int leftRowLength
, final Cell right
, int rightRowLength
) {
185 // left and right can be exactly the same at the beginning of a row
189 if (left
instanceof ByteBufferExtendedCell
&& right
instanceof ByteBufferExtendedCell
) {
190 return ByteBufferUtils
.compareTo(((ByteBufferExtendedCell
) left
).getRowByteBuffer(),
191 ((ByteBufferExtendedCell
) left
).getRowPosition(), leftRowLength
,
192 ((ByteBufferExtendedCell
) right
).getRowByteBuffer(),
193 ((ByteBufferExtendedCell
) right
).getRowPosition(), rightRowLength
);
195 if (left
instanceof ByteBufferExtendedCell
) {
196 return ByteBufferUtils
.compareTo(((ByteBufferExtendedCell
) left
).getRowByteBuffer(),
197 ((ByteBufferExtendedCell
) left
).getRowPosition(), leftRowLength
,
198 right
.getRowArray(), right
.getRowOffset(), rightRowLength
);
200 if (right
instanceof ByteBufferExtendedCell
) {
201 // Notice how we flip the order of the compare here. We used to negate the return value but
202 // see what FindBugs says
203 // http://findbugs.sourceforge.net/bugDescriptions.html#RV_NEGATING_RESULT_OF_COMPARETO
204 // It suggest flipping the order to get same effect and 'safer'.
205 return ByteBufferUtils
.compareTo(left
.getRowArray(), left
.getRowOffset(), leftRowLength
,
206 ((ByteBufferExtendedCell
)right
).getRowByteBuffer(),
207 ((ByteBufferExtendedCell
)right
).getRowPosition(), rightRowLength
);
209 return Bytes
.compareTo(left
.getRowArray(), left
.getRowOffset(), left
.getRowLength(),
210 right
.getRowArray(), right
.getRowOffset(), right
.getRowLength());
214 * Compares the row part of the cell with a simple plain byte[] like the
215 * stopRow in Scan. This should be used with context where for hbase:meta
216 * cells the {{@link #META_COMPARATOR} should be used
219 * the cell to be compared
221 * the kv serialized byte[] to be compared with
223 * the offset in the byte[]
225 * the length in the byte[]
226 * @return 0 if both cell and the byte[] are equal, 1 if the cell is bigger
227 * than byte[], -1 otherwise
230 public int compareRows(Cell left
, byte[] right
, int roffset
, int rlength
) {
231 if (left
instanceof ByteBufferExtendedCell
) {
232 return ByteBufferUtils
.compareTo(((ByteBufferExtendedCell
) left
).getRowByteBuffer(),
233 ((ByteBufferExtendedCell
) left
).getRowPosition(), left
.getRowLength(), right
,
236 return Bytes
.compareTo(left
.getRowArray(), left
.getRowOffset(), left
.getRowLength(), right
,
241 public final int compareWithoutRow(final Cell left
, final Cell right
) {
242 // If the column is not specified, the "minimum" key type appears the
243 // latest in the sorted order, regardless of the timestamp. This is used
244 // for specifying the last key/value in a given row, because there is no
245 // "lexicographically last column" (it would be infinitely long). The
246 // "maximum" key type does not need this behavior.
247 // Copied from KeyValue. This is bad in that we can't do memcmp w/ special rules like this.
248 int lFamLength
= left
.getFamilyLength();
249 int rFamLength
= right
.getFamilyLength();
250 int lQualLength
= left
.getQualifierLength();
251 int rQualLength
= right
.getQualifierLength();
252 if (lFamLength
+ lQualLength
== 0
253 && left
.getTypeByte() == Type
.Minimum
.getCode()) {
254 // left is "bigger", i.e. it appears later in the sorted order
257 if (rFamLength
+ rQualLength
== 0
258 && right
.getTypeByte() == Type
.Minimum
.getCode()) {
261 if (lFamLength
!= rFamLength
) {
262 // comparing column family is enough.
263 return compareFamilies(left
, right
);
265 // Compare cf:qualifier
266 int diff
= compareColumns(left
, right
);
271 diff
= compareTimestamps(left
.getTimestamp(), right
.getTimestamp());
276 // Compare types. Let the delete types sort ahead of puts; i.e. types
277 // of higher numbers sort before those of lesser numbers. Maximum (255)
278 // appears ahead of everything, and minimum (0) appears after
280 return (0xff & right
.getTypeByte()) - (0xff & left
.getTypeByte());
284 public int compareTimestamps(final Cell left
, final Cell right
) {
285 return compareTimestamps(left
.getTimestamp(), right
.getTimestamp());
289 public int compareTimestamps(final long ltimestamp
, final long rtimestamp
) {
290 // Swap order we pass into compare so we get DESCENDING order.
291 return Long
.compare(rtimestamp
, ltimestamp
);
295 * A {@link CellComparatorImpl} for <code>hbase:meta</code> catalog table
298 public static class MetaCellComparator
extends CellComparatorImpl
{
299 // TODO: Do we need a ByteBufferKeyValue version of this?
301 public int compareRows(final Cell left
, final Cell right
) {
302 return compareRows(left
.getRowArray(), left
.getRowOffset(), left
.getRowLength(),
303 right
.getRowArray(), right
.getRowOffset(), right
.getRowLength());
307 public int compareRows(Cell left
, byte[] right
, int roffset
, int rlength
) {
308 return compareRows(left
.getRowArray(), left
.getRowOffset(), left
.getRowLength(), right
,
313 public int compare(final Cell a
, final Cell b
, boolean ignoreSequenceid
) {
314 int diff
= compareRows(a
, b
);
319 diff
= compareWithoutRow(a
, b
);
324 // Negate following comparisons so later edits show up first mvccVersion: later sorts first
325 return ignoreSequenceid? diff
: Longs
.compare(b
.getSequenceId(), a
.getSequenceId());
328 private static int compareRows(byte[] left
, int loffset
, int llength
, byte[] right
, int roffset
,
330 int leftDelimiter
= Bytes
.searchDelimiterIndex(left
, loffset
, llength
, HConstants
.DELIMITER
);
331 int rightDelimiter
= Bytes
332 .searchDelimiterIndex(right
, roffset
, rlength
, HConstants
.DELIMITER
);
333 // Compare up to the delimiter
334 int lpart
= (leftDelimiter
< 0 ? llength
: leftDelimiter
- loffset
);
335 int rpart
= (rightDelimiter
< 0 ? rlength
: rightDelimiter
- roffset
);
336 int result
= Bytes
.compareTo(left
, loffset
, lpart
, right
, roffset
, rpart
);
340 if (leftDelimiter
< 0 && rightDelimiter
>= 0) {
342 } else if (rightDelimiter
< 0 && leftDelimiter
>= 0) {
344 } else if (leftDelimiter
< 0) {
348 // Compare middle bit of the row.
349 // Move past delimiter
352 int leftFarDelimiter
= Bytes
.searchDelimiterIndexInReverse(left
, leftDelimiter
, llength
353 - (leftDelimiter
- loffset
), HConstants
.DELIMITER
);
354 int rightFarDelimiter
= Bytes
.searchDelimiterIndexInReverse(right
, rightDelimiter
, rlength
355 - (rightDelimiter
- roffset
), HConstants
.DELIMITER
);
356 // Now compare middlesection of row.
357 lpart
= (leftFarDelimiter
< 0 ? llength
+ loffset
: leftFarDelimiter
) - leftDelimiter
;
358 rpart
= (rightFarDelimiter
< 0 ? rlength
+ roffset
: rightFarDelimiter
) - rightDelimiter
;
359 result
= Bytes
.compareTo(left
, leftDelimiter
, lpart
, right
, rightDelimiter
, rpart
);
363 if (leftDelimiter
< 0 && rightDelimiter
>= 0) {
365 } else if (rightDelimiter
< 0 && leftDelimiter
>= 0) {
367 } else if (leftDelimiter
< 0) {
371 // Compare last part of row, the rowid.
374 result
= Bytes
.compareTo(left
, leftFarDelimiter
, llength
- (leftFarDelimiter
- loffset
),
375 right
, rightFarDelimiter
, rlength
- (rightFarDelimiter
- roffset
));
380 public int compareRows(ByteBuffer row
, Cell cell
) {
383 int len
= row
.remaining();
384 if (row
.hasArray()) {
386 offset
= row
.position() + row
.arrayOffset();
388 // We copy the row array if offheap just so we can do a compare. We do this elsewhere too
389 // in BBUtils when Cell is backed by an offheap ByteBuffer. Needs fixing so no copy. TODO.
390 array
= new byte[len
];
392 ByteBufferUtils
.copyFromBufferToArray(array
, row
, row
.position(),
395 // Reverse result since we swap the order of the params we pass below.
396 return -compareRows(cell
, array
, offset
, len
);
400 public Comparator
getSimpleComparator() {
406 public Comparator
getSimpleComparator() {
407 return new BBKVComparator(this);
411 * Utility method that makes a guess at comparator to use based off passed tableName.
412 * Use in extreme when no comparator specified.
413 * @return CellComparator to use going off the {@code tableName} passed.
415 public static CellComparator
getCellComparator(TableName tableName
) {
416 return getCellComparator(tableName
.toBytes());
420 * Utility method that makes a guess at comparator to use based off passed tableName.
421 * Use in extreme when no comparator specified.
422 * @return CellComparator to use going off the {@code tableName} passed.
424 public static CellComparator
getCellComparator(byte [] tableName
) {
425 // FYI, TableName.toBytes does not create an array; just returns existing array pointer.
426 return Bytes
.equals(tableName
, TableName
.META_TABLE_NAME
.toBytes())?
427 CellComparatorImpl
.META_COMPARATOR
: CellComparatorImpl
.COMPARATOR
;