HBASE-24163 MOB compactor implementations should use format specifiers when calling...
[hbase.git] / hbase-common / src / main / java / org / apache / hadoop / hbase / CellComparatorImpl.java
blobe6c8e3ded62a58e500adc34de28b1b0ba2c98ff3
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.
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;
31 /**
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.
43 * </p>
45 @edu.umd.cs.findbugs.annotations.SuppressWarnings(
46 value="UNKNOWN",
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);
53 /**
54 * Comparator for plain key/values; i.e. non-catalog table key/values. Works on Key portion
55 * of KeyValue only.
57 public static final CellComparatorImpl COMPARATOR = new CellComparatorImpl();
59 /**
60 * A {@link CellComparatorImpl} for <code>hbase:meta</code> catalog table
61 * {@link KeyValue}s.
63 public static final CellComparatorImpl META_COMPARATOR = new MetaCellComparator();
65 @Override
66 public final int compare(final Cell a, final Cell b) {
67 return compare(a, b, false);
70 @Override
71 public int compare(final Cell a, final Cell b, boolean ignoreSequenceid) {
73 int diff = 0;
74 // "Peel off" the most common path.
75 if (a instanceof ByteBufferKeyValue && b instanceof ByteBufferKeyValue) {
76 diff = BBKVComparator.compare((ByteBufferKeyValue)a, (ByteBufferKeyValue)b, ignoreSequenceid);
77 if (diff != 0) {
78 return diff;
80 } else {
81 diff = compareRows(a, b);
82 if (diff != 0) {
83 return diff;
86 diff = compareWithoutRow(a, b);
87 if (diff != 0) {
88 return diff;
92 // Negate following comparisons so later edits show up first mvccVersion: later sorts first
93 return ignoreSequenceid? diff: Long.compare(b.getSequenceId(), a.getSequenceId());
96 /**
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);
102 if (diff != 0) {
103 return diff;
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
112 @Override
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
143 @Override
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
179 @Override
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
186 if (left == right) {
187 return 0;
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
218 * @param left
219 * the cell to be compared
220 * @param right
221 * the kv serialized byte[] to be compared with
222 * @param roffset
223 * the offset in the byte[]
224 * @param rlength
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
229 @Override
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,
234 roffset, rlength);
236 return Bytes.compareTo(left.getRowArray(), left.getRowOffset(), left.getRowLength(), right,
237 roffset, rlength);
240 @Override
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
255 return 1;
257 if (rFamLength + rQualLength == 0
258 && right.getTypeByte() == Type.Minimum.getCode()) {
259 return -1;
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);
267 if (diff != 0) {
268 return diff;
271 diff = compareTimestamps(left.getTimestamp(), right.getTimestamp());
272 if (diff != 0) {
273 return diff;
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
279 // everything.
280 return (0xff & right.getTypeByte()) - (0xff & left.getTypeByte());
283 @Override
284 public int compareTimestamps(final Cell left, final Cell right) {
285 return compareTimestamps(left.getTimestamp(), right.getTimestamp());
288 @Override
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
296 * {@link KeyValue}s.
298 public static class MetaCellComparator extends CellComparatorImpl {
299 // TODO: Do we need a ByteBufferKeyValue version of this?
300 @Override
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());
306 @Override
307 public int compareRows(Cell left, byte[] right, int roffset, int rlength) {
308 return compareRows(left.getRowArray(), left.getRowOffset(), left.getRowLength(), right,
309 roffset, rlength);
312 @Override
313 public int compare(final Cell a, final Cell b, boolean ignoreSequenceid) {
314 int diff = compareRows(a, b);
315 if (diff != 0) {
316 return diff;
319 diff = compareWithoutRow(a, b);
320 if (diff != 0) {
321 return diff;
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,
329 int rlength) {
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);
337 if (result != 0) {
338 return result;
339 } else {
340 if (leftDelimiter < 0 && rightDelimiter >= 0) {
341 return -1;
342 } else if (rightDelimiter < 0 && leftDelimiter >= 0) {
343 return 1;
344 } else if (leftDelimiter < 0) {
345 return 0;
348 // Compare middle bit of the row.
349 // Move past delimiter
350 leftDelimiter++;
351 rightDelimiter++;
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);
360 if (result != 0) {
361 return result;
362 } else {
363 if (leftDelimiter < 0 && rightDelimiter >= 0) {
364 return -1;
365 } else if (rightDelimiter < 0 && leftDelimiter >= 0) {
366 return 1;
367 } else if (leftDelimiter < 0) {
368 return 0;
371 // Compare last part of row, the rowid.
372 leftFarDelimiter++;
373 rightFarDelimiter++;
374 result = Bytes.compareTo(left, leftFarDelimiter, llength - (leftFarDelimiter - loffset),
375 right, rightFarDelimiter, rlength - (rightFarDelimiter - roffset));
376 return result;
379 @Override
380 public int compareRows(ByteBuffer row, Cell cell) {
381 byte [] array;
382 int offset;
383 int len = row.remaining();
384 if (row.hasArray()) {
385 array = row.array();
386 offset = row.position() + row.arrayOffset();
387 } else {
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];
391 offset = 0;
392 ByteBufferUtils.copyFromBufferToArray(array, row, row.position(),
393 0, len);
395 // Reverse result since we swap the order of the params we pass below.
396 return -compareRows(cell, array, offset, len);
399 @Override
400 public Comparator getSimpleComparator() {
401 return this;
405 @Override
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;