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