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