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 static org.junit.jupiter.api.Assertions.assertEquals;
021import static org.junit.jupiter.api.Assertions.assertTrue;
022
023import java.nio.ByteBuffer;
024import java.util.Collections;
025import java.util.Set;
026import java.util.TreeSet;
027import org.apache.hadoop.hbase.testclassification.MiscTests;
028import org.apache.hadoop.hbase.testclassification.SmallTests;
029import org.apache.hadoop.hbase.util.Bytes;
030import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
031import org.junit.jupiter.api.Tag;
032import org.junit.jupiter.api.Test;
033
034@Tag(MiscTests.TAG)
035@Tag(SmallTests.TAG)
036public class TestCellComparator {
037
038  private CellComparator comparator = CellComparator.getInstance();
039  private CellComparator innerStoreComparator = InnerStoreCellComparator.INNER_STORE_COMPARATOR;
040
041  byte[] row1 = Bytes.toBytes("row1");
042  byte[] row2 = Bytes.toBytes("row2");
043  byte[] row_1_0 = Bytes.toBytes("row10");
044
045  byte[] fam0 = HConstants.EMPTY_BYTE_ARRAY;
046  byte[] fam1 = Bytes.toBytes("fam1");
047  byte[] fam2 = Bytes.toBytes("fam2");
048  byte[] fam_1_2 = Bytes.toBytes("fam12");
049
050  byte[] qual1 = Bytes.toBytes("qual1");
051  byte[] qual2 = Bytes.toBytes("qual2");
052
053  byte[] val = Bytes.toBytes("val");
054
055  @Test
056  public void testCompareCells() {
057    KeyValue kv1 = new KeyValue(row1, fam1, qual1, val);
058    KeyValue kv2 = new KeyValue(row2, fam1, qual1, val);
059    assertTrue(comparator.compare(kv1, kv2) < 0);
060
061    kv1 = new KeyValue(row1, fam2, qual1, val);
062    kv2 = new KeyValue(row1, fam1, qual1, val);
063    assertTrue(comparator.compareFamilies(kv1, kv2) > 0);
064
065    kv1 = new KeyValue(row1, fam1, qual1, 1L, val);
066    kv2 = new KeyValue(row1, fam1, qual1, 2L, val);
067    assertTrue(comparator.compare(kv1, kv2) > 0);
068
069    kv1 = new KeyValue(row1, fam1, qual1, 1L, KeyValue.Type.Put);
070    kv2 = new KeyValue(row1, fam1, qual1, 1L, KeyValue.Type.Maximum);
071    assertTrue(comparator.compare(kv1, kv2) > 0);
072
073    kv1 = new KeyValue(row1, fam1, qual1, 1L, KeyValue.Type.Put);
074    kv2 = new KeyValue(row1, fam1, qual1, 1L, KeyValue.Type.Put);
075    assertTrue(PrivateCellUtil.equals(kv1, kv2));
076  }
077
078  @Test
079  public void testCompareCellsWithEmptyFamily() {
080    KeyValue kv1 = new KeyValue(row1, fam0, qual1, val);
081    KeyValue kv2 = new KeyValue(row1, fam1, qual1, val);
082    assertTrue(comparator.compare(kv1, kv2) < 0);
083    assertTrue(innerStoreComparator.compare(kv1, kv2) < 0);
084
085    kv1 = new KeyValue(row1, fam0, qual2, val);
086    kv2 = new KeyValue(row1, fam0, qual1, val);
087    assertTrue(comparator.compare(kv1, kv2) > 0);
088    assertTrue(innerStoreComparator.compare(kv1, kv2) > 0);
089
090    kv1 = new KeyValue(row1, fam0, qual2, val);
091    kv2 = new KeyValue(row1, fam0, qual1, val);
092    assertTrue(comparator.compareFamilies(kv1, kv2) == 0);
093    assertTrue(innerStoreComparator.compareFamilies(kv1, kv2) == 0);
094
095    kv1 = new KeyValue(row1, fam1, qual2, val);
096    kv2 = new KeyValue(row1, fam1, qual1, val);
097    assertTrue(comparator.compareFamilies(kv1, kv2) == 0);
098    assertTrue(innerStoreComparator.compareFamilies(kv1, kv2) == 0);
099  }
100
101  @Test
102  public void testCompareCellWithKey() throws Exception {
103    KeyValue kv1 = new KeyValue(row1, fam1, qual1, val);
104    KeyValue kv2 = new KeyValue(row2, fam1, qual1, val);
105    assertTrue(PrivateCellUtil.compare(comparator, kv1, kv2.getKey(), 0, kv2.getKey().length) < 0);
106
107    kv1 = new KeyValue(row1, fam2, qual1, val);
108    kv2 = new KeyValue(row1, fam1, qual1, val);
109    assertTrue(PrivateCellUtil.compare(comparator, kv1, kv2.getKey(), 0, kv2.getKey().length) > 0);
110
111    kv1 = new KeyValue(row1, fam1, qual1, 1L, val);
112    kv2 = new KeyValue(row1, fam1, qual1, 2L, val);
113    assertTrue(PrivateCellUtil.compare(comparator, kv1, kv2.getKey(), 0, kv2.getKey().length) > 0);
114
115    kv1 = new KeyValue(row1, fam1, qual1, 1L, KeyValue.Type.Put);
116    kv2 = new KeyValue(row1, fam1, qual1, 1L, KeyValue.Type.Maximum);
117    assertTrue(PrivateCellUtil.compare(comparator, kv1, kv2.getKey(), 0, kv2.getKey().length) > 0);
118
119    kv1 = new KeyValue(row1, fam1, qual1, 1L, KeyValue.Type.Put);
120    kv2 = new KeyValue(row1, fam1, qual1, 1L, KeyValue.Type.Put);
121    assertTrue(PrivateCellUtil.compare(comparator, kv1, kv2.getKey(), 0, kv2.getKey().length) == 0);
122  }
123
124  @Test
125  public void testCompareByteBufferedCell() {
126    byte[] r1 = Bytes.toBytes("row1");
127    byte[] r2 = Bytes.toBytes("row2");
128    byte[] f1 = Bytes.toBytes("cf1");
129    byte[] q1 = Bytes.toBytes("qual1");
130    byte[] q2 = Bytes.toBytes("qual2");
131    byte[] v = Bytes.toBytes("val1");
132    KeyValue kv = new KeyValue(r1, f1, q1, v);
133    ByteBuffer buffer = ByteBuffer.wrap(kv.getBuffer());
134    Cell bbCell1 = new ByteBufferKeyValue(buffer, 0, buffer.remaining());
135    kv = new KeyValue(r2, f1, q1, v);
136    buffer = ByteBuffer.wrap(kv.getBuffer());
137    Cell bbCell2 = new ByteBufferKeyValue(buffer, 0, buffer.remaining());
138    // compareColumns not on CellComparator so use Impl directly
139    assertEquals(0, CellComparatorImpl.COMPARATOR.compareColumns(bbCell1, bbCell2));
140    assertEquals(0, CellComparatorImpl.COMPARATOR.compareColumns(bbCell1, kv));
141    kv = new KeyValue(r2, f1, q2, v);
142    buffer = ByteBuffer.wrap(kv.getBuffer());
143    Cell bbCell3 = new ByteBufferKeyValue(buffer, 0, buffer.remaining());
144    assertEquals(0, comparator.compareFamilies(bbCell2, bbCell3));
145    assertTrue(comparator.compareQualifiers(bbCell2, bbCell3) < 0);
146    assertTrue(CellComparatorImpl.COMPARATOR.compareColumns(bbCell2, bbCell3) < 0);
147
148    assertEquals(0, comparator.compareRows(bbCell2, bbCell3));
149    assertTrue(comparator.compareRows(bbCell1, bbCell2) < 0);
150  }
151
152  /**
153   * Test meta comparisons using our new ByteBufferKeyValue Cell type, the type we use everywhere in
154   * 2.0.
155   */
156  @Test
157  public void testMetaComparisons() throws Exception {
158    long now = EnvironmentEdgeManager.currentTime();
159
160    // Meta compares
161    Cell aaa = createByteBufferKeyValueFromKeyValue(
162      new KeyValue(Bytes.toBytes("TestScanMultipleVersions,row_0500,1236020145502"), now));
163    Cell bbb = createByteBufferKeyValueFromKeyValue(
164      new KeyValue(Bytes.toBytes("TestScanMultipleVersions,,99999999999999"), now));
165    CellComparator c = MetaCellComparator.META_COMPARATOR;
166    assertTrue(c.compare(bbb, aaa) < 0);
167
168    Cell ccc = createByteBufferKeyValueFromKeyValue(
169      new KeyValue(Bytes.toBytes("TestScanMultipleVersions,,1236023996656"), Bytes.toBytes("info"),
170        Bytes.toBytes("regioninfo"), 1236024396271L, (byte[]) null));
171    assertTrue(c.compare(ccc, bbb) < 0);
172
173    Cell x = createByteBufferKeyValueFromKeyValue(
174      new KeyValue(Bytes.toBytes("TestScanMultipleVersions,row_0500,1236034574162"),
175        Bytes.toBytes("info"), Bytes.toBytes(""), 9223372036854775807L, (byte[]) null));
176    Cell y = createByteBufferKeyValueFromKeyValue(
177      new KeyValue(Bytes.toBytes("TestScanMultipleVersions,row_0500,1236034574162"),
178        Bytes.toBytes("info"), Bytes.toBytes("regioninfo"), 1236034574912L, (byte[]) null));
179    assertTrue(c.compare(x, y) < 0);
180  }
181
182  private static Cell createByteBufferKeyValueFromKeyValue(KeyValue kv) {
183    ByteBuffer bb = ByteBuffer.wrap(kv.getBuffer());
184    return new ByteBufferKeyValue(bb, 0, bb.remaining());
185  }
186
187  /**
188   * More tests using ByteBufferKeyValue copied over from TestKeyValue which uses old KVs only.
189   */
190  @Test
191  public void testMetaComparisons2() {
192    long now = EnvironmentEdgeManager.currentTime();
193    CellComparator c = MetaCellComparator.META_COMPARATOR;
194    assertTrue(c.compare(
195      createByteBufferKeyValueFromKeyValue(
196        new KeyValue(Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString() + ",a,,0,1"), now)),
197      createByteBufferKeyValueFromKeyValue(
198        new KeyValue(Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString() + ",a,,0,1"), now)))
199        == 0);
200    Cell a = createByteBufferKeyValueFromKeyValue(
201      new KeyValue(Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString() + ",a,,0,1"), now));
202    Cell b = createByteBufferKeyValueFromKeyValue(
203      new KeyValue(Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString() + ",a,,0,2"), now));
204    assertTrue(c.compare(a, b) < 0);
205    assertTrue(c.compare(
206      createByteBufferKeyValueFromKeyValue(
207        new KeyValue(Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString() + ",a,,0,2"), now)),
208      createByteBufferKeyValueFromKeyValue(
209        new KeyValue(Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString() + ",a,,0,1"), now)))
210        > 0);
211    assertTrue(c.compare(
212      createByteBufferKeyValueFromKeyValue(
213        new KeyValue(Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString() + ",,1"), now)),
214      createByteBufferKeyValueFromKeyValue(
215        new KeyValue(Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString() + ",,1"), now)))
216        == 0);
217    assertTrue(c.compare(
218      createByteBufferKeyValueFromKeyValue(
219        new KeyValue(Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString() + ",,1"), now)),
220      createByteBufferKeyValueFromKeyValue(
221        new KeyValue(Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString() + ",,2"), now)))
222        < 0);
223    assertTrue(c.compare(
224      createByteBufferKeyValueFromKeyValue(
225        new KeyValue(Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString() + ",,2"), now)),
226      createByteBufferKeyValueFromKeyValue(
227        new KeyValue(Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString() + ",,1"), now)))
228        > 0);
229  }
230
231  @Test
232  public void testBinaryKeys() throws Exception {
233    Set<Cell> set = new TreeSet<>(CellComparatorImpl.COMPARATOR);
234    final byte[] fam = Bytes.toBytes("col");
235    final byte[] qf = Bytes.toBytes("umn");
236    final byte[] nb = new byte[0];
237    Cell[] keys = {
238      createByteBufferKeyValueFromKeyValue(
239        new KeyValue(Bytes.toBytes("aaaaa,\u0000\u0000,2"), fam, qf, 2, nb)),
240      createByteBufferKeyValueFromKeyValue(
241        new KeyValue(Bytes.toBytes("aaaaa,\u0001,3"), fam, qf, 3, nb)),
242      createByteBufferKeyValueFromKeyValue(new KeyValue(Bytes.toBytes("aaaaa,,1"), fam, qf, 1, nb)),
243      createByteBufferKeyValueFromKeyValue(
244        new KeyValue(Bytes.toBytes("aaaaa,\u1000,5"), fam, qf, 5, nb)),
245      createByteBufferKeyValueFromKeyValue(
246        new KeyValue(Bytes.toBytes("aaaaa,a,4"), fam, qf, 4, nb)),
247      createByteBufferKeyValueFromKeyValue(new KeyValue(Bytes.toBytes("a,a,0"), fam, qf, 0, nb)), };
248    // Add to set with bad comparator
249    Collections.addAll(set, keys);
250    // This will output the keys incorrectly.
251    boolean assertion = false;
252    int count = 0;
253    for (Cell k : set) {
254      if (!(count++ == k.getTimestamp())) {
255        assertion = true;
256      }
257    }
258    assertTrue(assertion);
259    // Make set with good comparator
260    set = new TreeSet<>(MetaCellComparator.META_COMPARATOR);
261    Collections.addAll(set, keys);
262    count = 0;
263    for (Cell k : set) {
264      int currentCount = count++;
265      assertTrue(currentCount == k.getTimestamp(), "count=" + currentCount + ", " + k.toString());
266    }
267  }
268}