001/**
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *     http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019package org.apache.hadoop.hbase;
020
021import static org.junit.Assert.assertNotEquals;
022
023import java.io.ByteArrayInputStream;
024import java.io.ByteArrayOutputStream;
025import java.io.DataInputStream;
026import java.io.DataOutputStream;
027import java.io.IOException;
028import java.util.Collections;
029import java.util.Iterator;
030import java.util.List;
031import java.util.Set;
032import java.util.TreeSet;
033
034import org.apache.hadoop.hbase.util.ByteBufferUtils;
035import org.apache.hadoop.hbase.util.Bytes;
036import org.slf4j.Logger;
037import org.slf4j.LoggerFactory;
038
039import junit.framework.TestCase;
040
041public class TestKeyValue extends TestCase {
042  private static final Logger LOG = LoggerFactory.getLogger(TestKeyValue.class);
043
044  public void testColumnCompare() throws Exception {
045    final byte [] a = Bytes.toBytes("aaa");
046    byte [] family1 = Bytes.toBytes("abc");
047    byte [] qualifier1 = Bytes.toBytes("def");
048    byte [] family2 = Bytes.toBytes("abcd");
049    byte [] qualifier2 = Bytes.toBytes("ef");
050
051    KeyValue aaa = new KeyValue(a, family1, qualifier1, 0L, KeyValue.Type.Put, a);
052    assertFalse(CellUtil.matchingColumn(aaa, family2, qualifier2));
053    assertTrue(CellUtil.matchingColumn(aaa, family1, qualifier1));
054    aaa = new KeyValue(a, family2, qualifier2, 0L, KeyValue.Type.Put, a);
055    assertFalse(CellUtil.matchingColumn(aaa, family1, qualifier1));
056    assertTrue(CellUtil.matchingColumn(aaa, family2,qualifier2));
057    byte [] nullQualifier = new byte[0];
058    aaa = new KeyValue(a, family1, nullQualifier, 0L, KeyValue.Type.Put, a);
059    assertTrue(CellUtil.matchingColumn(aaa, family1,null));
060    assertFalse(CellUtil.matchingColumn(aaa, family2,qualifier2));
061  }
062
063  /**
064   * Test a corner case when the family qualifier is a prefix of the
065   *  column qualifier.
066   */
067  public void testColumnCompare_prefix() throws Exception {
068    final byte [] a = Bytes.toBytes("aaa");
069    byte [] family1 = Bytes.toBytes("abc");
070    byte [] qualifier1 = Bytes.toBytes("def");
071    byte [] family2 = Bytes.toBytes("ab");
072    byte [] qualifier2 = Bytes.toBytes("def");
073
074    KeyValue aaa = new KeyValue(a, family1, qualifier1, 0L, KeyValue.Type.Put, a);
075    assertFalse(CellUtil.matchingColumn(aaa, family2, qualifier2));
076  }
077
078  public void testBasics() throws Exception {
079    LOG.info("LOWKEY: " + KeyValue.LOWESTKEY.toString());
080    check(Bytes.toBytes(getName()),
081      Bytes.toBytes(getName()), Bytes.toBytes(getName()), 1,
082      Bytes.toBytes(getName()));
083    // Test empty value and empty column -- both should work. (not empty fam)
084    check(Bytes.toBytes(getName()), Bytes.toBytes(getName()), null, 1, null);
085    check(HConstants.EMPTY_BYTE_ARRAY, Bytes.toBytes(getName()), null, 1, null);
086    // empty qual is equivalent to null qual
087    assertEquals(
088      new KeyValue(Bytes.toBytes("rk"), Bytes.toBytes("fam"), null, 1, (byte[]) null),
089      new KeyValue(Bytes.toBytes("rk"), Bytes.toBytes("fam"),
090        HConstants.EMPTY_BYTE_ARRAY, 1, (byte[]) null));
091  }
092
093  private void check(final byte [] row, final byte [] family, byte [] qualifier,
094    final long timestamp, final byte [] value) {
095    KeyValue kv = new KeyValue(row, family, qualifier, timestamp, value);
096    assertTrue(Bytes.compareTo(kv.getRowArray(), kv.getRowOffset(), kv.getRowLength(), row, 0,
097      row.length) == 0);
098    assertTrue(CellUtil.matchingColumn(kv, family, qualifier));
099    // Call toString to make sure it works.
100    LOG.info(kv.toString());
101  }
102
103  public void testPlainCompare() throws Exception {
104    final byte [] a = Bytes.toBytes("aaa");
105    final byte [] b = Bytes.toBytes("bbb");
106    final byte [] fam = Bytes.toBytes("col");
107    final byte [] qf = Bytes.toBytes("umn");
108    KeyValue aaa = new KeyValue(a, fam, qf, a);
109    KeyValue bbb = new KeyValue(b, fam, qf, b);
110    assertTrue(CellComparatorImpl.COMPARATOR.compare(aaa, bbb) < 0);
111    assertTrue(CellComparatorImpl.COMPARATOR.compare(bbb, aaa) > 0);
112    // Compare breaks if passed same ByteBuffer as both left and right arguments.
113    assertTrue(CellComparatorImpl.COMPARATOR.compare(bbb, bbb) == 0);
114    assertTrue(CellComparatorImpl.COMPARATOR.compare(aaa, aaa) == 0);
115    // Do compare with different timestamps.
116    aaa = new KeyValue(a, fam, qf, 1, a);
117    bbb = new KeyValue(a, fam, qf, 2, a);
118    assertTrue(CellComparatorImpl.COMPARATOR.compare(aaa, bbb) > 0);
119    assertTrue(CellComparatorImpl.COMPARATOR.compare(bbb, aaa) < 0);
120    assertTrue(CellComparatorImpl.COMPARATOR.compare(aaa, aaa) == 0);
121    // Do compare with different types.  Higher numbered types -- Delete
122    // should sort ahead of lower numbers; i.e. Put
123    aaa = new KeyValue(a, fam, qf, 1, KeyValue.Type.Delete, a);
124    bbb = new KeyValue(a, fam, qf, 1, a);
125    assertTrue(CellComparatorImpl.COMPARATOR.compare(aaa, bbb) < 0);
126    assertTrue(CellComparatorImpl.COMPARATOR.compare(bbb, aaa) > 0);
127    assertTrue(CellComparatorImpl.COMPARATOR.compare(aaa, aaa) == 0);
128  }
129
130  public void testMoreComparisons() throws Exception {
131    long now = System.currentTimeMillis();
132
133    // Meta compares
134    KeyValue aaa = new KeyValue(
135        Bytes.toBytes("TestScanMultipleVersions,row_0500,1236020145502"), now);
136    KeyValue bbb = new KeyValue(
137        Bytes.toBytes("TestScanMultipleVersions,,99999999999999"), now);
138    CellComparator c = CellComparatorImpl.META_COMPARATOR;
139    assertTrue(c.compare(bbb, aaa) < 0);
140
141    KeyValue aaaa = new KeyValue(Bytes.toBytes("TestScanMultipleVersions,,1236023996656"),
142        Bytes.toBytes("info"), Bytes.toBytes("regioninfo"), 1236024396271L,
143        (byte[])null);
144    assertTrue(c.compare(aaaa, bbb) < 0);
145
146    KeyValue x = new KeyValue(Bytes.toBytes("TestScanMultipleVersions,row_0500,1236034574162"),
147        Bytes.toBytes("info"), Bytes.toBytes(""), 9223372036854775807L,
148        (byte[])null);
149    KeyValue y = new KeyValue(Bytes.toBytes("TestScanMultipleVersions,row_0500,1236034574162"),
150        Bytes.toBytes("info"), Bytes.toBytes("regioninfo"), 1236034574912L,
151        (byte[])null);
152    assertTrue(c.compare(x, y) < 0);
153    comparisons(CellComparatorImpl.META_COMPARATOR);
154    comparisons(CellComparatorImpl.COMPARATOR);
155    metacomparisons(CellComparatorImpl.META_COMPARATOR);
156  }
157
158  public void testMetaComparatorTableKeysWithCommaOk() {
159    CellComparator c = CellComparatorImpl.META_COMPARATOR;
160    long now = System.currentTimeMillis();
161    // meta keys values are not quite right.  A users can enter illegal values
162    // from shell when scanning meta.
163    KeyValue a = new KeyValue(Bytes.toBytes("table,key,with,commas1,1234"), now);
164    KeyValue b = new KeyValue(Bytes.toBytes("table,key,with,commas2,0123"), now);
165    assertTrue(c.compare(a, b) < 0);
166  }
167
168  /**
169   * Tests cases where rows keys have characters below the ','.
170   * See HBASE-832
171   * @throws IOException
172   */
173  public void testKeyValueBorderCases() throws IOException {
174    // % sorts before , so if we don't do special comparator, rowB would
175    // come before rowA.
176    KeyValue rowA = new KeyValue(Bytes.toBytes("testtable,www.hbase.org/,1234"),
177      Bytes.toBytes("fam"), Bytes.toBytes(""), Long.MAX_VALUE, (byte[])null);
178    KeyValue rowB = new KeyValue(Bytes.toBytes("testtable,www.hbase.org/%20,99999"),
179        Bytes.toBytes("fam"), Bytes.toBytes(""), Long.MAX_VALUE, (byte[])null);
180    assertTrue(CellComparatorImpl.META_COMPARATOR.compare(rowA, rowB) < 0);
181
182    rowA = new KeyValue(Bytes.toBytes("testtable,,1234"), Bytes.toBytes("fam"),
183        Bytes.toBytes(""), Long.MAX_VALUE, (byte[])null);
184    rowB = new KeyValue(Bytes.toBytes("testtable,$www.hbase.org/,99999"),
185        Bytes.toBytes("fam"), Bytes.toBytes(""), Long.MAX_VALUE, (byte[])null);
186    assertTrue(CellComparatorImpl.META_COMPARATOR.compare(rowA, rowB) < 0);
187
188  }
189
190  private void metacomparisons(final CellComparatorImpl c) {
191    long now = System.currentTimeMillis();
192    assertTrue(c.compare(new KeyValue(
193        Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",a,,0,1"), now),
194      new KeyValue(
195          Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",a,,0,1"), now)) == 0);
196    KeyValue a = new KeyValue(
197        Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",a,,0,1"), now);
198    KeyValue b = new KeyValue(
199        Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",a,,0,2"), now);
200    assertTrue(c.compare(a, b) < 0);
201    assertTrue(c.compare(new KeyValue(
202        Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",a,,0,2"), now),
203      new KeyValue(
204          Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",a,,0,1"), now)) > 0);
205  }
206
207  private void comparisons(final CellComparatorImpl c) {
208    long now = System.currentTimeMillis();
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()+",,1"), now)) == 0);
213    assertTrue(c.compare(new KeyValue(
214        Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",,1"), now),
215      new KeyValue(
216          Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",,2"), now)) < 0);
217    assertTrue(c.compare(new KeyValue(
218        Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",,2"), now),
219      new KeyValue(
220          Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",,1"), now)) > 0);
221  }
222
223  public void testBinaryKeys() throws Exception {
224    Set<KeyValue> set = new TreeSet<>(CellComparatorImpl.COMPARATOR);
225    final byte [] fam = Bytes.toBytes("col");
226    final byte [] qf = Bytes.toBytes("umn");
227    final byte [] nb = new byte[0];
228    KeyValue [] keys = {new KeyValue(Bytes.toBytes("aaaaa,\u0000\u0000,2"), fam, qf, 2, nb),
229      new KeyValue(Bytes.toBytes("aaaaa,\u0001,3"), fam, qf, 3, nb),
230      new KeyValue(Bytes.toBytes("aaaaa,,1"), fam, qf, 1, nb),
231      new KeyValue(Bytes.toBytes("aaaaa,\u1000,5"), fam, qf, 5, nb),
232      new KeyValue(Bytes.toBytes("aaaaa,a,4"), fam, qf, 4, nb),
233      new KeyValue(Bytes.toBytes("a,a,0"), fam, qf, 0, nb),
234    };
235    // Add to set with bad comparator
236    Collections.addAll(set, keys);
237    // This will output the keys incorrectly.
238    boolean assertion = false;
239    int count = 0;
240    try {
241      for (KeyValue k: set) {
242        assertTrue(count++ == k.getTimestamp());
243      }
244    } catch (junit.framework.AssertionFailedError e) {
245      // Expected
246      assertion = true;
247    }
248    assertTrue(assertion);
249    // Make set with good comparator
250    set = new TreeSet<>(CellComparatorImpl.META_COMPARATOR);
251    Collections.addAll(set, keys);
252    count = 0;
253    for (KeyValue k: set) {
254      assertTrue(count++ == k.getTimestamp());
255    }
256  }
257
258  public void testStackedUpKeyValue() {
259    // Test multiple KeyValues in a single blob.
260
261    // TODO actually write this test!
262
263  }
264
265  private final byte[] rowA = Bytes.toBytes("rowA");
266  private final byte[] rowB = Bytes.toBytes("rowB");
267
268  private final byte[] family = Bytes.toBytes("family");
269  private final byte[] qualA = Bytes.toBytes("qfA");
270  private final byte[] qualB = Bytes.toBytes("qfB");
271
272  private void assertKVLess(CellComparator c,
273                            KeyValue less,
274                            KeyValue greater) {
275    int cmp = c.compare(less,greater);
276    assertTrue(cmp < 0);
277    cmp = c.compare(greater,less);
278    assertTrue(cmp > 0);
279  }
280
281  private void assertKVLessWithoutRow(CellComparator c, int common, KeyValue less,
282      KeyValue greater) {
283    int cmp = c.compare(less, greater);
284    assertTrue(cmp < 0);
285    cmp = c.compare(greater, less);
286    assertTrue(cmp > 0);
287  }
288
289  public void testCompareWithoutRow() {
290    final CellComparator c = CellComparatorImpl.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, KeyValue.Type.Put);
304    // 'fami:'
305    KeyValue kv0_0 = new KeyValue(row, fami, qual0, ts, KeyValue.Type.Put);
306    // 'fami:qf1'
307    KeyValue kv0_1 = new KeyValue(row, fami, qual1, ts, KeyValue.Type.Put);
308    // 'fami:qf2'
309    KeyValue kv0_2 = new KeyValue(row, fami, qual2, ts, KeyValue.Type.Put);
310    // 'fami1:'
311    KeyValue kv1_0 = new KeyValue(row, fami1, qual0, ts, KeyValue.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 CellComparator c = CellComparatorImpl.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 = KeyValueUtil.createFirstOnRow(rowA);
347    final KeyValue firstOnRowABufferFamQual = KeyValueUtil.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, KeyValue.Type.Put);
350    final KeyValue kvA_2 = new KeyValue(rowA, family, qualA, ts, KeyValue.Type.Put);
351
352    final KeyValue lastOnRowA = KeyValueUtil.createLastOnRow(rowA);
353    final KeyValue firstOnRowB = KeyValueUtil.createFirstOnRow(rowB);
354    final KeyValue firstOnRowBBufferFam = KeyValueUtil.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, KeyValue.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.getValueLength() == (useLen?Bytes.SIZEOF_INT:0));
395        if (useLen) {
396          assertEquals(kv1.getValueLength(),
397            Bytes.toInt(kv1ko.getValueArray(), kv1ko.getValueOffset(), kv1ko.getValueLength()));
398        }
399      }
400    }
401  }
402
403  public void testCreateKeyValueFromKey() {
404    KeyValue kv = new KeyValue(Bytes.toBytes("myRow"), Bytes.toBytes("myCF"),
405        Bytes.toBytes("myQualifier"), 12345L, Bytes.toBytes("myValue"));
406    int initialPadding = 10;
407    int endingPadding = 20;
408    int keyLen = kv.getKeyLength();
409    byte[] tmpArr = new byte[initialPadding + endingPadding + keyLen];
410    System.arraycopy(kv.getBuffer(), kv.getKeyOffset(), tmpArr,
411        initialPadding, keyLen);
412    KeyValue kvFromKey = KeyValueUtil.createKeyValueFromKey(tmpArr, initialPadding,
413        keyLen);
414    assertEquals(keyLen, kvFromKey.getKeyLength());
415    assertEquals(KeyValue.ROW_OFFSET + keyLen, kvFromKey.getBuffer().length);
416    System.err.println("kv=" + kv);
417    System.err.println("kvFromKey=" + kvFromKey);
418    assertEquals(kvFromKey.toString(),
419        kv.toString().replaceAll("=[0-9]+", "=0"));
420  }
421
422  /**
423   * Tests that getTimestamp() does always return the proper timestamp, even after updating it.
424   * See HBASE-6265.
425   */
426  public void testGetTimestamp() {
427    KeyValue kv = new KeyValue(Bytes.toBytes("myRow"), Bytes.toBytes("myCF"),
428      Bytes.toBytes("myQualifier"), HConstants.LATEST_TIMESTAMP,
429      Bytes.toBytes("myValue"));
430    long time1 = kv.getTimestamp();
431    kv.updateLatestStamp(Bytes.toBytes(12345L));
432    long time2 = kv.getTimestamp();
433    assertEquals(HConstants.LATEST_TIMESTAMP, time1);
434    assertEquals(12345L, time2);
435  }
436
437  public void testKVsWithTags() {
438    byte[] row = Bytes.toBytes("myRow");
439    byte[] cf = Bytes.toBytes("myCF");
440    byte[] q = Bytes.toBytes("myQualifier");
441    byte[] value = Bytes.toBytes("myValue");
442    byte[] metaValue1 = Bytes.toBytes("metaValue1");
443    byte[] metaValue2 = Bytes.toBytes("metaValue2");
444    KeyValue kv = new KeyValue(row, cf, q, HConstants.LATEST_TIMESTAMP, value, new Tag[] {
445        new ArrayBackedTag((byte) 1, metaValue1), new ArrayBackedTag((byte) 2, metaValue2) });
446    assertTrue(kv.getTagsLength() > 0);
447    assertTrue(Bytes.equals(kv.getRowArray(), kv.getRowOffset(), kv.getRowLength(), row, 0,
448      row.length));
449    assertTrue(Bytes.equals(kv.getFamilyArray(), kv.getFamilyOffset(), kv.getFamilyLength(), cf, 0,
450      cf.length));
451    assertTrue(Bytes.equals(kv.getQualifierArray(), kv.getQualifierOffset(),
452      kv.getQualifierLength(), q, 0, q.length));
453    assertTrue(Bytes.equals(kv.getValueArray(), kv.getValueOffset(), kv.getValueLength(), value, 0,
454      value.length));
455    List<Tag> tags = PrivateCellUtil.getTags(kv);
456    assertNotNull(tags);
457    assertEquals(2, tags.size());
458    boolean meta1Ok = false, meta2Ok = false;
459    for (Tag tag : tags) {
460      if (tag.getType() == (byte) 1) {
461        if (Bytes.equals(Tag.cloneValue(tag), metaValue1)) {
462          meta1Ok = true;
463        }
464      } else {
465        if (Bytes.equals(Tag.cloneValue(tag), metaValue2)) {
466          meta2Ok = true;
467        }
468      }
469    }
470    assertTrue(meta1Ok);
471    assertTrue(meta2Ok);
472    Iterator<Tag> tagItr = PrivateCellUtil.tagsIterator(kv);
473    //Iterator<Tag> tagItr = kv.tagsIterator();
474    assertTrue(tagItr.hasNext());
475    Tag next = tagItr.next();
476    assertEquals(10, next.getValueLength());
477    assertEquals((byte) 1, next.getType());
478    Bytes.equals(Tag.cloneValue(next), metaValue1);
479    assertTrue(tagItr.hasNext());
480    next = tagItr.next();
481    assertEquals(10, next.getValueLength());
482    assertEquals((byte) 2, next.getType());
483    Bytes.equals(Tag.cloneValue(next), metaValue2);
484    assertFalse(tagItr.hasNext());
485
486    tagItr = PrivateCellUtil.tagsIterator(kv);
487    assertTrue(tagItr.hasNext());
488    next = tagItr.next();
489    assertEquals(10, next.getValueLength());
490    assertEquals((byte) 1, next.getType());
491    Bytes.equals(Tag.cloneValue(next), metaValue1);
492    assertTrue(tagItr.hasNext());
493    next = tagItr.next();
494    assertEquals(10, next.getValueLength());
495    assertEquals((byte) 2, next.getType());
496    Bytes.equals(Tag.cloneValue(next), metaValue2);
497    assertFalse(tagItr.hasNext());
498  }
499
500  public void testMetaKeyComparator() {
501    CellComparator c = CellComparatorImpl.META_COMPARATOR;
502    long now = System.currentTimeMillis();
503
504    KeyValue a = new KeyValue(Bytes.toBytes("table1"), now);
505    KeyValue b = new KeyValue(Bytes.toBytes("table2"), now);
506    assertTrue(c.compare(a, b) < 0);
507
508    a = new KeyValue(Bytes.toBytes("table1,111"), now);
509    b = new KeyValue(Bytes.toBytes("table2"), now);
510    assertTrue(c.compare(a, b) < 0);
511
512    a = new KeyValue(Bytes.toBytes("table1"), now);
513    b = new KeyValue(Bytes.toBytes("table2,111"), now);
514    assertTrue(c.compare(a, b) < 0);
515
516    a = new KeyValue(Bytes.toBytes("table,111"), now);
517    b = new KeyValue(Bytes.toBytes("table,2222"), now);
518    assertTrue(c.compare(a, b) < 0);
519
520    a = new KeyValue(Bytes.toBytes("table,111,aaaa"), now);
521    b = new KeyValue(Bytes.toBytes("table,2222"), now);
522    assertTrue(c.compare(a, b) < 0);
523
524    a = new KeyValue(Bytes.toBytes("table,111"), now);
525    b = new KeyValue(Bytes.toBytes("table,2222.bbb"), now);
526    assertTrue(c.compare(a, b) < 0);
527
528    a = new KeyValue(Bytes.toBytes("table,,aaaa"), now);
529    b = new KeyValue(Bytes.toBytes("table,111,bbb"), now);
530    assertTrue(c.compare(a, b) < 0);
531
532    a = new KeyValue(Bytes.toBytes("table,111,aaaa"), now);
533    b = new KeyValue(Bytes.toBytes("table,111,bbb"), now);
534    assertTrue(c.compare(a, b) < 0);
535
536    a = new KeyValue(Bytes.toBytes("table,111,xxxx"), now);
537    b = new KeyValue(Bytes.toBytes("table,111,222,bbb"), now);
538    assertTrue(c.compare(a, b) < 0);
539
540    a = new KeyValue(Bytes.toBytes("table,111,11,xxx"), now);
541    b = new KeyValue(Bytes.toBytes("table,111,222,bbb"), now);
542    assertTrue(c.compare(a, b) < 0);
543  }
544
545  public void testEqualsAndHashCode() throws Exception {
546    KeyValue kvA1 = new KeyValue(Bytes.toBytes("key"), Bytes.toBytes("cf"),
547        Bytes.toBytes("qualA"), Bytes.toBytes("1"));
548    KeyValue kvA2 = new KeyValue(Bytes.toBytes("key"), Bytes.toBytes("cf"),
549        Bytes.toBytes("qualA"), Bytes.toBytes("2"));
550    // We set a different sequence id on kvA2 to demonstrate that the equals and hashCode also
551    // don't take this into account.
552    kvA2.setSequenceId(2);
553    KeyValue kvB = new KeyValue(Bytes.toBytes("key"), Bytes.toBytes("cf"),
554        Bytes.toBytes("qualB"), Bytes.toBytes("1"));
555
556    assertEquals(kvA1, kvA2);
557    assertNotEquals(kvA1, kvB);
558    assertEquals(kvA1.hashCode(), kvA2.hashCode());
559    assertNotEquals(kvA1.hashCode(), kvB.hashCode());
560
561  }
562
563  public void testKeyValueSerialization() throws Exception {
564    KeyValue kvA1 = new KeyValue(Bytes.toBytes("key"), Bytes.toBytes("cf"), Bytes.toBytes("qualA"),
565        Bytes.toBytes("1"));
566    KeyValue kvA2 = new KeyValue(Bytes.toBytes("key"), Bytes.toBytes("cf"), Bytes.toBytes("qualA"),
567        Bytes.toBytes("2"));
568    MockKeyValue mkvA1 = new MockKeyValue(kvA1);
569    MockKeyValue mkvA2 = new MockKeyValue(kvA2);
570    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
571    DataOutputStream os = new DataOutputStream(byteArrayOutputStream);
572    ByteBufferUtils.putInt(os, KeyValueUtil.getSerializedSize(mkvA1, true));
573    KeyValueUtil.oswrite(mkvA1, os, true);
574    ByteBufferUtils.putInt(os, KeyValueUtil.getSerializedSize(mkvA2, true));
575    KeyValueUtil.oswrite(mkvA2, os, true);
576    DataInputStream is = new DataInputStream(new ByteArrayInputStream(
577        byteArrayOutputStream.toByteArray()));
578    KeyValue deSerKV1 = KeyValueUtil.iscreate(is, true);
579    assertTrue(kvA1.equals(deSerKV1));
580    KeyValue deSerKV2 = KeyValueUtil.iscreate(is, true);
581    assertTrue(kvA2.equals(deSerKV2));
582  }
583
584  private static class MockKeyValue implements Cell {
585    private final KeyValue kv;
586
587    public MockKeyValue(KeyValue kv) {
588      this.kv = kv;
589    }
590
591    /**
592     * This returns the offset where the tag actually starts.
593     */
594    @Override
595    public int getTagsOffset() {
596      return this.kv.getTagsOffset();
597    }
598
599    /**
600     * used to achieve atomic operations in the memstore.
601     */
602    @Override
603    public long getSequenceId() {
604      return this.kv.getSequenceId();
605    }
606
607    /**
608     * This returns the total length of the tag bytes
609     */
610    @Override
611    public int getTagsLength() {
612      return this.kv.getTagsLength();
613    }
614
615    /**
616     *
617     * @return Timestamp
618     */
619    @Override
620    public long getTimestamp() {
621      return this.kv.getTimestamp();
622    }
623
624    /**
625     * @return KeyValue.TYPE byte representation
626     */
627    @Override
628    public byte getTypeByte() {
629      return this.kv.getTypeByte();
630    }
631
632    /**
633     * @return the backing array of the entire KeyValue (all KeyValue fields are
634     *         in a single array)
635     */
636    @Override
637    public byte[] getValueArray() {
638      return this.kv.getValueArray();
639    }
640
641    /**
642     * @return the value offset
643     */
644    @Override
645    public int getValueOffset() {
646      return this.kv.getValueOffset();
647    }
648
649    /**
650     * @return Value length
651     */
652    @Override
653    public int getValueLength() {
654      return this.kv.getValueLength();
655    }
656
657    /**
658     * @return the backing array of the entire KeyValue (all KeyValue fields are
659     *         in a single array)
660     */
661    @Override
662    public byte[] getRowArray() {
663      return this.kv.getRowArray();
664    }
665
666    /**
667     * @return Row offset
668     */
669    @Override
670    public int getRowOffset() {
671      return this.kv.getRowOffset();
672    }
673
674    /**
675     * @return Row length
676     */
677    @Override
678    public short getRowLength() {
679      return this.kv.getRowLength();
680    }
681
682    /**
683     * @return the backing array of the entire KeyValue (all KeyValue fields are
684     *         in a single array)
685     */
686    @Override
687    public byte[] getFamilyArray() {
688      return this.kv.getFamilyArray();
689    }
690
691    /**
692     * @return Family offset
693     */
694    @Override
695    public int getFamilyOffset() {
696      return this.kv.getFamilyOffset();
697    }
698
699    /**
700     * @return Family length
701     */
702    @Override
703    public byte getFamilyLength() {
704      return this.kv.getFamilyLength();
705    }
706
707    /**
708     * @return the backing array of the entire KeyValue (all KeyValue fields are
709     *         in a single array)
710     */
711    @Override
712    public byte[] getQualifierArray() {
713      return this.kv.getQualifierArray();
714    }
715
716    /**
717     * @return Qualifier offset
718     */
719    @Override
720    public int getQualifierOffset() {
721      return this.kv.getQualifierOffset();
722    }
723
724    /**
725     * @return Qualifier length
726     */
727    @Override
728    public int getQualifierLength() {
729      return this.kv.getQualifierLength();
730    }
731
732    /**
733     * @return the backing array of the entire KeyValue (all KeyValue fields are
734     *         in a single array)
735     */
736    @Override
737    public byte[] getTagsArray() {
738      return this.kv.getTagsArray();
739    }
740  }
741}