001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertFalse; 022import static org.junit.Assert.assertTrue; 023import static org.junit.Assert.fail; 024 025import java.io.IOException; 026import java.math.BigDecimal; 027import java.nio.ByteBuffer; 028import java.util.ArrayList; 029import java.util.List; 030import java.util.NavigableMap; 031import java.util.TreeMap; 032import org.apache.hadoop.hbase.testclassification.MiscTests; 033import org.apache.hadoop.hbase.testclassification.SmallTests; 034import org.apache.hadoop.hbase.util.Bytes; 035import org.junit.Assert; 036import org.junit.ClassRule; 037import org.junit.Test; 038import org.junit.experimental.categories.Category; 039import org.mockito.Mockito; 040 041@Category({ MiscTests.class, SmallTests.class }) 042public class TestCellUtil { 043 @ClassRule 044 public static final HBaseClassTestRule CLASS_RULE = 045 HBaseClassTestRule.forClass(TestCellUtil.class); 046 047 /** 048 * CellScannable used in test. Returns a {@link TestCellScanner} 049 */ 050 private static class TestCellScannable implements CellScannable { 051 private final int cellsCount; 052 053 TestCellScannable(final int cellsCount) { 054 this.cellsCount = cellsCount; 055 } 056 057 @Override 058 public CellScanner cellScanner() { 059 return new TestCellScanner(this.cellsCount); 060 } 061 } 062 063 /** 064 * CellScanner used in test. 065 */ 066 private static class TestCellScanner implements CellScanner { 067 private int count = 0; 068 private Cell current = null; 069 private final int cellsCount; 070 071 TestCellScanner(final int cellsCount) { 072 this.cellsCount = cellsCount; 073 } 074 075 @Override 076 public Cell current() { 077 return this.current; 078 } 079 080 @Override 081 public boolean advance() { 082 if (this.count < cellsCount) { 083 this.current = new TestCell(this.count); 084 this.count++; 085 return true; 086 } 087 return false; 088 } 089 } 090 091 /** 092 * Cell used in test. Has row only. 093 */ 094 private static class TestCell implements ExtendedCell { 095 private final byte[] row; 096 097 TestCell(final int i) { 098 this.row = Bytes.toBytes(i); 099 } 100 101 @Override 102 public byte[] getRowArray() { 103 return this.row; 104 } 105 106 @Override 107 public int getRowOffset() { 108 return 0; 109 } 110 111 @Override 112 public short getRowLength() { 113 return (short) this.row.length; 114 } 115 116 @Override 117 public byte[] getFamilyArray() { 118 return null; 119 } 120 121 @Override 122 public int getFamilyOffset() { 123 return 0; 124 } 125 126 @Override 127 public byte getFamilyLength() { 128 return 0; 129 } 130 131 @Override 132 public byte[] getQualifierArray() { 133 return null; 134 } 135 136 @Override 137 public int getQualifierOffset() { 138 return 0; 139 } 140 141 @Override 142 public int getQualifierLength() { 143 return 0; 144 } 145 146 @Override 147 public long getTimestamp() { 148 return 0; 149 } 150 151 @Override 152 public byte getTypeByte() { 153 return 0; 154 } 155 156 @Override 157 public byte[] getValueArray() { 158 return null; 159 } 160 161 @Override 162 public int getValueOffset() { 163 return 0; 164 } 165 166 @Override 167 public int getValueLength() { 168 return 0; 169 } 170 171 @Override 172 public int getSerializedSize() { 173 return 0; 174 } 175 176 @Override 177 public byte[] getTagsArray() { 178 return null; 179 } 180 181 @Override 182 public int getTagsOffset() { 183 return 0; 184 } 185 186 @Override 187 public long getSequenceId() { 188 return 0; 189 } 190 191 @Override 192 public int getTagsLength() { 193 return 0; 194 } 195 196 @Override 197 public long heapSize() { 198 return 0; 199 } 200 201 @Override 202 public void setSequenceId(long seqId) throws IOException { 203 204 } 205 206 @Override 207 public void setTimestamp(long ts) throws IOException { 208 209 } 210 211 @Override 212 public void setTimestamp(byte[] ts) throws IOException { 213 } 214 } 215 216 /** 217 * Was overflowing if 100k or so lists of cellscanners to return. 218 */ 219 @Test 220 public void testCreateCellScannerOverflow() throws IOException { 221 consume(doCreateCellScanner(1, 1), 1); 222 consume(doCreateCellScanner(3, 0), 0); 223 consume(doCreateCellScanner(3, 3), 3 * 3); 224 consume(doCreateCellScanner(0, 1), 0); 225 // Do big number. See HBASE-11813 for why. 226 final int hundredK = 100000; 227 consume(doCreateCellScanner(hundredK, 0), 0); 228 consume(doCreateCellArray(1), 1); 229 consume(doCreateCellArray(0), 0); 230 consume(doCreateCellArray(3), 3); 231 List<CellScannable> cells = new ArrayList<>(hundredK); 232 for (int i = 0; i < hundredK; i++) { 233 cells.add(new TestCellScannable(1)); 234 } 235 consume(CellUtil.createCellScanner(cells), hundredK); 236 NavigableMap<byte[], List<Cell>> m = new TreeMap<>(Bytes.BYTES_COMPARATOR); 237 List<Cell> cellArray = new ArrayList<>(hundredK); 238 for (int i = 0; i < hundredK; i++) { 239 cellArray.add(new TestCell(i)); 240 } 241 m.put(new byte[] { 'f' }, cellArray); 242 consume(CellUtil.createCellScanner(m), hundredK); 243 } 244 245 private CellScanner doCreateCellArray(final int itemsPerList) { 246 Cell[] cells = new Cell[itemsPerList]; 247 for (int i = 0; i < itemsPerList; i++) { 248 cells[i] = new TestCell(i); 249 } 250 return CellUtil.createCellScanner(cells); 251 } 252 253 private CellScanner doCreateCellScanner(final int listsCount, final int itemsPerList) { 254 List<CellScannable> cells = new ArrayList<>(listsCount); 255 for (int i = 0; i < listsCount; i++) { 256 CellScannable cs = new CellScannable() { 257 @Override 258 public CellScanner cellScanner() { 259 return new TestCellScanner(itemsPerList); 260 } 261 }; 262 cells.add(cs); 263 } 264 return CellUtil.createCellScanner(cells); 265 } 266 267 private void consume(final CellScanner scanner, final int expected) throws IOException { 268 int count = 0; 269 while (scanner.advance()) { 270 count++; 271 } 272 Assert.assertEquals(expected, count); 273 } 274 275 @Test 276 public void testOverlappingKeys() { 277 byte[] empty = HConstants.EMPTY_BYTE_ARRAY; 278 byte[] a = Bytes.toBytes("a"); 279 byte[] b = Bytes.toBytes("b"); 280 byte[] c = Bytes.toBytes("c"); 281 byte[] d = Bytes.toBytes("d"); 282 283 // overlaps 284 Assert.assertTrue(PrivateCellUtil.overlappingKeys(a, b, a, b)); 285 Assert.assertTrue(PrivateCellUtil.overlappingKeys(a, c, a, b)); 286 Assert.assertTrue(PrivateCellUtil.overlappingKeys(a, b, a, c)); 287 Assert.assertTrue(PrivateCellUtil.overlappingKeys(b, c, a, c)); 288 Assert.assertTrue(PrivateCellUtil.overlappingKeys(a, c, b, c)); 289 Assert.assertTrue(PrivateCellUtil.overlappingKeys(a, d, b, c)); 290 Assert.assertTrue(PrivateCellUtil.overlappingKeys(b, c, a, d)); 291 292 Assert.assertTrue(PrivateCellUtil.overlappingKeys(empty, b, a, b)); 293 Assert.assertTrue(PrivateCellUtil.overlappingKeys(empty, b, a, c)); 294 295 Assert.assertTrue(PrivateCellUtil.overlappingKeys(a, b, empty, b)); 296 Assert.assertTrue(PrivateCellUtil.overlappingKeys(a, b, empty, c)); 297 298 Assert.assertTrue(PrivateCellUtil.overlappingKeys(a, empty, a, b)); 299 Assert.assertTrue(PrivateCellUtil.overlappingKeys(a, empty, a, c)); 300 301 Assert.assertTrue(PrivateCellUtil.overlappingKeys(a, b, empty, empty)); 302 Assert.assertTrue(PrivateCellUtil.overlappingKeys(empty, empty, a, b)); 303 304 // non overlaps 305 Assert.assertFalse(PrivateCellUtil.overlappingKeys(a, b, c, d)); 306 Assert.assertFalse(PrivateCellUtil.overlappingKeys(c, d, a, b)); 307 308 Assert.assertFalse(PrivateCellUtil.overlappingKeys(b, c, c, d)); 309 Assert.assertFalse(PrivateCellUtil.overlappingKeys(b, c, c, empty)); 310 Assert.assertFalse(PrivateCellUtil.overlappingKeys(b, c, d, empty)); 311 Assert.assertFalse(PrivateCellUtil.overlappingKeys(c, d, b, c)); 312 Assert.assertFalse(PrivateCellUtil.overlappingKeys(c, empty, b, c)); 313 Assert.assertFalse(PrivateCellUtil.overlappingKeys(d, empty, b, c)); 314 315 Assert.assertFalse(PrivateCellUtil.overlappingKeys(b, c, a, b)); 316 Assert.assertFalse(PrivateCellUtil.overlappingKeys(b, c, empty, b)); 317 Assert.assertFalse(PrivateCellUtil.overlappingKeys(b, c, empty, a)); 318 Assert.assertFalse(PrivateCellUtil.overlappingKeys(a, b, b, c)); 319 Assert.assertFalse(PrivateCellUtil.overlappingKeys(empty, b, b, c)); 320 Assert.assertFalse(PrivateCellUtil.overlappingKeys(empty, a, b, c)); 321 } 322 323 @Test 324 public void testFindCommonPrefixInFlatKey() { 325 // The whole key matching case 326 KeyValue kv1 = 327 new KeyValue(Bytes.toBytes("r1"), Bytes.toBytes("f1"), Bytes.toBytes("q1"), null); 328 Assert.assertEquals(kv1.getKeyLength(), 329 PrivateCellUtil.findCommonPrefixInFlatKey(kv1, kv1, true, true)); 330 Assert.assertEquals(kv1.getKeyLength(), 331 PrivateCellUtil.findCommonPrefixInFlatKey(kv1, kv1, false, true)); 332 Assert.assertEquals(kv1.getKeyLength() - KeyValue.TIMESTAMP_TYPE_SIZE, 333 PrivateCellUtil.findCommonPrefixInFlatKey(kv1, kv1, true, false)); 334 // The rk length itself mismatch 335 KeyValue kv2 = 336 new KeyValue(Bytes.toBytes("r12"), Bytes.toBytes("f1"), Bytes.toBytes("q1"), null); 337 Assert.assertEquals(1, PrivateCellUtil.findCommonPrefixInFlatKey(kv1, kv2, true, true)); 338 // part of rk is same 339 KeyValue kv3 = 340 new KeyValue(Bytes.toBytes("r14"), Bytes.toBytes("f1"), Bytes.toBytes("q1"), null); 341 Assert.assertEquals(KeyValue.ROW_LENGTH_SIZE + Bytes.toBytes("r1").length, 342 PrivateCellUtil.findCommonPrefixInFlatKey(kv2, kv3, true, true)); 343 // entire rk is same but different cf name 344 KeyValue kv4 = 345 new KeyValue(Bytes.toBytes("r14"), Bytes.toBytes("f2"), Bytes.toBytes("q1"), null); 346 Assert.assertEquals( 347 KeyValue.ROW_LENGTH_SIZE + kv3.getRowLength() + KeyValue.FAMILY_LENGTH_SIZE 348 + Bytes.toBytes("f").length, 349 PrivateCellUtil.findCommonPrefixInFlatKey(kv3, kv4, false, true)); 350 // rk and family are same and part of qualifier 351 KeyValue kv5 = 352 new KeyValue(Bytes.toBytes("r14"), Bytes.toBytes("f2"), Bytes.toBytes("q123"), null); 353 Assert.assertEquals( 354 KeyValue.ROW_LENGTH_SIZE + kv3.getRowLength() + KeyValue.FAMILY_LENGTH_SIZE 355 + kv4.getFamilyLength() + kv4.getQualifierLength(), 356 PrivateCellUtil.findCommonPrefixInFlatKey(kv4, kv5, true, true)); 357 // rk, cf and q are same. ts differs 358 KeyValue kv6 = new KeyValue(Bytes.toBytes("rk"), 1234L); 359 KeyValue kv7 = new KeyValue(Bytes.toBytes("rk"), 1235L); 360 // only last byte out of 8 ts bytes in ts part differs 361 Assert.assertEquals( 362 KeyValue.ROW_LENGTH_SIZE + kv6.getRowLength() + KeyValue.FAMILY_LENGTH_SIZE 363 + kv6.getFamilyLength() + kv6.getQualifierLength() + 7, 364 PrivateCellUtil.findCommonPrefixInFlatKey(kv6, kv7, true, true)); 365 // rk, cf, q and ts are same. Only type differs 366 KeyValue kv8 = new KeyValue(Bytes.toBytes("rk"), 1234L, KeyValue.Type.Delete); 367 Assert.assertEquals( 368 KeyValue.ROW_LENGTH_SIZE + kv6.getRowLength() + KeyValue.FAMILY_LENGTH_SIZE 369 + kv6.getFamilyLength() + kv6.getQualifierLength() + KeyValue.TIMESTAMP_SIZE, 370 PrivateCellUtil.findCommonPrefixInFlatKey(kv6, kv8, true, true)); 371 // With out TS_TYPE check 372 Assert.assertEquals( 373 KeyValue.ROW_LENGTH_SIZE + kv6.getRowLength() + KeyValue.FAMILY_LENGTH_SIZE 374 + kv6.getFamilyLength() + kv6.getQualifierLength(), 375 PrivateCellUtil.findCommonPrefixInFlatKey(kv6, kv8, true, false)); 376 } 377 378 /** 379 * Assert CellUtil makes Cell toStrings same way we do KeyValue toStrings. 380 */ 381 @Test 382 public void testToString() { 383 byte[] row = Bytes.toBytes("row"); 384 long ts = 123L; 385 // Make a KeyValue and a Cell and see if same toString result. 386 KeyValue kv = new KeyValue(row, HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY, ts, 387 KeyValue.Type.Minimum, HConstants.EMPTY_BYTE_ARRAY); 388 Cell cell = ExtendedCellBuilderFactory.create(CellBuilderType.DEEP_COPY).setRow(row) 389 .setFamily(HConstants.EMPTY_BYTE_ARRAY).setQualifier(HConstants.EMPTY_BYTE_ARRAY) 390 .setTimestamp(ts).setType(KeyValue.Type.Minimum.getCode()) 391 .setValue(HConstants.EMPTY_BYTE_ARRAY).build(); 392 String cellToString = CellUtil.getCellKeyAsString(cell); 393 assertEquals(kv.toString(), cellToString); 394 // Do another w/ non-null family. 395 byte[] f = new byte[] { 'f' }; 396 byte[] q = new byte[] { 'q' }; 397 kv = new KeyValue(row, f, q, ts, KeyValue.Type.Minimum, HConstants.EMPTY_BYTE_ARRAY); 398 cell = ExtendedCellBuilderFactory.create(CellBuilderType.DEEP_COPY).setRow(row).setFamily(f) 399 .setQualifier(q).setTimestamp(ts).setType(KeyValue.Type.Minimum.getCode()) 400 .setValue(HConstants.EMPTY_BYTE_ARRAY).build(); 401 cellToString = CellUtil.getCellKeyAsString(cell); 402 assertEquals(kv.toString(), cellToString); 403 } 404 405 @Test 406 public void testToString1() { 407 String row = "test.row"; 408 String family = "test.family"; 409 String qualifier = "test.qualifier"; 410 long timestamp = 42; 411 KeyValue.Type type = KeyValue.Type.Put; 412 String value = "test.value"; 413 long seqId = 1042; 414 415 Cell cell = ExtendedCellBuilderFactory.create(CellBuilderType.DEEP_COPY) 416 .setRow(Bytes.toBytes(row)).setFamily(Bytes.toBytes(family)) 417 .setQualifier(Bytes.toBytes(qualifier)).setTimestamp(timestamp).setType(type.getCode()) 418 .setValue(Bytes.toBytes(value)).setSequenceId(seqId).build(); 419 420 String nonVerbose = CellUtil.toString(cell, false); 421 String verbose = CellUtil.toString(cell, true); 422 423 System.out.println("nonVerbose=" + nonVerbose); 424 System.out.println("verbose=" + verbose); 425 426 Assert.assertEquals(String.format("%s/%s:%s/%d/%s/vlen=%s/seqid=%s", row, family, qualifier, 427 timestamp, type.toString(), Bytes.toBytes(value).length, seqId), nonVerbose); 428 429 Assert.assertEquals(String.format("%s/%s:%s/%d/%s/vlen=%s/seqid=%s/%s", row, family, qualifier, 430 timestamp, type.toString(), Bytes.toBytes(value).length, seqId, value), verbose); 431 432 // TODO: test with tags 433 } 434 435 @Test 436 public void testCloneCellFieldsFromByteBufferedCell() { 437 byte[] r = Bytes.toBytes("row1"); 438 byte[] f = Bytes.toBytes("cf1"); 439 byte[] q = Bytes.toBytes("qual1"); 440 byte[] v = Bytes.toBytes("val1"); 441 byte[] tags = Bytes.toBytes("tag1"); 442 KeyValue kv = 443 new KeyValue(r, f, q, 0, q.length, 1234L, KeyValue.Type.Put, v, 0, v.length, tags); 444 ByteBuffer buffer = ByteBuffer.wrap(kv.getBuffer()); 445 ExtendedCell bbCell = new ByteBufferKeyValue(buffer, 0, buffer.remaining()); 446 byte[] rDest = CellUtil.cloneRow(bbCell); 447 assertTrue(Bytes.equals(r, rDest)); 448 byte[] fDest = CellUtil.cloneFamily(bbCell); 449 assertTrue(Bytes.equals(f, fDest)); 450 byte[] qDest = CellUtil.cloneQualifier(bbCell); 451 assertTrue(Bytes.equals(q, qDest)); 452 byte[] vDest = CellUtil.cloneValue(bbCell); 453 assertTrue(Bytes.equals(v, vDest)); 454 byte[] tDest = new byte[tags.length]; 455 PrivateCellUtil.copyTagsTo(bbCell, tDest, 0); 456 assertTrue(Bytes.equals(tags, tDest)); 457 } 458 459 @Test 460 public void testMatchingCellFieldsFromByteBufferedCell() { 461 byte[] r = Bytes.toBytes("row1"); 462 byte[] f = Bytes.toBytes("cf1"); 463 byte[] q1 = Bytes.toBytes("qual1"); 464 byte[] q2 = Bytes.toBytes("qual2"); 465 byte[] v = Bytes.toBytes("val1"); 466 byte[] tags = Bytes.toBytes("tag1"); 467 KeyValue kv = 468 new KeyValue(r, f, q1, 0, q1.length, 1234L, KeyValue.Type.Put, v, 0, v.length, tags); 469 ByteBuffer buffer = ByteBuffer.wrap(kv.getBuffer()); 470 Cell bbCell1 = new ByteBufferKeyValue(buffer, 0, buffer.remaining()); 471 kv = new KeyValue(r, f, q2, 0, q2.length, 1234L, KeyValue.Type.Put, v, 0, v.length, tags); 472 buffer = ByteBuffer.wrap(kv.getBuffer()); 473 Cell bbCell2 = new ByteBufferKeyValue(buffer, 0, buffer.remaining()); 474 assertTrue(CellUtil.matchingRows(bbCell1, bbCell2)); 475 assertTrue(CellUtil.matchingRows(kv, bbCell2)); 476 assertTrue(CellUtil.matchingRows(bbCell1, r)); 477 assertTrue(CellUtil.matchingFamily(bbCell1, bbCell2)); 478 assertTrue(CellUtil.matchingFamily(kv, bbCell2)); 479 assertTrue(CellUtil.matchingFamily(bbCell1, f)); 480 assertFalse(CellUtil.matchingQualifier(bbCell1, bbCell2)); 481 assertTrue(CellUtil.matchingQualifier(kv, bbCell2)); 482 assertTrue(CellUtil.matchingQualifier(bbCell1, q1)); 483 assertTrue(CellUtil.matchingQualifier(bbCell2, q2)); 484 assertTrue(CellUtil.matchingValue(bbCell1, bbCell2)); 485 assertTrue(CellUtil.matchingValue(kv, bbCell2)); 486 assertTrue(CellUtil.matchingValue(bbCell1, v)); 487 assertFalse(CellUtil.matchingColumn(bbCell1, bbCell2)); 488 assertTrue(CellUtil.matchingColumn(kv, bbCell2)); 489 assertTrue(CellUtil.matchingColumn(bbCell1, f, q1)); 490 assertTrue(CellUtil.matchingColumn(bbCell2, f, q2)); 491 } 492 493 @Test 494 public void testCellFieldsAsPrimitiveTypesFromByteBufferedCell() { 495 int ri = 123; 496 byte[] r = Bytes.toBytes(ri); 497 byte[] f = Bytes.toBytes("cf1"); 498 byte[] q = Bytes.toBytes("qual1"); 499 long vl = 10981L; 500 byte[] v = Bytes.toBytes(vl); 501 KeyValue kv = new KeyValue(r, f, q, v); 502 ByteBuffer buffer = ByteBuffer.wrap(kv.getBuffer()); 503 Cell bbCell = new ByteBufferKeyValue(buffer, 0, buffer.remaining()); 504 assertEquals(ri, PrivateCellUtil.getRowAsInt(bbCell)); 505 assertEquals(vl, PrivateCellUtil.getValueAsLong(bbCell)); 506 double vd = 3005.5; 507 v = Bytes.toBytes(vd); 508 kv = new KeyValue(r, f, q, v); 509 buffer = ByteBuffer.wrap(kv.getBuffer()); 510 bbCell = new ByteBufferKeyValue(buffer, 0, buffer.remaining()); 511 assertEquals(vd, PrivateCellUtil.getValueAsDouble(bbCell), 0.0); 512 BigDecimal bd = new BigDecimal(9999); 513 v = Bytes.toBytes(bd); 514 kv = new KeyValue(r, f, q, v); 515 buffer = ByteBuffer.wrap(kv.getBuffer()); 516 bbCell = new ByteBufferKeyValue(buffer, 0, buffer.remaining()); 517 assertEquals(bd, PrivateCellUtil.getValueAsBigDecimal(bbCell)); 518 } 519 520 @Test 521 public void testGetType() { 522 ExtendedCell c = Mockito.mock(ExtendedCell.class); 523 Mockito.when(c.getType()).thenCallRealMethod(); 524 for (Cell.Type type : Cell.Type.values()) { 525 Mockito.when(c.getTypeByte()).thenReturn(type.getCode()); 526 assertEquals(type, c.getType()); 527 } 528 529 try { 530 Mockito.when(c.getTypeByte()).thenReturn(KeyValue.Type.Maximum.getCode()); 531 c.getType(); 532 fail("The code of Maximum can't be handled by Cell.Type"); 533 } catch (UnsupportedOperationException e) { 534 } 535 536 try { 537 Mockito.when(c.getTypeByte()).thenReturn(KeyValue.Type.Minimum.getCode()); 538 c.getType(); 539 fail("The code of Maximum can't be handled by Cell.Type"); 540 } catch (UnsupportedOperationException e) { 541 } 542 } 543}