1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase;
20
21 import java.io.Serializable;
22 import java.util.Comparator;
23
24 import org.apache.hadoop.hbase.KeyValue.Type;
25 import org.apache.hadoop.hbase.classification.InterfaceAudience;
26 import org.apache.hadoop.hbase.classification.InterfaceStability;
27 import org.apache.hadoop.hbase.util.Bytes;
28
29 import com.google.common.primitives.Longs;
30
31
32
33
34
35
36
37
38 @edu.umd.cs.findbugs.annotations.SuppressWarnings(
39 value="UNKNOWN",
40 justification="Findbugs doesn't like the way we are negating the result of a compare in below")
41 @InterfaceAudience.Private
42 @InterfaceStability.Evolving
43 public class CellComparator implements Comparator<Cell>, Serializable {
44 private static final long serialVersionUID = -8760041766259623329L;
45
46 @Override
47 public int compare(Cell a, Cell b) {
48 return compare(a, b, false);
49 }
50
51
52
53
54
55
56
57
58
59
60
61 public static int compare(final Cell a, final Cell b, boolean ignoreSequenceid) {
62
63 int c = compareRows(a, b);
64 if (c != 0) return c;
65
66 c = compareWithoutRow(a, b);
67 if(c != 0) return c;
68
69 if (!ignoreSequenceid) {
70
71
72 return Longs.compare(b.getMvccVersion(), a.getMvccVersion());
73 } else {
74 return c;
75 }
76 }
77
78 public static int findCommonPrefixInRowPart(Cell left, Cell right, int rowCommonPrefix) {
79 return findCommonPrefix(left.getRowArray(), right.getRowArray(), left.getRowLength()
80 - rowCommonPrefix, right.getRowLength() - rowCommonPrefix, left.getRowOffset()
81 + rowCommonPrefix, right.getRowOffset() + rowCommonPrefix);
82 }
83
84 private static int findCommonPrefix(byte[] left, byte[] right, int leftLength, int rightLength,
85 int leftOffset, int rightOffset) {
86 int length = Math.min(leftLength, rightLength);
87 int result = 0;
88
89 while (result < length && left[leftOffset + result] == right[rightOffset + result]) {
90 result++;
91 }
92 return result;
93 }
94
95 public static int findCommonPrefixInFamilyPart(Cell left, Cell right, int familyCommonPrefix) {
96 return findCommonPrefix(left.getFamilyArray(), right.getFamilyArray(), left.getFamilyLength()
97 - familyCommonPrefix, right.getFamilyLength() - familyCommonPrefix, left.getFamilyOffset()
98 + familyCommonPrefix, right.getFamilyOffset() + familyCommonPrefix);
99 }
100
101 public static int findCommonPrefixInQualifierPart(Cell left, Cell right,
102 int qualifierCommonPrefix) {
103 return findCommonPrefix(left.getQualifierArray(), right.getQualifierArray(),
104 left.getQualifierLength() - qualifierCommonPrefix, right.getQualifierLength()
105 - qualifierCommonPrefix, left.getQualifierOffset() + qualifierCommonPrefix,
106 right.getQualifierOffset() + qualifierCommonPrefix);
107 }
108
109
110
111 public static boolean equals(Cell a, Cell b){
112 return equalsRow(a, b)
113 && equalsFamily(a, b)
114 && equalsQualifier(a, b)
115 && equalsTimestamp(a, b)
116 && equalsType(a, b);
117 }
118
119 public static boolean equalsRow(Cell a, Cell b){
120 return Bytes.equals(
121 a.getRowArray(), a.getRowOffset(), a.getRowLength(),
122 b.getRowArray(), b.getRowOffset(), b.getRowLength());
123 }
124
125 public static boolean equalsFamily(Cell a, Cell b){
126 return Bytes.equals(
127 a.getFamilyArray(), a.getFamilyOffset(), a.getFamilyLength(),
128 b.getFamilyArray(), b.getFamilyOffset(), b.getFamilyLength());
129 }
130
131 public static boolean equalsQualifier(Cell a, Cell b){
132 return Bytes.equals(
133 a.getQualifierArray(), a.getQualifierOffset(), a.getQualifierLength(),
134 b.getQualifierArray(), b.getQualifierOffset(), b.getQualifierLength());
135 }
136
137 public static boolean equalsTimestamp(Cell a, Cell b){
138 return a.getTimestamp() == b.getTimestamp();
139 }
140
141 public static boolean equalsType(Cell a, Cell b){
142 return a.getTypeByte() == b.getTypeByte();
143 }
144
145 public static int compareColumns(final Cell left, final Cell right) {
146 int lfoffset = left.getFamilyOffset();
147 int rfoffset = right.getFamilyOffset();
148 int lclength = left.getQualifierLength();
149 int rclength = right.getQualifierLength();
150 int lfamilylength = left.getFamilyLength();
151 int rfamilylength = right.getFamilyLength();
152 int diff = compare(left.getFamilyArray(), lfoffset, lfamilylength, right.getFamilyArray(),
153 rfoffset, rfamilylength);
154 if (diff != 0) {
155 return diff;
156 } else {
157 return compare(left.getQualifierArray(), left.getQualifierOffset(), lclength,
158 right.getQualifierArray(), right.getQualifierOffset(), rclength);
159 }
160 }
161
162 public static int compareFamilies(Cell left, Cell right) {
163 return Bytes.compareTo(left.getFamilyArray(), left.getFamilyOffset(), left.getFamilyLength(),
164 right.getFamilyArray(), right.getFamilyOffset(), right.getFamilyLength());
165 }
166
167 public static int compareQualifiers(Cell left, Cell right) {
168 return Bytes.compareTo(left.getQualifierArray(), left.getQualifierOffset(),
169 left.getQualifierLength(), right.getQualifierArray(), right.getQualifierOffset(),
170 right.getQualifierLength());
171 }
172
173 public int compareFlatKey(Cell left, Cell right) {
174 int compare = compareRows(left, right);
175 if (compare != 0) {
176 return compare;
177 }
178 return compareWithoutRow(left, right);
179 }
180
181
182
183
184
185 public static int compareRows(final Cell left, final Cell right) {
186 return Bytes.compareTo(left.getRowArray(), left.getRowOffset(), left.getRowLength(),
187 right.getRowArray(), right.getRowOffset(), right.getRowLength());
188 }
189
190
191
192
193
194 public static int compareRows(byte[] left, int loffset, int llength, byte[] right, int roffset,
195 int rlength) {
196 return Bytes.compareTo(left, loffset, llength, right, roffset, rlength);
197 }
198
199 public static int compareWithoutRow(final Cell leftCell, final Cell rightCell) {
200
201
202
203
204
205
206
207 if (leftCell.getFamilyLength() + leftCell.getQualifierLength() == 0
208 && leftCell.getTypeByte() == Type.Minimum.getCode()) {
209
210 return 1;
211 }
212 if (rightCell.getFamilyLength() + rightCell.getQualifierLength() == 0
213 && rightCell.getTypeByte() == Type.Minimum.getCode()) {
214 return -1;
215 }
216 boolean sameFamilySize = (leftCell.getFamilyLength() == rightCell.getFamilyLength());
217 if (!sameFamilySize) {
218
219
220 return Bytes.compareTo(leftCell.getFamilyArray(), leftCell.getFamilyOffset(),
221 leftCell.getFamilyLength(), rightCell.getFamilyArray(), rightCell.getFamilyOffset(),
222 rightCell.getFamilyLength());
223 }
224 int diff = compareColumns(leftCell, rightCell);
225 if (diff != 0) return diff;
226
227 diff = compareTimestamps(leftCell, rightCell);
228 if (diff != 0) return diff;
229
230
231
232
233
234 return (0xff & rightCell.getTypeByte()) - (0xff & leftCell.getTypeByte());
235 }
236
237
238
239
240
241
242
243
244
245
246
247 public static int compareTimestamps(final Cell left, final Cell right) {
248 return compareTimestamps(left.getTimestamp(), right.getTimestamp());
249 }
250
251
252
253
254
255
256 public static int hashCode(Cell cell){
257 if (cell == null) {
258 return 0;
259 }
260
261 int hash = calculateHashForKeyValue(cell);
262 hash = 31 * hash + (int)cell.getMvccVersion();
263 return hash;
264 }
265
266
267
268
269
270
271
272
273 public static int hashCodeIgnoreMvcc(Cell cell) {
274 if (cell == null) {
275 return 0;
276 }
277
278 int hash = calculateHashForKeyValue(cell);
279 return hash;
280 }
281
282 private static int calculateHashForKeyValue(Cell cell) {
283
284 int rowHash = Bytes.hashCode(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
285 int familyHash =
286 Bytes.hashCode(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength());
287 int qualifierHash = Bytes.hashCode(cell.getQualifierArray(), cell.getQualifierOffset(),
288 cell.getQualifierLength());
289
290
291 int hash = 31 * rowHash + familyHash;
292 hash = 31 * hash + qualifierHash;
293 hash = 31 * hash + (int)cell.getTimestamp();
294 hash = 31 * hash + cell.getTypeByte();
295 return hash;
296 }
297
298
299
300
301 public static boolean areKeyLengthsEqual(Cell a, Cell b) {
302 return a.getRowLength() == b.getRowLength()
303 && a.getFamilyLength() == b.getFamilyLength()
304 && a.getQualifierLength() == b.getQualifierLength();
305 }
306
307 public static boolean areRowLengthsEqual(Cell a, Cell b) {
308 return a.getRowLength() == b.getRowLength();
309 }
310
311
312
313
314 private static int compare(byte[] left, int leftOffset, int leftLength, byte[] right,
315 int rightOffset, int rightLength) {
316 return Bytes.compareTo(left, leftOffset, leftLength, right, rightOffset, rightLength);
317 }
318
319 public static int compareCommonRowPrefix(Cell left, Cell right, int rowCommonPrefix) {
320 return compare(left.getRowArray(), left.getRowOffset() + rowCommonPrefix, left.getRowLength()
321 - rowCommonPrefix, right.getRowArray(), right.getRowOffset() + rowCommonPrefix,
322 right.getRowLength() - rowCommonPrefix);
323 }
324
325 public static int compareCommonFamilyPrefix(Cell left, Cell right,
326 int familyCommonPrefix) {
327 return compare(left.getFamilyArray(), left.getFamilyOffset() + familyCommonPrefix,
328 left.getFamilyLength() - familyCommonPrefix, right.getFamilyArray(),
329 right.getFamilyOffset() + familyCommonPrefix,
330 right.getFamilyLength() - familyCommonPrefix);
331 }
332
333 public static int compareCommonQualifierPrefix(Cell left, Cell right,
334 int qualCommonPrefix) {
335 return compare(left.getQualifierArray(), left.getQualifierOffset() + qualCommonPrefix,
336 left.getQualifierLength() - qualCommonPrefix, right.getQualifierArray(),
337 right.getQualifierOffset() + qualCommonPrefix, right.getQualifierLength()
338 - qualCommonPrefix);
339 }
340
341
342
343
344
345 public static boolean equalsIgnoreMvccVersion(Cell a, Cell b){
346 return 0 == compareStaticIgnoreMvccVersion(a, b);
347 }
348
349 private static int compareStaticIgnoreMvccVersion(Cell a, Cell b) {
350
351 int c = compareRows(a, b);
352 if (c != 0) return c;
353
354
355 c = compareColumns(a, b);
356 if (c != 0) return c;
357
358
359 c = compareTimestamps(a, b);
360 if (c != 0) return c;
361
362
363 c = (0xff & b.getTypeByte()) - (0xff & a.getTypeByte());
364 return c;
365 }
366
367
368
369
370
371
372
373
374
375
376
377 private static int compareTimestamps(final long ltimestamp, final long rtimestamp) {
378 if (ltimestamp < rtimestamp) {
379 return 1;
380 } else if (ltimestamp > rtimestamp) {
381 return -1;
382 }
383 return 0;
384 }
385
386
387
388
389 public static class RowComparator extends CellComparator {
390 @Override
391 public int compare(Cell a, Cell b) {
392 return compareRows(a, b);
393 }
394 }
395
396
397
398
399
400
401
402
403
404
405
406 public static Cell getMidpoint(final KeyValue.KVComparator comparator, final Cell left,
407 final Cell right) {
408
409
410 if (right == null) {
411 throw new IllegalArgumentException("right cell can not be null");
412 }
413 if (left == null) {
414 return right;
415 }
416
417
418
419 if (comparator != null && comparator instanceof KeyValue.MetaComparator) {
420 return right;
421 }
422 int diff = compareRows(left, right);
423 if (diff > 0) {
424 throw new IllegalArgumentException("Left row sorts after right row; left=" +
425 CellUtil.getCellKeyAsString(left) + ", right=" + CellUtil.getCellKeyAsString(right));
426 }
427 if (diff < 0) {
428
429 byte [] midRow = getMinimumMidpointArray(left.getRowArray(), left.getRowOffset(),
430 left.getRowLength(),
431 right.getRowArray(), right.getRowOffset(), right.getRowLength());
432
433 if (midRow == null) return right;
434 return CellUtil.createCell(midRow);
435 }
436
437 diff = compareFamilies(left, right);
438 if (diff > 0) {
439 throw new IllegalArgumentException("Left family sorts after right family; left=" +
440 CellUtil.getCellKeyAsString(left) + ", right=" + CellUtil.getCellKeyAsString(right));
441 }
442 if (diff < 0) {
443 byte [] midRow = getMinimumMidpointArray(left.getFamilyArray(), left.getFamilyOffset(),
444 left.getFamilyLength(),
445 right.getFamilyArray(), right.getFamilyOffset(), right.getFamilyLength());
446
447 if (midRow == null) return right;
448
449 return CellUtil.createCell(right.getRowArray(), right.getRowOffset(), right.getRowLength(),
450 midRow, 0, midRow.length, HConstants.EMPTY_BYTE_ARRAY, 0,
451 HConstants.EMPTY_BYTE_ARRAY.length);
452 }
453
454 diff = compareQualifiers(left, right);
455 if (diff > 0) {
456 throw new IllegalArgumentException("Left qualifier sorts after right qualifier; left=" +
457 CellUtil.getCellKeyAsString(left) + ", right=" + CellUtil.getCellKeyAsString(right));
458 }
459 if (diff < 0) {
460 byte [] midRow = getMinimumMidpointArray(left.getQualifierArray(), left.getQualifierOffset(),
461 left.getQualifierLength(),
462 right.getQualifierArray(), right.getQualifierOffset(), right.getQualifierLength());
463
464 if (midRow == null) return right;
465
466 return CellUtil.createCell(right.getRowArray(), right.getRowOffset(), right.getRowLength(),
467 right.getFamilyArray(), right.getFamilyOffset(), right.getFamilyLength(),
468 midRow, 0, midRow.length);
469 }
470
471 return right;
472 }
473
474
475
476
477
478
479
480
481
482
483
484 private static byte [] getMinimumMidpointArray(final byte [] leftArray, final int leftOffset,
485 final int leftLength,
486 final byte [] rightArray, final int rightOffset, final int rightLength) {
487
488 int minLength = leftLength < rightLength ? leftLength : rightLength;
489 int diffIdx = 0;
490 while (diffIdx < minLength &&
491 leftArray[leftOffset + diffIdx] == rightArray[rightOffset + diffIdx]) {
492 diffIdx++;
493 }
494 byte [] minimumMidpointArray = null;
495 if (diffIdx >= minLength) {
496
497 minimumMidpointArray = new byte[diffIdx + 1];
498 System.arraycopy(rightArray, rightOffset, minimumMidpointArray, 0, diffIdx + 1);
499 } else {
500 int diffByte = leftArray[leftOffset + diffIdx];
501 if ((0xff & diffByte) < 0xff && (diffByte + 1) < (rightArray[rightOffset + diffIdx] & 0xff)) {
502 minimumMidpointArray = new byte[diffIdx + 1];
503 System.arraycopy(leftArray, leftOffset, minimumMidpointArray, 0, diffIdx);
504 minimumMidpointArray[diffIdx] = (byte) (diffByte + 1);
505 } else {
506 minimumMidpointArray = new byte[diffIdx + 1];
507 System.arraycopy(rightArray, rightOffset, minimumMidpointArray, 0, diffIdx + 1);
508 }
509 }
510 return minimumMidpointArray;
511 }
512 }