View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  package org.apache.hadoop.hbase;
20  
21  import java.io.IOException;
22  import java.util.Arrays;
23  import java.util.Collections;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Set;
27  import java.util.TreeSet;
28  
29  import junit.framework.TestCase;
30  
31  import org.apache.commons.logging.Log;
32  import org.apache.commons.logging.LogFactory;
33  import org.apache.hadoop.hbase.KeyValue.KVComparator;
34  import org.apache.hadoop.hbase.KeyValue.MetaComparator;
35  import org.apache.hadoop.hbase.KeyValue.Type;
36  import org.apache.hadoop.hbase.util.Bytes;
37  
38  import static org.junit.Assert.assertNotEquals;
39  
40  public class TestKeyValue extends TestCase {
41    private final Log LOG = LogFactory.getLog(this.getClass().getName());
42  
43    public void testColumnCompare() throws Exception {
44      final byte [] a = Bytes.toBytes("aaa");
45      byte [] family1 = Bytes.toBytes("abc");
46      byte [] qualifier1 = Bytes.toBytes("def");
47      byte [] family2 = Bytes.toBytes("abcd");
48      byte [] qualifier2 = Bytes.toBytes("ef");
49  
50      KeyValue aaa = new KeyValue(a, family1, qualifier1, 0L, Type.Put, a);
51      assertFalse(aaa.matchingColumn(family2, qualifier2));
52      assertTrue(aaa.matchingColumn(family1, qualifier1));
53      aaa = new KeyValue(a, family2, qualifier2, 0L, Type.Put, a);
54      assertFalse(aaa.matchingColumn(family1, qualifier1));
55      assertTrue(aaa.matchingColumn(family2,qualifier2));
56      byte [] nullQualifier = new byte[0];
57      aaa = new KeyValue(a, family1, nullQualifier, 0L, Type.Put, a);
58      assertTrue(aaa.matchingColumn(family1,null));
59      assertFalse(aaa.matchingColumn(family2,qualifier2));
60    }
61  
62    /**
63     * Test a corner case when the family qualifier is a prefix of the
64     *  column qualifier.
65     */
66    public void testColumnCompare_prefix() throws Exception {
67      final byte [] a = Bytes.toBytes("aaa");
68      byte [] family1 = Bytes.toBytes("abc");
69      byte [] qualifier1 = Bytes.toBytes("def");
70      byte [] family2 = Bytes.toBytes("ab");
71      byte [] qualifier2 = Bytes.toBytes("def");
72  
73      KeyValue aaa = new KeyValue(a, family1, qualifier1, 0L, Type.Put, a);
74      assertFalse(aaa.matchingColumn(family2, qualifier2));
75    }
76  
77    public void testBasics() throws Exception {
78      LOG.info("LOWKEY: " + KeyValue.LOWESTKEY.toString());
79      check(Bytes.toBytes(getName()),
80        Bytes.toBytes(getName()), Bytes.toBytes(getName()), 1,
81        Bytes.toBytes(getName()));
82      // Test empty value and empty column -- both should work. (not empty fam)
83      check(Bytes.toBytes(getName()), Bytes.toBytes(getName()), null, 1, null);
84      check(HConstants.EMPTY_BYTE_ARRAY, Bytes.toBytes(getName()), null, 1, null);
85      // empty qual is equivalent to null qual
86      assertEquals(
87        new KeyValue(Bytes.toBytes("rk"), Bytes.toBytes("fam"), null, 1, (byte[]) null),
88        new KeyValue(Bytes.toBytes("rk"), Bytes.toBytes("fam"),
89          HConstants.EMPTY_BYTE_ARRAY, 1, (byte[]) null));
90    }
91  
92    private void check(final byte [] row, final byte [] family, byte [] qualifier,
93      final long timestamp, final byte [] value) {
94      KeyValue kv = new KeyValue(row, family, qualifier, timestamp, value);
95      assertTrue(Bytes.compareTo(kv.getRow(), row) == 0);
96      assertTrue(kv.matchingColumn(family, qualifier));
97      // Call toString to make sure it works.
98      LOG.info(kv.toString());
99    }
100 
101   public void testPlainCompare() throws Exception {
102     final byte [] a = Bytes.toBytes("aaa");
103     final byte [] b = Bytes.toBytes("bbb");
104     final byte [] fam = Bytes.toBytes("col");
105     final byte [] qf = Bytes.toBytes("umn");
106     KeyValue aaa = new KeyValue(a, fam, qf, a);
107     KeyValue bbb = new KeyValue(b, fam, qf, b);
108     assertTrue(KeyValue.COMPARATOR.compare(aaa, bbb) < 0);
109     assertTrue(KeyValue.COMPARATOR.compare(bbb, aaa) > 0);
110     // Compare breaks if passed same ByteBuffer as both left and right arguments.
111     assertTrue(KeyValue.COMPARATOR.compare(bbb, bbb) == 0);
112     assertTrue(KeyValue.COMPARATOR.compare(aaa, aaa) == 0);
113     // Do compare with different timestamps.
114     aaa = new KeyValue(a, fam, qf, 1, a);
115     bbb = new KeyValue(a, fam, qf, 2, a);
116     assertTrue(KeyValue.COMPARATOR.compare(aaa, bbb) > 0);
117     assertTrue(KeyValue.COMPARATOR.compare(bbb, aaa) < 0);
118     assertTrue(KeyValue.COMPARATOR.compare(aaa, aaa) == 0);
119     // Do compare with different types.  Higher numbered types -- Delete
120     // should sort ahead of lower numbers; i.e. Put
121     aaa = new KeyValue(a, fam, qf, 1, KeyValue.Type.Delete, a);
122     bbb = new KeyValue(a, fam, qf, 1, a);
123     assertTrue(KeyValue.COMPARATOR.compare(aaa, bbb) < 0);
124     assertTrue(KeyValue.COMPARATOR.compare(bbb, aaa) > 0);
125     assertTrue(KeyValue.COMPARATOR.compare(aaa, aaa) == 0);
126   }
127 
128   public void testMoreComparisons() throws Exception {
129     long now = System.currentTimeMillis();
130 
131     // Meta compares
132     KeyValue aaa = new KeyValue(
133         Bytes.toBytes("TestScanMultipleVersions,row_0500,1236020145502"), now);
134     KeyValue bbb = new KeyValue(
135         Bytes.toBytes("TestScanMultipleVersions,,99999999999999"), now);
136     KVComparator c = new KeyValue.MetaComparator();
137     assertTrue(c.compare(bbb, aaa) < 0);
138 
139     KeyValue aaaa = new KeyValue(Bytes.toBytes("TestScanMultipleVersions,,1236023996656"),
140         Bytes.toBytes("info"), Bytes.toBytes("regioninfo"), 1236024396271L,
141         (byte[])null);
142     assertTrue(c.compare(aaaa, bbb) < 0);
143 
144     KeyValue x = new KeyValue(Bytes.toBytes("TestScanMultipleVersions,row_0500,1236034574162"),
145         Bytes.toBytes("info"), Bytes.toBytes(""), 9223372036854775807L,
146         (byte[])null);
147     KeyValue y = new KeyValue(Bytes.toBytes("TestScanMultipleVersions,row_0500,1236034574162"),
148         Bytes.toBytes("info"), Bytes.toBytes("regioninfo"), 1236034574912L,
149         (byte[])null);
150     assertTrue(c.compare(x, y) < 0);
151     comparisons(new KeyValue.MetaComparator());
152     comparisons(new KeyValue.KVComparator());
153     metacomparisons(new KeyValue.MetaComparator());
154   }
155 
156   public void testMetaComparatorTableKeysWithCommaOk() {
157     MetaComparator c = new KeyValue.MetaComparator();
158     long now = System.currentTimeMillis();
159     // meta keys values are not quite right.  A users can enter illegal values
160     // from shell when scanning meta.
161     KeyValue a = new KeyValue(Bytes.toBytes("table,key,with,commas1,1234"), now);
162     KeyValue b = new KeyValue(Bytes.toBytes("table,key,with,commas2,0123"), now);
163     assertTrue(c.compare(a, b) < 0);
164   }
165 
166   /**
167    * Tests cases where rows keys have characters below the ','.
168    * See HBASE-832
169    * @throws IOException
170    */
171   public void testKeyValueBorderCases() throws IOException {
172     // % sorts before , so if we don't do special comparator, rowB would
173     // come before rowA.
174     KeyValue rowA = new KeyValue(Bytes.toBytes("testtable,www.hbase.org/,1234"),
175       Bytes.toBytes("fam"), Bytes.toBytes(""), Long.MAX_VALUE, (byte[])null);
176     KeyValue rowB = new KeyValue(Bytes.toBytes("testtable,www.hbase.org/%20,99999"),
177         Bytes.toBytes("fam"), Bytes.toBytes(""), Long.MAX_VALUE, (byte[])null);
178     assertTrue(KeyValue.META_COMPARATOR.compare(rowA, rowB) < 0);
179 
180     rowA = new KeyValue(Bytes.toBytes("testtable,,1234"), Bytes.toBytes("fam"),
181         Bytes.toBytes(""), Long.MAX_VALUE, (byte[])null);
182     rowB = new KeyValue(Bytes.toBytes("testtable,$www.hbase.org/,99999"),
183         Bytes.toBytes("fam"), Bytes.toBytes(""), Long.MAX_VALUE, (byte[])null);
184     assertTrue(KeyValue.META_COMPARATOR.compare(rowA, rowB) < 0);
185 
186   }
187 
188   private void metacomparisons(final KeyValue.MetaComparator c) {
189     long now = System.currentTimeMillis();
190     assertTrue(c.compare(new KeyValue(
191         Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",a,,0,1"), now),
192       new KeyValue(
193           Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",a,,0,1"), now)) == 0);
194     KeyValue a = new KeyValue(
195         Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",a,,0,1"), now);
196     KeyValue b = new KeyValue(
197         Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",a,,0,2"), now);
198     assertTrue(c.compare(a, b) < 0);
199     assertTrue(c.compare(new KeyValue(
200         Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",a,,0,2"), now),
201       new KeyValue(
202           Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",a,,0,1"), now)) > 0);
203   }
204 
205   private void comparisons(final KeyValue.KVComparator c) {
206     long now = System.currentTimeMillis();
207     assertTrue(c.compare(new KeyValue(
208         Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",,1"), now),
209       new KeyValue(
210           Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",,1"), now)) == 0);
211     assertTrue(c.compare(new KeyValue(
212         Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",,1"), now),
213       new KeyValue(
214           Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",,2"), now)) < 0);
215     assertTrue(c.compare(new KeyValue(
216         Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",,2"), now),
217       new KeyValue(
218           Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",,1"), now)) > 0);
219   }
220 
221   public void testBinaryKeys() throws Exception {
222     Set<KeyValue> set = new TreeSet<KeyValue>(KeyValue.COMPARATOR);
223     final byte [] fam = Bytes.toBytes("col");
224     final byte [] qf = Bytes.toBytes("umn");
225     final byte [] nb = new byte[0];
226     KeyValue [] keys = {new KeyValue(Bytes.toBytes("aaaaa,\u0000\u0000,2"), fam, qf, 2, nb),
227       new KeyValue(Bytes.toBytes("aaaaa,\u0001,3"), fam, qf, 3, nb),
228       new KeyValue(Bytes.toBytes("aaaaa,,1"), fam, qf, 1, nb),
229       new KeyValue(Bytes.toBytes("aaaaa,\u1000,5"), fam, qf, 5, nb),
230       new KeyValue(Bytes.toBytes("aaaaa,a,4"), fam, qf, 4, nb),
231       new KeyValue(Bytes.toBytes("a,a,0"), fam, qf, 0, nb),
232     };
233     // Add to set with bad comparator
234     Collections.addAll(set, keys);
235     // This will output the keys incorrectly.
236     boolean assertion = false;
237     int count = 0;
238     try {
239       for (KeyValue k: set) {
240         assertTrue(count++ == k.getTimestamp());
241       }
242     } catch (junit.framework.AssertionFailedError e) {
243       // Expected
244       assertion = true;
245     }
246     assertTrue(assertion);
247     // Make set with good comparator
248     set = new TreeSet<KeyValue>(new KeyValue.MetaComparator());
249     Collections.addAll(set, keys);
250     count = 0;
251     for (KeyValue k: set) {
252       assertTrue(count++ == k.getTimestamp());
253     }
254   }
255 
256   public void testStackedUpKeyValue() {
257     // Test multiple KeyValues in a single blob.
258 
259     // TODO actually write this test!
260 
261   }
262 
263   private final byte[] rowA = Bytes.toBytes("rowA");
264   private final byte[] rowB = Bytes.toBytes("rowB");
265 
266   private final byte[] family = Bytes.toBytes("family");
267   private final byte[] qualA = Bytes.toBytes("qfA");
268   private final byte[] qualB = Bytes.toBytes("qfB");
269 
270   private void assertKVLess(KeyValue.KVComparator c,
271                             KeyValue less,
272                             KeyValue greater) {
273     int cmp = c.compare(less,greater);
274     assertTrue(cmp < 0);
275     cmp = c.compare(greater,less);
276     assertTrue(cmp > 0);
277   }
278 
279   private void assertKVLessWithoutRow(KeyValue.KVComparator c, int common, KeyValue less,
280       KeyValue greater) {
281     int cmp = c.compareIgnoringPrefix(common, less.getBuffer(), less.getOffset()
282         + KeyValue.ROW_OFFSET, less.getKeyLength(), greater.getBuffer(),
283         greater.getOffset() + KeyValue.ROW_OFFSET, greater.getKeyLength());
284     assertTrue(cmp < 0);
285     cmp = c.compareIgnoringPrefix(common, greater.getBuffer(), greater.getOffset()
286         + KeyValue.ROW_OFFSET, greater.getKeyLength(), less.getBuffer(),
287         less.getOffset() + KeyValue.ROW_OFFSET, less.getKeyLength());
288     assertTrue(cmp > 0);
289   }
290 
291   public void testCompareWithoutRow() {
292     final KeyValue.KVComparator c = KeyValue.COMPARATOR;
293     byte[] row = Bytes.toBytes("row");
294 
295     byte[] fa = Bytes.toBytes("fa");
296     byte[] fami = Bytes.toBytes("fami");
297     byte[] fami1 = Bytes.toBytes("fami1");
298 
299     byte[] qual0 = Bytes.toBytes("");
300     byte[] qual1 = Bytes.toBytes("qf1");
301     byte[] qual2 = Bytes.toBytes("qf2");
302     long ts = 1;
303 
304     // 'fa:'
305     KeyValue kv_0 = new KeyValue(row, fa, qual0, ts, Type.Put);
306     // 'fami:'
307     KeyValue kv0_0 = new KeyValue(row, fami, qual0, ts, Type.Put);
308     // 'fami:qf1'
309     KeyValue kv0_1 = new KeyValue(row, fami, qual1, ts, Type.Put);
310     // 'fami:qf2'
311     KeyValue kv0_2 = new KeyValue(row, fami, qual2, ts, Type.Put);
312     // 'fami1:'
313     KeyValue kv1_0 = new KeyValue(row, fami1, qual0, ts, Type.Put);
314 
315     // 'fami:qf1' < 'fami:qf2'
316     assertKVLessWithoutRow(c, 0, kv0_1, kv0_2);
317     // 'fami:qf1' < 'fami1:'
318     assertKVLessWithoutRow(c, 0, kv0_1, kv1_0);
319 
320     // Test comparison by skipping the same prefix bytes.
321     /***
322      * KeyValue Format and commonLength:
323      * |_keyLen_|_valLen_|_rowLen_|_rowKey_|_famiLen_|_fami_|_Quali_|....
324      * ------------------|-------commonLength--------|--------------
325      */
326     int commonLength = KeyValue.ROW_LENGTH_SIZE + KeyValue.FAMILY_LENGTH_SIZE
327         + row.length;
328     // 'fa:' < 'fami:'. They have commonPrefix + 2 same prefix bytes.
329     assertKVLessWithoutRow(c, commonLength + 2, kv_0, kv0_0);
330     // 'fami:' < 'fami:qf1'. They have commonPrefix + 4 same prefix bytes.
331     assertKVLessWithoutRow(c, commonLength + 4, kv0_0, kv0_1);
332     // 'fami:qf1' < 'fami1:'. They have commonPrefix + 4 same prefix bytes.
333     assertKVLessWithoutRow(c, commonLength + 4, kv0_1, kv1_0);
334     // 'fami:qf1' < 'fami:qf2'. They have commonPrefix + 6 same prefix bytes.
335     assertKVLessWithoutRow(c, commonLength + 6, kv0_1, kv0_2);
336   }
337 
338   public void testFirstLastOnRow() {
339     final KVComparator c = KeyValue.COMPARATOR;
340     long ts = 1;
341     byte[] bufferA = new byte[128];
342     int offsetA = 0;
343     byte[] bufferB = new byte[128];
344     int offsetB = 7;
345 
346     // These are listed in sort order (ie: every one should be less
347     // than the one on the next line).
348     final KeyValue firstOnRowA = KeyValue.createFirstOnRow(rowA);
349     final KeyValue firstOnRowABufferFamQual = KeyValue.createFirstOnRow(bufferA, offsetA,
350         rowA, 0, rowA.length, family, 0, family.length, qualA, 0, qualA.length);
351     final KeyValue kvA_1 = new KeyValue(rowA, null, null, ts, Type.Put);
352     final KeyValue kvA_2 = new KeyValue(rowA, family, qualA, ts, Type.Put);
353 
354     final KeyValue lastOnRowA = KeyValue.createLastOnRow(rowA);
355     final KeyValue firstOnRowB = KeyValue.createFirstOnRow(rowB);
356     final KeyValue firstOnRowBBufferFam = KeyValue.createFirstOnRow(bufferB, offsetB,
357         rowB, 0, rowB.length, family, 0, family.length, null, 0, 0);
358     final KeyValue kvB = new KeyValue(rowB, family, qualA, ts, Type.Put);
359 
360     assertKVLess(c, firstOnRowA, firstOnRowB);
361     assertKVLess(c, firstOnRowA, firstOnRowBBufferFam);
362     assertKVLess(c, firstOnRowABufferFamQual, firstOnRowB);
363     assertKVLess(c, firstOnRowA, kvA_1);
364     assertKVLess(c, firstOnRowA, kvA_2);
365     assertKVLess(c, firstOnRowABufferFamQual, kvA_2);
366     assertKVLess(c, kvA_1, kvA_2);
367     assertKVLess(c, kvA_2, firstOnRowB);
368     assertKVLess(c, kvA_1, firstOnRowB);
369     assertKVLess(c, kvA_2, firstOnRowBBufferFam);
370     assertKVLess(c, kvA_1, firstOnRowBBufferFam);
371 
372     assertKVLess(c, lastOnRowA, firstOnRowB);
373     assertKVLess(c, lastOnRowA, firstOnRowBBufferFam);
374     assertKVLess(c, firstOnRowB, kvB);
375     assertKVLess(c, firstOnRowBBufferFam, kvB);
376     assertKVLess(c, lastOnRowA, kvB);
377 
378     assertKVLess(c, kvA_2, lastOnRowA);
379     assertKVLess(c, kvA_1, lastOnRowA);
380     assertKVLess(c, firstOnRowA, lastOnRowA);
381     assertKVLess(c, firstOnRowABufferFamQual, lastOnRowA);
382   }
383 
384   public void testCreateKeyOnly() throws Exception {
385     long ts = 1;
386     byte [] value = Bytes.toBytes("a real value");
387     byte [] evalue = new byte[0]; // empty value
388 
389     for (byte[] val : new byte[][]{value, evalue}) {
390       for (boolean useLen : new boolean[]{false,true}) {
391         KeyValue kv1 = new KeyValue(rowA, family, qualA, ts, val);
392         KeyValue kv1ko = kv1.createKeyOnly(useLen);
393         // keys are still the same
394         assertTrue(kv1.equals(kv1ko));
395         // but values are not
396         assertTrue(kv1ko.getValue().length == (useLen?Bytes.SIZEOF_INT:0));
397         if (useLen) {
398           assertEquals(kv1.getValueLength(), Bytes.toInt(kv1ko.getValue()));
399         }
400       }
401     }
402   }
403 
404   public void testCreateKeyValueFromKey() {
405     KeyValue kv = new KeyValue(Bytes.toBytes("myRow"), Bytes.toBytes("myCF"),
406         Bytes.toBytes("myQualifier"), 12345L, Bytes.toBytes("myValue"));
407     int initialPadding = 10;
408     int endingPadding = 20;
409     int keyLen = kv.getKeyLength();
410     byte[] tmpArr = new byte[initialPadding + endingPadding + keyLen];
411     System.arraycopy(kv.getBuffer(), kv.getKeyOffset(), tmpArr,
412         initialPadding, keyLen);
413     KeyValue kvFromKey = KeyValue.createKeyValueFromKey(tmpArr, initialPadding,
414         keyLen);
415     assertEquals(keyLen, kvFromKey.getKeyLength());
416     assertEquals(KeyValue.ROW_OFFSET + keyLen, kvFromKey.getBuffer().length);
417     System.err.println("kv=" + kv);
418     System.err.println("kvFromKey=" + kvFromKey);
419     assertEquals(kvFromKey.toString(),
420         kv.toString().replaceAll("=[0-9]+", "=0"));
421   }
422 
423   /**
424    * Tests that getTimestamp() does always return the proper timestamp, even after updating it.
425    * See HBASE-6265.
426    */
427   public void testGetTimestamp() {
428     KeyValue kv = new KeyValue(Bytes.toBytes("myRow"), Bytes.toBytes("myCF"),
429       Bytes.toBytes("myQualifier"), HConstants.LATEST_TIMESTAMP,
430       Bytes.toBytes("myValue"));
431     long time1 = kv.getTimestamp();
432     kv.updateLatestStamp(Bytes.toBytes(12345L));
433     long time2 = kv.getTimestamp();
434     assertEquals(HConstants.LATEST_TIMESTAMP, time1);
435     assertEquals(12345L, time2);
436   }
437 
438   /**
439    * See HBASE-7845
440    */
441   public void testGetShortMidpointKey() {
442     final KVComparator keyComparator = KeyValue.COMPARATOR;
443     //verify that faked shorter rowkey could be generated
444     long ts = 5;
445     KeyValue kv1 = new KeyValue(Bytes.toBytes("the quick brown fox"), family, qualA, ts, Type.Put);
446     KeyValue kv2 = new KeyValue(Bytes.toBytes("the who test text"), family, qualA, ts, Type.Put);
447     byte[] newKey = keyComparator.getShortMidpointKey(kv1.getKey(), kv2.getKey());
448     assertTrue(keyComparator.compareFlatKey(kv1.getKey(), newKey) < 0);
449     assertTrue(keyComparator.compareFlatKey(newKey, kv2.getKey()) < 0);
450     short newRowLength = Bytes.toShort(newKey, 0);
451     byte[] expectedArray = Bytes.toBytes("the r");
452     Bytes.equals(newKey, KeyValue.ROW_LENGTH_SIZE, newRowLength, expectedArray, 0,
453       expectedArray.length);
454 
455     //verify: same with "row + family + qualifier", return rightKey directly
456     kv1 = new KeyValue(Bytes.toBytes("ilovehbase"), family, qualA, 5, Type.Put);
457     kv2 = new KeyValue(Bytes.toBytes("ilovehbase"), family, qualA, 0, Type.Put);
458     assertTrue(keyComparator.compareFlatKey(kv1.getKey(), kv2.getKey()) < 0);
459     newKey = keyComparator.getShortMidpointKey(kv1.getKey(), kv2.getKey());
460     assertTrue(keyComparator.compareFlatKey(kv1.getKey(), newKey) < 0);
461     assertTrue(keyComparator.compareFlatKey(newKey, kv2.getKey()) == 0);
462     kv1 = new KeyValue(Bytes.toBytes("ilovehbase"), family, qualA, -5, Type.Put);
463     kv2 = new KeyValue(Bytes.toBytes("ilovehbase"), family, qualA, -10, Type.Put);
464     assertTrue(keyComparator.compareFlatKey(kv1.getKey(), kv2.getKey()) < 0);
465     newKey = keyComparator.getShortMidpointKey(kv1.getKey(), kv2.getKey());
466     assertTrue(keyComparator.compareFlatKey(kv1.getKey(), newKey) < 0);
467     assertTrue(keyComparator.compareFlatKey(newKey, kv2.getKey()) == 0);
468 
469     // verify: same with row, different with qualifier
470     kv1 = new KeyValue(Bytes.toBytes("ilovehbase"), family, qualA, 5, Type.Put);
471     kv2 = new KeyValue(Bytes.toBytes("ilovehbase"), family, qualB, 5, Type.Put);
472     assertTrue(keyComparator.compareFlatKey(kv1.getKey(), kv2.getKey()) < 0);
473     newKey = keyComparator.getShortMidpointKey(kv1.getKey(), kv2.getKey());
474     assertTrue(keyComparator.compareFlatKey(kv1.getKey(), newKey) < 0);
475     assertTrue(keyComparator.compareFlatKey(newKey, kv2.getKey()) < 0);
476     KeyValue newKeyValue = KeyValue.createKeyValueFromKey(newKey);
477     assertTrue(Arrays.equals(newKeyValue.getFamily(),family));
478     assertTrue(Arrays.equals(newKeyValue.getQualifier(),qualB));
479     assertTrue(newKeyValue.getTimestamp() == HConstants.LATEST_TIMESTAMP);
480     assertTrue(newKeyValue.getTypeByte() == Type.Maximum.getCode());
481 
482     //verify metaKeyComparator's getShortMidpointKey output
483     final KVComparator metaKeyComparator = KeyValue.META_COMPARATOR;
484     kv1 = new KeyValue(Bytes.toBytes("ilovehbase123"), family, qualA, 5, Type.Put);
485     kv2 = new KeyValue(Bytes.toBytes("ilovehbase234"), family, qualA, 0, Type.Put);
486     newKey = metaKeyComparator.getShortMidpointKey(kv1.getKey(), kv2.getKey());
487     assertTrue(metaKeyComparator.compareFlatKey(kv1.getKey(), newKey) < 0);
488     assertTrue(metaKeyComparator.compareFlatKey(newKey, kv2.getKey()) == 0);
489 
490     //verify common fix scenario
491     kv1 = new KeyValue(Bytes.toBytes("ilovehbase"), family, qualA, ts, Type.Put);
492     kv2 = new KeyValue(Bytes.toBytes("ilovehbaseandhdfs"), family, qualA, ts, Type.Put);
493     assertTrue(keyComparator.compareFlatKey(kv1.getKey(), kv2.getKey()) < 0);
494     newKey = keyComparator.getShortMidpointKey(kv1.getKey(), kv2.getKey());
495     assertTrue(keyComparator.compareFlatKey(kv1.getKey(), newKey) < 0);
496     assertTrue(keyComparator.compareFlatKey(newKey, kv2.getKey()) < 0);
497     newRowLength = Bytes.toShort(newKey, 0);
498     expectedArray = Bytes.toBytes("ilovehbasea");
499     Bytes.equals(newKey, KeyValue.ROW_LENGTH_SIZE, newRowLength, expectedArray, 0,
500       expectedArray.length);
501     //verify only 1 offset scenario
502     kv1 = new KeyValue(Bytes.toBytes("100abcdefg"), family, qualA, ts, Type.Put);
503     kv2 = new KeyValue(Bytes.toBytes("101abcdefg"), family, qualA, ts, Type.Put);
504     assertTrue(keyComparator.compareFlatKey(kv1.getKey(), kv2.getKey()) < 0);
505     newKey = keyComparator.getShortMidpointKey(kv1.getKey(), kv2.getKey());
506     assertTrue(keyComparator.compareFlatKey(kv1.getKey(), newKey) < 0);
507     assertTrue(keyComparator.compareFlatKey(newKey, kv2.getKey()) < 0);
508     newRowLength = Bytes.toShort(newKey, 0);
509     expectedArray = Bytes.toBytes("101");
510     Bytes.equals(newKey, KeyValue.ROW_LENGTH_SIZE, newRowLength, expectedArray, 0,
511       expectedArray.length);
512   }
513 
514   public void testKVsWithTags() {
515     byte[] row = Bytes.toBytes("myRow");
516     byte[] cf = Bytes.toBytes("myCF");
517     byte[] q = Bytes.toBytes("myQualifier");
518     byte[] value = Bytes.toBytes("myValue");
519     byte[] metaValue1 = Bytes.toBytes("metaValue1");
520     byte[] metaValue2 = Bytes.toBytes("metaValue2");
521     KeyValue kv = new KeyValue(row, cf, q, HConstants.LATEST_TIMESTAMP, value, new Tag[] {
522         new Tag((byte) 1, metaValue1), new Tag((byte) 2, metaValue2) });
523     assertTrue(kv.getTagsLengthUnsigned() > 0);
524     assertTrue(Bytes.equals(kv.getRow(), row));
525     assertTrue(Bytes.equals(kv.getFamily(), cf));
526     assertTrue(Bytes.equals(kv.getQualifier(), q));
527     assertTrue(Bytes.equals(kv.getValue(), value));
528     List<Tag> tags = kv.getTags();
529     assertNotNull(tags);
530     assertEquals(2, tags.size());
531     boolean meta1Ok = false, meta2Ok = false;
532     for (Tag tag : tags) {
533       if (tag.getType() == (byte) 1) {
534         if (Bytes.equals(tag.getValue(), metaValue1)) {
535           meta1Ok = true;
536         }
537       } else {
538         if (Bytes.equals(tag.getValue(), metaValue2)) {
539           meta2Ok = true;
540         }
541       }
542     }
543     assertTrue(meta1Ok);
544     assertTrue(meta2Ok);
545     Iterator<Tag> tagItr = CellUtil.tagsIterator(kv.getTagsArray(), kv.getTagsOffset(),
546         kv.getTagsLengthUnsigned());
547     //Iterator<Tag> tagItr = kv.tagsIterator();
548     assertTrue(tagItr.hasNext());
549     Tag next = tagItr.next();
550     assertEquals(10, next.getTagLength());
551     assertEquals((byte) 1, next.getType());
552     Bytes.equals(next.getValue(), metaValue1);
553     assertTrue(tagItr.hasNext());
554     next = tagItr.next();
555     assertEquals(10, next.getTagLength());
556     assertEquals((byte) 2, next.getType());
557     Bytes.equals(next.getValue(), metaValue2);
558     assertFalse(tagItr.hasNext());
559 
560     tagItr = CellUtil.tagsIterator(kv.getTagsArray(), kv.getTagsOffset(),
561         kv.getTagsLengthUnsigned());
562     assertTrue(tagItr.hasNext());
563     next = tagItr.next();
564     assertEquals(10, next.getTagLength());
565     assertEquals((byte) 1, next.getType());
566     Bytes.equals(next.getValue(), metaValue1);
567     assertTrue(tagItr.hasNext());
568     next = tagItr.next();
569     assertEquals(10, next.getTagLength());
570     assertEquals((byte) 2, next.getType());
571     Bytes.equals(next.getValue(), metaValue2);
572     assertFalse(tagItr.hasNext());
573   }
574   
575   public void testMetaKeyComparator() {
576     MetaComparator c = new KeyValue.MetaComparator();
577     long now = System.currentTimeMillis();
578 
579     KeyValue a = new KeyValue(Bytes.toBytes("table1"), now);
580     KeyValue b = new KeyValue(Bytes.toBytes("table2"), now);
581     assertTrue(c.compare(a, b) < 0);
582     
583     a = new KeyValue(Bytes.toBytes("table1,111"), now);
584     b = new KeyValue(Bytes.toBytes("table2"), now);
585     assertTrue(c.compare(a, b) < 0);
586     
587     a = new KeyValue(Bytes.toBytes("table1"), now);
588     b = new KeyValue(Bytes.toBytes("table2,111"), now);
589     assertTrue(c.compare(a, b) < 0);
590     
591     a = new KeyValue(Bytes.toBytes("table,111"), now);
592     b = new KeyValue(Bytes.toBytes("table,2222"), now);
593     assertTrue(c.compare(a, b) < 0);
594     
595     a = new KeyValue(Bytes.toBytes("table,111,aaaa"), now);
596     b = new KeyValue(Bytes.toBytes("table,2222"), now);
597     assertTrue(c.compare(a, b) < 0);
598     
599     a = new KeyValue(Bytes.toBytes("table,111"), now);
600     b = new KeyValue(Bytes.toBytes("table,2222.bbb"), now);
601     assertTrue(c.compare(a, b) < 0);
602 
603     a = new KeyValue(Bytes.toBytes("table,,aaaa"), now);
604     b = new KeyValue(Bytes.toBytes("table,111,bbb"), now);
605     assertTrue(c.compare(a, b) < 0);
606     
607     a = new KeyValue(Bytes.toBytes("table,111,aaaa"), now);
608     b = new KeyValue(Bytes.toBytes("table,111,bbb"), now);
609     assertTrue(c.compare(a, b) < 0);
610 
611     a = new KeyValue(Bytes.toBytes("table,111,xxxx"), now);
612     b = new KeyValue(Bytes.toBytes("table,111,222,bbb"), now);
613     assertTrue(c.compare(a, b) < 0);
614     
615     a = new KeyValue(Bytes.toBytes("table,111,11,xxx"), now);
616     b = new KeyValue(Bytes.toBytes("table,111,222,bbb"), now);
617     assertTrue(c.compare(a, b) < 0);
618   }
619 
620   public void testEqualsAndHashCode() throws Exception {
621     KeyValue kvA1 = new KeyValue(Bytes.toBytes("key"), Bytes.toBytes("cf"),
622         Bytes.toBytes("qualA"), Bytes.toBytes("1"));
623     KeyValue kvA2 = new KeyValue(Bytes.toBytes("key"), Bytes.toBytes("cf"),
624         Bytes.toBytes("qualA"), Bytes.toBytes("2"));
625     // We set a different sequence id on kvA2 to demonstrate that the equals and hashCode also
626     // don't take this into account.
627     kvA2.setMvccVersion(2);
628     KeyValue kvB = new KeyValue(Bytes.toBytes("key"), Bytes.toBytes("cf"),
629         Bytes.toBytes("qualB"), Bytes.toBytes("1"));
630 
631     assertEquals(kvA1, kvA2);
632     assertNotEquals(kvA1, kvB);
633     assertEquals(kvA1.hashCode(), kvA2.hashCode());
634     assertNotEquals(kvA1.hashCode(), kvB.hashCode());
635 
636   }
637 }