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.util.ByteBufferUtils;
023import org.apache.hadoop.hbase.util.Bytes;
024import org.apache.yetus.audience.InterfaceAudience;
025import org.apache.yetus.audience.InterfaceStability;
026
027import org.apache.hbase.thirdparty.com.google.common.primitives.Longs;
028
029/**
030 * A {@link CellComparatorImpl} for <code>hbase:meta</code> catalog table {@link KeyValue}s.
031 */
032@InterfaceAudience.Private
033@InterfaceStability.Evolving
034public class MetaCellComparator extends CellComparatorImpl {
035
036  /**
037   * A {@link MetaCellComparator} for <code>hbase:meta</code> catalog table {@link KeyValue}s.
038   */
039  public static final MetaCellComparator META_COMPARATOR = new MetaCellComparator();
040
041  @Override
042  public int compareRows(final Cell left, final Cell right) {
043    if (left instanceof ByteBufferExtendedCell) {
044      ByteBufferExtendedCell bbLeft = (ByteBufferExtendedCell) left;
045      if (right instanceof ByteBufferExtendedCell) {
046        ByteBufferExtendedCell bbRight = (ByteBufferExtendedCell) right;
047        return compareBBRows(bbLeft.getRowByteBuffer(), bbLeft.getRowPosition(),
048          left.getRowLength(), bbRight.getRowByteBuffer(), bbRight.getRowPosition(),
049          right.getRowLength());
050      } else {
051        return compareBBAndBytesRows(bbLeft.getRowByteBuffer(), bbLeft.getRowPosition(),
052          left.getRowLength(), right.getRowArray(), right.getRowOffset(), right.getRowLength());
053      }
054    } else {
055      if (right instanceof ByteBufferExtendedCell) {
056        ByteBufferExtendedCell bbRight = (ByteBufferExtendedCell) right;
057        return -compareBBAndBytesRows(bbRight.getRowByteBuffer(), bbRight.getRowPosition(),
058          right.getRowLength(), left.getRowArray(), left.getRowOffset(), left.getRowLength());
059      } else {
060        return compareBytesRows(left.getRowArray(), left.getRowOffset(), left.getRowLength(),
061          right.getRowArray(), right.getRowOffset(), right.getRowLength());
062      }
063    }
064  }
065
066  @Override
067  public int compareRows(Cell left, byte[] right, int roffset, int rlength) {
068    if (left instanceof ByteBufferExtendedCell) {
069      ByteBufferExtendedCell bbLeft = (ByteBufferExtendedCell) left;
070      return compareBBAndBytesRows(bbLeft.getRowByteBuffer(), bbLeft.getRowPosition(),
071        left.getRowLength(), right, roffset, rlength);
072    } else {
073      return compareBytesRows(left.getRowArray(), left.getRowOffset(), left.getRowLength(), right,
074        roffset, rlength);
075    }
076  }
077
078  @Override
079  public int compareRows(byte[] leftRow, byte[] rightRow) {
080    return compareBytesRows(leftRow, 0, leftRow.length, rightRow, 0, rightRow.length);
081  }
082
083  @Override
084  public int compare(final Cell a, final Cell b, boolean ignoreSequenceid) {
085    int diff = compareRows(a, b);
086    if (diff != 0) {
087      return diff;
088    }
089
090    diff = compareWithoutRow(a, b);
091    if (diff != 0) {
092      return diff;
093    }
094
095    // Negate following comparisons so later edits show up first mvccVersion: later sorts first
096    return ignoreSequenceid ? diff : Longs.compare(b.getSequenceId(), a.getSequenceId());
097  }
098
099  @FunctionalInterface
100  private interface SearchDelimiter<T> {
101    int search(T t, int offset, int length, int delimiter);
102  }
103
104  @FunctionalInterface
105  private interface SearchDelimiterInReverse<T> {
106    int search(T t, int offset, int length, int delimiter);
107  }
108
109  @FunctionalInterface
110  private interface Compare<L, R> {
111    int compareTo(L left, int loffset, int llength, R right, int roffset, int rlength);
112  }
113
114  private static <L, R> int compareRows(L left, int loffset, int llength, R right, int roffset,
115    int rlength, SearchDelimiter<L> searchLeft, SearchDelimiter<R> searchRight,
116    SearchDelimiterInReverse<L> searchInReverseLeft,
117    SearchDelimiterInReverse<R> searchInReverseRight, Compare<L, R> comparator) {
118    int leftDelimiter = searchLeft.search(left, loffset, llength, HConstants.DELIMITER);
119    int rightDelimiter = searchRight.search(right, roffset, rlength, HConstants.DELIMITER);
120    // Compare up to the delimiter
121    int lpart = (leftDelimiter < 0 ? llength : leftDelimiter - loffset);
122    int rpart = (rightDelimiter < 0 ? rlength : rightDelimiter - roffset);
123    int result = comparator.compareTo(left, loffset, lpart, right, roffset, rpart);
124    if (result != 0) {
125      return result;
126    } else {
127      if (leftDelimiter < 0 && rightDelimiter >= 0) {
128        return -1;
129      } else if (rightDelimiter < 0 && leftDelimiter >= 0) {
130        return 1;
131      } else if (leftDelimiter < 0) {
132        return 0;
133      }
134    }
135    // Compare middle bit of the row.
136    // Move past delimiter
137    leftDelimiter++;
138    rightDelimiter++;
139    int leftFarDelimiter = searchInReverseLeft.search(left, leftDelimiter,
140      llength - (leftDelimiter - loffset), HConstants.DELIMITER);
141    int rightFarDelimiter = searchInReverseRight.search(right, rightDelimiter,
142      rlength - (rightDelimiter - roffset), HConstants.DELIMITER);
143    // Now compare middlesection of row.
144    lpart = (leftFarDelimiter < 0 ? llength + loffset : leftFarDelimiter) - leftDelimiter;
145    rpart = (rightFarDelimiter < 0 ? rlength + roffset : rightFarDelimiter) - rightDelimiter;
146    result = comparator.compareTo(left, leftDelimiter, lpart, right, rightDelimiter, rpart);
147    if (result != 0) {
148      return result;
149    } else {
150      if (leftDelimiter < 0 && rightDelimiter >= 0) {
151        return -1;
152      } else if (rightDelimiter < 0 && leftDelimiter >= 0) {
153        return 1;
154      } else if (leftDelimiter < 0) {
155        return 0;
156      }
157    }
158    // Compare last part of row, the rowid.
159    leftFarDelimiter++;
160    rightFarDelimiter++;
161    result = comparator.compareTo(left, leftFarDelimiter, llength - (leftFarDelimiter - loffset),
162      right, rightFarDelimiter, rlength - (rightFarDelimiter - roffset));
163    return result;
164  }
165
166  private static int compareBBRows(ByteBuffer left, int loffset, int llength, ByteBuffer right,
167    int roffset, int rlength) {
168    if (left.hasArray()) {
169      return -compareBBAndBytesRows(right, roffset, rlength, left.array(),
170        left.arrayOffset() + loffset, llength);
171    }
172    if (right.hasArray()) {
173      return compareBBAndBytesRows(left, loffset, llength, right.array(),
174        right.arrayOffset() + roffset, rlength);
175    }
176    return compareRows(left, loffset, llength, right, roffset, rlength,
177      ByteBufferUtils::searchDelimiterIndex, ByteBufferUtils::searchDelimiterIndex,
178      ByteBufferUtils::searchDelimiterIndexInReverse,
179      ByteBufferUtils::searchDelimiterIndexInReverse, ByteBufferUtils::compareTo);
180  }
181
182  private static int compareBBAndBytesRows(ByteBuffer left, int loffset, int llength, byte[] right,
183    int roffset, int rlength) {
184    if (left.hasArray()) {
185      return compareBytesRows(left.array(), left.arrayOffset() + loffset, llength, right, roffset,
186        rlength);
187    }
188    return compareRows(left, loffset, llength, right, roffset, rlength,
189      ByteBufferUtils::searchDelimiterIndex, Bytes::searchDelimiterIndex,
190      ByteBufferUtils::searchDelimiterIndexInReverse, Bytes::searchDelimiterIndexInReverse,
191      ByteBufferUtils::compareTo);
192  }
193
194  private static int compareBytesRows(byte[] left, int loffset, int llength, byte[] right,
195    int roffset, int rlength) {
196    return compareRows(left, loffset, llength, right, roffset, rlength, Bytes::searchDelimiterIndex,
197      Bytes::searchDelimiterIndex, Bytes::searchDelimiterIndexInReverse,
198      Bytes::searchDelimiterIndexInReverse, Bytes::compareTo);
199  }
200
201  @Override
202  public int compareRows(ByteBuffer row, Cell cell) {
203    if (cell instanceof ByteBufferExtendedCell) {
204      ByteBufferExtendedCell bbCell = (ByteBufferExtendedCell) cell;
205      return compareBBRows(row, row.position(), row.remaining(), bbCell.getRowByteBuffer(),
206        bbCell.getRowPosition(), cell.getRowLength());
207    } else {
208      return compareBBAndBytesRows(row, row.position(), row.remaining(), cell.getRowArray(),
209        cell.getRowOffset(), cell.getRowLength());
210    }
211  }
212
213  @Override
214  public Comparator getSimpleComparator() {
215    return this;
216  }
217
218}