1   /**
2    * Copyright 2009 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase;
21  
22  import java.io.ByteArrayInputStream;
23  import java.io.DataInputStream;
24  import java.io.IOException;
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  import org.apache.hadoop.io.WritableUtils;
37  import org.junit.experimental.categories.Category;
38  
39  @Category(SmallTests.class)
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    }
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 //    final byte [] column = Bytes.toBytes("col:umn");
102     KeyValue aaa = new KeyValue(a, fam, qf, a);
103     KeyValue bbb = new KeyValue(b, fam, qf, b);
104     byte [] keyabb = aaa.getKey();
105     byte [] keybbb = bbb.getKey();
106     assertTrue(KeyValue.COMPARATOR.compare(aaa, bbb) < 0);
107     assertTrue(KeyValue.KEY_COMPARATOR.compare(keyabb, 0, keyabb.length, keybbb,
108       0, keybbb.length) < 0);
109     assertTrue(KeyValue.COMPARATOR.compare(bbb, aaa) > 0);
110     assertTrue(KeyValue.KEY_COMPARATOR.compare(keybbb, 0, keybbb.length, keyabb,
111       0, keyabb.length) > 0);
112     // Compare breaks if passed same ByteBuffer as both left and right arguments.
113     assertTrue(KeyValue.COMPARATOR.compare(bbb, bbb) == 0);
114     assertTrue(KeyValue.KEY_COMPARATOR.compare(keybbb, 0, keybbb.length, keybbb,
115       0, keybbb.length) == 0);
116     assertTrue(KeyValue.COMPARATOR.compare(aaa, aaa) == 0);
117     assertTrue(KeyValue.KEY_COMPARATOR.compare(keyabb, 0, keyabb.length, keyabb,
118       0, keyabb.length) == 0);
119     // Do compare with different timestamps.
120     aaa = new KeyValue(a, fam, qf, 1, a);
121     bbb = new KeyValue(a, fam, qf, 2, a);
122     assertTrue(KeyValue.COMPARATOR.compare(aaa, bbb) > 0);
123     assertTrue(KeyValue.COMPARATOR.compare(bbb, aaa) < 0);
124     assertTrue(KeyValue.COMPARATOR.compare(aaa, aaa) == 0);
125     // Do compare with different types.  Higher numbered types -- Delete
126     // should sort ahead of lower numbers; i.e. Put
127     aaa = new KeyValue(a, fam, qf, 1, KeyValue.Type.Delete, a);
128     bbb = new KeyValue(a, fam, qf, 1, a);
129     assertTrue(KeyValue.COMPARATOR.compare(aaa, bbb) < 0);
130     assertTrue(KeyValue.COMPARATOR.compare(bbb, aaa) > 0);
131     assertTrue(KeyValue.COMPARATOR.compare(aaa, aaa) == 0);
132   }
133 
134   public void testMoreComparisons() throws Exception {
135     // Root compares
136     long now = System.currentTimeMillis();
137     KeyValue a = new KeyValue(Bytes.toBytes(".META.,,99999999999999"), now);
138     KeyValue b = new KeyValue(Bytes.toBytes(".META.,,1"), now);
139     KVComparator c = new KeyValue.RootComparator();
140     assertTrue(c.compare(b, a) < 0);
141     KeyValue aa = new KeyValue(Bytes.toBytes(".META.,,1"), now);
142     KeyValue bb = new KeyValue(Bytes.toBytes(".META.,,1"),
143         Bytes.toBytes("info"), Bytes.toBytes("regioninfo"), 1235943454602L,
144         (byte[])null);
145     assertTrue(c.compare(aa, bb) < 0);
146 
147     // Meta compares
148     KeyValue aaa = new KeyValue(
149         Bytes.toBytes("TestScanMultipleVersions,row_0500,1236020145502"), now);
150     KeyValue bbb = new KeyValue(
151         Bytes.toBytes("TestScanMultipleVersions,,99999999999999"), now);
152     c = new KeyValue.MetaComparator();
153     assertTrue(c.compare(bbb, aaa) < 0);
154 
155     KeyValue aaaa = new KeyValue(Bytes.toBytes("TestScanMultipleVersions,,1236023996656"),
156         Bytes.toBytes("info"), Bytes.toBytes("regioninfo"), 1236024396271L,
157         (byte[])null);
158     assertTrue(c.compare(aaaa, bbb) < 0);
159 
160     KeyValue x = new KeyValue(Bytes.toBytes("TestScanMultipleVersions,row_0500,1236034574162"),
161         Bytes.toBytes("info"), Bytes.toBytes(""), 9223372036854775807L,
162         (byte[])null);
163     KeyValue y = new KeyValue(Bytes.toBytes("TestScanMultipleVersions,row_0500,1236034574162"),
164         Bytes.toBytes("info"), Bytes.toBytes("regioninfo"), 1236034574912L,
165         (byte[])null);
166     assertTrue(c.compare(x, y) < 0);
167     comparisons(new KeyValue.MetaComparator());
168     comparisons(new KeyValue.KVComparator());
169     metacomparisons(new KeyValue.RootComparator());
170     metacomparisons(new KeyValue.MetaComparator());
171   }
172 
173   public void testBadMetaCompareSingleDelim() {
174     MetaComparator c = new KeyValue.MetaComparator();
175     long now = System.currentTimeMillis();
176     // meta keys values are not quite right.  A users can enter illegal values 
177     // from shell when scanning meta.
178     KeyValue a = new KeyValue(Bytes.toBytes("table,a1"), now);
179     KeyValue b = new KeyValue(Bytes.toBytes("table,a2"), now);
180     try {
181       c.compare(a, b);
182     } catch (IllegalArgumentException iae) { 
183       assertEquals(".META. key must have two ',' delimiters and have the following" +
184       		" format: '<table>,<key>,<etc>'", iae.getMessage());
185       return;
186     }
187     fail("Expected IllegalArgumentException");
188   }
189 
190   public void testMetaComparatorTableKeysWithCommaOk() {
191     MetaComparator c = new KeyValue.MetaComparator();
192     long now = System.currentTimeMillis();
193     // meta keys values are not quite right.  A users can enter illegal values 
194     // from shell when scanning meta.
195     KeyValue a = new KeyValue(Bytes.toBytes("table,key,with,commas1,1234"), now);
196     KeyValue b = new KeyValue(Bytes.toBytes("table,key,with,commas2,0123"), now);
197     assertTrue(c.compare(a, b) < 0);
198   }
199   
200   /**
201    * Tests cases where rows keys have characters below the ','.
202    * See HBASE-832
203    * @throws IOException
204    */
205   public void testKeyValueBorderCases() throws IOException {
206     // % sorts before , so if we don't do special comparator, rowB would
207     // come before rowA.
208     KeyValue rowA = new KeyValue(Bytes.toBytes("testtable,www.hbase.org/,1234"),
209       Bytes.toBytes("fam"), Bytes.toBytes(""), Long.MAX_VALUE, (byte[])null);
210     KeyValue rowB = new KeyValue(Bytes.toBytes("testtable,www.hbase.org/%20,99999"),
211         Bytes.toBytes("fam"), Bytes.toBytes(""), Long.MAX_VALUE, (byte[])null);
212     assertTrue(KeyValue.META_COMPARATOR.compare(rowA, rowB) < 0);
213 
214     rowA = new KeyValue(Bytes.toBytes("testtable,,1234"), Bytes.toBytes("fam"),
215         Bytes.toBytes(""), Long.MAX_VALUE, (byte[])null);
216     rowB = new KeyValue(Bytes.toBytes("testtable,$www.hbase.org/,99999"),
217         Bytes.toBytes("fam"), Bytes.toBytes(""), Long.MAX_VALUE, (byte[])null);
218     assertTrue(KeyValue.META_COMPARATOR.compare(rowA, rowB) < 0);
219 
220     rowA = new KeyValue(Bytes.toBytes(".META.,testtable,www.hbase.org/,1234,4321"),
221         Bytes.toBytes("fam"), Bytes.toBytes(""), Long.MAX_VALUE, (byte[])null);
222     rowB = new KeyValue(Bytes.toBytes(".META.,testtable,www.hbase.org/%20,99999,99999"),
223         Bytes.toBytes("fam"), Bytes.toBytes(""), Long.MAX_VALUE, (byte[])null);
224     assertTrue(KeyValue.ROOT_COMPARATOR.compare(rowA, rowB) < 0);
225   }
226 
227   private void metacomparisons(final KeyValue.MetaComparator c) {
228     long now = System.currentTimeMillis();
229     assertTrue(c.compare(new KeyValue(Bytes.toBytes(".META.,a,,0,1"), now),
230       new KeyValue(Bytes.toBytes(".META.,a,,0,1"), now)) == 0);
231     KeyValue a = new KeyValue(Bytes.toBytes(".META.,a,,0,1"), now);
232     KeyValue b = new KeyValue(Bytes.toBytes(".META.,a,,0,2"), now);
233     assertTrue(c.compare(a, b) < 0);
234     assertTrue(c.compare(new KeyValue(Bytes.toBytes(".META.,a,,0,2"), now),
235       new KeyValue(Bytes.toBytes(".META.,a,,0,1"), now)) > 0);
236   }
237 
238   private void comparisons(final KeyValue.KVComparator c) {
239     long now = System.currentTimeMillis();
240     assertTrue(c.compare(new KeyValue(Bytes.toBytes(".META.,,1"), now),
241       new KeyValue(Bytes.toBytes(".META.,,1"), now)) == 0);
242     assertTrue(c.compare(new KeyValue(Bytes.toBytes(".META.,,1"), now),
243       new KeyValue(Bytes.toBytes(".META.,,2"), now)) < 0);
244     assertTrue(c.compare(new KeyValue(Bytes.toBytes(".META.,,2"), now),
245       new KeyValue(Bytes.toBytes(".META.,,1"), now)) > 0);
246   }
247 
248   public void testBinaryKeys() throws Exception {
249     Set<KeyValue> set = new TreeSet<KeyValue>(KeyValue.COMPARATOR);
250     final byte [] fam = Bytes.toBytes("col");
251     final byte [] qf = Bytes.toBytes("umn");
252     final byte [] nb = new byte[0];
253     KeyValue [] keys = {new KeyValue(Bytes.toBytes("aaaaa,\u0000\u0000,2"), fam, qf, 2, nb),
254       new KeyValue(Bytes.toBytes("aaaaa,\u0001,3"), fam, qf, 3, nb),
255       new KeyValue(Bytes.toBytes("aaaaa,,1"), fam, qf, 1, nb),
256       new KeyValue(Bytes.toBytes("aaaaa,\u1000,5"), fam, qf, 5, nb),
257       new KeyValue(Bytes.toBytes("aaaaa,a,4"), fam, qf, 4, nb),
258       new KeyValue(Bytes.toBytes("a,a,0"), fam, qf, 0, nb),
259     };
260     // Add to set with bad comparator
261     for (int i = 0; i < keys.length; i++) {
262       set.add(keys[i]);
263     }
264     // This will output the keys incorrectly.
265     boolean assertion = false;
266     int count = 0;
267     try {
268       for (KeyValue k: set) {
269         assertTrue(count++ == k.getTimestamp());
270       }
271     } catch (junit.framework.AssertionFailedError e) {
272       // Expected
273       assertion = true;
274     }
275     assertTrue(assertion);
276     // Make set with good comparator
277     set = new TreeSet<KeyValue>(new KeyValue.MetaComparator());
278     for (int i = 0; i < keys.length; i++) {
279       set.add(keys[i]);
280     }
281     count = 0;
282     for (KeyValue k: set) {
283       assertTrue(count++ == k.getTimestamp());
284     }
285     // Make up -ROOT- table keys.
286     KeyValue [] rootKeys = {
287         new KeyValue(Bytes.toBytes(".META.,aaaaa,\u0000\u0000,0,2"), fam, qf, 2, nb),
288         new KeyValue(Bytes.toBytes(".META.,aaaaa,\u0001,0,3"), fam, qf, 3, nb),
289         new KeyValue(Bytes.toBytes(".META.,aaaaa,,0,1"), fam, qf, 1, nb),
290         new KeyValue(Bytes.toBytes(".META.,aaaaa,\u1000,0,5"), fam, qf, 5, nb),
291         new KeyValue(Bytes.toBytes(".META.,aaaaa,a,0,4"), fam, qf, 4, nb),
292         new KeyValue(Bytes.toBytes(".META.,,0"), fam, qf, 0, nb),
293       };
294     // This will output the keys incorrectly.
295     set = new TreeSet<KeyValue>(new KeyValue.MetaComparator());
296     // Add to set with bad comparator
297     for (int i = 0; i < keys.length; i++) {
298       set.add(rootKeys[i]);
299     }
300     assertion = false;
301     count = 0;
302     try {
303       for (KeyValue k: set) {
304         assertTrue(count++ == k.getTimestamp());
305       }
306     } catch (junit.framework.AssertionFailedError e) {
307       // Expected
308       assertion = true;
309     }
310     // Now with right comparator
311     set = new TreeSet<KeyValue>(new KeyValue.RootComparator());
312     // Add to set with bad comparator
313     for (int i = 0; i < keys.length; i++) {
314       set.add(rootKeys[i]);
315     }
316     count = 0;
317     for (KeyValue k: set) {
318       assertTrue(count++ == k.getTimestamp());
319     }
320   }
321 
322   public void testStackedUpKeyValue() {
323     // Test multiple KeyValues in a single blob.
324 
325     // TODO actually write this test!
326 
327   }
328 
329   private final byte[] rowA = Bytes.toBytes("rowA");
330   private final byte[] rowB = Bytes.toBytes("rowB");
331 
332   private final byte[] family = Bytes.toBytes("family");
333   private final byte[] qualA = Bytes.toBytes("qfA");
334 
335   private void assertKVLess(KeyValue.KVComparator c,
336                             KeyValue less,
337                             KeyValue greater) {
338     int cmp = c.compare(less,greater);
339     assertTrue(cmp < 0);
340     cmp = c.compare(greater,less);
341     assertTrue(cmp > 0);
342   }
343 
344   private void assertKVLessWithoutRow(KeyValue.KeyComparator c, int common, KeyValue less,
345       KeyValue greater) {
346     int cmp = c.compareIgnoringPrefix(common, less.getBuffer(), less.getOffset()
347         + KeyValue.ROW_OFFSET, less.getKeyLength(), greater.getBuffer(),
348         greater.getOffset() + KeyValue.ROW_OFFSET, greater.getKeyLength());
349     assertTrue(cmp < 0);
350     cmp = c.compareIgnoringPrefix(common, greater.getBuffer(), greater.getOffset()
351         + KeyValue.ROW_OFFSET, greater.getKeyLength(), less.getBuffer(),
352         less.getOffset() + KeyValue.ROW_OFFSET, less.getKeyLength());
353     assertTrue(cmp > 0);
354   }
355 
356   public void testCompareWithoutRow() {
357     final KeyValue.KeyComparator c = KeyValue.KEY_COMPARATOR;
358     byte[] row = Bytes.toBytes("row");
359 
360     byte[] fa = Bytes.toBytes("fa");
361     byte[] fami = Bytes.toBytes("fami");
362     byte[] fami1 = Bytes.toBytes("fami1");
363 
364     byte[] qual0 = Bytes.toBytes("");
365     byte[] qual1 = Bytes.toBytes("qf1");
366     byte[] qual2 = Bytes.toBytes("qf2");
367     long ts = 1;
368 
369     // 'fa:'
370     KeyValue kv_0 = new KeyValue(row, fa, qual0, ts, Type.Put);
371     // 'fami:'
372     KeyValue kv0_0 = new KeyValue(row, fami, qual0, ts, Type.Put);
373     // 'fami:qf1'
374     KeyValue kv0_1 = new KeyValue(row, fami, qual1, ts, Type.Put);
375     // 'fami:qf2'
376     KeyValue kv0_2 = new KeyValue(row, fami, qual2, ts, Type.Put);
377     // 'fami1:'
378     KeyValue kv1_0 = new KeyValue(row, fami1, qual0, ts, Type.Put);
379 
380     // 'fami:qf1' < 'fami:qf2'
381     assertKVLessWithoutRow(c, 0, kv0_1, kv0_2);
382     // 'fami:qf1' < 'fami1:'
383     assertKVLessWithoutRow(c, 0, kv0_1, kv1_0);
384 
385     // Test comparison by skipping the same prefix bytes.
386     /***
387      * KeyValue Format and commonLength:
388      * |_keyLen_|_valLen_|_rowLen_|_rowKey_|_famiLen_|_fami_|_Quali_|....
389      * ------------------|-------commonLength--------|--------------
390      */
391     int commonLength = KeyValue.ROW_LENGTH_SIZE + KeyValue.FAMILY_LENGTH_SIZE
392         + row.length;
393     // 'fa:' < 'fami:'. They have commonPrefix + 2 same prefix bytes.
394     assertKVLessWithoutRow(c, commonLength + 2, kv_0, kv0_0);
395     // 'fami:' < 'fami:qf1'. They have commonPrefix + 4 same prefix bytes.
396     assertKVLessWithoutRow(c, commonLength + 4, kv0_0, kv0_1);
397     // 'fami:qf1' < 'fami1:'. They have commonPrefix + 4 same prefix bytes.
398     assertKVLessWithoutRow(c, commonLength + 4, kv0_1, kv1_0);
399     // 'fami:qf1' < 'fami:qf2'. They have commonPrefix + 6 same prefix bytes.
400     assertKVLessWithoutRow(c, commonLength + 6, kv0_1, kv0_2);
401   }
402 
403   public void testFirstLastOnRow() {
404     final KVComparator c = KeyValue.COMPARATOR;
405     long ts = 1;
406 
407     // These are listed in sort order (ie: every one should be less
408     // than the one on the next line).
409     final KeyValue firstOnRowA = KeyValue.createFirstOnRow(rowA);
410     final KeyValue kvA_1 = new KeyValue(rowA, null, null, ts, Type.Put);
411     final KeyValue kvA_2 = new KeyValue(rowA, family, qualA, ts, Type.Put);
412         
413     final KeyValue lastOnRowA = KeyValue.createLastOnRow(rowA);
414     final KeyValue firstOnRowB = KeyValue.createFirstOnRow(rowB);
415     final KeyValue kvB = new KeyValue(rowB, family, qualA, ts, Type.Put);
416 
417     assertKVLess(c, firstOnRowA, firstOnRowB);
418     assertKVLess(c, firstOnRowA, kvA_1);
419     assertKVLess(c, firstOnRowA, kvA_2);
420     assertKVLess(c, kvA_1, kvA_2);
421     assertKVLess(c, kvA_2, firstOnRowB);
422     assertKVLess(c, kvA_1, firstOnRowB);
423 
424     assertKVLess(c, lastOnRowA, firstOnRowB);
425     assertKVLess(c, firstOnRowB, kvB);
426     assertKVLess(c, lastOnRowA, kvB);
427 
428     assertKVLess(c, kvA_2, lastOnRowA);
429     assertKVLess(c, kvA_1, lastOnRowA);
430     assertKVLess(c, firstOnRowA, lastOnRowA);
431   }
432 
433   public void testCreateKeyOnly() throws Exception {
434     long ts = 1;
435     byte [] value = Bytes.toBytes("a real value");
436     byte [] evalue = new byte[0]; // empty value
437 
438     for (byte[] val : new byte[][]{value, evalue}) {
439       for (boolean useLen : new boolean[]{false,true}) {
440         KeyValue kv1 = new KeyValue(rowA, family, qualA, ts, val);
441         KeyValue kv1ko = kv1.createKeyOnly(useLen);
442         // keys are still the same
443         assertTrue(kv1.equals(kv1ko));
444         // but values are not
445         assertTrue(kv1ko.getValue().length == (useLen?Bytes.SIZEOF_INT:0));
446         if (useLen) {
447           assertEquals(kv1.getValueLength(), Bytes.toInt(kv1ko.getValue()));
448         }
449       }
450     }
451   }
452 
453   public void testCreateKeyValueFromKey() {
454     KeyValue kv = new KeyValue(Bytes.toBytes("myRow"), Bytes.toBytes("myCF"),
455         Bytes.toBytes("myQualifier"), 12345L, Bytes.toBytes("myValue"));
456     int initialPadding = 10;
457     int endingPadding = 20;
458     int keyLen = kv.getKeyLength();
459     byte[] tmpArr = new byte[initialPadding + endingPadding + keyLen];
460     System.arraycopy(kv.getBuffer(), kv.getKeyOffset(), tmpArr,
461         initialPadding, keyLen);
462     KeyValue kvFromKey = KeyValue.createKeyValueFromKey(tmpArr, initialPadding,
463         keyLen);
464     assertEquals(keyLen, kvFromKey.getKeyLength());
465     assertEquals(KeyValue.ROW_OFFSET + keyLen, kvFromKey.getBuffer().length);
466     System.err.println("kv=" + kv);
467     System.err.println("kvFromKey=" + kvFromKey);
468     assertEquals(kvFromKey.toString(),
469         kv.toString().replaceAll("=[0-9]+", "=0"));
470   }
471 
472   /**
473    * The row cache is cleared and re-read for the new value
474    *
475    * @throws IOException
476    */
477   public void testReadFields() throws IOException {
478     KeyValue kv1 = new KeyValue(Bytes.toBytes("row1"), Bytes.toBytes("cf1"),
479         Bytes.toBytes("qualifier1"), 12345L, Bytes.toBytes("value1"));
480     kv1.getRow(); // set row cache of kv1
481     KeyValue kv2 = new KeyValue(Bytes.toBytes("row2"), Bytes.toBytes("cf2"),
482         Bytes.toBytes("qualifier2"), 12345L, Bytes.toBytes("value2"));
483     kv1.readFields(new DataInputStream(new ByteArrayInputStream(WritableUtils
484         .toByteArray(kv2))));
485     // check equality
486     assertEquals(kv1, kv2);
487     // check cache state (getRow() return the cached value if the cache is set)
488     assertTrue(Bytes.equals(kv1.getRow(), kv2.getRow()));
489   }
490 
491   /**
492    * Tests that getTimestamp() does always return the proper timestamp, even after updating it.
493    * See HBASE-6265.
494    */
495   public void testGetTimestamp() {
496     KeyValue kv = new KeyValue(Bytes.toBytes("myRow"), Bytes.toBytes("myCF"),
497       Bytes.toBytes("myQualifier"), HConstants.LATEST_TIMESTAMP,
498       Bytes.toBytes("myValue"));
499     long time1 = kv.getTimestamp();
500     kv.updateLatestStamp(Bytes.toBytes(12345L));
501     long time2 = kv.getTimestamp();
502     assertEquals(HConstants.LATEST_TIMESTAMP, time1);
503     assertEquals(12345L, time2);
504   }
505 
506   @org.junit.Rule
507   public org.apache.hadoop.hbase.ResourceCheckerJUnitRule cu =
508     new org.apache.hadoop.hbase.ResourceCheckerJUnitRule();
509 }
510