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.assertArrayEquals; 022import static org.junit.Assert.assertEquals; 023import static org.junit.Assert.assertFalse; 024import static org.junit.Assert.assertNotEquals; 025import static org.junit.Assert.assertNotNull; 026import static org.junit.Assert.assertTrue; 027 028import java.io.ByteArrayInputStream; 029import java.io.ByteArrayOutputStream; 030import java.io.DataInputStream; 031import java.io.DataOutputStream; 032import java.io.IOException; 033import java.util.Collections; 034import java.util.Iterator; 035import java.util.List; 036import java.util.Set; 037import java.util.TreeSet; 038 039import org.apache.hadoop.hbase.testclassification.SmallTests; 040import org.apache.hadoop.hbase.util.ByteBufferUtils; 041import org.apache.hadoop.hbase.util.Bytes; 042import org.junit.Assert; 043import org.junit.ClassRule; 044import org.junit.Test; 045import org.junit.experimental.categories.Category; 046import org.slf4j.Logger; 047import org.slf4j.LoggerFactory; 048 049 050@Category(SmallTests.class) 051public class TestKeyValue { 052 @ClassRule 053 public static final HBaseClassTestRule CLASS_RULE = 054 HBaseClassTestRule.forClass(TestKeyValue.class); 055 private static final Logger LOG = LoggerFactory.getLogger(TestKeyValue.class); 056 057 @Test 058 public void testColumnCompare() throws Exception { 059 final byte [] a = Bytes.toBytes("aaa"); 060 byte [] family1 = Bytes.toBytes("abc"); 061 byte [] qualifier1 = Bytes.toBytes("def"); 062 byte [] family2 = Bytes.toBytes("abcd"); 063 byte [] qualifier2 = Bytes.toBytes("ef"); 064 065 KeyValue aaa = new KeyValue(a, family1, qualifier1, 0L, KeyValue.Type.Put, a); 066 assertFalse(CellUtil.matchingColumn(aaa, family2, qualifier2)); 067 assertTrue(CellUtil.matchingColumn(aaa, family1, qualifier1)); 068 aaa = new KeyValue(a, family2, qualifier2, 0L, KeyValue.Type.Put, a); 069 assertFalse(CellUtil.matchingColumn(aaa, family1, qualifier1)); 070 assertTrue(CellUtil.matchingColumn(aaa, family2,qualifier2)); 071 byte [] nullQualifier = new byte[0]; 072 aaa = new KeyValue(a, family1, nullQualifier, 0L, KeyValue.Type.Put, a); 073 assertTrue(CellUtil.matchingColumn(aaa, family1,null)); 074 assertFalse(CellUtil.matchingColumn(aaa, family2,qualifier2)); 075 } 076 077 /** 078 * Test a corner case when the family qualifier is a prefix of the 079 * column qualifier. 080 */ 081 @Test 082 public void testColumnCompare_prefix() throws Exception { 083 final byte [] a = Bytes.toBytes("aaa"); 084 byte [] family1 = Bytes.toBytes("abc"); 085 byte [] qualifier1 = Bytes.toBytes("def"); 086 byte [] family2 = Bytes.toBytes("ab"); 087 byte [] qualifier2 = Bytes.toBytes("def"); 088 089 KeyValue aaa = new KeyValue(a, family1, qualifier1, 0L, KeyValue.Type.Put, a); 090 assertFalse(CellUtil.matchingColumn(aaa, family2, qualifier2)); 091 } 092 093 @Test 094 public void testBasics() throws Exception { 095 LOG.info("LOWKEY: " + KeyValue.LOWESTKEY.toString()); 096 String name = "testBasics"; 097 check(Bytes.toBytes(name), 098 Bytes.toBytes(name), Bytes.toBytes(name), 1, 099 Bytes.toBytes(name)); 100 // Test empty value and empty column -- both should work. (not empty fam) 101 check(Bytes.toBytes(name), Bytes.toBytes(name), null, 1, null); 102 check(HConstants.EMPTY_BYTE_ARRAY, Bytes.toBytes(name), null, 1, null); 103 // empty qual is equivalent to null qual 104 assertEquals( 105 new KeyValue(Bytes.toBytes("rk"), Bytes.toBytes("fam"), null, 1, (byte[]) null), 106 new KeyValue(Bytes.toBytes("rk"), Bytes.toBytes("fam"), 107 HConstants.EMPTY_BYTE_ARRAY, 1, (byte[]) null)); 108 } 109 110 private void check(final byte [] row, final byte [] family, byte [] qualifier, 111 final long timestamp, final byte [] value) { 112 KeyValue kv = new KeyValue(row, family, qualifier, timestamp, value); 113 assertTrue(Bytes.compareTo(kv.getRowArray(), kv.getRowOffset(), kv.getRowLength(), row, 0, 114 row.length) == 0); 115 assertTrue(CellUtil.matchingColumn(kv, family, qualifier)); 116 // Call toString to make sure it works. 117 LOG.info(kv.toString()); 118 } 119 120 @Test 121 public void testPlainCompare() throws Exception { 122 final byte [] a = Bytes.toBytes("aaa"); 123 final byte [] b = Bytes.toBytes("bbb"); 124 final byte [] fam = Bytes.toBytes("col"); 125 final byte [] qf = Bytes.toBytes("umn"); 126 KeyValue aaa = new KeyValue(a, fam, qf, a); 127 KeyValue bbb = new KeyValue(b, fam, qf, b); 128 assertTrue(CellComparatorImpl.COMPARATOR.compare(aaa, bbb) < 0); 129 assertTrue(CellComparatorImpl.COMPARATOR.compare(bbb, aaa) > 0); 130 // Compare breaks if passed same ByteBuffer as both left and right arguments. 131 assertTrue(CellComparatorImpl.COMPARATOR.compare(bbb, bbb) == 0); 132 assertTrue(CellComparatorImpl.COMPARATOR.compare(aaa, aaa) == 0); 133 // Do compare with different timestamps. 134 aaa = new KeyValue(a, fam, qf, 1, a); 135 bbb = new KeyValue(a, fam, qf, 2, a); 136 assertTrue(CellComparatorImpl.COMPARATOR.compare(aaa, bbb) > 0); 137 assertTrue(CellComparatorImpl.COMPARATOR.compare(bbb, aaa) < 0); 138 assertTrue(CellComparatorImpl.COMPARATOR.compare(aaa, aaa) == 0); 139 // Do compare with different types. Higher numbered types -- Delete 140 // should sort ahead of lower numbers; i.e. Put 141 aaa = new KeyValue(a, fam, qf, 1, KeyValue.Type.Delete, a); 142 bbb = new KeyValue(a, fam, qf, 1, a); 143 assertTrue(CellComparatorImpl.COMPARATOR.compare(aaa, bbb) < 0); 144 assertTrue(CellComparatorImpl.COMPARATOR.compare(bbb, aaa) > 0); 145 assertTrue(CellComparatorImpl.COMPARATOR.compare(aaa, aaa) == 0); 146 } 147 148 @Test 149 public void testMoreComparisons() throws Exception { 150 long now = System.currentTimeMillis(); 151 152 // Meta compares 153 KeyValue aaa = new KeyValue( 154 Bytes.toBytes("TestScanMultipleVersions,row_0500,1236020145502"), now); 155 KeyValue bbb = new KeyValue( 156 Bytes.toBytes("TestScanMultipleVersions,,99999999999999"), now); 157 CellComparator c = CellComparatorImpl.META_COMPARATOR; 158 assertTrue(c.compare(bbb, aaa) < 0); 159 160 KeyValue aaaa = new KeyValue(Bytes.toBytes("TestScanMultipleVersions,,1236023996656"), 161 Bytes.toBytes("info"), Bytes.toBytes("regioninfo"), 1236024396271L, 162 (byte[])null); 163 assertTrue(c.compare(aaaa, bbb) < 0); 164 165 KeyValue x = new KeyValue(Bytes.toBytes("TestScanMultipleVersions,row_0500,1236034574162"), 166 Bytes.toBytes("info"), Bytes.toBytes(""), 9223372036854775807L, 167 (byte[])null); 168 KeyValue y = new KeyValue(Bytes.toBytes("TestScanMultipleVersions,row_0500,1236034574162"), 169 Bytes.toBytes("info"), Bytes.toBytes("regioninfo"), 1236034574912L, 170 (byte[])null); 171 assertTrue(c.compare(x, y) < 0); 172 comparisons(CellComparatorImpl.META_COMPARATOR); 173 comparisons(CellComparatorImpl.COMPARATOR); 174 metacomparisons(CellComparatorImpl.META_COMPARATOR); 175 } 176 177 @Test 178 public void testMetaComparatorTableKeysWithCommaOk() { 179 CellComparator c = CellComparatorImpl.META_COMPARATOR; 180 long now = System.currentTimeMillis(); 181 // meta keys values are not quite right. A users can enter illegal values 182 // from shell when scanning meta. 183 KeyValue a = new KeyValue(Bytes.toBytes("table,key,with,commas1,1234"), now); 184 KeyValue b = new KeyValue(Bytes.toBytes("table,key,with,commas2,0123"), now); 185 assertTrue(c.compare(a, b) < 0); 186 } 187 188 /** 189 * Tests cases where rows keys have characters below the ','. 190 * See HBASE-832 191 * @throws IOException 192 */ 193 @Test 194 public void testKeyValueBorderCases() throws IOException { 195 // % sorts before , so if we don't do special comparator, rowB would 196 // come before rowA. 197 KeyValue rowA = new KeyValue(Bytes.toBytes("testtable,www.hbase.org/,1234"), 198 Bytes.toBytes("fam"), Bytes.toBytes(""), Long.MAX_VALUE, (byte[])null); 199 KeyValue rowB = new KeyValue(Bytes.toBytes("testtable,www.hbase.org/%20,99999"), 200 Bytes.toBytes("fam"), Bytes.toBytes(""), Long.MAX_VALUE, (byte[])null); 201 assertTrue(CellComparatorImpl.META_COMPARATOR.compare(rowA, rowB) < 0); 202 203 rowA = new KeyValue(Bytes.toBytes("testtable,,1234"), Bytes.toBytes("fam"), 204 Bytes.toBytes(""), Long.MAX_VALUE, (byte[])null); 205 rowB = new KeyValue(Bytes.toBytes("testtable,$www.hbase.org/,99999"), 206 Bytes.toBytes("fam"), Bytes.toBytes(""), Long.MAX_VALUE, (byte[])null); 207 assertTrue(CellComparatorImpl.META_COMPARATOR.compare(rowA, rowB) < 0); 208 209 } 210 211 private void metacomparisons(final CellComparatorImpl c) { 212 long now = System.currentTimeMillis(); 213 assertTrue(c.compare(new KeyValue( 214 Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",a,,0,1"), now), 215 new KeyValue( 216 Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",a,,0,1"), now)) == 0); 217 KeyValue a = new KeyValue( 218 Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",a,,0,1"), now); 219 KeyValue b = new KeyValue( 220 Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",a,,0,2"), now); 221 assertTrue(c.compare(a, b) < 0); 222 assertTrue(c.compare(new KeyValue( 223 Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",a,,0,2"), now), 224 new KeyValue( 225 Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",a,,0,1"), now)) > 0); 226 } 227 228 private void comparisons(final CellComparatorImpl c) { 229 long now = System.currentTimeMillis(); 230 assertTrue(c.compare(new KeyValue( 231 Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",,1"), now), 232 new KeyValue( 233 Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",,1"), now)) == 0); 234 assertTrue(c.compare(new KeyValue( 235 Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",,1"), now), 236 new KeyValue( 237 Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",,2"), now)) < 0); 238 assertTrue(c.compare(new KeyValue( 239 Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",,2"), now), 240 new KeyValue( 241 Bytes.toBytes(TableName.META_TABLE_NAME.getNameAsString()+",,1"), now)) > 0); 242 } 243 244 @Test 245 public void testBinaryKeys() throws Exception { 246 Set<KeyValue> set = new TreeSet<>(CellComparatorImpl.COMPARATOR); 247 final byte [] fam = Bytes.toBytes("col"); 248 final byte [] qf = Bytes.toBytes("umn"); 249 final byte [] nb = new byte[0]; 250 KeyValue [] keys = {new KeyValue(Bytes.toBytes("aaaaa,\u0000\u0000,2"), fam, qf, 2, nb), 251 new KeyValue(Bytes.toBytes("aaaaa,\u0001,3"), fam, qf, 3, nb), 252 new KeyValue(Bytes.toBytes("aaaaa,,1"), fam, qf, 1, nb), 253 new KeyValue(Bytes.toBytes("aaaaa,\u1000,5"), fam, qf, 5, nb), 254 new KeyValue(Bytes.toBytes("aaaaa,a,4"), fam, qf, 4, nb), 255 new KeyValue(Bytes.toBytes("a,a,0"), fam, qf, 0, nb), 256 }; 257 // Add to set with bad comparator 258 Collections.addAll(set, keys); 259 // This will output the keys incorrectly. 260 boolean assertion = false; 261 int count = 0; 262 try { 263 for (KeyValue k: set) { 264 assertTrue(count++ == k.getTimestamp()); 265 } 266 } catch (java.lang.AssertionError e) { 267 // Expected 268 assertion = true; 269 } 270 assertTrue(assertion); 271 // Make set with good comparator 272 set = new TreeSet<>(CellComparatorImpl.META_COMPARATOR); 273 Collections.addAll(set, keys); 274 count = 0; 275 for (KeyValue k: set) { 276 assertTrue(count++ == k.getTimestamp()); 277 } 278 } 279 280 @Test 281 public void testStackedUpKeyValue() { 282 // Test multiple KeyValues in a single blob. 283 284 // TODO actually write this test! 285 286 } 287 288 private final byte[] rowA = Bytes.toBytes("rowA"); 289 private final byte[] rowB = Bytes.toBytes("rowB"); 290 291 private final byte[] family = Bytes.toBytes("family"); 292 private final byte[] qualA = Bytes.toBytes("qfA"); 293 private final byte[] qualB = Bytes.toBytes("qfB"); 294 295 private void assertKVLess(CellComparator c, 296 KeyValue less, 297 KeyValue greater) { 298 int cmp = c.compare(less,greater); 299 assertTrue(cmp < 0); 300 cmp = c.compare(greater,less); 301 assertTrue(cmp > 0); 302 } 303 304 private void assertKVLessWithoutRow(CellComparator c, int common, KeyValue less, 305 KeyValue greater) { 306 int cmp = c.compare(less, greater); 307 assertTrue(cmp < 0); 308 cmp = c.compare(greater, less); 309 assertTrue(cmp > 0); 310 } 311 312 @Test 313 public void testCompareWithoutRow() { 314 final CellComparator c = CellComparatorImpl.COMPARATOR; 315 byte[] row = Bytes.toBytes("row"); 316 317 byte[] fa = Bytes.toBytes("fa"); 318 byte[] fami = Bytes.toBytes("fami"); 319 byte[] fami1 = Bytes.toBytes("fami1"); 320 321 byte[] qual0 = Bytes.toBytes(""); 322 byte[] qual1 = Bytes.toBytes("qf1"); 323 byte[] qual2 = Bytes.toBytes("qf2"); 324 long ts = 1; 325 326 // 'fa:' 327 KeyValue kv_0 = new KeyValue(row, fa, qual0, ts, KeyValue.Type.Put); 328 // 'fami:' 329 KeyValue kv0_0 = new KeyValue(row, fami, qual0, ts, KeyValue.Type.Put); 330 // 'fami:qf1' 331 KeyValue kv0_1 = new KeyValue(row, fami, qual1, ts, KeyValue.Type.Put); 332 // 'fami:qf2' 333 KeyValue kv0_2 = new KeyValue(row, fami, qual2, ts, KeyValue.Type.Put); 334 // 'fami1:' 335 KeyValue kv1_0 = new KeyValue(row, fami1, qual0, ts, KeyValue.Type.Put); 336 337 // 'fami:qf1' < 'fami:qf2' 338 assertKVLessWithoutRow(c, 0, kv0_1, kv0_2); 339 // 'fami:qf1' < 'fami1:' 340 assertKVLessWithoutRow(c, 0, kv0_1, kv1_0); 341 342 // Test comparison by skipping the same prefix bytes. 343 /*** 344 * KeyValue Format and commonLength: 345 * |_keyLen_|_valLen_|_rowLen_|_rowKey_|_famiLen_|_fami_|_Quali_|.... 346 * ------------------|-------commonLength--------|-------------- 347 */ 348 int commonLength = KeyValue.ROW_LENGTH_SIZE + KeyValue.FAMILY_LENGTH_SIZE 349 + row.length; 350 // 'fa:' < 'fami:'. They have commonPrefix + 2 same prefix bytes. 351 assertKVLessWithoutRow(c, commonLength + 2, kv_0, kv0_0); 352 // 'fami:' < 'fami:qf1'. They have commonPrefix + 4 same prefix bytes. 353 assertKVLessWithoutRow(c, commonLength + 4, kv0_0, kv0_1); 354 // 'fami:qf1' < 'fami1:'. They have commonPrefix + 4 same prefix bytes. 355 assertKVLessWithoutRow(c, commonLength + 4, kv0_1, kv1_0); 356 // 'fami:qf1' < 'fami:qf2'. They have commonPrefix + 6 same prefix bytes. 357 assertKVLessWithoutRow(c, commonLength + 6, kv0_1, kv0_2); 358 } 359 360 @Test 361 public void testFirstLastOnRow() { 362 final CellComparator c = CellComparatorImpl.COMPARATOR; 363 long ts = 1; 364 byte[] bufferA = new byte[128]; 365 int offsetA = 0; 366 byte[] bufferB = new byte[128]; 367 int offsetB = 7; 368 369 // These are listed in sort order (ie: every one should be less 370 // than the one on the next line). 371 final KeyValue firstOnRowA = KeyValueUtil.createFirstOnRow(rowA); 372 final KeyValue firstOnRowABufferFamQual = KeyValueUtil.createFirstOnRow(bufferA, offsetA, 373 rowA, 0, rowA.length, family, 0, family.length, qualA, 0, qualA.length); 374 final KeyValue kvA_1 = new KeyValue(rowA, null, null, ts, KeyValue.Type.Put); 375 final KeyValue kvA_2 = new KeyValue(rowA, family, qualA, ts, KeyValue.Type.Put); 376 377 final KeyValue lastOnRowA = KeyValueUtil.createLastOnRow(rowA); 378 final KeyValue firstOnRowB = KeyValueUtil.createFirstOnRow(rowB); 379 final KeyValue firstOnRowBBufferFam = KeyValueUtil.createFirstOnRow(bufferB, offsetB, 380 rowB, 0, rowB.length, family, 0, family.length, null, 0, 0); 381 final KeyValue kvB = new KeyValue(rowB, family, qualA, ts, KeyValue.Type.Put); 382 383 assertKVLess(c, firstOnRowA, firstOnRowB); 384 assertKVLess(c, firstOnRowA, firstOnRowBBufferFam); 385 assertKVLess(c, firstOnRowABufferFamQual, firstOnRowB); 386 assertKVLess(c, firstOnRowA, kvA_1); 387 assertKVLess(c, firstOnRowA, kvA_2); 388 assertKVLess(c, firstOnRowABufferFamQual, kvA_2); 389 assertKVLess(c, kvA_1, kvA_2); 390 assertKVLess(c, kvA_2, firstOnRowB); 391 assertKVLess(c, kvA_1, firstOnRowB); 392 assertKVLess(c, kvA_2, firstOnRowBBufferFam); 393 assertKVLess(c, kvA_1, firstOnRowBBufferFam); 394 395 assertKVLess(c, lastOnRowA, firstOnRowB); 396 assertKVLess(c, lastOnRowA, firstOnRowBBufferFam); 397 assertKVLess(c, firstOnRowB, kvB); 398 assertKVLess(c, firstOnRowBBufferFam, kvB); 399 assertKVLess(c, lastOnRowA, kvB); 400 401 assertKVLess(c, kvA_2, lastOnRowA); 402 assertKVLess(c, kvA_1, lastOnRowA); 403 assertKVLess(c, firstOnRowA, lastOnRowA); 404 assertKVLess(c, firstOnRowABufferFamQual, lastOnRowA); 405 } 406 407 @Test 408 public void testCreateKeyOnly() throws Exception { 409 long ts = 1; 410 byte [] value = Bytes.toBytes("a real value"); 411 byte [] evalue = new byte[0]; // empty value 412 413 for (byte[] val : new byte[][]{value, evalue}) { 414 for (boolean useLen : new boolean[]{false,true}) { 415 KeyValue kv1 = new KeyValue(rowA, family, qualA, ts, val); 416 KeyValue kv1ko = kv1.createKeyOnly(useLen); 417 // keys are still the same 418 assertTrue(kv1.equals(kv1ko)); 419 // but values are not 420 assertTrue(kv1ko.getValueLength() == (useLen?Bytes.SIZEOF_INT:0)); 421 if (useLen) { 422 assertEquals(kv1.getValueLength(), 423 Bytes.toInt(kv1ko.getValueArray(), kv1ko.getValueOffset(), kv1ko.getValueLength())); 424 } 425 } 426 } 427 } 428 429 @Test 430 public void testCreateKeyValueFromKey() { 431 KeyValue kv = new KeyValue(Bytes.toBytes("myRow"), Bytes.toBytes("myCF"), 432 Bytes.toBytes("myQualifier"), 12345L, Bytes.toBytes("myValue")); 433 int initialPadding = 10; 434 int endingPadding = 20; 435 int keyLen = kv.getKeyLength(); 436 byte[] tmpArr = new byte[initialPadding + endingPadding + keyLen]; 437 System.arraycopy(kv.getBuffer(), kv.getKeyOffset(), tmpArr, 438 initialPadding, keyLen); 439 KeyValue kvFromKey = KeyValueUtil.createKeyValueFromKey(tmpArr, initialPadding, 440 keyLen); 441 assertEquals(keyLen, kvFromKey.getKeyLength()); 442 assertEquals(KeyValue.ROW_OFFSET + keyLen, kvFromKey.getBuffer().length); 443 System.err.println("kv=" + kv); 444 System.err.println("kvFromKey=" + kvFromKey); 445 assertEquals(kvFromKey.toString(), 446 kv.toString().replaceAll("=[0-9]+", "=0")); 447 } 448 449 /** 450 * Tests that getTimestamp() does always return the proper timestamp, even after updating it. 451 * See HBASE-6265. 452 */ 453 @Test 454 public void testGetTimestamp() { 455 KeyValue kv = new KeyValue(Bytes.toBytes("myRow"), Bytes.toBytes("myCF"), 456 Bytes.toBytes("myQualifier"), HConstants.LATEST_TIMESTAMP, 457 Bytes.toBytes("myValue")); 458 long time1 = kv.getTimestamp(); 459 kv.updateLatestStamp(Bytes.toBytes(12345L)); 460 long time2 = kv.getTimestamp(); 461 assertEquals(HConstants.LATEST_TIMESTAMP, time1); 462 assertEquals(12345L, time2); 463 } 464 465 @Test 466 public void testKVsWithTags() { 467 byte[] row = Bytes.toBytes("myRow"); 468 byte[] cf = Bytes.toBytes("myCF"); 469 byte[] q = Bytes.toBytes("myQualifier"); 470 byte[] value = Bytes.toBytes("myValue"); 471 byte[] metaValue1 = Bytes.toBytes("metaValue1"); 472 byte[] metaValue2 = Bytes.toBytes("metaValue2"); 473 KeyValue kv = new KeyValue(row, cf, q, HConstants.LATEST_TIMESTAMP, value, new Tag[] { 474 new ArrayBackedTag((byte) 1, metaValue1), new ArrayBackedTag((byte) 2, metaValue2) }); 475 assertTrue(kv.getTagsLength() > 0); 476 assertTrue(Bytes.equals(kv.getRowArray(), kv.getRowOffset(), kv.getRowLength(), row, 0, 477 row.length)); 478 assertTrue(Bytes.equals(kv.getFamilyArray(), kv.getFamilyOffset(), kv.getFamilyLength(), cf, 0, 479 cf.length)); 480 assertTrue(Bytes.equals(kv.getQualifierArray(), kv.getQualifierOffset(), 481 kv.getQualifierLength(), q, 0, q.length)); 482 assertTrue(Bytes.equals(kv.getValueArray(), kv.getValueOffset(), kv.getValueLength(), value, 0, 483 value.length)); 484 List<Tag> tags = PrivateCellUtil.getTags(kv); 485 assertNotNull(tags); 486 assertEquals(2, tags.size()); 487 boolean meta1Ok = false, meta2Ok = false; 488 for (Tag tag : tags) { 489 if (tag.getType() == (byte) 1) { 490 if (Bytes.equals(Tag.cloneValue(tag), metaValue1)) { 491 meta1Ok = true; 492 } 493 } else { 494 if (Bytes.equals(Tag.cloneValue(tag), metaValue2)) { 495 meta2Ok = true; 496 } 497 } 498 } 499 assertTrue(meta1Ok); 500 assertTrue(meta2Ok); 501 Iterator<Tag> tagItr = PrivateCellUtil.tagsIterator(kv); 502 //Iterator<Tag> tagItr = kv.tagsIterator(); 503 assertTrue(tagItr.hasNext()); 504 Tag next = tagItr.next(); 505 assertEquals(10, next.getValueLength()); 506 assertEquals((byte) 1, next.getType()); 507 Bytes.equals(Tag.cloneValue(next), metaValue1); 508 assertTrue(tagItr.hasNext()); 509 next = tagItr.next(); 510 assertEquals(10, next.getValueLength()); 511 assertEquals((byte) 2, next.getType()); 512 Bytes.equals(Tag.cloneValue(next), metaValue2); 513 assertFalse(tagItr.hasNext()); 514 515 tagItr = PrivateCellUtil.tagsIterator(kv); 516 assertTrue(tagItr.hasNext()); 517 next = tagItr.next(); 518 assertEquals(10, next.getValueLength()); 519 assertEquals((byte) 1, next.getType()); 520 Bytes.equals(Tag.cloneValue(next), metaValue1); 521 assertTrue(tagItr.hasNext()); 522 next = tagItr.next(); 523 assertEquals(10, next.getValueLength()); 524 assertEquals((byte) 2, next.getType()); 525 Bytes.equals(Tag.cloneValue(next), metaValue2); 526 assertFalse(tagItr.hasNext()); 527 } 528 529 @Test 530 public void testMetaKeyComparator() { 531 CellComparator c = CellComparatorImpl.META_COMPARATOR; 532 long now = System.currentTimeMillis(); 533 534 KeyValue a = new KeyValue(Bytes.toBytes("table1"), now); 535 KeyValue b = new KeyValue(Bytes.toBytes("table2"), now); 536 assertTrue(c.compare(a, b) < 0); 537 538 a = new KeyValue(Bytes.toBytes("table1,111"), now); 539 b = new KeyValue(Bytes.toBytes("table2"), now); 540 assertTrue(c.compare(a, b) < 0); 541 542 a = new KeyValue(Bytes.toBytes("table1"), now); 543 b = new KeyValue(Bytes.toBytes("table2,111"), now); 544 assertTrue(c.compare(a, b) < 0); 545 546 a = new KeyValue(Bytes.toBytes("table,111"), now); 547 b = new KeyValue(Bytes.toBytes("table,2222"), now); 548 assertTrue(c.compare(a, b) < 0); 549 550 a = new KeyValue(Bytes.toBytes("table,111,aaaa"), now); 551 b = new KeyValue(Bytes.toBytes("table,2222"), now); 552 assertTrue(c.compare(a, b) < 0); 553 554 a = new KeyValue(Bytes.toBytes("table,111"), now); 555 b = new KeyValue(Bytes.toBytes("table,2222.bbb"), now); 556 assertTrue(c.compare(a, b) < 0); 557 558 a = new KeyValue(Bytes.toBytes("table,,aaaa"), now); 559 b = new KeyValue(Bytes.toBytes("table,111,bbb"), now); 560 assertTrue(c.compare(a, b) < 0); 561 562 a = new KeyValue(Bytes.toBytes("table,111,aaaa"), now); 563 b = new KeyValue(Bytes.toBytes("table,111,bbb"), now); 564 assertTrue(c.compare(a, b) < 0); 565 566 a = new KeyValue(Bytes.toBytes("table,111,xxxx"), now); 567 b = new KeyValue(Bytes.toBytes("table,111,222,bbb"), now); 568 assertTrue(c.compare(a, b) < 0); 569 570 a = new KeyValue(Bytes.toBytes("table,111,11,xxx"), now); 571 b = new KeyValue(Bytes.toBytes("table,111,222,bbb"), now); 572 assertTrue(c.compare(a, b) < 0); 573 } 574 575 @Test 576 public void testEqualsAndHashCode() throws Exception { 577 KeyValue kvA1 = new KeyValue(Bytes.toBytes("key"), Bytes.toBytes("cf"), 578 Bytes.toBytes("qualA"), Bytes.toBytes("1")); 579 KeyValue kvA2 = new KeyValue(Bytes.toBytes("key"), Bytes.toBytes("cf"), 580 Bytes.toBytes("qualA"), Bytes.toBytes("2")); 581 // We set a different sequence id on kvA2 to demonstrate that the equals and hashCode also 582 // don't take this into account. 583 kvA2.setSequenceId(2); 584 KeyValue kvB = new KeyValue(Bytes.toBytes("key"), Bytes.toBytes("cf"), 585 Bytes.toBytes("qualB"), Bytes.toBytes("1")); 586 587 assertEquals(kvA1, kvA2); 588 assertNotEquals(kvA1, kvB); 589 assertEquals(kvA1.hashCode(), kvA2.hashCode()); 590 assertNotEquals(kvA1.hashCode(), kvB.hashCode()); 591 592 } 593 594 @Test 595 public void testKeyValueSerialization() throws Exception { 596 KeyValue[] keyValues = new KeyValue[] { 597 new KeyValue(Bytes.toBytes("key"), Bytes.toBytes("cf"), Bytes.toBytes("qualA"), 598 Bytes.toBytes("1")), 599 new KeyValue(Bytes.toBytes("key"), Bytes.toBytes("cf"), Bytes.toBytes("qualA"), 600 Bytes.toBytes("2")), 601 new KeyValue(Bytes.toBytes("key"), Bytes.toBytes("cf"), Bytes.toBytes("qualA"), 602 System.currentTimeMillis(), Bytes.toBytes("2"), 603 new Tag[] { new ArrayBackedTag((byte) 120, "tagA"), 604 new ArrayBackedTag((byte) 121, Bytes.toBytes("tagB")) }), 605 new KeyValue(Bytes.toBytes("key"), Bytes.toBytes("cf"), Bytes.toBytes("qualA"), 606 System.currentTimeMillis(), Bytes.toBytes("2"), 607 new Tag[] { new ArrayBackedTag((byte) 0, "tagA") }), 608 new KeyValue(Bytes.toBytes("key"), Bytes.toBytes("cf"), Bytes.toBytes(""), 609 Bytes.toBytes("1")) }; 610 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 611 for (KeyValue kv : keyValues) { 612 DataOutputStream os = new DataOutputStream(byteArrayOutputStream); 613 ByteBufferUtils.putInt(os, KeyValueUtil.getSerializedSize(kv, true)); 614 KeyValueUtil.oswrite(kv, os, true); 615 } 616 DataInputStream is = 617 new DataInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray())); 618 for (int i = 0; i < keyValues.length; i++) { 619 LOG.info("Case#" + i + ": deserialize the kv: " + keyValues[i]); 620 KeyValue destKv = KeyValueUtil.createKeyValueFromInputStream(is, true); 621 assertEquals(keyValues[i], destKv); 622 assertArrayEquals(CellUtil.cloneValue(keyValues[i]), CellUtil.cloneValue(destKv)); 623 assertArrayEquals(PrivateCellUtil.cloneTags(keyValues[i]), PrivateCellUtil.cloneTags(destKv)); 624 } 625 } 626 627 private static class FailureCase { 628 byte[] buf; 629 int offset; 630 int length; 631 boolean withTags; 632 String expectedMessage; 633 634 public FailureCase(byte[] buf, int offset, int length, boolean withTags, 635 String expectedMessage) { 636 this.buf = buf; 637 this.offset = offset; 638 this.length = length; 639 this.withTags = withTags; 640 this.expectedMessage = expectedMessage; 641 } 642 643 @Override 644 public String toString() { 645 return "FailureCaseDetails: [buf=" + Bytes.toStringBinary(buf, offset, length) + ", offset=" 646 + offset + ", " + "length=" + length + ", expectedMessage=" + expectedMessage 647 + ", withtags=" + withTags + "]"; 648 } 649 650 public String getExpectedMessage() { 651 return this.expectedMessage + KeyValueUtil.bytesToHex(buf, offset, length); 652 } 653 } 654 655 @Test 656 public void testCheckKeyValueBytesFailureCase() throws Exception { 657 byte[][] inputs = new byte[][] { HConstants.EMPTY_BYTE_ARRAY, // case.0 658 Bytes.toBytesBinary("a"), // case.1 659 Bytes.toBytesBinary("\\x00\\x00\\x00\\x01"), // case.2 660 Bytes.toBytesBinary("\\x00\\x00\\x00\\x01\\x00"), // case.3 661 Bytes.toBytesBinary("\\x00\\x00\\x00\\x01\\x00\\x00\\x00\\x01"), // case.4 662 Bytes.toBytesBinary("\\x00\\x00\\x00\\x01\\x00\\x00\\x00\\x01\\x00"), // case.5 663 Bytes.toBytesBinary("\\x00\\x00\\x00\\x01\\x00\\x00\\x00\\x01\\x00\\x01"), // case.6 664 Bytes.toBytesBinary("\\x00\\x00\\x00\\x01\\x00\\x00\\x00\\x01\\x00\\x03ROW"), // case.7 665 Bytes.toBytesBinary("\\x00\\x00\\x00\\x01\\x00\\x00\\x00\\x01\\x00\\x03ROW\\x01"), // case.8 666 Bytes.toBytesBinary("\\x00\\x00\\x00\\x11\\x00\\x00\\x00\\x01\\x00\\x03ROW\\x01FQ\\xFF" 667 + "\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\x03"), // case.9 668 Bytes.toBytesBinary("\\x00\\x00\\x00\\x11\\x00\\x00\\x00\\x01\\x00\\x03ROW\\x01FQ\\x00" 669 + "\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x03"), // case.10 670 Bytes.toBytesBinary("\\x00\\x00\\x00\\x11\\x00\\x00\\x00\\x01\\x00\\x03ROW\\x01FQ\\x00" 671 + "\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x04"), // case.11 672 Bytes.toBytesBinary("\\x00\\x00\\x00\\x11\\x00\\x00\\x00\\x01\\x00\\x03ROW\\x01FQ\\x00" 673 + "\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x04VALUE"), // case.12 674 }; 675 String[] outputs = new String[] { "Overflow when reading key length at position=0", 676 "Overflow when reading key length at position=0", 677 "Invalid key length in KeyValue. keyLength=1", 678 "Overflow when reading value length at position=4", 679 "Invalid value length in KeyValue, valueLength=1", 680 "Overflow when reading row length at position=8", 681 "Invalid row length in KeyValue, rowLength=1", 682 "Overflow when reading family length at position=13", 683 "Invalid family length in KeyValue, familyLength=1", "Timestamp cannot be negative, ts=-1", 684 "Invalid type in KeyValue, type=3", "Overflow when reading value part at position=25", 685 "Invalid tags length in KeyValue at position=26", }; 686 byte[][] withTagsInputs = new byte[][] { 687 Bytes.toBytesBinary("\\x00\\x00\\x00\\x11\\x00\\x00\\x00\\x01\\x00\\x03ROW\\x01FQ\\x00" 688 + "\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x04V\\x01"), // case.13 689 Bytes.toBytesBinary("\\x00\\x00\\x00\\x11\\x00\\x00\\x00\\x01\\x00\\x03ROW\\x01FQ\\x00" 690 + "\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x04V\\x00\\x01"), // case.14 691 Bytes.toBytesBinary("\\x00\\x00\\x00\\x11\\x00\\x00\\x00\\x01\\x00\\x03ROW\\x01FQ\\x00" 692 + "\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x04V\\x00\\x04\\x00\\x03\\x00A"), // case.15 693 // case.16 694 Bytes.toBytesBinary("\\x00\\x00\\x00\\x11\\x00\\x00\\x00\\x01\\x00\\x03ROW\\x01FQ\\x00" 695 + "\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x04V\\x00\\x0A\\x00\\x04\\x00TAG\\x00\\x04" 696 + "\\xFFT"), 697 Bytes.toBytesBinary("\\x00\\x00\\x00\\x11\\x00\\x00\\x00\\x01\\x00\\x03ROW\\x01FQ\\x00" 698 + "\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x04V\\x00\\x0C\\x00\\x04\\x00TAG\\x00\\x05" 699 + "\\xF0COME\\x00"), // case.17 700 Bytes.toBytesBinary("\\x00\\x00\\x00\\x11\\x00\\x00\\x00\\x01\\x00\\x03ROW\\x01FQ\\x00" 701 + "\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x04V\\x00\\x0C\\x00\\x04\\x00TAG\\x00\\x05" 702 + "\\xF0COME"), // case.18 703 Bytes.toBytesBinary("\\x00\\x00\\x00\\x11\\x00\\x00\\x00\\x01\\x00\\x03ROW\\x01FQ\\x00" 704 + "\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x04V\\x00\\x00"), // case.19 705 Bytes.toBytesBinary("\\x00\\x00\\x00\\x11\\x00\\x00\\x00\\x01\\x00\\x03ROW\\x01FQ\\x00" 706 + "\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x04V\\x00\\x1B\\x00\\x05\\x01TAG1\\x00\\x05" 707 + "\\x02TAG2\\x00\\x05\\x03TAG3\\x00\\x05\\x04TAG4"), // case.20 708 }; 709 String[] withTagsOutputs = new String[] { "Overflow when reading tags length at position=26", 710 "Invalid tags length in KeyValue at position=26", 711 "Invalid tag length at position=28, tagLength=3", 712 "Invalid tag length at position=34, tagLength=4", 713 "Some redundant bytes in KeyValue's buffer, startOffset=41, endOffset=42", null, null, 714 null, }; 715 assertEquals(inputs.length, outputs.length); 716 assertEquals(withTagsInputs.length, withTagsOutputs.length); 717 718 FailureCase[] cases = new FailureCase[inputs.length + withTagsInputs.length]; 719 for (int i = 0; i < inputs.length; i++) { 720 cases[i] = new FailureCase(inputs[i], 0, inputs[i].length, false, outputs[i]); 721 } 722 for (int i = 0; i < withTagsInputs.length; i++) { 723 cases[inputs.length + i] = 724 new FailureCase(withTagsInputs[i], 0, withTagsInputs[i].length, true, withTagsOutputs[i]); 725 } 726 727 for (int i = 0; i < cases.length; i++) { 728 FailureCase c = cases[i]; 729 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 730 DataOutputStream os = new DataOutputStream(baos); 731 ByteBufferUtils.putInt(os, c.length); 732 os.write(c.buf, c.offset, c.length); 733 try { 734 KeyValueUtil.createKeyValueFromInputStream( 735 new DataInputStream(new ByteArrayInputStream(baos.toByteArray())), c.withTags); 736 if (c.expectedMessage != null) { 737 Assert.fail("Should fail when parse kv from an invalid bytes, case#" + i + ". " + c); 738 } 739 } catch (IllegalArgumentException e) { 740 assertEquals("Case#" + i + " failed," + c, c.getExpectedMessage(), e.getMessage()); 741 } 742 } 743 } 744}