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