001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase; 019 020import java.nio.ByteBuffer; 021import java.util.Comparator; 022import org.apache.hadoop.hbase.KeyValue.Type; 023import org.apache.hadoop.hbase.util.ByteBufferUtils; 024import org.apache.hadoop.hbase.util.Bytes; 025import org.apache.yetus.audience.InterfaceAudience; 026import org.apache.yetus.audience.InterfaceStability; 027import org.slf4j.Logger; 028import org.slf4j.LoggerFactory; 029import org.apache.hbase.thirdparty.com.google.common.primitives.Longs; 030 031/** 032 * Compare two HBase cells. Do not use this method comparing <code>-ROOT-</code> or 033 * <code>hbase:meta</code> cells. Cells from these tables need a specialized comparator, one that 034 * takes account of the special formatting of the row where we have commas to delimit table from 035 * regionname, from row. See KeyValue for how it has a special comparator to do hbase:meta cells 036 * and yet another for -ROOT-. 037 * <p>While using this comparator for {{@link #compareRows(Cell, Cell)} et al, the hbase:meta cells 038 * format should be taken into consideration, for which the instance of this comparator 039 * should be used. In all other cases the static APIs in this comparator would be enough 040 * <p>HOT methods. We spend a good portion of CPU comparing. Anything that makes the compare 041 * faster will likely manifest at the macro level. See also 042 * {@link BBKVComparator}. Use it when mostly {@link ByteBufferKeyValue}s. 043 * </p> 044 */ 045@edu.umd.cs.findbugs.annotations.SuppressWarnings( 046 value="UNKNOWN", 047 justification="Findbugs doesn't like the way we are negating the result of a compare in below") 048@InterfaceAudience.Private 049@InterfaceStability.Evolving 050public class CellComparatorImpl implements CellComparator { 051 static final Logger LOG = LoggerFactory.getLogger(CellComparatorImpl.class); 052 053 /** 054 * Comparator for plain key/values; i.e. non-catalog table key/values. Works on Key portion 055 * of KeyValue only. 056 */ 057 public static final CellComparatorImpl COMPARATOR = new CellComparatorImpl(); 058 059 /** 060 * A {@link CellComparatorImpl} for <code>hbase:meta</code> catalog table 061 * {@link KeyValue}s. 062 */ 063 public static final CellComparatorImpl META_COMPARATOR = new MetaCellComparator(); 064 065 @Override 066 public final int compare(final Cell a, final Cell b) { 067 return compare(a, b, false); 068 } 069 070 @Override 071 public int compare(final Cell a, final Cell b, boolean ignoreSequenceid) { 072 073 int diff = 0; 074 // "Peel off" the most common path. 075 if (a instanceof ByteBufferKeyValue && b instanceof ByteBufferKeyValue) { 076 diff = BBKVComparator.compare((ByteBufferKeyValue)a, (ByteBufferKeyValue)b, ignoreSequenceid); 077 if (diff != 0) { 078 return diff; 079 } 080 } else { 081 diff = compareRows(a, b); 082 if (diff != 0) { 083 return diff; 084 } 085 086 diff = compareWithoutRow(a, b); 087 if (diff != 0) { 088 return diff; 089 } 090 } 091 092 // Negate following comparisons so later edits show up first mvccVersion: later sorts first 093 return ignoreSequenceid? diff: Long.compare(b.getSequenceId(), a.getSequenceId()); 094 } 095 096 /** 097 * Compares the family and qualifier part of the cell 098 * @return 0 if both cells are equal, 1 if left cell is bigger than right, -1 otherwise 099 */ 100 public final int compareColumns(final Cell left, final Cell right) { 101 int diff = compareFamilies(left, right); 102 if (diff != 0) { 103 return diff; 104 } 105 return compareQualifiers(left, right); 106 } 107 108 /** 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 111 */ 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()); 119 } 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()); 124 } 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()); 134 } 135 return Bytes.compareTo(left.getFamilyArray(), left.getFamilyOffset(), left.getFamilyLength(), 136 right.getFamilyArray(), right.getFamilyOffset(), right.getFamilyLength()); 137 } 138 139 /** 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 142 */ 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()); 152 } 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()); 157 } 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()); 167 } 168 return Bytes.compareTo(left.getQualifierArray(), left.getQualifierOffset(), 169 left.getQualifierLength(), right.getQualifierArray(), right.getQualifierOffset(), 170 right.getQualifierLength()); 171 } 172 173 /** 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 178 */ 179 @Override 180 public int compareRows(final Cell left, final Cell right) { 181 return compareRows(left, left.getRowLength(), right, right.getRowLength()); 182 } 183 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; 188 } 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); 194 } 195 if (left instanceof ByteBufferExtendedCell) { 196 return ByteBufferUtils.compareTo(((ByteBufferExtendedCell) left).getRowByteBuffer(), 197 ((ByteBufferExtendedCell) left).getRowPosition(), leftRowLength, 198 right.getRowArray(), right.getRowOffset(), rightRowLength); 199 } 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); 208 } 209 return Bytes.compareTo(left.getRowArray(), left.getRowOffset(), left.getRowLength(), 210 right.getRowArray(), right.getRowOffset(), right.getRowLength()); 211 } 212 213 /** 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 217 * 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 228 */ 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); 235 } 236 return Bytes.compareTo(left.getRowArray(), left.getRowOffset(), left.getRowLength(), right, 237 roffset, rlength); 238 } 239 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; 256 } 257 if (rFamLength + rQualLength == 0 258 && right.getTypeByte() == Type.Minimum.getCode()) { 259 return -1; 260 } 261 if (lFamLength != rFamLength) { 262 // comparing column family is enough. 263 return compareFamilies(left, right); 264 } 265 // Compare cf:qualifier 266 int diff = compareColumns(left, right); 267 if (diff != 0) { 268 return diff; 269 } 270 271 diff = compareTimestamps(left.getTimestamp(), right.getTimestamp()); 272 if (diff != 0) { 273 return diff; 274 } 275 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()); 281 } 282 283 @Override 284 public int compareTimestamps(final Cell left, final Cell right) { 285 return compareTimestamps(left.getTimestamp(), right.getTimestamp()); 286 } 287 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); 292 } 293 294 /** 295 * A {@link CellComparatorImpl} for <code>hbase:meta</code> catalog table 296 * {@link KeyValue}s. 297 */ 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()); 304 } 305 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); 310 } 311 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; 317 } 318 319 diff = compareWithoutRow(a, b); 320 if (diff != 0) { 321 return diff; 322 } 323 324 // Negate following comparisons so later edits show up first mvccVersion: later sorts first 325 return ignoreSequenceid? diff: Longs.compare(b.getSequenceId(), a.getSequenceId()); 326 } 327 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; 346 } 347 } 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; 369 } 370 } 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; 377 } 378 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); 394 } 395 // Reverse result since we swap the order of the params we pass below. 396 return -compareRows(cell, array, offset, len); 397 } 398 399 @Override 400 public Comparator getSimpleComparator() { 401 return this; 402 } 403 } 404 405 @Override 406 public Comparator getSimpleComparator() { 407 return new BBKVComparator(this); 408 } 409 410 /** 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. 414 */ 415 public static CellComparator getCellComparator(TableName tableName) { 416 return getCellComparator(tableName.toBytes()); 417 } 418 419 /** 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. 423 */ 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; 428 } 429}