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