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 */
018
019package org.apache.hadoop.hbase;
020
021import java.nio.ByteBuffer;
022import java.util.Comparator;
023
024import org.apache.hadoop.hbase.util.ByteBufferUtils;
025import org.apache.hadoop.hbase.util.Bytes;
026import org.apache.yetus.audience.InterfaceAudience;
027import org.apache.yetus.audience.InterfaceStability;
028
029import org.apache.hbase.thirdparty.com.google.common.primitives.Longs;
030
031/**
032 * A {@link CellComparatorImpl} for <code>hbase:meta</code> catalog table
033 * {@link KeyValue}s.
034 */
035@InterfaceAudience.Private
036@InterfaceStability.Evolving
037public class MetaCellComparator extends CellComparatorImpl {
038
039  /**
040   * A {@link MetaCellComparator} for <code>hbase:meta</code> catalog table
041   * {@link KeyValue}s.
042   */
043  public static final MetaCellComparator META_COMPARATOR = new MetaCellComparator();
044
045  // TODO: Do we need a ByteBufferKeyValue version of this?
046  @Override
047  public int compareRows(final Cell left, final Cell right) {
048    return compareRows(left.getRowArray(), left.getRowOffset(), left.getRowLength(),
049      right.getRowArray(), right.getRowOffset(), right.getRowLength());
050  }
051
052  @Override
053  public int compareRows(Cell left, byte[] right, int roffset, int rlength) {
054    return compareRows(left.getRowArray(), left.getRowOffset(), left.getRowLength(), right, roffset,
055      rlength);
056  }
057
058  @Override
059  public int compare(final Cell a, final Cell b, boolean ignoreSequenceid) {
060    int diff = compareRows(a, b);
061    if (diff != 0) {
062      return diff;
063    }
064
065    diff = compareWithoutRow(a, b);
066    if (diff != 0) {
067      return diff;
068    }
069
070    // Negate following comparisons so later edits show up first mvccVersion: later sorts first
071    return ignoreSequenceid ? diff : Longs.compare(b.getSequenceId(), a.getSequenceId());
072  }
073
074  private static int compareRows(byte[] left, int loffset, int llength, byte[] right, int roffset,
075      int rlength) {
076    int leftDelimiter = Bytes.searchDelimiterIndex(left, loffset, llength, HConstants.DELIMITER);
077    int rightDelimiter = Bytes.searchDelimiterIndex(right, roffset, rlength, HConstants.DELIMITER);
078    // Compare up to the delimiter
079    int lpart = (leftDelimiter < 0 ? llength : leftDelimiter - loffset);
080    int rpart = (rightDelimiter < 0 ? rlength : rightDelimiter - roffset);
081    int result = Bytes.compareTo(left, loffset, lpart, right, roffset, rpart);
082    if (result != 0) {
083      return result;
084    } else {
085      if (leftDelimiter < 0 && rightDelimiter >= 0) {
086        return -1;
087      } else if (rightDelimiter < 0 && leftDelimiter >= 0) {
088        return 1;
089      } else if (leftDelimiter < 0) {
090        return 0;
091      }
092    }
093    // Compare middle bit of the row.
094    // Move past delimiter
095    leftDelimiter++;
096    rightDelimiter++;
097    int leftFarDelimiter = Bytes
098      .searchDelimiterIndexInReverse(left, leftDelimiter, llength - (leftDelimiter - loffset),
099        HConstants.DELIMITER);
100    int rightFarDelimiter = Bytes
101      .searchDelimiterIndexInReverse(right, rightDelimiter, rlength - (rightDelimiter - roffset),
102        HConstants.DELIMITER);
103    // Now compare middlesection of row.
104    lpart = (leftFarDelimiter < 0 ? llength + loffset : leftFarDelimiter) - leftDelimiter;
105    rpart = (rightFarDelimiter < 0 ? rlength + roffset : rightFarDelimiter) - rightDelimiter;
106    result = Bytes.compareTo(left, leftDelimiter, lpart, right, rightDelimiter, rpart);
107    if (result != 0) {
108      return result;
109    } else {
110      if (leftDelimiter < 0 && rightDelimiter >= 0) {
111        return -1;
112      } else if (rightDelimiter < 0 && leftDelimiter >= 0) {
113        return 1;
114      } else if (leftDelimiter < 0) {
115        return 0;
116      }
117    }
118    // Compare last part of row, the rowid.
119    leftFarDelimiter++;
120    rightFarDelimiter++;
121    result = Bytes.compareTo(left, leftFarDelimiter, llength - (leftFarDelimiter - loffset), right,
122      rightFarDelimiter, rlength - (rightFarDelimiter - roffset));
123    return result;
124  }
125
126  @Override
127  public int compareRows(ByteBuffer row, Cell cell) {
128    byte[] array;
129    int offset;
130    int len = row.remaining();
131    if (row.hasArray()) {
132      array = row.array();
133      offset = row.position() + row.arrayOffset();
134    } else {
135      // We copy the row array if offheap just so we can do a compare. We do this elsewhere too
136      // in BBUtils when Cell is backed by an offheap ByteBuffer. Needs fixing so no copy. TODO.
137      array = new byte[len];
138      offset = 0;
139      ByteBufferUtils.copyFromBufferToArray(array, row, row.position(), 0, len);
140    }
141    // Reverse result since we swap the order of the params we pass below.
142    return -compareRows(cell, array, offset, len);
143  }
144
145  @Override
146  public Comparator getSimpleComparator() {
147    return this;
148  }
149
150}